| #!/usr/bin/python2.4 |
| # |
| # Copyright 2008 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Code for pie charts.""" |
| |
| import warnings |
| |
| from graphy import common |
| from graphy import util |
| |
| |
| class Segment(common.DataSeries): |
| """A single segment of the pie chart. |
| |
| Object attributes: |
| size: relative size of the segment |
| label: label of the segment (if any) |
| color: color of the segment (if any) |
| """ |
| def __init__(self, size, label=None, color=None): |
| if label is not None and util._IsColor(label): |
| warnings.warn('Your code may be broken! ' |
| 'Label looks like a hex triplet; it might be a color. ' |
| 'The old argument order (color before label) is ' |
| 'deprecated.', |
| DeprecationWarning, stacklevel=2) |
| style = common._BasicStyle(color) |
| super(Segment, self).__init__([size], label=label, style=style) |
| assert size >= 0 |
| |
| def _GetSize(self): |
| return self.data[0] |
| |
| def _SetSize(self, value): |
| assert value >= 0 |
| self.data[0] = value |
| |
| size = property(_GetSize, _SetSize, |
| doc = """The relative size of this pie segment.""") |
| |
| # Since Segments are so simple, provide color for convenience. |
| def _GetColor(self): |
| return self.style.color |
| |
| def _SetColor(self, color): |
| self.style.color = color |
| |
| color = property(_GetColor, _SetColor, |
| doc = """The color of this pie segment.""") |
| |
| |
| class PieChart(common.BaseChart): |
| """Represents a pie chart. |
| |
| The pie chart consists of a single "pie" by default, but additional pies |
| may be added using the AddPie method. The Google Chart API will display |
| the pies as concentric circles, with pie #0 on the inside; other backends |
| may display the pies differently. |
| """ |
| |
| def __init__(self, points=None, labels=None, colors=None): |
| """Constructor for PieChart objects. |
| |
| Creates a pie chart with a single pie. |
| |
| Args: |
| points: A list of data points for the pie chart; |
| i.e., relative sizes of the pie segments |
| labels: A list of labels for the pie segments. |
| TODO: Allow the user to pass in None as one of |
| the labels in order to skip that label. |
| colors: A list of colors for the pie segments, as hex strings |
| (f.ex. '0000ff' for blue). If there are less colors than pie |
| segments, the Google Chart API will attempt to produce a smooth |
| color transition between segments by spreading the colors across |
| them. |
| """ |
| super(PieChart, self).__init__() |
| self.formatters = [] |
| self._colors = None |
| if points: |
| self.AddPie(points, labels, colors) |
| |
| def AddPie(self, points, labels=None, colors=None): |
| """Add a whole pie to the chart. |
| |
| Args: |
| points: A list of pie segment sizes |
| labels: A list of labels for the pie segments |
| colors: A list of colors for the segments. Missing colors will be chosen |
| automatically. |
| Return: |
| The index of the newly added pie. |
| """ |
| num_colors = len(colors or []) |
| num_labels = len(labels or []) |
| pie_index = len(self.data) |
| self.data.append([]) |
| for i, pt in enumerate(points): |
| label = None |
| if i < num_labels: |
| label = labels[i] |
| color = None |
| if i < num_colors: |
| color = colors[i] |
| self.AddSegment(pt, label=label, color=color, pie_index=pie_index) |
| return pie_index |
| |
| def AddSegments(self, points, labels, colors): |
| """DEPRECATED.""" |
| warnings.warn('PieChart.AddSegments is deprecated. Call AddPie instead. ', |
| DeprecationWarning, stacklevel=2) |
| num_colors = len(colors or []) |
| for i, pt in enumerate(points): |
| assert pt >= 0 |
| label = labels[i] |
| color = None |
| if i < num_colors: |
| color = colors[i] |
| self.AddSegment(pt, label=label, color=color) |
| |
| def AddSegment(self, size, label=None, color=None, pie_index=0): |
| """Add a pie segment to this chart, and return the segment. |
| |
| size: The size of the segment. |
| label: The label for the segment. |
| color: The color of the segment, or None to automatically choose the color. |
| pie_index: The index of the pie that will receive the new segment. |
| By default, the chart has one pie (pie #0); use the AddPie method to |
| add more pies. |
| """ |
| if isinstance(size, Segment): |
| warnings.warn("AddSegment(segment) is deprecated. Use AddSegment(size, " |
| "label, color) instead", DeprecationWarning, stacklevel=2) |
| segment = size |
| else: |
| segment = Segment(size, label=label, color=color) |
| assert segment.size >= 0 |
| if pie_index == 0 and not self.data: |
| # Create the default pie |
| self.data.append([]) |
| assert (pie_index >= 0 and pie_index < len(self.data)) |
| self.data[pie_index].append(segment) |
| return segment |
| |
| def AddSeries(self, points, color=None, style=None, markers=None, label=None): |
| """DEPRECATED |
| |
| Add a new segment to the chart and return it. |
| |
| The segment must contain exactly one data point; all parameters |
| other than color and label are ignored. |
| """ |
| warnings.warn('PieChart.AddSeries is deprecated. Call AddSegment or ' |
| 'AddSegments instead.', DeprecationWarning) |
| return self.AddSegment(Segment(points[0], color=color, label=label)) |
| |
| def SetColors(self, *colors): |
| """Change the colors of this chart to the specified list of colors. |
| |
| Note that this will completely override the individual colors specified |
| in the pie segments. Missing colors will be interpolated, so that the |
| list of colors covers all segments in all the pies. |
| """ |
| self._colors = colors |