Example #1
0
class Axis(object):
    def __init__(self, scale, variant, allele):
        self.scale = scale
        self.allele = allele
        self.variant = variant
        self.chromPartsCollection = variant.chromParts(allele)
        self.height = 75


    def baseHeight(self):
        return 75

    def render(self, scaleFactor=1.0, spacing=1.0, height=None, thickerLines=False):
        self.height = height
        if height == None:
            self.height = 75 * scaleFactor

        self.svg = SVG(self.scale.pixelWidth, self.height, yrelto="top", headerExtras="""preserveAspectRatio="none" """)

        # dividers! (multi-part only)
        if len(self.chromPartsCollection) > 1:
            for part in list(self.chromPartsCollection)[1:]:
                divWidth = self.scale.relpixels(self.scale.dividerSize)
                x = self.scale.partsToStartPixels[part.id] - divWidth
                self.svg.rect(x, 0, divWidth, self.height, fill="#B2B2B2")
                self.svg.line(x, 0, x, self.height, stroke="black", **{"stroke-width":1*scaleFactor})
                self.svg.line(x+divWidth, 0, x+divWidth, self.height, stroke="black", **{"stroke-width":1*scaleFactor})

            for i, part in enumerate(self.chromPartsCollection):
                if i == 0:
                    x = self.scale.topixels(self.scale.partsToLengths[part.id], part.id) - 15
                    anchor = "end"
                else:
                    x = self.scale.partsToStartPixels[part.id] + 15
                    anchor = "start"
                self.svg.text(x, 18*scaleFactor, part.id, anchor=anchor, size=18*scaleFactor)



        # tick marks and coordinates
        for regionID in self.scale.partsToStartPixels:
            for tick in self.getTicks(regionID):
                x = self.scale.topixels(tick, regionID)

                self.svg.rect(x, 35*scaleFactor, 1*scaleFactor, 15*scaleFactor, fill="black")
                label = tick
                if tick > 1e6:
                    label = "{:.1f}MB".format(tick/1e6)
                elif tick > 1e3:
                    label = "{:.1f}KB".format(tick/1e3)

                if x < 50:
                    x = 50
                elif x > self.scale.pixelWidth - 50:
                    x = self.scale.pixelWidth - 50
                extras = {}
                if thickerLines:
                    extras["font-weight"] = "bold"
                self.svg.text(x, self.height-4*scaleFactor, label, size=18*scaleFactor, **extras)


        # segment arrows
        for part in self.chromPartsCollection:
            curOffset = self.scale.partsToStartPixels[part.id]
            for segment in part.segments:
                start = curOffset
                end = self.scale.relpixels(len(segment)) + curOffset
                curOffset = end

                arrowDirection = "right"

                if segment.strand == "-":
                    start, end = end, start
                    arrowDirection = "left"

                y = 35*scaleFactor

                self.svg.line(start, y, end, y, stroke=segment.color(), **{"stroke-width":8*scaleFactor})
                self.svg.lineWithInternalArrows(start, y, end, y, stroke=segment.color(), direction=arrowDirection,
                    arrowKwdArgs={"class":"scaleArrow"}, **{"stroke-width":3*scaleFactor})

        # breakpoints
        previousPosition = None
        for part in self.chromPartsCollection:
            for vline in self.scale.getBreakpointPositions(part.id):
                thickness = 1*scaleFactor
                if thickerLines:
                    thickness *= 2
                x = self.scale.topixels(vline, part.id)
                self.svg.line(x, 20*scaleFactor, x, 55*scaleFactor, 
                    stroke="black", **{"stroke-width":thickness})
                
                if previousPosition is None or x-previousPosition > 250*scaleFactor:     
                    self.svg.text(x-(scaleFactor/2.0), 18*scaleFactor, "breakpoint", size=18*scaleFactor, fill="black")
                previousPosition = x


        return str(self.svg)

    def getTicks(self, regionID):
        ticks = []
        start = 0
        width = self.scale.partsToLengths[regionID]
        end = start + width

        res = (10 ** round(math.log10(end - start))) / 10.0
        if width / res > 15:
            res *= 2.5
        elif width / res < 5:
            res /= 2.0

        roundStart = start - (start%res)

        for i in range(int(roundStart), end, int(res)):
            ticks.append(i)

        return ticks
Example #2
0
class Axis(object):
    def __init__(self, scale, variant, allele):
        self.scale = scale
        self.allele = allele
        self.variant = variant
        self.chromPartsCollection = variant.chromParts(allele)
        self.height = 75


    def baseHeight(self):
        return 75

    def render(self, scaleFactor=1.0, spacing=1.0, height=None, thickerLines=False):
        self.height = height
        if height == None:
            self.height = 75 * scaleFactor

        self.svg = SVG(self.scale.pixelWidth, self.height, yrelto="top", headerExtras="""preserveAspectRatio="none" """)

        # dividers! (multi-part only)
        if len(self.chromPartsCollection) > 1:
            for part in list(self.chromPartsCollection)[1:]:
                divWidth = self.scale.relpixels(self.scale.dividerSize)
                x = self.scale.partsToStartPixels[part.id] - divWidth
                self.svg.rect(x, 0, divWidth, self.height, fill="#B2B2B2")
                self.svg.line(x, 0, x, self.height, stroke="black", **{"stroke-width":1*scaleFactor})
                self.svg.line(x+divWidth, 0, x+divWidth, self.height, stroke="black", **{"stroke-width":1*scaleFactor})

            for i, part in enumerate(self.chromPartsCollection):
                if i == 0:
                    x = self.scale.topixels(self.scale.partsToLengths[part.id], part.id) - 15
                    anchor = "end"
                else:
                    x = self.scale.partsToStartPixels[part.id] + 15
                    anchor = "start"
                self.svg.text(x, 18*scaleFactor, part.id, anchor=anchor, size=18*scaleFactor)



        # tick marks and coordinates
        for regionID in self.scale.partsToStartPixels:
            for tick in self.getTicks(regionID):
                x = self.scale.topixels(tick, regionID)

                self.svg.rect(x, 35*scaleFactor, 1*scaleFactor, 15*scaleFactor, fill="black")
                label = tick
                if tick > 1e6:
                    label = "{:.1f}MB".format(tick/1e6)
                elif tick > 1e3:
                    label = "{:.1f}KB".format(tick/1e3)

                if x < 50:
                    x = 50
                elif x > self.scale.pixelWidth - 50:
                    x = self.scale.pixelWidth - 50
                extras = {}
                if thickerLines:
                    extras["font-weight"] = "bold"
                self.svg.text(x, self.height-4*scaleFactor, label, size=18*scaleFactor, **extras)


        # segment arrows
        for part in self.chromPartsCollection:
            curOffset = self.scale.partsToStartPixels[part.id]
            for segment in part.segments:
                start = curOffset
                end = self.scale.relpixels(len(segment)) + curOffset
                curOffset = end

                arrowDirection = "right"

                if segment.strand == "-":
                    start, end = end, start
                    arrowDirection = "left"

                y = 35*scaleFactor

                self.svg.line(start, y, end, y, stroke=segment.color(), **{"stroke-width":8*scaleFactor})
                self.svg.lineWithInternalArrows(start, y, end, y, stroke=segment.color(), direction=arrowDirection,
                    arrowKwdArgs={"class":"scaleArrow"}, **{"stroke-width":3*scaleFactor})

        # breakpoints
        previousPosition = None
        for part in self.chromPartsCollection:
            for vline in self.scale.getBreakpointPositions(part.id):
                thickness = 1*scaleFactor
                if thickerLines:
                    thickness *= 2
                x = self.scale.topixels(vline, part.id)
                self.svg.line(x, 20*scaleFactor, x, 55*scaleFactor, 
                    stroke="black", **{"stroke-width":thickness})
                
                if previousPosition is None or x-previousPosition > 250*scaleFactor:     
                    self.svg.text(x-(scaleFactor/2.0), 18*scaleFactor, "breakpoint", size=18*scaleFactor, fill="black")
                previousPosition = x


        return str(self.svg)

    def getTicks(self, regionID):
        ticks = []
        start = 0
        width = self.scale.partsToLengths[regionID]
        end = start + width

        res = (10 ** round(math.log10(end - start))) / 10.0
        if width / res > 15:
            res *= 2.5
        elif width / res < 5:
            res /= 2.0

        roundStart = start - (start%res)

        for i in range(int(roundStart), end, int(res)):
            ticks.append(i)

        return ticks
Example #3
0
class Track(object):
    def __init__(self, chromPartsCollection, alignmentSets, height, width, variant, allele, thickerLines, colorCigar):
        self.chromPartsCollection = chromPartsCollection
        self.height = height
        self.width = width

        self.scale = Scale(chromPartsCollection, width)

        self.rowHeight = 5
        self.rowMargin = 1

        self.readRenderer = ReadRenderer(self.rowHeight, self.scale, self.chromPartsCollection, thickerLines, colorCigar)

        self.alignmentSets = alignmentSets

        self.svg = None
        self.rendered = None

        self.variant = variant
        self.allele = allele

        self.rows = []
        self._axis = None

        self.xmin = None
        self.xmax = None

        self.thickerLines = thickerLines


    def findRow(self, start, end, regionID):
        for currow in range(len(self.rows)):
            if self.rows[currow] is None or (start - self.rows[currow]) >= 2:
                self.rows[currow] = end
                break
        else:
            self.rows.append(end)
            currow = len(self.rows)-1

        return currow

    def getAlignments(self):
        # check which reads are overlapping (self.gstart, self.gend)
        # sorting by name makes the layout process deterministic
        regionIDsToPositions = dict((part.id, i) for i, part in enumerate(self.chromPartsCollection))

        def sortKey(alnSet):
            return (regionIDsToPositions[alnSet.getAlignments()[0].regionID], 
                    alnSet.start, alnSet.end, alnSet.name())

        return sorted(self.alignmentSets, key=sortKey)

    def dolayout(self):
        self.rows = [None]#*numRows

        self.xmin = 1e100
        self.xmax = 0

        for alignmentSet in self.getAlignments():
            # if len(alignmentSet.getAlignments()) < 2:
                # continue

            regionIDs = set([x.regionID for x in alignmentSet.getAlignments()])
            assert self.allele=="amb" or len(regionIDs)==1, alignmentSet.getAlignments()
            regionID = regionIDs.pop()

            start = self.scale.topixels(alignmentSet.start, regionID)
            end = self.scale.topixels(alignmentSet.end, regionID)

            currow = self.findRow(start, end, regionID)
            yoffset = (self.rowHeight+self.rowMargin) * currow
            alignmentSet.yoffset = yoffset

            self.xmin = min(self.xmin, self.scale.topixels(alignmentSet.start, regionID))
            self.xmax = max(self.xmax, self.scale.topixels(alignmentSet.end, regionID))

        self.height = (self.rowHeight+self.rowMargin) * len(self.rows)

    def render(self):        
        if len(self.getAlignments()) == 0:
            xmiddle = self.scale.pixelWidth / 2.0

            self.height = xmiddle/20.0

            self.svg = SVG(self.width, self.height)
            self.svg.text(xmiddle, self.height*0.05, "No reads found", size=self.height*0.9, fill="#999999")
            self.rendered = self.svg.asString()
            return self.rendered

        self.dolayout()

        self.svg = SVG(self.width, self.height)
        self.readRenderer.svg = self.svg

        alnSets = self.getAlignments()
        flankingAlignments = [alnSet for alnSet in alnSets if alnSet.parentCollection.why == "flanking"]
        nonFlankingAlignments = [alnSet for alnSet in alnSets if alnSet.parentCollection.why != "flanking"]

        for alignmentSet in flankingAlignments+nonFlankingAlignments:
            self.readRenderer.render(alignmentSet)

        lineWidth = 1 if not self.thickerLines else 3
        lineWidth = lineWidth * ((self.xmax-self.xmin)/1200.0)

        for part in self.chromPartsCollection:
            for vline in self.scale.getBreakpointPositions(part.id):
                x = self.scale.topixels(vline, part.id)
                y1 = -20
                y2 = self.height+20
                self.svg.line(x, y1, x, y2, stroke="black", **{"stroke-width":lineWidth})


        # dividers!
        for part in list(self.chromPartsCollection)[1:]:
            divWidth = self.scale.relpixels(self.scale.dividerSize)
            x = self.scale.partsToStartPixels[part.id] - divWidth
            self.svg.rect(x, self.height+40, divWidth, self.height+40, fill="#B2B2B2")
            self.svg.line(x, 0, x, self.height+40, stroke="black", **{"stroke-width":4})
            self.svg.line(x+divWidth, 0, x+divWidth, self.height+40, stroke="black", **{"stroke-width":4})

        self.svg.rect(0, self.svg.height+20, self.scale.pixelWidth, 
            self.height+40, opacity=0.0, zindex=0)
        self.rendered = str(self.svg)

        return self.rendered
Example #4
0
class Track(object):
    def __init__(self, chromPartsCollection, alignmentSets, height, width, variant, allele, thickerLines, colorCigar):
        self.chromPartsCollection = chromPartsCollection
        self.height = height
        self.width = width

        self.scale = Scale(chromPartsCollection, width)

        self.rowHeight = 5
        self.rowMargin = 1

        self.readRenderer = ReadRenderer(self.rowHeight, self.scale, self.chromPartsCollection, thickerLines, colorCigar)

        self.alignmentSets = alignmentSets

        self.svg = None
        self.rendered = None

        self.variant = variant
        self.allele = allele

        self.rows = []
        self._axis = None

        self.xmin = None
        self.xmax = None

        self.thickerLines = thickerLines


    def findRow(self, start, end, regionID):
        for currow in range(len(self.rows)):
            if self.rows[currow] is None or (start - self.rows[currow]) >= 2:
                self.rows[currow] = end
                break
        else:
            self.rows.append(end)
            currow = len(self.rows)-1

        return currow

    def getAlignments(self):
        # check which reads are overlapping (self.gstart, self.gend)
        # sorting by name makes the layout process deterministic
        regionIDsToPositions = dict((part.id, i) for i, part in enumerate(self.chromPartsCollection))

        def sortKey(alnSet):
            return (regionIDsToPositions[alnSet.getAlignments()[0].regionID], 
                    alnSet.start, alnSet.end, alnSet.name())

        return sorted(self.alignmentSets, key=sortKey)

    def dolayout(self):
        self.rows = [None]#*numRows

        self.xmin = 1e100
        self.xmax = 0

        for alignmentSet in self.getAlignments():
            # if len(alignmentSet.getAlignments()) < 2:
                # continue

            regionIDs = set([x.regionID for x in alignmentSet.getAlignments()])
            assert self.allele=="amb" or len(regionIDs)==1, alignmentSet.getAlignments()
            regionID = regionIDs.pop()

            start = self.scale.topixels(alignmentSet.start, regionID)
            end = self.scale.topixels(alignmentSet.end, regionID)

            currow = self.findRow(start, end, regionID)
            yoffset = (self.rowHeight+self.rowMargin) * currow
            alignmentSet.yoffset = yoffset

            self.xmin = min(self.xmin, self.scale.topixels(alignmentSet.start, regionID))
            self.xmax = max(self.xmax, self.scale.topixels(alignmentSet.end, regionID))

        self.height = (self.rowHeight+self.rowMargin) * len(self.rows)

    def render(self):        
        if len(self.getAlignments()) == 0:
            xmiddle = self.scale.pixelWidth / 2.0

            self.height = xmiddle/20.0

            self.svg = SVG(self.width, self.height)
            self.svg.text(xmiddle, self.height*0.05, "No reads found", size=self.height*0.9, fill="#999999")
            self.rendered = self.svg.asString()
            return self.rendered

        self.dolayout()

        self.svg = SVG(self.width, self.height)
        self.readRenderer.svg = self.svg

        alnSets = self.getAlignments()
        flankingAlignments = [alnSet for alnSet in alnSets if alnSet.parentCollection.why == "flanking"]
        nonFlankingAlignments = [alnSet for alnSet in alnSets if alnSet.parentCollection.why != "flanking"]

        for alignmentSet in flankingAlignments+nonFlankingAlignments:
            self.readRenderer.render(alignmentSet)

        lineWidth = 1 if not self.thickerLines else 3
        lineWidth = lineWidth * ((self.xmax-self.xmin)/1200.0)

        for part in self.chromPartsCollection:
            for vline in self.scale.getBreakpointPositions(part.id):
                x = self.scale.topixels(vline, part.id)
                y1 = -20
                y2 = self.height+20
                self.svg.line(x, y1, x, y2, stroke="black", **{"stroke-width":lineWidth})


        # dividers!
        for part in list(self.chromPartsCollection)[1:]:
            divWidth = self.scale.relpixels(self.scale.dividerSize)
            x = self.scale.partsToStartPixels[part.id] - divWidth
            self.svg.rect(x, self.height+40, divWidth, self.height+40, fill="#B2B2B2")
            self.svg.line(x, 0, x, self.height+40, stroke="black", **{"stroke-width":4})
            self.svg.line(x+divWidth, 0, x+divWidth, self.height+40, stroke="black", **{"stroke-width":4})

        self.svg.rect(0, self.svg.height+20, self.scale.pixelWidth, 
            self.height+40, opacity=0.0, zindex=0)
        self.rendered = str(self.svg)

        return self.rendered