JustinTX commited on
Commit
b863129
·
verified ·
1 Parent(s): 3dc1188

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .venv/lib/python3.13/site-packages/instructor-1.14.3.dist-info/licenses/LICENSE +21 -0
  2. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/__init__.cpython-313.pyc +0 -0
  3. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/core.cpython-313.pyc +0 -0
  4. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/defaults.cpython-313.pyc +0 -0
  5. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/exception.cpython-313.pyc +0 -0
  6. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/json.cpython-313.pyc +0 -0
  7. .venv/lib/python3.13/site-packages/pythonjsonlogger/__pycache__/utils.cpython-313.pyc +0 -0
  8. .venv/lib/python3.13/site-packages/reportlab/graphics/charts/dotbox.py +165 -0
  9. .venv/lib/python3.13/site-packages/reportlab/graphics/charts/linecharts.py +801 -0
  10. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/__init__.py +1 -0
  11. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/bubble.py +73 -0
  12. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_bar.py +84 -0
  13. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/clustered_column.py +83 -0
  14. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/excelcolors.py +45 -0
  15. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/exploded_pie.py +65 -0
  16. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/filled_radar.py +54 -0
  17. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/line_chart.py +83 -0
  18. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/linechart_with_markers.py +94 -0
  19. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/radar.py +66 -0
  20. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/runall.py +57 -0
  21. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter.py +71 -0
  22. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines.py +82 -0
  23. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/scatter_lines_markers.py +72 -0
  24. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/simple_pie.py +61 -0
  25. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_bar.py +85 -0
  26. .venv/lib/python3.13/site-packages/reportlab/graphics/samples/stacked_column.py +84 -0
  27. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/__init__.py +5 -0
  28. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/adjustableArrow.py +126 -0
  29. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/eventcal.py +299 -0
  30. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/flags.py +879 -0
  31. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/grids.py +542 -0
  32. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/signsandsymbols.py +977 -0
  33. .venv/lib/python3.13/site-packages/reportlab/graphics/widgets/table.py +160 -0
  34. .venv/lib/python3.13/site-packages/urllib3/__pycache__/__init__.cpython-313.pyc +0 -0
  35. .venv/lib/python3.13/site-packages/urllib3/__pycache__/_base_connection.cpython-313.pyc +0 -0
  36. .venv/lib/python3.13/site-packages/urllib3/__pycache__/_collections.cpython-313.pyc +0 -0
  37. .venv/lib/python3.13/site-packages/urllib3/__pycache__/_request_methods.cpython-313.pyc +0 -0
  38. .venv/lib/python3.13/site-packages/urllib3/__pycache__/_version.cpython-313.pyc +0 -0
  39. .venv/lib/python3.13/site-packages/urllib3/__pycache__/connection.cpython-313.pyc +0 -0
  40. .venv/lib/python3.13/site-packages/urllib3/__pycache__/connectionpool.cpython-313.pyc +0 -0
  41. .venv/lib/python3.13/site-packages/urllib3/__pycache__/exceptions.cpython-313.pyc +0 -0
  42. .venv/lib/python3.13/site-packages/urllib3/__pycache__/fields.cpython-313.pyc +0 -0
  43. .venv/lib/python3.13/site-packages/urllib3/__pycache__/filepost.cpython-313.pyc +0 -0
  44. .venv/lib/python3.13/site-packages/urllib3/__pycache__/poolmanager.cpython-313.pyc +0 -0
  45. .venv/lib/python3.13/site-packages/urllib3/__pycache__/response.cpython-313.pyc +0 -0
  46. .venv/lib/python3.13/site-packages/urllib3/contrib/__init__.py +0 -0
  47. .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/__init__.cpython-313.pyc +0 -0
  48. .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-313.pyc +0 -0
  49. .venv/lib/python3.13/site-packages/urllib3/contrib/__pycache__/socks.cpython-313.pyc +0 -0
  50. .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 &amp; 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]