blob: 5ec3418cab72d569112788d9e0cca5e429d56823 [file] [log] [blame]
#!/usr/bin/env python
#
# 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 mapreduce.lib.graphy import common
from mapreduce.lib.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