Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/chart/_chart.py: 35%
125 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright (c) 2010-2022 openpyxl
3from collections import OrderedDict
4from operator import attrgetter
6from openpyxl.descriptors import (
7 Typed,
8 Integer,
9 Alias,
10 MinMax,
11 Bool,
12 Set,
13)
14from openpyxl.descriptors.sequence import ValueSequence
15from openpyxl.descriptors.serialisable import Serialisable
17from ._3d import _3DBase
18from .data_source import AxDataSource, NumRef
19from .layout import Layout
20from .legend import Legend
21from .reference import Reference
22from .series_factory import SeriesFactory
23from .series import attribute_mapping
24from .shapes import GraphicalProperties
25from .title import TitleDescriptor
27class AxId(Serialisable):
29 val = Integer()
31 def __init__(self, val):
32 self.val = val
35def PlotArea():
36 from .chartspace import PlotArea
37 return PlotArea()
40class ChartBase(Serialisable):
42 """
43 Base class for all charts
44 """
46 legend = Typed(expected_type=Legend, allow_none=True)
47 layout = Typed(expected_type=Layout, allow_none=True)
48 roundedCorners = Bool(allow_none=True)
49 axId = ValueSequence(expected_type=int)
50 visible_cells_only = Bool(allow_none=True)
51 display_blanks = Set(values=['span', 'gap', 'zero'])
53 _series_type = ""
54 ser = ()
55 series = Alias('ser')
56 title = TitleDescriptor()
57 anchor = "E15" # default anchor position
58 width = 15 # in cm, approx 5 rows
59 height = 7.5 # in cm, approx 14 rows
60 _id = 1
61 _path = "/xl/charts/chart{0}.xml"
62 style = MinMax(allow_none=True, min=1, max=48)
63 mime_type = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
64 graphical_properties = Typed(expected_type=GraphicalProperties, allow_none=True)
66 __elements__ = ()
69 def __init__(self, axId=(), **kw):
70 self._charts = [self]
71 self.title = None
72 self.layout = None
73 self.roundedCorners = None
74 self.legend = Legend()
75 self.graphical_properties = None
76 self.style = None
77 self.plot_area = PlotArea()
78 self.axId = axId
79 self.display_blanks = 'gap'
80 self.pivotSource = None
81 self.pivotFormats = ()
82 self.visible_cells_only = True
83 self.idx_base = 0
84 super(ChartBase, self).__init__()
87 def __hash__(self):
88 """
89 Just need to check for identity
90 """
91 return id(self)
93 def __iadd__(self, other):
94 """
95 Combine the chart with another one
96 """
97 if not isinstance(other, ChartBase):
98 raise TypeError("Only other charts can be added")
99 self._charts.append(other)
100 return self
103 def to_tree(self, namespace=None, tagname=None, idx=None):
104 self.axId = [id for id in self._axes]
105 if self.ser is not None:
106 for s in self.ser:
107 s.__elements__ = attribute_mapping[self._series_type]
108 return super(ChartBase, self).to_tree(tagname, idx)
111 def _reindex(self):
112 """
113 Normalise and rebase series: sort by order and then rebase order
115 """
116 # sort data series in order and rebase
117 ds = sorted(self.series, key=attrgetter("order"))
118 for idx, s in enumerate(ds):
119 s.order = idx
120 self.series = ds
123 def _write(self):
124 from .chartspace import ChartSpace, ChartContainer
125 self.plot_area.layout = self.layout
127 idx_base = self.idx_base
128 for chart in self._charts:
129 if chart not in self.plot_area._charts:
130 chart.idx_base = idx_base
131 idx_base += len(chart.series)
132 self.plot_area._charts = self._charts
134 container = ChartContainer(plotArea=self.plot_area, legend=self.legend, title=self.title)
135 if isinstance(chart, _3DBase):
136 container.view3D = chart.view3D
137 container.floor = chart.floor
138 container.sideWall = chart.sideWall
139 container.backWall = chart.backWall
140 container.plotVisOnly = self.visible_cells_only
141 container.dispBlanksAs = self.display_blanks
142 container.pivotFmts = self.pivotFormats
143 cs = ChartSpace(chart=container)
144 cs.style = self.style
145 cs.roundedCorners = self.roundedCorners
146 cs.pivotSource = self.pivotSource
147 return cs.to_tree()
150 @property
151 def _axes(self):
152 x = getattr(self, "x_axis", None)
153 y = getattr(self, "y_axis", None)
154 z = getattr(self, "z_axis", None)
155 return OrderedDict([(axis.axId, axis) for axis in (x, y, z) if axis])
158 def set_categories(self, labels):
159 """
160 Set the categories / x-axis values
161 """
162 if not isinstance(labels, Reference):
163 labels = Reference(range_string=labels)
164 for s in self.ser:
165 s.cat = AxDataSource(numRef=NumRef(f=labels))
168 def add_data(self, data, from_rows=False, titles_from_data=False):
169 """
170 Add a range of data in a single pass.
171 The default is to treat each column as a data series.
172 """
173 if not isinstance(data, Reference):
174 data = Reference(range_string=data)
176 if from_rows:
177 values = data.rows
179 else:
180 values = data.cols
182 for ref in values:
183 series = SeriesFactory(ref, title_from_data=titles_from_data)
184 self.series.append(series)
187 def append(self, value):
188 """Append a data series to the chart"""
189 l = self.series[:]
190 l.append(value)
191 self.series = l
194 @property
195 def path(self):
196 return self._path.format(self._id)