Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/xlsxwriter/chart_pie.py: 16%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1###############################################################################
2#
3# ChartPie - A class for writing the Excel XLSX Pie charts.
4#
5# SPDX-License-Identifier: BSD-2-Clause
6# Copyright 2013-2024, John McNamara, jmcnamara@cpan.org
7#
9from warnings import warn
10from . import chart
13class ChartPie(chart.Chart):
14 """
15 A class for writing the Excel XLSX Pie charts.
18 """
20 ###########################################################################
21 #
22 # Public API.
23 #
24 ###########################################################################
26 def __init__(self, options=None):
27 """
28 Constructor.
30 """
31 super(ChartPie, self).__init__()
33 self.vary_data_color = 1
34 self.rotation = 0
36 # Set the available data label positions for this chart type.
37 self.label_position_default = "best_fit"
38 self.label_positions = {
39 "center": "ctr",
40 "inside_end": "inEnd",
41 "outside_end": "outEnd",
42 "best_fit": "bestFit",
43 }
45 def set_rotation(self, rotation):
46 """
47 Set the Pie/Doughnut chart rotation: the angle of the first slice.
49 Args:
50 rotation: First segment angle: 0 <= rotation <= 360.
52 Returns:
53 Nothing.
55 """
56 if rotation is None:
57 return
59 # Ensure the rotation is in Excel's range.
60 if rotation < 0 or rotation > 360:
61 warn(
62 "Chart rotation %d outside Excel range: 0 <= rotation <= 360" % rotation
63 )
64 return
66 self.rotation = int(rotation)
68 ###########################################################################
69 #
70 # Private API.
71 #
72 ###########################################################################
74 def _write_chart_type(self, args):
75 # Override the virtual superclass method with a chart specific method.
76 # Write the c:pieChart element.
77 self._write_pie_chart(args)
79 ###########################################################################
80 #
81 # XML methods.
82 #
83 ###########################################################################
85 def _write_pie_chart(self, args):
86 # Write the <c:pieChart> element. Over-ridden method to remove
87 # axis_id code since Pie charts don't require val and cat axes.
88 self._xml_start_tag("c:pieChart")
90 # Write the c:varyColors element.
91 self._write_vary_colors()
93 # Write the series elements.
94 for data in self.series:
95 self._write_ser(data)
97 # Write the c:firstSliceAng element.
98 self._write_first_slice_ang()
100 self._xml_end_tag("c:pieChart")
102 def _write_plot_area(self):
103 # Over-ridden method to remove the cat_axis() and val_axis() code
104 # since Pie charts don't require those axes.
105 #
106 # Write the <c:plotArea> element.
108 self._xml_start_tag("c:plotArea")
110 # Write the c:layout element.
111 self._write_layout(self.plotarea.get("layout"), "plot")
113 # Write the subclass chart type element.
114 self._write_chart_type(None)
115 # Configure a combined chart if present.
116 second_chart = self.combined
118 if second_chart:
119 # Secondary axis has unique id otherwise use same as primary.
120 if second_chart.is_secondary:
121 second_chart.id = 1000 + self.id
122 else:
123 second_chart.id = self.id
125 # Share the same filehandle for writing.
126 second_chart.fh = self.fh
128 # Share series index with primary chart.
129 second_chart.series_index = self.series_index
131 # Write the subclass chart type elements for combined chart.
132 second_chart._write_chart_type(None)
134 # Write the c:spPr element for the plotarea formatting.
135 self._write_sp_pr(self.plotarea)
137 self._xml_end_tag("c:plotArea")
139 def _write_legend(self):
140 # Over-ridden method to add <c:txPr> to legend.
141 # Write the <c:legend> element.
142 legend = self.legend
143 position = legend.get("position", "right")
144 font = legend.get("font")
145 delete_series = []
146 overlay = 0
148 if legend.get("delete_series") and isinstance(legend["delete_series"], list):
149 delete_series = legend["delete_series"]
151 if position.startswith("overlay_"):
152 position = position.replace("overlay_", "")
153 overlay = 1
155 allowed = {
156 "right": "r",
157 "left": "l",
158 "top": "t",
159 "bottom": "b",
160 "top_right": "tr",
161 }
163 if position == "none":
164 return
166 if position not in allowed:
167 return
169 position = allowed[position]
171 self._xml_start_tag("c:legend")
173 # Write the c:legendPos element.
174 self._write_legend_pos(position)
176 # Remove series labels from the legend.
177 for index in delete_series:
178 # Write the c:legendEntry element.
179 self._write_legend_entry(index)
181 # Write the c:layout element.
182 self._write_layout(legend.get("layout"), "legend")
184 # Write the c:overlay element.
185 if overlay:
186 self._write_overlay()
188 # Write the c:spPr element.
189 self._write_sp_pr(legend)
191 # Write the c:txPr element. Over-ridden.
192 self._write_tx_pr_legend(None, font)
194 self._xml_end_tag("c:legend")
196 def _write_tx_pr_legend(self, horiz, font):
197 # Write the <c:txPr> element for legends.
199 if font and font.get("rotation"):
200 rotation = font["rotation"]
201 else:
202 rotation = None
204 self._xml_start_tag("c:txPr")
206 # Write the a:bodyPr element.
207 self._write_a_body_pr(rotation, horiz)
209 # Write the a:lstStyle element.
210 self._write_a_lst_style()
212 # Write the a:p element.
213 self._write_a_p_legend(font)
215 self._xml_end_tag("c:txPr")
217 def _write_a_p_legend(self, font):
218 # Write the <a:p> element for legends.
220 self._xml_start_tag("a:p")
222 # Write the a:pPr element.
223 self._write_a_p_pr_legend(font)
225 # Write the a:endParaRPr element.
226 self._write_a_end_para_rpr()
228 self._xml_end_tag("a:p")
230 def _write_a_p_pr_legend(self, font):
231 # Write the <a:pPr> element for legends.
232 attributes = [("rtl", 0)]
234 self._xml_start_tag("a:pPr", attributes)
236 # Write the a:defRPr element.
237 self._write_a_def_rpr(font)
239 self._xml_end_tag("a:pPr")
241 def _write_vary_colors(self):
242 # Write the <c:varyColors> element.
243 attributes = [("val", 1)]
245 self._xml_empty_tag("c:varyColors", attributes)
247 def _write_first_slice_ang(self):
248 # Write the <c:firstSliceAng> element.
249 attributes = [("val", self.rotation)]
251 self._xml_empty_tag("c:firstSliceAng", attributes)
253 def _write_show_leader_lines(self):
254 # Write the <c:showLeaderLines> element.
255 #
256 # This is for Pie/Doughnut charts. Other chart types only supported
257 # leader lines after Excel 2015 via an extension element.
258 attributes = [("val", 1)]
260 self._xml_empty_tag("c:showLeaderLines", attributes)