author  robin <robin@reportlab.com> 
Tue, 07 Mar 2017 10:00:34 +0000  
changeset 4330  617ffa6bbdc8 
parent 4252  fe660f227cac 
child 4332  b9b7e096842f 
permissions  rwrr 
4330  1 
#Copyright ReportLab Europe Ltd. 20002017 
817  2 
#see license.txt for license details 
2332  3 
#history http://www.reportlab.co.uk/cgibin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/charts/piecharts.py 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

4 
# experimental pie chart script. Two types of pie  one is a monolithic 
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

5 
#widget with all toplevel properties, the other delegates most stuff to 
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

6 
#a wedges collection whic lets you customize the group or every individual 
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

7 
#wedge. 
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

8 

4252  9 
__version__='3.3.0' 
3032  10 
__doc__="""Basic Pie Chart class. 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

11 

8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

12 
This permits you to customize and pop out individual wedges; 
909
a5ee7d2bdb17
Extracted validator functions into lib.validators.
dinu_gherman
parents:
907
diff
changeset

13 
supports elliptical and circular pies. 
a5ee7d2bdb17
Extracted validator functions into lib.validators.
dinu_gherman
parents:
907
diff
changeset

14 
""" 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

15 

3818  16 
import copy, functools 
907  17 
from math import sin, cos, pi 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

18 

909
a5ee7d2bdb17
Extracted validator functions into lib.validators.
dinu_gherman
parents:
907
diff
changeset

19 
from reportlab.lib import colors 
1620  20 
from reportlab.lib.validators import isColor, isNumber, isListOfNumbersOrNone,\ 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

21 
isListOfNumbers, isColorOrNone, isString,\ 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

22 
isListOfStringsOrNone, OneOf, SequenceOf,\ 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

23 
isBoolean, isListOfColors, isNumberOrNone,\ 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

24 
isNoneOrListOfNoneOrStrings, isTextAnchor,\ 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

25 
isNoneOrListOfNoneOrNumbers, isBoxAnchor,\ 
2431
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

26 
isStringOrNone, NoneOr 
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

27 
from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol 
948  28 
from reportlab.lib.attrmap import * 
909
a5ee7d2bdb17
Extracted validator functions into lib.validators.
dinu_gherman
parents:
907
diff
changeset

29 
from reportlab.pdfgen.canvas import Canvas 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

30 
from reportlab.graphics.shapes import Group, Drawing, Ellipse, Wedge, String, STATE_DEFAULTS, ArcPath, Polygon, Rect, PolyLine, Line 
916
de1bbc3958c3
Made more consistent use of typed collections.
dinu_gherman
parents:
909
diff
changeset

31 
from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection, PropHolder 
2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

32 
from reportlab.graphics.charts.areas import PlotArea 
2856
2225ac76e622
charts: fix unicode labels using _objStr (bug from Sebastian Ware sebastian@urbantalk.se)
rgbecker
parents:
2835
diff
changeset

33 
from reportlab.graphics.charts.legends import _objStr 
3580  34 
from reportlab.graphics.charts.textlabels import Label 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

35 

1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

36 
_ANGLE2BOXANCHOR={0:'w', 45:'sw', 90:'s', 135:'se', 180:'e', 225:'ne', 270:'n', 315: 'nw', 45: 'nw'} 
2520  37 
_ANGLE2RBOXANCHOR={0:'e', 45:'ne', 90:'n', 135:'nw', 180:'w', 225:'sw', 270:'s', 315: 'se', 45: 'se'} 
3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

38 

90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

39 
_ANGLELO = 1e7 
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

40 
_ANGLEHI = 360.0  _ANGLELO 
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

41 

1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

42 
class WedgeLabel(Label): 
2028  43 
def _checkDXY(self,ba): 
44 
pass 

1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

45 
def _getBoxAnchor(self): 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

46 
ba = self.boxAnchor 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

47 
if ba in ('autox','autoy'): 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

48 
na = (int((self._pmv%360)/45.)*45)%360 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

49 
if not (na % 90): # we have a right angle case 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

50 
da = (self._pmv  na) % 360 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

51 
if abs(da)>5: 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

52 
na += (da>0 and 45 or 45) 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

53 
ba = (getattr(self,'_anti',None) and _ANGLE2RBOXANCHOR or _ANGLE2BOXANCHOR)[na] 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

54 
self._checkDXY(ba) 
2028  55 
return ba 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

56 

916
de1bbc3958c3
Made more consistent use of typed collections.
dinu_gherman
parents:
909
diff
changeset

57 
class WedgeProperties(PropHolder): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

58 
"""This holds descriptive information about the wedges in a pie chart. 
1683  59 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

60 
It is not to be confused with the 'wedge itself'; this just holds 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

61 
a recipe for how to format one, and does not allow you to hack the 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

62 
angles. It can format a genuine Wedge object for you with its 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

63 
format method. 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

64 
""" 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

65 
_attrMap = AttrMap( 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

66 
strokeWidth = AttrMapValue(isNumber,desc='Width of the wedge border'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

67 
fillColor = AttrMapValue(isColorOrNone,desc='Filling color of the wedge'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

68 
strokeColor = AttrMapValue(isColorOrNone,desc='Color of the wedge border'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

69 
strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='Style of the wedge border, expressed as a list of lengths of alternating dashes and blanks'), 
3271  70 
strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), 
71 
strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), 

3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

72 
strokeMiterLimit = AttrMapValue(isNumber,desc='Miter limit control miter line joins'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

73 
popout = AttrMapValue(isNumber,desc="How far of centre a wedge to pop"), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

74 
fontName = AttrMapValue(isString,desc='Name of the font of the label text'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

75 
fontSize = AttrMapValue(isNumber,desc='Size of the font of the label text in points'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

76 
fontColor = AttrMapValue(isColorOrNone,desc='Color of the font of the label text'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

77 
labelRadius = AttrMapValue(isNumber,desc='Distance between the center of the label box and the center of the pie, expressed in times the radius of the pie'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

78 
label_dx = AttrMapValue(isNumber,desc='X Offset of the label'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

79 
label_dy = AttrMapValue(isNumber,desc='Y Offset of the label'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

80 
label_angle = AttrMapValue(isNumber,desc='Angle of the label, default (0) is horizontal, 90 is vertical, 180 is upside down'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

81 
label_boxAnchor = AttrMapValue(isBoxAnchor,desc='Anchoring point of the label'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

82 
label_boxStrokeColor = AttrMapValue(isColorOrNone,desc='Border color for the label box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

83 
label_boxStrokeWidth = AttrMapValue(isNumber,desc='Border width for the label box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

84 
label_boxFillColor = AttrMapValue(isColorOrNone,desc='Filling color of the label box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

85 
label_strokeColor = AttrMapValue(isColorOrNone,desc='Border color for the label text'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

86 
label_strokeWidth = AttrMapValue(isNumber,desc='Border width for the label text'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

87 
label_text = AttrMapValue(isStringOrNone,desc='Text of the label'), 
3270  88 
label_leading = AttrMapValue(isNumberOrNone,desc=''), 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

89 
label_width = AttrMapValue(isNumberOrNone,desc='Width of the label'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

90 
label_maxWidth = AttrMapValue(isNumberOrNone,desc='Maximum width the label can grow to'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

91 
label_height = AttrMapValue(isNumberOrNone,desc='Height of the label'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

92 
label_textAnchor = AttrMapValue(isTextAnchor,desc='Maximum height the label can grow to'), 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

93 
label_visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

94 
label_topPadding = AttrMapValue(isNumber,'Padding at top of box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

95 
label_leftPadding = AttrMapValue(isNumber,'Padding at left of box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

96 
label_rightPadding = AttrMapValue(isNumber,'Padding at right of box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

97 
label_bottomPadding = AttrMapValue(isNumber,'Padding at bottom of box'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

98 
label_simple_pointer = AttrMapValue(isBoolean,'Set to True for simple pointers'), 
2543  99 
label_pointer_strokeColor = AttrMapValue(isColorOrNone,desc='Color of indicator line'), 
100 
label_pointer_strokeWidth = AttrMapValue(isNumber,desc='StrokeWidth of indicator line'), 

3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

101 
label_pointer_elbowLength = AttrMapValue(isNumber,desc='Length of final indicator line segment'), 
2543  102 
label_pointer_edgePad = AttrMapValue(isNumber,desc='pad between pointer label and box'), 
103 
label_pointer_piePad = AttrMapValue(isNumber,desc='pad between pointer label and pie'), 

3270  104 
swatchMarker = AttrMapValue(NoneOr(isSymbol), desc="None or makeMarker('Diamond') ...",advancedUsage=1), 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

105 
visible = AttrMapValue(isBoolean,'Set to false to skip displaying'), 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

106 
) 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

107 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

108 
def __init__(self): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

109 
self.strokeWidth = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

110 
self.fillColor = None 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

111 
self.strokeColor = STATE_DEFAULTS["strokeColor"] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

112 
self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] 
3227
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

113 
self.strokeLineJoin = 1 
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

114 
self.strokeLineCap = 0 
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

115 
self.strokeMiterLimit = 0 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

116 
self.popout = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

117 
self.fontName = STATE_DEFAULTS["fontName"] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

118 
self.fontSize = STATE_DEFAULTS["fontSize"] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

119 
self.fontColor = STATE_DEFAULTS["fillColor"] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

120 
self.labelRadius = 1.2 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

121 
self.label_dx = self.label_dy = self.label_angle = 0 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

122 
self.label_text = None 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

123 
self.label_topPadding = self.label_leftPadding = self.label_rightPadding = self.label_bottomPadding = 0 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

124 
self.label_boxAnchor = 'autox' 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

125 
self.label_boxStrokeColor = None #boxStroke 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

126 
self.label_boxStrokeWidth = 0.5 #boxStrokeWidth 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

127 
self.label_boxFillColor = None 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

128 
self.label_strokeColor = None 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

129 
self.label_strokeWidth = 0.1 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

130 
self.label_leading = self.label_width = self.label_maxWidth = self.label_height = None 
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

131 
self.label_textAnchor = 'start' 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

132 
self.label_simple_pointer = 0 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

133 
self.label_visible = 1 
2543  134 
self.label_pointer_strokeColor = colors.black 
135 
self.label_pointer_strokeWidth = 0.5 

136 
self.label_pointer_elbowLength = 3 

137 
self.label_pointer_edgePad = 2 

138 
self.label_pointer_piePad = 3 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

139 
self.visible = 1 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

140 

3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

141 
def _addWedgeLabel(self,text,angle,labelX,labelY,wedgeStyle,labelClass=WedgeLabel): 
2017  142 
# now draw a label 
143 
if self.simpleLabels: 

144 
theLabel = String(labelX, labelY, text) 

3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

145 
if not self.sideLabels: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

146 
theLabel.textAnchor = "middle" 
3580  147 
else: 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

148 
if (abs(angle) < 90 ) or (angle >270 and angle<450) or (450< angle <270): 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

149 
theLabel.textAnchor = "start" 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

150 
else: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

151 
theLabel.textAnchor = "end" 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

152 
theLabel._pmv = angle 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

153 
theLabel._simple_pointer = 0 
2017  154 
else: 
2028  155 
theLabel = labelClass() 
2017  156 
theLabel._pmv = angle 
157 
theLabel.x = labelX 

158 
theLabel.y = labelY 

159 
theLabel.dx = wedgeStyle.label_dx 

3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

160 
if not self.sideLabels: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

161 
theLabel.dy = wedgeStyle.label_dy 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

162 
theLabel.boxAnchor = wedgeStyle.label_boxAnchor 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

163 
else: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

164 
if wedgeStyle.fontSize is None: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

165 
sideLabels_dy = self.fontSize / 2.5 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

166 
else: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

167 
sideLabels_dy = wedgeStyle.fontSize / 2.5 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

168 
if wedgeStyle.label_dy is None: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

169 
theLabel.dy = sideLabels_dy 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

170 
else: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

171 
theLabel.dy = wedgeStyle.label_dy + sideLabels_dy 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

172 
if (abs(angle) < 90 ) or (angle >270 and angle<450) or (450< angle <270): 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

173 
theLabel.boxAnchor = 'w' 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

174 
else: 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

175 
theLabel.boxAnchor = 'e' 
2017  176 
theLabel.angle = wedgeStyle.label_angle 
177 
theLabel.boxStrokeColor = wedgeStyle.label_boxStrokeColor 

178 
theLabel.boxStrokeWidth = wedgeStyle.label_boxStrokeWidth 

179 
theLabel.boxFillColor = wedgeStyle.label_boxFillColor 

180 
theLabel.strokeColor = wedgeStyle.label_strokeColor 

181 
theLabel.strokeWidth = wedgeStyle.label_strokeWidth 

182 
_text = wedgeStyle.label_text 

183 
if _text is None: _text = text 

184 
theLabel._text = _text 

185 
theLabel.leading = wedgeStyle.label_leading 

186 
theLabel.width = wedgeStyle.label_width 

187 
theLabel.maxWidth = wedgeStyle.label_maxWidth 

188 
theLabel.height = wedgeStyle.label_height 

189 
theLabel.textAnchor = wedgeStyle.label_textAnchor 

190 
theLabel.visible = wedgeStyle.label_visible 

191 
theLabel.topPadding = wedgeStyle.label_topPadding 

192 
theLabel.leftPadding = wedgeStyle.label_leftPadding 

193 
theLabel.rightPadding = wedgeStyle.label_rightPadding 

194 
theLabel.bottomPadding = wedgeStyle.label_bottomPadding 

3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

195 
theLabel._simple_pointer = wedgeStyle.label_simple_pointer 
2017  196 
theLabel.fontSize = wedgeStyle.fontSize 
197 
theLabel.fontName = wedgeStyle.fontName 

198 
theLabel.fillColor = wedgeStyle.fontColor 

3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

199 
return theLabel 
2017  200 

201 
def _fixLabels(labels,n): 

202 
if labels is None: 

203 
labels = [''] * n 

204 
else: 

205 
i = nlen(labels) 

3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

206 
if i>0: labels = list(labels)+['']*i 
2017  207 
return labels 
208 

2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

209 
class AbstractPieChart(PlotArea): 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

210 

1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

211 
def makeSwatchSample(self, rowNo, x, y, width, height): 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

212 
baseStyle = self.slices 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

213 
styleIdx = rowNo % len(baseStyle) 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

214 
style = baseStyle[styleIdx] 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

215 
strokeColor = getattr(style, 'strokeColor', getattr(baseStyle,'strokeColor',None)) 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

216 
fillColor = getattr(style, 'fillColor', getattr(baseStyle,'fillColor',None)) 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

217 
strokeDashArray = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None)) 
2431
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

218 
strokeWidth = getattr(style, 'strokeWidth', getattr(baseStyle, 'strokeWidth',None)) 
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

219 
swatchMarker = getattr(style, 'swatchMarker', getattr(baseStyle, 'swatchMarker',None)) 
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

220 
if swatchMarker: 
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

221 
return uSymbol2Symbol(swatchMarker,x+width/2.,y+height/2.,fillColor) 
2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

222 
return Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=strokeColor, 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

223 
strokeDashArray=strokeDashArray,fillColor=fillColor) 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

224 

1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

225 
def getSeriesName(self,i,default=None): 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

226 
'''return series name i or default''' 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

227 
try: 
2856
2225ac76e622
charts: fix unicode labels using _objStr (bug from Sebastian Ware sebastian@urbantalk.se)
rgbecker
parents:
2835
diff
changeset

228 
text = _objStr(self.labels[i]) 
2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

229 
except: 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

230 
text = default 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

231 
if not self.simpleLabels: 
2431
84617376d454
charts: minor adjustments to legends/swatches for pies/barcharts
rgbecker
parents:
2427
diff
changeset

232 
_text = getattr(self.slices[i],'label_text','') 
2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

233 
if _text is not None: text = _text 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

234 
return text 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

235 

2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

236 
def boundsOverlap(P,Q): 
3580  237 
return not(P[0]>Q[2]1e2 or Q[0]>P[2]1e2 or P[1]>(0.5*(Q[1]+Q[3]))1e2 or Q[1]>(0.5*(P[1]+P[3]))1e2) 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

238 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

239 
def _findOverlapRun(B,i,wrap): 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

240 
'''find overlap run containing B[i]''' 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

241 
n = len(B) 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

242 
R = [i] 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

243 
while 1: 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

244 
i = R[1] 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

245 
j = (i+1)%n 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

246 
if j in R or not boundsOverlap(B[i],B[j]): break 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

247 
R.append(j) 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

248 
while 1: 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

249 
i = R[0] 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

250 
j = (i1)%n 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

251 
if j in R or not boundsOverlap(B[i],B[j]): break 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

252 
R.insert(0,j) 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

253 
return R 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

254 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

255 
def findOverlapRun(B,wrap=1): 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

256 
'''determine a set of overlaps in bounding boxes B or return None''' 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

257 
n = len(B) 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

258 
if n>1: 
3721  259 
for i in range(n1): 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

260 
R = _findOverlapRun(B,i,wrap) 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

261 
if len(R)>1: return R 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

262 
return None 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

263 

3580  264 
def fixLabelOverlaps(L, sideLabels=False): 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

265 
nL = len(L) 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

266 
if nL<2: return 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

267 
B = [l._origdata['bounds'] for l in L] 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

268 
OK = 1 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

269 
RP = [] 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

270 
iter = 0 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

271 
mult = 1. 
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

272 

3580  273 
if not sideLabels: 
274 
while iter<30: 

275 
R = findOverlapRun(B) 

276 
if not R: break 

277 
nR = len(R) 

278 
if nR==nL: break 

279 
if not [r for r in RP if r in R]: 

280 
mult = 1.0 

281 
da = 0 

282 
r0 = R[0] 

283 
rL = R[1] 

284 
bi = B[r0] 

285 
taa = aa = _360(L[r0]._pmv) 

286 
for r in R[1:]: 

287 
b = B[r] 

288 
da = max(da,min(b[3]bi[1],bi[3]b[1])) 

289 
bi = b 

290 
aa += L[r]._pmv 

291 
aa = aa/float(nR) 

292 
utaa = abs(L[rL]._pmvtaa) 

293 
ntaa = _360(utaa) 

294 
da *= mult*(nR1)/ntaa 

295 

296 
for r in R: 

297 
l = L[r] 

298 
orig = l._origdata 

299 
angle = l._pmv = _360(l._pmv+da*(_360(l._pmv)aa)) 

300 
rad = angle/_180_pi 

301 
l.x = orig['cx'] + orig['rx']*cos(rad) 

302 
l.y = orig['cy'] + orig['ry']*sin(rad) 

303 
B[r] = l.getBounds() 

304 
RP = R 

305 
mult *= 1.05 

306 
iter += 1 

2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

307 

3580  308 
else: 
309 
while iter<30: 

310 
R = findOverlapRun(B) 

311 
if not R: break 

312 
nR = len(R) 

313 
if nR == nL: break 

314 
l1 = L[1] 

315 
orig1 = l1._origdata 

316 
bounds1 = orig1['bounds'] 

317 
for i,r in enumerate(R): 

318 
l = L[r] 

319 
orig = l._origdata 

320 
bounds = orig['bounds'] 

321 
diff1 = 0 

322 
diff2 = 0 

323 
if not i == nR1: 

324 
if not bounds == bounds1: 

325 
if bounds[3]>bounds1[1] and bounds1[1]<bounds[1]: 

326 
diff1 = bounds[3]bounds1[1] 

327 
if bounds1[3]>bounds[1] and bounds[1]<bounds1[1]: 

328 
diff2 = bounds1[3]bounds[1] 

329 
if diff1 > diff2: 

330 
l.y +=0.5*(bounds1[3]bounds1[1]) 

331 
elif diff2 >= diff1: 

332 
l.y = 0.5*(bounds1[3]bounds1[1]) 

333 
B[r] = l.getBounds() 

334 
iter += 1 

335 

2543  336 
def intervalIntersection(A,B): 
337 
x,y = max(min(A),min(B)),min(max(A),max(B)) 

338 
if x>=y: return None 

339 
return x,y 

340 

341 
def _makeSideArcDefs(sa,direction): 

342 
sa %= 360 

343 
if 90<=sa<270: 

344 
if direction=='clockwise': 

345 
a = (0,90,sa),(1,90,90),(0,360+sa,90) 

346 
else: 

347 
a = (0,sa,270),(1,270,450),(0,450,360+sa) 

348 
else: 

349 
offs = sa>=270 and 360 or 0 

350 
if direction=='clockwise': 

351 
a = (1,offs90,sa),(0,offs270,offs90),(1,360+sa,offs270) 

352 
else: 

353 
a = (1,sa,offs+90),(0,offs+90,offs+270),(1,offs+270,360+sa) 

354 
return tuple([a for a in a if a[1]<a[2]]) 

355 

3818  356 
def _keyFLA(x,y): 
357 
return cmp(y[1]y[0],x[1]x[0]) 

358 
_keyFLA = functools.cmp_to_key(_keyFLA) 

359 

2543  360 
def _findLargestArc(xArcs,side): 
361 
a = [a[1] for a in xArcs if a[0]==side and a[1] is not None] 

362 
if not a: return None 

3818  363 
if len(a)>1: a.sort(key=_keyFLA) 
2543  364 
return a[0] 
365 

366 
def _fPLSide(l,width,side=None): 

367 
data = l._origdata 

368 
if side is None: 

369 
li = data['li'] 

370 
ri = data['ri'] 

371 
if li is None: 

372 
side = 1 

373 
i = ri 

374 
elif ri is None: 

375 
side = 0 

376 
i = li 

377 
elif li[1]li[0]>ri[1]ri[0]: 

378 
side = 0 

379 
i = li 

380 
else: 

381 
side = 1 

382 
i = ri 

383 
w = data['width'] 

384 
edgePad = data['edgePad'] 

385 
if not side: #on left 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

386 
l._pmv = 180 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

387 
l.x = edgePad+w 
2543  388 
i = data['li'] 
389 
else: 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

390 
l._pmv = 0 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

391 
l.x = width  w  edgePad 
2543  392 
i = data['ri'] 
393 
mid = data['mid'] = (i[0]+i[1])*0.5 

394 
data['smid'] = sin(mid/_180_pi) 

395 
data['cmid'] = cos(mid/_180_pi) 

396 
data['side'] = side 

397 
return side,w 

398 

3818  399 
#key functions 
400 
def _fPLCF(a,b): 

3828  401 
return cmp(b._origdata['smid'],a._origdata['smid']) 
3818  402 
_fPLCF = functools.cmp_to_key(_fPLCF) 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

403 

3818  404 
def _arcCF(a): 
405 
return a[1] 

2543  406 

407 
def _fixPointerLabels(n,L,x,y,width,height,side=None): 

408 
LR = [],[] 

409 
mlr = [0,0] 

410 
for l in L: 

411 
i,w = _fPLSide(l,width,side) 

412 
LR[i].append(l) 

413 
mlr[i] = max(w,mlr[i]) 

414 
mul = 1 

415 
G = n*[None] 

416 
mel = 0 

417 
hh = height*0.5 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

418 
yhh = y+hh 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

419 
m = max(mlr) 
2543  420 
for i in (0,1): 
421 
T = LR[i] 

422 
if T: 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

423 
B = [] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

424 
aB = B.append 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

425 
S = [] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

426 
aS = S.append 
3818  427 
T.sort(key=_fPLCF) 
2543  428 
p = 0 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

429 
yh = y+height 
2543  430 
for l in T: 
431 
data = l._origdata 

432 
inc = x+mul*(mdata['width']) 

433 
l.x += inc 

434 
G[data['index']] = l 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

435 
ly = yhh+data['smid']*hh 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

436 
b = data['bounds'] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

437 
b2 = (b[3]b[1])*0.5 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

438 
if ly+b2>yh: ly = yhb2 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

439 
if lyb2<y: ly = y+b2 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

440 
data['bounds'] = b = (b[0],lyb2,b[2],ly+b2) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

441 
aB(b) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

442 
l.y = ly 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

443 
aS(max(0,yhlyb2)) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

444 
yh = lyb2 
2543  445 
p = max(p,data['edgePad']+data['piePad']) 
446 
mel = max(mel,abs(data['smid']*(hh+data['elbowLength']))hh) 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

447 
aS(yhy) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

448 

5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

449 
iter = 0 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

450 
nT = len(T) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

451 
while iter<30: 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

452 
R = findOverlapRun(B,wrap=0) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

453 
if not R: break 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

454 
nR = len(R) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

455 
if nR==nT: break 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

456 
j0 = R[0] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

457 
j1 = R[1] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

458 
jl = j1+1 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

459 
sAbove = sum(S[:j0+1]) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

460 
sFree = sAbove+sum(S[jl:]) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

461 
sNeed = sum([b[3]b[1] for b in B[j0:jl]])+jlj0(B[j0][3]B[j1][1]) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

462 
if sNeed>sFree: break 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

463 
yh = B[j0][3]+sAbove*sNeed/sFree 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

464 
for r in R: 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

465 
l = T[r] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

466 
data = l._origdata 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

467 
b = data['bounds'] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

468 
b2 = (b[3]b[1])*0.5 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

469 
yh = 0.5 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

470 
ly = l.y = yhb2 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

471 
B[r] = data['bounds'] = (b[0],lyb2,b[2],yh) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

472 
yh = ly  b2  0.5 
2543  473 
mlr[i] = m+p 
474 
mul = 1 

475 
return G, mlr[0], mlr[1], mel 

476 

3580  477 
def theta0(data, direction): 
478 
fac = (2*pi)/sum(data) 

479 
rads = [d*fac for d in data] 

480 

481 
r0 = 0 

482 
hrads = [] 

483 
for r in rads: 

484 
hrads.append(r0+r*0.5) 

485 
r0 += r 

486 

487 
vstar = len(data)*1e6 

488 
rstar = 0 

489 
delta = pi/36.0 

3721  490 
for i in range(36): 
3580  491 
r = i*delta 
492 
v = sum([abs(sin(r+a)) for a in hrads]) 

493 
if v < vstar: 

494 
if direction == 'clockwise': 

495 
rstar=r 

496 
else: 

497 
rstar=r 

498 
vstar = v 

499 
return rstar*180/pi 

500 

501 

3387  502 
class AngleData(float): 
503 
'''use this to carry the data along with the angle''' 

504 
def __new__(cls,angle,data): 

505 
self = float.__new__(cls,angle) 

506 
self._data = data 

507 
return self 

508 

2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

509 
class Pie(AbstractPieChart): 
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

510 
_attrMap = AttrMap(BASE=AbstractPieChart, 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

511 
data = AttrMapValue(isListOfNumbers, desc='List of numbers defining wedge sizes; need not sum to 1'), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

512 
labels = AttrMapValue(isListOfStringsOrNone, desc="Optional list of labels to use for each data point"), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

513 
startAngle = AttrMapValue(isNumber, desc="Angle of first slice; 0 is due East"), 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

514 
direction = AttrMapValue(OneOf('clockwise', 'anticlockwise'), desc="'clockwise' or 'anticlockwise'"), 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

515 
slices = AttrMapValue(None, desc="Collection of wedge descriptor objects"), 
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

516 
simpleLabels = AttrMapValue(isBoolean, desc="If true(default) use a simple String not an advanced WedgeLabel. A WedgeLabel is customisable using the properties prefixed label_ in the collection slices."), 
3270  517 
other_threshold = AttrMapValue(isNumber, desc='A value for doing threshholding, not used yet.',advancedUsage=1), 
518 
checkLabelOverlap = AttrMapValue(isBoolean, desc="If true check and attempt to fix\n standard label overlaps(default off)",advancedUsage=1), 

519 
pointerLabelMode = AttrMapValue(OneOf(None,'LeftRight','LeftAndRight'), desc='',advancedUsage=1), 

520 
sameRadii = AttrMapValue(isBoolean, desc="If true make x/y radii the same(default off)",advancedUsage=1), 

521 
orderMode = AttrMapValue(OneOf('fixed','alternate'),advancedUsage=1), 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

522 
xradius = AttrMapValue(isNumberOrNone, desc="X direction Radius"), 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

523 
yradius = AttrMapValue(isNumberOrNone, desc="Y direction Radius"), 
3671  524 
innerRadiusFraction = AttrMapValue(isNumberOrNone, desc="fraction of radii to start wedges at"), 
3387  525 
wedgeRecord = AttrMapValue(None, desc="callable(wedge,*args,**kwds)",advancedUsage=1), 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

526 
sideLabels = AttrMapValue(isBoolean, desc="If true attempt to make piechart with labels along side and pointers"), 
3586  527 
sideLabelsOffset = AttrMapValue(isNumber, desc="The fraction of the pie width that the labels are situated at from the edges of the pie"), 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

528 
) 
2019  529 
other_threshold=None 
1683  530 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

531 
def __init__(self,**kwd): 
2543  532 
PlotArea.__init__(self) 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

533 
self.x = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

534 
self.y = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

535 
self.width = 100 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

536 
self.height = 100 
2427
1de04210b407
charts: autolegending in place, legend now has boxAnchor
rgbecker
parents:
2420
diff
changeset

537 
self.data = [1,2.3,1.7,4.2] 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

538 
self.labels = None # or list of strings 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

539 
self.startAngle = 90 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

540 
self.direction = "clockwise" 
1961
eb03e38caf87
Allow for proper labels in piechart and some clean ups
rgbecker
parents:
1937
diff
changeset

541 
self.simpleLabels = 1 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

542 
self.checkLabelOverlap = 0 
2543  543 
self.pointerLabelMode = None 
544 
self.sameRadii = False 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

545 
self.orderMode = 'fixed' 
3671  546 
self.xradius = self.yradius = self.innerRadiusFraction = None 
3580  547 
self.sideLabels = 0 
3586  548 
self.sideLabelsOffset = 0.1 
1683  549 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

550 
self.slices = TypedPropertyCollection(WedgeProperties) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

551 
self.slices[0].fillColor = colors.darkcyan 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

552 
self.slices[1].fillColor = colors.blueviolet 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

553 
self.slices[2].fillColor = colors.blue 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

554 
self.slices[3].fillColor = colors.cyan 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

555 
self.slices[4].fillColor = colors.pink 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

556 
self.slices[5].fillColor = colors.magenta 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

557 
self.slices[6].fillColor = colors.yellow 
916
de1bbc3958c3
Made more consistent use of typed collections.
dinu_gherman
parents:
909
diff
changeset

558 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

559 
def demo(self): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

560 
d = Drawing(200, 100) 
1683  561 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

562 
pc = Pie() 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

563 
pc.x = 50 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

564 
pc.y = 10 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

565 
pc.width = 100 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

566 
pc.height = 80 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

567 
pc.data = [10,20,30,40,50,60] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

568 
pc.labels = ['a','b','c','d','e','f'] 
907  569 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

570 
pc.slices.strokeWidth=0.5 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

571 
pc.slices[3].popout = 10 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

572 
pc.slices[3].strokeWidth = 2 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

573 
pc.slices[3].strokeDashArray = [2,2] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

574 
pc.slices[3].labelRadius = 1.75 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

575 
pc.slices[3].fontColor = colors.red 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

576 
pc.slices[0].fillColor = colors.darkcyan 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

577 
pc.slices[1].fillColor = colors.blueviolet 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

578 
pc.slices[2].fillColor = colors.blue 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

579 
pc.slices[3].fillColor = colors.cyan 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

580 
pc.slices[4].fillColor = colors.aquamarine 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

581 
pc.slices[5].fillColor = colors.cadetblue 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

582 
pc.slices[6].fillColor = colors.lightcoral 
907  583 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

584 
d.add(pc) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

585 
return d 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

586 

2543  587 
def makePointerLabels(self,angles,plMode): 
588 
class PL: 

589 
def __init__(self,centerx,centery,xradius,yradius,data,lu=0,ru=0): 

590 
self.centerx = centerx 

591 
self.centery = centery 

592 
self.xradius = xradius 

593 
self.yradius = yradius 

594 
self.data = data 

595 
self.lu = lu 

596 
self.ru = ru 

597 

598 
labelX = self.width2 

599 
labelY = self.height 

600 
n = nr = nl = maxW = sumH = 0 

601 
styleCount = len(self.slices) 

602 
L=[] 

603 
L_add = L.append 

604 
refArcs = _makeSideArcDefs(self.startAngle,self.direction) 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

605 
for i, A in angles: 
2543  606 
if A[1] is None: continue 
607 
sn = self.getSeriesName(i,'') 

608 
if not sn: continue 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

609 
style = self.slices[i%styleCount] 
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

610 
if not style.label_visible or not style.visible: continue 
2543  611 
n += 1 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

612 
l=_addWedgeLabel(self,sn,180,labelX,labelY,style,labelClass=WedgeLabel) 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

613 
L_add(l) 
2543  614 
b = l.getBounds() 
615 
w = b[2]b[0] 

616 
h = b[3]b[1] 

617 
ri = [(a[0],intervalIntersection(A,(a[1],a[2]))) for a in refArcs] 

618 
li = _findLargestArc(ri,0) 

619 
ri = _findLargestArc(ri,1) 

620 
if li and ri: 

621 
if plMode=='LeftAndRight': 

622 
if li[1]li[0]<ri[1]ri[0]: 

623 
li = None 

624 
else: 

625 
ri = None 

626 
else: 

627 
if li[1]li[0]<0.02*(ri[1]ri[0]): 

628 
li = None 

629 
elif (li[1]li[0])*0.02>ri[1]ri[0]: 

630 
ri = None 

631 
if ri: nr += 1 

632 
if li: nl += 1 

633 
l._origdata = dict(bounds=b,width=w,height=h,li=li,ri=ri,index=i,edgePad=style.label_pointer_edgePad,piePad=style.label_pointer_piePad,elbowLength=style.label_pointer_elbowLength) 

634 
maxW = max(w,maxW) 

635 
sumH += h+2 

636 

637 
if not n: #we have no labels 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

638 
xradius = self.width*0.5 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

639 
yradius = self.height*0.5 
2543  640 
centerx = self.x+xradius 
641 
centery = self.y+yradius 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

642 
if self.xradius: xradius = self.xradius 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

643 
if self.yradius: yradius = self.yradius 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

644 
if self.sameRadii: xradius=yradius=min(xradius,yradius) 
2543  645 
return PL(centerx,centery,xradius,yradius,[]) 
646 

647 
aonR = nr==n 

648 
if sumH<self.height and (aonR or nl==n): 

649 
side=int(aonR) 

650 
else: 

651 
side=None 

652 
G,lu,ru,mel = _fixPointerLabels(len(angles),L,self.x,self.y,self.width,self.height,side=side) 

653 
if plMode=='LeftAndRight': 

654 
lu = ru = max(lu,ru) 

655 
x0 = self.x+lu 

656 
x1 = self.x+self.widthru 

657 
xradius = (x1x0)*0.5 

658 
yradius = self.height*0.5mel 

659 
centerx = x0+xradius 

660 
centery = self.y+yradius+mel 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

661 
if self.xradius: xradius = self.xradius 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

662 
if self.yradius: yradius = self.yradius 
2543  663 
if self.sameRadii: xradius=yradius=min(xradius,yradius) 
664 
return PL(centerx,centery,xradius,yradius,G,lu,ru) 

665 

3387  666 
def normalizeData(self,keepData=False): 
3721  667 
data = list(map(abs,self.data)) 
2835  668 
s = self._sum = float(sum(data)) 
4234
0137ff8f82d7
remove scale assumption and allow all zero data (issue raised by Michael Spector & bitbucket)
robin
parents:
3828
diff
changeset

669 
f = 360./s if s!=0 else 1 
3387  670 
if keepData: 
671 
return [AngleData(f*x,x) for x in data] 

672 
else: 

2835  673 
return [f*x for x in data] 
922  674 

2543  675 
def makeAngles(self): 
3387  676 
wr = getattr(self,'wedgeRecord',None) 
3580  677 
if self.sideLabels: 
678 
startAngle = theta0(self.data, self.direction) 

679 
self.slices.label_visible = 1 

680 
else: 

681 
startAngle = self.startAngle % 360 

2543  682 
whichWay = self.direction == "clockwise" and 1 or 1 
3387  683 
D = [a for a in enumerate(self.normalizeData(keepData=wr))] 
3580  684 
if self.orderMode=='alternate' and not self.sideLabels: 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

685 
W = [a for a in D if abs(a[1])>=1e5] 
3818  686 
W.sort(key=_arcCF) 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

687 
T = [[],[]] 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

688 
i = 0 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

689 
while W: 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

690 
if i<2: 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

691 
a = W.pop(0) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

692 
else: 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

693 
a = W.pop(1) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

694 
T[i%2].append(a) 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

695 
i += 1 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

696 
i %= 4 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

697 
T[1].reverse() 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

698 
D = T[0]+T[1] + [a for a in D if abs(a[1])<1e5] 
2543  699 
A = [] 
700 
a = A.append 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

701 
for i, angle in D: 
2543  702 
endAngle = (startAngle + (angle * whichWay)) 
3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

703 
if abs(angle)>=_ANGLELO: 
2543  704 
if startAngle >= endAngle: 
705 
aa = endAngle,startAngle 

706 
else: 

707 
aa = startAngle,endAngle 

708 
else: 

709 
aa = startAngle, None 

3387  710 
if wr: 
711 
aa = (AngleData(aa[0],angle._data),aa[1]) 

2543  712 
startAngle = endAngle 
2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

713 
a((i,aa)) 
2543  714 
return A 
715 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

716 
def makeWedges(self): 
2543  717 
angles = self.makeAngles() 
3580  718 
#Checking to see whether there are too many wedges packed in too small a space 
719 
halfAngles = [] 

720 
for i,(a1,a2) in angles: 

721 
if a2 is None: 

722 
halfAngle = a1 

723 
else: 

724 
halfAngle = 0.5*(a2+a1) 

725 
halfAngles.append(halfAngle) 

726 
sideLabels = self.sideLabels 

2543  727 
n = len(angles) 
2017  728 
labels = _fixLabels(self.labels,n) 
3387  729 
wr = getattr(self,'wedgeRecord',None) 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

730 

2543  731 
self._seriesCount = n 
732 
styleCount = len(self.slices) 

916
de1bbc3958c3
Made more consistent use of typed collections.
dinu_gherman
parents:
909
diff
changeset

733 

2543  734 
plMode = self.pointerLabelMode 
3580  735 
if sideLabels: 
3594
4e090d6bebed
New version of piecharts with new function side labels, documentation and new samples
guillaume
parents:
3590
diff
changeset

736 
plMode = None 
2543  737 
if plMode: 
738 
checkLabelOverlap = False 

739 
PL=self.makePointerLabels(angles,plMode) 

740 
xradius = PL.xradius 

741 
yradius = PL.yradius 

742 
centerx = PL.centerx 

743 
centery = PL.centery 

744 
PL_data = PL.data 

745 
gSN = lambda i: '' 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

746 
else: 
2543  747 
xradius = self.width*0.5 
748 
yradius = self.height*0.5 

749 
centerx = self.x + xradius 

750 
centery = self.y + yradius 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

751 
if self.xradius: xradius = self.xradius 
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

752 
if self.yradius: yradius = self.yradius 
2543  753 
if self.sameRadii: xradius=yradius=min(xradius,yradius) 
754 
checkLabelOverlap = self.checkLabelOverlap 

755 
gSN = lambda i: self.getSeriesName(i,'') 

921  756 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

757 
g = Group() 
2543  758 
g_add = g.add 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

759 
L = [] 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

760 
L_add = L.append 
2543  761 

3671  762 
innerRadiusFraction = self.innerRadiusFraction 
763 

2549
5978153b84b0
piecharts: now have orderMode 'alternate' and proper vertical spreading
rgbecker
parents:
2543
diff
changeset

764 
for i,(a1,a2) in angles: 
2543  765 
if a2 is None: continue 
766 
#if we didn't use %stylecount here we'd end up with the later wedges 

767 
#all having the default style 

768 
wedgeStyle = self.slices[i%styleCount] 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

769 
if not wedgeStyle.visible: continue 
3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

770 
aa = abs(a2a1) 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

771 

2543  772 
# is it a popout? 
773 
cx, cy = centerx, centery 

774 
text = gSN(i) 

775 
popout = wedgeStyle.popout 

776 
if text or popout: 

777 
averageAngle = (a1+a2)/2.0 

778 
aveAngleRadians = averageAngle/_180_pi 

779 
cosAA = cos(aveAngleRadians) 

780 
sinAA = sin(aveAngleRadians) 

3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

781 
if popout and aa<_ANGLEHI: 
2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

782 
# pop out the wedge 
2543  783 
cx = centerx + popout*cosAA 
784 
cy = centery + popout*sinAA 

883
ddfef4e6e647
Removed sector line for single sliced pie charts.
dinu_gherman
parents:
817
diff
changeset

785 

3671  786 
if innerRadiusFraction: 
787 
theWedge = Wedge(cx, cy, xradius, a1, a2, yradius=yradius, 

788 
radius1=xradius*innerRadiusFraction,yradius1=yradius*innerRadiusFraction) 

3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

789 
else: 
3671  790 
if aa>=_ANGLEHI: 
791 
theWedge = Ellipse(cx, cy, xradius, yradius) 

792 
else: 

793 
theWedge = Wedge(cx, cy, xradius, a1, a2, yradius=yradius) 

794 

973  795 

2543  796 
theWedge.fillColor = wedgeStyle.fillColor 
797 
theWedge.strokeColor = wedgeStyle.strokeColor 

798 
theWedge.strokeWidth = wedgeStyle.strokeWidth 

3227
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

799 
theWedge.strokeLineJoin = wedgeStyle.strokeLineJoin 
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

800 
theWedge.strokeLineCap = wedgeStyle.strokeLineCap 
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

801 
theWedge.strokeMiterLimit = wedgeStyle.strokeMiterLimit 
750fe33ccd5e
piecharts.py: add wedge stroke propertiels and set default LineJoin=1
rgbecker
parents:
3032
diff
changeset

802 
theWedge.strokeWidth = wedgeStyle.strokeWidth 
2543  803 
theWedge.strokeDashArray = wedgeStyle.strokeDashArray 
883
ddfef4e6e647
Removed sector line for single sliced pie charts.
dinu_gherman
parents:
817
diff
changeset

804 

2543  805 
g_add(theWedge) 
3387  806 
if wr: 
807 
wr(theWedge,value=a1._data,label=text) 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

808 
if wedgeStyle.label_visible: 
3580  809 
if not sideLabels: 
810 
if text: 

811 
labelRadius = wedgeStyle.labelRadius 

812 
rx = xradius*labelRadius 

813 
ry = yradius*labelRadius 

814 
labelX = cx + rx*cosAA 

815 
labelY = cy + ry*sinAA 

816 
l = _addWedgeLabel(self,text,averageAngle,labelX,labelY,wedgeStyle) 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

817 
L_add(l) 
3580  818 
if not plMode and l._simple_pointer: 
819 
l._aax = cx+xradius*cosAA 

820 
l._aay = cy+yradius*sinAA 

821 
if checkLabelOverlap: 

822 
l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 

823 
'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 

824 
'bounds': l.getBounds(), 

825 
} 

826 
elif plMode and PL_data: 

827 
l = PL_data[i] 

828 
if l: 

829 
data = l._origdata 

830 
sinM = data['smid'] 

831 
cosM = data['cmid'] 

832 
lX = cx + xradius*cosM 

833 
lY = cy + yradius*sinM 

834 
lpel = wedgeStyle.label_pointer_elbowLength 

835 
lXi = lX + lpel*cosM 

836 
lYi = lY + lpel*sinM 

837 
L_add(PolyLine((lX,lY,lXi,lYi,l.x,l.y), 

838 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 

839 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 

840 
L_add(l) 

841 
else: 

842 
if text: 

843 
slices_popout = self.slices.popout 

844 
m=0 

845 
for n, angle in angles: 

846 
if self.slices[n].fillColor: 

847 
m += 1 

848 
else: 

849 
r = n%m 

850 
self.slices[n].fillColor = self.slices[r].fillColor 

851 
self.slices[n].popout = self.slices[r].popout 

852 
for j in range(0,m1): 

853 
if self.slices[j].popout > slices_popout: 

854 
slices_popout = self.slices[j].popout 

855 
labelRadius = wedgeStyle.labelRadius 

856 
ry = yradius*labelRadius 

857 
if (abs(averageAngle) < 90 ) or (averageAngle >270 and averageAngle <450) or (450< 

858 
averageAngle <270): 

3586  859 
labelX = (1+self.sideLabelsOffset)*self.width + self.x + slices_popout 
3580  860 
rx = 0 
861 
else: 

3586  862 
labelX = self.x  (self.sideLabelsOffset)*self.width  slices_popout 
3580  863 
rx = 0 
864 
labelY = cy + ry*sinAA 

865 
l = _addWedgeLabel(self,text,averageAngle,labelX,labelY,wedgeStyle) 

866 
L_add(l) 

867 
if not plMode: 

868 
l._aax = cx+xradius*cosAA 

869 
l._aay = cy+yradius*sinAA 

870 
if checkLabelOverlap: 

871 
l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 

872 
'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 

873 
'bounds': l.getBounds(), 

874 
} 

875 
x1,y1,x2,y2 = l.getBounds() 

876 

2696
add3a2702a41
piecharts.py: allow wedges/wedge labels to be invisible
rgbecker
parents:
2689
diff
changeset

877 
if checkLabelOverlap and L: 
3580  878 
fixLabelOverlaps(L, sideLabels) 
3330  879 
for l in L: g_add(l) 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

880 

881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

881 
if not plMode: 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

882 
for l in L: 
3580  883 
if l._simple_pointer and not sideLabels: 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

884 
g_add(Line(l.x,l.y,l._aax,l._aay, 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

885 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

886 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 
3580  887 
elif sideLabels: 
888 
x1,y1,x2,y2 = l.getBounds() 

889 
#add pointers 

3586  890 
if l.x == (1+self.sideLabelsOffset)*self.width + self.x: 
3580  891 
g_add(Line(l._aax,l._aay,0.5*(l._aax+l.x),l.y+(0.25*(y2y1)), 
892 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 

893 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 

894 
g_add(Line(0.5*(l._aax+l.x),l.y+(0.25*(y2y1)),l.x,l.y+(0.25*(y2y1)), 

895 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 

896 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 

897 
else: 

898 
g_add(Line(l._aax,l._aay,0.5*(l._aax+l.x),l.y+(0.25*(y2y1)), 

899 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 

900 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 

901 
g_add(Line(0.5*(l._aax+l.x),l.y+(0.25*(y2y1)),l.x,l.y+(0.25*(y2y1)), 

902 
strokeWidth=wedgeStyle.label_pointer_strokeWidth, 

903 
strokeColor=wedgeStyle.label_pointer_strokeColor)) 

2518
355bc0c6c71f
reportlab/graphics/charts: better piechart labels
rgbecker
parents:
2432
diff
changeset

904 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

905 
return g 
737
8f0e58918da9
Initial checkin, replacing previous trailing digit filenames.
dinu_gherman
parents:
diff
changeset

906 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

907 
def draw(self): 
2543  908 
G = self.makeBackground() 
909 
w = self.makeWedges() 

910 
if G: return Group(G,w) 

911 
return w 

922  912 

1620  913 
class LegendedPie(Pie): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

914 
"""Pie with a two part legend (one editable with swatches, one hidden without swatches).""" 
1620  915 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

916 
_attrMap = AttrMap(BASE=Pie, 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

917 
drawLegend = AttrMapValue(isBoolean, desc="If true then create and draw legend"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

918 
legend1 = AttrMapValue(None, desc="Handle to legend for pie"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

919 
legendNumberFormat = AttrMapValue(None, desc="Formatting routine for number on right hand side of legend."), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

920 
legendNumberOffset = AttrMapValue(isNumber, desc="Horizontal space between legend and numbers on r/hand side"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

921 
pieAndLegend_colors = AttrMapValue(isListOfColors, desc="Colours used for both swatches and pie"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

922 
legend_names = AttrMapValue(isNoneOrListOfNoneOrStrings, desc="Names used in legend (or None)"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

923 
legend_data = AttrMapValue(isNoneOrListOfNoneOrNumbers, desc="Numbers used on r/hand side of legend (or None)"), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

924 
leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

925 
rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

926 
topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

927 
bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

928 
) 
1620  929 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

930 
def __init__(self): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

931 
Pie.__init__(self) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

932 
self.x = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

933 
self.y = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

934 
self.height = 100 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

935 
self.width = 100 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

936 
self.data = [38.4, 20.7, 18.9, 15.4, 6.6] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

937 
self.labels = None 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

938 
self.direction = 'clockwise' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

939 
PCMYKColor, black = colors.PCMYKColor, colors.black 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

940 
self.pieAndLegend_colors = [PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

941 
PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV'), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

942 
PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV',density=75), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

943 
PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV',density=75), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

944 
PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV',density=50), 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

945 
PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV',density=50)] 
1620  946 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

947 
#Allows us up to six 'wedges' to be coloured 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

948 
self.slices[0].fillColor=self.pieAndLegend_colors[0] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

949 
self.slices[1].fillColor=self.pieAndLegend_colors[1] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

950 
self.slices[2].fillColor=self.pieAndLegend_colors[2] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

951 
self.slices[3].fillColor=self.pieAndLegend_colors[3] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

952 
self.slices[4].fillColor=self.pieAndLegend_colors[4] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

953 
self.slices[5].fillColor=self.pieAndLegend_colors[5] 
1620  954 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

955 
self.slices.strokeWidth = 0.75 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

956 
self.slices.strokeColor = black 
1620  957 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

958 
legendOffset = 17 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

959 
self.legendNumberOffset = 51 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

960 
self.legendNumberFormat = '%.1f%%' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

961 
self.legend_data = self.data 
1620  962 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

963 
#set up the legends 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

964 
from reportlab.graphics.charts.legends import Legend 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

965 
self.legend1 = Legend() 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

966 
self.legend1.x = self.width+legendOffset 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

967 
self.legend1.y = self.height 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

968 
self.legend1.deltax = 5.67 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

969 
self.legend1.deltay = 14.17 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

970 
self.legend1.dxTextSpace = 11.39 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

971 
self.legend1.dx = 5.67 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

972 
self.legend1.dy = 5.67 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

973 
self.legend1.columnMaximum = 7 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

974 
self.legend1.alignment = 'right' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

975 
self.legend_names = ['AAA:','AA:','A:','BBB:','NR:'] 
3721  976 
for f in range(len(self.data)): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

977 
self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], self.legend_names[f])) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

978 
self.legend1.fontName = "HelveticaBold" 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

979 
self.legend1.fontSize = 6 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

980 
self.legend1.strokeColor = black 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

981 
self.legend1.strokeWidth = 0.5 
1620  982 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

983 
self._legend2 = Legend() 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

984 
self._legend2.dxTextSpace = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

985 
self._legend2.dx = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

986 
self._legend2.alignment = 'right' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

987 
self._legend2.fontName = "HelveticaOblique" 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

988 
self._legend2.fontSize = 6 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

989 
self._legend2.strokeColor = self.legend1.strokeColor 
1620  990 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

991 
self.leftPadding = 5 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

992 
self.rightPadding = 5 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

993 
self.topPadding = 5 
1683  994 
self.bottomPadding = 5 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

995 
self.drawLegend = 1 
1620  996 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

997 
def draw(self): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

998 
if self.drawLegend: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

999 
self.legend1.colorNamePairs = [] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1000 
self._legend2.colorNamePairs = [] 
3721  1001 
for f in range(len(self.data)): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1002 
if self.legend_names == None: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1003 
self.slices[f].fillColor = self.pieAndLegend_colors[f] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1004 
self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], None)) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1005 
else: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1006 
try: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1007 
self.slices[f].fillColor = self.pieAndLegend_colors[f] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1008 
self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], self.legend_names[f])) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1009 
except IndexError: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1010 
self.slices[f].fillColor = self.pieAndLegend_colors[f%len(self.pieAndLegend_colors)] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1011 
self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f%len(self.pieAndLegend_colors)], self.legend_names[f])) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1012 
if self.legend_data != None: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1013 
ldf = self.legend_data[f] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1014 
lNF = self.legendNumberFormat 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1015 
if ldf is None or lNF is None: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1016 
pass 
3800  1017 
elif isinstance(lNF,str): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1018 
ldf = lNF % ldf 
3326  1019 
elif hasattr(lNF,'__call__'): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1020 
ldf = lNF(ldf) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1021 
else: 
3800  1022 
raise ValueError("Unknown formatter type %s, expected string or function" % ascii(self.legendNumberFormat)) 
1023 
self._legend2.colorNamePairs.append((None,ldf)) 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1024 
p = Pie.draw(self) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1025 
if self.drawLegend: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1026 
p.add(self.legend1) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1027 
#hide from user  keeps both sides lined up! 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1028 
self._legend2.x = self.legend1.x+self.legendNumberOffset 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1029 
self._legend2.y = self.legend1.y 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1030 
self._legend2.deltax = self.legend1.deltax 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1031 
self._legend2.deltay = self.legend1.deltay 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1032 
self._legend2.dy = self.legend1.dy 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1033 
self._legend2.columnMaximum = self.legend1.columnMaximum 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1034 
p.add(self._legend2) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1035 
p.shift(self.leftPadding, self.bottomPadding) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1036 
return p 
1620  1037 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1038 
def _getDrawingDimensions(self): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1039 
tx = self.rightPadding 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1040 
if self.drawLegend: 
3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

1041 
tx += self.legend1.x+self.legendNumberOffset #self._legend2.x 
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

1042 
tx += self._legend2._calculateMaxWidth(self._legend2.colorNamePairs) 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1043 
ty = self.bottomPadding+self.height+self.topPadding 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1044 
return (tx,ty) 
1620  1045 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1046 
def demo(self, drawing=None): 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1047 
if not drawing: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1048 
tx,ty = self._getDrawingDimensions() 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1049 
drawing = Drawing(tx, ty) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1050 
drawing.add(self.draw()) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1662
diff
changeset

1051 
return drawing 
1620  1052 

3580  1053 
from reportlab.graphics.charts.utils3d import _getShaded, _2rad, _360, _pi_2, _2pi, _180_pi 
2017  1054 
class Wedge3dProperties(PropHolder): 
1055 
"""This holds descriptive information about the wedges in a pie chart. 

1056 

1057 
It is not to be confused with the 'wedge itself'; this just holds 

1058 
a recipe for how to format one, and does not allow you to hack the 

1059 
angles. It can format a genuine Wedge object for you with its 

1060 
format method. 

1061 
""" 

1062 
_attrMap = AttrMap( 

3270  1063 
fillColor = AttrMapValue(isColorOrNone,desc=''), 
1064 
fillColorShaded = AttrMapValue(isColorOrNone,desc=''), 

1065 
fontColor = AttrMapValue(isColorOrNone,desc=''), 

1066 
fontName = AttrMapValue(isString,desc=''), 

1067 
fontSize = AttrMapValue(isNumber,desc=''), 

1068 
label_angle = AttrMapValue(isNumber,desc=''), 

2017  1069 
label_bottomPadding = AttrMapValue(isNumber,'padding at bottom of box'), 
3270  1070 
label_boxAnchor = AttrMapValue(isBoxAnchor,desc=''), 
1071 
label_boxFillColor = AttrMapValue(isColorOrNone,desc=''), 

1072 
label_boxStrokeColor = AttrMapValue(isColorOrNone,desc=''), 

1073 
label_boxStrokeWidth = AttrMapValue(isNumber,desc=''), 

1074 
label_dx = AttrMapValue(isNumber,desc=''), 

1075 
label_dy = AttrMapValue(isNumber,desc=''), 

1076 
label_height = AttrMapValue(isNumberOrNone,desc=''), 

1077 
label_leading = AttrMapValue(isNumberOrNone,desc=''), 

2017  1078 
label_leftPadding = AttrMapValue(isNumber,'padding at left of box'), 
3270  1079 
label_maxWidth = AttrMapValue(isNumberOrNone,desc=''), 
2017  1080 
label_rightPadding = AttrMapValue(isNumber,'padding at right of box'), 
3238
77cfc01cb26c
piecharts.py: fix simple pointers attibute in 3d wedges
rgbecker
parents:
3227
diff
changeset

1081 
label_simple_pointer = AttrMapValue(isBoolean,'set to True for simple pointers'), 
3270  1082 
label_strokeColor = AttrMapValue(isColorOrNone,desc=''), 
1083 
label_strokeWidth = AttrMapValue(isNumber,desc=''), 

1084 
label_text = AttrMapValue(isStringOrNone,desc=''), 

1085 
label_textAnchor = AttrMapValue(isTextAnchor,desc=''), 

2017  1086 
label_topPadding = AttrMapValue(isNumber,'padding at top of box'), 
1087 
label_visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), 

3270  1088 
label_width = AttrMapValue(isNumberOrNone,desc=''), 
1089 
labelRadius = AttrMapValue(isNumber,desc=''), 

1090 
popout = AttrMapValue(isNumber,desc=''), 

1091 
shading = AttrMapValue(isNumber,desc=''), 

1092 
strokeColor = AttrMapValue(isColorOrNone,desc=''), 

1093 
strokeColorShaded = AttrMapValue(isColorOrNone,desc=''), 

1094 
strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc=''), 

1095 
strokeWidth = AttrMapValue(isNumber,desc=''), 

2017  1096 
visible = AttrMapValue(isBoolean,'set to false to skip displaying'), 
1097 
) 

1098 

1099 
def __init__(self): 

1100 
self.strokeWidth = 0 

1101 
self.shading = 0.3 

1102 
self.visible = 1 

1103 
self.strokeColorShaded = self.fillColorShaded = self.fillColor = None 

1104 
self.strokeColor = STATE_DEFAULTS["strokeColor"] 

1105 
self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] 

1106 
self.popout = 0 

1107 
self.fontName = STATE_DEFAULTS["fontName"] 

1108 
self.fontSize = STATE_DEFAULTS["fontSize"] 

1109 
self.fontColor = STATE_DEFAULTS["fillColor"] 

1110 
self.labelRadius = 1.2 

1111 
self.label_dx = self.label_dy = self.label_angle = 0 

1112 
self.label_text = None 

1113 
self.label_topPadding = self.label_leftPadding = self.label_rightPadding = self.label_bottomPadding = 0 

3016
881516600936
piecharts.py: simple pointers for nonsimple labels
rgbecker
parents:
2964
diff
changeset

1114 
self.label_boxAnchor = 'autox' 
2017  1115 
self.label_boxStrokeColor = None #boxStroke 
1116 
self.label_boxStrokeWidth = 0.5 #boxStrokeWidth 

1117 
self.label_boxFillColor = None 

1118 
self.label_strokeColor = None 

1119 
self.label_strokeWidth = 0.1 

1120 
self.label_leading = self.label_width = self.label_maxWidth = self.label_height = None 

1121 
self.label_textAnchor = 'start' 

1122 
self.label_visible = 1 

3238
77cfc01cb26c
piecharts.py: fix simple pointers attibute in 3d wedges
rgbecker
parents:
3227
diff
changeset

1123 
self.label_simple_pointer = 0 
2017  1124 

1125 
class _SL3D: 

1126 
def __init__(self,lo,hi): 

1127 
if lo<0: 

1128 
lo += 360 

1129 
hi += 360 

1130 
self.lo = lo 

1131 
self.hi = hi 

1132 
self.mid = (lo+hi)*0.5 

3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

1133 
self.not360 = abs(hilo) < _ANGLEHI 
2017  1134 

1135 
def __str__(self): 

1136 
return '_SL3D(%.2f,%.2f)' % (self.lo,self.hi) 

1137 

3818  1138 
def _keyS3D(a,b): 
1139 
return cmp(a[0],b[0]) 

1140 
_keyS3D = functools.cmp_to_key(_keyS3D) 

1141 

2039  1142 
_270r = _2rad(270) 
2019  1143 
class Pie3d(Pie): 
1144 
_attrMap = AttrMap(BASE=Pie, 

1145 
perspective = AttrMapValue(isNumber, desc='A flattening parameter.'), 

1146 
depth_3d = AttrMapValue(isNumber, desc='depth of the pie.'), 

1147 
angle_3d = AttrMapValue(isNumber, desc='The view angle.'), 

1148 
) 

2017  1149 
perspective = 70 
2019  1150 
depth_3d = 25 
1151 
angle_3d = 180 

2017  1152 

1153 
def _popout(self,i): 

3474
90bc9414d785
piecharts.py: eliminate wedge line for 360deg slice
rgbecker
parents:
3410
diff
changeset

1154 
return self._sl3d[i].not360 and self.slices[i].popout or 0 
2017  1155 

1156 
def CX(self, i,d ): 

1157 
return self._cx+(d and self._xdepth_3d or 0)+self._popout(i)*cos(_2rad(self._sl3d[i].mid)) 

1158 
def CY(self,i,d): 

1159 
return self._cy+(d and self._ydepth_3d or 0)+self._popout(i)*sin(_2rad(self._sl3d[i].mid)) 

1160 
def OX(self,i,o,d): 

1161 
return self.CX(i,d)+self._radiusx*cos(_2rad(o)) 

1162 
def OY(self,i,o,d): 

1163 
return self.CY(i,d)+self._radiusy*sin(_2rad(o)) 

1164 

1165 
def rad_dist(self,a): 

1166 
_3dva = self._3dva 

1167 
return min(abs(a_3dva),abs(a_3dva+360)) 

1168 

1169 
def __init__(self): 

3638
496a6b99c229
piecharts.py: fix Pie3d __init__ to call its superclass as suggested by Stephan Richter <stephan.richter@gmail.com>
rgbecker
parents:
3617
diff
changeset

1170 
Pie.__init__(self) 
496a6b99c229
piecharts.py: fix Pie3d __init__ to call its superclass as suggested by Stephan Richter <stephan.richter@gmail.com>
rgbecker
parents:
3617
diff
changeset

1171 
self.slices[4].fillColor = colors.azure 
496a6b99c229
piecharts.py: fix Pie3d __init__ to call its superclass as suggested by Stephan Richter <stephan.richter@gmail.com>
r 