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/xlsx.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""Chart builder and related objects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import io
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
|
|
8
|
+
from xlsxwriter import Workbook
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _BaseWorkbookWriter(object):
|
|
12
|
+
"""Base class for workbook writers, providing shared members."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, chart_data):
|
|
15
|
+
super(_BaseWorkbookWriter, self).__init__()
|
|
16
|
+
self._chart_data = chart_data
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def xlsx_blob(self):
|
|
20
|
+
"""bytes for Excel file containing chart_data."""
|
|
21
|
+
xlsx_file = io.BytesIO()
|
|
22
|
+
with self._open_worksheet(xlsx_file) as (workbook, worksheet):
|
|
23
|
+
self._populate_worksheet(workbook, worksheet)
|
|
24
|
+
return xlsx_file.getvalue()
|
|
25
|
+
|
|
26
|
+
@contextmanager
|
|
27
|
+
def _open_worksheet(self, xlsx_file):
|
|
28
|
+
"""
|
|
29
|
+
Enable XlsxWriter Worksheet object to be opened, operated on, and
|
|
30
|
+
then automatically closed within a `with` statement. A filename or
|
|
31
|
+
stream object (such as an `io.BytesIO` instance) is expected as
|
|
32
|
+
*xlsx_file*.
|
|
33
|
+
"""
|
|
34
|
+
workbook = Workbook(xlsx_file, {"in_memory": True})
|
|
35
|
+
worksheet = workbook.add_worksheet()
|
|
36
|
+
yield workbook, worksheet
|
|
37
|
+
workbook.close()
|
|
38
|
+
|
|
39
|
+
def _populate_worksheet(self, workbook, worksheet):
|
|
40
|
+
"""
|
|
41
|
+
Must be overridden by each subclass to provide the particulars of
|
|
42
|
+
writing the spreadsheet data.
|
|
43
|
+
"""
|
|
44
|
+
raise NotImplementedError("must be provided by each subclass")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CategoryWorkbookWriter(_BaseWorkbookWriter):
|
|
48
|
+
"""
|
|
49
|
+
Determines Excel worksheet layout and can write an Excel workbook from
|
|
50
|
+
a CategoryChartData object. Serves as the authority for Excel worksheet
|
|
51
|
+
ranges.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def categories_ref(self):
|
|
56
|
+
"""
|
|
57
|
+
The Excel worksheet reference to the categories for this chart (not
|
|
58
|
+
including the column heading).
|
|
59
|
+
"""
|
|
60
|
+
categories = self._chart_data.categories
|
|
61
|
+
if categories.depth == 0:
|
|
62
|
+
raise ValueError("chart data contains no categories")
|
|
63
|
+
right_col = chr(ord("A") + categories.depth - 1)
|
|
64
|
+
bottom_row = categories.leaf_count + 1
|
|
65
|
+
return "Sheet1!$A$2:$%s$%d" % (right_col, bottom_row)
|
|
66
|
+
|
|
67
|
+
def series_name_ref(self, series):
|
|
68
|
+
"""
|
|
69
|
+
Return the Excel worksheet reference to the cell containing the name
|
|
70
|
+
for *series*. This also serves as the column heading for the series
|
|
71
|
+
values.
|
|
72
|
+
"""
|
|
73
|
+
return "Sheet1!$%s$1" % self._series_col_letter(series)
|
|
74
|
+
|
|
75
|
+
def values_ref(self, series):
|
|
76
|
+
"""
|
|
77
|
+
The Excel worksheet reference to the values for this series (not
|
|
78
|
+
including the column heading).
|
|
79
|
+
"""
|
|
80
|
+
return "Sheet1!${col_letter}$2:${col_letter}${bottom_row}".format(
|
|
81
|
+
**{
|
|
82
|
+
"col_letter": self._series_col_letter(series),
|
|
83
|
+
"bottom_row": len(series) + 1,
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def _column_reference(column_number):
|
|
89
|
+
"""Return str Excel column reference like 'BQ' for *column_number*.
|
|
90
|
+
|
|
91
|
+
*column_number* is an int in the range 1-16384 inclusive, where
|
|
92
|
+
1 maps to column 'A'.
|
|
93
|
+
"""
|
|
94
|
+
if column_number < 1 or column_number > 16384:
|
|
95
|
+
raise ValueError("column_number must be in range 1-16384")
|
|
96
|
+
|
|
97
|
+
# ---Work right-to-left, one order of magnitude at a time. Note there
|
|
98
|
+
# is no zero representation in Excel address scheme, so this is
|
|
99
|
+
# not just a conversion to base-26---
|
|
100
|
+
|
|
101
|
+
col_ref = ""
|
|
102
|
+
while column_number:
|
|
103
|
+
remainder = column_number % 26
|
|
104
|
+
if remainder == 0:
|
|
105
|
+
remainder = 26
|
|
106
|
+
|
|
107
|
+
col_letter = chr(ord("A") + remainder - 1)
|
|
108
|
+
col_ref = col_letter + col_ref
|
|
109
|
+
|
|
110
|
+
# ---Advance to next order of magnitude or terminate loop. The
|
|
111
|
+
# minus-one in this expression reflects the fact the next lower
|
|
112
|
+
# order of magnitude has a minumum value of 1 (not zero). This is
|
|
113
|
+
# essentially the complement to the "if it's 0 make it 26' step
|
|
114
|
+
# above.---
|
|
115
|
+
column_number = (column_number - 1) // 26
|
|
116
|
+
|
|
117
|
+
return col_ref
|
|
118
|
+
|
|
119
|
+
def _populate_worksheet(self, workbook, worksheet):
|
|
120
|
+
"""
|
|
121
|
+
Write the chart data contents to *worksheet* in category chart
|
|
122
|
+
layout. Write categories starting in the first column starting in
|
|
123
|
+
the second row, and proceeding one column per category level (for
|
|
124
|
+
charts having multi-level categories). Write series as columns
|
|
125
|
+
starting in the next following column, placing the series title in
|
|
126
|
+
the first cell.
|
|
127
|
+
"""
|
|
128
|
+
self._write_categories(workbook, worksheet)
|
|
129
|
+
self._write_series(workbook, worksheet)
|
|
130
|
+
|
|
131
|
+
def _series_col_letter(self, series):
|
|
132
|
+
"""
|
|
133
|
+
The letter of the Excel worksheet column in which the data for a
|
|
134
|
+
series appears.
|
|
135
|
+
"""
|
|
136
|
+
column_number = 1 + series.categories.depth + series.index
|
|
137
|
+
return self._column_reference(column_number)
|
|
138
|
+
|
|
139
|
+
def _write_categories(self, workbook, worksheet):
|
|
140
|
+
"""
|
|
141
|
+
Write the categories column(s) to *worksheet*. Categories start in
|
|
142
|
+
the first column starting in the second row, and proceeding one
|
|
143
|
+
column per category level (for charts having multi-level categories).
|
|
144
|
+
A date category is formatted as a date. All others are formatted
|
|
145
|
+
`General`.
|
|
146
|
+
"""
|
|
147
|
+
categories = self._chart_data.categories
|
|
148
|
+
num_format = workbook.add_format({"num_format": categories.number_format})
|
|
149
|
+
depth = categories.depth
|
|
150
|
+
for idx, level in enumerate(categories.levels):
|
|
151
|
+
col = depth - idx - 1
|
|
152
|
+
self._write_cat_column(worksheet, col, level, num_format)
|
|
153
|
+
|
|
154
|
+
def _write_cat_column(self, worksheet, col, level, num_format):
|
|
155
|
+
"""
|
|
156
|
+
Write a category column defined by *level* to *worksheet* at offset
|
|
157
|
+
*col* and formatted with *num_format*.
|
|
158
|
+
"""
|
|
159
|
+
worksheet.set_column(col, col, 10) # wide enough for a date
|
|
160
|
+
for off, name in level:
|
|
161
|
+
row = off + 1
|
|
162
|
+
worksheet.write(row, col, name, num_format)
|
|
163
|
+
|
|
164
|
+
def _write_series(self, workbook, worksheet):
|
|
165
|
+
"""
|
|
166
|
+
Write the series column(s) to *worksheet*. Series start in the column
|
|
167
|
+
following the last categories column, placing the series title in the
|
|
168
|
+
first cell.
|
|
169
|
+
"""
|
|
170
|
+
col_offset = self._chart_data.categories.depth
|
|
171
|
+
for idx, series in enumerate(self._chart_data):
|
|
172
|
+
num_format = workbook.add_format({"num_format": series.number_format})
|
|
173
|
+
series_col = idx + col_offset
|
|
174
|
+
worksheet.write(0, series_col, series.name)
|
|
175
|
+
worksheet.write_column(1, series_col, series.values, num_format)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class XyWorkbookWriter(_BaseWorkbookWriter):
|
|
179
|
+
"""
|
|
180
|
+
Determines Excel worksheet layout and can write an Excel workbook from XY
|
|
181
|
+
chart data. Serves as the authority for Excel worksheet ranges.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
def series_name_ref(self, series):
|
|
185
|
+
"""
|
|
186
|
+
Return the Excel worksheet reference to the cell containing the name
|
|
187
|
+
for *series*. This also serves as the column heading for the series
|
|
188
|
+
Y values.
|
|
189
|
+
"""
|
|
190
|
+
row = self.series_table_row_offset(series) + 1
|
|
191
|
+
return "Sheet1!$B$%d" % row
|
|
192
|
+
|
|
193
|
+
def series_table_row_offset(self, series):
|
|
194
|
+
"""
|
|
195
|
+
Return the number of rows preceding the data table for *series* in
|
|
196
|
+
the Excel worksheet.
|
|
197
|
+
"""
|
|
198
|
+
title_and_spacer_rows = series.index * 2
|
|
199
|
+
data_point_rows = series.data_point_offset
|
|
200
|
+
return title_and_spacer_rows + data_point_rows
|
|
201
|
+
|
|
202
|
+
def x_values_ref(self, series):
|
|
203
|
+
"""
|
|
204
|
+
The Excel worksheet reference to the X values for this chart (not
|
|
205
|
+
including the column label).
|
|
206
|
+
"""
|
|
207
|
+
top_row = self.series_table_row_offset(series) + 2
|
|
208
|
+
bottom_row = top_row + len(series) - 1
|
|
209
|
+
return "Sheet1!$A$%d:$A$%d" % (top_row, bottom_row)
|
|
210
|
+
|
|
211
|
+
def y_values_ref(self, series):
|
|
212
|
+
"""
|
|
213
|
+
The Excel worksheet reference to the Y values for this chart (not
|
|
214
|
+
including the column label).
|
|
215
|
+
"""
|
|
216
|
+
top_row = self.series_table_row_offset(series) + 2
|
|
217
|
+
bottom_row = top_row + len(series) - 1
|
|
218
|
+
return "Sheet1!$B$%d:$B$%d" % (top_row, bottom_row)
|
|
219
|
+
|
|
220
|
+
def _populate_worksheet(self, workbook, worksheet):
|
|
221
|
+
"""
|
|
222
|
+
Write chart data contents to *worksheet* in the standard XY chart
|
|
223
|
+
layout. Write the data for each series to a separate two-column
|
|
224
|
+
table, X values in column A and Y values in column B. Place the
|
|
225
|
+
series label in the first (heading) cell of the column.
|
|
226
|
+
"""
|
|
227
|
+
chart_num_format = workbook.add_format({"num_format": self._chart_data.number_format})
|
|
228
|
+
for series in self._chart_data:
|
|
229
|
+
series_num_format = workbook.add_format({"num_format": series.number_format})
|
|
230
|
+
offset = self.series_table_row_offset(series)
|
|
231
|
+
# write X values
|
|
232
|
+
worksheet.write_column(offset + 1, 0, series.x_values, chart_num_format)
|
|
233
|
+
# write Y values
|
|
234
|
+
worksheet.write(offset, 1, series.name)
|
|
235
|
+
worksheet.write_column(offset + 1, 1, series.y_values, series_num_format)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class BubbleWorkbookWriter(XyWorkbookWriter):
|
|
239
|
+
"""
|
|
240
|
+
Service object that knows how to write an Excel workbook from bubble
|
|
241
|
+
chart data.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def bubble_sizes_ref(self, series):
|
|
245
|
+
"""
|
|
246
|
+
The Excel worksheet reference to the range containing the bubble
|
|
247
|
+
sizes for *series* (not including the column heading cell).
|
|
248
|
+
"""
|
|
249
|
+
top_row = self.series_table_row_offset(series) + 2
|
|
250
|
+
bottom_row = top_row + len(series) - 1
|
|
251
|
+
return "Sheet1!$C$%d:$C$%d" % (top_row, bottom_row)
|
|
252
|
+
|
|
253
|
+
def _populate_worksheet(self, workbook, worksheet):
|
|
254
|
+
"""
|
|
255
|
+
Write chart data contents to *worksheet* in the bubble chart layout.
|
|
256
|
+
Write the data for each series to a separate three-column table with
|
|
257
|
+
X values in column A, Y values in column B, and bubble sizes in
|
|
258
|
+
column C. Place the series label in the first (heading) cell of the
|
|
259
|
+
values column.
|
|
260
|
+
"""
|
|
261
|
+
chart_num_format = workbook.add_format({"num_format": self._chart_data.number_format})
|
|
262
|
+
for series in self._chart_data:
|
|
263
|
+
series_num_format = workbook.add_format({"num_format": series.number_format})
|
|
264
|
+
offset = self.series_table_row_offset(series)
|
|
265
|
+
# write X values
|
|
266
|
+
worksheet.write_column(offset + 1, 0, series.x_values, chart_num_format)
|
|
267
|
+
# write Y values
|
|
268
|
+
worksheet.write(offset, 1, series.name)
|
|
269
|
+
worksheet.write_column(offset + 1, 1, series.y_values, series_num_format)
|
|
270
|
+
# write bubble sizes
|
|
271
|
+
worksheet.write(offset, 2, "Size")
|
|
272
|
+
worksheet.write_column(offset + 1, 2, series.bubble_sizes, chart_num_format)
|