def writeToFile(self, outfile): """write svg image to file. """ self.finalizePlot() self.mRoot = SVGdraw.drawing() self.mDraw = SVGdraw.svg( (0, 0, self.mPageWidth, self.mPageHeight ) , "100%", "100%" ) kk = self.mElements.keys() kk.sort() kk.reverse() for k in kk: for e in self.mElements[k]: self.mDraw.addElement( e ) self.mRoot.setSVG(self.mDraw) tfile = tempfile.mktemp() self.mRoot.toXml( tfile ) lines = open(tfile,"r").readlines() outfile.write(string.join(lines,"")) outfile.write("\n") os.remove(tfile)
def errorsvg(msg): s=SVGdraw.svg(width='5cm', height='1cm') s.addElement(SVGdraw.text(0,0,msg)) d=SVGdraw.drawing() d.svg=s print d.toXml() return s
def errorsvg(msg): s = SVGdraw.svg(width='5cm', height='1cm') s.addElement(SVGdraw.text(0, 0, msg)) d = SVGdraw.drawing() d.svg = s print d.toXml() return s
def writeToFile(self, outfile): """write svg image to file. """ self.finalizePlot() kk = self.mElements.keys() kk.sort() kk.reverse() ## make sure the image size is ok min_x, min_y, max_x, max_y = 0, 0, 0, 0 for k in kk: for e in self.mElements[k]: for x in ('x', 'x2', 'x1'): if x in e.attributes: v = e.attributes[x] min_x = min(min_x, v ) max_x = max(max_x, v ) for y in ('y', 'y2', 'y1'): if y in e.attributes: v = e.attributes[y] min_y = min(min_y, v ) max_y = max(max_y, v ) min_x, min_y = int(math.floor(min_x)), int(math.floor(min_y)) max_x, max_y = int(math.floor(max_x)), int(math.floor(max_y)) for k in kk: for e in self.mElements[k]: for x in ('x', 'x2', 'x1'): if x in e.attributes: e.attributes[x] -= min_x for x in ('y', 'y2', 'y1'): if y in e.attributes: e.attributes[y] -= min_y ## now add all the elements self.mRoot = SVGdraw.drawing() self.mDraw = SVGdraw.svg( (0, 0, self.mPageWidth - min_x, self.mPageHeight - min_y ) , "100%", "100%" ) for k in kk: for e in self.mElements[k]: self.mDraw.addElement( e ) self.mRoot.setSVG(self.mDraw) tfile = tempfile.mktemp() self.mRoot.toXml( tfile ) lines = open(tfile,"r").readlines() outfile.write(string.join(lines,"")) outfile.write("\n") os.remove(tfile)
def render(self, scale=1, width=None, height=None, linkparent=False): """Render the revision tree""" self._svg = SVG.svg((0, 0, self._extent[0], self._extent[1]), scale * self._extent[0], scale * self._extent[1]) self._arrows.render() # FIXME: only two levels for enhancers (background, foreground) map(lambda e: e.render(self._addons[e], 1), self.enhancers) map(lambda b: b.render(), self._svgbranches.values()) map(lambda e: e.render(self._addons[e], 2), self.enhancers)
def render(self, scale=1, width=None, height=None, linkparent=False): """Render the revision tree""" self._svg = SVG.svg((0,0,self._extent[0],self._extent[1]), scale*self._extent[0], scale*self._extent[1]) self._arrows.render() # FIXME: only two levels for enhancers (background, foreground) map(lambda e: e.render(self._addons[e], 1), self.enhancers) map(lambda b: b.render(), self._svgbranches.values()) map(lambda e: e.render(self._addons[e], 2), self.enhancers)
def save(self, filename=None): document = SVGdraw.drawing() width = str(self.width) + self.units height = str(self.height) + self.units canvas = SVGdraw.svg(None, width, height) self.makeGrid(canvas) document.setSVG(canvas) if filename: document.toXml(filename) else: return document.toXml()
def render(self, scale=1.0): """Render the revision tree""" self._svg = SVG.svg((0, 0, self._extent[0], self._extent[1]), scale*self._extent[0], scale*self._extent[1], True, id='svgbox') self._arrows.render() map(lambda e: e.render(IRevtreeEnhancer.ZBACK), self._addons) map(lambda b: b.render(IRevtreeEnhancer.ZBACK), self._svgbranches.values()) map(lambda e: e.render(IRevtreeEnhancer.ZMID), self._addons) map(lambda b: b.render(IRevtreeEnhancer.ZMID), self._svgbranches.values()) map(lambda e: e.render(IRevtreeEnhancer.ZFORE), self._addons) map(lambda b: b.render(IRevtreeEnhancer.ZFORE), self._svgbranches.values()) dbgDump(self._svg)
def save(self, filename=None): document = SVGdraw.drawing() width = str(self.width) + self.units height = str(self.height) + self.units canvas = SVGdraw.svg(None, width, height) canvas.addElement(SVGdraw.description(self.description)) self.makeGrid(canvas) document.setSVG(canvas) if filename: document.toXml(filename) else: return document.toXml()
def plot(self, filename, segments, workspace, samples): nlines = 2 + len(samples) height = nlines * self.linewidth * self.linespace width = workspace.max() print(height, width) root = SVGdraw.drawing() canvas = SVGdraw.svg((0, 0, width, heigh), "100%", "100%") root.setSVG(canvas) root.toXml(filename)
def plot(self, filename, segments, workspace, samples ): nlines = 2 + len(samples) height = nlines * self.linewidth * self.linespace width = workspace.max() print height, width root = SVGdraw.drawing() canvas = SVGdraw.svg( (0, 0, width, heigh), "100%", "100%") root.setSVG( canvas ) root.toXml( filename )
def toSVG(self): #modification du maximum en X : depend du nombre d'element global XMAX XMAX = len(self.infos)*(BAR_THICKNESS+SPACE) # creation du document doc=SVGdraw.drawing() svg=SVGdraw.svg(None, '100%','100%') # creation des patterns pour les axes et la grille axeX = SVGdraw.pattern(id="axeX",width="20",height="10",patternUnits="userSpaceOnUse") axeX.addElement(SVGdraw.path("M 0 0, L 0 10","none","black","0.25")) axeX.addElement(SVGdraw.path("M 10 10, V 5","none","lightgray","0.25")) axeY = SVGdraw.pattern(id="axeY",width="10",height="20",patternUnits="userSpaceOnUse") axeY.addElement(SVGdraw.path("M 0 0, L 10 0","none","black","0.25")) axeY.addElement(SVGdraw.path("M 5 10, L 10 10","none","lightgray","0.25")) grid = SVGdraw.pattern(id="grid",width="10",height="10",patternUnits="userSpaceOnUse") grid.addElement(SVGdraw.path("M 0 0, L 10 0, L 10 10,L 0 10, L 0 0","none","lightgray","0.25")) defs=SVGdraw.defs() defs.addElement(axeX) defs.addElement(axeY) defs.addElement(grid) svg.addElement(defs) group=SVGdraw.group(transform="translate(130,130) scale(1,-1)") # dessin de la grille de fond group.addElement(SVGdraw.rect(0,0,XMAX,YMAX,"url(#grid)","lightgray","0.25")) # dessin des axes group.addElement(SVGdraw.rect(0,-10,XMAX,10,"url(#axeX)")) group.addElement(SVGdraw.rect(-10,0,10,YMAX,"url(#axeY)")) group.addElement(SVGdraw.line(0,0,XMAX,0,"black",1)) group.addElement(SVGdraw.line(0,0,0,YMAX,"black",1)) # dessin des fleches des axes group.addElement(SVGdraw.polygon([[-3,YMAX],[3,YMAX],[0,YMAX+10]], "black","white")) group.addElement(SVGdraw.polygon([[XMAX,-3],[XMAX,3],[XMAX+10,0]], "black","white")) textgroup=SVGdraw.group(transform="scale(1,-1)") # graduations for y in range(0,YMAX+STEP,STEP): textgroup.addElement(SVGdraw.text(-STEP,y, str(y), 8, text_anchor="middle", transform="translate(0,%d)"%(-y*2))) textgroup.addElement(SVGdraw.text(0,YMAX+SPACE, r"%", 8, transform="translate(0,%d)"%(-(YMAX+SPACE)*2))) # ajout de la legende principale legendText = "Repertoire %s - taille %.02f ko"%(self.rootName,float(self.totalSize/1024.0)) textgroup.addElement(SVGdraw.text(XMAX,YMAX+3*SPACE, legendText,12, "verdana", text_anchor="end", fill="darkblue",transform="translate(0,%d)"%(-(YMAX+3*SPACE)*2))) group.addElement(textgroup) # tri des elements selon la taille occupee self.infos.sort(self.tupleCmp) xincr=0 #self.infos for (name,size) in self.infos: # calcul du pourcentage de place occupe pourcent = (100.0*float(size))/float(self.totalSize) height=int(pourcent*YMAX/100); # insertion du texte de l'emplacement sur le disque et de la taille occupee en Ko legendText = "%s (%### ###.02f ko)"%(name,float(size/1024.0)) legend = SVGdraw.text(xincr+BAR_THICKNESS/2, -10,legendText,8,"verdana",text_anchor="begin",fill="blue") legend.attributes["transform"]="scale(1,-1) translate(0,20) rotate(45,%d,-10)"%(xincr+BAR_THICKNESS/2) group.addElement(legend) #insertion de la barre representant le pourcentage group.addElement(SVGdraw.rect(xincr,0,BAR_THICKNESS, height,"green","black",opacity=0.5)) #insertion de la taille en pourcentage a gauche de la barre pourcentText=SVGdraw.text(xincr+BAR_THICKNESS/2, height+SPACE,"%02.01f%% "%pourcent,6, "arial", text_anchor="middle", fill="black") pourcentText.attributes["transform"]="scale(1,-1) translate(0,-%d)"%((height+SPACE)*2) group.addElement(pourcentText) # augmentation du l'abscisse en X xincr = xincr+BAR_THICKNESS+SPACE svg.addElement(group) doc.setSVG(svg) doc.toXml(self.svgURL)
def __init__(self, desc=None): self.sd = SVGdraw.svg()
def svgout(self, stroke_width=0.3, scale=20, circle_radius=0.3, startat=None, coloriter=None, crossings=True, circradius=None, circscale=1): # if circradius is some positive number, try to draw a circular(!) diagram # circscale is how much to scale the y-dimension by (how thick a circle) # try: # if type(SVGdraw)!=type(__builtins__): # raise Exception("SVGdraw not a module?") # return None # except NameError: # raise Exception("No SVGDraw found") # return None cols = [ '#000000', '#800000', '#808000', '#008080', '#000080', '#ff2000', '#ffff20', '#20ffff', '#0020ff', '#ff0080', '#ff8000', '#8000ff', '#80ff00' ] if circradius: sz = (2 * self.ymax * circscale + 2 + 2 * circradius) svg = SVGdraw.svg( width="%dpx" % (sz * scale), height="%dpx" % (sz * scale), viewBox=[-sz + self.xmodulus / 2.0, -sz, 2 * sz, 2 * sz]) def transform(x, y): # Have to flip it over... r = self.ymax * circscale + circradius - y * circscale theta = 2 * math.pi * x / self.xmodulus - math.pi return [ sz / 2 + r * math.cos(theta), sz / 2 + r * math.sin(theta) ] else: svg = SVGdraw.svg( width="%dpx" % ((self.xmodulus + 2) * scale), height="%dpx" % ((self.ymax + 2) * scale), viewBox=[-1, -1, self.xmodulus + 2, self.ymax + 2]) def transform(x, y): return [x, y] defs = SVGdraw.defs(id="defs") plusmask = SVGdraw.SVGelement("mask", attributes={"id": "plusmask"}) minusmask = SVGdraw.SVGelement("mask", attributes={"id": "minusmask"}) if circradius: sz = 1 + 2 * self.ymax * circscale + 2 * circradius # Whatever, something big. r = SVGdraw.rect(x=-sz, y=-sz, width=sz * 2, height=sz * 2, fill='white') else: r = SVGdraw.rect(x=-1, y=-1, width=self.xmodulus + 2, height=self.ymax + 2, fill='white') plusmask.addElement(r) minusmask.addElement(r) defs.addElement(plusmask) defs.addElement(minusmask) svg.addElement(defs) maingroup = SVGdraw.group(id="main") # I've come to expect them this way up... maingroup.attributes['transform']='scale(1,-1) translate(0,%d)'% \ (-self.ymax) svg.addElement(maingroup) # Positive slopes and negative slopes. plus = SVGdraw.group(id="plus", mask="url(#plusmask)") minus = SVGdraw.group(id="minus", mask="url(#minusmask)") maingroup.addElement(plus) maingroup.addElement(minus) circgroup = SVGdraw.group(id="circgroup") maingroup.addElement(circgroup) strands = self.strands(self.pivots[0]) circuit = None if coloriter is None: if len(strands) > 1: # Multistranded; color it by strand. def multicoloriter(): counter = 0 lastcircuit = None while True: if circuit != lastcircuit: lastcircuit = circuit counter += 1 yield cols[counter % len(cols)] coloriter = multicoloriter() else: def singlecoloriter(): # for singlestranders! colcounter = 0 colordiv = len(self.pivots) / 6 while True: yield cols[int(colcounter / colordiv) % len(cols)] colcounter += 1 coloriter = singlecoloriter() for circuit in strands: # If there's a startat parameter, and it appears in this list, # slosh the list around so it's first if startat and startat in circuit: ind = circuit.index(startat) circuit = circuit[ind:] + circuit[0:ind] for i in range(0, len(circuit)): here = circuit[i] nxt = circuit[(i + 1) % len(circuit)] col = coloriter.next() if type(col) == int: # let iterator generate indexes col = cols[col % len(cols)] if circradius: path = [here, nxt] else: path = self.pathbetween(here, nxt) pathstring = "" for j in range(0, len(path), 2): # Had hoped that transform() would have been enough, but we need # to go through all the intermediate lattice-points when doing # circular plots, to curve around in the right direction. if circradius: betweens = self.pointsbetween(path[j], path[j + 1]) pathstring += " M %f %f " % tuple( transform(path[j].x, path[j].y)) for k in range(0, len(betweens)): pathstring+=" L %f %f "% \ tuple(transform(betweens[k].x,betweens[k].y)) pathstring+="L %f %f "% \ tuple(transform(path[j+1].x, path[j+1].y)) else: pathstring+=" M %f %f L %f %f"% \ (tuple(transform(path[j].x,path[j].y)+ transform(path[j+1].x,path[j+1].y))) pathelt = SVGdraw.path(pathstring, stroke_width=stroke_width, stroke=col, fill="none") if self.slopebetween(here, nxt) > 0: plus.addElement(pathelt) else: minus.addElement(pathelt) for i in self.pivots: cr = transform(i.x, i.y) c = SVGdraw.circle(cx=cr[0], cy=cr[1], r=circle_radius, fill='black') circgroup.addElement(c) if not circradius: # Mark the wraparound point. circgroup.addElement(SVGdraw.path("M 0 -1 l 0 %d M %d -1 l 0 %d"% \ (self.ymax+2,self.xmodulus, self.ymax+2), stroke='black', stroke_width=0.03)) # Somehow I want to *note* when a knot is single-strand or # multistrand. circgroup.addElement( SVGdraw.text(x=0.2, y=0, text=str(len(strands)), fill='#000408', font_size=1, font_family='sans-serif', transform='scale(1,-1)')) if crossings: # Try multistrand crossings? (not working right) # Need *ALL* the crossing points though. oncircuit = [] for circuit in strands: oncircuit.extend(self.oncircuit(circuit)) masked = set() over = 0 masks = [minusmask, plusmask] # How about this? For each horizontal line _that has intersections on it_, # all crossings go in one direction, and that direction alternates. # # How do we find those lines? points = [] for circuit in strands: for i in range(0, len(circuit)): here = circuit[i] nxt = circuit[(i + 1) % len(circuit)] points += self.pointsbetween(here, nxt) heights = [] howmanyhits = dict() for p in points: howmanyhits[p] = howmanyhits.get(p, 0) + 1 howmanyhits = [(p, howmanyhits[p]) for p in howmanyhits.keys()] howmanyhits = filter((lambda x: x[1] > 1), howmanyhits) heights = [x[0].y for x in howmanyhits] heights.sort() # No "sort unique" so just keep track of the last one we saw and skip it. # DOESN'T WORK EITHER BUT BETTER THAN BEFORE XXXXXX # (testing with python ./knots.py -l 18 17 6 32 6 37) Works with more # symmetrical designs. last = None for h in heights: if h == last: continue last = h mask = masks[over] over = 1 - over for x in range(0, self.xmodulus, 2): p = Point((x if not h % 2 else x + 1), h, self) if p in self.pivots: continue # Skip pivot-points. tp1 = transform(p.x - 0.5, p.y - 0.5) tp2 = transform(p.x - 0.5, p.y + 0.5) tp3 = transform(p.x + 0.5, p.y + 0.5) tp4 = transform(p.x + 0.5, p.y - 0.5) tp = transform(p.x, p.y) if circradius: r = SVGdraw.circle(fill="black", cx=tp[0], cy=tp[1], r=0.6) else: angle = 45 r=SVGdraw.polygon(fill="black", points=[tp1,tp2,tp3,tp4], transform="rotate(%f,%f,%f)"% \ (angle, tp[0], tp[1])) mask.addElement(r) # maingroup.addElement(r) # If it's on the edge, duplicate it on the other side # for ease of viewing. if p.x == 0 and not circradius: mask.addElement( SVGdraw.rect(x=self.xmodulus - 0.5, y=p.y - 0.5, width=1, height=1, fill="#111", transform="rotate(45,%d,%d)" % (self.xmodulus, p.y))) return svg
def svgout(self,stroke_width=0.3,scale=20,circle_radius=0.3, startat=None,coloriter=None,crossings=True,circradius=None,circscale=1): # if circradius is some positive number, try to draw a circular(!) diagram # circscale is how much to scale the y-dimension by (how thick a circle) # try: # if type(SVGdraw)!=type(__builtins__): # raise Exception("SVGdraw not a module?") # return None # except NameError: # raise Exception("No SVGDraw found") # return None cols=['#000000', '#800000', '#808000', '#008080', '#000080', '#ff2000', '#ffff20', '#20ffff', '#0020ff', '#ff0080', '#ff8000', '#8000ff', '#80ff00'] if circradius: sz=(2*self.ymax*circscale+2+2*circradius) svg=SVGdraw.svg(width="%dpx"%(sz*scale), height="%dpx"%(sz*scale), viewBox=[-sz+self.xmodulus/2.0, -sz, 2*sz, 2*sz]) def transform(x,y): # Have to flip it over... r=self.ymax*circscale+circradius-y*circscale theta=2*math.pi*x/self.xmodulus-math.pi return [sz/2+r*math.cos(theta), sz/2+r*math.sin(theta)] else: svg=SVGdraw.svg(width="%dpx"%((self.xmodulus+2)*scale), height="%dpx"%((self.ymax+2)*scale), viewBox=[-1, -1, self.xmodulus+2, self.ymax+2]) def transform(x,y): return [x,y] defs=SVGdraw.defs(id="defs") plusmask=SVGdraw.SVGelement("mask", attributes={"id":"plusmask"}) minusmask=SVGdraw.SVGelement("mask", attributes={"id":"minusmask"}) if circradius: sz=1+2*self.ymax*circscale+2*circradius # Whatever, something big. r=SVGdraw.rect(x=-sz, y=-sz, width=sz*2,height=sz*2,fill='white') else: r=SVGdraw.rect(x=-1,y=-1,width=self.xmodulus+2,height=self.ymax+2, fill='white') plusmask.addElement(r) minusmask.addElement(r) defs.addElement(plusmask) defs.addElement(minusmask) svg.addElement(defs) maingroup=SVGdraw.group(id="main") # I've come to expect them this way up... maingroup.attributes['transform']='scale(1,-1) translate(0,%d)'% \ (-self.ymax) svg.addElement(maingroup) # Positive slopes and negative slopes. plus=SVGdraw.group(id="plus",mask="url(#plusmask)") minus=SVGdraw.group(id="minus",mask="url(#minusmask)") maingroup.addElement(plus) maingroup.addElement(minus) circgroup=SVGdraw.group(id="circgroup") maingroup.addElement(circgroup) strands=self.strands(self.pivots[0]) circuit=None if coloriter is None: if len(strands)>1: # Multistranded; color it by strand. def multicoloriter(): counter=0 lastcircuit=None while True: if circuit != lastcircuit: lastcircuit=circuit counter+=1 yield cols[counter%len(cols)] coloriter=multicoloriter() else: def singlecoloriter(): # for singlestranders! colcounter=0 colordiv=len(self.pivots)/6 while True: yield cols[int(colcounter/colordiv)%len(cols)] colcounter+=1 coloriter=singlecoloriter() for circuit in strands: # If there's a startat parameter, and it appears in this list, # slosh the list around so it's first if startat and startat in circuit: ind=circuit.index(startat) circuit=circuit[ind:]+circuit[0:ind] for i in range(0,len(circuit)): here=circuit[i] nxt=circuit[(i+1)%len(circuit)] col=coloriter.next() if type(col)==int: # let iterator generate indexes col=cols[col%len(cols)] if circradius: path=[here,nxt] else: path=self.pathbetween(here,nxt) pathstring="" for j in range(0,len(path),2): # Had hoped that transform() would have been enough, but we need # to go through all the intermediate lattice-points when doing # circular plots, to curve around in the right direction. if circradius: betweens=self.pointsbetween(path[j],path[j+1]) pathstring+=" M %f %f "%tuple(transform(path[j].x,path[j].y)) for k in range(0,len(betweens)): pathstring+=" L %f %f "% \ tuple(transform(betweens[k].x,betweens[k].y)) pathstring+="L %f %f "% \ tuple(transform(path[j+1].x, path[j+1].y)) else: pathstring+=" M %f %f L %f %f"% \ (tuple(transform(path[j].x,path[j].y)+ transform(path[j+1].x,path[j+1].y))) pathelt=SVGdraw.path(pathstring,stroke_width=stroke_width, stroke=col,fill="none") if self.slopebetween(here,nxt)>0: plus.addElement(pathelt) else: minus.addElement(pathelt) for i in self.pivots: cr=transform(i.x, i.y) c=SVGdraw.circle(cx=cr[0], cy=cr[1], r=circle_radius, fill='black') circgroup.addElement(c) if not circradius: # Mark the wraparound point. circgroup.addElement(SVGdraw.path("M 0 -1 l 0 %d M %d -1 l 0 %d"% \ (self.ymax+2,self.xmodulus, self.ymax+2), stroke='black', stroke_width=0.03)) # Somehow I want to *note* when a knot is single-strand or # multistrand. circgroup.addElement(SVGdraw.text(x=0.2,y=0, text=str(len(strands)), fill='#000408', font_size=1, font_family='sans-serif', transform='scale(1,-1)')) if crossings: # Try multistrand crossings? (not working right) # Need *ALL* the crossing points though. oncircuit=[] for circuit in strands: oncircuit.extend(self.oncircuit(circuit)) masked=set() over=0 masks=[minusmask,plusmask] # How about this? For each horizontal line _that has intersections on it_, # all crossings go in one direction, and that direction alternates. # # How do we find those lines? points=[] for circuit in strands: for i in range(0,len(circuit)): here=circuit[i] nxt=circuit[(i+1)%len(circuit)] points+=self.pointsbetween(here,nxt) heights=[] howmanyhits=dict() for p in points: howmanyhits[p]=howmanyhits.get(p,0)+1 howmanyhits=[(p,howmanyhits[p]) for p in howmanyhits.keys()] howmanyhits=filter((lambda x: x[1]>1), howmanyhits) heights=[x[0].y for x in howmanyhits] heights.sort() # No "sort unique" so just keep track of the last one we saw and skip it. # DOESN'T WORK EITHER BUT BETTER THAN BEFORE XXXXXX # (testing with python ./knots.py -l 18 17 6 32 6 37) Works with more # symmetrical designs. last=None for h in heights: if h==last: continue last=h mask=masks[over] over=1-over for x in range(0,self.xmodulus,2): p=Point((x if not h%2 else x+1),h,self) if p in self.pivots: continue # Skip pivot-points. tp1=transform(p.x-0.5, p.y-0.5) tp2=transform(p.x-0.5, p.y+0.5) tp3=transform(p.x+0.5, p.y+0.5) tp4=transform(p.x+0.5, p.y-0.5) tp=transform(p.x, p.y) if circradius: r=SVGdraw.circle(fill="black", cx=tp[0], cy=tp[1], r=0.6) else: angle=45 r=SVGdraw.polygon(fill="black", points=[tp1,tp2,tp3,tp4], transform="rotate(%f,%f,%f)"% \ (angle, tp[0], tp[1])) mask.addElement(r) # maingroup.addElement(r) # If it's on the edge, duplicate it on the other side # for ease of viewing. if p.x==0 and not circradius: mask.addElement(SVGdraw.rect(x=self.xmodulus-0.5, y=p.y-0.5, width=1, height=1, fill="#111", transform= "rotate(45,%d,%d)"% (self.xmodulus,p.y))) return svg