1###############################################################################
2#
3# ChartColumn - A class for writing the Excel XLSX Column charts.
4#
5# SPDX-License-Identifier: BSD-2-Clause
6#
7# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org
8#
9
10from typing import Any, Dict, Optional
11
12from . import chart
13
14
15class ChartColumn(chart.Chart):
16 """
17 A class for writing the Excel XLSX Column charts.
18
19
20 """
21
22 ###########################################################################
23 #
24 # Public API.
25 #
26 ###########################################################################
27
28 def __init__(self, options: Optional[Dict[str, Any]] = None) -> None:
29 """
30 Constructor.
31
32 """
33 super().__init__()
34
35 if options is None:
36 options = {}
37
38 self.subtype = options.get("subtype")
39
40 if not self.subtype:
41 self.subtype = "clustered"
42
43 self.horiz_val_axis = 0
44
45 if self.subtype == "percent_stacked":
46 self.y_axis["defaults"]["num_format"] = "0%"
47
48 # Set the available data label positions for this chart type.
49 self.label_position_default = "outside_end"
50 self.label_positions = {
51 "center": "ctr",
52 "inside_base": "inBase",
53 "inside_end": "inEnd",
54 "outside_end": "outEnd",
55 }
56
57 self.set_y_axis({})
58
59 ###########################################################################
60 #
61 # Private API.
62 #
63 ###########################################################################
64
65 def _write_chart_type(self, args) -> None:
66 # Override the virtual superclass method with a chart specific method.
67
68 # Write the c:barChart element.
69 self._write_bar_chart(args)
70
71 def _write_bar_chart(self, args) -> None:
72 # Write the <c:barChart> element.
73
74 if args["primary_axes"]:
75 series = self._get_primary_axes_series()
76 else:
77 series = self._get_secondary_axes_series()
78
79 if not series:
80 return
81
82 subtype = self.subtype
83 if subtype == "percent_stacked":
84 subtype = "percentStacked"
85
86 # Set a default overlap for stacked charts.
87 if "stacked" in self.subtype and self.series_overlap_1 is None:
88 self.series_overlap_1 = 100
89
90 self._xml_start_tag("c:barChart")
91
92 # Write the c:barDir element.
93 self._write_bar_dir()
94
95 # Write the c:grouping element.
96 self._write_grouping(subtype)
97
98 # Write the c:ser elements.
99 for data in series:
100 self._write_ser(data)
101
102 # Write the c:gapWidth element.
103 if args["primary_axes"]:
104 self._write_gap_width(self.series_gap_1)
105 else:
106 self._write_gap_width(self.series_gap_2)
107
108 # Write the c:overlap element.
109 if args["primary_axes"]:
110 self._write_overlap(self.series_overlap_1)
111 else:
112 self._write_overlap(self.series_overlap_2)
113
114 # Write the c:axId elements
115 self._write_axis_ids(args)
116
117 self._xml_end_tag("c:barChart")
118
119 ###########################################################################
120 #
121 # XML methods.
122 #
123 ###########################################################################
124
125 def _write_bar_dir(self) -> None:
126 # Write the <c:barDir> element.
127 val = "col"
128
129 attributes = [("val", val)]
130
131 self._xml_empty_tag("c:barDir", attributes)
132
133 def _write_err_dir(self, val) -> None:
134 # Overridden from Chart class since it is not used in Column charts.
135 pass