def build(self): (x0, y0) = self._source.position('se') (x5, y5) = self._dest.position('ne') pd = SVG.pathdata() pd.move(x0, y0) (x1, y1) = (x0 + UNIT, y0 + UNIT) (x2, y2) = (x0 + UNIT, y0 + 2 * UNIT) (x3, y3) = (x5 + UNIT, y5 - 2 * UNIT) (x4, y4) = (x5 + UNIT, y5 - UNIT) if x2 < x4: pd.qbezier(x1, y1, x2, y2) pd.line(x3, y3) pd.qbezier(x4, y4, x5, y5) else: pd.qbezier(x0 + UNIT, (y5 + y0) / 2, x5, y5) self._extent = (abs(x5 - x0), abs(y5 - y0)) self._widget = SVG.path(pd, 'none', self._color, self._parent.strokewidth()) self._widget.attributes['stroke-dasharray'] = '5, 5'
def build(self): (x0,y0) = self._source.position('se') (x5,y5) = self._dest.position('ne') pd = SVG.pathdata() pd.move(x0,y0) (x1,y1) = (x0+UNIT,y0+UNIT) (x2,y2) = (x0+UNIT,y0+2*UNIT) (x3,y3) = (x5+UNIT,y5-2*UNIT) (x4,y4) = (x5+UNIT,y5-UNIT) if x2 < x4: pd.qbezier(x1,y1,x2,y2) pd.line(x3,y3) pd.qbezier(x4,y4,x5,y5) else: pd.qbezier(x0+UNIT,(y5+y0)/2,x5,y5) self._extent = (abs(x5-x0),abs(y5-y0)) self._widget = SVG.path(pd, 'none', self._color, self._parent.strokewidth()) self._widget.attributes['stroke-dasharray']='5, 5'
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 == 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 build(self): if self._source.branch() == self._dest.branch(): self._widget = None self._parent.env.log.warn("Invalid operation") return # get the position of the changeset to tie (xs,ys) = self._source.position() (xe,ye) = self._dest.position() # swap start and end points so that xs < xe if xs > xe: head = True (self._source, self._dest) = (self._dest, self._source) (xs,ys) = self._source.position() (xe,ye) = self._dest.position() else: head = False xbranches = self._parent.xsvgbranches(self._source, self._dest) # find which points on the changeset widget are used for connections if xs < xe: ss = 'e' se = 'w' else: ss = 'w' se = 'e' ps = self._source.position(ss) pe = self._dest.position(se) # compute the straight line from start to end widgets a = (ye-ys)/(xe-xs) b = ys-(a*xs) bz = [] # compute the points through which the 'operation' curve should go (xct,yct) = (ps[0],ps[1]) points = [(xct,yct)] for br in xbranches: x = br.vaxis() y = (a*x)+b ycu = ycd = None schangesets = br.svgchangesets() schangesets.sort() # add an invisible changeset in place of the branch header to avoid # special case for the first changeset hpos = br.header().position() hchg = SvgBaseChangeset(br, 0, (hpos[0], hpos[1]+3*UNIT/2)) schangesets.append(hchg) schangesets.reverse() pc = None for c in schangesets: # find the changesets which are right above and under the # selected point, and store their vertical position yc = c.position()[1] if yc < y: ycu = yc if yc >= y: ycd = yc if not ycu: if pc: ycu = pc.position()[1] elif c != schangesets[-1]: ycu = schangesets[-1].position()[1] break pc = c if not ycu or not ycd: pass # in this case, we need to create a virtual point (TODO) else: xt = x yt = (ycu+ycd)/2 if a != 0: a2 = -1/a b2 = yt - a2*xt xl = (b2-b)/(a-a2) yl = a2*xl + b2 nx = xt-xl ny = yt-yl dist = sqrt(nx*nx+ny*ny) radius = (3*c.extent()[1])/2 add_point = dist < radius else: add_point = True # do not insert a point if the ideal curve is far enough from # an existing changeset if add_point: # update the vertical position for the bezier control # point with the point that stands between both closest # changesets (xt,yt) = self._parent.fixup_point((xt,yt)) points.append((xt,yt)) if head: points.append(pe) else: points.append((pe[0]-UNIT,pe[1])) # now compute the qbezier curve pd = SVG.pathdata() pd.move(points[0][0],points[0][1]) if head: pd.line(points[0][0]+UNIT,points[0][1]) for i in range(len(points)-1): (xl,yl) = points[i] (xr,yr) = points[i+1] (xi,yi) = ((xl+xr)/2,(yl+yr)/2) pd.qbezier(xl+2*UNIT,yl,xi,yi) pd.qbezier(xr-2*UNIT,yr,xr,yr) if not head: pd.line(pe[0],pe[1]) self._widget = SVG.path(pd, 'none', self._color, self._parent.strokewidth()) self._widget.attributes['marker-%s' % (head and 'start' or 'end') ] = \ self._parent.svgarrow(self._color, head) if self._classes: self._widget.attributes['class'] = ' '.join(self._classes)
def build(self): SvgBaseChangeset.build(self) (fgc, bgc) = (self._strokecolor, self._fillcolor) txc = self._textcolor if 'firstchangeset' in self._classes: (fgc, bgc) = (bgc, fgc) if 'lastchangeset' in self._classes: bgc = SvgColor('black') txc = SvgColor('white') widgets = [] if self._shape == 'circle': widgets.append(SVG.circle(self._position[0], self._position[1], self._radius, bgc, fgc, self._parent.strokewidth())) if self._enhance: (x,y) = self._position (d,hr) = (self._radius*SQRT3/2, self._radius/2) widgets.append(SVG.line(x-d,y-hr,x+d,y-hr, fgc, self._parent.strokewidth())) widgets.append(SVG.line(x-d,y+hr,x+d,y+hr, fgc, self._parent.strokewidth())) elif self._shape == 'square': r = UNIT/6 size = self._radius-r widgets.append(SVG.rect(self._position[0]-size, self._position[1]-size, 2*size, 2*size, bgc, fgc, self._parent.strokewidth())) outline.attributes['rx'] = r outline.attributes['ry'] = r elif self._shape == 'hexa': (x,y) = self._position (r,hr) = (self._radius, self._radius/2) pd = SVG.pathdata() pd.move(x,y-r) pd.line(x+r,y-hr) pd.line(x+r,y+hr) pd.line(x,y+r) pd.line(x-r,y+hr) pd.line(x-r,y-hr) pd.line(x,y-r) widgets.append(SVG.path(pd, bgc, fgc, self._parent.strokewidth())) else: raise AssertionError, \ "unsupported changeset shape (%d)" % self._revision title = SVG.text(self._position[0], self._position[1] + UNIT/6, str(self._revision), self._parent.fontsize(), self._parent.fontname()) title.attributes['style'] = 'fill:%s; text-anchor: middle' % txc.rgb() widgets.append(title) g = SVG.group('grp%d' % self._revision, elements=widgets) link = "%s/changeset/%d" % (self._parent.urlbase(), self._revision) self._link = SVG.link(link, elements=[g]) if self._revision: self._link.attributes['style'] = \ 'color: %s; background-color: %s' % \ (self._strokecolor, self._fillcolor) self._link.attributes['id'] = 'rev%d' % self._revision self._link.attributes['class'] = ' '.join(self._classes)
def getElements(self, x, y, map_node2height ): t = self.mTree.get_terminals() elements = [] ## print locations if self.mPrintLocation: for i in range(len(t)): node_id1 = t[i] taxon1 = self.mTree.node(node_id1).data.taxon y1 = map_node2height[node_id1] + y elements.append( SVGdraw.text( x, y1, str(self.mMapId2Location[taxon1]), self.mFontSize, self.mFont, stroke = "rgb(%i,%i,%i)" % BLACK, text_anchor = "left" )) ## print connectors for i in range(len(t)-1): node_id1 = t[i] taxon1 = self.mTree.node(node_id1).data.taxon y1 = map_node2height[node_id1] + y for j in range(i+1, len(t)): node_id2 = t[j] taxon2 = self.mTree.node(node_id2).data.taxon if self.mExtractSpecies: species1 = self.mExtractSpecies(taxon1) species2 = self.mExtractSpecies(taxon2) if species1 != species2: continue if species1 not in self.mMapSpecies2Colour: self.mMapSpecies2Colour[species1] = COLOURS[len(self.mMapSpecies2Colour) % len(COLOURS) ] colour = self.mMapSpecies2Colour[species1] else: colour = self.mDefaultColour l1 = self.mMapId2Location[taxon1] l2 = self.mMapId2Location[taxon2] if l1.contig != l2.contig: continue if self.mMaxSeparation: s = min( abs(l1.mFrom - l2.mTo), abs(l1.mTo - l2.mFrom)) if s >= self.mMaxSeparation: continue y2 = map_node2height[node_id2] + y distance = y2 - y1 d = SVGdraw.pathdata( x, y1 ) d.line( x + self.mTickWidth, y1 ) d.ellarc( distance, distance, 0, 0, 1, x + self.mTickWidth, y2 ) d.line( x, y2 ) e = SVGdraw.path( d, fill = "none", stroke = "rgb(%i,%i,%i)" % colour, stroke_width = 1 ) elements.append( e ) return elements