python-pptx2 2.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pptx2/__init__.py +152 -0
- pptx2/_color.py +75 -0
- pptx2/_slide_importer.py +597 -0
- pptx2/_svg.py +155 -0
- pptx2/_template_applier.py +292 -0
- pptx2/_textstyle.py +187 -0
- pptx2/accessibility.py +365 -0
- pptx2/action.py +270 -0
- pptx2/animation.py +2237 -0
- pptx2/api.py +49 -0
- pptx2/audit.py +258 -0
- pptx2/chart/__init__.py +0 -0
- pptx2/chart/analytics.py +381 -0
- pptx2/chart/axis.py +543 -0
- pptx2/chart/category.py +200 -0
- pptx2/chart/chart.py +670 -0
- pptx2/chart/data.py +864 -0
- pptx2/chart/datalabel.py +406 -0
- pptx2/chart/legend.py +86 -0
- pptx2/chart/marker.py +70 -0
- pptx2/chart/palettes.py +129 -0
- pptx2/chart/plot.py +462 -0
- pptx2/chart/point.py +101 -0
- pptx2/chart/quick_layouts.py +325 -0
- pptx2/chart/series.py +334 -0
- pptx2/chart/xlsx.py +272 -0
- pptx2/chart/xmlwriter.py +1845 -0
- pptx2/compose/__init__.py +28 -0
- pptx2/compose/from_spec.py +1094 -0
- pptx2/design/__init__.py +8 -0
- pptx2/design/components.py +607 -0
- pptx2/design/figures.py +389 -0
- pptx2/design/layout.py +370 -0
- pptx2/design/recipes.py +1967 -0
- pptx2/design/style.py +209 -0
- pptx2/design/tokens.py +915 -0
- pptx2/diagrams.py +754 -0
- pptx2/dml/__init__.py +0 -0
- pptx2/dml/chtfmt.py +40 -0
- pptx2/dml/color.py +496 -0
- pptx2/dml/effect.py +909 -0
- pptx2/dml/fill.py +691 -0
- pptx2/dml/line.py +287 -0
- pptx2/dml/picture.py +212 -0
- pptx2/dml/three_d.py +381 -0
- pptx2/enum/__init__.py +0 -0
- pptx2/enum/action.py +71 -0
- pptx2/enum/animation.py +31 -0
- pptx2/enum/base.py +218 -0
- pptx2/enum/chart.py +574 -0
- pptx2/enum/dml.py +740 -0
- pptx2/enum/lang.py +685 -0
- pptx2/enum/presentation.py +133 -0
- pptx2/enum/shapes.py +1029 -0
- pptx2/enum/text.py +230 -0
- pptx2/exc.py +42 -0
- pptx2/formats.py +139 -0
- pptx2/geometry.py +420 -0
- pptx2/inherit.py +109 -0
- pptx2/lint.py +2256 -0
- pptx2/math.py +177 -0
- pptx2/media.py +197 -0
- pptx2/opc/__init__.py +0 -0
- pptx2/opc/constants.py +332 -0
- pptx2/opc/oxml.py +188 -0
- pptx2/opc/package.py +762 -0
- pptx2/opc/packuri.py +109 -0
- pptx2/opc/serialized.py +296 -0
- pptx2/opc/shared.py +20 -0
- pptx2/opc/spec.py +45 -0
- pptx2/oxml/__init__.py +555 -0
- pptx2/oxml/action.py +53 -0
- pptx2/oxml/chart/__init__.py +0 -0
- pptx2/oxml/chart/axis.py +337 -0
- pptx2/oxml/chart/chart.py +481 -0
- pptx2/oxml/chart/datalabel.py +253 -0
- pptx2/oxml/chart/legend.py +72 -0
- pptx2/oxml/chart/marker.py +61 -0
- pptx2/oxml/chart/plot.py +365 -0
- pptx2/oxml/chart/series.py +425 -0
- pptx2/oxml/chart/shared.py +220 -0
- pptx2/oxml/coreprops.py +288 -0
- pptx2/oxml/dml/__init__.py +0 -0
- pptx2/oxml/dml/color.py +135 -0
- pptx2/oxml/dml/effect.py +213 -0
- pptx2/oxml/dml/fill.py +316 -0
- pptx2/oxml/dml/line.py +12 -0
- pptx2/oxml/dml/three_d.py +110 -0
- pptx2/oxml/ns.py +135 -0
- pptx2/oxml/presentation.py +313 -0
- pptx2/oxml/shapes/__init__.py +19 -0
- pptx2/oxml/shapes/autoshape.py +467 -0
- pptx2/oxml/shapes/connector.py +107 -0
- pptx2/oxml/shapes/graphfrm.py +347 -0
- pptx2/oxml/shapes/groupshape.py +329 -0
- pptx2/oxml/shapes/picture.py +270 -0
- pptx2/oxml/shapes/shared.py +577 -0
- pptx2/oxml/simpletypes.py +1027 -0
- pptx2/oxml/slide.py +563 -0
- pptx2/oxml/table.py +650 -0
- pptx2/oxml/text.py +815 -0
- pptx2/oxml/theme.py +36 -0
- pptx2/oxml/xmlchemy.py +717 -0
- pptx2/package.py +222 -0
- pptx2/parts/__init__.py +0 -0
- pptx2/parts/chart.py +95 -0
- pptx2/parts/coreprops.py +167 -0
- pptx2/parts/diagram.py +37 -0
- pptx2/parts/embeddedpackage.py +93 -0
- pptx2/parts/image.py +275 -0
- pptx2/parts/media.py +37 -0
- pptx2/parts/presentation.py +136 -0
- pptx2/parts/slide.py +371 -0
- pptx2/presentation.py +408 -0
- pptx2/py.typed +0 -0
- pptx2/render.py +586 -0
- pptx2/section.py +272 -0
- pptx2/shapes/__init__.py +26 -0
- pptx2/shapes/autoshape.py +442 -0
- pptx2/shapes/base.py +1078 -0
- pptx2/shapes/connector.py +297 -0
- pptx2/shapes/freeform.py +337 -0
- pptx2/shapes/graphfrm.py +316 -0
- pptx2/shapes/group.py +264 -0
- pptx2/shapes/picture.py +422 -0
- pptx2/shapes/placeholder.py +468 -0
- pptx2/shapes/shapetree.py +2027 -0
- pptx2/shared.py +82 -0
- pptx2/skill/SKILL.md +450 -0
- pptx2/skill/__init__.py +78 -0
- pptx2/skill/__main__.py +64 -0
- pptx2/skill/references/animations.md +189 -0
- pptx2/skill/references/basics.md +421 -0
- pptx2/skill/references/charts.md +254 -0
- pptx2/skill/references/compose.md +234 -0
- pptx2/skill/references/design.md +366 -0
- pptx2/skill/references/effects.md +249 -0
- pptx2/skill/references/end-to-end-deck.md +231 -0
- pptx2/skill/references/geometry-and-arrows.md +334 -0
- pptx2/skill/references/lint.md +275 -0
- pptx2/skill/references/math.md +86 -0
- pptx2/skill/references/picture-effects.md +129 -0
- pptx2/skill/references/render.md +151 -0
- pptx2/skill/references/smart-art.md +75 -0
- pptx2/skill/references/space-aware-authoring.md +249 -0
- pptx2/skill/references/tables.md +244 -0
- pptx2/skill/references/theme.md +127 -0
- pptx2/skill/references/three-d.md +109 -0
- pptx2/skill/references/transitions.md +100 -0
- pptx2/slide.py +1244 -0
- pptx2/smart_art.py +220 -0
- pptx2/spec.py +633 -0
- pptx2/table.py +1181 -0
- pptx2/table_styles.py +184 -0
- pptx2/templates/default.pptx +0 -0
- pptx2/templates/docx-icon.emf +0 -0
- pptx2/templates/generic-icon.emf +0 -0
- pptx2/templates/notes.xml +23 -0
- pptx2/templates/notesMaster.xml +352 -0
- pptx2/templates/pptx-icon.emf +0 -0
- pptx2/templates/theme.xml +321 -0
- pptx2/templates/xlsx-icon.emf +0 -0
- pptx2/text/__init__.py +0 -0
- pptx2/text/fonts.py +482 -0
- pptx2/text/layout.py +374 -0
- pptx2/text/text.py +1272 -0
- pptx2/theme.py +721 -0
- pptx2/types.py +36 -0
- pptx2/util.py +263 -0
- python_pptx2-2.13.0.dist-info/METADATA +351 -0
- python_pptx2-2.13.0.dist-info/RECORD +175 -0
- python_pptx2-2.13.0.dist-info/WHEEL +5 -0
- python_pptx2-2.13.0.dist-info/entry_points.txt +3 -0
- python_pptx2-2.13.0.dist-info/licenses/LICENSE +22 -0
- python_pptx2-2.13.0.dist-info/top_level.txt +1 -0
pptx2/chart/data.py
ADDED
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
"""ChartData and related objects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from numbers import Number
|
|
8
|
+
|
|
9
|
+
from pptx2.chart.xlsx import (
|
|
10
|
+
BubbleWorkbookWriter,
|
|
11
|
+
CategoryWorkbookWriter,
|
|
12
|
+
XyWorkbookWriter,
|
|
13
|
+
)
|
|
14
|
+
from pptx2.chart.xmlwriter import ChartXmlWriter
|
|
15
|
+
from pptx2.util import lazyproperty
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _BaseChartData(Sequence):
|
|
19
|
+
"""Base class providing common members for chart data objects.
|
|
20
|
+
|
|
21
|
+
A chart data object serves as a proxy for the chart data table that will be written to an
|
|
22
|
+
Excel worksheet; operating as a sequence of series as well as providing access to chart-level
|
|
23
|
+
attributes. A chart data object is used as a parameter in :meth:`shapes.add_chart` and
|
|
24
|
+
:meth:`Chart.replace_data`. The data structure varies between major chart categories such as
|
|
25
|
+
category charts and XY charts.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, number_format="General"):
|
|
29
|
+
super(_BaseChartData, self).__init__()
|
|
30
|
+
self._number_format = number_format
|
|
31
|
+
self._series = []
|
|
32
|
+
|
|
33
|
+
def __getitem__(self, index):
|
|
34
|
+
return self._series.__getitem__(index)
|
|
35
|
+
|
|
36
|
+
def __len__(self):
|
|
37
|
+
return self._series.__len__()
|
|
38
|
+
|
|
39
|
+
def append(self, series):
|
|
40
|
+
return self._series.append(series)
|
|
41
|
+
|
|
42
|
+
def data_point_offset(self, series):
|
|
43
|
+
"""
|
|
44
|
+
The total integer number of data points appearing in the series of
|
|
45
|
+
this chart that are prior to *series* in this sequence.
|
|
46
|
+
"""
|
|
47
|
+
count = 0
|
|
48
|
+
for this_series in self:
|
|
49
|
+
if series is this_series:
|
|
50
|
+
return count
|
|
51
|
+
count += len(this_series)
|
|
52
|
+
raise ValueError("series not in chart data object")
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def number_format(self):
|
|
56
|
+
"""
|
|
57
|
+
The formatting template string, e.g. '#,##0.0', that determines how
|
|
58
|
+
X and Y values are formatted in this chart and in the Excel
|
|
59
|
+
spreadsheet. A number format specified on a series will override this
|
|
60
|
+
value for that series. Likewise, a distinct number format can be
|
|
61
|
+
specified for a particular data point within a series.
|
|
62
|
+
"""
|
|
63
|
+
return self._number_format
|
|
64
|
+
|
|
65
|
+
def series_index(self, series):
|
|
66
|
+
"""
|
|
67
|
+
Return the integer index of *series* in this sequence.
|
|
68
|
+
"""
|
|
69
|
+
for idx, s in enumerate(self):
|
|
70
|
+
if series is s:
|
|
71
|
+
return idx
|
|
72
|
+
raise ValueError("series not in chart data object")
|
|
73
|
+
|
|
74
|
+
def series_name_ref(self, series):
|
|
75
|
+
"""
|
|
76
|
+
Return the Excel worksheet reference to the cell containing the name
|
|
77
|
+
for *series*.
|
|
78
|
+
"""
|
|
79
|
+
return self._workbook_writer.series_name_ref(series)
|
|
80
|
+
|
|
81
|
+
def x_values_ref(self, series):
|
|
82
|
+
"""
|
|
83
|
+
The Excel worksheet reference to the X values for *series* (not
|
|
84
|
+
including the column label).
|
|
85
|
+
"""
|
|
86
|
+
return self._workbook_writer.x_values_ref(series)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def xlsx_blob(self):
|
|
90
|
+
"""
|
|
91
|
+
Return a blob containing an Excel workbook file populated with the
|
|
92
|
+
contents of this chart data object.
|
|
93
|
+
"""
|
|
94
|
+
return self._workbook_writer.xlsx_blob
|
|
95
|
+
|
|
96
|
+
def xml_bytes(self, chart_type):
|
|
97
|
+
"""
|
|
98
|
+
Return a blob containing the XML for a chart of *chart_type*
|
|
99
|
+
containing the series in this chart data object, as bytes suitable
|
|
100
|
+
for writing directly to a file.
|
|
101
|
+
"""
|
|
102
|
+
return self._xml(chart_type).encode("utf-8")
|
|
103
|
+
|
|
104
|
+
def y_values_ref(self, series):
|
|
105
|
+
"""
|
|
106
|
+
The Excel worksheet reference to the Y values for *series* (not
|
|
107
|
+
including the column label).
|
|
108
|
+
"""
|
|
109
|
+
return self._workbook_writer.y_values_ref(series)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def _workbook_writer(self):
|
|
113
|
+
"""
|
|
114
|
+
The worksheet writer object to which layout and writing of the Excel
|
|
115
|
+
worksheet for this chart will be delegated.
|
|
116
|
+
"""
|
|
117
|
+
raise NotImplementedError("must be implemented by all subclasses")
|
|
118
|
+
|
|
119
|
+
def _xml(self, chart_type):
|
|
120
|
+
"""
|
|
121
|
+
Return (as unicode text) the XML for a chart of *chart_type*
|
|
122
|
+
populated with the values in this chart data object. The XML is
|
|
123
|
+
a complete XML document, including an XML declaration specifying
|
|
124
|
+
UTF-8 encoding.
|
|
125
|
+
"""
|
|
126
|
+
return ChartXmlWriter(chart_type, self).xml
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class _BaseSeriesData(Sequence):
|
|
130
|
+
"""
|
|
131
|
+
Base class providing common members for series data objects. A series
|
|
132
|
+
data object serves as proxy for a series data column in the Excel
|
|
133
|
+
worksheet. It operates as a sequence of data points, as well as providing
|
|
134
|
+
access to series-level attributes like the series label.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def __init__(self, chart_data, name, number_format):
|
|
138
|
+
self._chart_data = chart_data
|
|
139
|
+
self._name = name
|
|
140
|
+
self._number_format = number_format
|
|
141
|
+
self._data_points = []
|
|
142
|
+
|
|
143
|
+
def __getitem__(self, index):
|
|
144
|
+
return self._data_points.__getitem__(index)
|
|
145
|
+
|
|
146
|
+
def __len__(self):
|
|
147
|
+
return self._data_points.__len__()
|
|
148
|
+
|
|
149
|
+
def append(self, data_point):
|
|
150
|
+
return self._data_points.append(data_point)
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def data_point_offset(self):
|
|
154
|
+
"""
|
|
155
|
+
The integer count of data points that appear in all chart series
|
|
156
|
+
prior to this one.
|
|
157
|
+
"""
|
|
158
|
+
return self._chart_data.data_point_offset(self)
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def index(self):
|
|
162
|
+
"""
|
|
163
|
+
Zero-based integer indicating the sequence position of this series in
|
|
164
|
+
its chart. For example, the second of three series would return `1`.
|
|
165
|
+
"""
|
|
166
|
+
return self._chart_data.series_index(self)
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def name(self):
|
|
170
|
+
"""
|
|
171
|
+
The name of this series, e.g. 'Series 1'. This name is used as the
|
|
172
|
+
column heading for the y-values of this series and may also appear in
|
|
173
|
+
the chart legend and perhaps other chart locations.
|
|
174
|
+
"""
|
|
175
|
+
return self._name if self._name is not None else ""
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def name_ref(self):
|
|
179
|
+
"""
|
|
180
|
+
The Excel worksheet reference to the cell containing the name for
|
|
181
|
+
this series.
|
|
182
|
+
"""
|
|
183
|
+
return self._chart_data.series_name_ref(self)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def number_format(self):
|
|
187
|
+
"""
|
|
188
|
+
The formatting template string that determines how a number in this
|
|
189
|
+
series is formatted, both in the chart and in the Excel spreadsheet;
|
|
190
|
+
for example '#,##0.0'. If not specified for this series, it is
|
|
191
|
+
inherited from the parent chart data object.
|
|
192
|
+
"""
|
|
193
|
+
number_format = self._number_format
|
|
194
|
+
if number_format is None:
|
|
195
|
+
return self._chart_data.number_format
|
|
196
|
+
return number_format
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def x_values(self):
|
|
200
|
+
"""
|
|
201
|
+
A sequence containing the X value of each datapoint in this series,
|
|
202
|
+
in data point order.
|
|
203
|
+
"""
|
|
204
|
+
return [dp.x for dp in self._data_points]
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def x_values_ref(self):
|
|
208
|
+
"""
|
|
209
|
+
The Excel worksheet reference to the X values for this chart (not
|
|
210
|
+
including the column heading).
|
|
211
|
+
"""
|
|
212
|
+
return self._chart_data.x_values_ref(self)
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def y_values(self):
|
|
216
|
+
"""
|
|
217
|
+
A sequence containing the Y value of each datapoint in this series,
|
|
218
|
+
in data point order.
|
|
219
|
+
"""
|
|
220
|
+
return [dp.y for dp in self._data_points]
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def y_values_ref(self):
|
|
224
|
+
"""
|
|
225
|
+
The Excel worksheet reference to the Y values for this chart (not
|
|
226
|
+
including the column heading).
|
|
227
|
+
"""
|
|
228
|
+
return self._chart_data.y_values_ref(self)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class _BaseDataPoint(object):
|
|
232
|
+
"""
|
|
233
|
+
Base class providing common members for data point objects.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
def __init__(self, series_data, number_format):
|
|
237
|
+
super(_BaseDataPoint, self).__init__()
|
|
238
|
+
self._series_data = series_data
|
|
239
|
+
self._number_format = number_format
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def number_format(self):
|
|
243
|
+
"""
|
|
244
|
+
The formatting template string that determines how the value of this
|
|
245
|
+
data point is formatted, both in the chart and in the Excel
|
|
246
|
+
spreadsheet; for example '#,##0.0'. If not specified for this data
|
|
247
|
+
point, it is inherited from the parent series data object.
|
|
248
|
+
"""
|
|
249
|
+
number_format = self._number_format
|
|
250
|
+
if number_format is None:
|
|
251
|
+
return self._series_data.number_format
|
|
252
|
+
return number_format
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class CategoryChartData(_BaseChartData):
|
|
256
|
+
"""
|
|
257
|
+
Accumulates data specifying the categories and series values for a chart
|
|
258
|
+
and acts as a proxy for the chart data table that will be written to an
|
|
259
|
+
Excel worksheet. Used as a parameter in :meth:`shapes.add_chart` and
|
|
260
|
+
:meth:`Chart.replace_data`.
|
|
261
|
+
|
|
262
|
+
This object is suitable for use with category charts, i.e. all those
|
|
263
|
+
having a discrete set of label values (categories) as the range of their
|
|
264
|
+
independent variable (X-axis) values. Unlike the ChartData types for
|
|
265
|
+
charts supporting a continuous range of independent variable values (such
|
|
266
|
+
as XyChartData), CategoryChartData has a single collection of category
|
|
267
|
+
(X) values and each data point in its series specifies only the Y value.
|
|
268
|
+
The corresponding X value is inferred by its position in the sequence.
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
def add_category(self, label):
|
|
272
|
+
"""
|
|
273
|
+
Return a newly created |data.Category| object having *label* and
|
|
274
|
+
appended to the end of the category collection for this chart.
|
|
275
|
+
*label* can be a string, a number, a datetime.date, or
|
|
276
|
+
datetime.datetime object. All category labels in a chart must be the
|
|
277
|
+
same type. All category labels in a chart having multi-level
|
|
278
|
+
categories must be strings.
|
|
279
|
+
"""
|
|
280
|
+
return self.categories.add_category(label)
|
|
281
|
+
|
|
282
|
+
def add_series(self, name, values=(), number_format=None):
|
|
283
|
+
"""
|
|
284
|
+
Add a series to this data set entitled *name* and having the data
|
|
285
|
+
points specified by *values*, an iterable of numeric values.
|
|
286
|
+
*number_format* specifies how the series values will be displayed,
|
|
287
|
+
and may be a string, e.g. '#,##0' corresponding to an Excel number
|
|
288
|
+
format.
|
|
289
|
+
"""
|
|
290
|
+
series_data = CategorySeriesData(self, name, number_format)
|
|
291
|
+
self.append(series_data)
|
|
292
|
+
for value in values:
|
|
293
|
+
series_data.add_data_point(value)
|
|
294
|
+
return series_data
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def categories(self):
|
|
298
|
+
"""|data.Categories| object providing access to category-object hierarchy.
|
|
299
|
+
|
|
300
|
+
Assigning an iterable of category labels (strings, numbers, or dates) replaces
|
|
301
|
+
the |data.Categories| object with a new one containing a category for each label
|
|
302
|
+
in the sequence.
|
|
303
|
+
|
|
304
|
+
Creating a chart from chart data having date categories will cause the chart to
|
|
305
|
+
have a |DateAxis| for its category axis.
|
|
306
|
+
"""
|
|
307
|
+
if not getattr(self, "_categories", False):
|
|
308
|
+
self._categories = Categories()
|
|
309
|
+
return self._categories
|
|
310
|
+
|
|
311
|
+
@categories.setter
|
|
312
|
+
def categories(self, category_labels):
|
|
313
|
+
categories = Categories()
|
|
314
|
+
for label in category_labels:
|
|
315
|
+
categories.add_category(label)
|
|
316
|
+
self._categories = categories
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def categories_ref(self):
|
|
320
|
+
"""
|
|
321
|
+
The Excel worksheet reference to the categories for this chart (not
|
|
322
|
+
including the column heading).
|
|
323
|
+
"""
|
|
324
|
+
return self._workbook_writer.categories_ref
|
|
325
|
+
|
|
326
|
+
def values_ref(self, series):
|
|
327
|
+
"""
|
|
328
|
+
The Excel worksheet reference to the values for *series* (not
|
|
329
|
+
including the column heading).
|
|
330
|
+
"""
|
|
331
|
+
return self._workbook_writer.values_ref(series)
|
|
332
|
+
|
|
333
|
+
@lazyproperty
|
|
334
|
+
def _workbook_writer(self):
|
|
335
|
+
"""
|
|
336
|
+
The worksheet writer object to which layout and writing of the Excel
|
|
337
|
+
worksheet for this chart will be delegated.
|
|
338
|
+
"""
|
|
339
|
+
return CategoryWorkbookWriter(self)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class Categories(Sequence):
|
|
343
|
+
"""
|
|
344
|
+
A sequence of |data.Category| objects, also having certain hierarchical
|
|
345
|
+
graph behaviors for support of multi-level (nested) categories.
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def __init__(self):
|
|
349
|
+
super(Categories, self).__init__()
|
|
350
|
+
self._categories = []
|
|
351
|
+
self._number_format = None
|
|
352
|
+
|
|
353
|
+
def __getitem__(self, idx):
|
|
354
|
+
return self._categories.__getitem__(idx)
|
|
355
|
+
|
|
356
|
+
def __len__(self):
|
|
357
|
+
"""
|
|
358
|
+
Return the count of the highest level of category in this sequence.
|
|
359
|
+
If it contains hierarchical (multi-level) categories, this number
|
|
360
|
+
will differ from :attr:`category_count`, which is the number of leaf
|
|
361
|
+
nodes.
|
|
362
|
+
"""
|
|
363
|
+
return self._categories.__len__()
|
|
364
|
+
|
|
365
|
+
def add_category(self, label):
|
|
366
|
+
"""
|
|
367
|
+
Return a newly created |data.Category| object having *label* and
|
|
368
|
+
appended to the end of this category sequence. *label* can be
|
|
369
|
+
a string, a number, a datetime.date, or datetime.datetime object. All
|
|
370
|
+
category labels in a chart must be the same type. All category labels
|
|
371
|
+
in a chart having multi-level categories must be strings.
|
|
372
|
+
|
|
373
|
+
Creating a chart from chart data having date categories will cause
|
|
374
|
+
the chart to have a |DateAxis| for its category axis.
|
|
375
|
+
"""
|
|
376
|
+
category = Category(label, self)
|
|
377
|
+
self._categories.append(category)
|
|
378
|
+
return category
|
|
379
|
+
|
|
380
|
+
@property
|
|
381
|
+
def are_dates(self):
|
|
382
|
+
"""
|
|
383
|
+
Return |True| if the first category in this collection has a date
|
|
384
|
+
label (as opposed to str or numeric). A date label is one of type
|
|
385
|
+
datetime.date or datetime.datetime. Returns |False| otherwise,
|
|
386
|
+
including when this category collection is empty. It also returns
|
|
387
|
+
False when this category collection is hierarchical, because
|
|
388
|
+
hierarchical categories can only be written as string labels.
|
|
389
|
+
"""
|
|
390
|
+
if self.depth != 1:
|
|
391
|
+
return False
|
|
392
|
+
first_cat_label = self[0].label
|
|
393
|
+
date_types = (datetime.date, datetime.datetime)
|
|
394
|
+
if isinstance(first_cat_label, date_types):
|
|
395
|
+
return True
|
|
396
|
+
return False
|
|
397
|
+
|
|
398
|
+
@property
|
|
399
|
+
def are_numeric(self):
|
|
400
|
+
"""
|
|
401
|
+
Return |True| if the first category in this collection has a numeric
|
|
402
|
+
label (as opposed to a string label), including if that value is
|
|
403
|
+
a datetime.date or datetime.datetime object (as those are converted
|
|
404
|
+
to integers for storage in Excel). Returns |False| otherwise,
|
|
405
|
+
including when this category collection is empty. It also returns
|
|
406
|
+
False when this category collection is hierarchical, because
|
|
407
|
+
hierarchical categories can only be written as string labels.
|
|
408
|
+
"""
|
|
409
|
+
if self.depth != 1:
|
|
410
|
+
return False
|
|
411
|
+
# This method only tests the first category. The categories must
|
|
412
|
+
# be of uniform type, and if they're not, there will be problems
|
|
413
|
+
# later in the process, but it's not this method's job to validate
|
|
414
|
+
# the caller's input.
|
|
415
|
+
first_cat_label = self[0].label
|
|
416
|
+
numeric_types = (Number, datetime.date, datetime.datetime)
|
|
417
|
+
if isinstance(first_cat_label, numeric_types):
|
|
418
|
+
return True
|
|
419
|
+
return False
|
|
420
|
+
|
|
421
|
+
@property
|
|
422
|
+
def depth(self):
|
|
423
|
+
"""
|
|
424
|
+
The number of hierarchy levels in this category graph. Returns 0 if
|
|
425
|
+
it contains no categories.
|
|
426
|
+
"""
|
|
427
|
+
categories = self._categories
|
|
428
|
+
if not categories:
|
|
429
|
+
return 0
|
|
430
|
+
first_depth = categories[0].depth
|
|
431
|
+
for category in categories[1:]:
|
|
432
|
+
if category.depth != first_depth:
|
|
433
|
+
raise ValueError("category depth not uniform")
|
|
434
|
+
return first_depth
|
|
435
|
+
|
|
436
|
+
def index(self, category):
|
|
437
|
+
"""
|
|
438
|
+
The offset of *category* in the overall sequence of leaf categories.
|
|
439
|
+
A non-leaf category gets the index of its first sub-category.
|
|
440
|
+
"""
|
|
441
|
+
index = 0
|
|
442
|
+
for this_category in self._categories:
|
|
443
|
+
if category is this_category:
|
|
444
|
+
return index
|
|
445
|
+
index += this_category.leaf_count
|
|
446
|
+
raise ValueError("category not in top-level categories")
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def leaf_count(self):
|
|
450
|
+
"""
|
|
451
|
+
The number of leaf-level categories in this hierarchy. The return
|
|
452
|
+
value is the same as that of `len()` only when the hierarchy is
|
|
453
|
+
single level.
|
|
454
|
+
"""
|
|
455
|
+
return sum(c.leaf_count for c in self._categories)
|
|
456
|
+
|
|
457
|
+
@property
|
|
458
|
+
def levels(self):
|
|
459
|
+
"""
|
|
460
|
+
A generator of (idx, label) sequences representing the category
|
|
461
|
+
hierarchy from the bottom up. The first level contains all leaf
|
|
462
|
+
categories, and each subsequent is the next level up.
|
|
463
|
+
"""
|
|
464
|
+
|
|
465
|
+
def levels(categories):
|
|
466
|
+
# yield all lower levels
|
|
467
|
+
sub_categories = [sc for c in categories for sc in c.sub_categories]
|
|
468
|
+
if sub_categories:
|
|
469
|
+
for level in levels(sub_categories):
|
|
470
|
+
yield level
|
|
471
|
+
# yield this level
|
|
472
|
+
yield [(cat.idx, cat.label) for cat in categories]
|
|
473
|
+
|
|
474
|
+
for level in levels(self):
|
|
475
|
+
yield level
|
|
476
|
+
|
|
477
|
+
@property
|
|
478
|
+
def number_format(self):
|
|
479
|
+
"""
|
|
480
|
+
Read/write. Return a string representing the number format used in
|
|
481
|
+
Excel to format these category values, e.g. '0.0' or 'mm/dd/yyyy'.
|
|
482
|
+
This string is only relevant when the categories are numeric or date
|
|
483
|
+
type, although it returns 'General' without error when the categories
|
|
484
|
+
are string labels. Assigning |None| causes the default number format
|
|
485
|
+
to be used, based on the type of the category labels.
|
|
486
|
+
"""
|
|
487
|
+
GENERAL = "General"
|
|
488
|
+
|
|
489
|
+
# defined value takes precedence
|
|
490
|
+
if self._number_format is not None:
|
|
491
|
+
return self._number_format
|
|
492
|
+
|
|
493
|
+
# multi-level (should) always be string labels
|
|
494
|
+
# zero depth means empty in which case we can't tell anyway
|
|
495
|
+
if self.depth != 1:
|
|
496
|
+
return GENERAL
|
|
497
|
+
|
|
498
|
+
# everything except dates gets 'General'
|
|
499
|
+
first_cat_label = self[0].label
|
|
500
|
+
if isinstance(first_cat_label, (datetime.date, datetime.datetime)):
|
|
501
|
+
return r"yyyy\-mm\-dd"
|
|
502
|
+
return GENERAL
|
|
503
|
+
|
|
504
|
+
@number_format.setter
|
|
505
|
+
def number_format(self, value):
|
|
506
|
+
self._number_format = value
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
class Category(object):
|
|
510
|
+
"""
|
|
511
|
+
A chart category, primarily having a label to be displayed on the
|
|
512
|
+
category axis, but also able to be configured in a hierarchy for support
|
|
513
|
+
of multi-level category charts.
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
def __init__(self, label, parent):
|
|
517
|
+
super(Category, self).__init__()
|
|
518
|
+
self._label = label
|
|
519
|
+
self._parent = parent
|
|
520
|
+
self._sub_categories = []
|
|
521
|
+
|
|
522
|
+
def add_sub_category(self, label):
|
|
523
|
+
"""
|
|
524
|
+
Return a newly created |data.Category| object having *label* and
|
|
525
|
+
appended to the end of the sub-category sequence for this category.
|
|
526
|
+
"""
|
|
527
|
+
category = Category(label, self)
|
|
528
|
+
self._sub_categories.append(category)
|
|
529
|
+
return category
|
|
530
|
+
|
|
531
|
+
@property
|
|
532
|
+
def depth(self):
|
|
533
|
+
"""
|
|
534
|
+
The number of hierarchy levels rooted at this category node. Returns
|
|
535
|
+
1 if this category has no sub-categories.
|
|
536
|
+
"""
|
|
537
|
+
sub_categories = self._sub_categories
|
|
538
|
+
if not sub_categories:
|
|
539
|
+
return 1
|
|
540
|
+
first_depth = sub_categories[0].depth
|
|
541
|
+
for category in sub_categories[1:]:
|
|
542
|
+
if category.depth != first_depth:
|
|
543
|
+
raise ValueError("category depth not uniform")
|
|
544
|
+
return first_depth + 1
|
|
545
|
+
|
|
546
|
+
@property
|
|
547
|
+
def idx(self):
|
|
548
|
+
"""
|
|
549
|
+
The offset of this category in the overall sequence of leaf
|
|
550
|
+
categories. A non-leaf category gets the index of its first
|
|
551
|
+
sub-category.
|
|
552
|
+
"""
|
|
553
|
+
return self._parent.index(self)
|
|
554
|
+
|
|
555
|
+
def index(self, sub_category):
|
|
556
|
+
"""
|
|
557
|
+
The offset of *sub_category* in the overall sequence of leaf
|
|
558
|
+
categories.
|
|
559
|
+
"""
|
|
560
|
+
index = self._parent.index(self)
|
|
561
|
+
for this_sub_category in self._sub_categories:
|
|
562
|
+
if sub_category is this_sub_category:
|
|
563
|
+
return index
|
|
564
|
+
index += this_sub_category.leaf_count
|
|
565
|
+
raise ValueError("sub_category not in this category")
|
|
566
|
+
|
|
567
|
+
@property
|
|
568
|
+
def leaf_count(self):
|
|
569
|
+
"""
|
|
570
|
+
The number of leaf category nodes under this category. Returns
|
|
571
|
+
1 if this category has no sub-categories.
|
|
572
|
+
"""
|
|
573
|
+
if not self._sub_categories:
|
|
574
|
+
return 1
|
|
575
|
+
return sum(category.leaf_count for category in self._sub_categories)
|
|
576
|
+
|
|
577
|
+
@property
|
|
578
|
+
def label(self):
|
|
579
|
+
"""
|
|
580
|
+
The value that appears on the axis for this category. The label can
|
|
581
|
+
be a string, a number, or a datetime.date or datetime.datetime
|
|
582
|
+
object.
|
|
583
|
+
"""
|
|
584
|
+
return self._label if self._label is not None else ""
|
|
585
|
+
|
|
586
|
+
def numeric_str_val(self, date_1904=False):
|
|
587
|
+
"""
|
|
588
|
+
The string representation of the numeric (or date) label of this
|
|
589
|
+
category, suitable for use in the XML `c:pt` element for this
|
|
590
|
+
category. The optional *date_1904* parameter specifies the epoch used
|
|
591
|
+
for calculating Excel date numbers.
|
|
592
|
+
"""
|
|
593
|
+
label = self._label
|
|
594
|
+
if isinstance(label, (datetime.date, datetime.datetime)):
|
|
595
|
+
return "%.1f" % self._excel_date_number(date_1904)
|
|
596
|
+
return str(self._label)
|
|
597
|
+
|
|
598
|
+
@property
|
|
599
|
+
def sub_categories(self):
|
|
600
|
+
"""
|
|
601
|
+
The sequence of child categories for this category.
|
|
602
|
+
"""
|
|
603
|
+
return self._sub_categories
|
|
604
|
+
|
|
605
|
+
def _excel_date_number(self, date_1904):
|
|
606
|
+
"""
|
|
607
|
+
Return an integer representing the date label of this category as the
|
|
608
|
+
number of days since January 1, 1900 (or 1904 if date_1904 is
|
|
609
|
+
|True|).
|
|
610
|
+
"""
|
|
611
|
+
date, label = datetime.date, self._label
|
|
612
|
+
# -- get date from label in type-independent-ish way
|
|
613
|
+
date_ = date(label.year, label.month, label.day)
|
|
614
|
+
epoch = date(1904, 1, 1) if date_1904 else date(1899, 12, 31)
|
|
615
|
+
delta = date_ - epoch
|
|
616
|
+
excel_day_number = delta.days
|
|
617
|
+
|
|
618
|
+
# -- adjust for Excel mistaking 1900 for a leap year --
|
|
619
|
+
if not date_1904 and excel_day_number > 59:
|
|
620
|
+
excel_day_number += 1
|
|
621
|
+
|
|
622
|
+
return excel_day_number
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class ChartData(CategoryChartData):
|
|
626
|
+
"""
|
|
627
|
+
|ChartData| is simply an alias for |CategoryChartData| and may be removed
|
|
628
|
+
in a future release. All new development should use |CategoryChartData|
|
|
629
|
+
for creating or replacing the data in chart types other than XY and
|
|
630
|
+
Bubble.
|
|
631
|
+
"""
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
class CategorySeriesData(_BaseSeriesData):
|
|
635
|
+
"""
|
|
636
|
+
The data specific to a particular category chart series. It provides
|
|
637
|
+
access to the series label, the series data points, and an optional
|
|
638
|
+
number format to be applied to each data point not having a specified
|
|
639
|
+
number format.
|
|
640
|
+
"""
|
|
641
|
+
|
|
642
|
+
def add_data_point(self, value, number_format=None):
|
|
643
|
+
"""
|
|
644
|
+
Return a CategoryDataPoint object newly created with value *value*,
|
|
645
|
+
an optional *number_format*, and appended to this sequence.
|
|
646
|
+
"""
|
|
647
|
+
data_point = CategoryDataPoint(self, value, number_format)
|
|
648
|
+
self.append(data_point)
|
|
649
|
+
return data_point
|
|
650
|
+
|
|
651
|
+
@property
|
|
652
|
+
def categories(self):
|
|
653
|
+
"""
|
|
654
|
+
The |data.Categories| object that provides access to the category
|
|
655
|
+
objects for this series.
|
|
656
|
+
"""
|
|
657
|
+
return self._chart_data.categories
|
|
658
|
+
|
|
659
|
+
@property
|
|
660
|
+
def categories_ref(self):
|
|
661
|
+
"""
|
|
662
|
+
The Excel worksheet reference to the categories for this chart (not
|
|
663
|
+
including the column heading).
|
|
664
|
+
"""
|
|
665
|
+
return self._chart_data.categories_ref
|
|
666
|
+
|
|
667
|
+
@property
|
|
668
|
+
def values(self):
|
|
669
|
+
"""
|
|
670
|
+
A sequence containing the (Y) value of each datapoint in this series,
|
|
671
|
+
in data point order.
|
|
672
|
+
"""
|
|
673
|
+
return [dp.value for dp in self._data_points]
|
|
674
|
+
|
|
675
|
+
@property
|
|
676
|
+
def values_ref(self):
|
|
677
|
+
"""
|
|
678
|
+
The Excel worksheet reference to the (Y) values for this series (not
|
|
679
|
+
including the column heading).
|
|
680
|
+
"""
|
|
681
|
+
return self._chart_data.values_ref(self)
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
class XyChartData(_BaseChartData):
|
|
685
|
+
"""
|
|
686
|
+
A specialized ChartData object suitable for use with an XY (aka. scatter)
|
|
687
|
+
chart. Unlike ChartData, it has no category sequence. Rather, each data
|
|
688
|
+
point of each series specifies both an X and a Y value.
|
|
689
|
+
"""
|
|
690
|
+
|
|
691
|
+
def add_series(self, name, number_format=None):
|
|
692
|
+
"""
|
|
693
|
+
Return an |XySeriesData| object newly created and added at the end of
|
|
694
|
+
this sequence, identified by *name* and values formatted with
|
|
695
|
+
*number_format*.
|
|
696
|
+
"""
|
|
697
|
+
series_data = XySeriesData(self, name, number_format)
|
|
698
|
+
self.append(series_data)
|
|
699
|
+
return series_data
|
|
700
|
+
|
|
701
|
+
@lazyproperty
|
|
702
|
+
def _workbook_writer(self):
|
|
703
|
+
"""
|
|
704
|
+
The worksheet writer object to which layout and writing of the Excel
|
|
705
|
+
worksheet for this chart will be delegated.
|
|
706
|
+
"""
|
|
707
|
+
return XyWorkbookWriter(self)
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
class BubbleChartData(XyChartData):
|
|
711
|
+
"""
|
|
712
|
+
A specialized ChartData object suitable for use with a bubble chart.
|
|
713
|
+
A bubble chart is essentially an XY chart where the markers are scaled to
|
|
714
|
+
provide a third quantitative dimension to the exhibit.
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
def add_series(self, name, number_format=None):
|
|
718
|
+
"""
|
|
719
|
+
Return a |BubbleSeriesData| object newly created and added at the end
|
|
720
|
+
of this sequence, and having series named *name* and values formatted
|
|
721
|
+
with *number_format*.
|
|
722
|
+
"""
|
|
723
|
+
series_data = BubbleSeriesData(self, name, number_format)
|
|
724
|
+
self.append(series_data)
|
|
725
|
+
return series_data
|
|
726
|
+
|
|
727
|
+
def bubble_sizes_ref(self, series):
|
|
728
|
+
"""
|
|
729
|
+
The Excel worksheet reference for the range containing the bubble
|
|
730
|
+
sizes for *series*.
|
|
731
|
+
"""
|
|
732
|
+
return self._workbook_writer.bubble_sizes_ref(series)
|
|
733
|
+
|
|
734
|
+
@lazyproperty
|
|
735
|
+
def _workbook_writer(self):
|
|
736
|
+
"""
|
|
737
|
+
The worksheet writer object to which layout and writing of the Excel
|
|
738
|
+
worksheet for this chart will be delegated.
|
|
739
|
+
"""
|
|
740
|
+
return BubbleWorkbookWriter(self)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
class XySeriesData(_BaseSeriesData):
|
|
744
|
+
"""
|
|
745
|
+
The data specific to a particular XY chart series. It provides access to
|
|
746
|
+
the series label, the series data points, and an optional number format
|
|
747
|
+
to be applied to each data point not having a specified number format.
|
|
748
|
+
|
|
749
|
+
The sequence of data points in an XY series is significant; lines are
|
|
750
|
+
plotted following the sequence of points, even if that causes a line
|
|
751
|
+
segment to "travel backward" (implying a multi-valued function). The data
|
|
752
|
+
points are not automatically sorted into increasing order by X value.
|
|
753
|
+
"""
|
|
754
|
+
|
|
755
|
+
def add_data_point(self, x, y, number_format=None):
|
|
756
|
+
"""
|
|
757
|
+
Return an XyDataPoint object newly created with values *x* and *y*,
|
|
758
|
+
and appended to this sequence.
|
|
759
|
+
"""
|
|
760
|
+
data_point = XyDataPoint(self, x, y, number_format)
|
|
761
|
+
self.append(data_point)
|
|
762
|
+
return data_point
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
class BubbleSeriesData(XySeriesData):
|
|
766
|
+
"""
|
|
767
|
+
The data specific to a particular Bubble chart series. It provides access
|
|
768
|
+
to the series label, the series data points, and an optional number
|
|
769
|
+
format to be applied to each data point not having a specified number
|
|
770
|
+
format.
|
|
771
|
+
|
|
772
|
+
The sequence of data points in a bubble chart series is maintained
|
|
773
|
+
throughout the chart building process because a data point has no unique
|
|
774
|
+
identifier and can only be retrieved by index.
|
|
775
|
+
"""
|
|
776
|
+
|
|
777
|
+
def add_data_point(self, x, y, size, number_format=None):
|
|
778
|
+
"""
|
|
779
|
+
Append a new BubbleDataPoint object having the values *x*, *y*, and
|
|
780
|
+
*size*. The optional *number_format* is used to format the Y value.
|
|
781
|
+
If not provided, the number format is inherited from the series data.
|
|
782
|
+
"""
|
|
783
|
+
data_point = BubbleDataPoint(self, x, y, size, number_format)
|
|
784
|
+
self.append(data_point)
|
|
785
|
+
return data_point
|
|
786
|
+
|
|
787
|
+
@property
|
|
788
|
+
def bubble_sizes(self):
|
|
789
|
+
"""
|
|
790
|
+
A sequence containing the bubble size for each datapoint in this
|
|
791
|
+
series, in data point order.
|
|
792
|
+
"""
|
|
793
|
+
return [dp.bubble_size for dp in self._data_points]
|
|
794
|
+
|
|
795
|
+
@property
|
|
796
|
+
def bubble_sizes_ref(self):
|
|
797
|
+
"""
|
|
798
|
+
The Excel worksheet reference for the range containing the bubble
|
|
799
|
+
sizes for this series.
|
|
800
|
+
"""
|
|
801
|
+
return self._chart_data.bubble_sizes_ref(self)
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
class CategoryDataPoint(_BaseDataPoint):
|
|
805
|
+
"""
|
|
806
|
+
A data point in a category chart series. Provides access to the value of
|
|
807
|
+
the datapoint and the number format with which it should appear in the
|
|
808
|
+
Excel file.
|
|
809
|
+
"""
|
|
810
|
+
|
|
811
|
+
def __init__(self, series_data, value, number_format):
|
|
812
|
+
super(CategoryDataPoint, self).__init__(series_data, number_format)
|
|
813
|
+
self._value = value
|
|
814
|
+
|
|
815
|
+
@property
|
|
816
|
+
def value(self):
|
|
817
|
+
"""
|
|
818
|
+
The (Y) value for this category data point.
|
|
819
|
+
"""
|
|
820
|
+
return self._value
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
class XyDataPoint(_BaseDataPoint):
|
|
824
|
+
"""
|
|
825
|
+
A data point in an XY chart series. Provides access to the x and y values
|
|
826
|
+
of the datapoint.
|
|
827
|
+
"""
|
|
828
|
+
|
|
829
|
+
def __init__(self, series_data, x, y, number_format):
|
|
830
|
+
super(XyDataPoint, self).__init__(series_data, number_format)
|
|
831
|
+
self._x = x
|
|
832
|
+
self._y = y
|
|
833
|
+
|
|
834
|
+
@property
|
|
835
|
+
def x(self):
|
|
836
|
+
"""
|
|
837
|
+
The X value for this XY data point.
|
|
838
|
+
"""
|
|
839
|
+
return self._x
|
|
840
|
+
|
|
841
|
+
@property
|
|
842
|
+
def y(self):
|
|
843
|
+
"""
|
|
844
|
+
The Y value for this XY data point.
|
|
845
|
+
"""
|
|
846
|
+
return self._y
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
class BubbleDataPoint(XyDataPoint):
|
|
850
|
+
"""
|
|
851
|
+
A data point in a bubble chart series. Provides access to the x, y, and
|
|
852
|
+
size values of the datapoint.
|
|
853
|
+
"""
|
|
854
|
+
|
|
855
|
+
def __init__(self, series_data, x, y, size, number_format):
|
|
856
|
+
super(BubbleDataPoint, self).__init__(series_data, x, y, number_format)
|
|
857
|
+
self._size = size
|
|
858
|
+
|
|
859
|
+
@property
|
|
860
|
+
def bubble_size(self):
|
|
861
|
+
"""
|
|
862
|
+
The value representing the size of the bubble for this data point.
|
|
863
|
+
"""
|
|
864
|
+
return self._size
|