Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .venv/lib/python3.13/site-packages/instructor-1.14.3.dist-info/licenses/LICENSE +21 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/__init__.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/core.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/defaults.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/exception.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/json.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/utils.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/charts/dotbox.py +165 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/charts/linecharts.py +801 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/__init__.py +1 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/bubble.py +73 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_bar.py +84 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_column.py +83 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/excelcolors.py +45 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/exploded_pie.py +65 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/filled_radar.py +54 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/line_chart.py +83 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/linechart_with_markers.py +94 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/radar.py +66 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/runall.py +57 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter.py +71 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines.py +82 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines_markers.py +72 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/simple_pie.py +61 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_bar.py +85 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_column.py +84 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/__init__.py +5 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/adjustableArrow.py +126 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/eventcal.py +299 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/flags.py +879 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/grids.py +542 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/signsandsymbols.py +977 -0
- .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/table.py +160 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/__init__.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/_base_connection.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/_collections.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/_request_methods.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/_version.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/connection.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/connectionpool.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/exceptions.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/fields.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/filepost.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/poolmanager.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/__pycache__/response.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/contrib/__init__.py +0 -0
- .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/__init__.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/socks.cpython-313.pyc +0 -0
- .venv/lib/python3.13/site-packages/urllib3/contrib/emscripten/__init__.py +17 -0
.venv/lib/python3.13/site-packages/instructor-1.14.3.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2023 Jason Liu
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (466 Bytes). View file
|
|
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/core.cpython-313.pyc
ADDED
|
Binary file (15.8 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/defaults.cpython-313.pyc
ADDED
|
Binary file (8.66 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/exception.cpython-313.pyc
ADDED
|
Binary file (1.33 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/json.cpython-313.pyc
ADDED
|
Binary file (5.82 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/utils.cpython-313.pyc
ADDED
|
Binary file (1.28 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/reportlab/graphics/charts/dotbox.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from reportlab.lib.colors import _PCMYK_black
|
| 2 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 3 |
+
from reportlab.graphics.shapes import Circle, Drawing, Group, Line, Rect, String
|
| 4 |
+
from reportlab.graphics.widgetbase import Widget
|
| 5 |
+
from reportlab.lib.attrmap import *
|
| 6 |
+
from reportlab.lib.validators import *
|
| 7 |
+
from reportlab.lib.units import cm
|
| 8 |
+
from reportlab.pdfbase.pdfmetrics import getFont
|
| 9 |
+
from reportlab.graphics.charts.lineplots import _maxWidth
|
| 10 |
+
|
| 11 |
+
class DotBox(Widget):
|
| 12 |
+
"""Returns a dotbox widget."""
|
| 13 |
+
|
| 14 |
+
#Doesn't use TypedPropertyCollection for labels - this can be a later improvement
|
| 15 |
+
_attrMap = AttrMap(
|
| 16 |
+
xlabels = AttrMapValue(isNoneOrListOfNoneOrStrings,
|
| 17 |
+
desc="List of text labels for boxes on left hand side"),
|
| 18 |
+
ylabels = AttrMapValue(isNoneOrListOfNoneOrStrings,
|
| 19 |
+
desc="Text label for second box on left hand side"),
|
| 20 |
+
labelFontName = AttrMapValue(isString,
|
| 21 |
+
desc="Name of font used for the labels"),
|
| 22 |
+
labelFontSize = AttrMapValue(isNumber,
|
| 23 |
+
desc="Size of font used for the labels"),
|
| 24 |
+
labelOffset = AttrMapValue(isNumber,
|
| 25 |
+
desc="Space between label text and grid edge"),
|
| 26 |
+
strokeWidth = AttrMapValue(isNumber,
|
| 27 |
+
desc='Width of the grid and dot outline'),
|
| 28 |
+
gridDivWidth = AttrMapValue(isNumber,
|
| 29 |
+
desc="Width of each 'box'"),
|
| 30 |
+
gridColor = AttrMapValue(isColor,
|
| 31 |
+
desc='Colour for the box and gridding'),
|
| 32 |
+
dotDiameter = AttrMapValue(isNumber,
|
| 33 |
+
desc="Diameter of the circle used for the 'dot'"),
|
| 34 |
+
dotColor = AttrMapValue(isColor,
|
| 35 |
+
desc='Colour of the circle on the box'),
|
| 36 |
+
dotXPosition = AttrMapValue(isNumber,
|
| 37 |
+
desc='X Position of the circle'),
|
| 38 |
+
dotYPosition = AttrMapValue(isNumber,
|
| 39 |
+
desc='X Position of the circle'),
|
| 40 |
+
x = AttrMapValue(isNumber,
|
| 41 |
+
desc='X Position of dotbox'),
|
| 42 |
+
y = AttrMapValue(isNumber,
|
| 43 |
+
desc='Y Position of dotbox'),
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
def __init__(self):
|
| 47 |
+
self.xlabels=["Value", "Blend", "Growth"]
|
| 48 |
+
self.ylabels=["Small", "Medium", "Large"]
|
| 49 |
+
self.labelFontName = "Helvetica"
|
| 50 |
+
self.labelFontSize = 6
|
| 51 |
+
self.labelOffset = 5
|
| 52 |
+
self.strokeWidth = 0.5
|
| 53 |
+
self.gridDivWidth=0.5*cm
|
| 54 |
+
self.gridColor=colors.Color(25/255.0,77/255.0,135/255.0)
|
| 55 |
+
self.dotDiameter=0.4*cm
|
| 56 |
+
self.dotColor=colors.Color(232/255.0,224/255.0,119/255.0)
|
| 57 |
+
self.dotXPosition = 1
|
| 58 |
+
self.dotYPosition = 1
|
| 59 |
+
self.x = 30
|
| 60 |
+
self.y = 5
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def _getDrawingDimensions(self):
|
| 64 |
+
leftPadding=rightPadding=topPadding=bottomPadding=5
|
| 65 |
+
#find width of grid
|
| 66 |
+
tx=len(self.xlabels)*self.gridDivWidth
|
| 67 |
+
#add padding (and offset)
|
| 68 |
+
tx=tx+leftPadding+rightPadding+self.labelOffset
|
| 69 |
+
#add in maximum width of text
|
| 70 |
+
tx=tx+_maxWidth(self.xlabels, self.labelFontName, self.labelFontSize)
|
| 71 |
+
#find height of grid
|
| 72 |
+
ty=len(self.ylabels)*self.gridDivWidth
|
| 73 |
+
#add padding (and offset)
|
| 74 |
+
ty=ty+topPadding+bottomPadding+self.labelOffset
|
| 75 |
+
#add in maximum width of text
|
| 76 |
+
ty=ty+_maxWidth(self.ylabels, self.labelFontName, self.labelFontSize)
|
| 77 |
+
#print (tx, ty)
|
| 78 |
+
return (tx,ty)
|
| 79 |
+
|
| 80 |
+
def demo(self,drawing=None):
|
| 81 |
+
if not drawing:
|
| 82 |
+
tx,ty=self._getDrawingDimensions()
|
| 83 |
+
drawing = Drawing(tx,ty)
|
| 84 |
+
drawing.add(self.draw())
|
| 85 |
+
return drawing
|
| 86 |
+
|
| 87 |
+
def draw(self):
|
| 88 |
+
g = Group()
|
| 89 |
+
|
| 90 |
+
#box
|
| 91 |
+
g.add(Rect(self.x,self.y,len(self.xlabels)*self.gridDivWidth,len(self.ylabels)*self.gridDivWidth,
|
| 92 |
+
strokeColor=self.gridColor,
|
| 93 |
+
strokeWidth=self.strokeWidth,
|
| 94 |
+
fillColor=None))
|
| 95 |
+
|
| 96 |
+
#internal gridding
|
| 97 |
+
for f in range (1,len(self.ylabels)):
|
| 98 |
+
#horizontal
|
| 99 |
+
g.add(Line(strokeColor=self.gridColor,
|
| 100 |
+
strokeWidth=self.strokeWidth,
|
| 101 |
+
x1 = self.x,
|
| 102 |
+
y1 = self.y+f*self.gridDivWidth,
|
| 103 |
+
x2 = self.x+len(self.xlabels)*self.gridDivWidth,
|
| 104 |
+
y2 = self.y+f*self.gridDivWidth))
|
| 105 |
+
for f in range (1,len(self.xlabels)):
|
| 106 |
+
#vertical
|
| 107 |
+
g.add(Line(strokeColor=self.gridColor,
|
| 108 |
+
strokeWidth=self.strokeWidth,
|
| 109 |
+
x1 = self.x+f*self.gridDivWidth,
|
| 110 |
+
y1 = self.y,
|
| 111 |
+
x2 = self.x+f*self.gridDivWidth,
|
| 112 |
+
y2 = self.y+len(self.ylabels)*self.gridDivWidth))
|
| 113 |
+
|
| 114 |
+
# draw the 'dot'
|
| 115 |
+
g.add(Circle(strokeColor=self.gridColor,
|
| 116 |
+
strokeWidth=self.strokeWidth,
|
| 117 |
+
fillColor=self.dotColor,
|
| 118 |
+
cx = self.x+(self.dotXPosition*self.gridDivWidth),
|
| 119 |
+
cy = self.y+(self.dotYPosition*self.gridDivWidth),
|
| 120 |
+
r = self.dotDiameter/2.0))
|
| 121 |
+
|
| 122 |
+
#used for centering y-labels (below)
|
| 123 |
+
ascent=getFont(self.labelFontName).face.ascent
|
| 124 |
+
if ascent==0:
|
| 125 |
+
ascent=0.718 # default (from helvetica)
|
| 126 |
+
ascent=ascent*self.labelFontSize # normalize
|
| 127 |
+
|
| 128 |
+
#do y-labels
|
| 129 |
+
if self.ylabels != None:
|
| 130 |
+
for f in range (len(self.ylabels)-1,-1,-1):
|
| 131 |
+
if self.ylabels[f]!= None:
|
| 132 |
+
g.add(String(strokeColor=self.gridColor,
|
| 133 |
+
text = self.ylabels[f],
|
| 134 |
+
fontName = self.labelFontName,
|
| 135 |
+
fontSize = self.labelFontSize,
|
| 136 |
+
fillColor=_PCMYK_black,
|
| 137 |
+
x = self.x-self.labelOffset,
|
| 138 |
+
y = self.y+(f*self.gridDivWidth+(self.gridDivWidth-ascent)/2.0),
|
| 139 |
+
textAnchor = 'end'))
|
| 140 |
+
|
| 141 |
+
#do x-labels
|
| 142 |
+
if self.xlabels != None:
|
| 143 |
+
for f in range (0,len(self.xlabels)):
|
| 144 |
+
if self.xlabels[f]!= None:
|
| 145 |
+
l=Label()
|
| 146 |
+
l.x=self.x+(f*self.gridDivWidth)+(self.gridDivWidth+ascent)/2.0
|
| 147 |
+
l.y=self.y+(len(self.ylabels)*self.gridDivWidth)+self.labelOffset
|
| 148 |
+
l.angle=90
|
| 149 |
+
l.textAnchor='start'
|
| 150 |
+
l.fontName = self.labelFontName
|
| 151 |
+
l.fontSize = self.labelFontSize
|
| 152 |
+
l.fillColor = _PCMYK_black
|
| 153 |
+
l.setText(self.xlabels[f])
|
| 154 |
+
l.boxAnchor = 'sw'
|
| 155 |
+
l.draw()
|
| 156 |
+
g.add(l)
|
| 157 |
+
|
| 158 |
+
return g
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
if __name__ == "__main__":
|
| 164 |
+
d = DotBox()
|
| 165 |
+
d.demo().save(fnRoot="dotbox")
|
.venv/lib/python3.13/site-packages/reportlab/graphics/charts/linecharts.py
ADDED
|
@@ -0,0 +1,801 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Copyright ReportLab Europe Ltd. 2000-2017
|
| 2 |
+
#see license.txt for license details
|
| 3 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/linecharts.py
|
| 4 |
+
|
| 5 |
+
__version__='3.3.0'
|
| 6 |
+
__doc__="""This modules defines a very preliminary Line Chart example."""
|
| 7 |
+
|
| 8 |
+
from reportlab.lib import colors
|
| 9 |
+
from reportlab.lib.validators import isNumber, isNumberOrNone, isColorOrNone, \
|
| 10 |
+
isListOfStringsOrNone, isBoolean, NoneOr, \
|
| 11 |
+
isListOfNumbersOrNone, isStringOrNone, OneOf, Percentage
|
| 12 |
+
from reportlab.lib.attrmap import *
|
| 13 |
+
from reportlab.lib.utils import flatten
|
| 14 |
+
from reportlab.graphics.widgetbase import TypedPropertyCollection, PropHolder, tpcGetItem
|
| 15 |
+
from reportlab.graphics.shapes import Line, Rect, Group, Drawing, Polygon, PolyLine
|
| 16 |
+
from reportlab.graphics.widgets.signsandsymbols import NoEntry
|
| 17 |
+
from reportlab.graphics.charts.axes import XCategoryAxis, YValueAxis, YCategoryAxis, XValueAxis
|
| 18 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 19 |
+
from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol, makeMarker
|
| 20 |
+
from reportlab.graphics.charts.areas import PlotArea
|
| 21 |
+
from reportlab.graphics.charts.legends import _objStr
|
| 22 |
+
from .utils import FillPairedData
|
| 23 |
+
|
| 24 |
+
class LineChartProperties(PropHolder):
|
| 25 |
+
_attrMap = AttrMap(
|
| 26 |
+
strokeWidth = AttrMapValue(isNumber, desc='Width of a line.'),
|
| 27 |
+
strokeColor = AttrMapValue(isColorOrNone, desc='Color of a line or border.'),
|
| 28 |
+
fillColor = AttrMapValue(isColorOrNone, desc='fill color of a bar.'),
|
| 29 |
+
strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array of a line.'),
|
| 30 |
+
symbol = AttrMapValue(NoneOr(isSymbol), desc='Widget placed at data points.',advancedUsage=1),
|
| 31 |
+
shader = AttrMapValue(None, desc='Shader Class.',advancedUsage=1),
|
| 32 |
+
filler = AttrMapValue(None, desc='Filler Class.',advancedUsage=1),
|
| 33 |
+
name = AttrMapValue(isStringOrNone, desc='Name of the line.'),
|
| 34 |
+
lineStyle = AttrMapValue(NoneOr(OneOf('line','joinedLine','bar')), desc="What kind of plot this line is",advancedUsage=1),
|
| 35 |
+
barWidth = AttrMapValue(isNumberOrNone,desc="Percentage of available width to be used for a bar",advancedUsage=1),
|
| 36 |
+
inFill = AttrMapValue(isBoolean, desc='If true flood fill to x axis',advancedUsage=1),
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
class AbstractLineChart(PlotArea):
|
| 40 |
+
|
| 41 |
+
def makeSwatchSample(self,rowNo, x, y, width, height):
|
| 42 |
+
baseStyle = self.lines
|
| 43 |
+
styleIdx = rowNo % len(baseStyle)
|
| 44 |
+
style = baseStyle[styleIdx]
|
| 45 |
+
color = style.strokeColor
|
| 46 |
+
yh2 = y+height/2.
|
| 47 |
+
lineStyle = getattr(style,'lineStyle',None)
|
| 48 |
+
if lineStyle=='bar':
|
| 49 |
+
dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None))
|
| 50 |
+
strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None))
|
| 51 |
+
L = Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=color,strokeLineCap=0,strokeDashArray=dash,fillColor=getattr(style,'fillColor',color))
|
| 52 |
+
elif self.joinedLines or lineStyle=='joinedLine':
|
| 53 |
+
dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None))
|
| 54 |
+
strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None))
|
| 55 |
+
L = Line(x,yh2,x+width,yh2,strokeColor=color,strokeLineCap=0)
|
| 56 |
+
if strokeWidth: L.strokeWidth = strokeWidth
|
| 57 |
+
if dash: L.strokeDashArray = dash
|
| 58 |
+
else:
|
| 59 |
+
L = None
|
| 60 |
+
|
| 61 |
+
if hasattr(style, 'symbol'):
|
| 62 |
+
S = style.symbol
|
| 63 |
+
elif hasattr(baseStyle, 'symbol'):
|
| 64 |
+
S = baseStyle.symbol
|
| 65 |
+
else:
|
| 66 |
+
S = None
|
| 67 |
+
|
| 68 |
+
if S: S = uSymbol2Symbol(S,x+width/2.,yh2,color)
|
| 69 |
+
if S and L:
|
| 70 |
+
g = Group()
|
| 71 |
+
g.add(L)
|
| 72 |
+
g.add(S)
|
| 73 |
+
return g
|
| 74 |
+
return S or L
|
| 75 |
+
|
| 76 |
+
def getSeriesName(self,i,default=None):
|
| 77 |
+
'''return series name i or default'''
|
| 78 |
+
return _objStr(getattr(self.lines[i],'name',default))
|
| 79 |
+
|
| 80 |
+
class LineChart(AbstractLineChart):
|
| 81 |
+
pass
|
| 82 |
+
|
| 83 |
+
# This is conceptually similar to the VerticalBarChart.
|
| 84 |
+
# Still it is better named HorizontalLineChart... :-/
|
| 85 |
+
|
| 86 |
+
class HorizontalLineChart(LineChart):
|
| 87 |
+
"""Line chart with multiple lines.
|
| 88 |
+
|
| 89 |
+
A line chart is assumed to have one category and one value axis.
|
| 90 |
+
Despite its generic name this particular line chart class has
|
| 91 |
+
a vertical value axis and a horizontal category one. It may
|
| 92 |
+
evolve into individual horizontal and vertical variants (like
|
| 93 |
+
with the existing bar charts).
|
| 94 |
+
|
| 95 |
+
Available attributes are:
|
| 96 |
+
|
| 97 |
+
x: x-position of lower-left chart origin
|
| 98 |
+
y: y-position of lower-left chart origin
|
| 99 |
+
width: chart width
|
| 100 |
+
height: chart height
|
| 101 |
+
|
| 102 |
+
useAbsolute: disables auto-scaling of chart elements (?)
|
| 103 |
+
lineLabelNudge: distance of data labels to data points
|
| 104 |
+
lineLabels: labels associated with data values
|
| 105 |
+
lineLabelFormat: format string or callback function
|
| 106 |
+
groupSpacing: space between categories
|
| 107 |
+
|
| 108 |
+
joinedLines: enables drawing of lines
|
| 109 |
+
|
| 110 |
+
strokeColor: color of chart lines (?)
|
| 111 |
+
fillColor: color for chart background (?)
|
| 112 |
+
lines: style list, used cyclically for data series
|
| 113 |
+
|
| 114 |
+
valueAxis: value axis object
|
| 115 |
+
categoryAxis: category axis object
|
| 116 |
+
categoryNames: category names
|
| 117 |
+
|
| 118 |
+
data: chart data, a list of data series of equal length
|
| 119 |
+
"""
|
| 120 |
+
_flipXY = 0
|
| 121 |
+
|
| 122 |
+
_attrMap = AttrMap(BASE=LineChart,
|
| 123 |
+
useAbsolute = AttrMapValue(isNumber, desc='Flag to use absolute spacing values.',advancedUsage=1),
|
| 124 |
+
lineLabelNudge = AttrMapValue(isNumber, desc='Distance between a data point and its label.',advancedUsage=1),
|
| 125 |
+
lineLabels = AttrMapValue(None, desc='Handle to the list of data point labels.'),
|
| 126 |
+
lineLabelFormat = AttrMapValue(None, desc='Formatting string or function used for data point labels.'),
|
| 127 |
+
lineLabelArray = AttrMapValue(None, desc='explicit array of line label values, must match size of data if present.'),
|
| 128 |
+
groupSpacing = AttrMapValue(isNumber, desc='? - Likely to disappear.'),
|
| 129 |
+
joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'),
|
| 130 |
+
lines = AttrMapValue(None, desc='Handle of the lines.'),
|
| 131 |
+
valueAxis = AttrMapValue(None, desc='Handle of the value axis.'),
|
| 132 |
+
categoryAxis = AttrMapValue(None, desc='Handle of the category axis.'),
|
| 133 |
+
categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'),
|
| 134 |
+
data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'),
|
| 135 |
+
inFill = AttrMapValue(isBoolean, desc='Whether infilling should be done.',advancedUsage=1),
|
| 136 |
+
reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1),
|
| 137 |
+
annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1),
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
def __init__(self):
|
| 141 |
+
LineChart.__init__(self)
|
| 142 |
+
|
| 143 |
+
# Allow for a bounding rectangle.
|
| 144 |
+
self.strokeColor = None
|
| 145 |
+
self.fillColor = None
|
| 146 |
+
|
| 147 |
+
# Named so we have less recoding for the horizontal one :-)
|
| 148 |
+
if self._flipXY:
|
| 149 |
+
self.categoryAxis = YCategoryAxis()
|
| 150 |
+
self.valueAxis = XValueAxis()
|
| 151 |
+
else:
|
| 152 |
+
self.categoryAxis = XCategoryAxis()
|
| 153 |
+
self.valueAxis = YValueAxis()
|
| 154 |
+
|
| 155 |
+
# This defines two series of 3 points. Just an example.
|
| 156 |
+
self.data = [(100,110,120,130),
|
| 157 |
+
(70, 80, 80, 90)]
|
| 158 |
+
self.categoryNames = ('North','South','East','West')
|
| 159 |
+
|
| 160 |
+
self.lines = TypedPropertyCollection(LineChartProperties)
|
| 161 |
+
self.lines.strokeWidth = 1
|
| 162 |
+
self.lines[0].strokeColor = colors.red
|
| 163 |
+
self.lines[1].strokeColor = colors.green
|
| 164 |
+
self.lines[2].strokeColor = colors.blue
|
| 165 |
+
|
| 166 |
+
# control spacing. if useAbsolute = 1 then
|
| 167 |
+
# the next parameters are in points; otherwise
|
| 168 |
+
# they are 'proportions' and are normalized to
|
| 169 |
+
# fit the available space.
|
| 170 |
+
self.useAbsolute = 0 #- not done yet
|
| 171 |
+
self.groupSpacing = 1 #5
|
| 172 |
+
|
| 173 |
+
self.lineLabels = TypedPropertyCollection(Label)
|
| 174 |
+
self.lineLabelFormat = None
|
| 175 |
+
self.lineLabelArray = None
|
| 176 |
+
|
| 177 |
+
# This says whether the origin is above or below
|
| 178 |
+
# the data point. +10 means put the origin ten points
|
| 179 |
+
# above the data point if value > 0, or ten
|
| 180 |
+
# points below if data value < 0. This is different
|
| 181 |
+
# to label dx/dy which are not dependent on the
|
| 182 |
+
# sign of the data.
|
| 183 |
+
self.lineLabelNudge = 10
|
| 184 |
+
# If you have multiple series, by default they butt
|
| 185 |
+
# together.
|
| 186 |
+
|
| 187 |
+
# New line chart attributes.
|
| 188 |
+
self.joinedLines = 1 # Connect items with straight lines.
|
| 189 |
+
self.inFill = 0
|
| 190 |
+
self.reversePlotOrder = 0
|
| 191 |
+
|
| 192 |
+
def demo(self):
|
| 193 |
+
"""Shows basic use of a line chart."""
|
| 194 |
+
|
| 195 |
+
drawing = Drawing(200, 100)
|
| 196 |
+
|
| 197 |
+
data = [
|
| 198 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 199 |
+
(14, 10, 21, 28, 38, 46, 25, 5)
|
| 200 |
+
]
|
| 201 |
+
|
| 202 |
+
lc = HorizontalLineChart()
|
| 203 |
+
|
| 204 |
+
lc.x = 20
|
| 205 |
+
lc.y = 10
|
| 206 |
+
lc.height = 85
|
| 207 |
+
lc.width = 170
|
| 208 |
+
lc.data = data
|
| 209 |
+
lc.lines.symbol = makeMarker('Circle')
|
| 210 |
+
|
| 211 |
+
drawing.add(lc)
|
| 212 |
+
|
| 213 |
+
return drawing
|
| 214 |
+
|
| 215 |
+
def calcPositions(self):
|
| 216 |
+
"""Works out where they go.
|
| 217 |
+
|
| 218 |
+
Sets an attribute _positions which is a list of
|
| 219 |
+
lists of (x, y) matching the data.
|
| 220 |
+
"""
|
| 221 |
+
|
| 222 |
+
self._seriesCount = len(self.data)
|
| 223 |
+
self._rowLength = max(list(map(len,self.data)))
|
| 224 |
+
|
| 225 |
+
if self.useAbsolute:
|
| 226 |
+
# Dimensions are absolute.
|
| 227 |
+
normFactor = 1.0
|
| 228 |
+
else:
|
| 229 |
+
# Dimensions are normalized to fit.
|
| 230 |
+
normWidth = self.groupSpacing
|
| 231 |
+
availWidth = self.categoryAxis.scale(0)[1]
|
| 232 |
+
normFactor = availWidth / normWidth
|
| 233 |
+
self._normFactor = normFactor
|
| 234 |
+
self._vzero = vzero = self.valueAxis.scale(0)
|
| 235 |
+
self._hngs = hngs = 0.5 * self.groupSpacing * normFactor
|
| 236 |
+
|
| 237 |
+
pairs = set()
|
| 238 |
+
P = [].append
|
| 239 |
+
cscale = self.categoryAxis.scale
|
| 240 |
+
vscale = self.valueAxis.scale
|
| 241 |
+
data = self.data
|
| 242 |
+
flipXY = self._flipXY
|
| 243 |
+
n = len(data)
|
| 244 |
+
for rowNo,row in enumerate(data):
|
| 245 |
+
if isinstance(row, FillPairedData):
|
| 246 |
+
other = row.other
|
| 247 |
+
if 0<=other<n:
|
| 248 |
+
if other==rowNo:
|
| 249 |
+
raise ValueError('data row %r may not be paired with itself' % rowNo)
|
| 250 |
+
t = (rowNo,other)
|
| 251 |
+
pairs.add((min(t),max(t)))
|
| 252 |
+
else:
|
| 253 |
+
raise ValueError('data row %r is paired with invalid data row %r' % (rowNo, other))
|
| 254 |
+
line = [].append
|
| 255 |
+
for colNo,datum in enumerate(row):
|
| 256 |
+
if datum is not None:
|
| 257 |
+
c, g = cscale(colNo)
|
| 258 |
+
v = vscale(datum)
|
| 259 |
+
line((v, c+hngs) if flipXY else (c+hngs, v))
|
| 260 |
+
P(line.__self__)
|
| 261 |
+
P = P.__self__
|
| 262 |
+
|
| 263 |
+
#if there are some paired lines we ensure only one is created
|
| 264 |
+
for rowNo, other in pairs:
|
| 265 |
+
P[rowNo] = FillPairedData(P[rowNo],other)
|
| 266 |
+
self._pairInFills = len(pairs)
|
| 267 |
+
self._positions = P
|
| 268 |
+
|
| 269 |
+
def _innerDrawLabel(self, rowNo, colNo, x, y):
|
| 270 |
+
"Draw a label for a given item in the list."
|
| 271 |
+
|
| 272 |
+
labelFmt = self.lineLabelFormat
|
| 273 |
+
labelValue = self.data[rowNo][colNo]
|
| 274 |
+
|
| 275 |
+
if labelFmt is None:
|
| 276 |
+
labelText = None
|
| 277 |
+
elif type(labelFmt) is str:
|
| 278 |
+
if labelFmt == 'values':
|
| 279 |
+
try:
|
| 280 |
+
labelText = self.lineLabelArray[rowNo][colNo]
|
| 281 |
+
except:
|
| 282 |
+
labelText = None
|
| 283 |
+
else:
|
| 284 |
+
labelText = labelFmt % labelValue
|
| 285 |
+
elif hasattr(labelFmt,'__call__'):
|
| 286 |
+
labelText = labelFmt(labelValue)
|
| 287 |
+
else:
|
| 288 |
+
raise ValueError("Unknown formatter type %s, expected string or function"%labelFmt)
|
| 289 |
+
|
| 290 |
+
if labelText:
|
| 291 |
+
label = self.lineLabels[(rowNo, colNo)]
|
| 292 |
+
if not label.visible: return
|
| 293 |
+
# Make sure labels are some distance off the data point.
|
| 294 |
+
if y > 0:
|
| 295 |
+
label.setOrigin(x, y + self.lineLabelNudge)
|
| 296 |
+
else:
|
| 297 |
+
label.setOrigin(x, y - self.lineLabelNudge)
|
| 298 |
+
label.setText(labelText)
|
| 299 |
+
else:
|
| 300 |
+
label = None
|
| 301 |
+
return label
|
| 302 |
+
|
| 303 |
+
def drawLabel(self, G, rowNo, colNo, x, y):
|
| 304 |
+
'''Draw a label for a given item in the list.
|
| 305 |
+
G must have an add method'''
|
| 306 |
+
G.add(self._innerDrawLabel(rowNo,colNo,x,y))
|
| 307 |
+
|
| 308 |
+
def makeLines(self):
|
| 309 |
+
g = Group()
|
| 310 |
+
|
| 311 |
+
labelFmt = self.lineLabelFormat
|
| 312 |
+
P = self._positions
|
| 313 |
+
if self.reversePlotOrder: P.reverse()
|
| 314 |
+
lines = self.lines
|
| 315 |
+
styleCount = len(lines)
|
| 316 |
+
flipXY = self._flipXY
|
| 317 |
+
cA = self.categoryAxis
|
| 318 |
+
vA = self.valueAxis
|
| 319 |
+
_inFill = self.inFill
|
| 320 |
+
if (_inFill or self._pairInFills or
|
| 321 |
+
[rowNo for rowNo in range(len(P))
|
| 322 |
+
if getattr(lines[rowNo%styleCount],'inFill',False)]
|
| 323 |
+
):
|
| 324 |
+
if flipXY:
|
| 325 |
+
infillC = cA._x
|
| 326 |
+
infillV0 = vA._y
|
| 327 |
+
infillV1 = infillV0 + cA._length
|
| 328 |
+
else:
|
| 329 |
+
infillC = cA._y
|
| 330 |
+
infillV0 = vA._x
|
| 331 |
+
infillV1 = infillV0 + cA._length
|
| 332 |
+
inFillG = getattr(self,'_inFillG',g)
|
| 333 |
+
vzero = self._vzero
|
| 334 |
+
bypos = None
|
| 335 |
+
|
| 336 |
+
# Iterate over data rows.
|
| 337 |
+
for rowNo, row in enumerate(reversed(P) if self.reversePlotOrder else P):
|
| 338 |
+
styleIdx = rowNo % styleCount
|
| 339 |
+
rowStyle = lines[styleIdx]
|
| 340 |
+
strokeColor = rowStyle.strokeColor
|
| 341 |
+
fillColor = getattr(rowStyle,'fillColor',strokeColor)
|
| 342 |
+
inFill = getattr(rowStyle,'inFill',_inFill)
|
| 343 |
+
dash = getattr(rowStyle, 'strokeDashArray', None)
|
| 344 |
+
lineStyle = getattr(rowStyle,'lineStyle',None)
|
| 345 |
+
|
| 346 |
+
if hasattr(rowStyle, 'strokeWidth'):
|
| 347 |
+
strokeWidth = rowStyle.strokeWidth
|
| 348 |
+
elif hasattr(lines, 'strokeWidth'):
|
| 349 |
+
strokeWidth = lines.strokeWidth
|
| 350 |
+
else:
|
| 351 |
+
strokeWidth = None
|
| 352 |
+
|
| 353 |
+
# Iterate over data columns.
|
| 354 |
+
if lineStyle=='bar':
|
| 355 |
+
if bypos is None:
|
| 356 |
+
if flipXY:
|
| 357 |
+
bypos = max(vA._x,vzero)
|
| 358 |
+
byneg = min(vA._x+vA._length,vzero)
|
| 359 |
+
else:
|
| 360 |
+
bypos = max(vA._y,vzero)
|
| 361 |
+
byneg = min(vA._y+vA._length,vzero)
|
| 362 |
+
barWidth = getattr(rowStyle,'barWidth',Percentage(50))
|
| 363 |
+
if isinstance(barWidth,Percentage):
|
| 364 |
+
hbw = self._hngs*barWidth*0.01
|
| 365 |
+
else:
|
| 366 |
+
hbw = barWidth*0.5
|
| 367 |
+
for x, y in row:
|
| 368 |
+
if flipXY:
|
| 369 |
+
v0 = byneg if x<vzero else bypos
|
| 370 |
+
t = v0, y-hbw, x-v0, 2*hbw
|
| 371 |
+
else:
|
| 372 |
+
v0 = byneg if y<vzero else bypos
|
| 373 |
+
t = x-hbw,v0,2*hbw,y-v0
|
| 374 |
+
g.add(Rect(*t,strokeWidth=strokeWidth,strokeColor=strokeColor,fillColor=fillColor))
|
| 375 |
+
elif self.joinedLines or lineStyle=='joinedLine':
|
| 376 |
+
points = flatten(row)
|
| 377 |
+
if inFill or isinstance(row,FillPairedData):
|
| 378 |
+
filler = getattr(rowStyle, 'filler', None)
|
| 379 |
+
if isinstance(row,FillPairedData):
|
| 380 |
+
fpoints = points + flatten(reversed(P[row.other]))
|
| 381 |
+
else:
|
| 382 |
+
if flipXY:
|
| 383 |
+
fpoints = [infillC,infillV0] + points + [infillC,infillV1]
|
| 384 |
+
else:
|
| 385 |
+
fpoints = [infillV0,infillC] + points + [infillV1,infillC]
|
| 386 |
+
if filler:
|
| 387 |
+
filler.fill(self,inFillG,rowNo,fillColor,fpoints)
|
| 388 |
+
else:
|
| 389 |
+
inFillG.add(Polygon(fpoints,fillColor=fillColor,strokeColor=strokeColor if strokeColor==fillColor else None,strokeWidth=strokeWidth or 0.1))
|
| 390 |
+
if not inFill or inFill==2 or strokeColor!=fillColor:
|
| 391 |
+
line = PolyLine(points,strokeColor=strokeColor,strokeLineCap=0,strokeLineJoin=1)
|
| 392 |
+
if strokeWidth:
|
| 393 |
+
line.strokeWidth = strokeWidth
|
| 394 |
+
if dash:
|
| 395 |
+
line.strokeDashArray = dash
|
| 396 |
+
g.add(line)
|
| 397 |
+
|
| 398 |
+
if hasattr(rowStyle, 'symbol'):
|
| 399 |
+
uSymbol = rowStyle.symbol
|
| 400 |
+
elif hasattr(lines, 'symbol'):
|
| 401 |
+
uSymbol = lines.symbol
|
| 402 |
+
else:
|
| 403 |
+
uSymbol = None
|
| 404 |
+
|
| 405 |
+
if uSymbol:
|
| 406 |
+
for colNo,(x,y) in enumerate(row):
|
| 407 |
+
symbol = uSymbol2Symbol(tpcGetItem(uSymbol,colNo),x,y,rowStyle.strokeColor)
|
| 408 |
+
if symbol: g.add(symbol)
|
| 409 |
+
|
| 410 |
+
# Draw item labels.
|
| 411 |
+
for colNo, (x, y) in enumerate(row):
|
| 412 |
+
self.drawLabel(g, rowNo, colNo, x, y)
|
| 413 |
+
|
| 414 |
+
return g
|
| 415 |
+
|
| 416 |
+
def draw(self):
|
| 417 |
+
"Draws itself."
|
| 418 |
+
|
| 419 |
+
vA, cA = self.valueAxis, self.categoryAxis
|
| 420 |
+
if self._flipXY:
|
| 421 |
+
vA.setPosition(self.x, self.y, self.width)
|
| 422 |
+
else:
|
| 423 |
+
vA.setPosition(self.x, self.y, self.height)
|
| 424 |
+
if vA: vA.joinAxis = cA
|
| 425 |
+
if cA: cA.joinAxis = vA
|
| 426 |
+
vA.configure(self.data)
|
| 427 |
+
|
| 428 |
+
y = self.y
|
| 429 |
+
x = self.x
|
| 430 |
+
if self._flipXY:
|
| 431 |
+
# If zero is in chart, put y axis there, otherwise
|
| 432 |
+
# use bottom.
|
| 433 |
+
crossesAt = vA.scale(0)
|
| 434 |
+
if not ((crossesAt > x + self.width) or (crossesAt < x)):
|
| 435 |
+
x = crossesAt
|
| 436 |
+
cA.setPosition(x, y, self.height)
|
| 437 |
+
else:
|
| 438 |
+
# If zero is in chart, put x axis there, otherwise
|
| 439 |
+
# use bottom.
|
| 440 |
+
crossesAt = vA.scale(0)
|
| 441 |
+
if not ((crossesAt > y + self.height) or (crossesAt < y)):
|
| 442 |
+
y = crossesAt
|
| 443 |
+
cA.setPosition(x, y, self.width)
|
| 444 |
+
cA.configure(self.data)
|
| 445 |
+
|
| 446 |
+
self.calcPositions()
|
| 447 |
+
|
| 448 |
+
g = Group()
|
| 449 |
+
g.add(self.makeBackground())
|
| 450 |
+
if self.inFill:
|
| 451 |
+
self._inFillG = Group()
|
| 452 |
+
g.add(self._inFillG)
|
| 453 |
+
|
| 454 |
+
g.add(cA)
|
| 455 |
+
g.add(vA)
|
| 456 |
+
cAdgl = getattr(cA,'drawGridLast',False)
|
| 457 |
+
vAdgl = getattr(vA,'drawGridLast',False)
|
| 458 |
+
if not cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
|
| 459 |
+
if not vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
|
| 460 |
+
g.add(self.makeLines())
|
| 461 |
+
if cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
|
| 462 |
+
if vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
|
| 463 |
+
for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale))
|
| 464 |
+
return g
|
| 465 |
+
|
| 466 |
+
def _fakeItemKey(a):
|
| 467 |
+
'''t, z0, z1, x, y = a[:5]'''
|
| 468 |
+
return (-a[1],a[3],a[0],-a[4])
|
| 469 |
+
|
| 470 |
+
class _FakeGroup:
|
| 471 |
+
def __init__(self):
|
| 472 |
+
self._data = []
|
| 473 |
+
|
| 474 |
+
def add(self,what):
|
| 475 |
+
if what: self._data.append(what)
|
| 476 |
+
|
| 477 |
+
def value(self):
|
| 478 |
+
return self._data
|
| 479 |
+
|
| 480 |
+
def sort(self):
|
| 481 |
+
self._data.sort(key=_fakeItemKey)
|
| 482 |
+
#for t in self._data: print t
|
| 483 |
+
|
| 484 |
+
class HorizontalLineChart3D(HorizontalLineChart):
|
| 485 |
+
_attrMap = AttrMap(BASE=HorizontalLineChart,
|
| 486 |
+
theta_x = AttrMapValue(isNumber, desc='dx/dz'),
|
| 487 |
+
theta_y = AttrMapValue(isNumber, desc='dy/dz'),
|
| 488 |
+
zDepth = AttrMapValue(isNumber, desc='depth of an individual series'),
|
| 489 |
+
zSpace = AttrMapValue(isNumber, desc='z gap around series'),
|
| 490 |
+
)
|
| 491 |
+
theta_x = .5
|
| 492 |
+
theta_y = .5
|
| 493 |
+
zDepth = 10
|
| 494 |
+
zSpace = 3
|
| 495 |
+
|
| 496 |
+
def calcPositions(self):
|
| 497 |
+
HorizontalLineChart.calcPositions(self)
|
| 498 |
+
nSeries = self._seriesCount
|
| 499 |
+
zSpace = self.zSpace
|
| 500 |
+
zDepth = self.zDepth
|
| 501 |
+
if self.categoryAxis.style=='parallel_3d':
|
| 502 |
+
_3d_depth = nSeries*zDepth+(nSeries+1)*zSpace
|
| 503 |
+
else:
|
| 504 |
+
_3d_depth = zDepth + 2*zSpace
|
| 505 |
+
self._3d_dx = self.theta_x*_3d_depth
|
| 506 |
+
self._3d_dy = self.theta_y*_3d_depth
|
| 507 |
+
|
| 508 |
+
def _calc_z0(self,rowNo):
|
| 509 |
+
zSpace = self.zSpace
|
| 510 |
+
if self.categoryAxis.style=='parallel_3d':
|
| 511 |
+
z0 = rowNo*(self.zDepth+zSpace)+zSpace
|
| 512 |
+
else:
|
| 513 |
+
z0 = zSpace
|
| 514 |
+
return z0
|
| 515 |
+
|
| 516 |
+
def _zadjust(self,x,y,z):
|
| 517 |
+
return x+z*self.theta_x, y+z*self.theta_y
|
| 518 |
+
|
| 519 |
+
def makeLines(self):
|
| 520 |
+
labelFmt = self.lineLabelFormat
|
| 521 |
+
P = list(range(len(self._positions)))
|
| 522 |
+
if self.reversePlotOrder: P.reverse()
|
| 523 |
+
inFill = self.inFill
|
| 524 |
+
assert not inFill, "inFill not supported for 3d yet"
|
| 525 |
+
#if inFill:
|
| 526 |
+
#inFillY = self.categoryAxis._y
|
| 527 |
+
#inFillX0 = self.valueAxis._x
|
| 528 |
+
#inFillX1 = inFillX0 + self.categoryAxis._length
|
| 529 |
+
#inFillG = getattr(self,'_inFillG',g)
|
| 530 |
+
zDepth = self.zDepth
|
| 531 |
+
_zadjust = self._zadjust
|
| 532 |
+
theta_x = self.theta_x
|
| 533 |
+
theta_y = self.theta_y
|
| 534 |
+
F = _FakeGroup()
|
| 535 |
+
from reportlab.graphics.charts.utils3d import _make_3d_line_info
|
| 536 |
+
tileWidth = getattr(self,'_3d_tilewidth',None)
|
| 537 |
+
if not tileWidth and self.categoryAxis.style!='parallel_3d': tileWidth = 1
|
| 538 |
+
|
| 539 |
+
# Iterate over data rows.
|
| 540 |
+
for rowNo in P:
|
| 541 |
+
row = self._positions[rowNo]
|
| 542 |
+
n = len(row)
|
| 543 |
+
styleCount = len(self.lines)
|
| 544 |
+
styleIdx = rowNo % styleCount
|
| 545 |
+
rowStyle = self.lines[styleIdx]
|
| 546 |
+
rowColor = rowStyle.strokeColor
|
| 547 |
+
dash = getattr(rowStyle, 'strokeDashArray', None)
|
| 548 |
+
z0 = self._calc_z0(rowNo)
|
| 549 |
+
z1 = z0 + zDepth
|
| 550 |
+
|
| 551 |
+
if hasattr(self.lines[styleIdx], 'strokeWidth'):
|
| 552 |
+
strokeWidth = self.lines[styleIdx].strokeWidth
|
| 553 |
+
elif hasattr(self.lines, 'strokeWidth'):
|
| 554 |
+
strokeWidth = self.lines.strokeWidth
|
| 555 |
+
else:
|
| 556 |
+
strokeWidth = None
|
| 557 |
+
|
| 558 |
+
# Iterate over data columns.
|
| 559 |
+
if self.joinedLines:
|
| 560 |
+
if n:
|
| 561 |
+
x0, y0 = row[0]
|
| 562 |
+
for colNo in range(1,n):
|
| 563 |
+
x1, y1 = row[colNo]
|
| 564 |
+
_make_3d_line_info( F, x0, x1, y0, y1, z0, z1,
|
| 565 |
+
theta_x, theta_y,
|
| 566 |
+
rowColor, fillColorShaded=None, tileWidth=tileWidth,
|
| 567 |
+
strokeColor=None, strokeWidth=None, strokeDashArray=None,
|
| 568 |
+
shading=0.1)
|
| 569 |
+
x0, y0 = x1, y1
|
| 570 |
+
|
| 571 |
+
if hasattr(self.lines[styleIdx], 'symbol'):
|
| 572 |
+
uSymbol = self.lines[styleIdx].symbol
|
| 573 |
+
elif hasattr(self.lines, 'symbol'):
|
| 574 |
+
uSymbol = self.lines.symbol
|
| 575 |
+
else:
|
| 576 |
+
uSymbol = None
|
| 577 |
+
|
| 578 |
+
if uSymbol:
|
| 579 |
+
for colNo in range(n):
|
| 580 |
+
x1, y1 = row[colNo]
|
| 581 |
+
x1, y1 = _zadjust(x1,y1,z0)
|
| 582 |
+
symbol = uSymbol2Symbol(uSymbol,x1,y1,rowColor)
|
| 583 |
+
if symbol: F.add((2,z0,z0,x1,y1,symbol))
|
| 584 |
+
|
| 585 |
+
# Draw item labels.
|
| 586 |
+
for colNo in range(n):
|
| 587 |
+
x1, y1 = row[colNo]
|
| 588 |
+
x1, y1 = _zadjust(x1,y1,z0)
|
| 589 |
+
L = self._innerDrawLabel(rowNo, colNo, x1, y1)
|
| 590 |
+
if L: F.add((2,z0,z0,x1,y1,L))
|
| 591 |
+
|
| 592 |
+
F.sort()
|
| 593 |
+
g = Group()
|
| 594 |
+
for v in F.value(): g.add(v[-1])
|
| 595 |
+
return g
|
| 596 |
+
|
| 597 |
+
class VerticalLineChart(HorizontalLineChart):
|
| 598 |
+
_flipXY = 1
|
| 599 |
+
|
| 600 |
+
def sample1():
|
| 601 |
+
drawing = Drawing(400, 200)
|
| 602 |
+
|
| 603 |
+
data = [
|
| 604 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 605 |
+
(5, 20, 46, 38, 23, 21, 6, 14)
|
| 606 |
+
]
|
| 607 |
+
|
| 608 |
+
lc = HorizontalLineChart()
|
| 609 |
+
|
| 610 |
+
lc.x = 50
|
| 611 |
+
lc.y = 50
|
| 612 |
+
lc.height = 125
|
| 613 |
+
lc.width = 300
|
| 614 |
+
lc.data = data
|
| 615 |
+
lc.joinedLines = 1
|
| 616 |
+
lc.lines.symbol = makeMarker('FilledDiamond')
|
| 617 |
+
lc.lineLabelFormat = '%2.0f'
|
| 618 |
+
|
| 619 |
+
catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
|
| 620 |
+
lc.categoryAxis.categoryNames = catNames
|
| 621 |
+
lc.categoryAxis.labels.boxAnchor = 'n'
|
| 622 |
+
|
| 623 |
+
lc.valueAxis.valueMin = 0
|
| 624 |
+
lc.valueAxis.valueMax = 60
|
| 625 |
+
lc.valueAxis.valueStep = 15
|
| 626 |
+
|
| 627 |
+
drawing.add(lc)
|
| 628 |
+
|
| 629 |
+
return drawing
|
| 630 |
+
|
| 631 |
+
class SampleHorizontalLineChart(HorizontalLineChart):
|
| 632 |
+
"Sample class overwriting one method to draw additional horizontal lines."
|
| 633 |
+
|
| 634 |
+
def demo(self):
|
| 635 |
+
"""Shows basic use of a line chart."""
|
| 636 |
+
|
| 637 |
+
drawing = Drawing(200, 100)
|
| 638 |
+
|
| 639 |
+
data = [
|
| 640 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 641 |
+
(14, 10, 21, 28, 38, 46, 25, 5)
|
| 642 |
+
]
|
| 643 |
+
|
| 644 |
+
lc = SampleHorizontalLineChart()
|
| 645 |
+
|
| 646 |
+
lc.x = 20
|
| 647 |
+
lc.y = 10
|
| 648 |
+
lc.height = 85
|
| 649 |
+
lc.width = 170
|
| 650 |
+
lc.data = data
|
| 651 |
+
lc.strokeColor = colors.white
|
| 652 |
+
lc.fillColor = colors.HexColor(0xCCCCCC)
|
| 653 |
+
|
| 654 |
+
drawing.add(lc)
|
| 655 |
+
|
| 656 |
+
return drawing
|
| 657 |
+
|
| 658 |
+
def makeBackground(self):
|
| 659 |
+
g = Group()
|
| 660 |
+
|
| 661 |
+
g.add(HorizontalLineChart.makeBackground(self))
|
| 662 |
+
|
| 663 |
+
valAxis = self.valueAxis
|
| 664 |
+
valTickPositions = valAxis._tickValues
|
| 665 |
+
|
| 666 |
+
for y in valTickPositions:
|
| 667 |
+
y = valAxis.scale(y)
|
| 668 |
+
g.add(Line(self.x, y, self.x+self.width, y,
|
| 669 |
+
strokeColor = self.strokeColor))
|
| 670 |
+
|
| 671 |
+
return g
|
| 672 |
+
|
| 673 |
+
def sample1a():
|
| 674 |
+
drawing = Drawing(400, 200)
|
| 675 |
+
|
| 676 |
+
data = [
|
| 677 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 678 |
+
(5, 20, 46, 38, 23, 21, 6, 14)
|
| 679 |
+
]
|
| 680 |
+
|
| 681 |
+
lc = SampleHorizontalLineChart()
|
| 682 |
+
|
| 683 |
+
lc.x = 50
|
| 684 |
+
lc.y = 50
|
| 685 |
+
lc.height = 125
|
| 686 |
+
lc.width = 300
|
| 687 |
+
lc.data = data
|
| 688 |
+
lc.joinedLines = 1
|
| 689 |
+
lc.strokeColor = colors.white
|
| 690 |
+
lc.fillColor = colors.HexColor(0xCCCCCC)
|
| 691 |
+
lc.lines.symbol = makeMarker('FilledDiamond')
|
| 692 |
+
lc.lineLabelFormat = '%2.0f'
|
| 693 |
+
|
| 694 |
+
catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
|
| 695 |
+
lc.categoryAxis.categoryNames = catNames
|
| 696 |
+
lc.categoryAxis.labels.boxAnchor = 'n'
|
| 697 |
+
|
| 698 |
+
lc.valueAxis.valueMin = 0
|
| 699 |
+
lc.valueAxis.valueMax = 60
|
| 700 |
+
lc.valueAxis.valueStep = 15
|
| 701 |
+
|
| 702 |
+
drawing.add(lc)
|
| 703 |
+
|
| 704 |
+
return drawing
|
| 705 |
+
|
| 706 |
+
def sample2():
|
| 707 |
+
drawing = Drawing(400, 200)
|
| 708 |
+
|
| 709 |
+
data = [
|
| 710 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 711 |
+
(5, 20, 46, 38, 23, 21, 6, 14)
|
| 712 |
+
]
|
| 713 |
+
|
| 714 |
+
lc = HorizontalLineChart()
|
| 715 |
+
|
| 716 |
+
lc.x = 50
|
| 717 |
+
lc.y = 50
|
| 718 |
+
lc.height = 125
|
| 719 |
+
lc.width = 300
|
| 720 |
+
lc.data = data
|
| 721 |
+
lc.joinedLines = 1
|
| 722 |
+
lc.lines.symbol = makeMarker('Smiley')
|
| 723 |
+
lc.lineLabelFormat = '%2.0f'
|
| 724 |
+
lc.strokeColor = colors.black
|
| 725 |
+
lc.fillColor = colors.lightblue
|
| 726 |
+
|
| 727 |
+
catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
|
| 728 |
+
lc.categoryAxis.categoryNames = catNames
|
| 729 |
+
lc.categoryAxis.labels.boxAnchor = 'n'
|
| 730 |
+
|
| 731 |
+
lc.valueAxis.valueMin = 0
|
| 732 |
+
lc.valueAxis.valueMax = 60
|
| 733 |
+
lc.valueAxis.valueStep = 15
|
| 734 |
+
|
| 735 |
+
drawing.add(lc)
|
| 736 |
+
|
| 737 |
+
return drawing
|
| 738 |
+
|
| 739 |
+
def sample3():
|
| 740 |
+
drawing = Drawing(400, 200)
|
| 741 |
+
|
| 742 |
+
data = [
|
| 743 |
+
(13, 5, 20, 22, 37, 45, 19, 4),
|
| 744 |
+
(5, 20, 46, 38, 23, 21, 6, 14)
|
| 745 |
+
]
|
| 746 |
+
|
| 747 |
+
lc = HorizontalLineChart()
|
| 748 |
+
|
| 749 |
+
lc.x = 50
|
| 750 |
+
lc.y = 50
|
| 751 |
+
lc.height = 125
|
| 752 |
+
lc.width = 300
|
| 753 |
+
lc.data = data
|
| 754 |
+
lc.joinedLines = 1
|
| 755 |
+
lc.lineLabelFormat = '%2.0f'
|
| 756 |
+
lc.strokeColor = colors.black
|
| 757 |
+
|
| 758 |
+
lc.lines[0].symbol = makeMarker('Smiley')
|
| 759 |
+
lc.lines[1].symbol = NoEntry
|
| 760 |
+
lc.lines[0].strokeWidth = 2
|
| 761 |
+
lc.lines[1].strokeWidth = 4
|
| 762 |
+
|
| 763 |
+
catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
|
| 764 |
+
lc.categoryAxis.categoryNames = catNames
|
| 765 |
+
lc.categoryAxis.labels.boxAnchor = 'n'
|
| 766 |
+
|
| 767 |
+
lc.valueAxis.valueMin = 0
|
| 768 |
+
lc.valueAxis.valueMax = 60
|
| 769 |
+
lc.valueAxis.valueStep = 15
|
| 770 |
+
|
| 771 |
+
drawing.add(lc)
|
| 772 |
+
|
| 773 |
+
return drawing
|
| 774 |
+
|
| 775 |
+
def sampleCandleStick():
|
| 776 |
+
from reportlab.graphics.widgetbase import CandleSticks
|
| 777 |
+
d = Drawing(400, 200)
|
| 778 |
+
chart = HorizontalLineChart()
|
| 779 |
+
d.add(chart)
|
| 780 |
+
chart.y = 20
|
| 781 |
+
boxMid = (100, 110, 120, 130)
|
| 782 |
+
hi = [m+10 for m in boxMid]
|
| 783 |
+
lo = [m-10 for m in boxMid]
|
| 784 |
+
boxHi = [m+6 for m in boxMid]
|
| 785 |
+
boxLo = [m-4 for m in boxMid]
|
| 786 |
+
boxFillColor = colors.pink
|
| 787 |
+
boxWidth = 20
|
| 788 |
+
crossWidth = 10
|
| 789 |
+
candleStrokeWidth = 0.5
|
| 790 |
+
candleStrokeColor = colors.black
|
| 791 |
+
chart.valueAxis.avoidBoundSpace = 5
|
| 792 |
+
|
| 793 |
+
chart.valueAxis.valueMin = min(min(boxMid),min(hi),min(lo),min(boxLo),min(boxHi))
|
| 794 |
+
chart.valueAxis.valueMax = max(max(boxMid),max(hi),max(lo),max(boxLo),max(boxHi))
|
| 795 |
+
lines = chart.lines
|
| 796 |
+
lines[0].strokeColor = None
|
| 797 |
+
I = range(len(boxMid))
|
| 798 |
+
chart.data = [boxMid]
|
| 799 |
+
lines[0].symbol = candles = CandleSticks(chart=chart, boxFillColor=boxFillColor, boxWidth=boxWidth, crossWidth=crossWidth, strokeWidth=candleStrokeWidth, strokeColor=candleStrokeColor)
|
| 800 |
+
for i in I: candles[i].setProperties(dict(position=i,boxMid=boxMid[i],crossLo=lo[i],crossHi=hi[i],boxLo=boxLo[i],boxHi=boxHi[i]))
|
| 801 |
+
return d
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
__doc__="""Example drawings to review, used in autogenerated docs"""
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/bubble.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import ScatterPlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class Bubble(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.lines[0].strokeColor = color01
|
| 17 |
+
self.chart.lines[1].strokeColor = color02
|
| 18 |
+
self.chart.lines[2].strokeColor = color03
|
| 19 |
+
self.chart.lines[3].strokeColor = color04
|
| 20 |
+
self.chart.lines[4].strokeColor = color05
|
| 21 |
+
self.chart.lines[5].strokeColor = color06
|
| 22 |
+
self.chart.lines[6].strokeColor = color07
|
| 23 |
+
self.chart.lines[7].strokeColor = color08
|
| 24 |
+
self.chart.lines[8].strokeColor = color09
|
| 25 |
+
self.chart.lines[9].strokeColor = color10
|
| 26 |
+
self.chart.lines.symbol.kind ='Circle'
|
| 27 |
+
self.chart.lines.symbol.size = 15
|
| 28 |
+
self.chart.fillColor = backgroundGrey
|
| 29 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 30 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 31 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 32 |
+
self.chart.xValueAxis.forceZero = 0
|
| 33 |
+
self.chart.data = [((100,100), (200,200), (250,210), (300,300), (350,450))]
|
| 34 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 35 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 36 |
+
self.chart.xValueAxis.tickDown = 3
|
| 37 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 38 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 39 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 41 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 42 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 43 |
+
self.Title.fontSize = 7
|
| 44 |
+
self.Title.x = 100
|
| 45 |
+
self.Title.y = 135
|
| 46 |
+
self.Title._text = 'Chart Title'
|
| 47 |
+
self.Title.maxWidth = 180
|
| 48 |
+
self.Title.height = 20
|
| 49 |
+
self.Title.textAnchor ='middle'
|
| 50 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 51 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets')]
|
| 52 |
+
self.Legend.fontName = 'Helvetica'
|
| 53 |
+
self.Legend.fontSize = 7
|
| 54 |
+
self.Legend.x = 153
|
| 55 |
+
self.Legend.y = 85
|
| 56 |
+
self.Legend.dxTextSpace = 5
|
| 57 |
+
self.Legend.dy = 5
|
| 58 |
+
self.Legend.dx = 5
|
| 59 |
+
self.Legend.deltay = 5
|
| 60 |
+
self.Legend.alignment ='right'
|
| 61 |
+
self.chart.lineLabelFormat = None
|
| 62 |
+
self.chart.xLabel = 'X Axis'
|
| 63 |
+
self.chart.y = 30
|
| 64 |
+
self.chart.yLabel = 'Y Axis'
|
| 65 |
+
self.chart.yValueAxis.labelTextFormat = '%d'
|
| 66 |
+
self.chart.yValueAxis.forceZero = 1
|
| 67 |
+
self.chart.xValueAxis.forceZero = 1
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 71 |
+
|
| 72 |
+
if __name__=="__main__": #NORUNTESTS
|
| 73 |
+
Bubble().save(formats=['pdf'],outDir=None,fnRoot='bubble')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_bar.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 4 |
+
from reportlab.graphics.charts.barcharts import HorizontalBarChart
|
| 5 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 6 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 7 |
+
|
| 8 |
+
class ClusteredBar(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.bars[0].fillColor = color01
|
| 17 |
+
self.chart.bars[1].fillColor = color02
|
| 18 |
+
self.chart.bars[2].fillColor = color03
|
| 19 |
+
self.chart.bars[3].fillColor = color04
|
| 20 |
+
self.chart.bars[4].fillColor = color05
|
| 21 |
+
self.chart.bars[5].fillColor = color06
|
| 22 |
+
self.chart.bars[6].fillColor = color07
|
| 23 |
+
self.chart.bars[7].fillColor = color08
|
| 24 |
+
self.chart.bars[8].fillColor = color09
|
| 25 |
+
self.chart.bars[9].fillColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.barLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.valueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.valueAxis.labels.fontSize = 6
|
| 30 |
+
self.chart.valueAxis.forceZero = 1
|
| 31 |
+
self.chart.data = [(100, 150, 180), (125, 180, 200)]
|
| 32 |
+
self.chart.groupSpacing = 15
|
| 33 |
+
self.chart.valueAxis.avoidBoundFrac = 1
|
| 34 |
+
self.chart.valueAxis.gridEnd = 80
|
| 35 |
+
self.chart.valueAxis.tickDown = 3
|
| 36 |
+
self.chart.valueAxis.visibleGrid = 1
|
| 37 |
+
self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central']
|
| 38 |
+
self.chart.categoryAxis.tickLeft = 3
|
| 39 |
+
self.chart.categoryAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.categoryAxis.labels.fontSize = 6
|
| 41 |
+
self.chart.categoryAxis.labels.dx = -3
|
| 42 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 43 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 44 |
+
self.Title.fontSize = 7
|
| 45 |
+
self.Title.x = 100
|
| 46 |
+
self.Title.y = 135
|
| 47 |
+
self.Title._text = 'Chart Title'
|
| 48 |
+
self.Title.maxWidth = 180
|
| 49 |
+
self.Title.height = 20
|
| 50 |
+
self.Title.textAnchor ='middle'
|
| 51 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 52 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 53 |
+
self.Legend.fontName = 'Helvetica'
|
| 54 |
+
self.Legend.fontSize = 7
|
| 55 |
+
self.Legend.x = 153
|
| 56 |
+
self.Legend.y = 85
|
| 57 |
+
self.Legend.dxTextSpace = 5
|
| 58 |
+
self.Legend.dy = 5
|
| 59 |
+
self.Legend.dx = 5
|
| 60 |
+
self.Legend.deltay = 5
|
| 61 |
+
self.Legend.alignment ='right'
|
| 62 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 63 |
+
self.XLabel.fontName = 'Helvetica'
|
| 64 |
+
self.XLabel.fontSize = 7
|
| 65 |
+
self.XLabel.x = 85
|
| 66 |
+
self.XLabel.y = 10
|
| 67 |
+
self.XLabel.textAnchor ='middle'
|
| 68 |
+
self.XLabel.maxWidth = 100
|
| 69 |
+
self.XLabel.height = 20
|
| 70 |
+
self.XLabel._text = "X Axis"
|
| 71 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 72 |
+
self.YLabel.fontName = 'Helvetica'
|
| 73 |
+
self.YLabel.fontSize = 7
|
| 74 |
+
self.YLabel.x = 12
|
| 75 |
+
self.YLabel.y = 80
|
| 76 |
+
self.YLabel.angle = 90
|
| 77 |
+
self.YLabel.textAnchor ='middle'
|
| 78 |
+
self.YLabel.maxWidth = 100
|
| 79 |
+
self.YLabel.height = 20
|
| 80 |
+
self.YLabel._text = "Y Axis"
|
| 81 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 82 |
+
|
| 83 |
+
if __name__=="__main__": #NORUNTESTS
|
| 84 |
+
ClusteredBar().save(formats=['pdf'],outDir=None,fnRoot='clustered_bar')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_column.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 4 |
+
from reportlab.graphics.charts.barcharts import VerticalBarChart
|
| 5 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 6 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 7 |
+
|
| 8 |
+
class ClusteredColumn(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.bars[0].fillColor = color01
|
| 17 |
+
self.chart.bars[1].fillColor = color02
|
| 18 |
+
self.chart.bars[2].fillColor = color03
|
| 19 |
+
self.chart.bars[3].fillColor = color04
|
| 20 |
+
self.chart.bars[4].fillColor = color05
|
| 21 |
+
self.chart.bars[5].fillColor = color06
|
| 22 |
+
self.chart.bars[6].fillColor = color07
|
| 23 |
+
self.chart.bars[7].fillColor = color08
|
| 24 |
+
self.chart.bars[8].fillColor = color09
|
| 25 |
+
self.chart.bars[9].fillColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.barLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.valueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.valueAxis.labels.fontSize = 7
|
| 30 |
+
self.chart.valueAxis.forceZero = 1
|
| 31 |
+
self.chart.data = [(100, 150, 180), (125, 180, 200)]
|
| 32 |
+
self.chart.groupSpacing = 15
|
| 33 |
+
self.chart.valueAxis.avoidBoundFrac = 1
|
| 34 |
+
self.chart.valueAxis.gridEnd = 115
|
| 35 |
+
self.chart.valueAxis.tickLeft = 3
|
| 36 |
+
self.chart.valueAxis.visibleGrid = 1
|
| 37 |
+
self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central']
|
| 38 |
+
self.chart.categoryAxis.tickDown = 3
|
| 39 |
+
self.chart.categoryAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.categoryAxis.labels.fontSize = 7
|
| 41 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 42 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 43 |
+
self.Title.fontSize = 7
|
| 44 |
+
self.Title.x = 100
|
| 45 |
+
self.Title.y = 135
|
| 46 |
+
self.Title._text = 'Chart Title'
|
| 47 |
+
self.Title.maxWidth = 180
|
| 48 |
+
self.Title.height = 20
|
| 49 |
+
self.Title.textAnchor ='middle'
|
| 50 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 51 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 52 |
+
self.Legend.fontName = 'Helvetica'
|
| 53 |
+
self.Legend.fontSize = 7
|
| 54 |
+
self.Legend.x = 153
|
| 55 |
+
self.Legend.y = 85
|
| 56 |
+
self.Legend.dxTextSpace = 5
|
| 57 |
+
self.Legend.dy = 5
|
| 58 |
+
self.Legend.dx = 5
|
| 59 |
+
self.Legend.deltay = 5
|
| 60 |
+
self.Legend.alignment ='right'
|
| 61 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 62 |
+
self.XLabel.fontName = 'Helvetica'
|
| 63 |
+
self.XLabel.fontSize = 7
|
| 64 |
+
self.XLabel.x = 85
|
| 65 |
+
self.XLabel.y = 10
|
| 66 |
+
self.XLabel.textAnchor ='middle'
|
| 67 |
+
self.XLabel.maxWidth = 100
|
| 68 |
+
self.XLabel.height = 20
|
| 69 |
+
self.XLabel._text = "X Axis"
|
| 70 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 71 |
+
self.YLabel.fontName = 'Helvetica'
|
| 72 |
+
self.YLabel.fontSize = 7
|
| 73 |
+
self.YLabel.x = 12
|
| 74 |
+
self.YLabel.y = 80
|
| 75 |
+
self.YLabel.angle = 90
|
| 76 |
+
self.YLabel.textAnchor ='middle'
|
| 77 |
+
self.YLabel.maxWidth = 100
|
| 78 |
+
self.YLabel.height = 20
|
| 79 |
+
self.YLabel._text = "Y Axis"
|
| 80 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 81 |
+
|
| 82 |
+
if __name__=="__main__": #NORUNTESTS
|
| 83 |
+
ClusteredColumn().save(formats=['pdf'],outDir=None,fnRoot='clustered_column')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/excelcolors.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# define standard colors to mimic those used by Microsoft Excel
|
| 2 |
+
from reportlab.lib.colors import PCMYKColor
|
| 3 |
+
|
| 4 |
+
#colour names as comments at the end of each line are as a memory jogger ONLY
|
| 5 |
+
#NOT HTML named colours!
|
| 6 |
+
|
| 7 |
+
#Main colours as used for bars etc
|
| 8 |
+
color01 = PCMYKColor(40,40,0,0) # Lavender
|
| 9 |
+
color02 = PCMYKColor(0,66,33,39) # Maroon
|
| 10 |
+
color03 = PCMYKColor(0,0,20,0) # Yellow
|
| 11 |
+
color04 = PCMYKColor(20,0,0,0) # Cyan
|
| 12 |
+
color05 = PCMYKColor(0,100,0,59) # Purple
|
| 13 |
+
color06 = PCMYKColor(0,49,49,0) # Salmon
|
| 14 |
+
color07 = PCMYKColor(100,49,0,19) # Blue
|
| 15 |
+
color08 = PCMYKColor(20,20,0,0) # PaleLavender
|
| 16 |
+
color09 = PCMYKColor(100,100,0,49) # NavyBlue
|
| 17 |
+
color10 = PCMYKColor(0,100,0,0) # Purple
|
| 18 |
+
|
| 19 |
+
#Highlight colors - eg for the tops of bars
|
| 20 |
+
color01Light = PCMYKColor(39,39,0,25) # Light Lavender
|
| 21 |
+
color02Light = PCMYKColor(0,66,33,54) # Light Maroon
|
| 22 |
+
color03Light = PCMYKColor(0,0,19,25) # Light Yellow
|
| 23 |
+
color04Light = PCMYKColor(19,0,0,25) # Light Cyan
|
| 24 |
+
color05Light = PCMYKColor(0,100,0,69) # Light Purple
|
| 25 |
+
color06Light = PCMYKColor(0,49,49,25) # Light Salmon
|
| 26 |
+
color07Light = PCMYKColor(100,49,0,39) # Light Blue
|
| 27 |
+
color08Light = PCMYKColor(19,19,0,25) # Light PaleLavender
|
| 28 |
+
color09Light = PCMYKColor(100,100,0,62) # Light NavyBlue
|
| 29 |
+
color10Light = PCMYKColor(0,100,0,25) # Light Purple
|
| 30 |
+
|
| 31 |
+
#Lowlight colors - eg for the sides of bars
|
| 32 |
+
color01Dark = PCMYKColor(39,39,0,49) # Dark Lavender
|
| 33 |
+
color02Dark = PCMYKColor(0,66,33,69) # Dark Maroon
|
| 34 |
+
color03Dark = PCMYKColor(0,0,20,49) # Dark Yellow
|
| 35 |
+
color04Dark = PCMYKColor(20,0,0,49) # Dark Cyan
|
| 36 |
+
color05Dark = PCMYKColor(0,100,0,80) # Dark Purple
|
| 37 |
+
color06Dark = PCMYKColor(0,50,50,49) # Dark Salmon
|
| 38 |
+
color07Dark = PCMYKColor(100,50,0,59) # Dark Blue
|
| 39 |
+
color08Dark = PCMYKColor(20,20,0,49) # Dark PaleLavender
|
| 40 |
+
color09Dark = PCMYKColor(100,100,0,79) # Dark NavyBlue
|
| 41 |
+
color10Dark = PCMYKColor(0,100,0,49) # Dark Purple
|
| 42 |
+
|
| 43 |
+
#for standard grey backgrounds
|
| 44 |
+
backgroundGrey = PCMYKColor(0,0,0,24)
|
| 45 |
+
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/exploded_pie.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.piecharts import Pie
|
| 3 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 4 |
+
from reportlab.graphics.widgets.grids import ShadedRect
|
| 5 |
+
from reportlab.graphics.charts.legends import Legend
|
| 6 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 7 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 8 |
+
|
| 9 |
+
class ExplodedPie(_DrawingEditorMixin,Drawing):
|
| 10 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 11 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 12 |
+
self._add(self,Pie(),name='chart',validate=None,desc="The main chart")
|
| 13 |
+
self.chart.width = 100
|
| 14 |
+
self.chart.height = 100
|
| 15 |
+
self.chart.x = 25
|
| 16 |
+
self.chart.y = 25
|
| 17 |
+
self.chart.slices[0].fillColor = color01
|
| 18 |
+
self.chart.slices[1].fillColor = color02
|
| 19 |
+
self.chart.slices[2].fillColor = color03
|
| 20 |
+
self.chart.slices[3].fillColor = color04
|
| 21 |
+
self.chart.slices[4].fillColor = color05
|
| 22 |
+
self.chart.slices[5].fillColor = color06
|
| 23 |
+
self.chart.slices[6].fillColor = color07
|
| 24 |
+
self.chart.slices[7].fillColor = color08
|
| 25 |
+
self.chart.slices[8].fillColor = color09
|
| 26 |
+
self.chart.slices[9].fillColor = color10
|
| 27 |
+
self.chart.data = (100, 150, 180)
|
| 28 |
+
self.chart.startAngle = -90
|
| 29 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 30 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 31 |
+
self.Title.fontSize = 7
|
| 32 |
+
self.Title.x = 100
|
| 33 |
+
self.Title.y = 135
|
| 34 |
+
self.Title._text = 'Chart Title'
|
| 35 |
+
self.Title.maxWidth = 180
|
| 36 |
+
self.Title.height = 20
|
| 37 |
+
self.Title.textAnchor ='middle'
|
| 38 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 39 |
+
self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'), (color03, 'Central')]
|
| 40 |
+
self.Legend.fontName = 'Helvetica'
|
| 41 |
+
self.Legend.fontSize = 7
|
| 42 |
+
self.Legend.x = 160
|
| 43 |
+
self.Legend.y = 85
|
| 44 |
+
self.Legend.dxTextSpace = 5
|
| 45 |
+
self.Legend.dy = 5
|
| 46 |
+
self.Legend.dx = 5
|
| 47 |
+
self.Legend.deltay = 5
|
| 48 |
+
self.Legend.alignment ='right'
|
| 49 |
+
self.Legend.columnMaximum = 10
|
| 50 |
+
self.chart.slices.strokeWidth = 1
|
| 51 |
+
self.chart.slices.fontName = 'Helvetica'
|
| 52 |
+
self.background = ShadedRect()
|
| 53 |
+
self.background.fillColorStart = backgroundGrey
|
| 54 |
+
self.background.fillColorEnd = backgroundGrey
|
| 55 |
+
self.background.numShades = 1
|
| 56 |
+
self.background.strokeWidth = 0.5
|
| 57 |
+
self.background.x = 20
|
| 58 |
+
self.background.y = 20
|
| 59 |
+
self.chart.slices.popout = 5
|
| 60 |
+
self.background.height = 110
|
| 61 |
+
self.background.width = 110
|
| 62 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 63 |
+
|
| 64 |
+
if __name__=="__main__": #NORUNTESTS
|
| 65 |
+
ExplodedPie().save(formats=['pdf'],outDir=None,fnRoot='exploded_pie')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/filled_radar.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.spider import SpiderChart
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class FilledRadarChart(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 90
|
| 13 |
+
self.chart.height = 90
|
| 14 |
+
self.chart.x = 45
|
| 15 |
+
self.chart.y = 25
|
| 16 |
+
self.chart.strands[0].fillColor = color01
|
| 17 |
+
self.chart.strands[1].fillColor = color02
|
| 18 |
+
self.chart.strands[2].fillColor = color03
|
| 19 |
+
self.chart.strands[3].fillColor = color04
|
| 20 |
+
self.chart.strands[4].fillColor = color05
|
| 21 |
+
self.chart.strands[5].fillColor = color06
|
| 22 |
+
self.chart.strands[6].fillColor = color07
|
| 23 |
+
self.chart.strands[7].fillColor = color08
|
| 24 |
+
self.chart.strands[8].fillColor = color09
|
| 25 |
+
self.chart.strands[9].fillColor = color10
|
| 26 |
+
self.chart.strandLabels.fontName = 'Helvetica'
|
| 27 |
+
self.chart.strandLabels.fontSize = 6
|
| 28 |
+
self.chart.fillColor = backgroundGrey
|
| 29 |
+
self.chart.data = [(125, 180, 200), (100, 150, 180)]
|
| 30 |
+
self.chart.labels = ['North', 'South', 'Central']
|
| 31 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 32 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 33 |
+
self.Title.fontSize = 7
|
| 34 |
+
self.Title.x = 100
|
| 35 |
+
self.Title.y = 135
|
| 36 |
+
self.Title._text = 'Chart Title'
|
| 37 |
+
self.Title.maxWidth = 180
|
| 38 |
+
self.Title.height = 20
|
| 39 |
+
self.Title.textAnchor ='middle'
|
| 40 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 41 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 42 |
+
self.Legend.fontName = 'Helvetica'
|
| 43 |
+
self.Legend.fontSize = 7
|
| 44 |
+
self.Legend.x = 153
|
| 45 |
+
self.Legend.y = 85
|
| 46 |
+
self.Legend.dxTextSpace = 5
|
| 47 |
+
self.Legend.dy = 5
|
| 48 |
+
self.Legend.dx = 5
|
| 49 |
+
self.Legend.deltay = 5
|
| 50 |
+
self.Legend.alignment ='right'
|
| 51 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 52 |
+
|
| 53 |
+
if __name__=="__main__": #NORUNTESTS
|
| 54 |
+
FilledRadarChart().save(formats=['pdf'],outDir=None,fnRoot='filled_radar')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/line_chart.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import LinePlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class LineChart(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.lines[0].strokeColor = color01
|
| 17 |
+
self.chart.lines[1].strokeColor = color02
|
| 18 |
+
self.chart.lines[2].strokeColor = color03
|
| 19 |
+
self.chart.lines[3].strokeColor = color04
|
| 20 |
+
self.chart.lines[4].strokeColor = color05
|
| 21 |
+
self.chart.lines[5].strokeColor = color06
|
| 22 |
+
self.chart.lines[6].strokeColor = color07
|
| 23 |
+
self.chart.lines[7].strokeColor = color08
|
| 24 |
+
self.chart.lines[8].strokeColor = color09
|
| 25 |
+
self.chart.lines[9].strokeColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 30 |
+
self.chart.xValueAxis.forceZero = 0
|
| 31 |
+
self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))]
|
| 32 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 33 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 34 |
+
self.chart.xValueAxis.tickDown = 3
|
| 35 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 36 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 37 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 38 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 39 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 40 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 41 |
+
self.Title.fontSize = 7
|
| 42 |
+
self.Title.x = 100
|
| 43 |
+
self.Title.y = 135
|
| 44 |
+
self.Title._text = 'Chart Title'
|
| 45 |
+
self.Title.maxWidth = 180
|
| 46 |
+
self.Title.height = 20
|
| 47 |
+
self.Title.textAnchor ='middle'
|
| 48 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 49 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 50 |
+
self.Legend.fontName = 'Helvetica'
|
| 51 |
+
self.Legend.fontSize = 7
|
| 52 |
+
self.Legend.x = 153
|
| 53 |
+
self.Legend.y = 85
|
| 54 |
+
self.Legend.dxTextSpace = 5
|
| 55 |
+
self.Legend.dy = 5
|
| 56 |
+
self.Legend.dx = 5
|
| 57 |
+
self.Legend.deltay = 5
|
| 58 |
+
self.Legend.alignment ='right'
|
| 59 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 60 |
+
self.XLabel.fontName = 'Helvetica'
|
| 61 |
+
self.XLabel.fontSize = 7
|
| 62 |
+
self.XLabel.x = 85
|
| 63 |
+
self.XLabel.y = 10
|
| 64 |
+
self.XLabel.textAnchor ='middle'
|
| 65 |
+
self.XLabel.maxWidth = 100
|
| 66 |
+
self.XLabel.height = 20
|
| 67 |
+
self.XLabel._text = "X Axis"
|
| 68 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 69 |
+
self.YLabel.fontName = 'Helvetica'
|
| 70 |
+
self.YLabel.fontSize = 7
|
| 71 |
+
self.YLabel.x = 12
|
| 72 |
+
self.YLabel.y = 80
|
| 73 |
+
self.YLabel.angle = 90
|
| 74 |
+
self.YLabel.textAnchor ='middle'
|
| 75 |
+
self.YLabel.maxWidth = 100
|
| 76 |
+
self.YLabel.height = 20
|
| 77 |
+
self.YLabel._text = "Y Axis"
|
| 78 |
+
self.chart.yValueAxis.forceZero = 1
|
| 79 |
+
self.chart.xValueAxis.forceZero = 1
|
| 80 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 81 |
+
|
| 82 |
+
if __name__=="__main__": #NORUNTESTS
|
| 83 |
+
LineChart().save(formats=['pdf'],outDir=None,fnRoot='line_chart')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/linechart_with_markers.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import LinePlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.widgets.markers import makeMarker
|
| 6 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 7 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 8 |
+
|
| 9 |
+
class LineChartWithMarkers(_DrawingEditorMixin,Drawing):
|
| 10 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 11 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 12 |
+
self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart")
|
| 13 |
+
self.chart.width = 115
|
| 14 |
+
self.chart.height = 80
|
| 15 |
+
self.chart.x = 30
|
| 16 |
+
self.chart.y = 40
|
| 17 |
+
self.chart.lines[0].strokeColor = color01
|
| 18 |
+
self.chart.lines[1].strokeColor = color02
|
| 19 |
+
self.chart.lines[2].strokeColor = color03
|
| 20 |
+
self.chart.lines[3].strokeColor = color04
|
| 21 |
+
self.chart.lines[4].strokeColor = color05
|
| 22 |
+
self.chart.lines[5].strokeColor = color06
|
| 23 |
+
self.chart.lines[6].strokeColor = color07
|
| 24 |
+
self.chart.lines[7].strokeColor = color08
|
| 25 |
+
self.chart.lines[8].strokeColor = color09
|
| 26 |
+
self.chart.lines[9].strokeColor = color10
|
| 27 |
+
self.chart.lines[0].symbol = makeMarker('FilledSquare')
|
| 28 |
+
self.chart.lines[1].symbol = makeMarker('FilledDiamond')
|
| 29 |
+
self.chart.lines[2].symbol = makeMarker('FilledStarFive')
|
| 30 |
+
self.chart.lines[3].symbol = makeMarker('FilledTriangle')
|
| 31 |
+
self.chart.lines[4].symbol = makeMarker('FilledCircle')
|
| 32 |
+
self.chart.lines[5].symbol = makeMarker('FilledPentagon')
|
| 33 |
+
self.chart.lines[6].symbol = makeMarker('FilledStarSix')
|
| 34 |
+
self.chart.lines[7].symbol = makeMarker('FilledHeptagon')
|
| 35 |
+
self.chart.lines[8].symbol = makeMarker('FilledOctagon')
|
| 36 |
+
self.chart.lines[9].symbol = makeMarker('FilledCross')
|
| 37 |
+
self.chart.fillColor = backgroundGrey
|
| 38 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 39 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 41 |
+
self.chart.xValueAxis.forceZero = 0
|
| 42 |
+
self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))]
|
| 43 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 44 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 45 |
+
self.chart.xValueAxis.tickDown = 3
|
| 46 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 47 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 48 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 49 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 50 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 51 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 52 |
+
self.Title.fontSize = 7
|
| 53 |
+
self.Title.x = 100
|
| 54 |
+
self.Title.y = 135
|
| 55 |
+
self.Title._text = 'Chart Title'
|
| 56 |
+
self.Title.maxWidth = 180
|
| 57 |
+
self.Title.height = 20
|
| 58 |
+
self.Title.textAnchor ='middle'
|
| 59 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 60 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 61 |
+
self.Legend.fontName = 'Helvetica'
|
| 62 |
+
self.Legend.fontSize = 7
|
| 63 |
+
self.Legend.x = 153
|
| 64 |
+
self.Legend.y = 85
|
| 65 |
+
self.Legend.dxTextSpace = 5
|
| 66 |
+
self.Legend.dy = 5
|
| 67 |
+
self.Legend.dx = 5
|
| 68 |
+
self.Legend.deltay = 5
|
| 69 |
+
self.Legend.alignment ='right'
|
| 70 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 71 |
+
self.XLabel.fontName = 'Helvetica'
|
| 72 |
+
self.XLabel.fontSize = 7
|
| 73 |
+
self.XLabel.x = 85
|
| 74 |
+
self.XLabel.y = 10
|
| 75 |
+
self.XLabel.textAnchor ='middle'
|
| 76 |
+
self.XLabel.maxWidth = 100
|
| 77 |
+
self.XLabel.height = 20
|
| 78 |
+
self.XLabel._text = "X Axis"
|
| 79 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 80 |
+
self.YLabel.fontName = 'Helvetica'
|
| 81 |
+
self.YLabel.fontSize = 7
|
| 82 |
+
self.YLabel.x = 12
|
| 83 |
+
self.YLabel.y = 80
|
| 84 |
+
self.YLabel.angle = 90
|
| 85 |
+
self.YLabel.textAnchor ='middle'
|
| 86 |
+
self.YLabel.maxWidth = 100
|
| 87 |
+
self.YLabel.height = 20
|
| 88 |
+
self.YLabel._text = "Y Axis"
|
| 89 |
+
self.chart.yValueAxis.forceZero = 1
|
| 90 |
+
self.chart.xValueAxis.forceZero = 1
|
| 91 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 92 |
+
|
| 93 |
+
if __name__=="__main__": #NORUNTESTS
|
| 94 |
+
LineChartWithMarkers().save(formats=['pdf'],outDir=None,fnRoot='linechart_with_markers')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/radar.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 4 |
+
from reportlab.graphics.charts.spider import SpiderChart
|
| 5 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 6 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 7 |
+
|
| 8 |
+
class RadarChart(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 90
|
| 13 |
+
self.chart.height = 90
|
| 14 |
+
self.chart.x = 45
|
| 15 |
+
self.chart.y = 25
|
| 16 |
+
self.chart.strands[0].strokeColor= color01
|
| 17 |
+
self.chart.strands[1].strokeColor= color02
|
| 18 |
+
self.chart.strands[2].strokeColor= color03
|
| 19 |
+
self.chart.strands[3].strokeColor= color04
|
| 20 |
+
self.chart.strands[4].strokeColor= color05
|
| 21 |
+
self.chart.strands[5].strokeColor= color06
|
| 22 |
+
self.chart.strands[6].strokeColor= color07
|
| 23 |
+
self.chart.strands[7].strokeColor= color08
|
| 24 |
+
self.chart.strands[8].strokeColor= color09
|
| 25 |
+
self.chart.strands[9].strokeColor= color10
|
| 26 |
+
self.chart.strands[0].fillColor = None
|
| 27 |
+
self.chart.strands[1].fillColor = None
|
| 28 |
+
self.chart.strands[2].fillColor = None
|
| 29 |
+
self.chart.strands[3].fillColor = None
|
| 30 |
+
self.chart.strands[4].fillColor = None
|
| 31 |
+
self.chart.strands[5].fillColor = None
|
| 32 |
+
self.chart.strands[6].fillColor = None
|
| 33 |
+
self.chart.strands[7].fillColor = None
|
| 34 |
+
self.chart.strands[8].fillColor = None
|
| 35 |
+
self.chart.strands[9].fillColor = None
|
| 36 |
+
self.chart.strands.strokeWidth = 1
|
| 37 |
+
self.chart.strandLabels.fontName = 'Helvetica'
|
| 38 |
+
self.chart.strandLabels.fontSize = 6
|
| 39 |
+
self.chart.fillColor = backgroundGrey
|
| 40 |
+
self.chart.data = [(125, 180, 200), (100, 150, 180)]
|
| 41 |
+
self.chart.labels = ['North', 'South', 'Central']
|
| 42 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 43 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 44 |
+
self.Title.fontSize = 7
|
| 45 |
+
self.Title.x = 100
|
| 46 |
+
self.Title.y = 135
|
| 47 |
+
self.Title._text = 'Chart Title'
|
| 48 |
+
self.Title.maxWidth = 180
|
| 49 |
+
self.Title.height = 20
|
| 50 |
+
self.Title.textAnchor ='middle'
|
| 51 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 52 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 53 |
+
self.Legend.fontName = 'Helvetica'
|
| 54 |
+
self.Legend.fontSize = 7
|
| 55 |
+
self.Legend.x = 153
|
| 56 |
+
self.Legend.y = 85
|
| 57 |
+
self.Legend.dxTextSpace = 5
|
| 58 |
+
self.Legend.dy = 5
|
| 59 |
+
self.Legend.dx = 5
|
| 60 |
+
self.Legend.deltay = 5
|
| 61 |
+
self.Legend.alignment ='right'
|
| 62 |
+
self.chart.strands.strokeWidth = 1
|
| 63 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 64 |
+
|
| 65 |
+
if __name__=="__main__": #NORUNTESTS
|
| 66 |
+
RadarChart().save(formats=['pdf'],outDir=None,fnRoot='radar')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/runall.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# runs all the GUIedit charts in this directory -
|
| 2 |
+
# makes a PDF sample for eaxh existing chart type
|
| 3 |
+
import sys
|
| 4 |
+
import glob
|
| 5 |
+
import inspect
|
| 6 |
+
|
| 7 |
+
def moduleClasses(mod):
|
| 8 |
+
def P(obj, m=mod.__name__, CT=type):
|
| 9 |
+
return (type(obj)==CT and obj.__module__==m)
|
| 10 |
+
try:
|
| 11 |
+
return inspect.getmembers(mod, P)[0][1]
|
| 12 |
+
except:
|
| 13 |
+
return None
|
| 14 |
+
|
| 15 |
+
def getclass(f):
|
| 16 |
+
return moduleClasses(__import__(f))
|
| 17 |
+
|
| 18 |
+
def run(format, VERBOSE=0):
|
| 19 |
+
formats = format.split( ',')
|
| 20 |
+
for i in range(0, len(formats)):
|
| 21 |
+
formats[i] == formats[i].strip().lower()
|
| 22 |
+
allfiles = glob.glob('*.py')
|
| 23 |
+
allfiles.sort()
|
| 24 |
+
for fn in allfiles:
|
| 25 |
+
f = fn.split('.')[0]
|
| 26 |
+
c = getclass(f)
|
| 27 |
+
if c != None:
|
| 28 |
+
print(c.__name__)
|
| 29 |
+
try:
|
| 30 |
+
for fmt in formats:
|
| 31 |
+
if fmt:
|
| 32 |
+
c().save(formats=[fmt],outDir='.',fnRoot=c.__name__)
|
| 33 |
+
if VERBOSE:
|
| 34 |
+
print(" %s.%s" % (c.__name__, fmt))
|
| 35 |
+
except:
|
| 36 |
+
print(" COULDN'T CREATE '%s.%s'!" % (c.__name__, format))
|
| 37 |
+
|
| 38 |
+
if __name__ == "__main__":
|
| 39 |
+
if len(sys.argv) == 1:
|
| 40 |
+
run('pdf,pict,png')
|
| 41 |
+
else:
|
| 42 |
+
try:
|
| 43 |
+
if sys.argv[1] == "-h":
|
| 44 |
+
print('usage: runall.py [FORMAT] [-h]')
|
| 45 |
+
print(' if format is supplied is should be one or more of pdf,gif,eps,png etc')
|
| 46 |
+
print(' if format is missing the following formats are assumed: pdf,pict,png')
|
| 47 |
+
print(' -h prints this message')
|
| 48 |
+
else:
|
| 49 |
+
t = sys.argv[1:]
|
| 50 |
+
for f in t:
|
| 51 |
+
run(f)
|
| 52 |
+
except:
|
| 53 |
+
print('usage: runall.py [FORMAT][-h]')
|
| 54 |
+
print(' if format is supplied is should be one or more of pdf,gif,eps,png etc')
|
| 55 |
+
print(' if format is missing the following formats are assumed: pdf,pict,png')
|
| 56 |
+
print(' -h prints this message')
|
| 57 |
+
raise
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import ScatterPlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class Scatter(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.lines[0].strokeColor = color01
|
| 17 |
+
self.chart.lines[1].strokeColor = color02
|
| 18 |
+
self.chart.lines[2].strokeColor = color03
|
| 19 |
+
self.chart.lines[3].strokeColor = color04
|
| 20 |
+
self.chart.lines[4].strokeColor = color05
|
| 21 |
+
self.chart.lines[5].strokeColor = color06
|
| 22 |
+
self.chart.lines[6].strokeColor = color07
|
| 23 |
+
self.chart.lines[7].strokeColor = color08
|
| 24 |
+
self.chart.lines[8].strokeColor = color09
|
| 25 |
+
self.chart.lines[9].strokeColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 30 |
+
self.chart.xValueAxis.forceZero = 0
|
| 31 |
+
self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))]
|
| 32 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 33 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 34 |
+
self.chart.xValueAxis.tickDown = 3
|
| 35 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 36 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 37 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 38 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 39 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 40 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 41 |
+
self.Title.fontSize = 7
|
| 42 |
+
self.Title.x = 100
|
| 43 |
+
self.Title.y = 135
|
| 44 |
+
self.Title._text = 'Chart Title'
|
| 45 |
+
self.Title.maxWidth = 180
|
| 46 |
+
self.Title.height = 20
|
| 47 |
+
self.Title.textAnchor ='middle'
|
| 48 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 49 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 50 |
+
self.Legend.fontName = 'Helvetica'
|
| 51 |
+
self.Legend.fontSize = 7
|
| 52 |
+
self.Legend.x = 153
|
| 53 |
+
self.Legend.y = 85
|
| 54 |
+
self.Legend.dxTextSpace = 5
|
| 55 |
+
self.Legend.dy = 5
|
| 56 |
+
self.Legend.dx = 5
|
| 57 |
+
self.Legend.deltay = 5
|
| 58 |
+
self.Legend.alignment ='right'
|
| 59 |
+
self.chart.lineLabelFormat = None
|
| 60 |
+
self.chart.xLabel = 'X Axis'
|
| 61 |
+
self.chart.y = 30
|
| 62 |
+
self.chart.yLabel = 'Y Axis'
|
| 63 |
+
self.chart.yValueAxis.labelTextFormat = '%d'
|
| 64 |
+
self.chart.yValueAxis.forceZero = 1
|
| 65 |
+
self.chart.xValueAxis.forceZero = 1
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 69 |
+
|
| 70 |
+
if __name__=="__main__": #NORUNTESTS
|
| 71 |
+
Scatter().save(formats=['pdf'],outDir=None,fnRoot='scatter')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import ScatterPlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class ScatterLines(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.lines[0].strokeColor = color01
|
| 17 |
+
self.chart.lines[1].strokeColor = color02
|
| 18 |
+
self.chart.lines[2].strokeColor = color03
|
| 19 |
+
self.chart.lines[3].strokeColor = color04
|
| 20 |
+
self.chart.lines[4].strokeColor = color05
|
| 21 |
+
self.chart.lines[5].strokeColor = color06
|
| 22 |
+
self.chart.lines[6].strokeColor = color07
|
| 23 |
+
self.chart.lines[7].strokeColor = color08
|
| 24 |
+
self.chart.lines[8].strokeColor = color09
|
| 25 |
+
self.chart.lines[9].strokeColor = color10
|
| 26 |
+
self.chart.lines[0].symbol = None
|
| 27 |
+
self.chart.lines[1].symbol = None
|
| 28 |
+
self.chart.lines[2].symbol = None
|
| 29 |
+
self.chart.lines[3].symbol = None
|
| 30 |
+
self.chart.lines[4].symbol = None
|
| 31 |
+
self.chart.lines[5].symbol = None
|
| 32 |
+
self.chart.lines[6].symbol = None
|
| 33 |
+
self.chart.lines[7].symbol = None
|
| 34 |
+
self.chart.lines[8].symbol = None
|
| 35 |
+
self.chart.lines[9].symbol = None
|
| 36 |
+
self.chart.fillColor = backgroundGrey
|
| 37 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 38 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 39 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 40 |
+
self.chart.xValueAxis.forceZero = 0
|
| 41 |
+
self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))]
|
| 42 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 43 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 44 |
+
self.chart.xValueAxis.tickDown = 3
|
| 45 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 46 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 47 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 48 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 49 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 50 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 51 |
+
self.Title.fontSize = 7
|
| 52 |
+
self.Title.x = 100
|
| 53 |
+
self.Title.y = 135
|
| 54 |
+
self.Title._text = 'Chart Title'
|
| 55 |
+
self.Title.maxWidth = 180
|
| 56 |
+
self.Title.height = 20
|
| 57 |
+
self.Title.textAnchor ='middle'
|
| 58 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 59 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 60 |
+
self.Legend.fontName = 'Helvetica'
|
| 61 |
+
self.Legend.fontSize = 7
|
| 62 |
+
self.Legend.x = 153
|
| 63 |
+
self.Legend.y = 85
|
| 64 |
+
self.Legend.dxTextSpace = 5
|
| 65 |
+
self.Legend.dy = 5
|
| 66 |
+
self.Legend.dx = 5
|
| 67 |
+
self.Legend.deltay = 5
|
| 68 |
+
self.Legend.alignment ='right'
|
| 69 |
+
self.chart.lineLabelFormat = None
|
| 70 |
+
self.chart.xLabel = 'X Axis'
|
| 71 |
+
self.chart.y = 30
|
| 72 |
+
self.chart.yLabel = 'Y Axis'
|
| 73 |
+
self.chart.yValueAxis.gridEnd = 115
|
| 74 |
+
self.chart.yValueAxis.visibleGrid = 1
|
| 75 |
+
self.chart.yValueAxis.labelTextFormat = '%d'
|
| 76 |
+
self.chart.yValueAxis.forceZero = 1
|
| 77 |
+
self.chart.xValueAxis.forceZero = 1
|
| 78 |
+
self.chart.joinedLines = 1
|
| 79 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 80 |
+
|
| 81 |
+
if __name__=="__main__": #NORUNTESTS
|
| 82 |
+
ScatterLines().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines_markers.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.lineplots import ScatterPlot
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class ScatterLinesMarkers(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.lines[0].strokeColor = color01
|
| 17 |
+
self.chart.lines[1].strokeColor = color02
|
| 18 |
+
self.chart.lines[2].strokeColor = color03
|
| 19 |
+
self.chart.lines[3].strokeColor = color04
|
| 20 |
+
self.chart.lines[4].strokeColor = color05
|
| 21 |
+
self.chart.lines[5].strokeColor = color06
|
| 22 |
+
self.chart.lines[6].strokeColor = color07
|
| 23 |
+
self.chart.lines[7].strokeColor = color08
|
| 24 |
+
self.chart.lines[8].strokeColor = color09
|
| 25 |
+
self.chart.lines[9].strokeColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.lineLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.xValueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.xValueAxis.labels.fontSize = 7
|
| 30 |
+
self.chart.xValueAxis.forceZero = 0
|
| 31 |
+
self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))]
|
| 32 |
+
self.chart.xValueAxis.avoidBoundFrac = 1
|
| 33 |
+
self.chart.xValueAxis.gridEnd = 115
|
| 34 |
+
self.chart.xValueAxis.tickDown = 3
|
| 35 |
+
self.chart.xValueAxis.visibleGrid = 1
|
| 36 |
+
self.chart.yValueAxis.tickLeft = 3
|
| 37 |
+
self.chart.yValueAxis.labels.fontName = 'Helvetica'
|
| 38 |
+
self.chart.yValueAxis.labels.fontSize = 7
|
| 39 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 40 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 41 |
+
self.Title.fontSize = 7
|
| 42 |
+
self.Title.x = 100
|
| 43 |
+
self.Title.y = 135
|
| 44 |
+
self.Title._text = 'Chart Title'
|
| 45 |
+
self.Title.maxWidth = 180
|
| 46 |
+
self.Title.height = 20
|
| 47 |
+
self.Title.textAnchor ='middle'
|
| 48 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 49 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 50 |
+
self.Legend.fontName = 'Helvetica'
|
| 51 |
+
self.Legend.fontSize = 7
|
| 52 |
+
self.Legend.x = 153
|
| 53 |
+
self.Legend.y = 85
|
| 54 |
+
self.Legend.dxTextSpace = 5
|
| 55 |
+
self.Legend.dy = 5
|
| 56 |
+
self.Legend.dx = 5
|
| 57 |
+
self.Legend.deltay = 5
|
| 58 |
+
self.Legend.alignment ='right'
|
| 59 |
+
self.chart.lineLabelFormat = None
|
| 60 |
+
self.chart.xLabel = 'X Axis'
|
| 61 |
+
self.chart.y = 30
|
| 62 |
+
self.chart.yLabel = 'Y Axis'
|
| 63 |
+
self.chart.yValueAxis.gridEnd = 115
|
| 64 |
+
self.chart.yValueAxis.visibleGrid = 1
|
| 65 |
+
self.chart.yValueAxis.labelTextFormat = '%d'
|
| 66 |
+
self.chart.yValueAxis.forceZero = 1
|
| 67 |
+
self.chart.xValueAxis.forceZero = 1
|
| 68 |
+
self.chart.joinedLines = 1
|
| 69 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 70 |
+
|
| 71 |
+
if __name__=="__main__": #NORUNTESTS
|
| 72 |
+
ScatterLinesMarkers().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines_markers')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/simple_pie.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.piecharts import Pie
|
| 3 |
+
from reportlab.graphics.widgets.grids import ShadedRect
|
| 4 |
+
from reportlab.graphics.charts.legends import Legend
|
| 5 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 6 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 7 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 8 |
+
|
| 9 |
+
class SimplePie(_DrawingEditorMixin,Drawing):
|
| 10 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 11 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 12 |
+
self._add(self,Pie(),name='chart',validate=None,desc="The main chart")
|
| 13 |
+
self.chart.width = 100
|
| 14 |
+
self.chart.height = 100
|
| 15 |
+
self.chart.x = 25
|
| 16 |
+
self.chart.y = 25
|
| 17 |
+
self.chart.slices[0].fillColor = color01
|
| 18 |
+
self.chart.slices[1].fillColor = color02
|
| 19 |
+
self.chart.slices[2].fillColor = color03
|
| 20 |
+
self.chart.slices[3].fillColor = color04
|
| 21 |
+
self.chart.slices[4].fillColor = color05
|
| 22 |
+
self.chart.slices[5].fillColor = color06
|
| 23 |
+
self.chart.slices[6].fillColor = color07
|
| 24 |
+
self.chart.slices[7].fillColor = color08
|
| 25 |
+
self.chart.slices[8].fillColor = color09
|
| 26 |
+
self.chart.slices[9].fillColor = color10
|
| 27 |
+
self.chart.data = (100, 150, 180)
|
| 28 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 29 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 30 |
+
self.Title.fontSize = 7
|
| 31 |
+
self.Title.x = 100
|
| 32 |
+
self.Title.y = 135
|
| 33 |
+
self.Title._text = 'Chart Title'
|
| 34 |
+
self.Title.maxWidth = 180
|
| 35 |
+
self.Title.height = 20
|
| 36 |
+
self.Title.textAnchor ='middle'
|
| 37 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 38 |
+
self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'),(color03, 'Central')]
|
| 39 |
+
self.Legend.fontName = 'Helvetica'
|
| 40 |
+
self.Legend.fontSize = 7
|
| 41 |
+
self.Legend.x = 160
|
| 42 |
+
self.Legend.y = 85
|
| 43 |
+
self.Legend.dxTextSpace = 5
|
| 44 |
+
self.Legend.dy = 5
|
| 45 |
+
self.Legend.dx = 5
|
| 46 |
+
self.Legend.deltay = 5
|
| 47 |
+
self.Legend.alignment ='right'
|
| 48 |
+
self.chart.slices.strokeWidth = 1
|
| 49 |
+
self.chart.slices.fontName = 'Helvetica'
|
| 50 |
+
self.background = ShadedRect()
|
| 51 |
+
self.background.fillColorStart = backgroundGrey
|
| 52 |
+
self.background.fillColorEnd = backgroundGrey
|
| 53 |
+
self.background.numShades = 1
|
| 54 |
+
self.background.strokeWidth = 0.5
|
| 55 |
+
self.background.x = 25
|
| 56 |
+
self.background.y = 25
|
| 57 |
+
self.Legend.columnMaximum = 10
|
| 58 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 59 |
+
|
| 60 |
+
if __name__=="__main__": #NORUNTESTS
|
| 61 |
+
SimplePie().save(formats=['pdf'],outDir=None,fnRoot=None)
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_bar.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.barcharts import HorizontalBarChart
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class StackedBar(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.bars[0].fillColor = color01
|
| 17 |
+
self.chart.bars[1].fillColor = color02
|
| 18 |
+
self.chart.bars[2].fillColor = color03
|
| 19 |
+
self.chart.bars[3].fillColor = color04
|
| 20 |
+
self.chart.bars[4].fillColor = color05
|
| 21 |
+
self.chart.bars[5].fillColor = color06
|
| 22 |
+
self.chart.bars[6].fillColor = color07
|
| 23 |
+
self.chart.bars[7].fillColor = color08
|
| 24 |
+
self.chart.bars[8].fillColor = color09
|
| 25 |
+
self.chart.bars[9].fillColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.barLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.valueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.valueAxis.labels.fontSize = 6
|
| 30 |
+
self.chart.valueAxis.forceZero = 1
|
| 31 |
+
self.chart.data = [(100, 150, 180), (125, 180, 200)]
|
| 32 |
+
self.chart.groupSpacing = 15
|
| 33 |
+
self.chart.valueAxis.avoidBoundFrac = 1
|
| 34 |
+
self.chart.valueAxis.gridEnd = 80
|
| 35 |
+
self.chart.valueAxis.tickDown = 3
|
| 36 |
+
self.chart.valueAxis.visibleGrid = 1
|
| 37 |
+
self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central']
|
| 38 |
+
self.chart.categoryAxis.tickLeft = 3
|
| 39 |
+
self.chart.categoryAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.categoryAxis.labels.fontSize = 6
|
| 41 |
+
self.chart.categoryAxis.labels.dx = -3
|
| 42 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 43 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 44 |
+
self.Title.fontSize = 7
|
| 45 |
+
self.Title.x = 100
|
| 46 |
+
self.Title.y = 135
|
| 47 |
+
self.Title._text = 'Chart Title'
|
| 48 |
+
self.Title.maxWidth = 180
|
| 49 |
+
self.Title.height = 20
|
| 50 |
+
self.Title.textAnchor ='middle'
|
| 51 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 52 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 53 |
+
self.Legend.fontName = 'Helvetica'
|
| 54 |
+
self.Legend.fontSize = 7
|
| 55 |
+
self.Legend.x = 153
|
| 56 |
+
self.Legend.y = 85
|
| 57 |
+
self.Legend.dxTextSpace = 5
|
| 58 |
+
self.Legend.dy = 5
|
| 59 |
+
self.Legend.dx = 5
|
| 60 |
+
self.Legend.deltay = 5
|
| 61 |
+
self.Legend.alignment ='right'
|
| 62 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 63 |
+
self.XLabel.fontName = 'Helvetica'
|
| 64 |
+
self.XLabel.fontSize = 7
|
| 65 |
+
self.XLabel.x = 85
|
| 66 |
+
self.XLabel.y = 10
|
| 67 |
+
self.XLabel.textAnchor ='middle'
|
| 68 |
+
self.XLabel.maxWidth = 100
|
| 69 |
+
self.XLabel.height = 20
|
| 70 |
+
self.XLabel._text = "X Axis"
|
| 71 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 72 |
+
self.YLabel.fontName = 'Helvetica'
|
| 73 |
+
self.YLabel.fontSize = 7
|
| 74 |
+
self.YLabel.x = 12
|
| 75 |
+
self.YLabel.y = 80
|
| 76 |
+
self.YLabel.angle = 90
|
| 77 |
+
self.YLabel.textAnchor ='middle'
|
| 78 |
+
self.YLabel.maxWidth = 100
|
| 79 |
+
self.YLabel.height = 20
|
| 80 |
+
self.YLabel._text = "Y Axis"
|
| 81 |
+
self.chart.categoryAxis.style='stacked'
|
| 82 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 83 |
+
|
| 84 |
+
if __name__=="__main__": #NORUNTESTS
|
| 85 |
+
StackedBar().save(formats=['pdf'],outDir=None,fnRoot='stacked_bar')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_column.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Autogenerated by ReportLab guiedit do not edit
|
| 2 |
+
from reportlab.graphics.charts.legends import Legend
|
| 3 |
+
from reportlab.graphics.charts.barcharts import VerticalBarChart
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
|
| 5 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 6 |
+
from reportlab.graphics.samples.excelcolors import *
|
| 7 |
+
|
| 8 |
+
class StackedColumn(_DrawingEditorMixin,Drawing):
|
| 9 |
+
def __init__(self,width=200,height=150,*args,**kw):
|
| 10 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 11 |
+
self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart")
|
| 12 |
+
self.chart.width = 115
|
| 13 |
+
self.chart.height = 80
|
| 14 |
+
self.chart.x = 30
|
| 15 |
+
self.chart.y = 40
|
| 16 |
+
self.chart.bars[0].fillColor = color01
|
| 17 |
+
self.chart.bars[1].fillColor = color02
|
| 18 |
+
self.chart.bars[2].fillColor = color03
|
| 19 |
+
self.chart.bars[3].fillColor = color04
|
| 20 |
+
self.chart.bars[4].fillColor = color05
|
| 21 |
+
self.chart.bars[5].fillColor = color06
|
| 22 |
+
self.chart.bars[6].fillColor = color07
|
| 23 |
+
self.chart.bars[7].fillColor = color08
|
| 24 |
+
self.chart.bars[8].fillColor = color09
|
| 25 |
+
self.chart.bars[9].fillColor = color10
|
| 26 |
+
self.chart.fillColor = backgroundGrey
|
| 27 |
+
self.chart.barLabels.fontName = 'Helvetica'
|
| 28 |
+
self.chart.valueAxis.labels.fontName = 'Helvetica'
|
| 29 |
+
self.chart.valueAxis.labels.fontSize = 7
|
| 30 |
+
self.chart.valueAxis.forceZero = 1
|
| 31 |
+
self.chart.data = [(100, 150, 180), (125, 180, 200)]
|
| 32 |
+
self.chart.groupSpacing = 15
|
| 33 |
+
self.chart.valueAxis.avoidBoundFrac = 1
|
| 34 |
+
self.chart.valueAxis.gridEnd = 115
|
| 35 |
+
self.chart.valueAxis.tickLeft = 3
|
| 36 |
+
self.chart.valueAxis.visibleGrid = 1
|
| 37 |
+
self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central']
|
| 38 |
+
self.chart.categoryAxis.tickDown = 3
|
| 39 |
+
self.chart.categoryAxis.labels.fontName = 'Helvetica'
|
| 40 |
+
self.chart.categoryAxis.labels.fontSize = 7
|
| 41 |
+
self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart")
|
| 42 |
+
self.Title.fontName = 'Helvetica-Bold'
|
| 43 |
+
self.Title.fontSize = 7
|
| 44 |
+
self.Title.x = 100
|
| 45 |
+
self.Title.y = 135
|
| 46 |
+
self.Title._text = 'Chart Title'
|
| 47 |
+
self.Title.maxWidth = 180
|
| 48 |
+
self.Title.height = 20
|
| 49 |
+
self.Title.textAnchor ='middle'
|
| 50 |
+
self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart")
|
| 51 |
+
self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')]
|
| 52 |
+
self.Legend.fontName = 'Helvetica'
|
| 53 |
+
self.Legend.fontSize = 7
|
| 54 |
+
self.Legend.x = 153
|
| 55 |
+
self.Legend.y = 85
|
| 56 |
+
self.Legend.dxTextSpace = 5
|
| 57 |
+
self.Legend.dy = 5
|
| 58 |
+
self.Legend.dx = 5
|
| 59 |
+
self.Legend.deltay = 5
|
| 60 |
+
self.Legend.alignment ='right'
|
| 61 |
+
self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis")
|
| 62 |
+
self.XLabel.fontName = 'Helvetica'
|
| 63 |
+
self.XLabel.fontSize = 7
|
| 64 |
+
self.XLabel.x = 85
|
| 65 |
+
self.XLabel.y = 10
|
| 66 |
+
self.XLabel.textAnchor ='middle'
|
| 67 |
+
self.XLabel.maxWidth = 100
|
| 68 |
+
self.XLabel.height = 20
|
| 69 |
+
self.XLabel._text = "X Axis"
|
| 70 |
+
self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis")
|
| 71 |
+
self.YLabel.fontName = 'Helvetica'
|
| 72 |
+
self.YLabel.fontSize = 7
|
| 73 |
+
self.YLabel.x = 12
|
| 74 |
+
self.YLabel.y = 80
|
| 75 |
+
self.YLabel.angle = 90
|
| 76 |
+
self.YLabel.textAnchor ='middle'
|
| 77 |
+
self.YLabel.maxWidth = 100
|
| 78 |
+
self.YLabel.height = 20
|
| 79 |
+
self.YLabel._text = "Y Axis"
|
| 80 |
+
self.chart.categoryAxis.style='stacked'
|
| 81 |
+
self._add(self,0,name='preview',validate=None,desc=None)
|
| 82 |
+
|
| 83 |
+
if __name__=="__main__": #NORUNTESTS
|
| 84 |
+
StackedColumn().save(formats=['pdf'],outDir=None,fnRoot='stacked_column')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Copyright ReportLab Europe Ltd. 2000-2017
|
| 2 |
+
#see license.txt for license details
|
| 3 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/__init__.py
|
| 4 |
+
__version__='3.3.0'
|
| 5 |
+
__doc__='''Some non-chart widgets'''
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/adjustableArrow.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from reportlab.lib import colors
|
| 2 |
+
from reportlab.lib.validators import *
|
| 3 |
+
from reportlab.lib.attrmap import *
|
| 4 |
+
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, Group, Polygon
|
| 5 |
+
from reportlab.graphics.widgetbase import Widget
|
| 6 |
+
|
| 7 |
+
class AdjustableArrow(Widget):
|
| 8 |
+
"""This widget draws an arrow (style one).
|
| 9 |
+
|
| 10 |
+
possible attributes:
|
| 11 |
+
'x', 'y', 'size', 'fillColor'
|
| 12 |
+
|
| 13 |
+
"""
|
| 14 |
+
_attrMap = AttrMap(
|
| 15 |
+
x = AttrMapValue(isNumber,desc='symbol x coordinate'),
|
| 16 |
+
y = AttrMapValue(isNumber,desc='symbol y coordinate'),
|
| 17 |
+
dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
| 18 |
+
dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
| 19 |
+
stemThickness = AttrMapValue(isNumber, 'width of the stem'),
|
| 20 |
+
stemLength = AttrMapValue(isNumber, 'length of the stem'),
|
| 21 |
+
headProjection = AttrMapValue(isNumber, 'how much the head projects from the stem'),
|
| 22 |
+
headLength = AttrMapValue(isNumber, 'length of the head'),
|
| 23 |
+
headSweep = AttrMapValue(isNumber, 'howmuch the head sweeps back (-ve) or forwards (+ve)'),
|
| 24 |
+
scale = AttrMapValue(isNumber, 'scaling factor'),
|
| 25 |
+
fillColor = AttrMapValue(isColorOrNone),
|
| 26 |
+
strokeColor = AttrMapValue(isColorOrNone),
|
| 27 |
+
strokeWidth = AttrMapValue(isNumber),
|
| 28 |
+
boxAnchor = AttrMapValue(isBoxAnchor,desc='anchoring point of the label'),
|
| 29 |
+
right =AttrMapValue(isBoolean,desc='If True (default) the arrow is horizontal pointing right\nFalse means it points up'),
|
| 30 |
+
angle = AttrMapValue(isNumber, desc='angle of arrow default (0), right True 0 is horizontal to right else vertical up'),
|
| 31 |
+
)
|
| 32 |
+
def __init__(self,**kwds):
|
| 33 |
+
self._setKeywords(**kwds)
|
| 34 |
+
self._setKeywords(**dict(
|
| 35 |
+
x = 0,
|
| 36 |
+
y = 0,
|
| 37 |
+
fillColor = colors.red,
|
| 38 |
+
strokeWidth = 0,
|
| 39 |
+
strokeColor = None,
|
| 40 |
+
boxAnchor = 'c',
|
| 41 |
+
angle = 0,
|
| 42 |
+
stemThickness = 33,
|
| 43 |
+
stemLength = 50,
|
| 44 |
+
headProjection = 15,
|
| 45 |
+
headLength = 50,
|
| 46 |
+
headSweep = 0,
|
| 47 |
+
scale = 1.,
|
| 48 |
+
right=True,
|
| 49 |
+
))
|
| 50 |
+
|
| 51 |
+
def draw(self):
|
| 52 |
+
# general widget bits
|
| 53 |
+
g = Group()
|
| 54 |
+
|
| 55 |
+
x = self.x
|
| 56 |
+
y = self.y
|
| 57 |
+
scale = self.scale
|
| 58 |
+
stemThickness = self.stemThickness*scale
|
| 59 |
+
stemLength = self.stemLength*scale
|
| 60 |
+
headProjection = self.headProjection*scale
|
| 61 |
+
headLength = self.headLength*scale
|
| 62 |
+
headSweep = self.headSweep*scale
|
| 63 |
+
w = stemLength+headLength
|
| 64 |
+
h = 2*headProjection+stemThickness
|
| 65 |
+
# shift to the boxAnchor
|
| 66 |
+
boxAnchor = self.boxAnchor
|
| 67 |
+
if self.right:
|
| 68 |
+
if boxAnchor in ('sw','w','nw'):
|
| 69 |
+
dy = -h
|
| 70 |
+
elif boxAnchor in ('s','c','n'):
|
| 71 |
+
dy = -h*0.5
|
| 72 |
+
else:
|
| 73 |
+
dy = 0
|
| 74 |
+
if boxAnchor in ('w','c','e'):
|
| 75 |
+
dx = -w*0.5
|
| 76 |
+
elif boxAnchor in ('nw','n','ne'):
|
| 77 |
+
dx = -w
|
| 78 |
+
else:
|
| 79 |
+
dx = 0
|
| 80 |
+
points = [
|
| 81 |
+
dx, dy+headProjection+stemThickness,
|
| 82 |
+
dx+stemLength, dy+headProjection+stemThickness,
|
| 83 |
+
dx+stemLength+headSweep, dy+2*headProjection+stemThickness,
|
| 84 |
+
dx+stemLength+headLength, dy+0.5*stemThickness+headProjection,
|
| 85 |
+
dx+stemLength+headSweep, dy,
|
| 86 |
+
dx+stemLength, dy+headProjection,
|
| 87 |
+
dx, dy+headProjection,
|
| 88 |
+
]
|
| 89 |
+
else:
|
| 90 |
+
w,h = h,w
|
| 91 |
+
if boxAnchor in ('nw','n','ne'):
|
| 92 |
+
dy = -h
|
| 93 |
+
elif boxAnchor in ('w','c','e'):
|
| 94 |
+
dy = -h*0.5
|
| 95 |
+
else:
|
| 96 |
+
dy = 0
|
| 97 |
+
if boxAnchor in ('ne','e','se'):
|
| 98 |
+
dx = -w
|
| 99 |
+
elif boxAnchor in ('n','c','s'):
|
| 100 |
+
dx = -w*0.5
|
| 101 |
+
else:
|
| 102 |
+
dx = 0
|
| 103 |
+
points = [
|
| 104 |
+
dx+headProjection, dy, #sw
|
| 105 |
+
dx+headProjection+stemThickness, dy, #se
|
| 106 |
+
dx+headProjection+stemThickness, dy+stemLength,
|
| 107 |
+
dx+w, dy+stemLength+headSweep,
|
| 108 |
+
dx+headProjection+0.5*stemThickness, dy+h,
|
| 109 |
+
dx, dy+stemLength+headSweep,
|
| 110 |
+
dx+headProjection, dy+stemLength,
|
| 111 |
+
]
|
| 112 |
+
|
| 113 |
+
g.add(Polygon(
|
| 114 |
+
points = points,
|
| 115 |
+
fillColor = self.fillColor,
|
| 116 |
+
strokeColor = self.strokeColor,
|
| 117 |
+
strokeWidth = self.strokeWidth,
|
| 118 |
+
))
|
| 119 |
+
g.translate(x,y)
|
| 120 |
+
g.rotate(self.angle)
|
| 121 |
+
return g
|
| 122 |
+
|
| 123 |
+
class AdjustableArrowDrawing(_DrawingEditorMixin,Drawing):
|
| 124 |
+
def __init__(self,width=100,height=63,*args,**kw):
|
| 125 |
+
Drawing.__init__(self,width,height,*args,**kw)
|
| 126 |
+
self._add(self,AdjustableArrow(),name='adjustableArrow',validate=None,desc=None)
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/eventcal.py
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#see license.txt for license details
|
| 2 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/eventcal.py
|
| 3 |
+
# Event Calendar widget
|
| 4 |
+
# author: Andy Robinson
|
| 5 |
+
|
| 6 |
+
__version__='3.3.0'
|
| 7 |
+
__doc__="""This file is a
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
from reportlab.lib import colors
|
| 11 |
+
from reportlab.graphics.shapes import Rect, Drawing, Group, String
|
| 12 |
+
from reportlab.graphics.charts.textlabels import Label
|
| 13 |
+
from reportlab.graphics.widgetbase import Widget
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class EventCalendar(Widget):
|
| 17 |
+
def __init__(self):
|
| 18 |
+
self.x = 0
|
| 19 |
+
self.y = 0
|
| 20 |
+
self.width = 300
|
| 21 |
+
self.height = 150
|
| 22 |
+
self.timeColWidth = None # if declared, use it; otherwise auto-size.
|
| 23 |
+
self.trackRowHeight = 20
|
| 24 |
+
self.data = [] # list of Event objects
|
| 25 |
+
self.trackNames = None
|
| 26 |
+
|
| 27 |
+
self.startTime = None #displays ALL data on day if not set
|
| 28 |
+
self.endTime = None # displays ALL data on day if not set
|
| 29 |
+
self.day = 0
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# we will keep any internal geometry variables
|
| 33 |
+
# here. These are computed by computeSize(),
|
| 34 |
+
# which is the first thing done when drawing.
|
| 35 |
+
self._talksVisible = [] # subset of data which will get plotted, cache
|
| 36 |
+
self._startTime = None
|
| 37 |
+
self._endTime = None
|
| 38 |
+
self._trackCount = 0
|
| 39 |
+
self._colWidths = []
|
| 40 |
+
self._colLeftEdges = [] # left edge of each column
|
| 41 |
+
|
| 42 |
+
def computeSize(self):
|
| 43 |
+
"Called at start of draw. Sets various column widths"
|
| 44 |
+
self._talksVisible = self.getRelevantTalks(self.data)
|
| 45 |
+
self._trackCount = len(self.getAllTracks())
|
| 46 |
+
self.computeStartAndEndTimes()
|
| 47 |
+
self._colLeftEdges = [self.x]
|
| 48 |
+
if self.timeColWidth is None:
|
| 49 |
+
w = self.width / (1 + self._trackCount)
|
| 50 |
+
self._colWidths = [w] * (1+ self._trackCount)
|
| 51 |
+
for i in range(self._trackCount):
|
| 52 |
+
self._colLeftEdges.append(self._colLeftEdges[-1] + w)
|
| 53 |
+
else:
|
| 54 |
+
self._colWidths = [self.timeColWidth]
|
| 55 |
+
w = (self.width - self.timeColWidth) / self._trackCount
|
| 56 |
+
for i in range(self._trackCount):
|
| 57 |
+
self._colWidths.append(w)
|
| 58 |
+
self._colLeftEdges.append(self._colLeftEdges[-1] + w)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def computeStartAndEndTimes(self):
|
| 63 |
+
"Work out first and last times to display"
|
| 64 |
+
if self.startTime:
|
| 65 |
+
self._startTime = self.startTime
|
| 66 |
+
else:
|
| 67 |
+
for (title, speaker, trackId, day, start, duration) in self._talksVisible:
|
| 68 |
+
|
| 69 |
+
if self._startTime is None: #first one
|
| 70 |
+
self._startTime = start
|
| 71 |
+
else:
|
| 72 |
+
if start < self._startTime:
|
| 73 |
+
self._startTime = start
|
| 74 |
+
|
| 75 |
+
if self.endTime:
|
| 76 |
+
self._endTime = self.endTime
|
| 77 |
+
else:
|
| 78 |
+
for (title, speaker, trackId, day, start, duration) in self._talksVisible:
|
| 79 |
+
if self._endTime is None: #first one
|
| 80 |
+
self._endTime = start + duration
|
| 81 |
+
else:
|
| 82 |
+
if start + duration > self._endTime:
|
| 83 |
+
self._endTime = start + duration
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def getAllTracks(self):
|
| 89 |
+
tracks = []
|
| 90 |
+
for (title, speaker, trackId, day, hours, duration) in self.data:
|
| 91 |
+
if trackId is not None:
|
| 92 |
+
if trackId not in tracks:
|
| 93 |
+
tracks.append(trackId)
|
| 94 |
+
tracks.sort()
|
| 95 |
+
return tracks
|
| 96 |
+
|
| 97 |
+
def getRelevantTalks(self, talkList):
|
| 98 |
+
"Scans for tracks actually used"
|
| 99 |
+
used = []
|
| 100 |
+
for talk in talkList:
|
| 101 |
+
(title, speaker, trackId, day, hours, duration) = talk
|
| 102 |
+
assert trackId != 0, "trackId must be None or 1,2,3... zero not allowed!"
|
| 103 |
+
if day == self.day:
|
| 104 |
+
if (((self.startTime is None) or ((hours + duration) >= self.startTime))
|
| 105 |
+
and ((self.endTime is None) or (hours <= self.endTime))):
|
| 106 |
+
used.append(talk)
|
| 107 |
+
return used
|
| 108 |
+
|
| 109 |
+
def scaleTime(self, theTime):
|
| 110 |
+
"Return y-value corresponding to times given"
|
| 111 |
+
axisHeight = self.height - self.trackRowHeight
|
| 112 |
+
# compute fraction between 0 and 1, 0 is at start of period
|
| 113 |
+
proportionUp = ((theTime - self._startTime) / (self._endTime - self._startTime))
|
| 114 |
+
y = self.y + axisHeight - (axisHeight * proportionUp)
|
| 115 |
+
return y
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def getTalkRect(self, startTime, duration, trackId, text):
|
| 119 |
+
"Return shapes for a specific talk"
|
| 120 |
+
g = Group()
|
| 121 |
+
y_bottom = self.scaleTime(startTime + duration)
|
| 122 |
+
y_top = self.scaleTime(startTime)
|
| 123 |
+
y_height = y_top - y_bottom
|
| 124 |
+
|
| 125 |
+
if trackId is None:
|
| 126 |
+
#spans all columns
|
| 127 |
+
x = self._colLeftEdges[1]
|
| 128 |
+
width = self.width - self._colWidths[0]
|
| 129 |
+
else:
|
| 130 |
+
#trackId is 1-based and these arrays have the margin info in column
|
| 131 |
+
#zero, so no need to add 1
|
| 132 |
+
x = self._colLeftEdges[trackId]
|
| 133 |
+
width = self._colWidths[trackId]
|
| 134 |
+
|
| 135 |
+
lab = Label()
|
| 136 |
+
lab.setText(text)
|
| 137 |
+
lab.setOrigin(x + 0.5*width, y_bottom+0.5*y_height)
|
| 138 |
+
lab.boxAnchor = 'c'
|
| 139 |
+
lab.width = width
|
| 140 |
+
lab.height = y_height
|
| 141 |
+
lab.fontSize = 6
|
| 142 |
+
|
| 143 |
+
r = Rect(x, y_bottom, width, y_height, fillColor=colors.cyan)
|
| 144 |
+
g.add(r)
|
| 145 |
+
g.add(lab)
|
| 146 |
+
|
| 147 |
+
#now for a label
|
| 148 |
+
# would expect to color-code and add text
|
| 149 |
+
return g
|
| 150 |
+
|
| 151 |
+
def draw(self):
|
| 152 |
+
self.computeSize()
|
| 153 |
+
g = Group()
|
| 154 |
+
|
| 155 |
+
# time column
|
| 156 |
+
g.add(Rect(self.x, self.y, self._colWidths[0], self.height - self.trackRowHeight, fillColor=colors.cornsilk))
|
| 157 |
+
|
| 158 |
+
# track headers
|
| 159 |
+
x = self.x + self._colWidths[0]
|
| 160 |
+
y = self.y + self.height - self.trackRowHeight
|
| 161 |
+
for trk in range(self._trackCount):
|
| 162 |
+
wid = self._colWidths[trk+1]
|
| 163 |
+
r = Rect(x, y, wid, self.trackRowHeight, fillColor=colors.yellow)
|
| 164 |
+
s = String(x + 0.5*wid, y, 'Track %d' % trk, align='middle')
|
| 165 |
+
g.add(r)
|
| 166 |
+
g.add(s)
|
| 167 |
+
x = x + wid
|
| 168 |
+
|
| 169 |
+
for talk in self._talksVisible:
|
| 170 |
+
(title, speaker, trackId, day, start, duration) = talk
|
| 171 |
+
r = self.getTalkRect(start, duration, trackId, title + '\n' + speaker)
|
| 172 |
+
g.add(r)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
return g
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def test():
|
| 181 |
+
"Make a conference event for day 1 of UP Python 2003"
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
d = Drawing(400,200)
|
| 185 |
+
|
| 186 |
+
cal = EventCalendar()
|
| 187 |
+
cal.x = 50
|
| 188 |
+
cal.y = 25
|
| 189 |
+
cal.data = [
|
| 190 |
+
# these might be better as objects instead of tuples, since I
|
| 191 |
+
# predict a large number of "optionsl" variables to affect
|
| 192 |
+
# formatting in future.
|
| 193 |
+
|
| 194 |
+
#title, speaker, track id, day, start time (hrs), duration (hrs)
|
| 195 |
+
# track ID is 1-based not zero-based!
|
| 196 |
+
('Keynote: Why design another programming language?', 'Guido van Rossum', None, 1, 9.0, 1.0),
|
| 197 |
+
|
| 198 |
+
('Siena Web Service Architecture', 'Marc-Andre Lemburg', 1, 1, 10.5, 1.5),
|
| 199 |
+
('Extreme Programming in Python', 'Chris Withers', 2, 1, 10.5, 1.5),
|
| 200 |
+
('Pattern Experiences in C++', 'Mark Radford', 3, 1, 10.5, 1.5),
|
| 201 |
+
('What is the Type of std::toupper()', 'Gabriel Dos Reis', 4, 1, 10.5, 1.5),
|
| 202 |
+
('Linguistic Variables: Clear Thinking with Fuzzy Logic ', 'Walter Banks', 5, 1, 10.5, 1.5),
|
| 203 |
+
|
| 204 |
+
('lunch, short presentations, vendor presentations', '', None, 1, 12.0, 2.0),
|
| 205 |
+
|
| 206 |
+
("CORBA? Isn't that obsolete", 'Duncan Grisby', 1, 1, 14.0, 1.5),
|
| 207 |
+
("Python Design Patterns", 'Duncan Booth', 2, 1, 14.0, 1.5),
|
| 208 |
+
("Inside Security Checks and Safe Exceptions", 'Brandon Bray', 3, 1, 14.0, 1.5),
|
| 209 |
+
("Studying at a Distance", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 1, 14.0, 1.5),
|
| 210 |
+
("Coding Standards - Given the ANSI C Standard why do I still need a coding Standard", 'Randy Marques', 5, 1, 14.0, 1.5),
|
| 211 |
+
|
| 212 |
+
("RESTful Python", 'Hamish Lawson', 1, 1, 16.0, 1.5),
|
| 213 |
+
("Parsing made easier - a radical old idea", 'Andrew Koenig', 2, 1, 16.0, 1.5),
|
| 214 |
+
("C++ & Multimethods", 'Julian Smith', 3, 1, 16.0, 1.5),
|
| 215 |
+
("C++ Threading", 'Kevlin Henney', 4, 1, 16.0, 1.5),
|
| 216 |
+
("The Organisation Strikes Back", 'Alan Griffiths & Sarah Lees', 5, 1, 16.0, 1.5),
|
| 217 |
+
|
| 218 |
+
('Birds of a Feather meeting', '', None, 1, 17.5, 2.0),
|
| 219 |
+
|
| 220 |
+
('Keynote: In the Spirit of C', 'Greg Colvin', None, 2, 9.0, 1.0),
|
| 221 |
+
|
| 222 |
+
('The Infinite Filing Cabinet - object storage in Python', 'Jacob Hallen', 1, 2, 10.5, 1.5),
|
| 223 |
+
('Introduction to Python and Jython for C++ and Java Programmers', 'Alex Martelli', 2, 2, 10.5, 1.5),
|
| 224 |
+
('Template metaprogramming in Haskell', 'Simon Peyton Jones', 3, 2, 10.5, 1.5),
|
| 225 |
+
('Plenty People Programming: C++ Programming in a Group, Workshop with a difference', 'Nico Josuttis', 4, 2, 10.5, 1.5),
|
| 226 |
+
('Design and Implementation of the Boost Graph Library', 'Jeremy Siek', 5, 2, 10.5, 1.5),
|
| 227 |
+
|
| 228 |
+
('lunch, short presentations, vendor presentations', '', None, 2, 12.0, 2.0),
|
| 229 |
+
|
| 230 |
+
("Building GUI Applications with PythonCard and PyCrust", 'Andy Todd', 1, 2, 14.0, 1.5),
|
| 231 |
+
("Integrating Python, C and C++", 'Duncan Booth', 2, 2, 14.0, 1.5),
|
| 232 |
+
("Secrets and Pitfalls of Templates", 'Nicolai Josuttis & David Vandevoorde', 3, 2, 14.0, 1.5),
|
| 233 |
+
("Being a Mentor", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 2, 14.0, 1.5),
|
| 234 |
+
("The Embedded C Extensions to C", 'Willem Wakker', 5, 2, 14.0, 1.5),
|
| 235 |
+
|
| 236 |
+
("Lightning Talks", 'Paul Brian', 1, 2, 16.0, 1.5),
|
| 237 |
+
("Scripting Java Applications with Jython", 'Anthony Eden', 2, 2, 16.0, 1.5),
|
| 238 |
+
("Metaprogramming and the Boost Metaprogramming Library", 'David Abrahams', 3, 2, 16.0, 1.5),
|
| 239 |
+
("A Common Vendor ABI for C++ -- GCC's why, what and not", 'Nathan Sidwell & Gabriel Dos Reis', 4, 2, 16.0, 1.5),
|
| 240 |
+
("The Timing and Cost of Choices", 'Hubert Matthews', 5, 2, 16.0, 1.5),
|
| 241 |
+
|
| 242 |
+
('Birds of a Feather meeting', '', None, 2, 17.5, 2.0),
|
| 243 |
+
|
| 244 |
+
('Keynote: The Cost of C & C++ Compatibility', 'Andy Koenig', None, 3, 9.0, 1.0),
|
| 245 |
+
|
| 246 |
+
('Prying Eyes: Generic Observer Implementations in C++', 'Andrei Alexandrescu', 1, 2, 10.5, 1.5),
|
| 247 |
+
('The Roadmap to Generative Programming With C++', 'Ulrich Eisenecker', 2, 2, 10.5, 1.5),
|
| 248 |
+
('Design Patterns in C++ and C# for the Common Language Runtime', 'Brandon Bray', 3, 2, 10.5, 1.5),
|
| 249 |
+
('Extreme Hour (XH): (workshop) - Jutta Eckstein and Nico Josuttis', 'Jutta Ecstein', 4, 2, 10.5, 1.5),
|
| 250 |
+
('The Lambda Library : Unnamed Functions for C++', 'Jaako Jarvi', 5, 2, 10.5, 1.5),
|
| 251 |
+
|
| 252 |
+
('lunch, short presentations, vendor presentations', '', None, 3, 12.0, 2.0),
|
| 253 |
+
|
| 254 |
+
('Reflective Metaprogramming', 'Daveed Vandevoorde', 1, 3, 14.0, 1.5),
|
| 255 |
+
('Advanced Template Issues and Solutions (double session)', 'Herb Sutter',2, 3, 14.0, 3),
|
| 256 |
+
('Concurrent Programming in Java (double session)', 'Angelika Langer', 3, 3, 14.0, 3),
|
| 257 |
+
('What can MISRA-C (2nd Edition) do for us?', 'Chris Hills', 4, 3, 14.0, 1.5),
|
| 258 |
+
('C++ Metaprogramming Concepts and Results', 'Walter E Brown', 5, 3, 14.0, 1.5),
|
| 259 |
+
|
| 260 |
+
('Binding C++ to Python with the Boost Python Library', 'David Abrahams', 1, 3, 16.0, 1.5),
|
| 261 |
+
('Using Aspect Oriented Programming for Enterprise Application Integration', 'Arno Schmidmeier', 4, 3, 16.0, 1.5),
|
| 262 |
+
('Defective C++', 'Marc Paterno', 5, 3, 16.0, 1.5),
|
| 263 |
+
|
| 264 |
+
("Speakers' Banquet & Birds of a Feather meeting", '', None, 3, 17.5, 2.0),
|
| 265 |
+
|
| 266 |
+
('Keynote: The Internet, Software and Computers - A Report Card', 'Alan Lenton', None, 4, 9.0, 1.0),
|
| 267 |
+
|
| 268 |
+
('Multi-Platform Software Development; Lessons from the Boost libraries', 'Beman Dawes', 1, 5, 10.5, 1.5),
|
| 269 |
+
('The Stability of the C++ ABI', 'Steve Clamage', 2, 5, 10.5, 1.5),
|
| 270 |
+
('Generic Build Support - A Pragmatic Approach to the Software Build Process', 'Randy Marques', 3, 5, 10.5, 1.5),
|
| 271 |
+
('How to Handle Project Managers: a survival guide', 'Barb Byro', 4, 5, 10.5, 1.5),
|
| 272 |
+
|
| 273 |
+
('lunch, ACCU AGM', '', None, 5, 12.0, 2.0),
|
| 274 |
+
|
| 275 |
+
('Sauce: An OO recursive descent parser; its design and implementation.', 'Jon Jagger', 1, 5, 14.0, 1.5),
|
| 276 |
+
('GNIRTS ESAC REWOL - Bringing the UNIX filters to the C++ iostream library.', 'JC van Winkel', 2, 5, 14.0, 1.5),
|
| 277 |
+
('Pattern Writing: Live and Direct', 'Frank Buschmann & Kevlin Henney', 3, 5, 14.0, 3.0),
|
| 278 |
+
('The Future of Programming Languages - A Goldfish Bowl', 'Francis Glassborow and friends', 3, 5, 14.0, 1.5),
|
| 279 |
+
|
| 280 |
+
('Honey, I Shrunk the Threads: Compile-time checked multithreaded transactions in C++', 'Andrei Alexandrescu', 1, 5, 16.0, 1.5),
|
| 281 |
+
('Fun and Functionality with Functors', 'Lois Goldthwaite', 2, 5, 16.0, 1.5),
|
| 282 |
+
('Agile Enough?', 'Alan Griffiths', 4, 5, 16.0, 1.5),
|
| 283 |
+
("Conference Closure: A brief plenary session", '', None, 5, 17.5, 0.5),
|
| 284 |
+
|
| 285 |
+
]
|
| 286 |
+
|
| 287 |
+
#return cal
|
| 288 |
+
cal.day = 1
|
| 289 |
+
|
| 290 |
+
d.add(cal)
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
for format in ['pdf']:#,'gif','png']:
|
| 294 |
+
out = d.asString(format)
|
| 295 |
+
open('eventcal.%s' % format, 'wb').write(out)
|
| 296 |
+
print('saved eventcal.%s' % format)
|
| 297 |
+
|
| 298 |
+
if __name__=='__main__':
|
| 299 |
+
test()
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/flags.py
ADDED
|
@@ -0,0 +1,879 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#see license.txt for license details
|
| 2 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/flags.py
|
| 3 |
+
# Flag Widgets - a collection of flags as widgets
|
| 4 |
+
# author: John Precedo (johnp@reportlab.com)
|
| 5 |
+
|
| 6 |
+
__version__='3.3.0'
|
| 7 |
+
__doc__="""This file is a collection of flag graphics as widgets.
|
| 8 |
+
|
| 9 |
+
All flags are represented at the ratio of 1:2, even where the official ratio for the flag is something else
|
| 10 |
+
(such as 3:5 for the German national flag). The only exceptions are for where this would look _very_ wrong,
|
| 11 |
+
such as the Danish flag whose (ratio is 28:37), or the Swiss flag (which is square).
|
| 12 |
+
|
| 13 |
+
Unless otherwise stated, these flags are all the 'national flags' of the countries, rather than their
|
| 14 |
+
state flags, naval flags, ensigns or any other variants. (National flags are the flag flown by civilians
|
| 15 |
+
of a country and the ones usually used to represent a country abroad. State flags are the variants used by
|
| 16 |
+
the government and by diplomatic missions overseas).
|
| 17 |
+
|
| 18 |
+
To check on how close these are to the 'official' representations of flags, check the World Flag Database at
|
| 19 |
+
http://www.flags.ndirect.co.uk/
|
| 20 |
+
|
| 21 |
+
The flags this file contains are:
|
| 22 |
+
|
| 23 |
+
EU Members:
|
| 24 |
+
United Kingdom, Austria, Belgium, Denmark, Finland, France, Germany, Greece, Ireland, Italy, Luxembourg,
|
| 25 |
+
Holland (The Netherlands), Spain, Sweden
|
| 26 |
+
|
| 27 |
+
Others:
|
| 28 |
+
USA, Czech Republic, European Union, Switzerland, Turkey, Brazil
|
| 29 |
+
|
| 30 |
+
(Brazilian flag contributed by Publio da Costa Melo [publio@planetarium.com.br]).
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
from reportlab.lib import colors
|
| 34 |
+
from reportlab.lib.validators import *
|
| 35 |
+
from reportlab.lib.attrmap import *
|
| 36 |
+
from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge
|
| 37 |
+
from reportlab.graphics import renderPDF
|
| 38 |
+
from reportlab.graphics.widgets.signsandsymbols import _Symbol
|
| 39 |
+
import copy
|
| 40 |
+
from math import sin, cos, pi
|
| 41 |
+
|
| 42 |
+
validFlag=OneOf(None,
|
| 43 |
+
'UK',
|
| 44 |
+
'USA',
|
| 45 |
+
'Afghanistan',
|
| 46 |
+
'Austria',
|
| 47 |
+
'Belgium',
|
| 48 |
+
'China',
|
| 49 |
+
'Cuba',
|
| 50 |
+
'Denmark',
|
| 51 |
+
'Finland',
|
| 52 |
+
'France',
|
| 53 |
+
'Germany',
|
| 54 |
+
'Greece',
|
| 55 |
+
'Ireland',
|
| 56 |
+
'Italy',
|
| 57 |
+
'Japan',
|
| 58 |
+
'Luxembourg',
|
| 59 |
+
'Holland',
|
| 60 |
+
'Palestine',
|
| 61 |
+
'Portugal',
|
| 62 |
+
'Russia',
|
| 63 |
+
'Spain',
|
| 64 |
+
'Sweden',
|
| 65 |
+
'Norway',
|
| 66 |
+
'CzechRepublic',
|
| 67 |
+
'Turkey',
|
| 68 |
+
'Switzerland',
|
| 69 |
+
'EU',
|
| 70 |
+
'Brazil'
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
_size = 100.
|
| 74 |
+
|
| 75 |
+
class Star(_Symbol):
|
| 76 |
+
"""This draws a 5-pointed star.
|
| 77 |
+
|
| 78 |
+
possible attributes:
|
| 79 |
+
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
| 80 |
+
|
| 81 |
+
"""
|
| 82 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 83 |
+
angle = AttrMapValue(isNumber, desc='angle in degrees'),
|
| 84 |
+
)
|
| 85 |
+
_size = 100.
|
| 86 |
+
|
| 87 |
+
def __init__(self):
|
| 88 |
+
_Symbol.__init__(self)
|
| 89 |
+
self.size = 100
|
| 90 |
+
self.fillColor = colors.yellow
|
| 91 |
+
self.strokeColor = None
|
| 92 |
+
self.angle = 0
|
| 93 |
+
|
| 94 |
+
def demo(self):
|
| 95 |
+
D = Drawing(200, 100)
|
| 96 |
+
et = Star()
|
| 97 |
+
et.x=50
|
| 98 |
+
et.y=0
|
| 99 |
+
D.add(et)
|
| 100 |
+
labelFontSize = 10
|
| 101 |
+
D.add(String(et.x+(et.size/2.0),(et.y-(1.2*labelFontSize)),
|
| 102 |
+
et.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 103 |
+
fontSize=labelFontSize))
|
| 104 |
+
return D
|
| 105 |
+
|
| 106 |
+
def draw(self):
|
| 107 |
+
s = float(self.size) #abbreviate as we will use this a lot
|
| 108 |
+
g = Group()
|
| 109 |
+
|
| 110 |
+
# new algorithm from markers.StarFive
|
| 111 |
+
R = float(self.size)/2
|
| 112 |
+
r = R*sin(18*(pi/180.0))/cos(36*(pi/180.0))
|
| 113 |
+
P = []
|
| 114 |
+
angle = 90
|
| 115 |
+
for i in range(5):
|
| 116 |
+
for radius in R, r:
|
| 117 |
+
theta = angle*(pi/180.0)
|
| 118 |
+
P.append(radius*cos(theta))
|
| 119 |
+
P.append(radius*sin(theta))
|
| 120 |
+
angle = angle + 36
|
| 121 |
+
# star specific bits
|
| 122 |
+
star = Polygon(P,
|
| 123 |
+
fillColor = self.fillColor,
|
| 124 |
+
strokeColor = self.strokeColor,
|
| 125 |
+
strokeWidth=s/50)
|
| 126 |
+
g.rotate(self.angle)
|
| 127 |
+
g.shift(self.x+self.dx,self.y+self.dy)
|
| 128 |
+
g.add(star)
|
| 129 |
+
|
| 130 |
+
return g
|
| 131 |
+
|
| 132 |
+
class Flag(_Symbol):
|
| 133 |
+
"""This is a generic flag class that all the flags in this file use as a basis.
|
| 134 |
+
|
| 135 |
+
This class basically provides edges and a tidy-up routine to hide any bits of
|
| 136 |
+
line that overlap the 'outside' of the flag
|
| 137 |
+
|
| 138 |
+
possible attributes:
|
| 139 |
+
'x', 'y', 'size', 'fillColor'
|
| 140 |
+
"""
|
| 141 |
+
|
| 142 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 143 |
+
fillColor = AttrMapValue(isColor, desc='Background color'),
|
| 144 |
+
border = AttrMapValue(isBoolean, 'Whether a background is drawn'),
|
| 145 |
+
kind = AttrMapValue(validFlag, desc='Which flag'),
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
_cache = {}
|
| 149 |
+
|
| 150 |
+
def __init__(self,**kw):
|
| 151 |
+
_Symbol.__init__(self)
|
| 152 |
+
self.kind = None
|
| 153 |
+
self.size = 100
|
| 154 |
+
self.fillColor = colors.white
|
| 155 |
+
self.border=1
|
| 156 |
+
self.setProperties(kw)
|
| 157 |
+
|
| 158 |
+
def availableFlagNames(self):
|
| 159 |
+
'''return a list of the things we can display'''
|
| 160 |
+
return [x for x in self._attrMap['kind'].validate._enum if x is not None]
|
| 161 |
+
|
| 162 |
+
def _Flag_None(self):
|
| 163 |
+
s = _size # abbreviate as we will use this a lot
|
| 164 |
+
g = Group()
|
| 165 |
+
g.add(Rect(0, 0, s*2, s, fillColor = colors.purple, strokeColor = colors.black, strokeWidth=0))
|
| 166 |
+
return g
|
| 167 |
+
|
| 168 |
+
def _borderDraw(self,f):
|
| 169 |
+
s = self.size # abbreviate as we will use this a lot
|
| 170 |
+
g = Group()
|
| 171 |
+
g.add(f)
|
| 172 |
+
x, y, sW = self.x+self.dx, self.y+self.dy, self.strokeWidth/2.
|
| 173 |
+
g.insert(0,Rect(-sW, -sW, width=getattr(self,'_width',2*s)+3*sW, height=getattr(self,'_height',s)+2*sW,
|
| 174 |
+
fillColor = None, strokeColor = self.strokeColor, strokeWidth=sW*2))
|
| 175 |
+
g.shift(x,y)
|
| 176 |
+
g.scale(s/_size, s/_size)
|
| 177 |
+
return g
|
| 178 |
+
|
| 179 |
+
def draw(self):
|
| 180 |
+
kind = self.kind or 'None'
|
| 181 |
+
f = self._cache.get(kind)
|
| 182 |
+
if not f:
|
| 183 |
+
f = getattr(self,'_Flag_'+kind)()
|
| 184 |
+
self._cache[kind] = f._explode()
|
| 185 |
+
return self._borderDraw(f)
|
| 186 |
+
|
| 187 |
+
def clone(self):
|
| 188 |
+
return copy.copy(self)
|
| 189 |
+
|
| 190 |
+
def demo(self):
|
| 191 |
+
D = Drawing(200, 100)
|
| 192 |
+
name = self.availableFlagNames()
|
| 193 |
+
import time
|
| 194 |
+
name = name[int(time.time()) % len(name)]
|
| 195 |
+
fx = Flag()
|
| 196 |
+
fx.kind = name
|
| 197 |
+
fx.x = 0
|
| 198 |
+
fx.y = 0
|
| 199 |
+
D.add(fx)
|
| 200 |
+
labelFontSize = 10
|
| 201 |
+
D.add(String(fx.x+(fx.size/2.0),(fx.y-(1.2*labelFontSize)),
|
| 202 |
+
name, fillColor=colors.black, textAnchor='middle',
|
| 203 |
+
fontSize=labelFontSize))
|
| 204 |
+
labelFontSize = int(fx.size/4.0)
|
| 205 |
+
D.add(String(fx.x+(fx.size),(fx.y+((fx.size/2.0))),
|
| 206 |
+
"SAMPLE", fillColor=colors.gold, textAnchor='middle',
|
| 207 |
+
fontSize=labelFontSize, fontName="Helvetica-Bold"))
|
| 208 |
+
return D
|
| 209 |
+
|
| 210 |
+
def _Flag_UK(self):
|
| 211 |
+
s = _size
|
| 212 |
+
g = Group()
|
| 213 |
+
w = s*2
|
| 214 |
+
g.add(Rect(0, 0, w, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0))
|
| 215 |
+
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))
|
| 216 |
+
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))
|
| 217 |
+
g.add(Polygon([0, s-(s/15.0), (s-((s/10.0)*4)), (s*0.65), (s-(s/10.0)*3), (s*0.65), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 218 |
+
g.add(Polygon([0, 0, (s-((s/10.0)*3)), (s*0.35), (s-((s/10.0)*2)), (s*0.35), (s/10.0), 0], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 219 |
+
g.add(Polygon([w, s, (s+((s/10.0)*3)), (s*0.65), (s+((s/10.0)*2)), (s*0.65), w-(s/10.0), s], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 220 |
+
g.add(Polygon([w, (s/15.0), (s+((s/10.0)*4)), (s*0.35), (s+((s/10.0)*3)), (s*0.35), w, 0], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 221 |
+
g.add(Rect(((s*0.42)*2), 0, width=(0.16*s)*2, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
| 222 |
+
g.add(Rect(0, (s*0.35), width=w, height=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
| 223 |
+
g.add(Rect(((s*0.45)*2), 0, width=(0.1*s)*2, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 224 |
+
g.add(Rect(0, (s*0.4), width=w, height=s*0.2, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 225 |
+
return g
|
| 226 |
+
|
| 227 |
+
def _Flag_USA(self):
|
| 228 |
+
s = _size # abbreviate as we will use this a lot
|
| 229 |
+
g = Group()
|
| 230 |
+
|
| 231 |
+
box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
| 232 |
+
g.add(box)
|
| 233 |
+
|
| 234 |
+
for stripecounter in range (13,0, -1):
|
| 235 |
+
stripeheight = s/13.0
|
| 236 |
+
if not (stripecounter%2 == 0):
|
| 237 |
+
stripecolor = colors.red
|
| 238 |
+
else:
|
| 239 |
+
stripecolor = colors.mintcream
|
| 240 |
+
redorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight,
|
| 241 |
+
fillColor = stripecolor, strokeColor = None, strokeWidth=20)
|
| 242 |
+
g.add(redorwhiteline)
|
| 243 |
+
|
| 244 |
+
bluebox = Rect(0, (s-(stripeheight*7)), width=0.8*s, height=stripeheight*7,
|
| 245 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 246 |
+
g.add(bluebox)
|
| 247 |
+
|
| 248 |
+
lss = s*0.045
|
| 249 |
+
lss2 = lss/2.0
|
| 250 |
+
s9 = s/9.0
|
| 251 |
+
s7 = s/7.0
|
| 252 |
+
for starxcounter in range(5):
|
| 253 |
+
for starycounter in range(4):
|
| 254 |
+
ls = Star()
|
| 255 |
+
ls.size = lss
|
| 256 |
+
ls.x = 0-s/22.0+lss/2.0+s7+starxcounter*s7
|
| 257 |
+
ls.fillColor = colors.mintcream
|
| 258 |
+
ls.y = s-(starycounter+1)*s9+lss2
|
| 259 |
+
g.add(ls)
|
| 260 |
+
|
| 261 |
+
for starxcounter in range(6):
|
| 262 |
+
for starycounter in range(5):
|
| 263 |
+
ls = Star()
|
| 264 |
+
ls.size = lss
|
| 265 |
+
ls.x = 0-(s/22.0)+lss/2.0+s/14.0+starxcounter*s7
|
| 266 |
+
ls.fillColor = colors.mintcream
|
| 267 |
+
ls.y = s-(starycounter+1)*s9+(s/18.0)+lss2
|
| 268 |
+
g.add(ls)
|
| 269 |
+
return g
|
| 270 |
+
|
| 271 |
+
def _Flag_Afghanistan(self):
|
| 272 |
+
s = _size
|
| 273 |
+
g = Group()
|
| 274 |
+
|
| 275 |
+
box = Rect(0, 0, s*2, s,
|
| 276 |
+
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
| 277 |
+
g.add(box)
|
| 278 |
+
|
| 279 |
+
greenbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
| 280 |
+
fillColor = colors.limegreen, strokeColor = None, strokeWidth=0)
|
| 281 |
+
g.add(greenbox)
|
| 282 |
+
|
| 283 |
+
blackbox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
| 284 |
+
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
| 285 |
+
g.add(blackbox)
|
| 286 |
+
return g
|
| 287 |
+
|
| 288 |
+
def _Flag_Austria(self):
|
| 289 |
+
s = _size # abbreviate as we will use this a lot
|
| 290 |
+
g = Group()
|
| 291 |
+
|
| 292 |
+
box = Rect(0, 0, s*2, s, fillColor = colors.mintcream,
|
| 293 |
+
strokeColor = colors.black, strokeWidth=0)
|
| 294 |
+
g.add(box)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
redbox1 = Rect(0, 0, width=s*2.0, height=s/3.0,
|
| 298 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 299 |
+
g.add(redbox1)
|
| 300 |
+
|
| 301 |
+
redbox2 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
| 302 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 303 |
+
g.add(redbox2)
|
| 304 |
+
return g
|
| 305 |
+
|
| 306 |
+
def _Flag_Belgium(self):
|
| 307 |
+
s = _size
|
| 308 |
+
g = Group()
|
| 309 |
+
|
| 310 |
+
box = Rect(0, 0, s*2, s,
|
| 311 |
+
fillColor = colors.black, strokeColor = colors.black, strokeWidth=0)
|
| 312 |
+
g.add(box)
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
box1 = Rect(0, 0, width=(s/3.0)*2.0, height=s,
|
| 316 |
+
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
| 317 |
+
g.add(box1)
|
| 318 |
+
|
| 319 |
+
box2 = Rect(((s/3.0)*2.0), 0, width=(s/3.0)*2.0, height=s,
|
| 320 |
+
fillColor = colors.gold, strokeColor = None, strokeWidth=0)
|
| 321 |
+
g.add(box2)
|
| 322 |
+
|
| 323 |
+
box3 = Rect(((s/3.0)*4.0), 0, width=(s/3.0)*2.0, height=s,
|
| 324 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 325 |
+
g.add(box3)
|
| 326 |
+
return g
|
| 327 |
+
|
| 328 |
+
def _Flag_China(self):
|
| 329 |
+
s = _size
|
| 330 |
+
g = Group()
|
| 331 |
+
self._width = w = s*1.5
|
| 332 |
+
g.add(Rect(0, 0, w, s, fillColor=colors.red, strokeColor=None, strokeWidth=0))
|
| 333 |
+
|
| 334 |
+
def addStar(x,y,size,angle,g=g,w=s/20.0,x0=0,y0=s/2.0):
|
| 335 |
+
s = Star()
|
| 336 |
+
s.fillColor=colors.yellow
|
| 337 |
+
s.angle = angle
|
| 338 |
+
s.size = size*w*2
|
| 339 |
+
s.x = x*w+x0
|
| 340 |
+
s.y = y*w+y0
|
| 341 |
+
g.add(s)
|
| 342 |
+
|
| 343 |
+
addStar(5,5,3, 0)
|
| 344 |
+
addStar(10,1,1,36.86989765)
|
| 345 |
+
addStar(12,3,1,8.213210702)
|
| 346 |
+
addStar(12,6,1,16.60154960)
|
| 347 |
+
addStar(10,8,1,53.13010235)
|
| 348 |
+
return g
|
| 349 |
+
|
| 350 |
+
def _Flag_Cuba(self):
|
| 351 |
+
s = _size
|
| 352 |
+
g = Group()
|
| 353 |
+
|
| 354 |
+
for i in range(5):
|
| 355 |
+
stripe = Rect(0, i*s/5.0, width=s*2, height=s/5.0,
|
| 356 |
+
fillColor = [colors.darkblue, colors.mintcream][i%2],
|
| 357 |
+
strokeColor = None,
|
| 358 |
+
strokeWidth=0)
|
| 359 |
+
g.add(stripe)
|
| 360 |
+
|
| 361 |
+
redwedge = Polygon(points = [ 0, 0, 4*s/5.0, (s/2.0), 0, s],
|
| 362 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 363 |
+
g.add(redwedge)
|
| 364 |
+
|
| 365 |
+
star = Star()
|
| 366 |
+
star.x = 2.5*s/10.0
|
| 367 |
+
star.y = s/2.0
|
| 368 |
+
star.size = 3*s/10.0
|
| 369 |
+
star.fillColor = colors.white
|
| 370 |
+
g.add(star)
|
| 371 |
+
|
| 372 |
+
box = Rect(0, 0, s*2, s,
|
| 373 |
+
fillColor = None,
|
| 374 |
+
strokeColor = colors.black,
|
| 375 |
+
strokeWidth=0)
|
| 376 |
+
g.add(box)
|
| 377 |
+
|
| 378 |
+
return g
|
| 379 |
+
|
| 380 |
+
def _Flag_Denmark(self):
|
| 381 |
+
s = _size
|
| 382 |
+
g = Group()
|
| 383 |
+
self._width = w = s*1.4
|
| 384 |
+
|
| 385 |
+
box = Rect(0, 0, w, s,
|
| 386 |
+
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
| 387 |
+
g.add(box)
|
| 388 |
+
|
| 389 |
+
whitebox1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s,
|
| 390 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 391 |
+
g.add(whitebox1)
|
| 392 |
+
|
| 393 |
+
whitebox2 = Rect(0, ((s/2.0)-(s/12.0)), width=w, height=s/6.0,
|
| 394 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 395 |
+
g.add(whitebox2)
|
| 396 |
+
return g
|
| 397 |
+
|
| 398 |
+
def _Flag_Finland(self):
|
| 399 |
+
s = _size
|
| 400 |
+
g = Group()
|
| 401 |
+
|
| 402 |
+
# crossbox specific bits
|
| 403 |
+
box = Rect(0, 0, s*2, s,
|
| 404 |
+
fillColor = colors.ghostwhite, strokeColor = colors.black, strokeWidth=0)
|
| 405 |
+
g.add(box)
|
| 406 |
+
|
| 407 |
+
blueline1 = Rect((s*0.6), 0, width=0.3*s, height=s,
|
| 408 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 409 |
+
g.add(blueline1)
|
| 410 |
+
|
| 411 |
+
blueline2 = Rect(0, (s*0.4), width=s*2, height=s*0.3,
|
| 412 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 413 |
+
g.add(blueline2)
|
| 414 |
+
return g
|
| 415 |
+
|
| 416 |
+
def _Flag_France(self):
|
| 417 |
+
s = _size
|
| 418 |
+
g = Group()
|
| 419 |
+
|
| 420 |
+
box = Rect(0, 0, s*2, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0)
|
| 421 |
+
g.add(box)
|
| 422 |
+
|
| 423 |
+
bluebox = Rect(0, 0, width=((s/3.0)*2.0), height=s,
|
| 424 |
+
fillColor = colors.blue, strokeColor = None, strokeWidth=0)
|
| 425 |
+
g.add(bluebox)
|
| 426 |
+
|
| 427 |
+
whitebox = Rect(((s/3.0)*2.0), 0, width=((s/3.0)*2.0), height=s,
|
| 428 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 429 |
+
g.add(whitebox)
|
| 430 |
+
|
| 431 |
+
redbox = Rect(((s/3.0)*4.0), 0, width=((s/3.0)*2.0), height=s,
|
| 432 |
+
fillColor = colors.red,
|
| 433 |
+
strokeColor = None,
|
| 434 |
+
strokeWidth=0)
|
| 435 |
+
g.add(redbox)
|
| 436 |
+
return g
|
| 437 |
+
|
| 438 |
+
def _Flag_Germany(self):
|
| 439 |
+
s = _size
|
| 440 |
+
g = Group()
|
| 441 |
+
|
| 442 |
+
box = Rect(0, 0, s*2, s,
|
| 443 |
+
fillColor = colors.gold, strokeColor = colors.black, strokeWidth=0)
|
| 444 |
+
g.add(box)
|
| 445 |
+
|
| 446 |
+
blackbox1 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
| 447 |
+
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
| 448 |
+
g.add(blackbox1)
|
| 449 |
+
|
| 450 |
+
redbox1 = Rect(0, (s/3.0), width=s*2.0, height=s/3.0,
|
| 451 |
+
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
| 452 |
+
g.add(redbox1)
|
| 453 |
+
return g
|
| 454 |
+
|
| 455 |
+
def _Flag_Greece(self):
|
| 456 |
+
s = _size
|
| 457 |
+
g = Group()
|
| 458 |
+
|
| 459 |
+
box = Rect(0, 0, s*2, s, fillColor = colors.gold,
|
| 460 |
+
strokeColor = colors.black, strokeWidth=0)
|
| 461 |
+
g.add(box)
|
| 462 |
+
|
| 463 |
+
for stripecounter in range (9,0, -1):
|
| 464 |
+
stripeheight = s/9.0
|
| 465 |
+
if not (stripecounter%2 == 0):
|
| 466 |
+
stripecolor = colors.deepskyblue
|
| 467 |
+
else:
|
| 468 |
+
stripecolor = colors.mintcream
|
| 469 |
+
|
| 470 |
+
blueorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight,
|
| 471 |
+
fillColor = stripecolor, strokeColor = None, strokeWidth=20)
|
| 472 |
+
g.add(blueorwhiteline)
|
| 473 |
+
|
| 474 |
+
bluebox1 = Rect(0, ((s)-stripeheight*5), width=(stripeheight*5), height=stripeheight*5,
|
| 475 |
+
fillColor = colors.deepskyblue, strokeColor = None, strokeWidth=0)
|
| 476 |
+
g.add(bluebox1)
|
| 477 |
+
|
| 478 |
+
whiteline1 = Rect(0, ((s)-stripeheight*3), width=stripeheight*5, height=stripeheight,
|
| 479 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 480 |
+
g.add(whiteline1)
|
| 481 |
+
|
| 482 |
+
whiteline2 = Rect((stripeheight*2), ((s)-stripeheight*5), width=stripeheight, height=stripeheight*5,
|
| 483 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 484 |
+
g.add(whiteline2)
|
| 485 |
+
|
| 486 |
+
return g
|
| 487 |
+
|
| 488 |
+
def _Flag_Ireland(self):
|
| 489 |
+
s = _size
|
| 490 |
+
g = Group()
|
| 491 |
+
|
| 492 |
+
box = Rect(0, 0, s*2, s,
|
| 493 |
+
fillColor = colors.forestgreen, strokeColor = colors.black, strokeWidth=0)
|
| 494 |
+
g.add(box)
|
| 495 |
+
|
| 496 |
+
whitebox = Rect(((s*2.0)/3.0), 0, width=(2.0*(s*2.0)/3.0), height=s,
|
| 497 |
+
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
| 498 |
+
g.add(whitebox)
|
| 499 |
+
|
| 500 |
+
orangebox = Rect(((2.0*(s*2.0)/3.0)), 0, width=(s*2.0)/3.0, height=s,
|
| 501 |
+
fillColor = colors.darkorange, strokeColor = None, strokeWidth=0)
|
| 502 |
+
g.add(orangebox)
|
| 503 |
+
return g
|
| 504 |
+
|
| 505 |
+
def _Flag_Italy(self):
|
| 506 |
+
s = _size
|
| 507 |
+
g = Group()
|
| 508 |
+
g.add(Rect(0,0,s*2,s,fillColor=colors.forestgreen,strokeColor=None, strokeWidth=0))
|
| 509 |
+
g.add(Rect((2*s)/3.0, 0, width=(s*4)/3.0, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
| 510 |
+
g.add(Rect((4*s)/3.0, 0, width=(s*2)/3.0, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 511 |
+
return g
|
| 512 |
+
|
| 513 |
+
def _Flag_Japan(self):
|
| 514 |
+
s = _size
|
| 515 |
+
g = Group()
|
| 516 |
+
w = self._width = s*1.5
|
| 517 |
+
g.add(Rect(0,0,w,s,fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
| 518 |
+
g.add(Circle(cx=w/2.0,cy=s/2.0,r=0.3*w,fillColor=colors.red,strokeColor=None, strokeWidth=0))
|
| 519 |
+
return g
|
| 520 |
+
|
| 521 |
+
def _Flag_Luxembourg(self):
|
| 522 |
+
s = _size
|
| 523 |
+
g = Group()
|
| 524 |
+
|
| 525 |
+
box = Rect(0, 0, s*2, s,
|
| 526 |
+
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
| 527 |
+
g.add(box)
|
| 528 |
+
|
| 529 |
+
redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
| 530 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 531 |
+
g.add(redbox)
|
| 532 |
+
|
| 533 |
+
bluebox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
| 534 |
+
fillColor = colors.dodgerblue, strokeColor = None, strokeWidth=0)
|
| 535 |
+
g.add(bluebox)
|
| 536 |
+
return g
|
| 537 |
+
|
| 538 |
+
def _Flag_Holland(self):
|
| 539 |
+
s = _size
|
| 540 |
+
g = Group()
|
| 541 |
+
|
| 542 |
+
box = Rect(0, 0, s*2, s,
|
| 543 |
+
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
| 544 |
+
g.add(box)
|
| 545 |
+
|
| 546 |
+
redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
| 547 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 548 |
+
g.add(redbox)
|
| 549 |
+
|
| 550 |
+
bluebox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
| 551 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 552 |
+
g.add(bluebox)
|
| 553 |
+
return g
|
| 554 |
+
|
| 555 |
+
def _Flag_Portugal(self):
|
| 556 |
+
return Group()
|
| 557 |
+
|
| 558 |
+
def _Flag_Russia(self):
|
| 559 |
+
s = _size
|
| 560 |
+
g = Group()
|
| 561 |
+
w = self._width = s*1.5
|
| 562 |
+
t = s/3.0
|
| 563 |
+
g.add(Rect(0, 0, width=w, height=t, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 564 |
+
g.add(Rect(0, t, width=w, height=t, fillColor = colors.blue, strokeColor = None, strokeWidth=0))
|
| 565 |
+
g.add(Rect(0, 2*t, width=w, height=t, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
| 566 |
+
return g
|
| 567 |
+
|
| 568 |
+
def _Flag_Spain(self):
|
| 569 |
+
s = _size
|
| 570 |
+
g = Group()
|
| 571 |
+
w = self._width = s*1.5
|
| 572 |
+
g.add(Rect(0, 0, width=w, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
| 573 |
+
g.add(Rect(0, (s/4.0), width=w, height=s/2.0, fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
| 574 |
+
return g
|
| 575 |
+
|
| 576 |
+
def _Flag_Sweden(self):
|
| 577 |
+
s = _size
|
| 578 |
+
g = Group()
|
| 579 |
+
self._width = s*1.4
|
| 580 |
+
box = Rect(0, 0, self._width, s,
|
| 581 |
+
fillColor = colors.dodgerblue, strokeColor = colors.black, strokeWidth=0)
|
| 582 |
+
g.add(box)
|
| 583 |
+
|
| 584 |
+
box1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s,
|
| 585 |
+
fillColor = colors.gold, strokeColor = None, strokeWidth=0)
|
| 586 |
+
g.add(box1)
|
| 587 |
+
|
| 588 |
+
box2 = Rect(0, ((s/2.0)-(s/12.0)), width=self._width, height=s/6.0,
|
| 589 |
+
fillColor = colors.gold,
|
| 590 |
+
strokeColor = None,
|
| 591 |
+
strokeWidth=0)
|
| 592 |
+
g.add(box2)
|
| 593 |
+
return g
|
| 594 |
+
|
| 595 |
+
def _Flag_Norway(self):
|
| 596 |
+
s = _size
|
| 597 |
+
g = Group()
|
| 598 |
+
self._width = s*1.4
|
| 599 |
+
|
| 600 |
+
box = Rect(0, 0, self._width, s,
|
| 601 |
+
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
| 602 |
+
g.add(box)
|
| 603 |
+
|
| 604 |
+
box = Rect(0, 0, self._width, s,
|
| 605 |
+
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
| 606 |
+
g.add(box)
|
| 607 |
+
|
| 608 |
+
whiteline1 = Rect(((s*0.2)*2), 0, width=s*0.2, height=s,
|
| 609 |
+
fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0)
|
| 610 |
+
g.add(whiteline1)
|
| 611 |
+
|
| 612 |
+
whiteline2 = Rect(0, (s*0.4), width=self._width, height=s*0.2,
|
| 613 |
+
fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0)
|
| 614 |
+
g.add(whiteline2)
|
| 615 |
+
|
| 616 |
+
blueline1 = Rect(((s*0.225)*2), 0, width=0.1*s, height=s,
|
| 617 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 618 |
+
g.add(blueline1)
|
| 619 |
+
|
| 620 |
+
blueline2 = Rect(0, (s*0.45), width=self._width, height=s*0.1,
|
| 621 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 622 |
+
g.add(blueline2)
|
| 623 |
+
return g
|
| 624 |
+
|
| 625 |
+
def _Flag_CzechRepublic(self):
|
| 626 |
+
s = _size
|
| 627 |
+
g = Group()
|
| 628 |
+
box = Rect(0, 0, s*2, s,
|
| 629 |
+
fillColor = colors.mintcream,
|
| 630 |
+
strokeColor = colors.black,
|
| 631 |
+
strokeWidth=0)
|
| 632 |
+
g.add(box)
|
| 633 |
+
|
| 634 |
+
redbox = Rect(0, 0, width=s*2, height=s/2.0,
|
| 635 |
+
fillColor = colors.red,
|
| 636 |
+
strokeColor = None,
|
| 637 |
+
strokeWidth=0)
|
| 638 |
+
g.add(redbox)
|
| 639 |
+
|
| 640 |
+
bluewedge = Polygon(points = [ 0, 0, s, (s/2.0), 0, s],
|
| 641 |
+
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
| 642 |
+
g.add(bluewedge)
|
| 643 |
+
return g
|
| 644 |
+
|
| 645 |
+
def _Flag_Palestine(self):
|
| 646 |
+
s = _size
|
| 647 |
+
g = Group()
|
| 648 |
+
box = Rect(0, s/3.0, s*2, s/3.0,
|
| 649 |
+
fillColor = colors.mintcream,
|
| 650 |
+
strokeColor = None,
|
| 651 |
+
strokeWidth=0)
|
| 652 |
+
g.add(box)
|
| 653 |
+
|
| 654 |
+
greenbox = Rect(0, 0, width=s*2, height=s/3.0,
|
| 655 |
+
fillColor = colors.limegreen,
|
| 656 |
+
strokeColor = None,
|
| 657 |
+
strokeWidth=0)
|
| 658 |
+
g.add(greenbox)
|
| 659 |
+
|
| 660 |
+
blackbox = Rect(0, 2*s/3.0, width=s*2, height=s/3.0,
|
| 661 |
+
fillColor = colors.black,
|
| 662 |
+
strokeColor = None,
|
| 663 |
+
strokeWidth=0)
|
| 664 |
+
g.add(blackbox)
|
| 665 |
+
|
| 666 |
+
redwedge = Polygon(points = [ 0, 0, 2*s/3.0, (s/2.0), 0, s],
|
| 667 |
+
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
| 668 |
+
g.add(redwedge)
|
| 669 |
+
return g
|
| 670 |
+
|
| 671 |
+
def _Flag_Turkey(self):
|
| 672 |
+
s = _size
|
| 673 |
+
g = Group()
|
| 674 |
+
|
| 675 |
+
box = Rect(0, 0, s*2, s,
|
| 676 |
+
fillColor = colors.red,
|
| 677 |
+
strokeColor = colors.black,
|
| 678 |
+
strokeWidth=0)
|
| 679 |
+
g.add(box)
|
| 680 |
+
|
| 681 |
+
whitecircle = Circle(cx=((s*0.35)*2), cy=s/2.0, r=s*0.3,
|
| 682 |
+
fillColor = colors.mintcream,
|
| 683 |
+
strokeColor = None,
|
| 684 |
+
strokeWidth=0)
|
| 685 |
+
g.add(whitecircle)
|
| 686 |
+
|
| 687 |
+
redcircle = Circle(cx=((s*0.39)*2), cy=s/2.0, r=s*0.24,
|
| 688 |
+
fillColor = colors.red,
|
| 689 |
+
strokeColor = None,
|
| 690 |
+
strokeWidth=0)
|
| 691 |
+
g.add(redcircle)
|
| 692 |
+
|
| 693 |
+
ws = Star()
|
| 694 |
+
ws.angle = 15
|
| 695 |
+
ws.size = s/5.0
|
| 696 |
+
ws.x = (s*0.5)*2+ws.size/2.0
|
| 697 |
+
ws.y = (s*0.5)
|
| 698 |
+
ws.fillColor = colors.mintcream
|
| 699 |
+
ws.strokeColor = None
|
| 700 |
+
g.add(ws)
|
| 701 |
+
return g
|
| 702 |
+
|
| 703 |
+
def _Flag_Switzerland(self):
|
| 704 |
+
s = _size
|
| 705 |
+
g = Group()
|
| 706 |
+
self._width = s
|
| 707 |
+
|
| 708 |
+
g.add(Rect(0, 0, s, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0))
|
| 709 |
+
g.add(Line((s/2.0), (s/5.5), (s/2), (s-(s/5.5)),
|
| 710 |
+
fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=(s/5.0)))
|
| 711 |
+
g.add(Line((s/5.5), (s/2.0), (s-(s/5.5)), (s/2.0),
|
| 712 |
+
fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=s/5.0))
|
| 713 |
+
return g
|
| 714 |
+
|
| 715 |
+
def _Flag_EU(self):
|
| 716 |
+
s = _size
|
| 717 |
+
g = Group()
|
| 718 |
+
w = self._width = 1.5*s
|
| 719 |
+
|
| 720 |
+
g.add(Rect(0, 0, w, s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0))
|
| 721 |
+
centerx=w/2.0
|
| 722 |
+
centery=s/2.0
|
| 723 |
+
radius=s/3.0
|
| 724 |
+
yradius = radius
|
| 725 |
+
xradius = radius
|
| 726 |
+
nStars = 12
|
| 727 |
+
delta = 2*pi/nStars
|
| 728 |
+
for i in range(nStars):
|
| 729 |
+
rad = i*delta
|
| 730 |
+
gs = Star()
|
| 731 |
+
gs.x=cos(rad)*radius+centerx
|
| 732 |
+
gs.y=sin(rad)*radius+centery
|
| 733 |
+
gs.size=s/10.0
|
| 734 |
+
gs.fillColor=colors.gold
|
| 735 |
+
g.add(gs)
|
| 736 |
+
return g
|
| 737 |
+
|
| 738 |
+
def _Flag_Brazil(self):
|
| 739 |
+
s = _size # abbreviate as we will use this a lot
|
| 740 |
+
g = Group()
|
| 741 |
+
|
| 742 |
+
m = s/14.0
|
| 743 |
+
self._width = w = (m * 20)
|
| 744 |
+
|
| 745 |
+
def addStar(x,y,size, g=g, w=w, s=s, m=m):
|
| 746 |
+
st = Star()
|
| 747 |
+
st.fillColor=colors.mintcream
|
| 748 |
+
st.size = size*m
|
| 749 |
+
st.x = (w/2.0) + (x * (0.35 * m))
|
| 750 |
+
st.y = (s/2.0) + (y * (0.35 * m))
|
| 751 |
+
g.add(st)
|
| 752 |
+
|
| 753 |
+
g.add(Rect(0, 0, w, s, fillColor = colors.green, strokeColor = None, strokeWidth=0))
|
| 754 |
+
g.add(Polygon(points = [ 1.7*m, (s/2.0), (w/2.0), s-(1.7*m), w-(1.7*m),(s/2.0),(w/2.0), 1.7*m],
|
| 755 |
+
fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
| 756 |
+
g.add(Circle(cx=w/2.0, cy=s/2.0, r=3.5*m,
|
| 757 |
+
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
| 758 |
+
g.add(Wedge((w/2.0)-(2*m), 0, 8.5*m, 50, 98.1, 8.5*m,
|
| 759 |
+
fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
| 760 |
+
g.add(Wedge((w/2.0), (s/2.0), 3.501*m, 156, 352, 3.501*m,
|
| 761 |
+
fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
| 762 |
+
g.add(Wedge((w/2.0)-(2*m), 0, 8*m, 48.1, 100, 8*m,
|
| 763 |
+
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
| 764 |
+
g.add(Rect(0, 0, w, (s/4.0) + 1.7*m,
|
| 765 |
+
fillColor = colors.green, strokeColor = None, strokeWidth=0))
|
| 766 |
+
g.add(Polygon(points = [ 1.7*m,(s/2.0), (w/2.0),s/2.0 - 2*m, w-(1.7*m),(s/2.0) , (w/2.0),1.7*m],
|
| 767 |
+
fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
| 768 |
+
g.add(Wedge(w/2.0, s/2.0, 3.502*m, 166, 342.1, 3.502*m,
|
| 769 |
+
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
| 770 |
+
|
| 771 |
+
addStar(3.2,3.5,0.3)
|
| 772 |
+
addStar(-8.5,1.5,0.3)
|
| 773 |
+
addStar(-7.5,-3,0.3)
|
| 774 |
+
addStar(-4,-5.5,0.3)
|
| 775 |
+
addStar(0,-4.5,0.3)
|
| 776 |
+
addStar(7,-3.5,0.3)
|
| 777 |
+
addStar(-3.5,-0.5,0.25)
|
| 778 |
+
addStar(0,-1.5,0.25)
|
| 779 |
+
addStar(1,-2.5,0.25)
|
| 780 |
+
addStar(3,-7,0.25)
|
| 781 |
+
addStar(5,-6.5,0.25)
|
| 782 |
+
addStar(6.5,-5,0.25)
|
| 783 |
+
addStar(7,-4.5,0.25)
|
| 784 |
+
addStar(-5.5,-3.2,0.25)
|
| 785 |
+
addStar(-6,-4.2,0.25)
|
| 786 |
+
addStar(-1,-2.75,0.2)
|
| 787 |
+
addStar(2,-5.5,0.2)
|
| 788 |
+
addStar(4,-5.5,0.2)
|
| 789 |
+
addStar(5,-7.5,0.2)
|
| 790 |
+
addStar(5,-5.5,0.2)
|
| 791 |
+
addStar(6,-5.5,0.2)
|
| 792 |
+
addStar(-8.8,-3.2,0.2)
|
| 793 |
+
addStar(2.5,0.5,0.2)
|
| 794 |
+
addStar(-0.2,-3.2,0.14)
|
| 795 |
+
addStar(-7.2,-2,0.14)
|
| 796 |
+
addStar(0,-8,0.1)
|
| 797 |
+
|
| 798 |
+
sTmp = "ORDEM E PROGRESSO"
|
| 799 |
+
nTmp = len(sTmp)
|
| 800 |
+
delta = 0.850848010347/nTmp
|
| 801 |
+
radius = 7.9 *m
|
| 802 |
+
centerx = (w/2.0)-(2*m)
|
| 803 |
+
centery = 0
|
| 804 |
+
for i in range(nTmp):
|
| 805 |
+
rad = 2*pi - i*delta -4.60766922527
|
| 806 |
+
x=cos(rad)*radius+centerx
|
| 807 |
+
y=sin(rad)*radius+centery
|
| 808 |
+
if i == 6:
|
| 809 |
+
z = 0.35*m
|
| 810 |
+
else:
|
| 811 |
+
z= 0.45*m
|
| 812 |
+
g2 = Group(String(x, y, sTmp[i], fontName='Helvetica-Bold',
|
| 813 |
+
fontSize = z,strokeColor=None,fillColor=colors.green))
|
| 814 |
+
g2.rotate(rad)
|
| 815 |
+
g.add(g2)
|
| 816 |
+
return g
|
| 817 |
+
|
| 818 |
+
def makeFlag(name):
|
| 819 |
+
flag = Flag()
|
| 820 |
+
flag.kind = name
|
| 821 |
+
return flag
|
| 822 |
+
|
| 823 |
+
def test():
|
| 824 |
+
"""This function produces three pdf files with examples of all the signs and symbols from this file.
|
| 825 |
+
"""
|
| 826 |
+
# page 1
|
| 827 |
+
|
| 828 |
+
labelFontSize = 10
|
| 829 |
+
|
| 830 |
+
X = (20,245)
|
| 831 |
+
|
| 832 |
+
flags = [
|
| 833 |
+
'UK',
|
| 834 |
+
'USA',
|
| 835 |
+
'Afghanistan',
|
| 836 |
+
'Austria',
|
| 837 |
+
'Belgium',
|
| 838 |
+
'Denmark',
|
| 839 |
+
'Cuba',
|
| 840 |
+
'Finland',
|
| 841 |
+
'France',
|
| 842 |
+
'Germany',
|
| 843 |
+
'Greece',
|
| 844 |
+
'Ireland',
|
| 845 |
+
'Italy',
|
| 846 |
+
'Luxembourg',
|
| 847 |
+
'Holland',
|
| 848 |
+
'Palestine',
|
| 849 |
+
'Portugal',
|
| 850 |
+
'Spain',
|
| 851 |
+
'Sweden',
|
| 852 |
+
'Norway',
|
| 853 |
+
'CzechRepublic',
|
| 854 |
+
'Turkey',
|
| 855 |
+
'Switzerland',
|
| 856 |
+
'EU',
|
| 857 |
+
'Brazil',
|
| 858 |
+
]
|
| 859 |
+
y = Y0 = 530
|
| 860 |
+
f = 0
|
| 861 |
+
D = None
|
| 862 |
+
for name in flags:
|
| 863 |
+
if not D: D = Drawing(450,650)
|
| 864 |
+
flag = makeFlag(name)
|
| 865 |
+
i = flags.index(name)
|
| 866 |
+
flag.x = X[i%2]
|
| 867 |
+
flag.y = y
|
| 868 |
+
D.add(flag)
|
| 869 |
+
D.add(String(flag.x+(flag.size/2.0),(flag.y-(1.2*labelFontSize)),
|
| 870 |
+
name, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize))
|
| 871 |
+
if i%2: y = y - 125
|
| 872 |
+
if (i%2 and y<0) or name==flags[-1]:
|
| 873 |
+
renderPDF.drawToFile(D, 'flags%02d.pdf'%f, 'flags.py - Page #%d'%(f+1))
|
| 874 |
+
y = Y0
|
| 875 |
+
f = f+1
|
| 876 |
+
D = None
|
| 877 |
+
|
| 878 |
+
if __name__=='__main__':
|
| 879 |
+
test()
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/grids.py
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Copyright ReportLab Europe Ltd. 2000-2017
|
| 2 |
+
#see license.txt for license details
|
| 3 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/grids.py
|
| 4 |
+
__version__='3.3.0'
|
| 5 |
+
|
| 6 |
+
from reportlab.lib import colors
|
| 7 |
+
from reportlab.lib.validators import isNumber, isColorOrNone, isBoolean, isListOfNumbers, OneOf, isListOfColors, isNumberOrNone
|
| 8 |
+
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
| 9 |
+
from reportlab.graphics.shapes import Drawing, Group, Line, Rect, LineShape, definePath, EmptyClipPath
|
| 10 |
+
from reportlab.graphics.widgetbase import Widget
|
| 11 |
+
from math import radians
|
| 12 |
+
from reportlab.graphics.transform import translate, rotate, mmult, transformPoints, inverse
|
| 13 |
+
from reportlab.lib.utils import flatten
|
| 14 |
+
|
| 15 |
+
def frange(start, end=None, inc=None):
|
| 16 |
+
"A range function, that does accept float increments..."
|
| 17 |
+
|
| 18 |
+
if end == None:
|
| 19 |
+
end = start + 0.0
|
| 20 |
+
start = 0.0
|
| 21 |
+
|
| 22 |
+
if inc == None:
|
| 23 |
+
inc = 1.0
|
| 24 |
+
|
| 25 |
+
L = []
|
| 26 |
+
end = end - inc*0.0001 #to avoid numrical problems
|
| 27 |
+
while 1:
|
| 28 |
+
next = start + len(L) * inc
|
| 29 |
+
if inc > 0 and next >= end:
|
| 30 |
+
break
|
| 31 |
+
elif inc < 0 and next <= end:
|
| 32 |
+
break
|
| 33 |
+
L.append(next)
|
| 34 |
+
|
| 35 |
+
return L
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def makeDistancesList(list):
|
| 39 |
+
"""Returns a list of distances between adjacent numbers in some input list.
|
| 40 |
+
|
| 41 |
+
E.g. [1, 1, 2, 3, 5, 7] -> [0, 1, 1, 2, 2]
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
d = []
|
| 45 |
+
for i in range(len(list[:-1])):
|
| 46 |
+
d.append(list[i+1] - list[i])
|
| 47 |
+
|
| 48 |
+
return d
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class Grid(Widget):
|
| 52 |
+
"""This makes a rectangular grid of equidistant stripes.
|
| 53 |
+
|
| 54 |
+
The grid contains an outer border rectangle, and stripes
|
| 55 |
+
inside which can be drawn with lines and/or as solid tiles.
|
| 56 |
+
The drawing order is: outer rectangle, then lines and tiles.
|
| 57 |
+
|
| 58 |
+
The stripes' width is indicated as 'delta'. The sequence of
|
| 59 |
+
stripes can have an offset named 'delta0'. Both values need
|
| 60 |
+
to be positive!
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
_attrMap = AttrMap(
|
| 64 |
+
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
| 65 |
+
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
| 66 |
+
width = AttrMapValue(isNumber, desc="The grid's width."),
|
| 67 |
+
height = AttrMapValue(isNumber, desc="The grid's height."),
|
| 68 |
+
orientation = AttrMapValue(OneOf(('vertical', 'horizontal')),
|
| 69 |
+
desc='Determines if stripes are vertical or horizontal.'),
|
| 70 |
+
useLines = AttrMapValue(OneOf((0, 1)),
|
| 71 |
+
desc='Determines if stripes are drawn with lines.'),
|
| 72 |
+
useRects = AttrMapValue(OneOf((0, 1)),
|
| 73 |
+
desc='Determines if stripes are drawn with solid rectangles.'),
|
| 74 |
+
delta = AttrMapValue(isNumber,
|
| 75 |
+
desc='Determines the width/height of the stripes.'),
|
| 76 |
+
delta0 = AttrMapValue(isNumber,
|
| 77 |
+
desc='Determines the stripes initial width/height offset.'),
|
| 78 |
+
deltaSteps = AttrMapValue(isListOfNumbers,
|
| 79 |
+
desc='List of deltas to be used cyclically.'),
|
| 80 |
+
stripeColors = AttrMapValue(isListOfColors,
|
| 81 |
+
desc='Colors applied cyclically in the right or upper direction.'),
|
| 82 |
+
fillColor = AttrMapValue(isColorOrNone,
|
| 83 |
+
desc='Background color for entire rectangle.'),
|
| 84 |
+
strokeColor = AttrMapValue(isColorOrNone,
|
| 85 |
+
desc='Color used for lines.'),
|
| 86 |
+
strokeWidth = AttrMapValue(isNumber,
|
| 87 |
+
desc='Width used for lines.'),
|
| 88 |
+
rectStrokeColor = AttrMapValue(isColorOrNone, desc='Color for outer rect stroke.'),
|
| 89 |
+
rectStrokeWidth = AttrMapValue(isNumberOrNone, desc='Width for outer rect stroke.'),
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
def __init__(self):
|
| 93 |
+
self.x = 0
|
| 94 |
+
self.y = 0
|
| 95 |
+
self.width = 100
|
| 96 |
+
self.height = 100
|
| 97 |
+
self.orientation = 'vertical'
|
| 98 |
+
self.useLines = 0
|
| 99 |
+
self.useRects = 1
|
| 100 |
+
self.delta = 20
|
| 101 |
+
self.delta0 = 0
|
| 102 |
+
self.deltaSteps = []
|
| 103 |
+
self.fillColor = colors.white
|
| 104 |
+
self.stripeColors = [colors.red, colors.green, colors.blue]
|
| 105 |
+
self.strokeColor = colors.black
|
| 106 |
+
self.strokeWidth = 2
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def demo(self):
|
| 110 |
+
D = Drawing(100, 100)
|
| 111 |
+
|
| 112 |
+
g = Grid()
|
| 113 |
+
D.add(g)
|
| 114 |
+
|
| 115 |
+
return D
|
| 116 |
+
|
| 117 |
+
def makeOuterRect(self):
|
| 118 |
+
strokeColor = getattr(self,'rectStrokeColor',self.strokeColor)
|
| 119 |
+
strokeWidth = getattr(self,'rectStrokeWidth',self.strokeWidth)
|
| 120 |
+
if self.fillColor or (strokeColor and strokeWidth):
|
| 121 |
+
rect = Rect(self.x, self.y, self.width, self.height)
|
| 122 |
+
rect.fillColor = self.fillColor
|
| 123 |
+
rect.strokeColor = strokeColor
|
| 124 |
+
rect.strokeWidth = strokeWidth
|
| 125 |
+
return rect
|
| 126 |
+
else:
|
| 127 |
+
return None
|
| 128 |
+
|
| 129 |
+
def makeLinePosList(self, start, isX=0):
|
| 130 |
+
"Returns a list of positions where to place lines."
|
| 131 |
+
|
| 132 |
+
w, h = self.width, self.height
|
| 133 |
+
if isX:
|
| 134 |
+
length = w
|
| 135 |
+
else:
|
| 136 |
+
length = h
|
| 137 |
+
if self.deltaSteps:
|
| 138 |
+
r = [start + self.delta0]
|
| 139 |
+
i = 0
|
| 140 |
+
while 1:
|
| 141 |
+
if r[-1] > start + length:
|
| 142 |
+
del r[-1]
|
| 143 |
+
break
|
| 144 |
+
r.append(r[-1] + self.deltaSteps[i % len(self.deltaSteps)])
|
| 145 |
+
i = i + 1
|
| 146 |
+
else:
|
| 147 |
+
r = frange(start + self.delta0, start + length, self.delta)
|
| 148 |
+
|
| 149 |
+
r.append(start + length)
|
| 150 |
+
if self.delta0 != 0:
|
| 151 |
+
r.insert(0, start)
|
| 152 |
+
#print 'Grid.makeLinePosList() -> %s' % r
|
| 153 |
+
return r
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def makeInnerLines(self):
|
| 157 |
+
# inner grid lines
|
| 158 |
+
group = Group()
|
| 159 |
+
|
| 160 |
+
w, h = self.width, self.height
|
| 161 |
+
|
| 162 |
+
if self.useLines == 1:
|
| 163 |
+
if self.orientation == 'vertical':
|
| 164 |
+
r = self.makeLinePosList(self.x, isX=1)
|
| 165 |
+
for x in r:
|
| 166 |
+
line = Line(x, self.y, x, self.y + h)
|
| 167 |
+
line.strokeColor = self.strokeColor
|
| 168 |
+
line.strokeWidth = self.strokeWidth
|
| 169 |
+
group.add(line)
|
| 170 |
+
elif self.orientation == 'horizontal':
|
| 171 |
+
r = self.makeLinePosList(self.y, isX=0)
|
| 172 |
+
for y in r:
|
| 173 |
+
line = Line(self.x, y, self.x + w, y)
|
| 174 |
+
line.strokeColor = self.strokeColor
|
| 175 |
+
line.strokeWidth = self.strokeWidth
|
| 176 |
+
group.add(line)
|
| 177 |
+
|
| 178 |
+
return group
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def makeInnerTiles(self):
|
| 182 |
+
# inner grid lines
|
| 183 |
+
group = Group()
|
| 184 |
+
|
| 185 |
+
w, h = self.width, self.height
|
| 186 |
+
|
| 187 |
+
# inner grid stripes (solid rectangles)
|
| 188 |
+
if self.useRects == 1:
|
| 189 |
+
cols = self.stripeColors
|
| 190 |
+
|
| 191 |
+
if self.orientation == 'vertical':
|
| 192 |
+
r = self.makeLinePosList(self.x, isX=1)
|
| 193 |
+
elif self.orientation == 'horizontal':
|
| 194 |
+
r = self.makeLinePosList(self.y, isX=0)
|
| 195 |
+
|
| 196 |
+
dist = makeDistancesList(r)
|
| 197 |
+
|
| 198 |
+
i = 0
|
| 199 |
+
for j in range(len(dist)):
|
| 200 |
+
if self.orientation == 'vertical':
|
| 201 |
+
x = r[j]
|
| 202 |
+
stripe = Rect(x, self.y, dist[j], h)
|
| 203 |
+
elif self.orientation == 'horizontal':
|
| 204 |
+
y = r[j]
|
| 205 |
+
stripe = Rect(self.x, y, w, dist[j])
|
| 206 |
+
stripe.fillColor = cols[i % len(cols)]
|
| 207 |
+
stripe.strokeColor = None
|
| 208 |
+
group.add(stripe)
|
| 209 |
+
i = i + 1
|
| 210 |
+
|
| 211 |
+
return group
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def draw(self):
|
| 215 |
+
# general widget bits
|
| 216 |
+
group = Group()
|
| 217 |
+
|
| 218 |
+
group.add(self.makeOuterRect())
|
| 219 |
+
group.add(self.makeInnerTiles())
|
| 220 |
+
group.add(self.makeInnerLines(),name='_gridLines')
|
| 221 |
+
|
| 222 |
+
return group
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
class DoubleGrid(Widget):
|
| 226 |
+
"""This combines two ordinary Grid objects orthogonal to each other.
|
| 227 |
+
"""
|
| 228 |
+
|
| 229 |
+
_attrMap = AttrMap(
|
| 230 |
+
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
| 231 |
+
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
| 232 |
+
width = AttrMapValue(isNumber, desc="The grid's width."),
|
| 233 |
+
height = AttrMapValue(isNumber, desc="The grid's height."),
|
| 234 |
+
grid0 = AttrMapValue(None, desc="The first grid component."),
|
| 235 |
+
grid1 = AttrMapValue(None, desc="The second grid component."),
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
def __init__(self):
|
| 239 |
+
self.x = 0
|
| 240 |
+
self.y = 0
|
| 241 |
+
self.width = 100
|
| 242 |
+
self.height = 100
|
| 243 |
+
|
| 244 |
+
g0 = Grid()
|
| 245 |
+
g0.x = self.x
|
| 246 |
+
g0.y = self.y
|
| 247 |
+
g0.width = self.width
|
| 248 |
+
g0.height = self.height
|
| 249 |
+
g0.orientation = 'vertical'
|
| 250 |
+
g0.useLines = 1
|
| 251 |
+
g0.useRects = 0
|
| 252 |
+
g0.delta = 20
|
| 253 |
+
g0.delta0 = 0
|
| 254 |
+
g0.deltaSteps = []
|
| 255 |
+
g0.fillColor = colors.white
|
| 256 |
+
g0.stripeColors = [colors.red, colors.green, colors.blue]
|
| 257 |
+
g0.strokeColor = colors.black
|
| 258 |
+
g0.strokeWidth = 1
|
| 259 |
+
|
| 260 |
+
g1 = Grid()
|
| 261 |
+
g1.x = self.x
|
| 262 |
+
g1.y = self.y
|
| 263 |
+
g1.width = self.width
|
| 264 |
+
g1.height = self.height
|
| 265 |
+
g1.orientation = 'horizontal'
|
| 266 |
+
g1.useLines = 1
|
| 267 |
+
g1.useRects = 0
|
| 268 |
+
g1.delta = 20
|
| 269 |
+
g1.delta0 = 0
|
| 270 |
+
g1.deltaSteps = []
|
| 271 |
+
g1.fillColor = colors.white
|
| 272 |
+
g1.stripeColors = [colors.red, colors.green, colors.blue]
|
| 273 |
+
g1.strokeColor = colors.black
|
| 274 |
+
g1.strokeWidth = 1
|
| 275 |
+
|
| 276 |
+
self.grid0 = g0
|
| 277 |
+
self.grid1 = g1
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
## # This gives an AttributeError:
|
| 281 |
+
## # DoubleGrid instance has no attribute 'grid0'
|
| 282 |
+
## def __setattr__(self, name, value):
|
| 283 |
+
## if name in ('x', 'y', 'width', 'height'):
|
| 284 |
+
## setattr(self.grid0, name, value)
|
| 285 |
+
## setattr(self.grid1, name, value)
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
def demo(self):
|
| 289 |
+
D = Drawing(100, 100)
|
| 290 |
+
g = DoubleGrid()
|
| 291 |
+
D.add(g)
|
| 292 |
+
return D
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
def draw(self):
|
| 296 |
+
group = Group()
|
| 297 |
+
g0, g1 = self.grid0, self.grid1
|
| 298 |
+
# Order groups to make sure both v and h lines
|
| 299 |
+
# are visible (works only when there is only
|
| 300 |
+
# one kind of stripes, v or h).
|
| 301 |
+
G = g0.useRects == 1 and g1.useRects == 0 and (g0,g1) or (g1,g0)
|
| 302 |
+
for g in G:
|
| 303 |
+
group.add(g.makeOuterRect())
|
| 304 |
+
for g in G:
|
| 305 |
+
group.add(g.makeInnerTiles())
|
| 306 |
+
group.add(g.makeInnerLines(),name='_gridLines')
|
| 307 |
+
|
| 308 |
+
return group
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
class ShadedRect(Widget):
|
| 312 |
+
"""This makes a rectangle with shaded colors between two colors.
|
| 313 |
+
|
| 314 |
+
Colors are interpolated linearly between 'fillColorStart'
|
| 315 |
+
and 'fillColorEnd', both of which appear at the margins.
|
| 316 |
+
If 'numShades' is set to one, though, only 'fillColorStart'
|
| 317 |
+
is used.
|
| 318 |
+
"""
|
| 319 |
+
|
| 320 |
+
_attrMap = AttrMap(
|
| 321 |
+
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
| 322 |
+
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
| 323 |
+
width = AttrMapValue(isNumber, desc="The grid's width."),
|
| 324 |
+
height = AttrMapValue(isNumber, desc="The grid's height."),
|
| 325 |
+
orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), desc='Determines if stripes are vertical or horizontal.'),
|
| 326 |
+
numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'),
|
| 327 |
+
fillColorStart = AttrMapValue(isColorOrNone, desc='Start value of the color shade.'),
|
| 328 |
+
fillColorEnd = AttrMapValue(isColorOrNone, desc='End value of the color shade.'),
|
| 329 |
+
strokeColor = AttrMapValue(isColorOrNone, desc='Color used for border line.'),
|
| 330 |
+
strokeWidth = AttrMapValue(isNumber, desc='Width used for lines.'),
|
| 331 |
+
cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'),
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
def __init__(self,**kw):
|
| 335 |
+
self.x = 0
|
| 336 |
+
self.y = 0
|
| 337 |
+
self.width = 100
|
| 338 |
+
self.height = 100
|
| 339 |
+
self.orientation = 'vertical'
|
| 340 |
+
self.numShades = 20
|
| 341 |
+
self.fillColorStart = colors.pink
|
| 342 |
+
self.fillColorEnd = colors.black
|
| 343 |
+
self.strokeColor = colors.black
|
| 344 |
+
self.strokeWidth = 2
|
| 345 |
+
self.cylinderMode = 0
|
| 346 |
+
self.setProperties(kw)
|
| 347 |
+
|
| 348 |
+
def demo(self):
|
| 349 |
+
D = Drawing(100, 100)
|
| 350 |
+
g = ShadedRect()
|
| 351 |
+
D.add(g)
|
| 352 |
+
|
| 353 |
+
return D
|
| 354 |
+
|
| 355 |
+
def _flipRectCorners(self):
|
| 356 |
+
"Flip rectangle's corners if width or height is negative."
|
| 357 |
+
x, y, width, height, fillColorStart, fillColorEnd = self.x, self.y, self.width, self.height, self.fillColorStart, self.fillColorEnd
|
| 358 |
+
if width < 0 and height > 0:
|
| 359 |
+
x = x + width
|
| 360 |
+
width = -width
|
| 361 |
+
if self.orientation=='vertical': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart
|
| 362 |
+
elif height<0 and width>0:
|
| 363 |
+
y = y + height
|
| 364 |
+
height = -height
|
| 365 |
+
if self.orientation=='horizontal': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart
|
| 366 |
+
elif height < 0 and height < 0:
|
| 367 |
+
x = x + width
|
| 368 |
+
width = -width
|
| 369 |
+
y = y + height
|
| 370 |
+
height = -height
|
| 371 |
+
return x, y, width, height, fillColorStart, fillColorEnd
|
| 372 |
+
|
| 373 |
+
def draw(self):
|
| 374 |
+
# general widget bits
|
| 375 |
+
group = Group()
|
| 376 |
+
x, y, w, h, c0, c1 = self._flipRectCorners()
|
| 377 |
+
vertical = self.orientation == 'vertical'
|
| 378 |
+
cylinderMode = self.cylinderMode
|
| 379 |
+
linG = getattr(getattr(self,'_canvas',None),'linearGradient',None)
|
| 380 |
+
if linG:
|
| 381 |
+
canv = linG.__self__
|
| 382 |
+
canv.saveState()
|
| 383 |
+
p = canv.beginPath()
|
| 384 |
+
p.rect(x, y, w, h)
|
| 385 |
+
canv.clipPath(p, stroke=0)
|
| 386 |
+
if cylinderMode:
|
| 387 |
+
if vertical:
|
| 388 |
+
linG(x, y, x+w/2, y, (c0,c1), extend=False)
|
| 389 |
+
linG(x+w/2, y, x+w, y, (c1,c0), extend=False)
|
| 390 |
+
else:
|
| 391 |
+
linG(x, y, x, y+h/2, (c0,c1), extend=False)
|
| 392 |
+
linG(x, y+h/2, x, y+h, (c1,c0), extend=False)
|
| 393 |
+
else:
|
| 394 |
+
if vertical:
|
| 395 |
+
linG(x, y, x+w, y, (c0,c1), extend=False)
|
| 396 |
+
else:
|
| 397 |
+
linG(x, y, x, y+h, (c0,c1), extend=False)
|
| 398 |
+
canv.restoreState()
|
| 399 |
+
else:
|
| 400 |
+
numShades = self.numShades
|
| 401 |
+
if cylinderMode:
|
| 402 |
+
if not numShades%2: numShades = numShades+1
|
| 403 |
+
halfNumShades = int((numShades-1)/2) + 1
|
| 404 |
+
num = float(numShades) # must make it float!
|
| 405 |
+
if vertical:
|
| 406 |
+
if numShades == 1:
|
| 407 |
+
V = [x]
|
| 408 |
+
else:
|
| 409 |
+
V = frange(x, x + w, w/num)
|
| 410 |
+
else:
|
| 411 |
+
if numShades == 1:
|
| 412 |
+
V = [y]
|
| 413 |
+
else:
|
| 414 |
+
V = frange(y, y + h, h/num)
|
| 415 |
+
|
| 416 |
+
for v in V:
|
| 417 |
+
stripe = vertical and Rect(v, y, w/num, h) or Rect(x, v, w, h/num)
|
| 418 |
+
if cylinderMode:
|
| 419 |
+
if V.index(v)>=halfNumShades:
|
| 420 |
+
col = colors.linearlyInterpolatedColor(c1,c0,V[halfNumShades],V[-1], v)
|
| 421 |
+
else:
|
| 422 |
+
col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[halfNumShades], v)
|
| 423 |
+
else:
|
| 424 |
+
col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[-1], v)
|
| 425 |
+
stripe.fillColor = col
|
| 426 |
+
stripe.strokeColor = col
|
| 427 |
+
stripe.strokeWidth = 1
|
| 428 |
+
group.add(stripe)
|
| 429 |
+
if self.strokeColor and self.strokeWidth>=0:
|
| 430 |
+
rect = Rect(x, y, w, h)
|
| 431 |
+
rect.strokeColor = self.strokeColor
|
| 432 |
+
rect.strokeWidth = self.strokeWidth
|
| 433 |
+
rect.fillColor = None
|
| 434 |
+
group.add(rect)
|
| 435 |
+
return group
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
def colorRange(c0, c1, n):
|
| 439 |
+
"Return a range of intermediate colors between c0 and c1"
|
| 440 |
+
if n==1: return [c0]
|
| 441 |
+
|
| 442 |
+
C = []
|
| 443 |
+
if n>1:
|
| 444 |
+
lim = n-1
|
| 445 |
+
for i in range(n):
|
| 446 |
+
C.append(colors.linearlyInterpolatedColor(c0,c1,0,lim, i))
|
| 447 |
+
return C
|
| 448 |
+
|
| 449 |
+
|
| 450 |
+
def centroid(P):
|
| 451 |
+
'''compute average point of a set of points'''
|
| 452 |
+
cx = 0
|
| 453 |
+
cy = 0
|
| 454 |
+
for x,y in P:
|
| 455 |
+
cx+=x
|
| 456 |
+
cy+=y
|
| 457 |
+
n = len(P)
|
| 458 |
+
return cx/n, cy/n
|
| 459 |
+
|
| 460 |
+
def rotatedEnclosingRect(P, angle, rect):
|
| 461 |
+
'''
|
| 462 |
+
given P a sequence P of x,y coordinate pairs and an angle in degrees
|
| 463 |
+
find the centroid of P and the axis at angle theta through it
|
| 464 |
+
find the extreme points of P wrt axis parallel distance and axis
|
| 465 |
+
orthogonal distance. Then compute the least rectangle that will still
|
| 466 |
+
enclose P when rotated by angle. Positive angles correspond to clockwise
|
| 467 |
+
rotation of the enclosing rect.
|
| 468 |
+
'''
|
| 469 |
+
x0, y0 = centroid(P)
|
| 470 |
+
theta = radians(angle)
|
| 471 |
+
#translate to the centroid and rotate
|
| 472 |
+
mx = mmult(translate(x0,y0),rotate(angle))
|
| 473 |
+
|
| 474 |
+
#compute min and max of x and y of the rotated points
|
| 475 |
+
tp = flatten(transformPoints(mx,P))
|
| 476 |
+
xx = tp[::2]
|
| 477 |
+
yx = tp[1::2]
|
| 478 |
+
xn = min(xx)
|
| 479 |
+
xx = max(xx)
|
| 480 |
+
yn = min(yx)
|
| 481 |
+
yx = max(yx)
|
| 482 |
+
|
| 483 |
+
#make the enclosing rect and invert the original transform
|
| 484 |
+
rect.x = xn
|
| 485 |
+
rect.width = xx-xn
|
| 486 |
+
rect.y = yn
|
| 487 |
+
rect.height = yx-yn
|
| 488 |
+
g = Group(transform=inverse(mx))
|
| 489 |
+
g.add(rect)
|
| 490 |
+
return g
|
| 491 |
+
|
| 492 |
+
class ShadedPolygon(Widget,LineShape):
|
| 493 |
+
'''given a list of points [(x0,y0),....] we construct an enclosing
|
| 494 |
+
shaded rectangle and mask using the polygon points.
|
| 495 |
+
At angle 0 the shading fillColorStart left --> fillColorEnd right.
|
| 496 |
+
positive angles rotate the shading clockwise.
|
| 497 |
+
'''
|
| 498 |
+
_attrMap = AttrMap(BASE=LineShape,
|
| 499 |
+
angle = AttrMapValue(isNumber,desc="Shading angle"),
|
| 500 |
+
fillColorStart = AttrMapValue(isColorOrNone),
|
| 501 |
+
fillColorEnd = AttrMapValue(isColorOrNone),
|
| 502 |
+
numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'),
|
| 503 |
+
cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'),
|
| 504 |
+
points = AttrMapValue(isListOfNumbers),
|
| 505 |
+
)
|
| 506 |
+
|
| 507 |
+
def __init__(self,**kw):
|
| 508 |
+
self.angle = 90
|
| 509 |
+
self.fillColorStart = colors.red
|
| 510 |
+
self.fillColorEnd = colors.green
|
| 511 |
+
self.cylinderMode = 0
|
| 512 |
+
self.numShades = 50
|
| 513 |
+
self.points = [-1,-1,2,2,3,-1]
|
| 514 |
+
LineShape.__init__(self,kw)
|
| 515 |
+
|
| 516 |
+
def draw(self):
|
| 517 |
+
P = self.points
|
| 518 |
+
P = list(zip(P[::2],P[1::2]))
|
| 519 |
+
path = definePath([('moveTo',)+P[0]]+[('lineTo',)+x for x in P[1:]]+['closePath'],
|
| 520 |
+
fillColor=None, strokeColor=None)
|
| 521 |
+
path.isClipPath = 1
|
| 522 |
+
g = Group()
|
| 523 |
+
g.add(path)
|
| 524 |
+
angle = self.angle % 360
|
| 525 |
+
orientation = 'horizontal' if 0<=angle<=45 or 315<=angle<=360 or 135<=angle<=225 else 'vertical'
|
| 526 |
+
rect = ShadedRect(strokeWidth=0,strokeColor=None,orientation=orientation)
|
| 527 |
+
for k in 'fillColorStart', 'fillColorEnd', 'numShades', 'cylinderMode':
|
| 528 |
+
setattr(rect,k,getattr(self,k))
|
| 529 |
+
g.add(rotatedEnclosingRect(P, angle, rect))
|
| 530 |
+
g.add(EmptyClipPath)
|
| 531 |
+
path = path.copy()
|
| 532 |
+
path.isClipPath = 0
|
| 533 |
+
path.strokeColor = self.strokeColor
|
| 534 |
+
path.strokeWidth = self.strokeWidth
|
| 535 |
+
g.add(path)
|
| 536 |
+
return g
|
| 537 |
+
|
| 538 |
+
if __name__=='__main__': #noruntests
|
| 539 |
+
angle=45
|
| 540 |
+
D = Drawing(120,120)
|
| 541 |
+
D.add(ShadedPolygon(points=(10,10,60,60,110,10),strokeColor=None,strokeWidth=1,angle=90,numShades=50,cylinderMode=0))
|
| 542 |
+
D.save(formats=['pdf','gif'],fnRoot='shobj',outDir='/tmp')
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/signsandsymbols.py
ADDED
|
@@ -0,0 +1,977 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#Copyright ReportLab Europe Ltd. 2000-2017
|
| 2 |
+
#see license.txt for license details
|
| 3 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/signsandsymbols.py
|
| 4 |
+
# signsandsymbols.py
|
| 5 |
+
# A collection of new widgets
|
| 6 |
+
# author: John Precedo (johnp@reportlab.com)
|
| 7 |
+
|
| 8 |
+
__version__='3.3.0'
|
| 9 |
+
__doc__="""This file is a collection of widgets to produce some common signs and symbols.
|
| 10 |
+
|
| 11 |
+
Widgets include:
|
| 12 |
+
|
| 13 |
+
- ETriangle (an equilateral triangle),
|
| 14 |
+
- RTriangle (a right angled triangle),
|
| 15 |
+
- Octagon,
|
| 16 |
+
- Crossbox,
|
| 17 |
+
- Tickbox,
|
| 18 |
+
- SmileyFace,
|
| 19 |
+
- StopSign,
|
| 20 |
+
- NoEntry,
|
| 21 |
+
- NotAllowed (the red roundel from 'no smoking' signs),
|
| 22 |
+
- NoSmoking,
|
| 23 |
+
- DangerSign (a black exclamation point in a yellow triangle),
|
| 24 |
+
- YesNo (returns a tickbox or a crossbox depending on a testvalue),
|
| 25 |
+
- FloppyDisk,
|
| 26 |
+
- ArrowOne, and
|
| 27 |
+
- ArrowTwo
|
| 28 |
+
- CrossHair
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
from reportlab.lib import colors
|
| 32 |
+
from reportlab.lib.validators import *
|
| 33 |
+
from reportlab.lib.attrmap import *
|
| 34 |
+
from reportlab.lib.utils import isStr, asUnicode
|
| 35 |
+
from reportlab.graphics import shapes
|
| 36 |
+
from reportlab.graphics.widgetbase import Widget
|
| 37 |
+
from reportlab.graphics import renderPDF
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class _Symbol(Widget):
|
| 41 |
+
"""Abstract base widget
|
| 42 |
+
possible attributes:
|
| 43 |
+
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
| 44 |
+
"""
|
| 45 |
+
_nodoc = 1
|
| 46 |
+
_attrMap = AttrMap(
|
| 47 |
+
x = AttrMapValue(isNumber,desc='symbol x coordinate'),
|
| 48 |
+
y = AttrMapValue(isNumber,desc='symbol y coordinate'),
|
| 49 |
+
dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
| 50 |
+
dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
| 51 |
+
size = AttrMapValue(isNumber),
|
| 52 |
+
fillColor = AttrMapValue(isColorOrNone),
|
| 53 |
+
strokeColor = AttrMapValue(isColorOrNone),
|
| 54 |
+
strokeWidth = AttrMapValue(isNumber),
|
| 55 |
+
)
|
| 56 |
+
def __init__(self):
|
| 57 |
+
assert self.__class__.__name__!='_Symbol', 'Abstract class _Symbol instantiated'
|
| 58 |
+
self.x = self.y = self.dx = self.dy = 0
|
| 59 |
+
self.size = 100
|
| 60 |
+
self.fillColor = colors.red
|
| 61 |
+
self.strokeColor = None
|
| 62 |
+
self.strokeWidth = 0.1
|
| 63 |
+
|
| 64 |
+
def demo(self):
|
| 65 |
+
D = shapes.Drawing(200, 100)
|
| 66 |
+
s = float(self.size)
|
| 67 |
+
ob = self.__class__()
|
| 68 |
+
ob.x=50
|
| 69 |
+
ob.y=0
|
| 70 |
+
ob.draw()
|
| 71 |
+
D.add(ob)
|
| 72 |
+
D.add(shapes.String(ob.x+(s/2),(ob.y-12),
|
| 73 |
+
ob.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 74 |
+
fontSize=10))
|
| 75 |
+
return D
|
| 76 |
+
|
| 77 |
+
class ETriangle(_Symbol):
|
| 78 |
+
"""This draws an equilateral triangle."""
|
| 79 |
+
|
| 80 |
+
def __init__(self):
|
| 81 |
+
_Symbol.__init__(self)
|
| 82 |
+
|
| 83 |
+
def draw(self):
|
| 84 |
+
# general widget bits
|
| 85 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 86 |
+
g = shapes.Group()
|
| 87 |
+
|
| 88 |
+
# Triangle specific bits
|
| 89 |
+
ae = s*0.125 #(ae = 'an eighth')
|
| 90 |
+
triangle = shapes.Polygon(points = [
|
| 91 |
+
self.x, self.y,
|
| 92 |
+
self.x+s, self.y,
|
| 93 |
+
self.x+(s/2),self.y+s],
|
| 94 |
+
fillColor = self.fillColor,
|
| 95 |
+
strokeColor = self.strokeColor,
|
| 96 |
+
strokeWidth=s/50.)
|
| 97 |
+
g.add(triangle)
|
| 98 |
+
return g
|
| 99 |
+
|
| 100 |
+
class RTriangle(_Symbol):
|
| 101 |
+
"""This draws a right-angled triangle.
|
| 102 |
+
|
| 103 |
+
possible attributes:
|
| 104 |
+
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
| 105 |
+
|
| 106 |
+
"""
|
| 107 |
+
|
| 108 |
+
def __init__(self):
|
| 109 |
+
self.x = 0
|
| 110 |
+
self.y = 0
|
| 111 |
+
self.size = 100
|
| 112 |
+
self.fillColor = colors.green
|
| 113 |
+
self.strokeColor = None
|
| 114 |
+
|
| 115 |
+
def draw(self):
|
| 116 |
+
# general widget bits
|
| 117 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 118 |
+
g = shapes.Group()
|
| 119 |
+
|
| 120 |
+
# Triangle specific bits
|
| 121 |
+
ae = s*0.125 #(ae = 'an eighth')
|
| 122 |
+
triangle = shapes.Polygon(points = [
|
| 123 |
+
self.x, self.y,
|
| 124 |
+
self.x+s, self.y,
|
| 125 |
+
self.x,self.y+s],
|
| 126 |
+
fillColor = self.fillColor,
|
| 127 |
+
strokeColor = self.strokeColor,
|
| 128 |
+
strokeWidth=s/50.)
|
| 129 |
+
g.add(triangle)
|
| 130 |
+
return g
|
| 131 |
+
|
| 132 |
+
class Octagon(_Symbol):
|
| 133 |
+
"""This widget draws an Octagon.
|
| 134 |
+
|
| 135 |
+
possible attributes:
|
| 136 |
+
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
| 137 |
+
|
| 138 |
+
"""
|
| 139 |
+
|
| 140 |
+
def __init__(self):
|
| 141 |
+
self.x = 0
|
| 142 |
+
self.y = 0
|
| 143 |
+
self.size = 100
|
| 144 |
+
self.fillColor = colors.yellow
|
| 145 |
+
self.strokeColor = None
|
| 146 |
+
|
| 147 |
+
def draw(self):
|
| 148 |
+
# general widget bits
|
| 149 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 150 |
+
g = shapes.Group()
|
| 151 |
+
|
| 152 |
+
# Octagon specific bits
|
| 153 |
+
athird=s/3
|
| 154 |
+
|
| 155 |
+
octagon = shapes.Polygon(points=[self.x+athird, self.y,
|
| 156 |
+
self.x, self.y+athird,
|
| 157 |
+
self.x, self.y+(athird*2),
|
| 158 |
+
self.x+athird, self.y+s,
|
| 159 |
+
self.x+(athird*2), self.y+s,
|
| 160 |
+
self.x+s, self.y+(athird*2),
|
| 161 |
+
self.x+s, self.y+athird,
|
| 162 |
+
self.x+(athird*2), self.y],
|
| 163 |
+
strokeColor = self.strokeColor,
|
| 164 |
+
fillColor = self.fillColor,
|
| 165 |
+
strokeWidth=10)
|
| 166 |
+
g.add(octagon)
|
| 167 |
+
return g
|
| 168 |
+
|
| 169 |
+
class Crossbox(_Symbol):
|
| 170 |
+
"""This draws a black box with a red cross in it - a 'checkbox'.
|
| 171 |
+
|
| 172 |
+
possible attributes:
|
| 173 |
+
'x', 'y', 'size', 'crossColor', 'strokeColor', 'crosswidth'
|
| 174 |
+
|
| 175 |
+
"""
|
| 176 |
+
|
| 177 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 178 |
+
crossColor = AttrMapValue(isColorOrNone),
|
| 179 |
+
crosswidth = AttrMapValue(isNumber),
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
def __init__(self):
|
| 183 |
+
self.x = 0
|
| 184 |
+
self.y = 0
|
| 185 |
+
self.size = 100
|
| 186 |
+
self.fillColor = colors.white
|
| 187 |
+
self.crossColor = colors.red
|
| 188 |
+
self.strokeColor = colors.black
|
| 189 |
+
self.crosswidth = 10
|
| 190 |
+
|
| 191 |
+
def draw(self):
|
| 192 |
+
# general widget bits
|
| 193 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 194 |
+
g = shapes.Group()
|
| 195 |
+
|
| 196 |
+
# crossbox specific bits
|
| 197 |
+
box = shapes.Rect(self.x+1, self.y+1, s-2, s-2,
|
| 198 |
+
fillColor = self.fillColor,
|
| 199 |
+
strokeColor = self.strokeColor,
|
| 200 |
+
strokeWidth=2)
|
| 201 |
+
g.add(box)
|
| 202 |
+
|
| 203 |
+
crossLine1 = shapes.Line(self.x+(s*0.15), self.y+(s*0.15), self.x+(s*0.85), self.y+(s*0.85),
|
| 204 |
+
fillColor = self.crossColor,
|
| 205 |
+
strokeColor = self.crossColor,
|
| 206 |
+
strokeWidth = self.crosswidth)
|
| 207 |
+
g.add(crossLine1)
|
| 208 |
+
|
| 209 |
+
crossLine2 = shapes.Line(self.x+(s*0.15), self.y+(s*0.85), self.x+(s*0.85) ,self.y+(s*0.15),
|
| 210 |
+
fillColor = self.crossColor,
|
| 211 |
+
strokeColor = self.crossColor,
|
| 212 |
+
strokeWidth = self.crosswidth)
|
| 213 |
+
g.add(crossLine2)
|
| 214 |
+
|
| 215 |
+
return g
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
class Tickbox(_Symbol):
|
| 219 |
+
"""This draws a black box with a red tick in it - another 'checkbox'.
|
| 220 |
+
|
| 221 |
+
possible attributes:
|
| 222 |
+
'x', 'y', 'size', 'tickColor', 'strokeColor', 'tickwidth'
|
| 223 |
+
|
| 224 |
+
"""
|
| 225 |
+
|
| 226 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 227 |
+
tickColor = AttrMapValue(isColorOrNone),
|
| 228 |
+
tickwidth = AttrMapValue(isNumber),
|
| 229 |
+
)
|
| 230 |
+
|
| 231 |
+
def __init__(self):
|
| 232 |
+
self.x = 0
|
| 233 |
+
self.y = 0
|
| 234 |
+
self.size = 100
|
| 235 |
+
self.tickColor = colors.red
|
| 236 |
+
self.strokeColor = colors.black
|
| 237 |
+
self.fillColor = colors.white
|
| 238 |
+
self.tickwidth = 10
|
| 239 |
+
|
| 240 |
+
def draw(self):
|
| 241 |
+
# general widget bits
|
| 242 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 243 |
+
g = shapes.Group()
|
| 244 |
+
|
| 245 |
+
# tickbox specific bits
|
| 246 |
+
box = shapes.Rect(self.x+1, self.y+1, s-2, s-2,
|
| 247 |
+
fillColor = self.fillColor,
|
| 248 |
+
strokeColor = self.strokeColor,
|
| 249 |
+
strokeWidth=2)
|
| 250 |
+
g.add(box)
|
| 251 |
+
|
| 252 |
+
tickLine = shapes.PolyLine(points = [self.x+(s*0.15), self.y+(s*0.35), self.x+(s*0.35), self.y+(s*0.15),
|
| 253 |
+
self.x+(s*0.35), self.y+(s*0.15), self.x+(s*0.85) ,self.y+(s*0.85)],
|
| 254 |
+
fillColor = self.tickColor,
|
| 255 |
+
strokeColor = self.tickColor,
|
| 256 |
+
strokeWidth = self.tickwidth)
|
| 257 |
+
g.add(tickLine)
|
| 258 |
+
|
| 259 |
+
return g
|
| 260 |
+
|
| 261 |
+
class SmileyFace(_Symbol):
|
| 262 |
+
"""This draws a classic smiley face.
|
| 263 |
+
|
| 264 |
+
possible attributes:
|
| 265 |
+
'x', 'y', 'size', 'fillColor'
|
| 266 |
+
|
| 267 |
+
"""
|
| 268 |
+
|
| 269 |
+
def __init__(self):
|
| 270 |
+
_Symbol.__init__(self)
|
| 271 |
+
self.x = 0
|
| 272 |
+
self.y = 0
|
| 273 |
+
self.size = 100
|
| 274 |
+
self.fillColor = colors.yellow
|
| 275 |
+
self.strokeColor = colors.black
|
| 276 |
+
|
| 277 |
+
def draw(self):
|
| 278 |
+
# general widget bits
|
| 279 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 280 |
+
g = shapes.Group()
|
| 281 |
+
|
| 282 |
+
# SmileyFace specific bits
|
| 283 |
+
g.add(shapes.Circle(cx=self.x+(s/2), cy=self.y+(s/2), r=s/2,
|
| 284 |
+
fillColor=self.fillColor, strokeColor=self.strokeColor,
|
| 285 |
+
strokeWidth=max(s/38.,self.strokeWidth)))
|
| 286 |
+
|
| 287 |
+
for i in (1,2):
|
| 288 |
+
g.add(shapes.Ellipse(self.x+(s/3)*i,self.y+(s/3)*2, s/30, s/10,
|
| 289 |
+
fillColor=self.strokeColor, strokeColor = self.strokeColor,
|
| 290 |
+
strokeWidth=max(s/38.,self.strokeWidth)))
|
| 291 |
+
|
| 292 |
+
# calculate a pointslist for the mouth
|
| 293 |
+
# THIS IS A HACK! - don't use if there is a 'shapes.Arc'
|
| 294 |
+
centerx=self.x+(s/2)
|
| 295 |
+
centery=self.y+(s/2)
|
| 296 |
+
radius=s/3
|
| 297 |
+
yradius = radius
|
| 298 |
+
xradius = radius
|
| 299 |
+
startangledegrees=200
|
| 300 |
+
endangledegrees=340
|
| 301 |
+
degreedelta = 1
|
| 302 |
+
pointslist = []
|
| 303 |
+
a = pointslist.append
|
| 304 |
+
from math import sin, cos, pi
|
| 305 |
+
degreestoradians = pi/180.0
|
| 306 |
+
radiansdelta = degreedelta*degreestoradians
|
| 307 |
+
startangle = startangledegrees*degreestoradians
|
| 308 |
+
endangle = endangledegrees*degreestoradians
|
| 309 |
+
while endangle<startangle:
|
| 310 |
+
endangle = endangle+2*pi
|
| 311 |
+
angle = startangle
|
| 312 |
+
while angle<endangle:
|
| 313 |
+
x = centerx + cos(angle)*radius
|
| 314 |
+
y = centery + sin(angle)*yradius
|
| 315 |
+
a(x); a(y)
|
| 316 |
+
angle = angle+radiansdelta
|
| 317 |
+
|
| 318 |
+
# make the mouth
|
| 319 |
+
smile = shapes.PolyLine(pointslist,
|
| 320 |
+
fillColor = self.strokeColor,
|
| 321 |
+
strokeColor = self.strokeColor,
|
| 322 |
+
strokeWidth = max(s/38.,self.strokeWidth))
|
| 323 |
+
g.add(smile)
|
| 324 |
+
|
| 325 |
+
return g
|
| 326 |
+
|
| 327 |
+
class StopSign(_Symbol):
|
| 328 |
+
"""This draws a (British) stop sign.
|
| 329 |
+
|
| 330 |
+
possible attributes:
|
| 331 |
+
'x', 'y', 'size'
|
| 332 |
+
|
| 333 |
+
"""
|
| 334 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 335 |
+
stopColor = AttrMapValue(isColorOrNone,desc='color of the word stop'),
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
def __init__(self):
|
| 339 |
+
self.x = 0
|
| 340 |
+
self.y = 0
|
| 341 |
+
self.size = 100
|
| 342 |
+
self.strokeColor = colors.black
|
| 343 |
+
self.fillColor = colors.orangered
|
| 344 |
+
self.stopColor = colors.ghostwhite
|
| 345 |
+
|
| 346 |
+
def draw(self):
|
| 347 |
+
# general widget bits
|
| 348 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 349 |
+
g = shapes.Group()
|
| 350 |
+
|
| 351 |
+
# stop-sign specific bits
|
| 352 |
+
athird=s/3
|
| 353 |
+
|
| 354 |
+
outerOctagon = shapes.Polygon(points=[self.x+athird, self.y,
|
| 355 |
+
self.x, self.y+athird,
|
| 356 |
+
self.x, self.y+(athird*2),
|
| 357 |
+
self.x+athird, self.y+s,
|
| 358 |
+
self.x+(athird*2), self.y+s,
|
| 359 |
+
self.x+s, self.y+(athird*2),
|
| 360 |
+
self.x+s, self.y+athird,
|
| 361 |
+
self.x+(athird*2), self.y],
|
| 362 |
+
strokeColor = self.strokeColor,
|
| 363 |
+
fillColor = None,
|
| 364 |
+
strokeWidth=1)
|
| 365 |
+
g.add(outerOctagon)
|
| 366 |
+
|
| 367 |
+
innerOctagon = shapes.Polygon(points=[self.x+athird+(s/75), self.y+(s/75),
|
| 368 |
+
self.x+(s/75), self.y+athird+(s/75),
|
| 369 |
+
self.x+(s/75), self.y+(athird*2)-(s/75),
|
| 370 |
+
self.x+athird+(s/75), self.y+s-(s/75),
|
| 371 |
+
self.x+(athird*2)-(s/75), (self.y+s)-(s/75),
|
| 372 |
+
(self.x+s)-(s/75), self.y+(athird*2)-(s/75),
|
| 373 |
+
(self.x+s)-(s/75), self.y+athird+(s/75),
|
| 374 |
+
self.x+(athird*2)-(s/75), self.y+(s/75)],
|
| 375 |
+
strokeColor = None,
|
| 376 |
+
fillColor = self.fillColor,
|
| 377 |
+
strokeWidth=0)
|
| 378 |
+
g.add(innerOctagon)
|
| 379 |
+
|
| 380 |
+
if self.stopColor:
|
| 381 |
+
g.add(shapes.String(self.x+(s*0.5),self.y+(s*0.4),
|
| 382 |
+
'STOP', fillColor=self.stopColor, textAnchor='middle',
|
| 383 |
+
fontSize=s/3, fontName="Helvetica-Bold"))
|
| 384 |
+
|
| 385 |
+
return g
|
| 386 |
+
|
| 387 |
+
|
| 388 |
+
class NoEntry(_Symbol):
|
| 389 |
+
"""This draws a (British) No Entry sign - a red circle with a white line on it.
|
| 390 |
+
|
| 391 |
+
possible attributes:
|
| 392 |
+
'x', 'y', 'size'
|
| 393 |
+
|
| 394 |
+
"""
|
| 395 |
+
|
| 396 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 397 |
+
innerBarColor = AttrMapValue(isColorOrNone,desc='color of the inner bar'),
|
| 398 |
+
)
|
| 399 |
+
|
| 400 |
+
def __init__(self):
|
| 401 |
+
self.x = 0
|
| 402 |
+
self.y = 0
|
| 403 |
+
self.size = 100
|
| 404 |
+
self.strokeColor = colors.black
|
| 405 |
+
self.fillColor = colors.orangered
|
| 406 |
+
self.innerBarColor = colors.ghostwhite
|
| 407 |
+
|
| 408 |
+
def draw(self):
|
| 409 |
+
# general widget bits
|
| 410 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 411 |
+
g = shapes.Group()
|
| 412 |
+
|
| 413 |
+
# no-entry-sign specific bits
|
| 414 |
+
if self.strokeColor:
|
| 415 |
+
g.add(shapes.Circle(cx = (self.x+(s/2)), cy = (self.y+(s/2)), r = s/2, fillColor = None, strokeColor = self.strokeColor, strokeWidth=1))
|
| 416 |
+
|
| 417 |
+
if self.fillColor:
|
| 418 |
+
g.add(shapes.Circle(cx = (self.x+(s/2)), cy =(self.y+(s/2)), r = ((s/2)-(s/50)), fillColor = self.fillColor, strokeColor = None, strokeWidth=0))
|
| 419 |
+
|
| 420 |
+
innerBarColor = self.innerBarColor
|
| 421 |
+
if innerBarColor:
|
| 422 |
+
g.add(shapes.Rect(self.x+(s*0.1), self.y+(s*0.4), width=s*0.8, height=s*0.2, fillColor = innerBarColor, strokeColor = innerBarColor, strokeLineCap = 1, strokeWidth = 0))
|
| 423 |
+
return g
|
| 424 |
+
|
| 425 |
+
class NotAllowed(_Symbol):
|
| 426 |
+
"""This draws a 'forbidden' roundel (as used in the no-smoking sign).
|
| 427 |
+
|
| 428 |
+
possible attributes:
|
| 429 |
+
'x', 'y', 'size'
|
| 430 |
+
|
| 431 |
+
"""
|
| 432 |
+
|
| 433 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 434 |
+
)
|
| 435 |
+
|
| 436 |
+
def __init__(self):
|
| 437 |
+
self.x = 0
|
| 438 |
+
self.y = 0
|
| 439 |
+
self.size = 100
|
| 440 |
+
self.strokeColor = colors.red
|
| 441 |
+
self.fillColor = colors.white
|
| 442 |
+
|
| 443 |
+
def draw(self):
|
| 444 |
+
# general widget bits
|
| 445 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 446 |
+
g = shapes.Group()
|
| 447 |
+
strokeColor = self.strokeColor
|
| 448 |
+
|
| 449 |
+
# not=allowed specific bits
|
| 450 |
+
outerCircle = shapes.Circle(cx = (self.x+(s/2)), cy = (self.y+(s/2)), r = (s/2)-(s/10), fillColor = self.fillColor, strokeColor = strokeColor, strokeWidth=s/10.)
|
| 451 |
+
g.add(outerCircle)
|
| 452 |
+
|
| 453 |
+
centerx=self.x+s
|
| 454 |
+
centery=self.y+(s/2)-(s/6)
|
| 455 |
+
radius=s-(s/6)
|
| 456 |
+
yradius = radius/2
|
| 457 |
+
xradius = radius/2
|
| 458 |
+
startangledegrees=100
|
| 459 |
+
endangledegrees=-80
|
| 460 |
+
degreedelta = 90
|
| 461 |
+
pointslist = []
|
| 462 |
+
a = pointslist.append
|
| 463 |
+
from math import sin, cos, pi
|
| 464 |
+
degreestoradians = pi/180.0
|
| 465 |
+
radiansdelta = degreedelta*degreestoradians
|
| 466 |
+
startangle = startangledegrees*degreestoradians
|
| 467 |
+
endangle = endangledegrees*degreestoradians
|
| 468 |
+
while endangle<startangle:
|
| 469 |
+
endangle = endangle+2*pi
|
| 470 |
+
angle = startangle
|
| 471 |
+
while angle<endangle:
|
| 472 |
+
x = centerx + cos(angle)*radius
|
| 473 |
+
y = centery + sin(angle)*yradius
|
| 474 |
+
a(x); a(y)
|
| 475 |
+
angle = angle+radiansdelta
|
| 476 |
+
crossbar = shapes.PolyLine(pointslist, fillColor = strokeColor, strokeColor = strokeColor, strokeWidth = s/10.)
|
| 477 |
+
g.add(crossbar)
|
| 478 |
+
return g
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
class NoSmoking(NotAllowed):
|
| 482 |
+
"""This draws a no-smoking sign.
|
| 483 |
+
|
| 484 |
+
possible attributes:
|
| 485 |
+
'x', 'y', 'size'
|
| 486 |
+
|
| 487 |
+
"""
|
| 488 |
+
|
| 489 |
+
def __init__(self):
|
| 490 |
+
NotAllowed.__init__(self)
|
| 491 |
+
|
| 492 |
+
def draw(self):
|
| 493 |
+
# general widget bits
|
| 494 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 495 |
+
g = NotAllowed.draw(self)
|
| 496 |
+
|
| 497 |
+
# no-smoking-sign specific bits
|
| 498 |
+
newx = self.x+(s/2)-(s/3.5)
|
| 499 |
+
newy = self.y+(s/2)-(s/32)
|
| 500 |
+
cigarrette1 = shapes.Rect(x = newx, y = newy, width = (s/2), height =(s/16),
|
| 501 |
+
fillColor = colors.ghostwhite, strokeColor = colors.gray, strokeWidth=0)
|
| 502 |
+
newx=newx+(s/2)+(s/64)
|
| 503 |
+
g.insert(-1,cigarrette1)
|
| 504 |
+
|
| 505 |
+
cigarrette2 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
| 506 |
+
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
| 507 |
+
newx= newx+(s/35)
|
| 508 |
+
g.insert(-1,cigarrette2)
|
| 509 |
+
|
| 510 |
+
cigarrette3 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
| 511 |
+
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
| 512 |
+
newx= newx+(s/35)
|
| 513 |
+
g.insert(-1,cigarrette3)
|
| 514 |
+
|
| 515 |
+
cigarrette4 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
| 516 |
+
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
| 517 |
+
newx= newx+(s/35)
|
| 518 |
+
g.insert(-1,cigarrette4)
|
| 519 |
+
|
| 520 |
+
return g
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
class DangerSign(_Symbol):
|
| 524 |
+
"""This draws a 'danger' sign: a yellow box with a black exclamation point.
|
| 525 |
+
|
| 526 |
+
possible attributes:
|
| 527 |
+
'x', 'y', 'size', 'strokeColor', 'fillColor', 'strokeWidth'
|
| 528 |
+
|
| 529 |
+
"""
|
| 530 |
+
|
| 531 |
+
def __init__(self):
|
| 532 |
+
self.x = 0
|
| 533 |
+
self.y = 0
|
| 534 |
+
self.size = 100
|
| 535 |
+
self.strokeColor = colors.black
|
| 536 |
+
self.fillColor = colors.gold
|
| 537 |
+
self.strokeWidth = self.size*0.125
|
| 538 |
+
|
| 539 |
+
def draw(self):
|
| 540 |
+
# general widget bits
|
| 541 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 542 |
+
g = shapes.Group()
|
| 543 |
+
ew = self.strokeWidth
|
| 544 |
+
ae = s*0.125 #(ae = 'an eighth')
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
# danger sign specific bits
|
| 548 |
+
|
| 549 |
+
ew = self.strokeWidth
|
| 550 |
+
ae = s*0.125 #(ae = 'an eighth')
|
| 551 |
+
|
| 552 |
+
outerTriangle = shapes.Polygon(points = [
|
| 553 |
+
self.x, self.y,
|
| 554 |
+
self.x+s, self.y,
|
| 555 |
+
self.x+(s/2),self.y+s],
|
| 556 |
+
fillColor = None,
|
| 557 |
+
strokeColor = self.strokeColor,
|
| 558 |
+
strokeWidth=0)
|
| 559 |
+
g.add(outerTriangle)
|
| 560 |
+
|
| 561 |
+
innerTriangle = shapes.Polygon(points = [
|
| 562 |
+
self.x+(s/50), self.y+(s/75),
|
| 563 |
+
(self.x+s)-(s/50), self.y+(s/75),
|
| 564 |
+
self.x+(s/2),(self.y+s)-(s/50)],
|
| 565 |
+
fillColor = self.fillColor,
|
| 566 |
+
strokeColor = None,
|
| 567 |
+
strokeWidth=0)
|
| 568 |
+
g.add(innerTriangle)
|
| 569 |
+
|
| 570 |
+
exmark = shapes.Polygon(points=[
|
| 571 |
+
((self.x+s/2)-ew/2), self.y+ae*2.5,
|
| 572 |
+
((self.x+s/2)+ew/2), self.y+ae*2.5,
|
| 573 |
+
((self.x+s/2)+((ew/2))+(ew/6)), self.y+ae*5.5,
|
| 574 |
+
((self.x+s/2)-((ew/2))-(ew/6)), self.y+ae*5.5],
|
| 575 |
+
fillColor = self.strokeColor,
|
| 576 |
+
strokeColor = None)
|
| 577 |
+
g.add(exmark)
|
| 578 |
+
|
| 579 |
+
exdot = shapes.Polygon(points=[
|
| 580 |
+
((self.x+s/2)-ew/2), self.y+ae,
|
| 581 |
+
((self.x+s/2)+ew/2), self.y+ae,
|
| 582 |
+
((self.x+s/2)+ew/2), self.y+ae*2,
|
| 583 |
+
((self.x+s/2)-ew/2), self.y+ae*2],
|
| 584 |
+
fillColor = self.strokeColor,
|
| 585 |
+
strokeColor = None)
|
| 586 |
+
g.add(exdot)
|
| 587 |
+
|
| 588 |
+
return g
|
| 589 |
+
|
| 590 |
+
|
| 591 |
+
class YesNo(_Symbol):
|
| 592 |
+
"""This widget draw a tickbox or crossbox depending on 'testValue'.
|
| 593 |
+
|
| 594 |
+
If this widget is supplied with a 'True' or 1 as a value for
|
| 595 |
+
testValue, it will use the tickbox widget. Otherwise, it will
|
| 596 |
+
produce a crossbox.
|
| 597 |
+
|
| 598 |
+
possible attributes:
|
| 599 |
+
'x', 'y', 'size', 'tickcolor', 'crosscolor', 'testValue'
|
| 600 |
+
|
| 601 |
+
"""
|
| 602 |
+
|
| 603 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 604 |
+
tickcolor = AttrMapValue(isColor),
|
| 605 |
+
crosscolor = AttrMapValue(isColor),
|
| 606 |
+
testValue = AttrMapValue(isBoolean),
|
| 607 |
+
)
|
| 608 |
+
|
| 609 |
+
def __init__(self):
|
| 610 |
+
self.x = 0
|
| 611 |
+
self.y = 0
|
| 612 |
+
self.size = 100
|
| 613 |
+
self.tickcolor = colors.green
|
| 614 |
+
self.crosscolor = colors.red
|
| 615 |
+
self.testValue = 1
|
| 616 |
+
|
| 617 |
+
def draw(self):
|
| 618 |
+
if self.testValue:
|
| 619 |
+
yn=Tickbox()
|
| 620 |
+
yn.tickColor=self.tickcolor
|
| 621 |
+
else:
|
| 622 |
+
yn=Crossbox()
|
| 623 |
+
yn.crossColor=self.crosscolor
|
| 624 |
+
yn.x=self.x
|
| 625 |
+
yn.y=self.y
|
| 626 |
+
yn.size=self.size
|
| 627 |
+
yn.draw()
|
| 628 |
+
return yn
|
| 629 |
+
|
| 630 |
+
|
| 631 |
+
def demo(self):
|
| 632 |
+
D = shapes.Drawing(200, 100)
|
| 633 |
+
yn = YesNo()
|
| 634 |
+
yn.x = 15
|
| 635 |
+
yn.y = 25
|
| 636 |
+
yn.size = 70
|
| 637 |
+
yn.testValue = 0
|
| 638 |
+
yn.draw()
|
| 639 |
+
D.add(yn)
|
| 640 |
+
yn2 = YesNo()
|
| 641 |
+
yn2.x = 120
|
| 642 |
+
yn2.y = 25
|
| 643 |
+
yn2.size = 70
|
| 644 |
+
yn2.testValue = 1
|
| 645 |
+
yn2.draw()
|
| 646 |
+
D.add(yn2)
|
| 647 |
+
labelFontSize = 8
|
| 648 |
+
D.add(shapes.String(yn.x+(yn.size/2),(yn.y-(1.2*labelFontSize)),
|
| 649 |
+
'testValue=0', fillColor=colors.black, textAnchor='middle',
|
| 650 |
+
fontSize=labelFontSize))
|
| 651 |
+
D.add(shapes.String(yn2.x+(yn2.size/2),(yn2.y-(1.2*labelFontSize)),
|
| 652 |
+
'testValue=1', fillColor=colors.black, textAnchor='middle',
|
| 653 |
+
fontSize=labelFontSize))
|
| 654 |
+
labelFontSize = 10
|
| 655 |
+
D.add(shapes.String(yn.x+85,(yn.y-20),
|
| 656 |
+
self.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 657 |
+
fontSize=labelFontSize))
|
| 658 |
+
return D
|
| 659 |
+
|
| 660 |
+
class FloppyDisk(_Symbol):
|
| 661 |
+
"""This widget draws an icon of a floppy disk.
|
| 662 |
+
|
| 663 |
+
possible attributes:
|
| 664 |
+
'x', 'y', 'size', 'diskcolor'
|
| 665 |
+
|
| 666 |
+
"""
|
| 667 |
+
|
| 668 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 669 |
+
diskColor = AttrMapValue(isColor),
|
| 670 |
+
)
|
| 671 |
+
|
| 672 |
+
def __init__(self):
|
| 673 |
+
self.x = 0
|
| 674 |
+
self.y = 0
|
| 675 |
+
self.size = 100
|
| 676 |
+
self.diskColor = colors.black
|
| 677 |
+
|
| 678 |
+
def draw(self):
|
| 679 |
+
# general widget bits
|
| 680 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 681 |
+
g = shapes.Group()
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
# floppy disk specific bits
|
| 685 |
+
diskBody = shapes.Rect(x=self.x, y=self.y+(s/100), width=s, height=s-(s/100),
|
| 686 |
+
fillColor = self.diskColor,
|
| 687 |
+
strokeColor = None,
|
| 688 |
+
strokeWidth=0)
|
| 689 |
+
g.add(diskBody)
|
| 690 |
+
|
| 691 |
+
label = shapes.Rect(x=self.x+(s*0.1), y=(self.y+s)-(s*0.5), width=s*0.8, height=s*0.48,
|
| 692 |
+
fillColor = colors.whitesmoke,
|
| 693 |
+
strokeColor = None,
|
| 694 |
+
strokeWidth=0)
|
| 695 |
+
g.add(label)
|
| 696 |
+
|
| 697 |
+
labelsplash = shapes.Rect(x=self.x+(s*0.1), y=(self.y+s)-(s*0.1), width=s*0.8, height=s*0.08,
|
| 698 |
+
fillColor = colors.royalblue,
|
| 699 |
+
strokeColor = None,
|
| 700 |
+
strokeWidth=0)
|
| 701 |
+
g.add(labelsplash)
|
| 702 |
+
|
| 703 |
+
|
| 704 |
+
line1 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.6*s), x2=self.x+(s*0.85), y2=self.y+(0.6*s),
|
| 705 |
+
fillColor = colors.black,
|
| 706 |
+
strokeColor = colors.black,
|
| 707 |
+
strokeWidth=0)
|
| 708 |
+
g.add(line1)
|
| 709 |
+
|
| 710 |
+
line2 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.7*s), x2=self.x+(s*0.85), y2=self.y+(0.7*s),
|
| 711 |
+
fillColor = colors.black,
|
| 712 |
+
strokeColor = colors.black,
|
| 713 |
+
strokeWidth=0)
|
| 714 |
+
g.add(line2)
|
| 715 |
+
|
| 716 |
+
line3 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.8*s), x2=self.x+(s*0.85), y2=self.y+(0.8*s),
|
| 717 |
+
fillColor = colors.black,
|
| 718 |
+
strokeColor = colors.black,
|
| 719 |
+
strokeWidth=0)
|
| 720 |
+
g.add(line3)
|
| 721 |
+
|
| 722 |
+
metalcover = shapes.Rect(x=self.x+(s*0.2), y=(self.y), width=s*0.5, height=s*0.35,
|
| 723 |
+
fillColor = colors.silver,
|
| 724 |
+
strokeColor = None,
|
| 725 |
+
strokeWidth=0)
|
| 726 |
+
g.add(metalcover)
|
| 727 |
+
|
| 728 |
+
coverslot = shapes.Rect(x=self.x+(s*0.28), y=(self.y)+(s*0.035), width=s*0.12, height=s*0.28,
|
| 729 |
+
fillColor = self.diskColor,
|
| 730 |
+
strokeColor = None,
|
| 731 |
+
strokeWidth=0)
|
| 732 |
+
g.add(coverslot)
|
| 733 |
+
|
| 734 |
+
return g
|
| 735 |
+
|
| 736 |
+
class ArrowOne(_Symbol):
|
| 737 |
+
"""This widget draws an arrow (style one).
|
| 738 |
+
|
| 739 |
+
possible attributes:
|
| 740 |
+
'x', 'y', 'size', 'fillColor'
|
| 741 |
+
|
| 742 |
+
"""
|
| 743 |
+
def __init__(self):
|
| 744 |
+
self.x = 0
|
| 745 |
+
self.y = 0
|
| 746 |
+
self.size = 100
|
| 747 |
+
self.fillColor = colors.red
|
| 748 |
+
self.strokeWidth = 0
|
| 749 |
+
self.strokeColor = None
|
| 750 |
+
|
| 751 |
+
def draw(self):
|
| 752 |
+
# general widget bits
|
| 753 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 754 |
+
g = shapes.Group()
|
| 755 |
+
|
| 756 |
+
x = self.x
|
| 757 |
+
y = self.y
|
| 758 |
+
s2 = s/2
|
| 759 |
+
s3 = s/3
|
| 760 |
+
s5 = s/5
|
| 761 |
+
g.add(shapes.Polygon(points = [
|
| 762 |
+
x,y+s3,
|
| 763 |
+
x,y+2*s3,
|
| 764 |
+
x+s2,y+2*s3,
|
| 765 |
+
x+s2,y+4*s5,
|
| 766 |
+
x+s,y+s2,
|
| 767 |
+
x+s2,y+s5,
|
| 768 |
+
x+s2,y+s3,
|
| 769 |
+
],
|
| 770 |
+
fillColor = self.fillColor,
|
| 771 |
+
strokeColor = self.strokeColor,
|
| 772 |
+
strokeWidth = self.strokeWidth,
|
| 773 |
+
)
|
| 774 |
+
)
|
| 775 |
+
return g
|
| 776 |
+
|
| 777 |
+
class ArrowTwo(ArrowOne):
|
| 778 |
+
"""This widget draws an arrow (style two).
|
| 779 |
+
|
| 780 |
+
possible attributes:
|
| 781 |
+
'x', 'y', 'size', 'fillColor'
|
| 782 |
+
|
| 783 |
+
"""
|
| 784 |
+
|
| 785 |
+
def __init__(self):
|
| 786 |
+
self.x = 0
|
| 787 |
+
self.y = 0
|
| 788 |
+
self.size = 100
|
| 789 |
+
self.fillColor = colors.blue
|
| 790 |
+
self.strokeWidth = 0
|
| 791 |
+
self.strokeColor = None
|
| 792 |
+
|
| 793 |
+
def draw(self):
|
| 794 |
+
# general widget bits
|
| 795 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 796 |
+
g = shapes.Group()
|
| 797 |
+
|
| 798 |
+
# arrow specific bits
|
| 799 |
+
x = self.x
|
| 800 |
+
y = self.y
|
| 801 |
+
s2 = s/2
|
| 802 |
+
s3 = s/3
|
| 803 |
+
s5 = s/5
|
| 804 |
+
s24 = s/24
|
| 805 |
+
|
| 806 |
+
g.add(shapes.Polygon(
|
| 807 |
+
points = [
|
| 808 |
+
x,y+11*s24,
|
| 809 |
+
x,y+13*s24,
|
| 810 |
+
x+18.75*s24, y+13*s24,
|
| 811 |
+
x+2*s3, y+2*s3,
|
| 812 |
+
x+s, y+s2,
|
| 813 |
+
x+2*s3, y+s3,
|
| 814 |
+
x+18.75*s24, y+11*s24,
|
| 815 |
+
],
|
| 816 |
+
fillColor = self.fillColor,
|
| 817 |
+
strokeColor = self.strokeColor,
|
| 818 |
+
strokeWidth = self.strokeWidth)
|
| 819 |
+
)
|
| 820 |
+
|
| 821 |
+
return g
|
| 822 |
+
|
| 823 |
+
class CrossHair(_Symbol):
|
| 824 |
+
"""This draws an equilateral triangle."""
|
| 825 |
+
_attrMap = AttrMap(BASE=_Symbol,
|
| 826 |
+
innerGap = AttrMapValue(EitherOr((isString,isNumberOrNone)),desc=' gap at centre as "x%" or points or None'),
|
| 827 |
+
)
|
| 828 |
+
|
| 829 |
+
def __init__(self):
|
| 830 |
+
self.x = self.y = self.dx = self.dy = 0
|
| 831 |
+
self.size = 10
|
| 832 |
+
self.fillColor = None
|
| 833 |
+
self.strokeColor = colors.black
|
| 834 |
+
self.strokeWidth = 0.5
|
| 835 |
+
self.innerGap = '20%'
|
| 836 |
+
|
| 837 |
+
def draw(self):
|
| 838 |
+
# general widget bits
|
| 839 |
+
s = float(self.size) # abbreviate as we will use this a lot
|
| 840 |
+
g = shapes.Group()
|
| 841 |
+
ig = self.innerGap
|
| 842 |
+
|
| 843 |
+
x = self.x+self.dx
|
| 844 |
+
y = self.y+self.dy
|
| 845 |
+
hsize = 0.5*self.size
|
| 846 |
+
if not ig:
|
| 847 |
+
L = [(x-hsize,y,x+hsize,y), (x,y-hsize,x,y+hsize)]
|
| 848 |
+
else:
|
| 849 |
+
if isStr(ig):
|
| 850 |
+
ig = asUnicode(ig)
|
| 851 |
+
if ig.endswith(u'%'):
|
| 852 |
+
gs = hsize*float(ig[:-1])/100.0
|
| 853 |
+
else:
|
| 854 |
+
gs = float(ig)*0.5
|
| 855 |
+
else:
|
| 856 |
+
gs = ig*0.5
|
| 857 |
+
L = [(x-hsize,y,x-gs,y), (x+gs,y,x+hsize,y), (x,y-hsize,x,y-gs), (x,y+gs,x,y+hsize)]
|
| 858 |
+
P = shapes.Path(strokeWidth=self.strokeWidth,strokeColor=self.strokeColor)
|
| 859 |
+
for x0,y0,x1,y1 in L:
|
| 860 |
+
P.moveTo(x0,y0)
|
| 861 |
+
P.lineTo(x1,y1)
|
| 862 |
+
g.add(P)
|
| 863 |
+
return g
|
| 864 |
+
|
| 865 |
+
|
| 866 |
+
def test():
|
| 867 |
+
"""This function produces a pdf with examples of all the signs and symbols from this file.
|
| 868 |
+
"""
|
| 869 |
+
labelFontSize = 10
|
| 870 |
+
D = shapes.Drawing(450,650)
|
| 871 |
+
cb = Crossbox()
|
| 872 |
+
cb.x = 20
|
| 873 |
+
cb.y = 530
|
| 874 |
+
D.add(cb)
|
| 875 |
+
D.add(shapes.String(cb.x+(cb.size/2),(cb.y-(1.2*labelFontSize)),
|
| 876 |
+
cb.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 877 |
+
fontSize=labelFontSize))
|
| 878 |
+
|
| 879 |
+
tb = Tickbox()
|
| 880 |
+
tb.x = 170
|
| 881 |
+
tb.y = 530
|
| 882 |
+
D.add(tb)
|
| 883 |
+
D.add(shapes.String(tb.x+(tb.size/2),(tb.y-(1.2*labelFontSize)),
|
| 884 |
+
tb.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 885 |
+
fontSize=labelFontSize))
|
| 886 |
+
|
| 887 |
+
|
| 888 |
+
yn = YesNo()
|
| 889 |
+
yn.x = 320
|
| 890 |
+
yn.y = 530
|
| 891 |
+
D.add(yn)
|
| 892 |
+
tempstring = yn.__class__.__name__ + '*'
|
| 893 |
+
D.add(shapes.String(yn.x+(tb.size/2),(yn.y-(1.2*labelFontSize)),
|
| 894 |
+
tempstring, fillColor=colors.black, textAnchor='middle',
|
| 895 |
+
fontSize=labelFontSize))
|
| 896 |
+
D.add(shapes.String(130,6,
|
| 897 |
+
"(The 'YesNo' widget returns a tickbox if testvalue=1, and a crossbox if testvalue=0)", fillColor=colors.black, textAnchor='middle',
|
| 898 |
+
fontSize=labelFontSize*0.75))
|
| 899 |
+
|
| 900 |
+
|
| 901 |
+
ss = StopSign()
|
| 902 |
+
ss.x = 20
|
| 903 |
+
ss.y = 400
|
| 904 |
+
D.add(ss)
|
| 905 |
+
D.add(shapes.String(ss.x+(ss.size/2), ss.y-(1.2*labelFontSize),
|
| 906 |
+
ss.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 907 |
+
fontSize=labelFontSize))
|
| 908 |
+
|
| 909 |
+
ne = NoEntry()
|
| 910 |
+
ne.x = 170
|
| 911 |
+
ne.y = 400
|
| 912 |
+
D.add(ne)
|
| 913 |
+
D.add(shapes.String(ne.x+(ne.size/2),(ne.y-(1.2*labelFontSize)),
|
| 914 |
+
ne.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 915 |
+
fontSize=labelFontSize))
|
| 916 |
+
|
| 917 |
+
sf = SmileyFace()
|
| 918 |
+
sf.x = 320
|
| 919 |
+
sf.y = 400
|
| 920 |
+
D.add(sf)
|
| 921 |
+
D.add(shapes.String(sf.x+(sf.size/2),(sf.y-(1.2*labelFontSize)),
|
| 922 |
+
sf.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 923 |
+
fontSize=labelFontSize))
|
| 924 |
+
|
| 925 |
+
ds = DangerSign()
|
| 926 |
+
ds.x = 20
|
| 927 |
+
ds.y = 270
|
| 928 |
+
D.add(ds)
|
| 929 |
+
D.add(shapes.String(ds.x+(ds.size/2),(ds.y-(1.2*labelFontSize)),
|
| 930 |
+
ds.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 931 |
+
fontSize=labelFontSize))
|
| 932 |
+
|
| 933 |
+
na = NotAllowed()
|
| 934 |
+
na.x = 170
|
| 935 |
+
na.y = 270
|
| 936 |
+
D.add(na)
|
| 937 |
+
D.add(shapes.String(na.x+(na.size/2),(na.y-(1.2*labelFontSize)),
|
| 938 |
+
na.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 939 |
+
fontSize=labelFontSize))
|
| 940 |
+
|
| 941 |
+
ns = NoSmoking()
|
| 942 |
+
ns.x = 320
|
| 943 |
+
ns.y = 270
|
| 944 |
+
D.add(ns)
|
| 945 |
+
D.add(shapes.String(ns.x+(ns.size/2),(ns.y-(1.2*labelFontSize)),
|
| 946 |
+
ns.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 947 |
+
fontSize=labelFontSize))
|
| 948 |
+
|
| 949 |
+
a1 = ArrowOne()
|
| 950 |
+
a1.x = 20
|
| 951 |
+
a1.y = 140
|
| 952 |
+
D.add(a1)
|
| 953 |
+
D.add(shapes.String(a1.x+(a1.size/2),(a1.y-(1.2*labelFontSize)),
|
| 954 |
+
a1.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 955 |
+
fontSize=labelFontSize))
|
| 956 |
+
|
| 957 |
+
a2 = ArrowTwo()
|
| 958 |
+
a2.x = 170
|
| 959 |
+
a2.y = 140
|
| 960 |
+
D.add(a2)
|
| 961 |
+
D.add(shapes.String(a2.x+(a2.size/2),(a2.y-(1.2*labelFontSize)),
|
| 962 |
+
a2.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 963 |
+
fontSize=labelFontSize))
|
| 964 |
+
|
| 965 |
+
fd = FloppyDisk()
|
| 966 |
+
fd.x = 320
|
| 967 |
+
fd.y = 140
|
| 968 |
+
D.add(fd)
|
| 969 |
+
D.add(shapes.String(fd.x+(fd.size/2),(fd.y-(1.2*labelFontSize)),
|
| 970 |
+
fd.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
| 971 |
+
fontSize=labelFontSize))
|
| 972 |
+
|
| 973 |
+
renderPDF.drawToFile(D, 'signsandsymbols.pdf', 'signsandsymbols.py')
|
| 974 |
+
print('wrote file: signsandsymbols.pdf')
|
| 975 |
+
|
| 976 |
+
if __name__=='__main__':
|
| 977 |
+
test()
|
.venv/lib/python3.13/site-packages/reportlab/graphics/widgets/table.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
#Copyright ReportLab Europe Ltd. 2000-2017
|
| 3 |
+
#see license.txt for license details
|
| 4 |
+
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/table.py
|
| 5 |
+
__version__='3.3.0'
|
| 6 |
+
|
| 7 |
+
from reportlab.graphics.widgetbase import Widget
|
| 8 |
+
from reportlab.graphics import shapes
|
| 9 |
+
from reportlab.lib import colors
|
| 10 |
+
from reportlab.lib.validators import *
|
| 11 |
+
from reportlab.lib.attrmap import *
|
| 12 |
+
|
| 13 |
+
from reportlab.graphics.shapes import Drawing
|
| 14 |
+
|
| 15 |
+
class TableWidget(Widget):
|
| 16 |
+
"""A two dimensions table of labels
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
_attrMap = AttrMap(
|
| 20 |
+
x = AttrMapValue(isNumber, desc="x position of left edge of table"),
|
| 21 |
+
y = AttrMapValue(isNumber, desc="y position of bottom edge of table"),
|
| 22 |
+
width = AttrMapValue(isNumber, desc="table width"),
|
| 23 |
+
height = AttrMapValue(isNumber, desc="table height"),
|
| 24 |
+
borderStrokeColor = AttrMapValue(isColorOrNone, desc="table border color"),
|
| 25 |
+
fillColor = AttrMapValue(isColorOrNone, desc="table fill color"),
|
| 26 |
+
borderStrokeWidth = AttrMapValue(isNumber, desc="border line width"),
|
| 27 |
+
horizontalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner horizontal lines color"),
|
| 28 |
+
verticalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner vertical lines color"),
|
| 29 |
+
horizontalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner horizontal lines width"),
|
| 30 |
+
verticalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner vertical lines width"),
|
| 31 |
+
dividerDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array for dividerLines.'),
|
| 32 |
+
data = AttrMapValue(None, desc="a list of list of strings to be displayed in the cells"),
|
| 33 |
+
boxAnchor = AttrMapValue(isBoxAnchor, desc="location of the table anchoring point"),
|
| 34 |
+
fontName = AttrMapValue(isString, desc="text font in the table"),
|
| 35 |
+
fontSize = AttrMapValue(isNumber, desc="font size of the table"),
|
| 36 |
+
fontColor = AttrMapValue(isColorOrNone, desc="font color"),
|
| 37 |
+
alignment = AttrMapValue(OneOf("left", "right"), desc="Alignment of text within cells"),
|
| 38 |
+
textAnchor = AttrMapValue(OneOf('start','middle','end','numeric'), desc="Alignment of text within cells"),
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
def __init__(self, x=10, y=10, **kw):
|
| 42 |
+
|
| 43 |
+
self.x = x
|
| 44 |
+
self.y = y
|
| 45 |
+
self.width = 200
|
| 46 |
+
self.height = 100
|
| 47 |
+
self.borderStrokeColor = colors.black
|
| 48 |
+
self.fillColor = None
|
| 49 |
+
self.borderStrokeWidth = 0.5
|
| 50 |
+
self.horizontalDividerStrokeColor = colors.black
|
| 51 |
+
self.verticalDividerStrokeColor = colors.black
|
| 52 |
+
self.horizontalDividerStrokeWidth = 0.5
|
| 53 |
+
self.verticalDividerStrokeWidth = 0.25
|
| 54 |
+
self.dividerDashArray = None
|
| 55 |
+
self.data = [['North','South','East','West'],[100,110,120,130],['A','B','C','D']] # list of rows each row is a list of columns
|
| 56 |
+
self.boxAnchor = 'nw'
|
| 57 |
+
#self.fontName = None
|
| 58 |
+
self.fontSize = 8
|
| 59 |
+
self.fontColor = colors.black
|
| 60 |
+
self.alignment = 'right'
|
| 61 |
+
self.textAnchor = 'start'
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
for k, v in kw.items():
|
| 65 |
+
if k in list(self.__class__._attrMap.keys()):
|
| 66 |
+
setattr(self, k, v)
|
| 67 |
+
else:
|
| 68 |
+
raise ValueError('invalid argument supplied for class %s'%self.__class__)
|
| 69 |
+
|
| 70 |
+
def demo(self):
|
| 71 |
+
""" returns a sample of this widget with data
|
| 72 |
+
"""
|
| 73 |
+
d = Drawing(400, 200)
|
| 74 |
+
t = TableWidget()
|
| 75 |
+
d.add(t, name='table')
|
| 76 |
+
d.table.dividerDashArray = (1, 3, 2)
|
| 77 |
+
d.table.verticalDividerStrokeColor = None
|
| 78 |
+
d.table.borderStrokeWidth = 0
|
| 79 |
+
d.table.borderStrokeColor = colors.red
|
| 80 |
+
return d
|
| 81 |
+
|
| 82 |
+
def draw(self):
|
| 83 |
+
""" returns a group of shapes
|
| 84 |
+
"""
|
| 85 |
+
g = shapes.Group()
|
| 86 |
+
|
| 87 |
+
#overall border and fill
|
| 88 |
+
if self.borderStrokeColor or self.fillColor: # adds border and filling color
|
| 89 |
+
rect = shapes.Rect(self.x, self.y, self.width, self.height)
|
| 90 |
+
rect.fillColor = self.fillColor
|
| 91 |
+
rect.strokeColor = self.borderStrokeColor
|
| 92 |
+
rect.strokeWidth = self.borderStrokeWidth
|
| 93 |
+
g.add(rect)
|
| 94 |
+
|
| 95 |
+
#special case - for an empty table we want to avoid divide-by-zero
|
| 96 |
+
data = self.preProcessData(self.data)
|
| 97 |
+
rows = len(self.data)
|
| 98 |
+
cols = len(self.data[0])
|
| 99 |
+
#print "(rows,cols)=(%s, %s)"%(rows,cols)
|
| 100 |
+
row_step = self.height / float(rows)
|
| 101 |
+
col_step = self.width / float(cols)
|
| 102 |
+
#print "(row_step,col_step)=(%s, %s)"%(row_step,col_step)
|
| 103 |
+
# draw the grid
|
| 104 |
+
if self.horizontalDividerStrokeColor:
|
| 105 |
+
for i in range(rows): # make horizontal lines
|
| 106 |
+
x1 = self.x
|
| 107 |
+
x2 = self.x + self.width
|
| 108 |
+
y = self.y + row_step*i
|
| 109 |
+
#print 'line (%s, %s), (%s, %s)'%(x1, y, x2, y)
|
| 110 |
+
line = shapes.Line(x1, y, x2, y)
|
| 111 |
+
line.strokeDashArray = self.dividerDashArray
|
| 112 |
+
line.strokeWidth = self.horizontalDividerStrokeWidth
|
| 113 |
+
line.strokeColor = self.horizontalDividerStrokeColor
|
| 114 |
+
g.add(line)
|
| 115 |
+
if self.verticalDividerStrokeColor:
|
| 116 |
+
for i in range(cols): # make vertical lines
|
| 117 |
+
x = self.x+col_step*i
|
| 118 |
+
y1 = self.y
|
| 119 |
+
y2 = self.y + self.height
|
| 120 |
+
#print 'line (%s, %s), (%s, %s)'%(x, y1, x, y2)
|
| 121 |
+
line = shapes.Line(x, y1, x, y2)
|
| 122 |
+
line.strokeDashArray = self.dividerDashArray
|
| 123 |
+
line.strokeWidth = self.verticalDividerStrokeWidth
|
| 124 |
+
line.strokeColor = self.verticalDividerStrokeColor
|
| 125 |
+
g.add(line)
|
| 126 |
+
|
| 127 |
+
# since we plot data from down up, we reverse the list
|
| 128 |
+
self.data.reverse()
|
| 129 |
+
for (j, row) in enumerate(self.data):
|
| 130 |
+
y = self.y + j*row_step + 0.5*row_step - 0.5 * self.fontSize
|
| 131 |
+
for (i, datum) in enumerate(row):
|
| 132 |
+
if datum:
|
| 133 |
+
x = self.x + i*col_step + 0.5*col_step
|
| 134 |
+
s = shapes.String(x, y, str(datum), textAnchor=self.textAnchor)
|
| 135 |
+
s.fontName = self.fontName
|
| 136 |
+
s.fontSize = self.fontSize
|
| 137 |
+
s.fillColor = self.fontColor
|
| 138 |
+
g.add(s)
|
| 139 |
+
return g
|
| 140 |
+
|
| 141 |
+
def preProcessData(self, data):
|
| 142 |
+
"""preprocess and return a new array with at least one row
|
| 143 |
+
and column (use a None) if needed, and all rows the same
|
| 144 |
+
length (adding Nones if needed)
|
| 145 |
+
|
| 146 |
+
"""
|
| 147 |
+
if not data:
|
| 148 |
+
return [[None]]
|
| 149 |
+
#make all rows have similar number of cells, append None when needed
|
| 150 |
+
max_row = max( [len(x) for x in data] )
|
| 151 |
+
for rowNo, row in enumerate(data):
|
| 152 |
+
if len(row) < max_row:
|
| 153 |
+
row.extend([None]*(max_row-len(row)))
|
| 154 |
+
return data
|
| 155 |
+
|
| 156 |
+
#test
|
| 157 |
+
if __name__ == '__main__':
|
| 158 |
+
d = TableWidget().demo()
|
| 159 |
+
import os
|
| 160 |
+
d.save(formats=['pdf'],outDir=os.getcwd(),fnRoot=None)
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (7.12 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/_base_connection.cpython-313.pyc
ADDED
|
Binary file (6.97 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/_collections.cpython-313.pyc
ADDED
|
Binary file (23.1 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/_request_methods.cpython-313.pyc
ADDED
|
Binary file (9.96 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/_version.cpython-313.pyc
ADDED
|
Binary file (800 Bytes). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/connection.cpython-313.pyc
ADDED
|
Binary file (39.3 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/connectionpool.cpython-313.pyc
ADDED
|
Binary file (39.1 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/exceptions.cpython-313.pyc
ADDED
|
Binary file (17.4 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/fields.cpython-313.pyc
ADDED
|
Binary file (11.6 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/filepost.cpython-313.pyc
ADDED
|
Binary file (3.5 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/poolmanager.cpython-313.pyc
ADDED
|
Binary file (23.9 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/__pycache__/response.cpython-313.pyc
ADDED
|
Binary file (58.6 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/contrib/__init__.py
ADDED
|
File without changes
|
.venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (190 Bytes). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-313.pyc
ADDED
|
Binary file (28.6 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/socks.cpython-313.pyc
ADDED
|
Binary file (8.41 kB). View file
|
|
|
.venv/lib/python3.13/site-packages/urllib3/contrib/emscripten/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import urllib3.connection
|
| 4 |
+
|
| 5 |
+
from ...connectionpool import HTTPConnectionPool, HTTPSConnectionPool
|
| 6 |
+
from .connection import EmscriptenHTTPConnection, EmscriptenHTTPSConnection
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def inject_into_urllib3() -> None:
|
| 10 |
+
# override connection classes to use emscripten specific classes
|
| 11 |
+
# n.b. mypy complains about the overriding of classes below
|
| 12 |
+
# if it isn't ignored
|
| 13 |
+
HTTPConnectionPool.ConnectionCls = EmscriptenHTTPConnection
|
| 14 |
+
HTTPSConnectionPool.ConnectionCls = EmscriptenHTTPSConnection
|
| 15 |
+
urllib3.connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment]
|
| 16 |
+
urllib3.connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment]
|
| 17 |
+
urllib3.connection.VerifiedHTTPSConnection = EmscriptenHTTPSConnection # type: ignore[assignment]
|