[reportlab-users] [patch] value labels for PieChart

Gael Chardon gael.dev at 4now.net
Mon Sep 25 06:28:22 EDT 2006


Hello,
herefater a little patch that add a new feature to PieChart class.
It optionally draw a value (typically the percent) on each slice.

The idea:
- User sets percentFormat slice attribute to a string or a function ;
- Optionally user can set percentFontName, percentFontSize, 
percentFontColor.
- If percentFormat is a string then it is used to format the percent 
value (a float) that represent the slice.
- If percentFormat is callable, the function is called  for every slice 
with two arguments: the current slice value and the sum. The funcion 
should returns the string to draw.

See sample4() in diff file

Hope it helps.

-- 
Gael Chardon
-------------- next part --------------
Index: piecharts.py
===================================================================
--- piecharts.py        (révision 2971)
+++ piecharts.py        (copie de travail)
@@ -15,6 +15,7 @@

 import copy
 from math import sin, cos, pi
+from types import FunctionType, StringType

 from reportlab.lib import colors
 from reportlab.lib.validators import isColor, isNumber, isListOfNumbersOrNone,\
@@ -65,6 +66,10 @@
         fontSize = AttrMapValue(isNumber),
         fontColor = AttrMapValue(isColorOrNone),
         labelRadius = AttrMapValue(isNumber),
+        percentFormat = AttrMapValue(None, desc='Formatting string or function used for wedges label (percent).'),
+        percentFontName = AttrMapValue(isString),
+        percentFontSize = AttrMapValue(isNumber),
+        percentFontColor = AttrMapValue(isColorOrNone),
         label_dx = AttrMapValue(isNumber),
         label_dy = AttrMapValue(isNumber),
         label_angle = AttrMapValue(isNumber),
@@ -120,6 +125,10 @@
         self.label_pointer_elbowLength = 3
         self.label_pointer_edgePad = 2
         self.label_pointer_piePad = 3
+        self.percentFormat = None
+        self.percentFontName = STATE_DEFAULTS["fontName"]
+        self.percentFontSize = STATE_DEFAULTS["fontSize"]
+        self.percentFontColor = STATE_DEFAULTS["fillColor"]

 def _addWedgeLabel(self,text,add,angle,labelX,labelY,wedgeStyle,labelClass=WedgeLabel):
     # now draw a label
@@ -637,7 +646,8 @@
             cx, cy = centerx, centery
             text = gSN(i)
             popout = wedgeStyle.popout
-            if text or popout:
+            percentFormat = wedgeStyle.percentFormat
+            if text or popout or percentFormat:
                 averageAngle = (a1+a2)/2.0
                 aveAngleRadians = averageAngle/_180_pi
                 cosAA = cos(aveAngleRadians)
@@ -658,6 +668,24 @@
             theWedge.strokeDashArray = wedgeStyle.strokeDashArray

             g_add(theWedge)
+
+            if percentFormat:
+                p = float(self.data[i])/self._sum
+                if callable(percentFormat):
+                    percentStr = percentFormat(self.data[i], self._sum)
+                elif type(percentFormat) is StringType:
+                    percentStr = percentFormat % (100.*p)
+                else:
+                    msg = "Unknown formatter type %s, expected string or function" % percentFormat
+                    raise Exception, msg
+                thePercentLabel = String(cx+0.55*(xradius*cosAA), cy+0.55*(yradius*sinAA), percentStr)
+                thePercentLabel.textAnchor = "middle"
+                thePercentLabel.fontSize = wedgeStyle.percentFontSize
+                thePercentLabel.fontName = wedgeStyle.percentFontName
+                thePercentLabel.fillColor = wedgeStyle.percentFontColor
+                thePercentLabel._pmv = averageAngle
+                g_add(thePercentLabel)
+
             if text:
                 labelRadius = wedgeStyle.labelRadius
                 rx = xradius*labelRadius
@@ -1280,3 +1308,36 @@
     d.add(pc)

     return d
+
+def sample4_percent_formatter(value, sum):
+     if sum:
+         text = "%.1f%% (%d)" % (100.*value/sum, value)
+     else:
+         text = ""
+     return text
+
+def sample4():
+    "Make a pie chart with a very slim slice and percent labels."
+
+    d = Drawing(400, 200)
+
+    pc = Pie()
+    pc.x = 125
+    pc.y = 25
+
+    pc.data = [120, 20, 60]
+
+    pc.width = 150
+    pc.height = 150
+    pc.slices.strokeWidth=1#0.5
+    pc.slices[0].fillColor = colors.steelblue
+    pc.slices[1].fillColor = colors.thistle
+    pc.slices[2].fillColor = colors.cornflower
+
+    pc.slices[0].percentFormat = "%.1f%%"
+    pc.slices[1].percentFormat = "%.2f%%"
+    pc.slices[2].percentFormat = sample4_percent_formatter
+
+    d.add(pc)
+
+    return d


More information about the reportlab-users mailing list