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 . import chart
11
12
13class ChartLine(chart.Chart):
14 """
15 A class for writing the Excel XLSX Line charts.
16
17
18 """
19
20 ###########################################################################
21 #
22 # Public API.
23 #
24 ###########################################################################
25
26 def __init__(self, options=None):
27 """
28 Constructor.
29
30 """
31 super().__init__()
32
33 if options is None:
34 options = {}
35
36 self.subtype = options.get("subtype")
37
38 if not self.subtype:
39 self.subtype = "standard"
40
41 self.default_marker = {"type": "none"}
42 self.smooth_allowed = True
43
44 # Override and reset the default axis values.
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 = "right"
50 self.label_positions = {
51 "center": "ctr",
52 "right": "r",
53 "left": "l",
54 "above": "t",
55 "below": "b",
56 # For backward compatibility.
57 "top": "t",
58 "bottom": "b",
59 }
60
61 self.set_y_axis({})
62
63 ###########################################################################
64 #
65 # Private API.
66 #
67 ###########################################################################
68
69 def _write_chart_type(self, args):
70 # Override the virtual superclass method with a chart specific method.
71 # Write the c:lineChart element.
72 self._write_line_chart(args)
73
74 ###########################################################################
75 #
76 # XML methods.
77 #
78 ###########################################################################
79
80 def _write_line_chart(self, args):
81 # Write the <c:lineChart> element.
82
83 if args["primary_axes"]:
84 series = self._get_primary_axes_series()
85 else:
86 series = self._get_secondary_axes_series()
87
88 if not series:
89 return
90
91 subtype = self.subtype
92
93 if subtype == "percent_stacked":
94 subtype = "percentStacked"
95
96 self._xml_start_tag("c:lineChart")
97
98 # Write the c:grouping element.
99 self._write_grouping(subtype)
100
101 # Write the series elements.
102 for data in series:
103 self._write_ser(data)
104
105 # Write the c:dropLines element.
106 self._write_drop_lines()
107
108 # Write the c:hiLowLines element.
109 self._write_hi_low_lines()
110
111 # Write the c:upDownBars element.
112 self._write_up_down_bars()
113
114 # Write the c:marker element.
115 self._write_marker_value()
116
117 # Write the c:axId elements
118 self._write_axis_ids(args)
119
120 self._xml_end_tag("c:lineChart")
121
122 def _write_d_pt_point(self, index, point):
123 # Write an individual <c:dPt> element. Override the parent method to
124 # add markers.
125
126 self._xml_start_tag("c:dPt")
127
128 # Write the c:idx element.
129 self._write_idx(index)
130
131 self._xml_start_tag("c:marker")
132
133 # Write the c:spPr element.
134 self._write_sp_pr(point)
135
136 self._xml_end_tag("c:marker")
137
138 self._xml_end_tag("c:dPt")
139
140 def _write_marker_value(self):
141 # Write the <c:marker> element without a sub-element.
142 attributes = [("val", 1)]
143
144 self._xml_empty_tag("c:marker", attributes)