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)
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
    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)
Esempio n. 5
0
 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)
Esempio n. 6
0
 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)
Esempio n. 7
0
	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()
Esempio n. 8
0
 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)
Esempio n. 9
0
    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()
Esempio n. 10
0
    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)
Esempio n. 11
0
    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 )
Esempio n. 12
0
	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)
Esempio n. 13
0
 def __init__(self, desc=None):
     self.sd = SVGdraw.svg()
Esempio n. 14
0
    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
Esempio n. 15
0
    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