Ejemplo n.º 1
0
 def getAnnotatedSeq(self, feature_types=None, where_feature=None):
     regions = list(self.getFeatures(feature_types = feature_types, 
                     where_feature = where_feature))
     # seq_map is on the + strand, regardless the actual strand of sequence
     seq_map = Map(locations = [(self.Location.Start, self.Location.End)], 
                 parent_length = DEFAULT_PARENT_LENGTH)
     seq_map = seq_map.inverse()
     
     for region in regions:
         data = region.featureData(seq_map)
         if data is None:
             continue
         # this will consider the strand information of actual sequence
         feature_map = [data[-1],
                 data[-1].nucleicReversed()][self.Location.Strand == -1]
         self.Seq.addAnnotation(Feature, data[0], data[1], feature_map)
         
         if region.Type == 'gene':  # TODO: SHOULD be much simplified
             sub_data = region.subFeatureData(seq_map)
             for feature_type, feature_name, feature_map in sub_data:
                 if self.Location.Strand == -1:
                     # again, change feature map to -1 strand sequence if
                     # needed.
                     feature_map = feature_map.nucleicReversed()
                 self.Seq.addAnnotation(Feature, feature_type, 
                                         feature_name, feature_map)
     
     return self.Seq
Ejemplo n.º 2
0
class Display(rlg2mpl.Drawable):
    """Holds a list of tracks and displays them all aligned
    
    base: A sequence, alignment, or anything else offering .getTracks(policy)
    policy: A DisplayPolicy subclass.
    pad: Gap between tracks in points.
    
    Other keyword arguments are used to modify the DisplayPolicy: 
    
    Sequence display:
    show_text: Represent bases as characters.  Slow.
    draw_bases: Represent bases as rectangles if MolType allows.
    show_gaps: Represent bases as line segments.
    colour_sequences: Colour code sequences if MolType allows.
    seq_color_callback: f(seq)->[colours] for flexible seq coloring.
    
    Layout:
    rowlen: wrap at this many characters per line.
    min_feature_height: minimum feature symbol height in points.
    min_graph_height: minimum height of any graphed features in points.
    
    Inclusion:
    recursive: include the sequences of the alignment.
    ignored_features: list of feature type tags to leave out.
    keep_unexpected_tracks: show features not assigned to a track by the policy.
    """
    
    def __init__(self, base, policy=DisplayPolicy, _policy=None, pad=1,
            yrange=None, **kw):
        self.pad = pad
        self.base = base
        self.yrange = yrange
        assert len(base) > 0, len(base)
        
        if _policy is None:
            policy = policy(**kw).copy(
                map=Map([(0, len(base))], parent_length=len(base)),
                depth=0, 
                rowlen=len(base))
        else:
            policy = _policy
        self.policy = policy
        self.smap=Map([(0, len(base))], parent_length=len(base))

        self._calc_tracks()
    
    def __len__(self):
        return len(self.smap.inverse())
    
    def _calc_tracks(self):
        y = 0
        self._tracks = []
        for p in self.base.getTracks(self.policy)[::-1]:
            if not isinstance(p, Track):
                if not isinstance(p, list):
                    p = [p]
                p = Track('', p)
            y2 = y + p.height + self.pad
            self._tracks.append((y+self.pad/2, (y+y2)/2, p))
            y = y2
        self.height = y
        
        if self.yrange is None:
            self.yrange = {}
            for (y, ym, p) in self._tracks:
                self.yrange[p.tag] = max(self.yrange.get(p.tag, 0), p.range)
        
    def copy(self, **kw):
        new = copy.copy(self)
        new.policy = self.policy.copy(**kw)
        new._calc_tracks()
        return new
    
    def __getitem__(self, slice):
        c = copy.copy(self)
        c.smap = self.smap.inverse()[slice].inverse()
        return c
        
    def makeArtist(self, vertical=False):
        g = rlg2mpl.Group()
        for (y, ym, p) in self._tracks:
            smap = self.smap.inverse()
            for s in p.getShapes(
                    span=(smap.Start, smap.End),
                    rotated=vertical,
                    height=float(p.height), 
                    yrange=self.yrange[p.tag]):
                trans = matplotlib.transforms.Affine2D()
                trans.translate(0, y)
                s.set_transform(s.get_transform() + trans)
                g.add(s)
        if vertical:
            g.rotate(90)
            g.scale(-1.0, 1.0)
        return g
    
    def asAxes(self, fig, posn, labeled=True, vertical=False):
        ax = fig.add_axes(posn)
        self.applyScaleToAxes(ax, labeled=labeled, vertical=vertical)
        g = self.makeArtist(vertical=vertical)
        ax.add_artist(g)
        return ax
        
    def applyScaleToAxes(self, ax, labeled=True, vertical=False):
        (seqaxis, trackaxis) = [ax.xaxis, ax.yaxis]
        if vertical:
            (seqaxis, trackaxis) = (trackaxis, seqaxis) 

        if not labeled:
            trackaxis.set_ticks([])
        else:
            track_positions = []
            track_labels = []
            for (y, ym, p) in self._tracks:
                if p.height > 8:
                    track_labels.append(p.label)
                    track_positions.append(ym)
            trackaxis.set_ticks(track_positions)
            trackaxis.set_ticklabels(track_labels)
            if vertical:
                for tick in trackaxis.get_major_ticks():
                    tick.label1.set_rotation('vertical')
                    tick.label2.set_rotation('vertical')
            
        seqaxis.set_major_formatter(
            matplotlib.ticker.FuncFormatter(lambda x,pos:str(int(x))))
        
        smap = self.smap.inverse()
        seq_lim = (smap.Start, smap.End)
        if vertical:
            ax.set_ylim(*seq_lim)
            ax.set_xlim(0, self.height or 0.1)
        else:
            ax.set_xlim(*seq_lim)
            ax.set_ylim(0, self.height or 0.1)
    
    def figureLayout(self, labeled=True, vertical=False, width=None, 
            height=None, left=None, **kw):

        if left is None:
            if labeled and self._tracks:
                left = max(len(p.label) for (y, ym, p) in self._tracks)
                left *= 12/72 * .5 # guess mixed chars, 12pt, inaccurate!
            else:
                left = 0
        
        height = height or (self.height or 0.1) / 72
        
        useful_width = len(self)*16/72 # ie bigish font, wide chars
        
        fkw = dict(leftovers=True, width=width, height=height, left=left, 
                useful_width=useful_width, **kw)  
        (w,h),posn,kw = rlg2mpl.figureLayout(**fkw)
        
        #points_per_base = w * posn[3] / len(self)
        if vertical:
            (w, h) = (h, w)
            posn[0:2] = reversed(posn[0:2])
            posn[2:4] = reversed(posn[2:4])
        return (w, h), posn, kw
    
    def makeFigure(self, width=None, height=None, rowlen=None, **kw):
        if rowlen:
            rows = [self[i:i+rowlen] for i in range(0, len(self), rowlen)]
        else:
            rows = [self]
            rowlen = len(self)
        kw.update(width=width, height=height)
        ((width, height), (x, y, w, h), kw) = self.figureLayout(**kw)
        N = len(rows)
        # since scales go below and titles go above, each row
        # gets the bottom margin, but not the top margin.
        vzoom = 1 + (y+h) * (N-1)
        fig = self._makeFigure(width, height * vzoom)
        for (i, row) in enumerate(rows):
            i = len(rows) - i - 1
            posn = [x, (y+i*(y+h))/vzoom, w*len(row)/rowlen, h/vzoom]
            row.asAxes(fig, posn, **kw)
        return fig
Ejemplo n.º 3
0
                'a': 'ATCGAAATCGAT',
                'b': 'ATCGA--TCGAT'})
        b = aln.getSeq('b')
        b.addAnnotation(Feature, 'test_type', 'test_label', [(4,6)])
        
        answer = aln.getBySequenceAnnotation('b', 'test_type')[0].todict()
        self.assertEqual(answer, {'b':'A--T', 'a':'AAAT'})
    

if 0:  # old, needs fixes
    # Maps
    a = Map([(10,20)], parent_length=100)
    
    for (desc, map, expected) in [
        ('a ', a,                                "Map([10:20] on base)"),
        ('i ', a.inverse(),                     "Map([-10-, 0:10, -80-] on Map([10:20] on base))"),
        ('1 ', a[5:],                            "Map([5:10] on Map([10:20] on base))"),
        ('1r', a[5:].relative_to(b),            "Map([15:20] on base)"),
        ('2 ', a[:5],                            "Map([0:5] on Map([10:20] on base))"),
        ('2r', a[:5].relative_to(b),            "Map([10:15] on base)"),
        ('r ', a.relative_to(a[5:]),            "Map([-5-, 0:5] on Map([5:10] on Map([10:20] on base)))"),
        ('r ', a[2:4].relative_to(a[2:6]),      "Map([0:2] on Map([2:6] on Map([10:20] on base)))"),
        ('r ', a[2:4].relative_to(a[2:6][0:3]), "Map([0:2] on Map([0:3] on Map([2:6] on Map([10:20] on base))))")]:
        print desc, repr(map),
        if repr(map) == expected:
            print
        else:
            print ' <--- ', expected
            bad = True

if __name__ == '__main__':
Ejemplo n.º 4
0
    def test_getBySequenceAnnotation(self):
        aln = LoadSeqs(data={'a': 'ATCGAAATCGAT', 'b': 'ATCGA--TCGAT'})
        b = aln.getSeq('b')
        b.addAnnotation(Feature, 'test_type', 'test_label', [(4, 6)])

        answer = aln.getBySequenceAnnotation('b', 'test_type')[0].todict()
        self.assertEqual(answer, {'b': 'A--T', 'a': 'AAAT'})


if 0:  # old, needs fixes
    # Maps
    a = Map([(10, 20)], parent_length=100)

    for (desc, map, expected) in [
        ('a ', a, "Map([10:20] on base)"),
        ('i ', a.inverse(), "Map([-10-, 0:10, -80-] on Map([10:20] on base))"),
        ('1 ', a[5:], "Map([5:10] on Map([10:20] on base))"),
        ('1r', a[5:].relative_to(b), "Map([15:20] on base)"),
        ('2 ', a[:5], "Map([0:5] on Map([10:20] on base))"),
        ('2r', a[:5].relative_to(b), "Map([10:15] on base)"),
        ('r ', a.relative_to(a[5:]),
         "Map([-5-, 0:5] on Map([5:10] on Map([10:20] on base)))"),
        ('r ', a[2:4].relative_to(a[2:6]),
         "Map([0:2] on Map([2:6] on Map([10:20] on base)))"),
        ('r ', a[2:4].relative_to(a[2:6][0:3]),
         "Map([0:2] on Map([0:3] on Map([2:6] on Map([10:20] on base))))")
    ]:
        print(desc, repr(map), end=' ')
        if repr(map) == expected:
            print()
        else:
Ejemplo n.º 5
0
class Display(rlg2mpl.Drawable):
    """Holds a list of tracks and displays them all aligned
    
    base: A sequence, alignment, or anything else offering .getTracks(policy)
    policy: A DisplayPolicy subclass.
    pad: Gap between tracks in points.
    
    Other keyword arguments are used to modify the DisplayPolicy: 
    
    Sequence display:
    show_text: Represent bases as characters.  Slow.
    draw_bases: Represent bases as rectangles if MolType allows.
    show_gaps: Represent bases as line segments.
    colour_sequences: Colour code sequences if MolType allows.
    seq_color_callback: f(seq)->[colours] for flexible seq coloring.
    
    Layout:
    rowlen: wrap at this many characters per line.
    min_feature_height: minimum feature symbol height in points.
    min_graph_height: minimum height of any graphed features in points.
    
    Inclusion:
    recursive: include the sequences of the alignment.
    ignored_features: list of feature type tags to leave out.
    keep_unexpected_tracks: show features not assigned to a track by the policy.
    """
    def __init__(self,
                 base,
                 policy=DisplayPolicy,
                 _policy=None,
                 pad=1,
                 yrange=None,
                 **kw):
        self.pad = pad
        self.base = base
        self.yrange = yrange
        assert len(base) > 0, len(base)

        if _policy is None:
            policy = policy(**kw).copy(map=Map([(0, len(base))],
                                               parent_length=len(base)),
                                       depth=0,
                                       rowlen=len(base))
        else:
            policy = _policy
        self.policy = policy
        self.smap = Map([(0, len(base))], parent_length=len(base))

        self._calc_tracks()

    def __len__(self):
        return len(self.smap.inverse())

    def _calc_tracks(self):
        y = 0
        self._tracks = []
        for p in self.base.getTracks(self.policy)[::-1]:
            if not isinstance(p, Track):
                if not isinstance(p, list):
                    p = [p]
                p = Track('', p)
            y2 = y + p.height + self.pad
            self._tracks.append((y + self.pad / 2, (y + y2) / 2, p))
            y = y2
        self.height = y

        if self.yrange is None:
            self.yrange = {}
            for (y, ym, p) in self._tracks:
                self.yrange[p.tag] = max(self.yrange.get(p.tag, 0), p.range)

    def copy(self, **kw):
        new = copy.copy(self)
        new.policy = self.policy.copy(**kw)
        new._calc_tracks()
        return new

    def __getitem__(self, slice):
        c = copy.copy(self)
        c.smap = self.smap.inverse()[slice].inverse()
        return c

    def makeArtist(self, vertical=False):
        g = rlg2mpl.Group()
        for (y, ym, p) in self._tracks:
            smap = self.smap.inverse()
            for s in p.getShapes(span=(smap.Start, smap.End),
                                 rotated=vertical,
                                 height=float(p.height),
                                 yrange=self.yrange[p.tag]):
                trans = matplotlib.transforms.Affine2D()
                trans.translate(0, y)
                s.set_transform(s.get_transform() + trans)
                g.add(s)
        if vertical:
            g.rotate(90)
            g.scale(-1.0, 1.0)
        return g

    def asAxes(self, fig, posn, labeled=True, vertical=False):
        ax = fig.add_axes(posn)
        self.applyScaleToAxes(ax, labeled=labeled, vertical=vertical)
        g = self.makeArtist(vertical=vertical)
        ax.add_artist(g)
        return ax

    def applyScaleToAxes(self, ax, labeled=True, vertical=False):
        (seqaxis, trackaxis) = [ax.xaxis, ax.yaxis]
        if vertical:
            (seqaxis, trackaxis) = (trackaxis, seqaxis)

        if not labeled:
            trackaxis.set_ticks([])
        else:
            track_positions = []
            track_labels = []
            for (y, ym, p) in self._tracks:
                if p.height > 8:
                    track_labels.append(p.label)
                    track_positions.append(ym)
            trackaxis.set_ticks(track_positions)
            trackaxis.set_ticklabels(track_labels)
            if vertical:
                for tick in trackaxis.get_major_ticks():
                    tick.label1.set_rotation('vertical')
                    tick.label2.set_rotation('vertical')

        seqaxis.set_major_formatter(
            matplotlib.ticker.FuncFormatter(lambda x, pos: str(int(x))))

        smap = self.smap.inverse()
        seq_lim = (smap.Start, smap.End)
        if vertical:
            ax.set_ylim(*seq_lim)
            ax.set_xlim(0, self.height or 0.1)
        else:
            ax.set_xlim(*seq_lim)
            ax.set_ylim(0, self.height or 0.1)

    def figureLayout(self,
                     labeled=True,
                     vertical=False,
                     width=None,
                     height=None,
                     left=None,
                     **kw):

        if left is None:
            if labeled and self._tracks:
                left = max(len(p.label) for (y, ym, p) in self._tracks)
                left *= 12 / 72 * .5  # guess mixed chars, 12pt, inaccurate!
            else:
                left = 0

        height = height or (self.height or 0.1) / 72

        useful_width = len(self) * 16 / 72  # ie bigish font, wide chars

        fkw = dict(leftovers=True,
                   width=width,
                   height=height,
                   left=left,
                   useful_width=useful_width,
                   **kw)
        (w, h), posn, kw = rlg2mpl.figureLayout(**fkw)

        #points_per_base = w * posn[3] / len(self)
        if vertical:
            (w, h) = (h, w)
            posn[0:2] = reversed(posn[0:2])
            posn[2:4] = reversed(posn[2:4])
        return (w, h), posn, kw

    def makeFigure(self, width=None, height=None, rowlen=None, **kw):
        if rowlen:
            rows = [self[i:i + rowlen] for i in range(0, len(self), rowlen)]
        else:
            rows = [self]
            rowlen = len(self)
        kw.update(width=width, height=height)
        ((width, height), (x, y, w, h), kw) = self.figureLayout(**kw)
        N = len(rows)
        # since scales go below and titles go above, each row
        # gets the bottom margin, but not the top margin.
        vzoom = 1 + (y + h) * (N - 1)
        fig = self._makeFigure(width, height * vzoom)
        for (i, row) in enumerate(rows):
            i = len(rows) - i - 1
            posn = [
                x, (y + i * (y + h)) / vzoom, w * len(row) / rowlen, h / vzoom
            ]
            row.asAxes(fig, posn, **kw)
        return fig