-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Expand file tree
/
Copy pathcontainer.py
More file actions
255 lines (200 loc) · 7.94 KB
/
container.py
File metadata and controls
255 lines (200 loc) · 7.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
from matplotlib import cbook
from matplotlib.artist import Artist
class Container(tuple):
"""
Base class for containers.
Containers are classes that collect semantically related Artists such as
the bars of a bar plot.
"""
def __repr__(self):
return f"<{type(self).__name__} object of {len(self)} artists>"
def __new__(cls, *args, **kwargs):
return tuple.__new__(cls, args[0])
def __init__(self, kl, label=None):
self._callbacks = cbook.CallbackRegistry(signals=["pchanged"])
self._remove_method = None
self._label = str(label) if label is not None else None
def remove(self):
for c in cbook.flatten(
self, scalarp=lambda x: isinstance(x, Artist)):
if c is not None:
c.remove()
if self._remove_method:
self._remove_method(self)
def get_children(self):
return [child for child in cbook.flatten(self) if child is not None]
get_label = Artist.get_label
set_label = Artist.set_label
add_callback = Artist.add_callback
remove_callback = Artist.remove_callback
pchanged = Artist.pchanged
class BarContainer(Container):
"""
Container for the artists of bar plots (e.g. created by `.Axes.bar`).
The container can be treated as a tuple of the *patches* themselves.
Additionally, you can access these and further parameters by the
attributes.
Attributes
----------
patches : list of :class:`~matplotlib.patches.Rectangle`
The artists of the bars.
errorbar : None or :class:`~matplotlib.container.ErrorbarContainer`
A container for the error bar artists if error bars are present.
*None* otherwise.
datavalues : None or array-like
The underlying data values corresponding to the bars.
orientation : {'vertical', 'horizontal'}, default: None
If 'vertical', the bars are assumed to be vertical.
If 'horizontal', the bars are assumed to be horizontal.
"""
def __init__(self, patches, errorbar=None, *, datavalues=None,
orientation=None, **kwargs):
self.patches = patches
self.errorbar = errorbar
self.datavalues = datavalues
self.orientation = orientation
super().__init__(patches, **kwargs)
@property
def bottoms(self):
"""
Return the values at the lower end of the bars.
.. versionadded:: 3.11
"""
if self.orientation == 'vertical':
return [p.get_y() for p in self.patches]
elif self.orientation == 'horizontal':
return [p.get_x() for p in self.patches]
else:
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
@property
def tops(self):
"""
Return the values at the upper end of the bars.
.. versionadded:: 3.11
"""
if self.orientation == 'vertical':
return [p.get_y() + p.get_height() for p in self.patches]
elif self.orientation == 'horizontal':
return [p.get_x() + p.get_width() for p in self.patches]
else:
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
@property
def position_centers(self):
"""
Return the centers of bar positions.
.. versionadded:: 3.11
"""
if self.orientation == 'vertical':
return [p.get_x() + p.get_width() / 2 for p in self.patches]
elif self.orientation == 'horizontal':
return [p.get_y() + p.get_height() / 2 for p in self.patches]
else:
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
class ErrorbarContainer(Container):
"""
Container for the artists of error bars (e.g. created by `.Axes.errorbar`).
The container can be treated as the *lines* tuple itself.
Additionally, you can access these and further parameters by the
attributes.
Attributes
----------
lines : tuple
Tuple of ``(data_line, caplines, barlinecols)``.
- data_line : A `~matplotlib.lines.Line2D` instance of x, y plot markers
and/or line.
- caplines : A tuple of `~matplotlib.lines.Line2D` instances of the error
bar caps.
- barlinecols : A tuple of `~matplotlib.collections.LineCollection` with the
horizontal and vertical error ranges.
has_xerr, has_yerr : bool
``True`` if the errorbar has x/y errors.
"""
def __init__(self, lines, has_xerr=False, has_yerr=False, **kwargs):
self.lines = lines
self.has_xerr = has_xerr
self.has_yerr = has_yerr
super().__init__(lines, **kwargs)
class PieContainer:
"""
Container for the artists of pie charts (e.g. created by `.Axes.pie`).
.. versionadded:: 3.11
.. warning::
The class name ``PieContainer`` name is provisional and may change in future
to reflect development of its functionality.
You can access the wedge patches and further parameters by the attributes.
Attributes
----------
wedges : list of `~matplotlib.patches.Wedge`
The artists of the pie wedges.
values : `numpy.ndarray`
The data that the pie is based on.
fracs : `numpy.ndarray`
The fraction of the pie that each wedge represents.
texts : list of list of `~matplotlib.text.Text`
The artists of any labels on the pie wedges. Each inner list has one
text label per wedge.
"""
def __init__(self, wedges, values, normalize):
self.wedges = wedges
self._texts = []
self._values = values
self._normalize = normalize
@property
def texts(self):
# Only return non-empty sublists. An empty sublist may have been added
# for backwards compatibility of the Axes.pie return value (see __getitem__).
return [t_list for t_list in self._texts if t_list]
@property
def values(self):
result = self._values.copy()
result.flags.writeable = False
return result
@property
def fracs(self):
if self._normalize:
result = self._values / self._values.sum()
else:
result = self._values
result.flags.writeable = False
return result
def add_texts(self, texts):
"""Add a list of `~matplotlib.text.Text` objects to the container."""
self._texts.append(texts)
def remove(self):
"""Remove all wedges and texts from the axes"""
for artist_list in self.wedges, self._texts:
for artist in cbook.flatten(artist_list):
artist.remove()
def __getitem__(self, key):
# needed to support unpacking into a tuple for backward compatibility of the
# Axes.pie return value
return (self.wedges, *self._texts)[key]
class StemContainer(Container):
"""
Container for the artists created in a :meth:`.Axes.stem` plot.
The container can be treated like a namedtuple ``(markerline, stemlines,
baseline)``.
Attributes
----------
markerline : `~matplotlib.lines.Line2D`
The artist of the markers at the stem heads.
stemlines : `~matplotlib.collections.LineCollection`
The artists of the vertical lines for all stems.
baseline : `~matplotlib.lines.Line2D`
The artist of the horizontal baseline.
"""
def __init__(self, markerline_stemlines_baseline, **kwargs):
"""
Parameters
----------
markerline_stemlines_baseline : tuple
Tuple of ``(markerline, stemlines, baseline)``.
``markerline`` contains the `.Line2D` of the markers,
``stemlines`` is a `.LineCollection` of the main lines,
``baseline`` is the `.Line2D` of the baseline.
"""
markerline, stemlines, baseline = markerline_stemlines_baseline
self.markerline = markerline
self.stemlines = stemlines
self.baseline = baseline
super().__init__(markerline_stemlines_baseline, **kwargs)