def addValue(self, row, col, size, colour_value): """add a dot in row/col. """ # decide the size of the box pos = bisect.bisect(self.mThresholdsSize, size) if self.mRevertSize: size = self.mMaxBoxSize * \ (1.0 - float(pos) / len(self.mThresholdsSize)) else: size = self.mMaxBoxSize * float(pos) / len(self.mThresholdsSize) d = (self.mMaxBoxSize - size) / 2 x = self.mMapCol2Position[col] + d try: y = self.mMapRow2Position[row] + d except KeyError: return # determine the colour of the box pos = bisect.bisect(self.mThresholdsColour, colour_value) colour = self.mColours[pos] e = SVGdraw.rect(x, y, size, size, stroke="black", fill="rgb(%i,%i,%i)" % colour) self.mElements.append(e)
def writeFooter(self): """write footer. The footer contains the legend. """ current_x = self.mFooterFrom current_y = self.mHeaderHeight + self.mDataHeight + 2 * self.mSeparator self.mFooterBoxSize = 30 self.mNumTicks = 20 for x in range(len(self.mColourThresholds)): e = SVGdraw.rect(current_x, current_y, self.mFooterBoxSize, self.mFooterBoxSize, fill="rgb(%i,%i,%i)" % self.mColours[x], stroke="rgb(%i,%i,%i)" % self.mColours[x]) self.addElement(e) if x % self.mNumTicks == 0: e = SVGdraw.line(current_x, current_y, current_x, current_y + self.mFooterBoxSize, stroke="rgb(%i,%i,%i)" % BLACK, stroke_width=5) self.addElement(e) e = SVGdraw.text(current_x, current_y - self.mFooterBoxSize, self.mFormatNumberLegend % self.mColourThresholds[x], self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") self.addElement(e) current_x += self.mFooterBoxSize ########################################################### if self.mFooter: current_y += max(self.mFooterFontSize, self.mMaxBoxSize) + self.mSeparator e = SVGdraw.text(self.mPageWidth / 2, current_y + self.mFooterFontSize, self.mFooter, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="middle") self.addElement(e)
def writeFooter(self): """write footer. The footer contains the legend. """ current_x = self.mFooterFrom current_y = self.mHeaderHeight + self.mDataHeight + 2 * self.mSeparator self.mFooterBoxSize = 30 self.mNumTicks = 20 for x in range(len(self.mColourThresholds)): e = SVGdraw.rect(current_x, current_y, self.mFooterBoxSize, self.mFooterBoxSize, fill="rgb(%i,%i,%i)" % self.mColours[x], stroke="rgb(%i,%i,%i)" % self.mColours[x]) self.addElement(e) if x % self.mNumTicks == 0: e = SVGdraw.line(current_x, current_y, current_x, current_y + self.mFooterBoxSize, stroke="rgb(%i,%i,%i)" % BLACK, stroke_width=5) self.addElement(e) e = SVGdraw.text(current_x, current_y - self.mFooterBoxSize, self.mFormatNumberLegend % self.mColourThresholds[ x], self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") self.addElement(e) current_x += self.mFooterBoxSize ########################################################### if self.mFooter: current_y += max(self.mFooterFontSize, self.mMaxBoxSize) + self.mSeparator e = SVGdraw.text(self.mPageWidth / 2, current_y + self.mFooterFontSize, self.mFooter, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="middle") self.addElement(e)
def writeScale(self): """write scales.""" current_x = self.mScaleX current_y = self.mScaleY + self.mScaleHeight nboxes = len(self.mColourThresholds) # box size for legend in x-direction # subtract size of right-most axis label so that it takes the # same width as self.mDataWidth. box_size_x = math.ceil( (self.mDataWidth - (self.mScaleFontSize * len(self.mFormatNumberLegend % self.mColourThresholds[-1]))) / nboxes) # change font size such that it labels will fit between tick-marks self.mScaleFontSize = min( self.mScaleFontSize, (box_size_x * self.mScaleNumTicks * 1.5) / len(self.mFormatNumberLegend % self.mColourThresholds[-1])) for x in range(nboxes): e = SVGdraw.rect(current_x, current_y, box_size_x, self.mScaleBoxSizeY, fill="rgb(%i,%i,%i)" % self.mColours[x], stroke="rgb(%i,%i,%i)" % self.mColours[x]) self.addElement(e) if x % self.mScaleNumTicks == 0: e = SVGdraw.line(current_x, current_y, current_x, current_y + self.mScaleBoxSizeY, stroke="rgb(%i,%i,%i)" % BLACK, stroke_width=5) self.addElement(e) e = SVGdraw.text(current_x, current_y - self.mScaleBoxSizeY, self.mFormatNumberLegend % self.mColourThresholds[x], self.mScaleFontSize, self.mScaleFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") self.addElement(e) current_x += box_size_x
def writeScale(self): """write scales.""" current_x = self.mScaleX current_y = self.mScaleY + self.mScaleHeight nboxes = len(self.mColourThresholds) # box size for legend in x-direction # subtract size of right-most axis label so that it takes the # same width as self.mDataWidth. box_size_x = math.ceil((self.mDataWidth - (self.mScaleFontSize * len( self.mFormatNumberLegend % self.mColourThresholds[-1]))) / nboxes) # change font size such that it labels will fit between tick-marks self.mScaleFontSize = min(self.mScaleFontSize, (box_size_x * self.mScaleNumTicks * 1.5) / len(self.mFormatNumberLegend % self.mColourThresholds[-1])) for x in range(nboxes): e = SVGdraw.rect(current_x, current_y, box_size_x, self.mScaleBoxSizeY, fill="rgb(%i,%i,%i)" % self.mColours[x], stroke="rgb(%i,%i,%i)" % self.mColours[x]) self.addElement(e) if x % self.mScaleNumTicks == 0: e = SVGdraw.line(current_x, current_y, current_x, current_y + self.mScaleBoxSizeY, stroke="rgb(%i,%i,%i)" % BLACK, stroke_width=5) self.addElement(e) e = SVGdraw.text(current_x, current_y - self.mScaleBoxSizeY, self.mFormatNumberLegend % self.mColourThresholds[ x], self.mScaleFontSize, self.mScaleFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") self.addElement(e) current_x += box_size_x
def getElements(self, x, y, map_node2height): elements = [] for n in self.mTree.get_terminals(): t = self.mTree.node(n).data.taxon if t not in self.mMapId2Cluster: continue cluster = self.mMapId2Cluster[t] if cluster not in self.mMapCluster2Colour: self.mMapCluster2Colour[cluster] = COLOURS[ len(self.mMapCluster2Colour) % len(COLOURS)] colour = self.mMapCluster2Colour[cluster] elements.append(SVGdraw.rect(x, y + map_node2height[n] - self.mBoxWidth / 2, self.mBoxWidth, self.mBoxWidth, stroke="rgb(%i,%i,%i)" % colour, fill="rgb(%i,%i,%i)" % colour)) return elements
def getElements(self, node_id, x, y): e = [] colour = self.getColour(node_id, x, y) if self.mPlotSymbol == "circle": e.append(SVGdraw.circle(x + self.mFontSize / 2, y, self.mFontSize / 2, stroke="rgb(%i,%i,%i)" % BLACK, fill="rgb(%i,%i,%i)" % colour)) elif self.mPlotSymbol == "square": e.append(SVGdraw.rect(x, y - self.mFontSize / 2, self.mFontSize, self.mFontSize, stroke="rgb(%i,%i,%i)" % BLACK, fill="rgb(%i,%i,%i)" % colour)) return e
def getElements(self, node_id, x, y): e = [] colour = self.getColour(node_id, x, y) if self.mPlotSymbol == "circle": e.append( SVGdraw.circle(x + self.mFontSize / 2, y, self.mFontSize / 2, stroke="rgb(%i,%i,%i)" % BLACK, fill="rgb(%i,%i,%i)" % colour)) elif self.mPlotSymbol == "square": e.append( SVGdraw.rect(x, y - self.mFontSize / 2, self.mFontSize, self.mFontSize, stroke="rgb(%i,%i,%i)" % BLACK, fill="rgb(%i,%i,%i)" % colour)) return e
def getElements(self, x, y, map_node2height): elements = [] for n in self.mTree.get_terminals(): t = self.mTree.node(n).data.taxon if t not in self.mMapId2Cluster: continue cluster = self.mMapId2Cluster[t] if cluster not in self.mMapCluster2Colour: self.mMapCluster2Colour[cluster] = COLOURS[len( self.mMapCluster2Colour) % len(COLOURS)] colour = self.mMapCluster2Colour[cluster] elements.append( SVGdraw.rect(x, y + map_node2height[n] - self.mBoxWidth / 2, self.mBoxWidth, self.mBoxWidth, stroke="rgb(%i,%i,%i)" % colour, fill="rgb(%i,%i,%i)" % colour)) return elements
def addDuplication(self, entries, map_gene2pos, height, url=None, with_separator=True, link_to_previous=False, quality2symbol={}, quality2mask={}): """add a dot in row/col.""" mi, ma = None, 0 pos = bisect.bisect(self.mColourThresholds, height) master_colour = self.mColours[pos] chrs = {} points = [] for species, transcript, gene, quality in entries: chr, strand, first_res, last_res = map_gene2pos[gene] chrs[chr] = 1 pos1 = self.getPosition(chr, strand, first_res) pos2 = self.getPosition(chr, strand, last_res) a = min(pos1, pos2) b = max(pos1, pos2) if mi is None: mi = a else: mi = min(a, mi) ma = max(b, ma) points.append((pos1, pos2, gene, quality)) # decide whether we need to increment the radius cis = len(chrs) == 1 old_radius = self.mRadius is_overlap = False if cis: if not self.mLastChr: self.mLastChr = chr if chr != self.mLastChr: self.mRadius = self.mRadiusFallBack self.mLastMax = ma self.mPreviousMax = ma self.mLastChr = chr else: if self.mPreviousMax + self.mMinDistance > mi: # overlap due to close proximitiy self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() # true overlap if self.mPreviousMax > mi: is_overlap = True elif self.mLastMax + self.mMinDistance > mi: pass else: self.mRadius = self.mRadiusFallBack self.mLastMax = max(self.mLastMax, ma) else: if self.mLastMax > mi: self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() if cis and self.mPreviousCis and (link_to_previous or is_overlap): # print old_x1, old_y1, old_x2, old_y2, new_x1, new_y2, new_x2, # new_y2 r1 = old_radius r2 = self.mRadius old_x1, old_y1 = self.getPosOnArcForRadius(self.mPreviousMin, r1) old_x2, old_y2 = self.getPosOnArcForRadius(self.mPreviousMax, r1) new_x1, new_y1 = self.getPosOnArcForRadius(mi, r2) new_x2, new_y2 = self.getPosOnArcForRadius(ma, r2) if link_to_previous: # print cis, entries, chrs d = SVGdraw.pathdata(old_x1, old_y1) d.ellarc(r1, r1, 0, 0, 1, old_x2, old_y2) d.line(new_x2, new_y2) d.ellarc(r2, r2, 0, 0, 1, new_x1, new_y1) d.line(old_x1, old_y1) e = SVGdraw.path(d, fill="rgb(%i,%i,%i)" % GREY, stroke="rgb(%i,%i,%i)" % GREY, stroke_width=1) else: # get points of center old_x1, old_y1 = self.getPosOnArcForRadius( (self.mPreviousMax + self.mPreviousMin) / 2, r1) new_x1, new_y1 = self.getPosOnArcForRadius((ma + mi) / 2, r2) # lines for interleaved spans: skip if not ((self.mPreviousMin < mi and self.mPreviousMax > ma) or (self.mPreviousMin > mi and self.mPreviousMax < ma)): ## d = SVGdraw.pathdata( old_x2, old_y2 ) ## d.line( new_x2, new_y2 ) ## d.move( new_x1, new_y1 ) ## d.line( old_x1, old_y1 ) ## d.move( old_x2, old_y2 ) # e = SVGdraw.path( d, ## fill = "none", ## stroke = "rgb(%i,%i,%i)" % BLACK, # stroke_width = self.mMarkerWidth / 2 ) e = SVGdraw.line(old_x1, old_y1, new_x1, new_y1, fill="none", stroke="rgb(%i,%i,%i)" % GREY, stroke_width=self.mMarkerWidth / 2) else: # lines for covering spans, as these overlaps e = None # e = SVGdraw.line( old_x1, old_y1, ## new_x1, new_y1, ## fill = "none", ## stroke = "rgb(%i,%i,%i)" % GREY, # stroke_width = self.mMarkerWidth / 2 ) if e: self.addElement(e, self.mPlaneJoins) self.mPreviousMin = mi self.mPreviousMax = ma self.mPreviousCis = cis self.mRadiusMax = max(self.mRadius, self.mRadiusMax) # draw points link_colour = master_colour link_width = 10 for pos1, pos2, gene, quality in points: angle = self.getAngle((pos1 + pos2) / 2) x, y = self.getPosOnArc(angle, self.mRadius) try: symbol = quality2symbol[quality] except KeyError: symbol = "rect" if quality in quality2mask: colour = GREY link_colour = GREY link_width = 1 else: colour = master_colour if symbol == "circle": ee = SVGdraw.circle(x, y, self.mMarkerWidth, fill="rgb(%i,%i,%i)" % colour, stroke="black", stroke_width=1) elif symbol == "rect": ee = SVGdraw.rect(x - self.mMarkerWidth / 2, y - self.mMarkerWidth / 2, self.mMarkerWidth, self.mMarkerWidth, fill="rgb(%i,%i,%i)" % colour, stroke="black", stroke_width=1) if url: e = SVGdraw.link(url % gene) e.addElement(ee) else: e = ee self.addElement(e) angle1 = self.getAngle(mi) angle2 = self.getAngle(ma) x1, y1 = self.getPosOnArc(angle1, self.mRadius) x2, y2 = self.getPosOnArc(angle2, self.mRadius) d = SVGdraw.pathdata(x1, y1) if cis: d.ellarc(self.mRadius, self.mRadius, 0, 0, 1, x2, y2) else: d.ellarc(self.mRadius * 2, self.mRadius * 2, 0, 0, 0, x2, y2) e = SVGdraw.path(d, fill="none", stroke="rgb(%i,%i,%i)" % link_colour, stroke_width=link_width) self.addElement(e)
def plotGene(self, x, y, gene=None, group_id=None): """plot a gene at x,y.""" if gene: group_id = gene.mOrthologId colour, format = self.mMapGroup2Colour[group_id] filled, shape = format.split("-") if filled == "filled": fill = "rgb(%i,%i,%i)" % colour stroke = "rgb(%i,%i,%i)" % BLACK stroke_width = 1 elif filled == "open": fill = "rgb(%i,%i,%i)" % WHITE stroke = "rgb(%i,%i,%i)" % colour stroke_width = self.mBlockSize / 2 if shape == "circle": ee = SVGdraw.circle(x, y, self.mBlockSize, fill=fill, stroke=stroke, stroke_width=stroke_width) elif shape == "box": ee = SVGdraw.rect( x - self.mBlockSize, y - self.mBlockSize, 2 * self.mBlockSize, 2 * self.mBlockSize, fill=fill, stroke=stroke, stroke_width=stroke_width, ) elif shape == "lefttriangle": ee = SVGdraw.polygon( ( (x - self.mBlockSize, y), (x + self.mBlockSize, y - self.mBlockSize), (x + self.mBlockSize, y + self.mBlockSize), ), fill=fill, stroke=stroke, stroke_width=stroke_width, ) elif shape == "righttriangle": ee = SVGdraw.polygon( ( (x - self.mBlockSize, y - self.mBlockSize), (x + self.mBlockSize, y), (x - self.mBlockSize, y + self.mBlockSize), ), fill=fill, stroke=stroke, stroke_width=stroke_width, ) elif shape == "uptriangle": ee = SVGdraw.polygon( ( (x, y - self.mBlockSize), (x + self.mBlockSize, y + self.mBlockSize), (x - self.mBlockSize, y + self.mBlockSize), ), fill="rgb(%i,%i,%i)" % WHITE, stroke="rgb(%i,%i,%i)" % colour, stroke_width=self.mBlockSize / 2, ) elif shape == "downtriangle": ee = SVGdraw.polygon( ( (x, y + self.mBlockSize), (x + self.mBlockSize, y - self.mBlockSize), (x - self.mBlockSize, y - self.mBlockSize), ), fill="rgb(%i,%i,%i)" % WHITE, stroke="rgb(%i,%i,%i)" % colour, stroke_width=self.mBlockSize / 2, ) return ee
def writeFooter(self): """write footer. The footer contains the legend. """ current_x = self.mFooterFrom current_y = self.mHeaderHeight + self.mDataHeight + 2 * self.mSeparator ########################################################### # Draw legend 1: size of boxes e = SVGdraw.text(current_x, current_y + self.mFooterFontSize, self.mThresholdsSizeTitle, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") current_x += len(self.mThresholdsSizeTitle) * \ self.mFooterFontSize / 1.5 + self.mSeparator self.mElements.append(e) l = len(self.mThresholdsSize) for x in range(l): if self.mRevertSize: p = int(self.mMaxBoxSize * (1.0 - float(x) / l)) else: p = int(self.mMaxBoxSize * (float(x) / l)) e = SVGdraw.rect(current_x, current_y + (self.mMaxBoxSize - p) / 2, p, p, stroke="black", fill="rgb(%i,%i,%i)" % self.startColour) self.mElements.append(e) current_x += self.mMaxBoxSize + self.mSeparator t = "< %g" % (self.mThresholdsSize[x]) e = SVGdraw.text(current_x, current_y + self.mFooterFontSize, t, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") current_x += len(t) * self.mFooterFontSize / 1.5 + self.mSeparator self.mElements.append(e) ########################################################### # Draw legend 2: colour of boxes current_x = self.mFooterFrom current_y += max(self.mFooterFontSize, self.mMaxBoxSize) + \ self.mSeparator e = SVGdraw.text(current_x, current_y + self.mFooterFontSize, self.mThresholdsColourTitle, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") current_x += len(self.mThresholdsColourTitle) * \ self.mFooterFontSize / 1.5 + self.mSeparator self.mElements.append(e) l = len(self.mThresholdsColour) for x in range(l + 1): p = self.mMaxBoxSize if x < l: t = "< %g" % (self.mThresholdsColour[x]) else: t = "> %g" % (self.mThresholdsColour[x - 1]) e = SVGdraw.rect(current_x, current_y, p, p, stroke="black", fill="rgb(%i,%i,%i)" % self.mColours[x]) self.mElements.append(e) current_x += self.mMaxBoxSize + self.mSeparator e = SVGdraw.text(current_x, current_y + self.mFooterFontSize, t, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="start") current_x += len(t) * self.mFooterFontSize / 1.5 + self.mSeparator self.mElements.append(e) ########################################################### if self.mMaxPValue is not None or self.mMaxQValue is not None: current_y += max(self.mFooterFontSize / 1.5, self.mMaxBoxSize) + self.mSeparator a = [] if self.mMaxPValue: a.append("P < %6.4f" % self.mMaxPValue) if self.mMaxQValue: a.append("FDR = %6.4f" % self.mMaxQValue) e = SVGdraw.text(self.mPageWidth / 2, current_y + self.mFooterFontSize, " ".join(a), self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="middle") ########################################################### if self.mFooter: current_y += max(self.mFooterFontSize / 1.5, self.mMaxBoxSize) + self.mSeparator e = SVGdraw.text(self.mPageWidth / 2, current_y + self.mFooterFontSize, self.mFooter, self.mFooterFontSize, self.mFooterFont, stroke="rgb(%i,%i,%i)" % BLACK, text_anchor="middle") self.mElements.append(e)
def addDuplication( self, entries, map_gene2pos, height, url = None, with_separator=True, link_to_previous = False, quality2symbol = {}, quality2mask = {}): """add a dot in row/col.""" mi, ma = None, 0 pos = bisect.bisect( self.mColourThresholds, height ) master_colour = self.mColours[pos] chrs = {} points = [] for species, transcript, gene, quality in entries: chr, strand, first_res, last_res = map_gene2pos[gene] chrs[chr] = 1 pos1 = self.getPosition( chr, strand, first_res ) pos2 = self.getPosition( chr, strand, last_res ) a = min( pos1, pos2 ) b = max( pos1, pos2 ) if mi == None: mi = a else: mi = min(a, mi) ma = max(b, ma) points.append( (pos1, pos2, gene, quality) ) ## decide whether we need to increment the radius cis = len(chrs) == 1 old_radius = self.mRadius is_overlap = False if cis: if not self.mLastChr: self.mLastChr = chr if chr != self.mLastChr: self.mRadius = self.mRadiusFallBack self.mLastMax = ma self.mPreviousMax = ma self.mLastChr = chr else: if self.mPreviousMax + self.mMinDistance > mi: ## overlap due to close proximitiy self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() ## true overlap if self.mPreviousMax > mi: is_overlap = True elif self.mLastMax + self.mMinDistance > mi: pass else: self.mRadius = self.mRadiusFallBack self.mLastMax = max(self.mLastMax, ma) else: if self.mLastMax > mi: self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() if cis and self.mPreviousCis and (link_to_previous or is_overlap): # print old_x1, old_y1, old_x2, old_y2, new_x1, new_y2, new_x2, new_y2 r1 = old_radius r2 = self.mRadius old_x1, old_y1 = self.getPosOnArcForRadius( self.mPreviousMin, r1 ) old_x2, old_y2 = self.getPosOnArcForRadius( self.mPreviousMax, r1 ) new_x1, new_y1 = self.getPosOnArcForRadius( mi, r2 ) new_x2, new_y2 = self.getPosOnArcForRadius( ma, r2 ) if link_to_previous: # print cis, entries, chrs d = SVGdraw.pathdata( old_x1, old_y1 ) d.ellarc( r1, r1, 0, 0, 1, old_x2, old_y2 ) d.line( new_x2, new_y2 ) d.ellarc( r2, r2, 0, 0, 1, new_x1, new_y1 ) d.line( old_x1, old_y1 ) e = SVGdraw.path( d, fill = "rgb(%i,%i,%i)" % GREY, stroke = "rgb(%i,%i,%i)" % GREY, stroke_width = 1 ) else: # get points of center old_x1, old_y1 = self.getPosOnArcForRadius( (self.mPreviousMax + self.mPreviousMin) / 2, r1 ) new_x1, new_y1 = self.getPosOnArcForRadius( (ma + mi) / 2, r2 ) # lines for interleaved spans: skip if not ((self.mPreviousMin < mi and self.mPreviousMax > ma) or \ (self.mPreviousMin > mi and self.mPreviousMax < ma)) : ## d = SVGdraw.pathdata( old_x2, old_y2 ) ## d.line( new_x2, new_y2 ) ## d.move( new_x1, new_y1 ) ## d.line( old_x1, old_y1 ) ## d.move( old_x2, old_y2 ) ## e = SVGdraw.path( d, ## fill = "none", ## stroke = "rgb(%i,%i,%i)" % BLACK, ## stroke_width = self.mMarkerWidth / 2 ) e = SVGdraw.line( old_x1, old_y1, new_x1, new_y1, fill = "none", stroke = "rgb(%i,%i,%i)" % GREY, stroke_width = self.mMarkerWidth / 2 ) else: # lines for covering spans, as these overlaps e = None ## e = SVGdraw.line( old_x1, old_y1, ## new_x1, new_y1, ## fill = "none", ## stroke = "rgb(%i,%i,%i)" % GREY, ## stroke_width = self.mMarkerWidth / 2 ) if e: self.addElement( e, self.mPlaneJoins ) self.mPreviousMin = mi self.mPreviousMax = ma self.mPreviousCis = cis self.mRadiusMax = max(self.mRadius, self.mRadiusMax) ## draw points link_colour = master_colour link_width = 10 for pos1, pos2, gene, quality in points: angle = self.getAngle( (pos1 + pos2) / 2 ) x,y = self.getPosOnArc( angle, self.mRadius ) try: symbol = quality2symbol[quality] except KeyError: symbol = "rect" if quality in quality2mask: colour = GREY link_colour = GREY link_width = 1 else: colour = master_colour if symbol == "circle": ee = SVGdraw.circle( x, y, self.mMarkerWidth, fill = "rgb(%i,%i,%i)" % colour, stroke="black", stroke_width= 1) elif symbol == "rect": ee = SVGdraw.rect( x-self.mMarkerWidth/2, y-self.mMarkerWidth/2, self.mMarkerWidth, self.mMarkerWidth, fill = "rgb(%i,%i,%i)" % colour, stroke="black", stroke_width= 1) if url: e = SVGdraw.link( url % gene ) e.addElement( ee ) else: e = ee self.addElement( e ) angle1 = self.getAngle( mi ) angle2 = self.getAngle( ma ) x1,y1 = self.getPosOnArc( angle1, self.mRadius ) x2,y2 = self.getPosOnArc( angle2, self.mRadius ) d = SVGdraw.pathdata( x1, y1 ) if cis: d.ellarc( self.mRadius, self.mRadius, 0, 0, 1, x2, y2 ) else: d.ellarc( self.mRadius * 2, self.mRadius * 2, 0, 0, 0, x2, y2 ) e = SVGdraw.path( d, fill = "none", stroke = "rgb(%i,%i,%i)" % link_colour, stroke_width = link_width ) self.addElement(e)
def addDuplication(self, entries, map_gene2pos, height, url=None, with_separator=True, link_to_previous=False, quality2symbol={}, quality2mask={}): """add a dot in row/col.""" mi, ma = None, 0 pos = bisect.bisect(self.mColourThresholds, height) master_colour = self.mColours[pos] chrs = {} points = [] if not link_to_previous: self.mPreviousPoints = {} ######################################################## ######################################################## ######################################################## # convert gene list to a set of points ######################################################## for species, transcript, gene, quality in entries: chr, strand, first_res, last_res = map_gene2pos[gene] chrs[chr] = 1 pos1 = self.getPosition(chr, strand, first_res) pos2 = self.getPosition(chr, strand, last_res) a = min(pos1, pos2) b = max(pos1, pos2) if mi is None: mi = a else: mi = min(a, mi) ma = max(b, ma) points.append((pos1, pos2, gene, quality, chr)) ######################################################## ######################################################## ######################################################## # decide whether we need to increment the radius ######################################################## cis = len(chrs) == 1 old_radius = self.mRadius is_overlap = False if cis: if not self.mLastChr: self.mLastChr = chr if chr != self.mLastChr: self.mRadius = self.mRadiusFallBack self.mLastMax = ma self.mPreviousMax = ma self.mLastChr = chr else: if self.mPreviousMax + self.mMinDistance > mi: # overlap due to close proximitiy self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() # true overlap if self.mPreviousMax > mi: is_overlap = True elif self.mLastMax + self.mMinDistance > mi: pass else: self.mRadius = self.mRadiusFallBack self.mLastMax = max(self.mLastMax, ma) else: if self.mLastMax > mi: self.mRadius += self.mRadiusIncrement if with_separator: self.addSeparator() self.mPreviousMin = mi self.mPreviousMax = ma self.mPreviousCis = cis self.mRadiusMax = max(self.mRadius, self.mRadiusMax) ######################################################## ######################################################## ######################################################## # draw points ######################################################## link_colour = master_colour link_rad_width = self.mLinkRadStrokeWidth link_arc_width = self.mLinkArcStrokeWidth new_points = {} for pos1, pos2, gene, quality, chr in points: angle = self.getAngle((pos1 + pos2) / 2) x, y = self.getPosOnArc(angle, self.mRadius) try: symbol = quality2symbol[quality] except KeyError: symbol = "rect" if quality in quality2mask: colour = self.mLinkColourSymbolMasked link_colour = self.mLinkColourMasked link_rad_width = self.mLinkStrokeWidthMasked link_arc_width = self.mLinkStrokeWidthMasked else: colour = master_colour if gene in self.mPreviousPoints: continue new_points[gene] = (x, y, angle, quality, chr) if symbol == "circle": ee = SVGdraw.circle(x, y, self.mLinkSymbolSize, fill="rgb(%i,%i,%i)" % colour, stroke="black", stroke_width=self.mLinkStrokeWidthSymbol) elif symbol == "rect": ee = SVGdraw.rect(x - self.mLinkSymbolSize / 2, y - self.mLinkSymbolSize / 2, self.mLinkSymbolSize, self.mLinkSymbolSize, fill="rgb(%i,%i,%i)" % colour, stroke="black", stroke_width=self.mLinkStrokeWidthSymbol) if url: e = SVGdraw.link(url % gene) e.addElement(ee) else: e = ee self.addWheelElement(e) ######################################################## ######################################################## ######################################################## # write all arcs in between old points and new points # cis: circular arc # trans: radial arc ######################################################## angles = [] for x1, y1, angle1, quality1, chr1 in new_points.values(): # reduce clutter by not writing arc to the same angle for x2, y2, angle2, quality2, chr2 in self.mPreviousPoints.values(): for a in angles: if a - self.mAngleResolution < angle2 < a + self.mAngleResolution: break else: angles.append(angle2) d = SVGdraw.pathdata(x1, y1) if chr1 == chr2: d.relellarc( self.mRadius, self.mRadius, 0, 0, 1, x2 - x1, y2 - y1) link_width = link_rad_width else: d.relellarc( self.mRadius * 2, self.mRadius * 2, 0, 0, 0, x2 - x1, y2 - y1) link_width = link_arc_width e = SVGdraw.path(d, fill="none", stroke="rgb(%i,%i,%i)" % link_colour, stroke_width=link_width) self.addWheelElement(e, self.mPlaneLinks) # plot lines between new points new_genes = new_points.keys() for g1 in range(len(new_genes) - 1): x1, y1, angle1, quality1, chr1 = new_points[new_genes[g1]] for g2 in range(g1 + 1, len(new_genes)): x2, y2, angle2, quality2, chr2 = new_points[new_genes[g2]] for a in angles: if a - self.mAngleResolution < angle2 < a + self.mAngleResolution: break else: angles.append(angle2) d = SVGdraw.pathdata(x1, y1) if chr1 == chr2: d.relellarc( self.mRadius, self.mRadius, 0, 0, 1, x2 - x1, y2 - y1) link_width = link_rad_width else: d.relellarc( self.mRadius * 2, self.mRadius * 2, 0, 0, 0, x2 - x1, y2 - y1) link_width = link_arc_width e = SVGdraw.path(d, fill="none", stroke="rgb(%i,%i,%i)" % link_colour, stroke_width=link_width) self.addWheelElement(e, self.mPlaneLinks) # add new points to old points for k, v in new_points.items(): self.mPreviousPoints[k] = v
def plotGene(self, x, y, gene=None, group_id=None): """plot a gene at x,y.""" if gene: group_id = gene.mOrthologId colour, format = self.mMapGroup2Colour[group_id] filled, shape = format.split("-") if filled == "filled": fill = "rgb(%i,%i,%i)" % colour stroke = "rgb(%i,%i,%i)" % BLACK stroke_width = 1 elif filled == "open": fill = "rgb(%i,%i,%i)" % WHITE stroke = "rgb(%i,%i,%i)" % colour stroke_width = self.mBlockSize / 2 if shape == "circle": ee = SVGdraw.circle(x, y, self.mBlockSize, fill=fill, stroke=stroke, stroke_width=stroke_width) elif shape == "box": ee = SVGdraw.rect(x - self.mBlockSize, y - self.mBlockSize, 2 * self.mBlockSize, 2 * self.mBlockSize, fill=fill, stroke=stroke, stroke_width=stroke_width) elif shape == "lefttriangle": ee = SVGdraw.polygon(((x - self.mBlockSize, y), (x + self.mBlockSize, y - self.mBlockSize), (x + self.mBlockSize, y + self.mBlockSize)), fill=fill, stroke=stroke, stroke_width=stroke_width) elif shape == "righttriangle": ee = SVGdraw.polygon(((x - self.mBlockSize, y - self.mBlockSize), (x + self.mBlockSize, y), (x - self.mBlockSize, y + self.mBlockSize)), fill=fill, stroke=stroke, stroke_width=stroke_width) elif shape == "uptriangle": ee = SVGdraw.polygon(((x, y - self.mBlockSize), (x + self.mBlockSize, y + self.mBlockSize), (x - self.mBlockSize, y + self.mBlockSize)), fill="rgb(%i,%i,%i)" % WHITE, stroke="rgb(%i,%i,%i)" % colour, stroke_width=self.mBlockSize / 2) elif shape == "downtriangle": ee = SVGdraw.polygon(((x, y + self.mBlockSize), (x + self.mBlockSize, y - self.mBlockSize), (x - self.mBlockSize, y - self.mBlockSize)), fill="rgb(%i,%i,%i)" % WHITE, stroke="rgb(%i,%i,%i)" % colour, stroke_width=self.mBlockSize / 2) return ee