1###############################################################################
2#
3# ChartLine - A class for writing the Excel XLSX Line 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 ChartLine(chart.Chart):
16 """
17 A class for writing the Excel XLSX Line 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 = "standard"
42
43 self.default_marker = {"type": "none"}
44 self.smooth_allowed = True
45
46 # Override and reset the default axis values.
47 if self.subtype == "percent_stacked":
48 self.y_axis["defaults"]["num_format"] = "0%"
49
50 # Set the available data label positions for this chart type.
51 self.label_position_default = "right"
52 self.label_positions = {
53 "center": "ctr",
54 "right": "r",
55 "left": "l",
56 "above": "t",
57 "below": "b",
58 # For backward compatibility.
59 "top": "t",
60 "bottom": "b",
61 }
62
63 self.set_y_axis({})
64
65 ###########################################################################
66 #
67 # Private API.
68 #
69 ###########################################################################
70
71 def _write_chart_type(self, args) -> None:
72 # Override the virtual superclass method with a chart specific method.
73 # Write the c:lineChart element.
74 self._write_line_chart(args)
75
76 ###########################################################################
77 #
78 # XML methods.
79 #
80 ###########################################################################
81
82 def _write_line_chart(self, args) -> None:
83 # Write the <c:lineChart> element.
84
85 if args["primary_axes"]:
86 series = self._get_primary_axes_series()
87 else:
88 series = self._get_secondary_axes_series()
89
90 if not series:
91 return
92
93 subtype = self.subtype
94
95 if subtype == "percent_stacked":
96 subtype = "percentStacked"
97
98 self._xml_start_tag("c:lineChart")
99
100 # Write the c:grouping element.
101 self._write_grouping(subtype)
102
103 # Write the series elements.
104 for data in series:
105 self._write_ser(data)
106
107 # Write the c:dropLines element.
108 self._write_drop_lines()
109
110 # Write the c:hiLowLines element.
111 self._write_hi_low_lines()
112
113 # Write the c:upDownBars element.
114 self._write_up_down_bars()
115
116 # Write the c:marker element.
117 self._write_marker_value()
118
119 # Write the c:axId elements
120 self._write_axis_ids(args)
121
122 self._xml_end_tag("c:lineChart")
123
124 def _write_d_pt_point(self, index, point) -> None:
125 # Write an individual <c:dPt> element. Override the parent method to
126 # add markers.
127
128 self._xml_start_tag("c:dPt")
129
130 # Write the c:idx element.
131 self._write_idx(index)
132
133 self._xml_start_tag("c:marker")
134
135 # Write the c:spPr element.
136 self._write_sp_pr(point)
137
138 self._xml_end_tag("c:marker")
139
140 self._xml_end_tag("c:dPt")
141
142 def _write_marker_value(self) -> None:
143 # Write the <c:marker> element without a sub-element.
144 attributes = [("val", 1)]
145
146 self._xml_empty_tag("c:marker", attributes)