class SeqTrack (Track):
    """Track for displaying a single sequence along the genome"""

    def __init__(self, seqs, **options):
        options.setdefault("size", [0.0, 0.5])
        Track.__init__(self, **options)
        
        self.seqs = seqs
        self.shown = False
        self.multiscale = Multiscale(marginx=.5, marginy=.5)

    
    def draw(self):
        self.shown = False
        self.multiscale.init(self.get_window())
        
        # return placeholder group
        self.gid = group()
        return self.gid
    
    
    def update(self):
        if self.view == None:
            raise Exception("Track view not initialized")
        
        win = self.get_window()
        
        view = win.get_visible()
        x, y = self.pos
        
        if self.multiscale.atleast(4, .1, view=view):
            if not self.shown or \
               not self.multiscale.same_view(view):
                self.shown = True
                start = max(int(self.multiscale.worldx1 - x + self.view.start), 
                            int(self.view.start))
                end = min(int(self.multiscale.worldx2 - x + self.view.start), 
                          int(self.view.end))
                
                seq = self.seqs.getseq(self.view.seqname, start, end)
                
                # convert from inclusive to exclusive
                end = len(seq) + start - 1
                
                self.gid = win.replace_group(self.gid, 
                    group(translate(x, y,
                        color(0,0,0),
                        scale(1, self.size[1], 
                        text_scale(seq, start-self.view.start, 
                                        0, end-self.view.start+1, 2, 
                                        "left", "bottom")))))
            
        elif self.shown:
            self.shown = False
            self.gid = win.replace_group(self.gid, group())
Exemplo n.º 2
0
class SeqTrack(Track):
    """Track for displaying a single sequence along the genome"""
    def __init__(self, seqs, **options):
        options.setdefault("size", [0.0, 0.5])
        Track.__init__(self, **options)

        self.seqs = seqs
        self.shown = False
        self.multiscale = Multiscale(marginx=.5, marginy=.5)

    def draw(self):
        self.shown = False
        self.multiscale.init(self.get_window())

        # return placeholder group
        self.gid = group()
        return self.gid

    def update(self):
        if self.view == None:
            raise Exception("Track view not initialized")

        win = self.get_window()

        view = win.get_visible()
        x, y = self.pos

        if self.multiscale.atleast(4, .1, view=view):
            if not self.shown or \
               not self.multiscale.same_view(view):
                self.shown = True
                start = max(int(self.multiscale.worldx1 - x + self.view.start),
                            int(self.view.start))
                end = min(int(self.multiscale.worldx2 - x + self.view.start),
                          int(self.view.end))

                seq = self.seqs.getseq(self.view.seqname, start, end)

                # convert from inclusive to exclusive
                end = len(seq) + start - 1

                self.gid = win.replace_group(
                    self.gid,
                    group(
                        translate(
                            x, y, color(0, 0, 0),
                            scale(
                                1, self.size[1],
                                text_scale(seq, start - self.view.start, 0,
                                           end - self.view.start + 1, 2,
                                           "left", "bottom")))))

        elif self.shown:
            self.shown = False
            self.gid = win.replace_group(self.gid, group())
class AlignTrack (Track):
    def __init__(self, aln, collapse=None, cols=None, color_bases=False, 
                 seqtype=None, show_color_bases=True, show_bases=True,
                 show_labels=True,
                 rowspacing=None,
                 **options):
        Track.__init__(self, **options)
        self.size = [aln.alignlen(), len(aln)]
        self.multiscale = Multiscale(marginx=.5, marginy=.5)
        self.collapse = collapse
        
        self.show_color_bases = show_color_bases
        self.show_bases = show_bases
        self.show_labels = show_labels
        self.rowspacing = rowspacing
        self.always_color = False
        self.color_bases_vis = None
        
        if seqtype == None:
            self.seqtype = guessAlign(aln)
        else:
            self.seqtype = seqtype
        
        if color_bases == True:
            if self.seqtype == "dna":
                self.color_bases = dna_colors
            elif self.seqtype == "pep":
                self.color_bases = pep_colors
        else:
            self.color_bases = color_bases
        
        if collapse != None:
            assert collapse in aln.keys()
            cols = util.findneq('-', aln[collapse])
            
        if cols != None:
            self.aln = alignlib.subalign(aln, cols)
        else:
            self.aln = aln
        
    
        
    def draw(self):
        self.text_shown = False
        self.multiscale.init(self.get_window())
    
        BASE    = 0
        GAP     = 1
        NOBASE  = 2
        
        if self.seqtype == "dna":
            baseclasses = {'A': BASE, 'C': BASE, 'T': BASE, 'G': BASE,
                           '-': GAP, 'N': NOBASE, '*': NOBASE, 'X': NOBASE}
            
        elif self.seqtype == "pep":
            baseclasses = {'-': GAP, 'N': NOBASE, '*': NOBASE, 'X': NOBASE}
            
            for aa in 'ARNDCEQGHILKMFPSTWYVU':
                baseclasses[aa] = BASE
        
        else:
            raise Exception("unknown seqtype '%s'" % self.seqtype)
        
        # init row spacing
        if self.rowspacing == None:
            self.rowspacing = range(len(self.aln))
        
        def getRegions(selectedClass):
            boxpts = []
            diagpts = []
            diagpts2 = []
            
            for row, (key, val) in zip(self.rowspacing, self.aln.iteritems()):
                lastbase = None
                lastclass = None
                lasti = 0
                for i in xrange(len(val)+1):
                    # this extra is being used to handle the case when
                    # a sequence is all bases
                    if i < len(val):
                        base = val[i]
                    else:
                        base = '-'
                    if base not in baseclasses:
                        baseclass = NOBASE
                    else:
                        baseclass = baseclasses[base]

                    if baseclass == lastclass:
                        continue
                    
                    if lastbase != None and lastclass == selectedClass:
                        boxpts.extend([lasti, -row, lasti, -row-1, i, -row-1, i, -row])
                        diagpts.extend([i, -row, i, -row-1])
                        #diagpts.extend([lasti, -row, i, -row-1])
                        #diagpts2.extend([lasti, -row, lasti, -row-1])

                    lasti = i
                    lastbase = base
                    lastclass = baseclass
            return boxpts, diagpts, diagpts2
        
        base_boxpts, base_diagpts, base_diagpts2 = getRegions(BASE)
        nobase_boxpts, nobase_diagpts, nobase_diagpts2 = getRegions(NOBASE)
        
        
        # build labels
        if self.show_labels:
            labels = []
            for i, key in zip(self.rowspacing, self.aln):
                labels.append(text_clip(key, -util.INF, -i, 0, -i-1,
                                    4, 12, "middle", "right"))
            labelsgroup = group(*labels)
        else:
            labelsgroup = group()
        
        
        # build hotspot
        click = hotspot("click", 0, 0, self.aln.alignlen(), -self.size[1],
                        self.on_click_callback)
        
        self.text_group = group()
        
        return group(translate(self.pos[0], self.pos[1] + self.size[1],
                     color(0, 0, 0),
                     labelsgroup,
                     
                     click,
                     
                     color(.5, .5, .5), 
                     quads(* base_boxpts),
                     lines(* base_diagpts),
                     #lines(* base_diagpts2),
                     
                     color(.7, .2, .2),
                     quads(* nobase_boxpts),
                     lines(* nobase_diagpts),
                     #lines(* nobase_diagpts2),
                     group(self.text_group)))
    
    def draw_left(self):
        labels = []
        maxsize = max(map(len, self.aln.keys()))
        
        for i, key in enumerate(self.aln):
            labels.append(text_clip(key, -util.INF, -i, 0, -i-1,
                                    4, 12, "middle", "right"))
        return group(translate(self.pos[0], self.pos[1] + self.size[1],
                     color(0,0,0), 
                     #lines(0, 0, 0, -len(self.aln),
                     #      -maxsize, 0, 0, 0,
                     #      -maxsize, -len(self.aln), 0, -len(self.aln)),
                     *labels))
        
        
    
    def update(self):
        win = self.get_window()
        view = win.get_visible()
        size = win.get_size()
        x, y = self.pos
        
        mintextSize = 4
        minblockSize = 1
        
        color_bases = self.color_bases
        
        if self.multiscale.atleast(minblockSize, .1, 
                                   view=view, size=size):
            if not self.text_shown or \
               not self.multiscale.same_view(view):
                self.text_shown = True
                
                start = max(int(self.multiscale.worldx1 - x - 1), 
                            0)
                end = max(int(self.multiscale.worldx2 - x), start)
                
                vis = []
                vis2 = []
                for i, row in enumerate(self.aln.itervalues()):
                    seq = row[start:end]
                    seq = seq.replace("-", " ")
                    
                    # color bases
                    if self.show_color_bases and color_bases != False:
                        for j in xrange(len(seq)):
                            base = seq[j].upper()
                            if base in color_bases:
                                vis2.extend([color_bases[base], 
                                             quads(start + j, -i,
                                                   start + j, -i-1,
                                                   start + j+1, -i-1,
                                                   start + j+1, -i)])
                    
                    end2 = start + len(seq)
                    
                    # draw text
                    if self.show_bases and \
                       self.multiscale.atleast(mintextSize, 2, 
                                               view=view, size=size):
                        vis.append(text_scale(seq, 
                                              start, -i+1, 
                                              end2, -i-1, 
                                              "left", "bottom"))
                
                self.text_group = win.replace_group(self.text_group, 
                    group(group(*vis2), color(0,0,0), * vis))
            
        elif self.text_shown:
            self.text_shown = False
            self.text_group = win.replace_group(self.text_group, group())


    def on_click_callback(self):
        # TODO: should not rely on get_mouse_pos("world")
        win = self.get_window()
        x, y = win.get_mouse_pos('world')
        x -= self.pos[0]
        y = self.size[1] - (y - self.pos[1])
        self.on_click(x, y)


    def on_click(self, x, y):
        y = int(y)
    
        if 0 <= y < len(self.aln):
            print self.aln.keys()[y]
Exemplo n.º 4
0
class AlignTrack(Track):
    def __init__(self,
                 aln,
                 collapse=None,
                 cols=None,
                 color_bases=False,
                 seqtype=None,
                 show_color_bases=True,
                 show_bases=True,
                 show_labels=True,
                 rowspacing=None,
                 **options):
        Track.__init__(self, **options)
        self.size = [aln.alignlen(), len(aln)]
        self.multiscale = Multiscale(marginx=.5, marginy=.5)
        self.collapse = collapse

        self.show_color_bases = show_color_bases
        self.show_bases = show_bases
        self.show_labels = show_labels
        self.rowspacing = rowspacing
        self.always_color = False
        self.color_bases_vis = None

        if seqtype == None:
            self.seqtype = guessAlign(aln)
        else:
            self.seqtype = seqtype

        if color_bases == True:
            if self.seqtype == "dna":
                self.color_bases = dna_colors
            elif self.seqtype == "pep":
                self.color_bases = pep_colors
        else:
            self.color_bases = color_bases

        if collapse != None:
            assert collapse in aln.keys()
            cols = util.findneq('-', aln[collapse])

        if cols != None:
            self.aln = alignlib.subalign(aln, cols)
        else:
            self.aln = aln

    def draw(self):
        self.text_shown = False
        self.multiscale.init(self.get_window())

        BASE = 0
        GAP = 1
        NOBASE = 2

        if self.seqtype == "dna":
            baseclasses = {
                'A': BASE,
                'C': BASE,
                'T': BASE,
                'G': BASE,
                '-': GAP,
                'N': NOBASE,
                '*': NOBASE,
                'X': NOBASE
            }

        elif self.seqtype == "pep":
            baseclasses = {'-': GAP, 'N': NOBASE, '*': NOBASE, 'X': NOBASE}

            for aa in 'ARNDCEQGHILKMFPSTWYVU':
                baseclasses[aa] = BASE

        else:
            raise Exception("unknown seqtype '%s'" % self.seqtype)

        # init row spacing
        if self.rowspacing == None:
            self.rowspacing = range(len(self.aln))

        def getRegions(selectedClass):
            boxpts = []
            diagpts = []
            diagpts2 = []

            for row, (key, val) in zip(self.rowspacing, self.aln.iteritems()):
                lastbase = None
                lastclass = None
                lasti = 0
                for i in xrange(len(val) + 1):
                    # this extra is being used to handle the case when
                    # a sequence is all bases
                    if i < len(val):
                        base = val[i]
                    else:
                        base = '-'
                    if base not in baseclasses:
                        baseclass = NOBASE
                    else:
                        baseclass = baseclasses[base]

                    if baseclass == lastclass:
                        continue

                    if lastbase != None and lastclass == selectedClass:
                        boxpts.extend([
                            lasti, -row, lasti, -row - 1, i, -row - 1, i, -row
                        ])
                        diagpts.extend([i, -row, i, -row - 1])
                        #diagpts.extend([lasti, -row, i, -row-1])
                        #diagpts2.extend([lasti, -row, lasti, -row-1])

                    lasti = i
                    lastbase = base
                    lastclass = baseclass
            return boxpts, diagpts, diagpts2

        base_boxpts, base_diagpts, base_diagpts2 = getRegions(BASE)
        nobase_boxpts, nobase_diagpts, nobase_diagpts2 = getRegions(NOBASE)

        # build labels
        if self.show_labels:
            labels = []
            for i, key in zip(self.rowspacing, self.aln):
                labels.append(
                    text_clip(key, -util.INF, -i, 0, -i - 1, 4, 12, "middle",
                              "right"))
            labelsgroup = group(*labels)
        else:
            labelsgroup = group()

        # build hotspot
        click = hotspot("click", 0, 0, self.aln.alignlen(), -self.size[1],
                        self.on_click_callback)

        self.text_group = group()

        return group(
            translate(
                self.pos[0],
                self.pos[1] + self.size[1],
                color(0, 0, 0),
                labelsgroup,
                click,
                color(.5, .5, .5),
                quads(*base_boxpts),
                lines(*base_diagpts),
                #lines(* base_diagpts2),
                color(.7, .2, .2),
                quads(*nobase_boxpts),
                lines(*nobase_diagpts),
                #lines(* nobase_diagpts2),
                group(self.text_group)))

    def draw_left(self):
        labels = []
        maxsize = max(map(len, self.aln.keys()))

        for i, key in enumerate(self.aln):
            labels.append(
                text_clip(key, -util.INF, -i, 0, -i - 1, 4, 12, "middle",
                          "right"))
        return group(
            translate(
                self.pos[0],
                self.pos[1] + self.size[1],
                color(0, 0, 0),
                #lines(0, 0, 0, -len(self.aln),
                #      -maxsize, 0, 0, 0,
                #      -maxsize, -len(self.aln), 0, -len(self.aln)),
                *labels))

    def update(self):
        win = self.get_window()
        view = win.get_visible()
        size = win.get_size()
        x, y = self.pos

        mintextSize = 4
        minblockSize = 1

        color_bases = self.color_bases

        if self.multiscale.atleast(minblockSize, .1, view=view, size=size):
            if not self.text_shown or \
               not self.multiscale.same_view(view):
                self.text_shown = True

                start = max(int(self.multiscale.worldx1 - x - 1), 0)
                end = max(int(self.multiscale.worldx2 - x), start)

                vis = []
                vis2 = []
                for i, row in enumerate(self.aln.itervalues()):
                    seq = row[start:end]
                    seq = seq.replace("-", " ")

                    # color bases
                    if self.show_color_bases and color_bases != False:
                        for j in xrange(len(seq)):
                            base = seq[j].upper()
                            if base in color_bases:
                                vis2.extend([
                                    color_bases[base],
                                    quads(start + j, -i, start + j, -i - 1,
                                          start + j + 1, -i - 1, start + j + 1,
                                          -i)
                                ])

                    end2 = start + len(seq)

                    # draw text
                    if self.show_bases and \
                       self.multiscale.atleast(mintextSize, 2,
                                               view=view, size=size):
                        vis.append(
                            text_scale(seq, start, -i + 1, end2, -i - 1,
                                       "left", "bottom"))

                self.text_group = win.replace_group(
                    self.text_group, group(group(*vis2), color(0, 0, 0), *vis))

        elif self.text_shown:
            self.text_shown = False
            self.text_group = win.replace_group(self.text_group, group())

    def on_click_callback(self):
        # TODO: should not rely on get_mouse_pos("world")
        win = self.get_window()
        x, y = win.get_mouse_pos('world')
        x -= self.pos[0]
        y = self.size[1] - (y - self.pos[1])
        self.on_click(x, y)

    def on_click(self, x, y):
        y = int(y)

        if 0 <= y < len(self.aln):
            print self.aln.keys()[y]