def solid_shapes(): drawing = Drawing(width=400, height=200) rectangle = Rect(10, 10, 100, 100) rectangle.fillColor = colors.blue drawing.add(rectangle) ellipse = Ellipse(100, 50, 50, 25) ellipse.fillColor = colors.red drawing.add(ellipse) circle = Circle(50, 170, 25) circle.fillColor = colors.green drawing.add(circle) wedge = Wedge(150, 150, 65, startangledegrees=0, endangledegrees=45) wedge.fillColor = colors.yellow drawing.add(wedge) poly = Polygon(points=[250, 150, 280, 150, 280, 100, 250, 100 ]) poly.fillColor = colors.purple drawing.add(poly) drawing.save(formats=['pdf'], outDir='.', fnRoot='solid_shapes')
def __init__(self,width=400,height=400,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self.transform = (1,0,0,1,0,0) self.add(Polygon(points=[108.3032,252.9412,200,288.2353,291.6968,252.9412,306.9796,138.2353,200,58.82353,93.02039,138.2353,108.3032,252.9412],fillColor=Color(1,.972549,.862745,1),fillOpacity=None,strokeColor=None,strokeWidth=0,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(Polygon(points=[85.37899,266.1765,200,252.9412,261.1312,235.2941,276.414,155.8824,200,94.11765,131.2274,160.2941,85.37899,266.1765],fillColor=Color(0,1,1,1),fillOpacity=None,strokeColor=None,strokeWidth=0,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(Polygon(points=[138.8688,235.2941,200,261.7647,261.1312,235.2941,329.9038,125,200,164.7059,108.3032,147.0588,138.8688,235.2941],fillColor=Color(.596078,.984314,.596078,1),fillOpacity=None,strokeColor=None,strokeWidth=0,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(PolyLine(points=[108.3032,252.9412,200,288.2353,291.6968,252.9412,306.9796,138.2353,200,58.82353,93.02039,138.2353,108.3032,252.9412],strokeColor=Color(1,.972549,.862745,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(PolyLine(points=[85.37899,266.1765,200,252.9412,261.1312,235.2941,276.414,155.8824,200,94.11765,131.2274,160.2941,85.37899,266.1765],strokeColor=Color(0,1,1,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(PolyLine(points=[138.8688,235.2941,200,261.7647,261.1312,235.2941,329.9038,125,200,164.7059,108.3032,147.0588,138.8688,235.2941],strokeColor=Color(.596078,.984314,.596078,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(Line(200,200,200,350,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) self.add(Line(200,200,329.9038,275,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) self.add(Line(200,200,329.9038,125,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) self.add(Line(200,200,200,50,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) self.add(Line(200,200,70.09619,125,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) self.add(Line(200,200,70.09619,275,strokeColor=Color(0,0,0,1),strokeWidth=.5,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=(2,2),strokeOpacity=None)) v0=self._nn(Group()) v0.transform = (1,0,0,1,200,357.5) v0.add(String(-2.22,-4,'a',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,336.399,278.75) v0.add(String(-2.5,-4,'b',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,336.399,121.25) v0.add(String(-2.22,-4,'c',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,200,42.5) v0.add(String(-2.5,-4,'d',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,63.601,121.25) v0.add(String(-2.22,-4,'e',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,63.601,278.75) v0.add(String(-1.665,-4,'f',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
def convertPolyline(self, node): getAttr = node.getAttribute points = getAttr("points") points = points.replace(',', ' ') points = points.split() points = list(map(self.attrConverter.convertLength, points)) if len(points) % 2 != 0 or len(points) == 0: # Odd number of coordinates or no coordinates, invalid polyline return None polyline = PolyLine(points) self.applyStyleOnShape(polyline, node) has_fill = self.attrConverter.findAttr(node, 'fill') not in ('', 'none') if has_fill: # ReportLab doesn't fill polylines, so we are creating a polygon # polygon copy of the polyline, but without stroke. group = Group() polygon = Polygon(points) self.applyStyleOnShape(polygon, node) polygon.strokeColor = None group.add(polygon) group.add(polyline) return group return polyline
def makeFilledDiamond(x, y, size, color): "Make a filled diamond marker." d = size/2.0 poly = Polygon((x-d,y, x,y+d, x+d,y, x,y-d)) poly.strokeColor = color poly.fillColor = color return poly
def makeFilledDiamond(x, y, size, color): "Make a filled diamond marker." d = size / 2.0 poly = Polygon((x - d, y, x, y + d, x + d, y, x, y - d)) poly.strokeColor = color poly.fillColor = color return poly
def makeBackground(self): if self.background is not None: BG = self.background if isinstance(BG,Group): g = BG for bg in g.contents: bg.x = self.x bg.y = self.y bg.width = self.width bg.height = self.height else: g = Group() if type(BG) not in (type(()),type([])): BG=(BG,) for bg in BG: bg.x = self.x bg.y = self.y bg.width = self.width bg.height = self.height g.add(bg) return g else: strokeColor,strokeWidth,fillColor=self.strokeColor, self.strokeWidth, self.fillColor if (strokeWidth and strokeColor) or fillColor: g = Group() _3d_dy = getattr(self,'_3d_dy',None) x = self.x y = self.y h = self.height w = self.width if _3d_dy is not None: _3d_dx = self._3d_dx if fillColor and not strokeColor: from reportlab.lib.colors import Blacker c = Blacker(fillColor, getattr(self,'_3d_blacken',0.7)) else: c = strokeColor if not strokeWidth: strokeWidth = 0.5 if fillColor or strokeColor or c: bg = Polygon([x,y,x,y+h,x+_3d_dx,y+h+_3d_dy,x+w+_3d_dx,y+h+_3d_dy,x+w+_3d_dx,y+_3d_dy,x+w,y], strokeColor=strokeColor or c or grey, strokeWidth=strokeWidth, fillColor=fillColor) g.add(bg) g.add(Line(x,y,x+_3d_dx,y+_3d_dy, strokeWidth=0.5, strokeColor=c)) g.add(Line(x+_3d_dx,y+_3d_dy, x+_3d_dx,y+h+_3d_dy,strokeWidth=0.5, strokeColor=c)) fc = Blacker(c, getattr(self,'_3d_blacken',0.8)) g.add(Polygon([x,y,x+_3d_dx,y+_3d_dy,x+w+_3d_dx,y+_3d_dy,x+w,y], strokeColor=strokeColor or c or grey, strokeWidth=strokeWidth, fillColor=fc)) bg = Line(x+_3d_dx,y+_3d_dy, x+w+_3d_dx,y+_3d_dy,strokeWidth=0.5, strokeColor=c) else: bg = None else: bg = Rect(x, y, w, h, strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor) if bg: g.add(bg) return g else: return None
def draw_polygon(list_of_points, color=colors.lightgreen, border=None, colour=None, **kwargs): """Draw polygon. Arguments: - list_of_point - list of (x,y) tuples for the corner coordinates - color / colour - The color for the box Returns a closed path object, beginning at (x1,y1) going round the four points in order, and filling with the passed colour. """ # Let the UK spelling (colour) override the USA spelling (color) if colour is not None: color = colour del colour strokecolor, color = _stroke_and_fill_colors(color, border) xy_list = [] for (x, y) in list_of_points: xy_list.append(x) xy_list.append(y) return Polygon(deduplicate(xy_list), strokeColor=strokecolor, fillColor=color, strokewidth=0, **kwargs)
def draw(self): s = float(self.size) #abbreviate as we will use this a lot g = Group() # new algorithm from markers.StarFive R = float(self.size) / 2 r = R * sin(18 * (pi / 180.0)) / cos(36 * (pi / 180.0)) P = [] angle = 90 for i in xrange(5): for radius in R, r: theta = angle * (pi / 180.0) P.append(radius * cos(theta)) P.append(radius * sin(theta)) angle = angle + 36 # star specific bits star = Polygon(P, fillColor=self.fillColor, strokeColor=self.strokeColor, strokeWidth=s / 50) g.rotate(self.angle) g.shift(self.x + self.dx, self.y + self.dy) g.add(star) return g
def _Flag_CzechRepublic(self): s = _size g = Group() box = Rect(0, 0, s * 2, s, fillColor=colors.mintcream, strokeColor=colors.black, strokeWidth=0) g.add(box) redbox = Rect(0, 0, width=s * 2, height=s / 2, fillColor=colors.red, strokeColor=None, strokeWidth=0) g.add(redbox) bluewedge = Polygon(points=[0, 0, s, (s / 2), 0, s], fillColor=colors.darkblue, strokeColor=None, strokeWidth=0) g.add(bluewedge) return g
def _Flag_Palestine(self): s = _size g = Group() box = Rect(0, s/3, s*2, s/3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(box) greenbox = Rect(0, 0, width=s*2, height=s/3, fillColor = colors.limegreen, strokeColor = None, strokeWidth=0) g.add(greenbox) blackbox = Rect(0, 2*s/3, width=s*2, height=s/3, fillColor = colors.black, strokeColor = None, strokeWidth=0) g.add(blackbox) redwedge = Polygon(points = [ 0, 0, 2*s/3, (s/2), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redwedge) return g
def draw_cut_corner_box(point1, point2, corner=0.5, color=colors.lightgreen, border=None, **kwargs): """Draw a box with the corners cut off.""" x1, y1 = point1 x2, y2 = point2 if not corner: return draw_box(point1, point2, color, border) elif corner < 0: raise ValueError("Arrow head length ratio should be positive") strokecolor, color = _stroke_and_fill_colors(color, border) boxheight = y2 - y1 boxwidth = x2 - x1 x_corner = min(boxheight * 0.5 * corner, boxwidth * 0.5) y_corner = min(boxheight * 0.5 * corner, boxheight * 0.5) points = [ x1, y1 + y_corner, x1, y2 - y_corner, x1 + x_corner, y2, x2 - x_corner, y2, x2, y2 - y_corner, x2, y1 + y_corner, x2 - x_corner, y1, x1 + x_corner, y1 ] return Polygon( deduplicate(points), strokeColor=strokecolor, strokeWidth=1, strokeLineJoin=1, # 1=round fillColor=color, **kwargs)
def _Flag_Cuba(self): s = _size g = Group() for i in range(5): stripe = Rect(0, i*s/5, width=s*2, height=s/5, fillColor = [colors.darkblue, colors.mintcream][i%2], strokeColor = None, strokeWidth=0) g.add(stripe) redwedge = Polygon(points = [ 0, 0, 4*s/5, (s/2), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redwedge) star = Star() star.x = 2.5*s/10 star.y = s/2 star.size = 3*s/10 star.fillColor = colors.white g.add(star) box = Rect(0, 0, s*2, s, fillColor = None, strokeColor = colors.black, strokeWidth=0) g.add(box) return g
def draw_box(point1, point2, color=colors.lightgreen, border=None, colour=None, **kwargs): """Draw a box. Arguments: - point1, point2 - coordinates for opposite corners of the box (x,y tuples) - color /colour - The color for the box (colour takes priority over color) - border - Border color for the box Returns a closed path object, beginning at (x1,y1) going round the four points in order, and filling with the passed color. """ x1, y1 = point1 x2, y2 = point2 # Let the UK spelling (colour) override the USA spelling (color) if colour is not None: color = colour del colour strokecolor, color = _stroke_and_fill_colors(color, border) x1, y1, x2, y2 = min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2) return Polygon([x1, y1, x2, y1, x2, y2, x1, y2], strokeColor=strokecolor, fillColor=color, strokewidth=0, **kwargs)
def convert_polygon(self, node): points = attributes.convert_length_list(node_attr(node, "points")) if len(points) % 2 != 0 or len(points) == 0: _logger.warn("Invalid Polygon points: %s" % points) return None return Polygon(points)
def __init__(self,width=224,height=124,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) points = [122.0, 87.0, 122.0, 88.0, 123.0, 88.0, 123.0, 89.0, 124.0, 89.0, 124.0, 90.0, 126.0, 90.0, 126.0, 89.0, 128.0, 88.0, 128.0, 89.0, 129.0, 89.0, 129.0, 91.0, 128.0, 91.0, 128.0, 92.0, 130.0, 99.0, 130.0, 100.0, 129.0, 100.0, 126.0, 103.0, 125.0, 103.0, 125.0, 104.0, 126.0, 106.0, 130.0, 87.0, 129.0, 87.0, 129.0, 86.0, 126.0, 86.0, 126.0, 87.0] grp = Group(Polygon(points, fillColor=toColor('red'))) grp.scale(1, -1) grp.translate(0, -124) self.add(grp)
def _make_3d_line_info(G, x0, x1, y0, y1, z0, z1, theta_x, theta_y, fillColor, fillColorShaded=None, tileWidth=1, strokeColor=None, strokeWidth=None, strokeDashArray=None, shading=0.1): zwidth = abs(z1 - z0) xdepth = zwidth * theta_x ydepth = zwidth * theta_y depth_slope = xdepth == 0 and 1e150 or -ydepth / float(xdepth) x = float(x1 - x0) slope = x == 0 and 1e150 or (y1 - y0) / x c = slope > depth_slope and _getShaded(fillColor, fillColorShaded, shading) or fillColor zy0 = z0 * theta_y zx0 = z0 * theta_x tileStrokeWidth = 0.6 if tileWidth is None: D = [(x1, y1)] else: T = ((y1 - y0)**2 + (x1 - x0)**2)**0.5 tileStrokeWidth *= tileWidth if T < tileWidth: D = [(x1, y1)] else: n = int(T / float(tileWidth)) + 1 dx = float(x1 - x0) / n dy = float(y1 - y0) / n D = [] a = D.append for i in range(1, n): a((x0 + dx * i, y0 + dy * i)) a = G.add x_0 = x0 + zx0 y_0 = y0 + zy0 for x, y in D: x_1 = x + zx0 y_1 = y + zy0 P = Polygon(_ystrip_poly(x_0, x_1, y_0, y_1, xdepth, ydepth), fillColor=c, strokeColor=c, strokeWidth=tileStrokeWidth) a((0, z0, z1, x_0, y_0, P)) x_0 = x_1 y_0 = y_1
def _fillSide(self,L,i,angle,strokeColor,strokeWidth,fillColor): rd = self.rad_dist(angle) if rd<self.rad_dist(self._sl3d[i].mid): p = [self.CX(i,0),self.CY(i,0), self.CX(i,1),self.CY(i,1), self.OX(i,angle,1),self.OY(i,angle,1), self.OX(i,angle,0),self.OY(i,angle,0)] L.append((rd,Polygon(p, strokeColor=strokeColor, fillColor=fillColor,strokeWidth=strokeWidth,strokeLineJoin=1)))
def _doPolygon(self, P): x, y = self.x + self.dx, self.y + self.dy if x or y: P = map(lambda i, P=P, A=[x, y]: P[i] + A[i & 1], range(len(P))) return Polygon(P, strokeWidth=self.strokeWidth, strokeColor=self.strokeColor, fillColor=self.fillColor)
def convertPolygon(self, node): getAttr = node.getAttribute points = getAttr("points") points = points.replace(',', ' ') points = points.split() points = list(map(self.attrConverter.convertLength, points)) if len(points) % 2 != 0 or len(points) == 0: # Odd number of coordinates or no coordinates, invalid polygon return None shape = Polygon(points) return shape
def border(): draw = Drawing(1, 1) rect = Polygon(points=[ -12, cm / 6, (PAGE_WIDTH - (RIGHT_MARGIN + LEFT_MARGIN)), cm / 6, PAGE_WIDTH - (RIGHT_MARGIN + LEFT_MARGIN), -1 * (PAGE_HEIGHT - (TOP_MARGIN + BOTTOM_MARGIN + cm / 2)), -12, -1 * (PAGE_HEIGHT - (TOP_MARGIN + BOTTOM_MARGIN + cm / 2)) ], strokeColor=Color(*charts.BG_COLOR)) rect.fillColor = Color(*charts.BG_COLOR, 0.1) draw.add(rect) draw.add(Circle(100, 90, 5, fillColor=colors.green)) lab = Label() lab.setOrigin(350, -50) lab.boxAnchor = 'ne' lab.fillColor = Color(*charts.BG_COLOR, 0.15) lab.fontSize = 72 lab.angle = 60 lab.dx = 0 lab.dy = 0 lab.setText('Wisdom Tests') draw.add(lab) return draw
def convert_polyline(self, node): points = attributes.convert_length_list(node_attr(node, "points")) has_fill = node_attr(node, 'fill') not in ('', 'none') if len(points) % 2 != 0 or len(points) == 0: _logger.warn("Invalid Polyline points: %s" % points) return None polyline = PolyLine(points) self.apply_style(polyline, node) if has_fill: # Need to use two shapes, because standard RLG polylines do not support filling... # Polygon is the same as the polyline but without a border (stroke) gr = Group() polygon = Polygon(points) self.apply_style(polygon, node) polygon.strokeColor = None gr.add(polygon) gr.add(polyline) return gr else: return polyline
def __init__(self,width=400,height=200,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self.transform = (1,0,0,1,0,0) self.add(Line(20,10,200,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(Line(25.54729,10,25.54729,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(60.17003,10,60.17003,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(95.36663,10,95.36663,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(129.9894,10,129.9894,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(165.186,10,165.186,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(200,10,200,5,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) v0=self._nn(Group()) v0.transform = (1,0,0,1,25.54729,5) v0.add(String(-11.39,-10,'12/97',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,60.17003,5) v0.add(String(-11.39,-10,'06/98',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,95.36663,5) v0.add(String(-11.39,-10,'12/98',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,129.9894,5) v0.add(String(-11.39,-10,'06/99',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,165.186,5) v0.add(String(-11.39,-10,'12/99',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,200,5) v0.add(String(-11.39,-10,'06/00',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) self.add(Line(20,10,20,95,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(Line(20,10,15,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(20,36.89873,15,36.89873,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(20,63.79747,15,63.79747,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) self.add(Line(20,90.6962,15,90.6962,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=10,strokeDashArray=None,strokeOpacity=None)) v0=self._nn(Group()) v0.transform = (1,0,0,1,15,10) v0.add(String(-15,-4,'100',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,15,36.89873) v0.add(String(-15,-4,'105',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,15,63.79747) v0.add(String(-15,-4,'110',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) v0=self._nn(Group()) v0.transform = (1,0,0,1,15,90.6962) v0.add(String(-15,-4,'115',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1))) self.add(Polygon(points=[20,10,25.54729,10.91691,31.47715,18.4137,36.83316,21.77085,42.76302,18.78903,48.50159,24.86986,54.43146,25.70781,60.17003,27.53468,66.09989,27.49301,72.02976,39.45106,77.76833,60.16221,83.69819,74.48126,89.43677,68.73857,95.36663,68.73857,101.2965,74.49377,106.6525,62.67451,112.5824,65.09881,118.3209,66.09963,124.2508,60.24444,129.9894,54.29778,135.9192,64.94306,141.8491,69.00671,147.5877,76.9377,153.5175,78.49173,159.2561,76.44506,165.186,76.5263,171.1158,68.77656,176.6631,66.63061,182.593,81.61309,188.3316,69.41884,194.2614,72.95765,200,83.07427,200,88.5443,194.2614,77.78481,188.3316,75.63291,182.593,95,176.6631,84.77848,171.1158,78.32278,165.186,92.8481,159.2561,84.77848,153.5175,81.01266,147.5877,77.78481,141.8491,72.94304,135.9192,70.25316,129.9894,60.03165,124.2508,64.33544,118.3209,76.17089,112.5824,73.48101,106.6525,64.87342,101.2965,80.47468,95.36663,74.01899,89.43677,53.57595,83.69819,54.6519,77.76833,40.12658,72.02976,25.06329,66.09989,26.67722,60.17003,26.67722,54.43146,26.13924,48.50159,26.13924,42.76302,20.22152,36.83316,20.75949,31.47715,14.3038,25.54729,10,20,10],fillColor=Color(.623529,.623529,.623529,1),fillOpacity=None,strokeColor=None,strokeWidth=0,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(PolyLine(points=[20,10,25.54729,10.91691,31.47715,18.4137,36.83316,21.77085,42.76302,18.78903,48.50159,24.86986,54.43146,25.70781,60.17003,27.53468,66.09989,27.49301,72.02976,39.45106,77.76833,60.16221,83.69819,74.48126,89.43677,68.73857,95.36663,68.73857,101.2965,74.49377,106.6525,62.67451,112.5824,65.09881,118.3209,66.09963,124.2508,60.24444,129.9894,54.29778,135.9192,64.94306,141.8491,69.00671,147.5877,76.9377,153.5175,78.49173,159.2561,76.44506,165.186,76.5263,171.1158,68.77656,176.6631,66.63061,182.593,81.61309,188.3316,69.41884,194.2614,72.95765,200,83.07427],strokeColor=None,strokeWidth=1,strokeLineCap=0,strokeLineJoin=1,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None)) self.add(PolyLine(points=[20,10,25.54729,10,31.47715,14.3038,36.83316,20.75949,42.76302,20.22152,48.50159,26.13924,54.43146,26.13924,60.17003,26.67722,66.09989,26.67722,72.02976,25.06329,77.76833,40.12658,83.69819,54.6519,89.43677,53.57595,95.36663,74.01899,101.2965,80.47468,106.6525,64.87342,112.5824,73.48101,118.3209,76.17089,124.2508,64.33544,129.9894,60.03165,135.9192,70.25316,141.8491,72.94304,147.5877,77.78481,153.5175,81.01266,159.2561,84.77848,165.186,92.8481,171.1158,78.32278,176.6631,84.77848,182.593,95,188.3316,75.63291,194.2614,77.78481,200,88.5443],strokeColor=None,strokeWidth=1,strokeLineCap=0,strokeLineJoin=1,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
def _add_3d_bar(x1, x2, y1, y2, xoff, yoff, G=G, strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor): G.add( Polygon( (x1, y1, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff, x2, y2), strokeWidth=strokeWidth, strokeColor=strokeColor, fillColor=fillColor, strokeLineJoin=1))
def _Flag_UK(self): s = _size g = Group() w = s*2 g.add(Rect(0, 0, w, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0)) g.add(Polygon([0,0, s*.225,0, w,s*(1-.1125), w,s, w-s*.225,s, 0, s*.1125], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) g.add(Polygon([0,s*(1-.1125), 0, s, s*.225,s, w, s*.1125, w,0, w-s*.225,0], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) g.add(Polygon([0, s-(s/15), (s-((s/10)*4)), (s*0.65), (s-(s/10)*3), (s*0.65), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([0, 0, (s-((s/10)*3)), (s*0.35), (s-((s/10)*2)), (s*0.35), (s/10), 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([w, s, (s+((s/10)*3)), (s*0.65), (s+((s/10)*2)), (s*0.65), w-(s/10), s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([w, (s/15), (s+((s/10)*4)), (s*0.35), (s+((s/10)*3)), (s*0.35), w, 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(((s*0.42)*2), 0, width=(0.16*s)*2, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) g.add(Rect(0, (s*0.35), width=w, height=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) g.add(Rect(((s*0.45)*2), 0, width=(0.1*s)*2, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(0, (s*0.4), width=w, height=s*0.2, fillColor = colors.red, strokeColor = None, strokeWidth=0)) return g
def _draw_3d_bar(G, x1, x2, y0, yhigh, xdepth, ydepth, fillColor=None, fillColorShaded=None, strokeColor=None, strokeWidth=1, shading=0.1): fillColorShaded = _getShaded(fillColor,None,shading) fillColorShadedTop = _getShaded(fillColor,None,shading/2.0) def _add_3d_bar(x1, x2, y1, y2, xoff, yoff, G=G,strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor): G.add(Polygon((x1,y1, x1+xoff,y1+yoff, x2+xoff,y2+yoff, x2,y2), strokeWidth=strokeWidth, strokeColor=strokeColor, fillColor=fillColor,strokeLineJoin=1)) usd = max(y0, yhigh) if xdepth or ydepth: if y0!=yhigh: #non-zero height _add_3d_bar( x2, x2, y0, yhigh, xdepth, ydepth, fillColor=fillColorShaded) #side _add_3d_bar(x1, x2, usd, usd, xdepth, ydepth, fillColor=fillColorShadedTop) #top G.add(Polygon((x1,y0,x2,y0,x2,yhigh,x1,yhigh), strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor,strokeLineJoin=1)) #front if xdepth or ydepth: G.add(Line( x1, usd, x2, usd, strokeWidth=strokeWidth, strokeColor=strokeColor or fillColorShaded))
def makeLines(self): g = Group() labelFmt = self.lineLabelFormat P = list(range(len(self._positions))) if self.reversePlotOrder: P.reverse() inFill = self.inFill if inFill: inFillY = self.categoryAxis._y inFillX0 = self.valueAxis._x inFillX1 = inFillX0 + self.categoryAxis._length inFillG = getattr(self,'_inFillG',g) yzero = self._yzero # Iterate over data rows. for rowNo in P: row = self._positions[rowNo] styleCount = len(self.lines) styleIdx = rowNo % styleCount rowStyle = self.lines[styleIdx] rowColor = rowStyle.strokeColor dash = getattr(rowStyle, 'strokeDashArray', None) lineStyle = getattr(rowStyle,'lineStyle',None) if hasattr(rowStyle, 'strokeWidth'): strokeWidth = rowStyle.strokeWidth elif hasattr(self.lines, 'strokeWidth'): strokeWidth = self.lines.strokeWidth else: strokeWidth = None # Iterate over data columns. if lineStyle=='bar': barWidth = getattr(rowStyle,'barWidth',Percentage(50)) fillColor = getattr(rowStyle,'fillColor',rowColor) if isinstance(barWidth,Percentage): hbw = self._hngs*barWidth*0.01 else: hbw = barWidth*0.5 for colNo in range(len(row)): x,y = row[colNo] g.add(Rect(x-hbw,min(y,yzero),2*hbw,abs(y-yzero),strokeWidth=strokeWidth,strokeColor=rowColor,fillColor=fillColor)) elif self.joinedLines or lineStyle=='joinedLine': points = [] for colNo in range(len(row)): points += row[colNo] if inFill: points = points + [inFillX1,inFillY,inFillX0,inFillY] inFillG.add(Polygon(points,fillColor=rowColor,strokeColor=rowColor,strokeWidth=0.1)) else: line = PolyLine(points,strokeColor=rowColor,strokeLineCap=0,strokeLineJoin=1) if strokeWidth: line.strokeWidth = strokeWidth if dash: line.strokeDashArray = dash g.add(line) if hasattr(rowStyle, 'symbol'): uSymbol = rowStyle.symbol elif hasattr(self.lines, 'symbol'): uSymbol = self.lines.symbol else: uSymbol = None if uSymbol: for colNo in range(len(row)): x1, y1 = row[colNo] symbol = uSymbol2Symbol(uSymbol,x1,y1,rowStyle.strokeColor) if symbol: g.add(symbol) # Draw item labels. for colNo in range(len(row)): x1, y1 = row[colNo] self.drawLabel(g, rowNo, colNo, x1, y1) return g
def draw(self): # normalize slice data g = self.makeBackground() or Group() xradius = self.width/2.0 yradius = self.height/2.0 self._radius = radius = min(xradius, yradius) cx = self.x + xradius cy = self.y + yradius data = self.normalizeData() self._seriesCount = len(data) n = len(data[0]) #labels if self.labels is None: labels = [''] * n else: labels = self.labels #there's no point in raising errors for less than enough errors if #we silently create all for the extreme case of no labels. i = n-len(labels) if i>0: labels = labels + ['']*i S = [] STRANDS = [] STRANDAREAS = [] syms = [] labs = [] csa = [] angle = self.startAngle*pi/180 direction = self.direction == "clockwise" and -1 or 1 angleBetween = direction*(2 * pi)/float(n) spokes = self.spokes spokeLabels = self.spokeLabels for i in xrange(n): car = cos(angle)*radius sar = sin(angle)*radius csa.append((car,sar,angle)) si = self.spokes[i] if si.visible: spoke = Line(cx, cy, cx + car, cy + sar, strokeWidth = si.strokeWidth, strokeColor=si.strokeColor, strokeDashArray=si.strokeDashArray) S.append(spoke) sli = spokeLabels[i] text = sli._text if not text: text = labels[i] if text: S.append(_setupLabel(WedgeLabel, text, si.labelRadius, cx, cy, angle, car, sar, sli)) angle += angleBetween # now plot the polygons rowIdx = 0 strands = self.strands strandLabels = self.strandLabels for row in data: # series plot rsty = strands[rowIdx] points = [] car, sar = csa[-1][:2] r = row[-1] points.append(cx+car*r) points.append(cy+sar*r) for i in xrange(n): car, sar, angle = csa[i] r = row[i] points.append(cx+car*r) points.append(cy+sar*r) L = self._innerDrawLabel(strandLabels[(rowIdx,i)], r, cx, cy, angle, car, sar, labelClass=StrandLabel) if L: labs.append(L) sty = strands[(rowIdx,i)] uSymbol = sty.symbol # put in a marker, if it needs one if uSymbol: s_x = cx+car*r s_y = cy+sar*r s_fillColor = sty.fillColor s_strokeColor = sty.strokeColor s_strokeWidth = sty.strokeWidth s_angle = 0 s_size = sty.symbolSize if type(uSymbol) is type(''): symbol = makeMarker(uSymbol, size = s_size, x = s_x, y = s_y, fillColor = s_fillColor, strokeColor = s_strokeColor, strokeWidth = s_strokeWidth, angle = s_angle, ) else: symbol = uSymbol2Symbol(uSymbol,s_x,s_y,s_fillColor) for k,v in (('size', s_size), ('fillColor', s_fillColor), ('x', s_x), ('y', s_y), ('strokeColor',s_strokeColor), ('strokeWidth',s_strokeWidth), ('angle',s_angle),): if getattr(symbol,k,None) is None: try: setattr(symbol,k,v) except: pass syms.append(symbol) # make up the 'strand' if rsty.fillColor: strand = Polygon(points) strand.fillColor = rsty.fillColor strand.strokeColor = None strand.strokeWidth = 0 STRANDAREAS.append(strand) if rsty.strokeColor and rsty.strokeWidth: strand = PolyLine(points) strand.strokeColor = rsty.strokeColor strand.strokeWidth = rsty.strokeWidth strand.strokeDashArray = rsty.strokeDashArray STRANDS.append(strand) rowIdx += 1 map(g.add,STRANDAREAS+STRANDS+syms+S+labs) return g
def test_fillrule(self): converter = svglib.Svg2RlgShapeConverter(None) node = etree.XML('<polygon fill-rule="evenodd"/>') poly = Polygon() converter.applyStyleOnShape(poly, node) assert poly._fillRule == FILL_EVEN_ODD
def draw(self): # normalize slice data g = self.makeBackground() or Group() xradius = self.width/2.0 yradius = self.height/2.0 self._radius = radius = min(xradius, yradius) centerx = self.x + xradius centery = self.y + yradius data = self.normalizeData() n = len(data[0]) #labels if self.labels is None: labels = [''] * n else: labels = self.labels #there's no point in raising errors for less than enough errors if #we silently create all for the extreme case of no labels. i = n-len(labels) if i>0: labels = labels + ['']*i spokes = [] csa = [] angle = self.startAngle*pi/180 direction = self.direction == "clockwise" and -1 or 1 angleBetween = direction*(2 * pi)/n markers = self.strands.markers for i in xrange(n): car = cos(angle)*radius sar = sin(angle)*radius csa.append((car,sar,angle)) spoke = Line(centerx, centery, centerx + car, centery + sar, strokeWidth = 0.5) #print 'added spoke (%0.2f, %0.2f) -> (%0.2f, %0.2f)' % (spoke.x1, spoke.y1, spoke.x2, spoke.y2) spokes.append(spoke) if labels: si = self.strands[i] text = si.label_text if text is None: text = labels[i] if text: labelRadius = si.labelRadius L = WedgeLabel() L.x = centerx + labelRadius*car L.y = centery + labelRadius*sar L.boxAnchor = si.label_boxAnchor L._pmv = angle*180/pi L.dx = si.label_dx L.dy = si.label_dy L.angle = si.label_angle L.boxAnchor = si.label_boxAnchor L.boxStrokeColor = si.label_boxStrokeColor L.boxStrokeWidth = si.label_boxStrokeWidth L.boxFillColor = si.label_boxFillColor L.strokeColor = si.label_strokeColor L.strokeWidth = si.label_strokeWidth L._text = text L.leading = si.label_leading L.width = si.label_width L.maxWidth = si.label_maxWidth L.height = si.label_height L.textAnchor = si.label_textAnchor L.visible = si.label_visible L.topPadding = si.label_topPadding L.leftPadding = si.label_leftPadding L.rightPadding = si.label_rightPadding L.bottomPadding = si.label_bottomPadding L.fontName = si.fontName L.fontSize = si.fontSize L.fillColor = si.fontColor spokes.append(L) angle = angle + angleBetween # now plot the polygons rowIdx = 0 for row in data: # series plot points = [] car, sar = csa[-1][:2] r = row[-1] points.append(centerx+car*r) points.append(centery+sar*r) for i in xrange(n): car, sar = csa[i][:2] r = row[i] points.append(centerx+car*r) points.append(centery+sar*r) # make up the 'strand' strand = Polygon(points) strand.fillColor = self.strands[rowIdx].fillColor strand.strokeColor = self.strands[rowIdx].strokeColor strand.strokeWidth = self.strands[rowIdx].strokeWidth strand.strokeDashArray = self.strands[rowIdx].strokeDashArray g.add(strand) # put in a marker, if it needs one if markers: if hasattr(self.strands[rowIdx], 'markerType'): uSymbol = self.strands[rowIdx].markerType elif hasattr(self.strands, 'markerType'): uSymbol = self.strands.markerType else: uSymbol = None m_x = centerx+car*r m_y = centery+sar*r m_size = self.strands[rowIdx].markerSize m_fillColor = self.strands[rowIdx].fillColor m_strokeColor = self.strands[rowIdx].strokeColor m_strokeWidth = self.strands[rowIdx].strokeWidth m_angle = 0 if type(uSymbol) is type(''): symbol = makeMarker(uSymbol, size = m_size, x = m_x, y = m_y, fillColor = m_fillColor, strokeColor = m_strokeColor, strokeWidth = m_strokeWidth, angle = m_angle, ) else: symbol = uSymbol2Symbol(uSymbol,m_x,m_y,m_fillColor) for k,v in (('size', m_size), ('fillColor', m_fillColor), ('x', m_x), ('y', m_y), ('strokeColor',m_strokeColor), ('strokeWidth',m_strokeWidth), ('angle',m_angle),): try: setattr(uSymbol,k,v) except: pass g.add(symbol) rowIdx = rowIdx + 1 # spokes go over strands for spoke in spokes: g.add(spoke) return g
def fill(self, lp, g, rowNo, rowColor, points): g.add( Polygon(points, fillColor=getattr(self, 'fillColor', rowColor), strokeColor=getattr(self, 'strokeColor', rowColor), strokeWidth=getattr(self, 'strokeWidth', 0.1)))
def _Flag_Brazil(self): s = _size # abbreviate as we will use this a lot g = Group() m = s / 14 self._width = w = (m * 20) def addStar(x, y, size, g=g, w=w, s=s, m=m): st = Star() st.fillColor = colors.mintcream st.size = size * m st.x = (w / 2) + (x * (0.35 * m)) st.y = (s / 2) + (y * (0.35 * m)) g.add(st) g.add( Rect(0, 0, w, s, fillColor=colors.green, strokeColor=None, strokeWidth=0)) g.add( Polygon(points=[ 1.7 * m, (s / 2), (w / 2), s - (1.7 * m), w - (1.7 * m), (s / 2), (w / 2), 1.7 * m ], fillColor=colors.yellow, strokeColor=None, strokeWidth=0)) g.add( Circle(cx=w / 2, cy=s / 2, r=3.5 * m, fillColor=colors.blue, strokeColor=None, strokeWidth=0)) g.add( Wedge((w / 2) - (2 * m), 0, 8.5 * m, 50, 98.1, 8.5 * m, fillColor=colors.mintcream, strokeColor=None, strokeWidth=0)) g.add( Wedge((w / 2), (s / 2), 3.501 * m, 156, 352, 3.501 * m, fillColor=colors.mintcream, strokeColor=None, strokeWidth=0)) g.add( Wedge((w / 2) - (2 * m), 0, 8 * m, 48.1, 100, 8 * m, fillColor=colors.blue, strokeColor=None, strokeWidth=0)) g.add( Rect(0, 0, w, (s / 4) + 1.7 * m, fillColor=colors.green, strokeColor=None, strokeWidth=0)) g.add( Polygon(points=[ 1.7 * m, (s / 2), (w / 2), s / 2 - 2 * m, w - (1.7 * m), (s / 2), (w / 2), 1.7 * m ], fillColor=colors.yellow, strokeColor=None, strokeWidth=0)) g.add( Wedge(w / 2, s / 2, 3.502 * m, 166, 342.1, 3.502 * m, fillColor=colors.blue, strokeColor=None, strokeWidth=0)) addStar(3.2, 3.5, 0.3) addStar(-8.5, 1.5, 0.3) addStar(-7.5, -3, 0.3) addStar(-4, -5.5, 0.3) addStar(0, -4.5, 0.3) addStar(7, -3.5, 0.3) addStar(-3.5, -0.5, 0.25) addStar(0, -1.5, 0.25) addStar(1, -2.5, 0.25) addStar(3, -7, 0.25) addStar(5, -6.5, 0.25) addStar(6.5, -5, 0.25) addStar(7, -4.5, 0.25) addStar(-5.5, -3.2, 0.25) addStar(-6, -4.2, 0.25) addStar(-1, -2.75, 0.2) addStar(2, -5.5, 0.2) addStar(4, -5.5, 0.2) addStar(5, -7.5, 0.2) addStar(5, -5.5, 0.2) addStar(6, -5.5, 0.2) addStar(-8.8, -3.2, 0.2) addStar(2.5, 0.5, 0.2) addStar(-0.2, -3.2, 0.14) addStar(-7.2, -2, 0.14) addStar(0, -8, 0.1) sTmp = "ORDEM E PROGRESSO" nTmp = len(sTmp) delta = 0.850848010347 / nTmp radius = 7.9 * m centerx = (w / 2) - (2 * m) centery = 0 for i in range(nTmp): rad = 2 * pi - i * delta - 4.60766922527 x = cos(rad) * radius + centerx y = sin(rad) * radius + centery if i == 6: z = 0.35 * m else: z = 0.45 * m g2 = Group( String(x, y, sTmp[i], fontName='Helvetica-Bold', fontSize=z, strokeColor=None, fillColor=colors.green)) g2.rotate(rad) g.add(g2) return g
def draw_arrow(point1, point2, color=colors.lightgreen, border=None, shaft_height_ratio=0.4, head_length_ratio=0.5, orientation="right", colour=None, **kwargs): """Draw an arrow. Returns a closed path object representing an arrow enclosed by the box with corners at {point1=(x1,y1), point2=(x2,y2)}, a shaft height given by shaft_height_ratio (relative to box height), a head length given by head_length_ratio (also relative to box height), and an orientation that may be 'left' or 'right'. """ x1, y1 = point1 x2, y2 = point2 if shaft_height_ratio < 0 or 1 < shaft_height_ratio: raise ValueError("Arrow shaft height ratio should be in range 0 to 1") if head_length_ratio < 0: raise ValueError("Arrow head length ratio should be positive") # Let the UK spelling (colour) override the USA spelling (color) if colour is not None: color = colour del colour strokecolor, color = _stroke_and_fill_colors(color, border) # Depending on the orientation, we define the bottom left (x1, y1) and # top right (x2, y2) coordinates differently, but still draw the box # using the same relative coordinates: xmin, ymin = min(x1, x2), min(y1, y2) xmax, ymax = max(x1, x2), max(y1, y2) if orientation == "right": x1, x2, y1, y2 = xmin, xmax, ymin, ymax elif orientation == "left": x1, x2, y1, y2 = xmax, xmin, ymin, ymax else: raise ValueError( "Invalid orientation %r, should be 'left' or 'right'" % orientation) # We define boxheight and boxwidth accordingly, and calculate the shaft # height from these. We also ensure that the maximum head length is # the width of the box enclosure boxheight = y2 - y1 boxwidth = x2 - x1 shaftheight = boxheight * shaft_height_ratio headlength = min(abs(boxheight) * head_length_ratio, abs(boxwidth)) if boxwidth < 0: headlength *= -1 # reverse it shafttop = 0.5 * (boxheight + shaftheight) shaftbase = boxheight - shafttop headbase = boxwidth - headlength midheight = 0.5 * boxheight points = [ x1, y1 + shafttop, x1 + headbase, y1 + shafttop, x1 + headbase, y2, x2, y1 + midheight, x1 + headbase, y1, x1 + headbase, y1 + shaftbase, x1, y1 + shaftbase, ] return Polygon( deduplicate(points), strokeColor=strokecolor, # strokeWidth=max(1, int(boxheight/40.)), strokeWidth=1, # default is mitre/miter which can stick out too much: strokeLineJoin=1, # 1=round fillColor=color, **kwargs)