diplotocus 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diplotocus/GUI/GUI.html +120 -0
- diplotocus/GUI/__init__.py +2 -0
- diplotocus/GUI/app.js +1646 -0
- diplotocus/GUI/server.py +1352 -0
- diplotocus/GUI/src/bg.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Draw.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Morph.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Rotate.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Scale.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Sequence.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Translate.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_Tween.png +0 -0
- diplotocus/GUI/src/btn/btn_bg_default.png +0 -0
- diplotocus/GUI/src/favicon.ico +0 -0
- diplotocus/GUI/src/logo_bg.png +0 -0
- diplotocus/GUI/style.css +622 -0
- diplotocus/__init__.py +4 -0
- diplotocus/_version.py +1 -0
- diplotocus/animations.py +3686 -0
- diplotocus/core.py +358 -0
- diplotocus/easings.py +284 -0
- diplotocus-0.0.0.dist-info/METADATA +16 -0
- diplotocus-0.0.0.dist-info/RECORD +26 -0
- diplotocus-0.0.0.dist-info/WHEEL +5 -0
- diplotocus-0.0.0.dist-info/licenses/LICENSE +21 -0
- diplotocus-0.0.0.dist-info/top_level.txt +1 -0
diplotocus/animations.py
ADDED
|
@@ -0,0 +1,3686 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numbers,inspect
|
|
3
|
+
import matplotlib as mpl
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
from svgpath2mpl import parse_path
|
|
6
|
+
from matplotlib import transforms
|
|
7
|
+
from matplotlib.textpath import TextPath
|
|
8
|
+
from matplotlib.patches import PathPatch
|
|
9
|
+
from matplotlib.font_manager import FontProperties
|
|
10
|
+
|
|
11
|
+
from . import easings
|
|
12
|
+
|
|
13
|
+
def dealias(mpl_obj,kwargs):
|
|
14
|
+
if mpl_obj is None:
|
|
15
|
+
return kwargs
|
|
16
|
+
for alias in mpl_obj._alias_map:
|
|
17
|
+
has_main_alias = alias in kwargs
|
|
18
|
+
for other_alias in mpl_obj._alias_map[alias]:
|
|
19
|
+
if other_alias in kwargs:
|
|
20
|
+
if has_main_alias:
|
|
21
|
+
raise TypeError('Got both \'{}\' and \'{}\', which are aliases of one another'.format(alias,other_alias))
|
|
22
|
+
else:
|
|
23
|
+
has_main_alias = True
|
|
24
|
+
kwargs[alias] = kwargs[other_alias]
|
|
25
|
+
kwargs.pop(other_alias)
|
|
26
|
+
|
|
27
|
+
return kwargs
|
|
28
|
+
|
|
29
|
+
def to_np_array(obj):
|
|
30
|
+
obj = np.array(obj)
|
|
31
|
+
if obj.ndim == 0:
|
|
32
|
+
obj = np.ravel(obj)
|
|
33
|
+
return obj
|
|
34
|
+
|
|
35
|
+
class Animation:
|
|
36
|
+
"""
|
|
37
|
+
A parent Animation object for all plotting objects.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
duration : float
|
|
42
|
+
Duration of the animation
|
|
43
|
+
delay : float, default=0
|
|
44
|
+
Delay before starting
|
|
45
|
+
easing : callable, optional
|
|
46
|
+
Easing function
|
|
47
|
+
axis : matplotlib.axes.Axes, optional
|
|
48
|
+
Axis to plot on
|
|
49
|
+
"""
|
|
50
|
+
def __init__(self,easing=None,axis=None,**kwargs):
|
|
51
|
+
self.anims = []
|
|
52
|
+
self.tl = None
|
|
53
|
+
self.set_easing(easing)
|
|
54
|
+
self.set_axis(axis)
|
|
55
|
+
self.animate_easing = None
|
|
56
|
+
self.obj = None
|
|
57
|
+
self.base_color = None
|
|
58
|
+
self.tween_properties = []
|
|
59
|
+
self.x_min = 0
|
|
60
|
+
self.x_max = 0
|
|
61
|
+
self.tween_starts = []
|
|
62
|
+
self.tween_ends = []
|
|
63
|
+
self.transforms = []
|
|
64
|
+
self.x = None
|
|
65
|
+
self.y = None
|
|
66
|
+
self.persistent = False
|
|
67
|
+
self.T = transforms.Affine2D()
|
|
68
|
+
if not hasattr(self, 'mpl_obj_type'):
|
|
69
|
+
self.mpl_obj_type = None
|
|
70
|
+
if not hasattr(self, 'mpl_plot_type'):
|
|
71
|
+
self.mpl_plot_type = None
|
|
72
|
+
self.alias_map = self.get_alias_map()
|
|
73
|
+
self.possible_kwargs = self.get_possible_kwargs()
|
|
74
|
+
|
|
75
|
+
kwargs = self.clean_kwargs(kwargs)
|
|
76
|
+
kwargs['animated'] = True
|
|
77
|
+
self.kwargs = kwargs
|
|
78
|
+
self.kwargs = dealias(self.mpl_obj_type,self.kwargs)
|
|
79
|
+
if 'alpha' not in self.kwargs:
|
|
80
|
+
self.kwargs['alpha'] = 1
|
|
81
|
+
|
|
82
|
+
def function(self):
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
def init(self):
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
def get_alias_map(self):
|
|
89
|
+
if self.mpl_obj_type is None:
|
|
90
|
+
return None
|
|
91
|
+
alias_map = self.mpl_obj_type._alias_map
|
|
92
|
+
if self.mpl_plot_type == plt.plot and False:
|
|
93
|
+
alias_map['color'] = ['c']
|
|
94
|
+
return alias_map
|
|
95
|
+
|
|
96
|
+
def get_possible_kwargs(self):
|
|
97
|
+
if self.mpl_obj_type is None or self.mpl_plot_type is None:
|
|
98
|
+
return {}
|
|
99
|
+
sig = inspect.signature(self.mpl_obj_type)
|
|
100
|
+
kwargs = [
|
|
101
|
+
param.name for param in sig.parameters.values() if
|
|
102
|
+
(param.kind == param.KEYWORD_ONLY or param.kind == param.VAR_KEYWORD or param.default != param.empty)
|
|
103
|
+
and param.name != 'kwargs']
|
|
104
|
+
|
|
105
|
+
sig = inspect.signature(self.mpl_plot_type)
|
|
106
|
+
kwargs += [
|
|
107
|
+
param.name for param in sig.parameters.values() if
|
|
108
|
+
(param.kind == param.KEYWORD_ONLY or param.kind == param.VAR_KEYWORD or param.default != param.empty)
|
|
109
|
+
and param.name != 'kwargs']
|
|
110
|
+
return kwargs
|
|
111
|
+
|
|
112
|
+
def get_main_alias(self,properties):
|
|
113
|
+
if self.mpl_obj_type is None:
|
|
114
|
+
return properties
|
|
115
|
+
is_iterable = isinstance(properties,(list,np.ndarray,tuple))
|
|
116
|
+
properties = to_np_array(properties).astype(np.object_)
|
|
117
|
+
for i,property in enumerate(properties):
|
|
118
|
+
if property not in self.alias_map:
|
|
119
|
+
for alias in self.alias_map:
|
|
120
|
+
if property in self.alias_map[alias]:
|
|
121
|
+
properties[i] = alias
|
|
122
|
+
if is_iterable:
|
|
123
|
+
return properties
|
|
124
|
+
return properties[0]
|
|
125
|
+
|
|
126
|
+
def set_axis(self,axis):
|
|
127
|
+
self.axis = axis
|
|
128
|
+
if self.axis is None and self.tl is not None:
|
|
129
|
+
self.set_axis(self.tl.main_axis)
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
def set_easing(self,easing):
|
|
133
|
+
self.easing = easing
|
|
134
|
+
return self
|
|
135
|
+
|
|
136
|
+
def apply(self,x,animate_easing):
|
|
137
|
+
self.animate_easing = animate_easing
|
|
138
|
+
if x < self.x_min:
|
|
139
|
+
return
|
|
140
|
+
if x >= self.x_max and self.persistent == False:
|
|
141
|
+
self.clean(self.x_max-2,clear_anims=False)
|
|
142
|
+
return
|
|
143
|
+
self.T = transforms.Affine2D()
|
|
144
|
+
kwargs = self._tween(self.kwargs.copy(),x)
|
|
145
|
+
_x = x
|
|
146
|
+
if self.x_max-self.x_min == 1:#handle 1 frame anims
|
|
147
|
+
_x = self.x_max
|
|
148
|
+
self.anim_function(_x,kwargs)
|
|
149
|
+
self.check_transforms(x)
|
|
150
|
+
|
|
151
|
+
def anim_function(self,x,kwargs):
|
|
152
|
+
data_x = to_np_array(self.x)
|
|
153
|
+
data_y = to_np_array(self.y)
|
|
154
|
+
if self.__class__.__name__ == 'errorbar':
|
|
155
|
+
data_x_err = to_np_array(self.xerr)
|
|
156
|
+
data_y_err = to_np_array(self.yerr)
|
|
157
|
+
elif self.__class__.__name__ == 'fill_between':
|
|
158
|
+
y1 = to_np_array(self.y1)
|
|
159
|
+
y2 = to_np_array(self.y2)
|
|
160
|
+
elif self.__class__.__name__ == 'fill_betweenx':
|
|
161
|
+
x1 = to_np_array(self.x1)
|
|
162
|
+
x2 = to_np_array(self.x2)
|
|
163
|
+
|
|
164
|
+
#First pass to get frame if sequencing
|
|
165
|
+
for anim in self.anims:
|
|
166
|
+
if anim['name'] != 'sequence':
|
|
167
|
+
continue
|
|
168
|
+
if self.x is None:
|
|
169
|
+
continue
|
|
170
|
+
if x < anim['delay'] or x > anim['delay'] + anim['duration']:
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
t = self.get_t_from_x(anim,x)
|
|
174
|
+
|
|
175
|
+
if len(data_x.shape) == 1:
|
|
176
|
+
data_x = data_x.reshape((-1,1))
|
|
177
|
+
data_y = data_y.reshape((-1,1))
|
|
178
|
+
|
|
179
|
+
_i = max(min(round(t*len(data_x)),len(data_x)-1),0)
|
|
180
|
+
data_x = data_x[_i]
|
|
181
|
+
data_y = data_y[_i]
|
|
182
|
+
|
|
183
|
+
if self.__class__.__name__ == 'errorbar':
|
|
184
|
+
data_x_err = data_x_err[_i]
|
|
185
|
+
data_y_err = data_y_err[_i]
|
|
186
|
+
elif self.__class__.__name__ == 'fill_between':
|
|
187
|
+
y1 = y1[_i]
|
|
188
|
+
y2 = y2[_i]
|
|
189
|
+
elif self.__class__.__name__ == 'fill_betweenx':
|
|
190
|
+
x1 = x1[_i]
|
|
191
|
+
x2 = x2[_i]
|
|
192
|
+
|
|
193
|
+
#Second pass to cut points if drawing or erasing
|
|
194
|
+
i_max = -1
|
|
195
|
+
for anim in self.anims:
|
|
196
|
+
if anim['name'] != 'draw':
|
|
197
|
+
continue
|
|
198
|
+
if self.x is None:
|
|
199
|
+
continue
|
|
200
|
+
if x < anim['delay'] or x > anim['delay'] + anim['duration']:
|
|
201
|
+
continue
|
|
202
|
+
t = self.get_t_from_x(anim,x)
|
|
203
|
+
|
|
204
|
+
if 'alpha' in kwargs:
|
|
205
|
+
alpha = to_np_array(kwargs['alpha'])
|
|
206
|
+
if np.sum(alpha) == 0:
|
|
207
|
+
kwargs['alpha'] = 1
|
|
208
|
+
|
|
209
|
+
if anim['reverse']:
|
|
210
|
+
i_max = max(round((1-t)*len(data_x)),0)
|
|
211
|
+
else:
|
|
212
|
+
i_max = min(round(t*len(data_x)),len(data_x))
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
if i_max > 0:
|
|
216
|
+
data_x = data_x[:i_max]
|
|
217
|
+
if data_y is not None:
|
|
218
|
+
data_y = data_y[:i_max]
|
|
219
|
+
if self.__class__.__name__ == 'errorbar':
|
|
220
|
+
data_x_err = data_x_err[:i_max]
|
|
221
|
+
data_y_err = data_y_err[:i_max]
|
|
222
|
+
elif self.__class__.__name__ == 'fill_between':
|
|
223
|
+
y1 = y1[:i_max]
|
|
224
|
+
y2 = y2[:i_max]
|
|
225
|
+
elif self.__class__.__name__ == 'fill_betweenx':
|
|
226
|
+
x1 = x1[:i_max]
|
|
227
|
+
x2 = x2[:i_max]
|
|
228
|
+
if 'c' in kwargs and isinstance(kwargs['c'],(list,np.ndarray)):
|
|
229
|
+
kwargs['c'] = kwargs['c'][:i_max]
|
|
230
|
+
elif i_max == 0:
|
|
231
|
+
data_x = []
|
|
232
|
+
data_y = []
|
|
233
|
+
if self.__class__.__name__ == 'errorbar':
|
|
234
|
+
data_x_err = []
|
|
235
|
+
data_y_err = []
|
|
236
|
+
elif self.__class__.__name__ == 'fill_between':
|
|
237
|
+
y1 = []
|
|
238
|
+
y2 = []
|
|
239
|
+
elif self.__class__.__name__ == 'fill_betweenx':
|
|
240
|
+
x1 = []
|
|
241
|
+
x2 = []
|
|
242
|
+
if 'c' in kwargs and isinstance(kwargs['c'],(list,np.ndarray)):
|
|
243
|
+
kwargs['c'] = []
|
|
244
|
+
|
|
245
|
+
#Third pass to morph
|
|
246
|
+
for anim in self.anims:
|
|
247
|
+
if anim['name'] != 'morph':
|
|
248
|
+
continue
|
|
249
|
+
if self.x is None:
|
|
250
|
+
continue
|
|
251
|
+
if x < anim['delay'] or x > anim['delay'] + anim['duration']:
|
|
252
|
+
continue
|
|
253
|
+
t = self.get_t_from_x(anim,x)
|
|
254
|
+
|
|
255
|
+
if data_x is None or data_y is None:
|
|
256
|
+
continue
|
|
257
|
+
|
|
258
|
+
new_data_x = []
|
|
259
|
+
new_data_y = []
|
|
260
|
+
for i in range(len(data_x)):
|
|
261
|
+
new_data_x.append(data_x[i] + (anim['new_x'][i] - data_x[i])*t)
|
|
262
|
+
if len(data_y) == len(anim['new_y']):
|
|
263
|
+
new_data_y.append(data_y[i] + (anim['new_y'][i] - data_y[i])*t)
|
|
264
|
+
data_x = new_data_x
|
|
265
|
+
data_y = new_data_y
|
|
266
|
+
|
|
267
|
+
if self.__class__.__name__ == 'errorbar':
|
|
268
|
+
new_data_x_err = []
|
|
269
|
+
new_data_y_err = []
|
|
270
|
+
for i in range(len(data_x_err)):
|
|
271
|
+
new_data_x_err.append(data_x_err[i] + (anim['new_x_err'][i] - data_x_err[i])*t)
|
|
272
|
+
new_data_y_err.append(data_y_err[i] + (anim['new_y_err'][i] - data_y_err[i])*t)
|
|
273
|
+
data_x_err = new_data_x_err
|
|
274
|
+
data_y_err = new_data_y_err
|
|
275
|
+
|
|
276
|
+
if self.__class__.__name__ == 'errorbar':
|
|
277
|
+
kwargs['xerr'] = data_x_err
|
|
278
|
+
kwargs['yerr'] = data_y_err
|
|
279
|
+
elif self.__class__.__name__ == 'fill_between':
|
|
280
|
+
kwargs['y1'] = y1
|
|
281
|
+
kwargs['y2'] = y2
|
|
282
|
+
elif self.__class__.__name__ == 'fill_betweenx':
|
|
283
|
+
kwargs['x1'] = x1
|
|
284
|
+
kwargs['x2'] = x2
|
|
285
|
+
|
|
286
|
+
data_x = to_np_array(data_x)
|
|
287
|
+
data_y = to_np_array(data_y)
|
|
288
|
+
|
|
289
|
+
if self.function is not None:
|
|
290
|
+
self.function(data_x,data_y,x,kwargs)
|
|
291
|
+
|
|
292
|
+
def initialize(self,timeline):
|
|
293
|
+
self.tl = timeline
|
|
294
|
+
if self.axis is None:
|
|
295
|
+
self.set_axis(self.tl.main_axis)
|
|
296
|
+
|
|
297
|
+
self.clean(0)
|
|
298
|
+
self.compute_timings()
|
|
299
|
+
self.init()
|
|
300
|
+
|
|
301
|
+
def compute_timings(self):
|
|
302
|
+
x_max = 0
|
|
303
|
+
x_min = np.inf
|
|
304
|
+
for anim in self.anims:
|
|
305
|
+
if anim['duration'] + anim['delay'] > x_max:
|
|
306
|
+
x_max = anim['duration'] + anim['delay']
|
|
307
|
+
self.persistent = anim['persistent']
|
|
308
|
+
if anim['delay'] < x_min:
|
|
309
|
+
x_min = anim['delay']
|
|
310
|
+
self.x_max = x_max
|
|
311
|
+
self.x_min = x_min
|
|
312
|
+
|
|
313
|
+
def get_t_from_x(self,anim,x):
|
|
314
|
+
easing = easings.easeLinear()
|
|
315
|
+
if self.tl.easing is not None:
|
|
316
|
+
easing = self.tl.easing
|
|
317
|
+
if self.easing is not None:
|
|
318
|
+
easing = self.easing
|
|
319
|
+
if self.animate_easing is not None:
|
|
320
|
+
easing = self.animate_easing
|
|
321
|
+
if anim['easing'] is not None:
|
|
322
|
+
easing = anim['easing']
|
|
323
|
+
|
|
324
|
+
if anim['duration'] == 1 and x == anim['delay']:
|
|
325
|
+
return 1
|
|
326
|
+
return easing.ease((x - anim['delay']) / max(1, anim['duration'] - 1))
|
|
327
|
+
|
|
328
|
+
def sanitize_colors(self,properties,starts,ends):
|
|
329
|
+
for i in range(len(properties)):
|
|
330
|
+
if properties[i] in ['c','colors','color','edgecolor','facecolor','edgecolors','facecolors']:
|
|
331
|
+
starts[i] = list(mpl.colors.to_rgba_array(starts[i])[0])
|
|
332
|
+
ends[i] = list(mpl.colors.to_rgba_array(ends[i])[0])
|
|
333
|
+
return properties,starts,ends
|
|
334
|
+
|
|
335
|
+
def tween(self,property,start,end,duration,delay=0,easing=None,persistent=True):
|
|
336
|
+
"""Animate a change in a property of the plot object.
|
|
337
|
+
|
|
338
|
+
Parameters
|
|
339
|
+
----------
|
|
340
|
+
property : str
|
|
341
|
+
the name of the property to animate.
|
|
342
|
+
start : any
|
|
343
|
+
the starting value of the property.
|
|
344
|
+
end : any
|
|
345
|
+
the ending value of the property.
|
|
346
|
+
duration : float
|
|
347
|
+
the number of frames the animation runs from.
|
|
348
|
+
delay : float, default=0
|
|
349
|
+
the number of frames after what the animation starts playing.
|
|
350
|
+
easing : callable, optional
|
|
351
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
352
|
+
"""
|
|
353
|
+
return self.tweens([property],[start],[end],duration,delay,easing,persistent=persistent)
|
|
354
|
+
|
|
355
|
+
def tweens(self,properties,starts,ends,duration,delay=0,easing=None,persistent=True):
|
|
356
|
+
"""Animate multiple properties at once.
|
|
357
|
+
|
|
358
|
+
Parameters
|
|
359
|
+
----------
|
|
360
|
+
properties : list[str]
|
|
361
|
+
a list of the names of the properties to animate.
|
|
362
|
+
starts : list[Any]
|
|
363
|
+
the starting values of the properties.
|
|
364
|
+
ends : list[Any]
|
|
365
|
+
the ending values of the properties.
|
|
366
|
+
duration : float
|
|
367
|
+
the number of frames the animation runs from.
|
|
368
|
+
delay : float, default=0
|
|
369
|
+
the number of frames after what the animation starts playing.
|
|
370
|
+
easing : callable, optional
|
|
371
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
372
|
+
"""
|
|
373
|
+
starts = [to_np_array(start) for start in starts]
|
|
374
|
+
ends = [to_np_array(end) for end in ends]
|
|
375
|
+
properties = self.get_main_alias(properties)
|
|
376
|
+
properties,starts,ends = self.sanitize_colors(properties,starts,ends)
|
|
377
|
+
|
|
378
|
+
for property,start,end in zip(properties,starts,ends):
|
|
379
|
+
new_anim = {
|
|
380
|
+
'name':'tween',
|
|
381
|
+
'duration':duration,
|
|
382
|
+
'delay':delay,
|
|
383
|
+
'easing':easing,
|
|
384
|
+
'property':property,
|
|
385
|
+
'start':start,
|
|
386
|
+
'end':end,
|
|
387
|
+
'persistent':persistent,
|
|
388
|
+
'played':False
|
|
389
|
+
}
|
|
390
|
+
self.anims.append(new_anim)
|
|
391
|
+
self.compute_timings()
|
|
392
|
+
return self
|
|
393
|
+
|
|
394
|
+
def _tween(self,kwargs,x):
|
|
395
|
+
for anim in self.anims:
|
|
396
|
+
if x < anim['delay']:
|
|
397
|
+
continue
|
|
398
|
+
if anim['name'] != 'tween':
|
|
399
|
+
continue
|
|
400
|
+
_x = min(x,anim['duration'] + anim['delay'])
|
|
401
|
+
t = self.get_t_from_x(anim,_x)
|
|
402
|
+
t = np.clip(t,0,1)
|
|
403
|
+
start = to_np_array(anim['start'])
|
|
404
|
+
end = to_np_array(anim['end'])
|
|
405
|
+
current = start + (end - start)*t
|
|
406
|
+
kwargs[anim['property']] = current
|
|
407
|
+
return kwargs
|
|
408
|
+
|
|
409
|
+
def show(self,duration,delay=0,easing=None,persistent=True):
|
|
410
|
+
"""Fade in plot objects.
|
|
411
|
+
|
|
412
|
+
This is a shorthand animation that fades in plot objects. It is equivalent to `tween('alpha',0,1)`.
|
|
413
|
+
|
|
414
|
+
Parameters
|
|
415
|
+
----------
|
|
416
|
+
duration : float
|
|
417
|
+
the number of frames the animation runs from.
|
|
418
|
+
delay : float, default=0
|
|
419
|
+
the number of frames after what the animation starts playing.
|
|
420
|
+
easing : callable, optional
|
|
421
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
422
|
+
persistent : bool, default=True
|
|
423
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
424
|
+
"""
|
|
425
|
+
return self.tween('alpha',start=0,end=1,duration=duration,delay=delay,easing=easing,persistent=persistent)
|
|
426
|
+
|
|
427
|
+
def hide(self,duration,delay=0,easing=None,persistent=True):
|
|
428
|
+
"""Fade out plot objects.
|
|
429
|
+
|
|
430
|
+
This is a shorthand animation that fades out plot objects. It is equivalent to `tween('alpha',1,0)`.
|
|
431
|
+
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
duration : float
|
|
435
|
+
the number of frames the animation runs from.
|
|
436
|
+
delay : float, default=0
|
|
437
|
+
the number of frames after what the animation starts playing.
|
|
438
|
+
easing : callable, optional
|
|
439
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
440
|
+
persistent : bool, default=True
|
|
441
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
442
|
+
"""
|
|
443
|
+
return self.tween('alpha',start=1,end=0,duration=duration,delay=delay,easing=easing,persistent=persistent)
|
|
444
|
+
|
|
445
|
+
def draw(self,duration,reverse=False,delay=0,easing=None,persistent=True):
|
|
446
|
+
"""Animate the plot object by sequentially adding more points of the dataset.
|
|
447
|
+
|
|
448
|
+
Parameters
|
|
449
|
+
----------
|
|
450
|
+
duration : float
|
|
451
|
+
the number of frames the animation runs from.
|
|
452
|
+
delay : float, default=0
|
|
453
|
+
the number of frames after what the animation starts playing.
|
|
454
|
+
easing : callable, optional
|
|
455
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
456
|
+
reverse : bool, default=False
|
|
457
|
+
if True, removes points sequentially instead of adding points.
|
|
458
|
+
persistent : bool, default=True
|
|
459
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
460
|
+
"""
|
|
461
|
+
self.anims.append({
|
|
462
|
+
'name':'draw',
|
|
463
|
+
'duration':duration,
|
|
464
|
+
'delay':delay,
|
|
465
|
+
'easing':easing,
|
|
466
|
+
'reverse':reverse,
|
|
467
|
+
'persistent':persistent,
|
|
468
|
+
'played':False
|
|
469
|
+
})
|
|
470
|
+
self.compute_timings()
|
|
471
|
+
return self
|
|
472
|
+
|
|
473
|
+
def scale(self,start_scale,end_scale,duration,center=None,delay=0,easing=None,persistent=True):
|
|
474
|
+
"""Scale a plot object from one size to another.
|
|
475
|
+
|
|
476
|
+
Parameters
|
|
477
|
+
----------
|
|
478
|
+
start_scale : float or tuple[float, float]
|
|
479
|
+
the starting scale of the plot object.
|
|
480
|
+
end_scale : float or tuple[float, float]
|
|
481
|
+
the ending scale of the plot object.
|
|
482
|
+
duration : float
|
|
483
|
+
the number of frames the animation runs from.
|
|
484
|
+
delay : float, default=0
|
|
485
|
+
the number of frames after what the animation starts playing.
|
|
486
|
+
easing : callable, optional
|
|
487
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
488
|
+
persistent : bool, default=True
|
|
489
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
490
|
+
|
|
491
|
+
You can either pass scalar values, in which case the plot object will be uniformly scaled, or a 2-tuple for independent X and Y scales.
|
|
492
|
+
"""
|
|
493
|
+
if isinstance(start_scale,(list,tuple,np.ndarray)):
|
|
494
|
+
scalex_start,scaley_start = start_scale
|
|
495
|
+
else:
|
|
496
|
+
scalex_start = start_scale
|
|
497
|
+
scaley_start = start_scale
|
|
498
|
+
if isinstance(end_scale,(list,tuple,np.ndarray)):
|
|
499
|
+
scalex_end,scaley_end = end_scale
|
|
500
|
+
else:
|
|
501
|
+
scalex_end = end_scale
|
|
502
|
+
scaley_end = end_scale
|
|
503
|
+
|
|
504
|
+
self.anims.append({
|
|
505
|
+
'name':'scale',
|
|
506
|
+
'duration':duration,
|
|
507
|
+
'delay':delay,
|
|
508
|
+
'easing':easing,
|
|
509
|
+
'start':(scalex_start,scaley_start),
|
|
510
|
+
'end':(scalex_end,scaley_end),
|
|
511
|
+
'persistent':persistent,
|
|
512
|
+
'center':center,
|
|
513
|
+
'played':False
|
|
514
|
+
})
|
|
515
|
+
self.compute_timings()
|
|
516
|
+
return self
|
|
517
|
+
|
|
518
|
+
def _scale(self, t, start, end, center=None):
|
|
519
|
+
if center is None:
|
|
520
|
+
cx, cy = self.get_center()
|
|
521
|
+
else:
|
|
522
|
+
cx, cy = center
|
|
523
|
+
scale_x = start[0] + (end[0] - start[0]) * t
|
|
524
|
+
scale_y = start[1] + (end[1] - start[1]) * t
|
|
525
|
+
|
|
526
|
+
# Update Affine2D for non-collections
|
|
527
|
+
self.T = (
|
|
528
|
+
self.T
|
|
529
|
+
.translate(-cx, -cy)
|
|
530
|
+
.scale(scale_x, scale_y)
|
|
531
|
+
.translate(cx, cy)
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
obj = to_np_array(self.obj)
|
|
535
|
+
for o in obj:
|
|
536
|
+
if isinstance(o, mpl.collections.Collection) and self.mpl_obj_type == mpl.collections.Collection:
|
|
537
|
+
offsets = np.asarray(o.get_offsets(), dtype=float).reshape(-1, 2)
|
|
538
|
+
offsets_centered = offsets - np.array([cx, cy])
|
|
539
|
+
|
|
540
|
+
new_offsets = offsets_centered * np.array([scale_x, scale_y]) + np.array([cx, cy])
|
|
541
|
+
|
|
542
|
+
new_offsets = new_offsets.reshape(-1, 2)
|
|
543
|
+
o.set_offsets(new_offsets)
|
|
544
|
+
else:
|
|
545
|
+
o.set_transform(self.T + self.axis.transData)
|
|
546
|
+
|
|
547
|
+
def rotate(self,start_angle,end_angle,duration,center=None,delay=0,easing=None,persistent=True):
|
|
548
|
+
"""Rotate a plot object from one angle to another.
|
|
549
|
+
|
|
550
|
+
Parameters
|
|
551
|
+
----------
|
|
552
|
+
start_angle : float
|
|
553
|
+
the starting angle of the rotation in radians.
|
|
554
|
+
end_angle : float
|
|
555
|
+
the ending angle of the rotation in radians.
|
|
556
|
+
duration : float
|
|
557
|
+
the number of frames the animation runs from.
|
|
558
|
+
delay : float, default=0
|
|
559
|
+
the number of frames after what the animation starts playing.
|
|
560
|
+
easing : callable, optional
|
|
561
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
562
|
+
persistent : bool, default=True
|
|
563
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
564
|
+
"""
|
|
565
|
+
self.anims.append({
|
|
566
|
+
'name':'rotate',
|
|
567
|
+
'duration':duration,
|
|
568
|
+
'delay':delay,
|
|
569
|
+
'easing':easing,
|
|
570
|
+
'start':start_angle,
|
|
571
|
+
'end':end_angle,
|
|
572
|
+
'center':center,
|
|
573
|
+
'persistent':persistent,
|
|
574
|
+
'played':False
|
|
575
|
+
})
|
|
576
|
+
self.compute_timings()
|
|
577
|
+
return self
|
|
578
|
+
|
|
579
|
+
def _rotate(self, t, start, end, center=None):
|
|
580
|
+
if center is None:
|
|
581
|
+
cx, cy = self.get_center()
|
|
582
|
+
else:
|
|
583
|
+
cx, cy = center
|
|
584
|
+
rotation = start + (end - start) * t
|
|
585
|
+
self.T = (
|
|
586
|
+
self.T
|
|
587
|
+
.translate(-cx, -cy)
|
|
588
|
+
.rotate_deg(rotation)
|
|
589
|
+
.translate(cx, cy)
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
obj = to_np_array(self.obj)
|
|
593
|
+
for o in obj:
|
|
594
|
+
if isinstance(o, mpl.collections.Collection) and self.mpl_obj_type == mpl.collections.Collection:
|
|
595
|
+
offsets = np.asarray(o.get_offsets(), dtype=float).reshape(-1, 2)
|
|
596
|
+
offsets_centered = offsets - np.array([cx, cy])
|
|
597
|
+
|
|
598
|
+
theta = np.deg2rad(rotation)
|
|
599
|
+
R = np.array([[np.cos(theta), -np.sin(theta)],
|
|
600
|
+
[np.sin(theta), np.cos(theta)]])
|
|
601
|
+
|
|
602
|
+
new_offsets = offsets_centered @ R.T + np.array([cx, cy])
|
|
603
|
+
|
|
604
|
+
new_offsets = new_offsets.reshape(-1, 2)
|
|
605
|
+
o.set_offsets(new_offsets)
|
|
606
|
+
else:
|
|
607
|
+
o.set_transform(self.T + self.axis.transData)
|
|
608
|
+
|
|
609
|
+
def translate(self,start_pos,end_pos,duration,delay=0,easing=None,persistent=True):
|
|
610
|
+
"""Move a plot object from one position to another.
|
|
611
|
+
|
|
612
|
+
Parameters
|
|
613
|
+
----------
|
|
614
|
+
start_pos : array-like
|
|
615
|
+
where the translation starts, relative to the current center of the plot object.
|
|
616
|
+
end_pos : array-like
|
|
617
|
+
where the translation ends, relative to the current center of the plot object.
|
|
618
|
+
duration : float
|
|
619
|
+
the number of frames the animation runs from.
|
|
620
|
+
delay : float, default=0
|
|
621
|
+
the number of frames after what the animation starts playing.
|
|
622
|
+
easing : callable, optional
|
|
623
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
624
|
+
persistent : bool, default=True
|
|
625
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
626
|
+
"""
|
|
627
|
+
self.anims.append({
|
|
628
|
+
'name':'translate',
|
|
629
|
+
'duration':duration,
|
|
630
|
+
'delay':delay,
|
|
631
|
+
'easing':easing,
|
|
632
|
+
'start':start_pos,
|
|
633
|
+
'end':end_pos,
|
|
634
|
+
'persistent':persistent,
|
|
635
|
+
'played':False
|
|
636
|
+
})
|
|
637
|
+
self.compute_timings()
|
|
638
|
+
return self
|
|
639
|
+
|
|
640
|
+
def _translate(self,t,start,end):
|
|
641
|
+
pos_x = start[0] + (end[0] - start[0])*t
|
|
642
|
+
pos_y = start[1] + (end[1] - start[1])*t
|
|
643
|
+
self.T = self.T.translate(pos_x,pos_y)
|
|
644
|
+
obj = to_np_array(self.obj)
|
|
645
|
+
for o in obj:
|
|
646
|
+
if self.mpl_obj_type == mpl.collections.Collection:
|
|
647
|
+
offsets = o.get_offsets()
|
|
648
|
+
o.set_offsets(offsets + np.array([pos_x,pos_y]))
|
|
649
|
+
else:
|
|
650
|
+
o.set_transform(self.T + self.axis.transData)
|
|
651
|
+
|
|
652
|
+
def morph(self,new_x,new_y,duration,delay=0,easing=None,persistent=True):
|
|
653
|
+
"""Morph between the base dataset and a new dataset.
|
|
654
|
+
|
|
655
|
+
Parameters
|
|
656
|
+
----------
|
|
657
|
+
new_x : array-like or float
|
|
658
|
+
the x data points to morph to.
|
|
659
|
+
new_y : array-like or float
|
|
660
|
+
the y data points to morph to.
|
|
661
|
+
duration : float
|
|
662
|
+
the number of frames the animation runs from.
|
|
663
|
+
delay : float, default=0
|
|
664
|
+
the number of frames after what the animation starts playing.
|
|
665
|
+
easing : callable, optional
|
|
666
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
667
|
+
persistent : bool, default=True
|
|
668
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
669
|
+
|
|
670
|
+
For plot objects that take 1D datasets (e.g. hist()), `morph()` only accepts `new_x`.
|
|
671
|
+
"""
|
|
672
|
+
# TODO : if new_x/new_y not the same size, resample them to match
|
|
673
|
+
if isinstance(new_x,numbers.Number):
|
|
674
|
+
new_x = [new_x]
|
|
675
|
+
new_y = [new_y]
|
|
676
|
+
new_x = to_np_array(new_x)
|
|
677
|
+
new_y = to_np_array(new_y)
|
|
678
|
+
|
|
679
|
+
self.anims.append({
|
|
680
|
+
'name':'morph',
|
|
681
|
+
'duration':duration,
|
|
682
|
+
'delay':delay,
|
|
683
|
+
'easing':easing,
|
|
684
|
+
'new_x':new_x,
|
|
685
|
+
'new_y':new_y,
|
|
686
|
+
'persistent':persistent,
|
|
687
|
+
'played':False
|
|
688
|
+
})
|
|
689
|
+
self.compute_timings()
|
|
690
|
+
return self
|
|
691
|
+
|
|
692
|
+
def sequence(self,duration,delay=0,easing=None,persistent=True):
|
|
693
|
+
"""Plot one datapoint or row of the dataset per frame.
|
|
694
|
+
|
|
695
|
+
Parameters
|
|
696
|
+
----------
|
|
697
|
+
duration : float
|
|
698
|
+
the number of frames the animation runs from.
|
|
699
|
+
delay : float, default=0
|
|
700
|
+
the number of frames after what the animation starts playing.
|
|
701
|
+
easing : callable, optional
|
|
702
|
+
the easing used for this animation. If None, a linear easing is applied.
|
|
703
|
+
persistent : bool, default=True
|
|
704
|
+
if True, the plot object will continue to be plotted after its last animation has played.
|
|
705
|
+
|
|
706
|
+
If the dataset is 1-dimensional, this plots a single datapoint per frame, if 2D, it will plot one row per frame. This animation can be used if you have a predefined list of datapoints you want to animate frame-by-frame.
|
|
707
|
+
"""
|
|
708
|
+
self.anims.append({
|
|
709
|
+
'name':'sequence',
|
|
710
|
+
'duration':duration,
|
|
711
|
+
'delay':delay,
|
|
712
|
+
'easing':easing,
|
|
713
|
+
'persistent':persistent,
|
|
714
|
+
'played':False
|
|
715
|
+
})
|
|
716
|
+
self.compute_timings()
|
|
717
|
+
return self
|
|
718
|
+
|
|
719
|
+
def clean(self,x,clear_anims=True):
|
|
720
|
+
if self.obj is not None and self.base_color is None:
|
|
721
|
+
if isinstance(self.obj,(list,np.ndarray)):
|
|
722
|
+
self.base_color = self.obj[0].get_color()
|
|
723
|
+
elif hasattr(self.obj,'get_color'):
|
|
724
|
+
self.base_color = self.obj.get_color()
|
|
725
|
+
if 'color' not in self.kwargs and 'c' not in self.kwargs and self.base_color is not None:
|
|
726
|
+
self.kwargs['color'] = self.base_color
|
|
727
|
+
|
|
728
|
+
for anim in self.anims:
|
|
729
|
+
t = self.get_t_from_x(anim,x)
|
|
730
|
+
if t != 1:
|
|
731
|
+
continue
|
|
732
|
+
if anim['name'] == 'morph':
|
|
733
|
+
self.x = anim['new_x']
|
|
734
|
+
self.y = anim['new_y']
|
|
735
|
+
|
|
736
|
+
if x >= self.x_min-1 and x < self.x_max-1 and self.obj is not None:
|
|
737
|
+
if isinstance(self.obj,list):
|
|
738
|
+
for obj in self.obj:
|
|
739
|
+
try:
|
|
740
|
+
obj.remove()
|
|
741
|
+
except:
|
|
742
|
+
pass
|
|
743
|
+
else:
|
|
744
|
+
try:
|
|
745
|
+
self.obj.remove()
|
|
746
|
+
except:
|
|
747
|
+
pass
|
|
748
|
+
self.obj = None
|
|
749
|
+
elif x == self.x_max and clear_anims:
|
|
750
|
+
self.end_animation()
|
|
751
|
+
|
|
752
|
+
def end_animation(self):
|
|
753
|
+
self.anims = []
|
|
754
|
+
|
|
755
|
+
def clean_kwargs(self,kwargs):
|
|
756
|
+
if 'duration' in kwargs:
|
|
757
|
+
del kwargs['duration']
|
|
758
|
+
if 'delay' in kwargs:
|
|
759
|
+
del kwargs['delay']
|
|
760
|
+
if 'easing' in kwargs:
|
|
761
|
+
del kwargs['delay']
|
|
762
|
+
if 'axis' in kwargs:
|
|
763
|
+
del kwargs['axis']
|
|
764
|
+
return kwargs
|
|
765
|
+
|
|
766
|
+
def check_transforms(self,x):
|
|
767
|
+
if self.mpl_obj_type is None:
|
|
768
|
+
return
|
|
769
|
+
for anim in self.anims:
|
|
770
|
+
if x < anim['delay']:
|
|
771
|
+
continue
|
|
772
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
773
|
+
|
|
774
|
+
t = self.get_t_from_x(anim,_x)
|
|
775
|
+
if anim['name'] == 'scale':
|
|
776
|
+
start = to_np_array(anim['start'])
|
|
777
|
+
end = to_np_array(anim['end'])
|
|
778
|
+
self._scale(t,start,end,center=anim['center'])
|
|
779
|
+
if anim['name'] == 'translate':
|
|
780
|
+
start = to_np_array(anim['start'])
|
|
781
|
+
end = to_np_array(anim['end'])
|
|
782
|
+
self._translate(t,start,end)
|
|
783
|
+
if anim['name'] == 'rotate':
|
|
784
|
+
start = to_np_array(anim['start'])
|
|
785
|
+
end = to_np_array(anim['end'])
|
|
786
|
+
self._rotate(t,start,end,center=anim['center'])
|
|
787
|
+
|
|
788
|
+
def get_center(self):
|
|
789
|
+
if self.mpl_obj_type == mpl.lines.Line2D:
|
|
790
|
+
bbox = self.obj[0].get_bbox().get_points()
|
|
791
|
+
cx = (bbox[0][0] + bbox[1][0])/2
|
|
792
|
+
cy = (bbox[0][1] + bbox[1][1])/2
|
|
793
|
+
elif self.mpl_obj_type == mpl.patches.PathPatch:
|
|
794
|
+
bbox = self.path.get_extents()
|
|
795
|
+
cx = (bbox.x0 + bbox.x1) / 2
|
|
796
|
+
cy = (bbox.y0 + bbox.y1) / 2
|
|
797
|
+
elif self.mpl_obj_type == mpl.contour.QuadContourSet:
|
|
798
|
+
bboxes = [p.get_extents() for p in self.obj.get_paths()]
|
|
799
|
+
bbox = mpl.transforms.Bbox.union(bboxes)
|
|
800
|
+
cx = (bbox.x0 + bbox.x1) / 2
|
|
801
|
+
cy = (bbox.y0 + bbox.y1) / 2
|
|
802
|
+
elif self.mpl_obj_type == mpl.collections.Collection:
|
|
803
|
+
offsets = self.obj.get_offsets()
|
|
804
|
+
if len(offsets) == 0:
|
|
805
|
+
cx,cy = 0,0
|
|
806
|
+
else:
|
|
807
|
+
cx = np.mean(offsets[:, 0])
|
|
808
|
+
cy = np.mean(offsets[:, 1])
|
|
809
|
+
elif self.mpl_obj_type == mpl.collections.QuadMesh:
|
|
810
|
+
coords = self.obj.get_coordinates()
|
|
811
|
+
x0 = np.nanmin(coords[..., 0])
|
|
812
|
+
x1 = np.nanmax(coords[..., 0])
|
|
813
|
+
y0 = np.nanmin(coords[..., 1])
|
|
814
|
+
y1 = np.nanmax(coords[..., 1])
|
|
815
|
+
|
|
816
|
+
cx = 0.5 * (x0 + x1)
|
|
817
|
+
cy = 0.5 * (y0 + y1)
|
|
818
|
+
elif self.mpl_obj_type == mpl.patches.Rectangle:
|
|
819
|
+
rects = self.obj.patches
|
|
820
|
+
if isinstance(rects, list) and len(rects) > 0:
|
|
821
|
+
centers_x = []
|
|
822
|
+
centers_y = []
|
|
823
|
+
for rect in rects:
|
|
824
|
+
bbox = rect.get_bbox()
|
|
825
|
+
cx = (bbox.x0 + bbox.x1) / 2
|
|
826
|
+
cy = (bbox.y0 + bbox.y1) / 2
|
|
827
|
+
centers_x.append(cx)
|
|
828
|
+
centers_y.append(cy)
|
|
829
|
+
cx = np.mean(centers_x)
|
|
830
|
+
cy = np.mean(centers_y)
|
|
831
|
+
else:
|
|
832
|
+
bbox = self.obj.get_bbox()
|
|
833
|
+
cx = (bbox.x0 + bbox.x1) / 2
|
|
834
|
+
cy = (bbox.y0 + bbox.y1) / 2
|
|
835
|
+
elif self.mpl_obj_type == mpl.collections.FillBetweenPolyCollection:
|
|
836
|
+
bboxes = [p.get_extents() for p in self.obj.get_paths() if p.vertices.size]
|
|
837
|
+
bbox = mpl.transforms.Bbox.union(bboxes)
|
|
838
|
+
cx = 0.5 * (bbox.x0 + bbox.x1)
|
|
839
|
+
cy = 0.5 * (bbox.y0 + bbox.y1)
|
|
840
|
+
return (cx,cy)
|
|
841
|
+
|
|
842
|
+
class axis_zoom(Animation):
|
|
843
|
+
"""
|
|
844
|
+
Zooms into the axis given a zoom value.
|
|
845
|
+
|
|
846
|
+
Parameters
|
|
847
|
+
----------
|
|
848
|
+
zoom : float
|
|
849
|
+
Zoom level
|
|
850
|
+
duration : float
|
|
851
|
+
Duration of the animation
|
|
852
|
+
delay : float, default=0
|
|
853
|
+
Delay before starting
|
|
854
|
+
easing : callable, optional
|
|
855
|
+
Easing function
|
|
856
|
+
axis : matplotlib.axes.Axes, optional
|
|
857
|
+
Axis to plot on
|
|
858
|
+
|
|
859
|
+
Example
|
|
860
|
+
--------
|
|
861
|
+
Zoom 2 times in 100 frames:
|
|
862
|
+
>>> axis_zoom(zoom=2,duration=100)
|
|
863
|
+
"""
|
|
864
|
+
def __init__(self,zoom,duration,delay=0,easing=None,axis=None,*args,**kwargs):
|
|
865
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
866
|
+
self.anims = [{
|
|
867
|
+
'name':'axis_move',
|
|
868
|
+
'duration':duration,
|
|
869
|
+
'delay':delay,
|
|
870
|
+
'easing':easing,
|
|
871
|
+
'persistent':True,
|
|
872
|
+
'zoom':zoom,
|
|
873
|
+
'played':False
|
|
874
|
+
}]
|
|
875
|
+
self.compute_timings()
|
|
876
|
+
|
|
877
|
+
def init(self):
|
|
878
|
+
if 'start_width' not in self.anims[0]:
|
|
879
|
+
self.anims[0]['start_width'] = self.axis.get_xlim()[1] - self.axis.get_xlim()[0]
|
|
880
|
+
self.anims[0]['start_height'] = self.axis.get_ylim()[1] - self.axis.get_ylim()[0]
|
|
881
|
+
self.anims[0]['end_width'] = self.anims[0]['start_width']/self.anims[0]['zoom']
|
|
882
|
+
self.anims[0]['end_height'] = self.anims[0]['start_height']/self.anims[0]['zoom']
|
|
883
|
+
|
|
884
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
885
|
+
anim = self.anims[0]
|
|
886
|
+
if x < anim['delay']:
|
|
887
|
+
return
|
|
888
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
889
|
+
t = self.get_t_from_x(anim,x)
|
|
890
|
+
|
|
891
|
+
center = ((self.axis.get_xlim()[1]+self.axis.get_xlim()[0])/2,(self.axis.get_ylim()[1]+self.axis.get_ylim()[0])/2)
|
|
892
|
+
width = anim['start_width'] + (anim['end_width'] - anim['start_width'])*t
|
|
893
|
+
height = anim['start_height'] + (anim['end_height'] - anim['start_height'])*t
|
|
894
|
+
x_range = (center[0] - width/2, center[0] + width/2)
|
|
895
|
+
y_range = (center[1] - height/2, center[1] + height/2)
|
|
896
|
+
self.axis.set_xlim(x_range[0],x_range[1])
|
|
897
|
+
self.axis.set_ylim(y_range[0],y_range[1])
|
|
898
|
+
|
|
899
|
+
class axis_limits(Animation):
|
|
900
|
+
"""
|
|
901
|
+
Reframe axis to the given limits (on the x-axis, y-axis or both depending on passed arguments)
|
|
902
|
+
|
|
903
|
+
Parameters
|
|
904
|
+
----------
|
|
905
|
+
xlim : array-like, default=None
|
|
906
|
+
Target limits of the x-axis
|
|
907
|
+
ylim : array-like, default=None
|
|
908
|
+
Target limits of the y-axis
|
|
909
|
+
duration : float
|
|
910
|
+
Duration of the animation
|
|
911
|
+
delay : float, default=0
|
|
912
|
+
Delay before starting
|
|
913
|
+
easing : callable, optional
|
|
914
|
+
Easing function
|
|
915
|
+
axis : matplotlib.axes.Axes, optional
|
|
916
|
+
Axis to plot on
|
|
917
|
+
|
|
918
|
+
Example
|
|
919
|
+
--------
|
|
920
|
+
Reframe x-axis to limits [0-2] in 100 frames:
|
|
921
|
+
>>> axis_limits(xlim=(0,2),duration=100)
|
|
922
|
+
"""
|
|
923
|
+
def __init__(self,duration,xlim=None,ylim=None,delay=0,easing=None,axis=None,*args,**kwargs):
|
|
924
|
+
if xlim is None and ylim is None:
|
|
925
|
+
raise ValueError('Both xlim and ylim cannot be empty.')
|
|
926
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
927
|
+
self.anims = [{
|
|
928
|
+
'name':'axis_move',
|
|
929
|
+
'duration':duration,
|
|
930
|
+
'delay':delay,
|
|
931
|
+
'easing':easing,
|
|
932
|
+
'persistent':True,
|
|
933
|
+
'xlim':xlim,
|
|
934
|
+
'ylim':ylim,
|
|
935
|
+
'played':False
|
|
936
|
+
}]
|
|
937
|
+
self.compute_timings()
|
|
938
|
+
|
|
939
|
+
def init(self):
|
|
940
|
+
if 'start_xlim' not in self.anims[0]:
|
|
941
|
+
self.anims[0]['start_xlim'] = self.axis.get_xlim()
|
|
942
|
+
self.anims[0]['start_ylim'] = self.axis.get_ylim()
|
|
943
|
+
|
|
944
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
945
|
+
anim = self.anims[0]
|
|
946
|
+
if x < anim['delay']:
|
|
947
|
+
return
|
|
948
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
949
|
+
t = self.get_t_from_x(anim,x)
|
|
950
|
+
|
|
951
|
+
if anim['xlim'] is not None:
|
|
952
|
+
xlim_left = anim['start_xlim'][0] + (anim['xlim'][0] - anim['start_xlim'][0])*t
|
|
953
|
+
xlim_right = anim['start_xlim'][1] + (anim['xlim'][1] - anim['start_xlim'][1])*t
|
|
954
|
+
self.axis.set_xlim(xlim_left,xlim_right)
|
|
955
|
+
if anim['ylim'] is not None:
|
|
956
|
+
ylim_bottom = anim['start_ylim'][0] + (anim['ylim'][0] - anim['start_ylim'][0])*t
|
|
957
|
+
ylim_top = anim['start_ylim'][1] + (anim['ylim'][1] - anim['start_ylim'][1])*t
|
|
958
|
+
self.axis.set_ylim(ylim_bottom,ylim_top)
|
|
959
|
+
|
|
960
|
+
class axis_move(Animation):
|
|
961
|
+
"""
|
|
962
|
+
Move the center of the axis to a given position.
|
|
963
|
+
|
|
964
|
+
Parameters
|
|
965
|
+
----------
|
|
966
|
+
pos : array-like
|
|
967
|
+
Target center position
|
|
968
|
+
duration : float
|
|
969
|
+
Duration of the animation
|
|
970
|
+
delay : float, default=0
|
|
971
|
+
Delay before starting
|
|
972
|
+
easing : callable, optional
|
|
973
|
+
Easing function
|
|
974
|
+
axis : matplotlib.axes.Axes, optional
|
|
975
|
+
Axis to plot on
|
|
976
|
+
|
|
977
|
+
Example
|
|
978
|
+
--------
|
|
979
|
+
Recenter the axis to (-1,-1) in 100 frames:
|
|
980
|
+
>>> axis_move(pos=(-1,-1),duration=100)
|
|
981
|
+
"""
|
|
982
|
+
def __init__(self,end_pos,duration,start_pos=None,delay=0,easing=None,axis=None,*args,**kwargs):
|
|
983
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
984
|
+
self.anims = [{
|
|
985
|
+
'name':'axis_move',
|
|
986
|
+
'duration':duration,
|
|
987
|
+
'delay':delay,
|
|
988
|
+
'easing':easing,
|
|
989
|
+
'persistent':True,
|
|
990
|
+
'start':start_pos,
|
|
991
|
+
'end':end_pos,
|
|
992
|
+
'played':False
|
|
993
|
+
}]
|
|
994
|
+
self.compute_timings()
|
|
995
|
+
|
|
996
|
+
def init(self):
|
|
997
|
+
if self.anims[0]['start'] is None:
|
|
998
|
+
self.anims[0]['start'] = [
|
|
999
|
+
(self.axis.get_xlim()[0]+self.axis.get_xlim()[1])/2,
|
|
1000
|
+
(self.axis.get_ylim()[0]+self.axis.get_ylim()[1])/2,
|
|
1001
|
+
]
|
|
1002
|
+
|
|
1003
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1004
|
+
anim = self.anims[0]
|
|
1005
|
+
if x < anim['delay']:
|
|
1006
|
+
return
|
|
1007
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
1008
|
+
t = self.get_t_from_x(anim,x)
|
|
1009
|
+
width = self.axis.get_xlim()[1]-self.axis.get_xlim()[0]
|
|
1010
|
+
height = self.axis.get_ylim()[1]-self.axis.get_ylim()[0]
|
|
1011
|
+
pos_x = anim['start'][0] + (anim['end'][0] - anim['start'][0])*t
|
|
1012
|
+
pos_y = anim['start'][1] + (anim['end'][1] - anim['start'][1])*t
|
|
1013
|
+
self.axis.set_xlim(pos_x-width/2,pos_x+width/2)
|
|
1014
|
+
self.axis.set_ylim(pos_y-height/2,pos_y+height/2)
|
|
1015
|
+
|
|
1016
|
+
class axis_alpha(Animation):
|
|
1017
|
+
"""
|
|
1018
|
+
Change the opacity of the axis.
|
|
1019
|
+
|
|
1020
|
+
Parameters
|
|
1021
|
+
----------
|
|
1022
|
+
start_alpha : float
|
|
1023
|
+
Initial alpha value
|
|
1024
|
+
end_alpha : float
|
|
1025
|
+
Final alpha value
|
|
1026
|
+
duration : float
|
|
1027
|
+
Duration of the animation
|
|
1028
|
+
delay : float, default=0
|
|
1029
|
+
Delay before starting
|
|
1030
|
+
easing : callable, optional
|
|
1031
|
+
Easing function
|
|
1032
|
+
axis : matplotlib.axes.Axes, optional
|
|
1033
|
+
Axis to plot on
|
|
1034
|
+
|
|
1035
|
+
Example
|
|
1036
|
+
--------
|
|
1037
|
+
Make the axis appear in 100 frames
|
|
1038
|
+
>>> axis_alpha(start_alpha=0,end_alpha=1,duration=100)
|
|
1039
|
+
"""
|
|
1040
|
+
def __init__(self,start_alpha,end_alpha,duration,delay=0,alpha_objs=True,easing=None,axis=None,*args,**kwargs):
|
|
1041
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
1042
|
+
self.anims = [{
|
|
1043
|
+
'name':'axis_move',
|
|
1044
|
+
'duration':duration,
|
|
1045
|
+
'delay':delay,
|
|
1046
|
+
'easing':easing,
|
|
1047
|
+
'persistent':True,
|
|
1048
|
+
'start':start_alpha,
|
|
1049
|
+
'end':end_alpha,
|
|
1050
|
+
'alpha_objs':alpha_objs,
|
|
1051
|
+
'played':False
|
|
1052
|
+
}]
|
|
1053
|
+
self.compute_timings()
|
|
1054
|
+
|
|
1055
|
+
def init(self):
|
|
1056
|
+
pass
|
|
1057
|
+
|
|
1058
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1059
|
+
anim = self.anims[0]
|
|
1060
|
+
if x < anim['delay']:
|
|
1061
|
+
return
|
|
1062
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
1063
|
+
t = self.get_t_from_x(anim,x)
|
|
1064
|
+
alpha = anim['start'] + (anim['end'] - anim['start'])*t
|
|
1065
|
+
alpha = np.clip(alpha,0,1)
|
|
1066
|
+
|
|
1067
|
+
self.axis.patch.set_alpha(alpha)
|
|
1068
|
+
|
|
1069
|
+
for spine in self.axis.spines.values():
|
|
1070
|
+
spine.set_alpha(alpha)
|
|
1071
|
+
|
|
1072
|
+
for tick in self.axis.xaxis.get_major_ticks() + self.axis.yaxis.get_major_ticks():
|
|
1073
|
+
for line in tick.tick1line, tick.tick2line:
|
|
1074
|
+
line.set_alpha(alpha)
|
|
1075
|
+
label = tick.label1
|
|
1076
|
+
label.set_alpha(alpha)
|
|
1077
|
+
|
|
1078
|
+
self.axis.xaxis.label.set_alpha(alpha)
|
|
1079
|
+
self.axis.yaxis.label.set_alpha(alpha)
|
|
1080
|
+
|
|
1081
|
+
self.axis.title.set_alpha(alpha)
|
|
1082
|
+
|
|
1083
|
+
if anim['alpha_objs']:
|
|
1084
|
+
for line in self.axis.get_xgridlines() + self.axis.get_ygridlines():
|
|
1085
|
+
line.set_alpha(alpha)
|
|
1086
|
+
for line in self.axis.lines:
|
|
1087
|
+
line.set_alpha(alpha)
|
|
1088
|
+
for col in self.axis.collections:
|
|
1089
|
+
col.set_alpha(alpha)
|
|
1090
|
+
for patch in self.axis.patches:
|
|
1091
|
+
patch.set_alpha(alpha)
|
|
1092
|
+
for img in self.axis.images:
|
|
1093
|
+
img.set_alpha(alpha)
|
|
1094
|
+
for txt in self.axis.texts:
|
|
1095
|
+
txt.set_alpha(alpha)
|
|
1096
|
+
leg = self.axis.get_legend()
|
|
1097
|
+
if leg:
|
|
1098
|
+
leg.get_frame().set_alpha(alpha)
|
|
1099
|
+
for txt in leg.get_texts():
|
|
1100
|
+
txt.set_alpha(alpha)
|
|
1101
|
+
|
|
1102
|
+
class fig_width_ratio(Animation):
|
|
1103
|
+
"""
|
|
1104
|
+
Resize subplots' widths.
|
|
1105
|
+
|
|
1106
|
+
Parameters
|
|
1107
|
+
----------
|
|
1108
|
+
start_widths : array-like
|
|
1109
|
+
Starting width ratios
|
|
1110
|
+
end_widths : array-like
|
|
1111
|
+
End width ratios
|
|
1112
|
+
duration : float
|
|
1113
|
+
Duration of the animation
|
|
1114
|
+
delay : float, default=0
|
|
1115
|
+
Delay before starting
|
|
1116
|
+
easing : callable, optional
|
|
1117
|
+
Easing function
|
|
1118
|
+
axis : matplotlib.axes.Axes, optional
|
|
1119
|
+
Axis to plot on
|
|
1120
|
+
|
|
1121
|
+
Example
|
|
1122
|
+
--------
|
|
1123
|
+
Resize 2 subplots from equal widths to a ratio of 2:1 in 100 frames:
|
|
1124
|
+
>>> fig_width_ratio(start_widths=(1,1),end_widths=(1,2),duration=100)
|
|
1125
|
+
"""
|
|
1126
|
+
def __init__(self,start_widths,end_widths,duration,delay=0,easing=None,axis=None,*args,**kwargs):
|
|
1127
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
1128
|
+
self.grid = None
|
|
1129
|
+
start_widths = to_np_array(start_widths).astype(float)
|
|
1130
|
+
end_widths = to_np_array(end_widths).astype(float)
|
|
1131
|
+
start_widths = np.maximum(start_widths,1e-3)
|
|
1132
|
+
end_widths = np.maximum(end_widths,1e-3)
|
|
1133
|
+
#Normalize the ratios so scaling with time remains linear
|
|
1134
|
+
start_widths = start_widths/np.sum(start_widths)
|
|
1135
|
+
end_widths = end_widths/np.sum(end_widths)
|
|
1136
|
+
self.anims = [{
|
|
1137
|
+
'name':'axis_move',
|
|
1138
|
+
'duration':duration,
|
|
1139
|
+
'delay':delay,
|
|
1140
|
+
'easing':easing,
|
|
1141
|
+
'persistent':True,
|
|
1142
|
+
'start':start_widths,
|
|
1143
|
+
'end':end_widths,
|
|
1144
|
+
'played':False
|
|
1145
|
+
}]
|
|
1146
|
+
self.compute_timings()
|
|
1147
|
+
|
|
1148
|
+
def init(self):
|
|
1149
|
+
if self.tl.fig.get_layout_engine() is None:
|
|
1150
|
+
#Band-aid fix
|
|
1151
|
+
self.tl.fig.set_layout_engine('tight')
|
|
1152
|
+
if self.grid is None:
|
|
1153
|
+
self.grid = self.axis.get_gridspec()
|
|
1154
|
+
|
|
1155
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1156
|
+
anim = self.anims[0]
|
|
1157
|
+
if x < anim['delay']:
|
|
1158
|
+
return
|
|
1159
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
1160
|
+
t = self.get_t_from_x(anim,x)
|
|
1161
|
+
|
|
1162
|
+
widths = anim['start'] + (anim['end'] - anim['start'])*t
|
|
1163
|
+
|
|
1164
|
+
self.grid.set_width_ratios(widths)
|
|
1165
|
+
|
|
1166
|
+
axes = to_np_array(self.tl.fig.get_axes())
|
|
1167
|
+
shape = self.tl.fig.axes[0].get_subplotspec().get_gridspec().get_geometry()
|
|
1168
|
+
axes = axes.reshape(shape)
|
|
1169
|
+
for i in range(len(widths)):
|
|
1170
|
+
if widths[i] < 1e-3:
|
|
1171
|
+
for row in axes:
|
|
1172
|
+
row[i].set_axis_off()
|
|
1173
|
+
else:
|
|
1174
|
+
for row in axes:
|
|
1175
|
+
if row[i].axison == False:
|
|
1176
|
+
row[i].set_axis_on()
|
|
1177
|
+
|
|
1178
|
+
class fig_height_ratio(Animation):
|
|
1179
|
+
"""
|
|
1180
|
+
Resize subplots' heights.
|
|
1181
|
+
|
|
1182
|
+
Parameters
|
|
1183
|
+
----------
|
|
1184
|
+
start_heights : array-like
|
|
1185
|
+
Starting height ratios
|
|
1186
|
+
end_heights : array-like
|
|
1187
|
+
End height ratios
|
|
1188
|
+
duration : float
|
|
1189
|
+
Duration of the animation
|
|
1190
|
+
delay : float, default=0
|
|
1191
|
+
Delay before starting
|
|
1192
|
+
easing : callable, optional
|
|
1193
|
+
Easing function
|
|
1194
|
+
axis : matplotlib.axes.Axes, optional
|
|
1195
|
+
Axis to plot on
|
|
1196
|
+
|
|
1197
|
+
Example
|
|
1198
|
+
--------
|
|
1199
|
+
Resize 2 subplots from equal heights to a ratio of 2:1 in 100 frames:
|
|
1200
|
+
>>> fig_width_ratio(start_heights=(1,1),end_heights=(1,2),duration=100)
|
|
1201
|
+
"""
|
|
1202
|
+
def __init__(self,start_heights,end_heights,duration,delay=0,easing=None,axis=None,*args,**kwargs):
|
|
1203
|
+
super().__init__(axis=axis,*args, **kwargs)
|
|
1204
|
+
self.grid = None
|
|
1205
|
+
start_heights = to_np_array(start_heights)
|
|
1206
|
+
end_heights = to_np_array(end_heights)
|
|
1207
|
+
start_heights = np.maximum(start_heights,1e-3)
|
|
1208
|
+
end_heights = np.maximum(end_heights,1e-3)
|
|
1209
|
+
#Normalize the ratios so scaling with time remains linear
|
|
1210
|
+
start_heights = start_heights/np.sum(start_heights)
|
|
1211
|
+
end_heights = end_heights/np.sum(end_heights)
|
|
1212
|
+
self.anims = [{
|
|
1213
|
+
'name':'axis_move',
|
|
1214
|
+
'duration':duration,
|
|
1215
|
+
'delay':delay,
|
|
1216
|
+
'easing':easing,
|
|
1217
|
+
'persistent':True,
|
|
1218
|
+
'start':start_heights,
|
|
1219
|
+
'end':end_heights,
|
|
1220
|
+
'played':False
|
|
1221
|
+
}]
|
|
1222
|
+
self.compute_timings()
|
|
1223
|
+
|
|
1224
|
+
def init(self):
|
|
1225
|
+
if self.tl.fig.get_layout_engine() is None:
|
|
1226
|
+
#Band-aid fix
|
|
1227
|
+
self.tl.fig.set_layout_engine('tight')
|
|
1228
|
+
if self.grid is None:
|
|
1229
|
+
self.grid = self.axis.get_gridspec()
|
|
1230
|
+
|
|
1231
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1232
|
+
anim = self.anims[0]
|
|
1233
|
+
if x < anim['delay']:
|
|
1234
|
+
return
|
|
1235
|
+
_x = min(x,anim['duration'] + anim['delay']-1)
|
|
1236
|
+
t = self.get_t_from_x(anim,x)
|
|
1237
|
+
|
|
1238
|
+
heights = anim['start'] + (anim['end'] - anim['start'])*t
|
|
1239
|
+
|
|
1240
|
+
self.grid.set_height_ratios(heights)
|
|
1241
|
+
|
|
1242
|
+
axes = to_np_array(self.tl.fig.get_axes())
|
|
1243
|
+
shape = self.tl.fig.axes[0].get_subplotspec().get_gridspec().get_geometry()
|
|
1244
|
+
axes = axes.reshape(shape)
|
|
1245
|
+
for i in range(len(heights)):
|
|
1246
|
+
if heights[i] < 1e-3:
|
|
1247
|
+
for column in axes.T:
|
|
1248
|
+
column[i].set_axis_off()
|
|
1249
|
+
else:
|
|
1250
|
+
for column in axes.T:
|
|
1251
|
+
if column[i].axison == False:
|
|
1252
|
+
column[i].set_axis_on()
|
|
1253
|
+
|
|
1254
|
+
class scatter(Animation):
|
|
1255
|
+
"""
|
|
1256
|
+
A scatter plot of *y* vs. *x* with varying marker size and/or color.
|
|
1257
|
+
|
|
1258
|
+
Parameters
|
|
1259
|
+
----------
|
|
1260
|
+
x, y : float or array-like, shape (n, )
|
|
1261
|
+
The data positions.
|
|
1262
|
+
|
|
1263
|
+
duration : float
|
|
1264
|
+
Duration of the animation
|
|
1265
|
+
delay : float, default=0
|
|
1266
|
+
Delay before starting
|
|
1267
|
+
easing : callable, optional
|
|
1268
|
+
Easing function
|
|
1269
|
+
axis : matplotlib.axes.Axes, optional
|
|
1270
|
+
Axis to plot on
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
s : float or array-like, shape (n, ), optional
|
|
1274
|
+
The marker size in points**2 (typographic points are 1/72 in.).
|
|
1275
|
+
Default is ``rcParams['lines.markersize'] ** 2``.
|
|
1276
|
+
|
|
1277
|
+
The linewidth and edgecolor can visually interact with the marker
|
|
1278
|
+
size, and can lead to artifacts if the marker size is smaller than
|
|
1279
|
+
the linewidth.
|
|
1280
|
+
|
|
1281
|
+
If the linewidth is greater than 0 and the edgecolor is anything
|
|
1282
|
+
but *'none'*, then the effective size of the marker will be
|
|
1283
|
+
increased by half the linewidth because the stroke will be centered
|
|
1284
|
+
on the edge of the shape.
|
|
1285
|
+
|
|
1286
|
+
To eliminate the marker edge either set *linewidth=0* or
|
|
1287
|
+
*edgecolor='none'*.
|
|
1288
|
+
|
|
1289
|
+
c : array-like or list of color or color, optional
|
|
1290
|
+
The marker colors. Possible values:
|
|
1291
|
+
|
|
1292
|
+
- A scalar or sequence of n numbers to be mapped to colors using
|
|
1293
|
+
*cmap* and *norm*.
|
|
1294
|
+
- A 2D array in which the rows are RGB or RGBA.
|
|
1295
|
+
- A sequence of colors of length n.
|
|
1296
|
+
- A single color format string.
|
|
1297
|
+
|
|
1298
|
+
Note that *c* should not be a single numeric RGB or RGBA sequence
|
|
1299
|
+
because that is indistinguishable from an array of values to be
|
|
1300
|
+
colormapped. If you want to specify the same RGB or RGBA value for
|
|
1301
|
+
all points, use a 2D array with a single row. Otherwise,
|
|
1302
|
+
value-matching will have precedence in case of a size matching with
|
|
1303
|
+
*x* and *y*.
|
|
1304
|
+
|
|
1305
|
+
If you wish to specify a single color for all points
|
|
1306
|
+
prefer the *color* keyword argument.
|
|
1307
|
+
|
|
1308
|
+
Defaults to `None`. In that case the marker color is determined
|
|
1309
|
+
by the value of *color*, *facecolor* or *facecolors*. In case
|
|
1310
|
+
those are not specified or `None`, the marker color is determined
|
|
1311
|
+
by the next color of the ``Axes``' current "shape and fill" color
|
|
1312
|
+
cycle. This cycle defaults to axes.prop_cycle.
|
|
1313
|
+
|
|
1314
|
+
marker : `~.markers.MarkerStyle`, default: scatter.marker
|
|
1315
|
+
The marker style. *marker* can be either an instance of the class
|
|
1316
|
+
or the text shorthand for a particular marker.
|
|
1317
|
+
See :mod:`matplotlib.markers` for more information about marker
|
|
1318
|
+
styles.
|
|
1319
|
+
|
|
1320
|
+
cmap : str or `~matplotlib.colors.Colormap`, default: image.cmap
|
|
1321
|
+
The Colormap instance or registered colormap name used to map scalar data
|
|
1322
|
+
to colors.
|
|
1323
|
+
|
|
1324
|
+
This parameter is ignored if *c* is RGB(A).
|
|
1325
|
+
|
|
1326
|
+
norm : str or `~matplotlib.colors.Normalize`, optional
|
|
1327
|
+
The normalization method used to scale scalar data to the [0, 1] range
|
|
1328
|
+
before mapping to colors using *cmap*. By default, a linear scaling is
|
|
1329
|
+
used, mapping the lowest value to 0 and the highest to 1.
|
|
1330
|
+
|
|
1331
|
+
If given, this can be one of the following:
|
|
1332
|
+
|
|
1333
|
+
- An instance of `.Normalize` or one of its subclasses
|
|
1334
|
+
(see :ref:`colormapnorms`).
|
|
1335
|
+
- A scale name, i.e. one of "linear", "log", "symlog", "logit", etc. For a
|
|
1336
|
+
list of available scales, call `matplotlib.scale.get_scale_names()`.
|
|
1337
|
+
In that case, a suitable `.Normalize` subclass is dynamically generated
|
|
1338
|
+
and instantiated.
|
|
1339
|
+
|
|
1340
|
+
This parameter is ignored if *c* is RGB(A).
|
|
1341
|
+
|
|
1342
|
+
vmin, vmax : float, optional
|
|
1343
|
+
When using scalar data and no explicit *norm*, *vmin* and *vmax* define
|
|
1344
|
+
the data range that the colormap covers. By default, the colormap covers
|
|
1345
|
+
the complete value range of the supplied data. It is an error to use
|
|
1346
|
+
*vmin*/*vmax* when a *norm* instance is given (but using a `str` *norm*
|
|
1347
|
+
name together with *vmin*/*vmax* is acceptable).
|
|
1348
|
+
|
|
1349
|
+
This parameter is ignored if *c* is RGB(A).
|
|
1350
|
+
|
|
1351
|
+
alpha : float, default: None
|
|
1352
|
+
The alpha blending value, between 0 (transparent) and 1 (opaque).
|
|
1353
|
+
|
|
1354
|
+
linewidths : float or array-like, default: lines.linewidth
|
|
1355
|
+
The linewidth of the marker edges. Note: The default *edgecolors*
|
|
1356
|
+
is 'face'. You may want to change this as well.
|
|
1357
|
+
|
|
1358
|
+
edgecolors : {'face', 'none', *None*} or color or list of color, default: scatter.edgecolors
|
|
1359
|
+
The edge color of the marker. Possible values:
|
|
1360
|
+
|
|
1361
|
+
- 'face': The edge color will always be the same as the face color.
|
|
1362
|
+
- 'none': No patch boundary will be drawn.
|
|
1363
|
+
- A color or sequence of colors.
|
|
1364
|
+
|
|
1365
|
+
For non-filled markers, *edgecolors* is ignored. Instead, the color
|
|
1366
|
+
is determined like with 'face', i.e. from *c*, *colors*, or
|
|
1367
|
+
*facecolors*.
|
|
1368
|
+
|
|
1369
|
+
colorizer : `~matplotlib.colorizer.Colorizer` or None, default: None
|
|
1370
|
+
The Colorizer object used to map color to data. If None, a Colorizer
|
|
1371
|
+
object is created from a *norm* and *cmap*.
|
|
1372
|
+
|
|
1373
|
+
This parameter is ignored if *c* is RGB(A).
|
|
1374
|
+
|
|
1375
|
+
plotnonfinite : bool, default: False
|
|
1376
|
+
Whether to plot points with nonfinite *c* (i.e. ``inf``, ``-inf``
|
|
1377
|
+
or ``nan``). If ``True`` the points are drawn with the *bad*
|
|
1378
|
+
colormap color (see `.Colormap.set_bad`).
|
|
1379
|
+
|
|
1380
|
+
Returns
|
|
1381
|
+
-------
|
|
1382
|
+
`~matplotlib.collections.PathCollection`
|
|
1383
|
+
|
|
1384
|
+
Other Parameters
|
|
1385
|
+
----------------
|
|
1386
|
+
data : indexable object, optional
|
|
1387
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
1388
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
1389
|
+
|
|
1390
|
+
*x*, *y*, *s*, *linewidths*, *edgecolors*, *c*, *facecolor*, *facecolors*, *color*
|
|
1391
|
+
**kwargs : `~matplotlib.collections.PathCollection` properties
|
|
1392
|
+
Properties:
|
|
1393
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
1394
|
+
alpha: array-like or float or None
|
|
1395
|
+
animated: bool
|
|
1396
|
+
antialiased or aa or antialiaseds: bool or list of bools
|
|
1397
|
+
array: array-like or None
|
|
1398
|
+
capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
1399
|
+
clim: (vmin: float, vmax: float)
|
|
1400
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
1401
|
+
clip_on: bool
|
|
1402
|
+
clip_path: Patch or (Path, Transform) or None
|
|
1403
|
+
cmap: `.Colormap` or str or None
|
|
1404
|
+
color: color or list of RGBA tuples
|
|
1405
|
+
edgecolor or ec or edgecolors: color or list of color or 'face'
|
|
1406
|
+
facecolor or facecolors or fc: color or list of color
|
|
1407
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
1408
|
+
gid: str
|
|
1409
|
+
hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
|
|
1410
|
+
hatch_linewidth: unknown
|
|
1411
|
+
in_layout: bool
|
|
1412
|
+
joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
1413
|
+
label: object
|
|
1414
|
+
linestyle or dashes or linestyles or ls: str or tuple or list thereof
|
|
1415
|
+
linewidth or linewidths or lw: float or list of floats
|
|
1416
|
+
mouseover: bool
|
|
1417
|
+
norm: `.Normalize` or str or None
|
|
1418
|
+
offset_transform or transOffset: `.Transform`
|
|
1419
|
+
offsets: (N, 2) or (2,) array-like
|
|
1420
|
+
path_effects: list of `.AbstractPathEffect`
|
|
1421
|
+
paths: unknown
|
|
1422
|
+
picker: None or bool or float or callable
|
|
1423
|
+
pickradius: float
|
|
1424
|
+
rasterized: bool
|
|
1425
|
+
sizes: `numpy.ndarray` or None
|
|
1426
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
1427
|
+
snap: bool or None
|
|
1428
|
+
transform: `~matplotlib.transforms.Transform`
|
|
1429
|
+
url: str
|
|
1430
|
+
urls: list of str or None
|
|
1431
|
+
visible: bool
|
|
1432
|
+
zorder: float
|
|
1433
|
+
|
|
1434
|
+
See Also
|
|
1435
|
+
--------
|
|
1436
|
+
plot : To plot scatter plots when markers are identical in size and
|
|
1437
|
+
color.
|
|
1438
|
+
|
|
1439
|
+
Notes
|
|
1440
|
+
-----
|
|
1441
|
+
|
|
1442
|
+
.. note::
|
|
1443
|
+
|
|
1444
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.scatter`.
|
|
1445
|
+
|
|
1446
|
+
* The `.plot` function will be faster for scatterplots where markers
|
|
1447
|
+
don't vary in size or color.
|
|
1448
|
+
|
|
1449
|
+
* Any or all of *x*, *y*, *s*, and *c* may be masked arrays, in which
|
|
1450
|
+
case all masks will be combined and only unmasked points will be
|
|
1451
|
+
plotted.
|
|
1452
|
+
|
|
1453
|
+
* Fundamentally, scatter works with 1D arrays; *x*, *y*, *s*, and *c*
|
|
1454
|
+
may be input as N-D arrays, but within scatter they will be
|
|
1455
|
+
flattened. The exception is *c*, which will be flattened only if its
|
|
1456
|
+
size matches the size of *x* and *y*.
|
|
1457
|
+
"""
|
|
1458
|
+
def __init__(self,x,y,easing=None,axis=None,*args,**kwargs):
|
|
1459
|
+
self.mpl_obj_type = mpl.collections.Collection
|
|
1460
|
+
self.mpl_plot_type = plt.plot
|
|
1461
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
1462
|
+
|
|
1463
|
+
self.x = to_np_array(x)
|
|
1464
|
+
self.y = to_np_array(y)
|
|
1465
|
+
if self.x.size != self.y.size:
|
|
1466
|
+
raise ValueError("x and y must be the same size")
|
|
1467
|
+
|
|
1468
|
+
def clean(self,x,clear_anims=True):
|
|
1469
|
+
if self.obj is not None and self.base_color is None:
|
|
1470
|
+
self.base_color = self.obj.get_edgecolors()[0]
|
|
1471
|
+
if 'color' not in self.kwargs and 'c' not in self.kwargs:
|
|
1472
|
+
self.kwargs['color'] = self.base_color
|
|
1473
|
+
super().clean(x,clear_anims)
|
|
1474
|
+
|
|
1475
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1476
|
+
if 'c' in kwargs and 'color' in kwargs:
|
|
1477
|
+
kwargs.pop('color')
|
|
1478
|
+
if 'c' in kwargs:
|
|
1479
|
+
c = to_np_array(kwargs['c'])
|
|
1480
|
+
if c.ndim == 1 and (len(c) == 3 or len(c) == 4) and len(c) != len(data_x) and (c <= 1).all():
|
|
1481
|
+
kwargs['c'] = c.reshape(1,-1)
|
|
1482
|
+
self.obj = self.axis.scatter(data_x,data_y,**kwargs)
|
|
1483
|
+
|
|
1484
|
+
class plot(Animation):
|
|
1485
|
+
"""
|
|
1486
|
+
Plot y versus x as lines and/or markers.
|
|
1487
|
+
|
|
1488
|
+
Call signatures::
|
|
1489
|
+
|
|
1490
|
+
plot([x], y, [fmt], *, data=None, **kwargs)
|
|
1491
|
+
plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)
|
|
1492
|
+
|
|
1493
|
+
The coordinates of the points or line nodes are given by *x*, *y*.
|
|
1494
|
+
|
|
1495
|
+
The optional parameter *fmt* is a convenient way for defining basic
|
|
1496
|
+
formatting like color, marker and linestyle. It's a shortcut string
|
|
1497
|
+
notation described in the *Notes* section below.
|
|
1498
|
+
|
|
1499
|
+
>>> plot(x, y) # plot x and y using default line style and color
|
|
1500
|
+
>>> plot(x, y, 'bo') # plot x and y using blue circle markers
|
|
1501
|
+
>>> plot(y) # plot y using x as index array 0..N-1
|
|
1502
|
+
>>> plot(y, 'r+') # ditto, but with red plusses
|
|
1503
|
+
|
|
1504
|
+
You can use `.Line2D` properties as keyword arguments for more
|
|
1505
|
+
control on the appearance. Line properties and *fmt* can be mixed.
|
|
1506
|
+
The following two calls yield identical results:
|
|
1507
|
+
|
|
1508
|
+
>>> plot(x, y, 'go--', linewidth=2, markersize=12)
|
|
1509
|
+
>>> plot(x, y, color='green', marker='o', linestyle='dashed',
|
|
1510
|
+
... linewidth=2, markersize=12)
|
|
1511
|
+
|
|
1512
|
+
When conflicting with *fmt*, keyword arguments take precedence.
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
**Plotting labelled data**
|
|
1516
|
+
|
|
1517
|
+
There's a convenient way for plotting objects with labelled data (i.e.
|
|
1518
|
+
data that can be accessed by index ``obj['y']``). Instead of giving
|
|
1519
|
+
the data in *x* and *y*, you can provide the object in the *data*
|
|
1520
|
+
parameter and just give the labels for *x* and *y*::
|
|
1521
|
+
|
|
1522
|
+
>>> plot('xlabel', 'ylabel', data=obj)
|
|
1523
|
+
|
|
1524
|
+
All indexable objects are supported. This could e.g. be a `dict`, a
|
|
1525
|
+
`pandas.DataFrame` or a structured numpy array.
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
**Plotting multiple sets of data**
|
|
1529
|
+
|
|
1530
|
+
There are various ways to plot multiple sets of data.
|
|
1531
|
+
|
|
1532
|
+
- The most straight forward way is just to call `plot` multiple times.
|
|
1533
|
+
Example:
|
|
1534
|
+
|
|
1535
|
+
>>> plot(x1, y1, 'bo')
|
|
1536
|
+
>>> plot(x2, y2, 'go')
|
|
1537
|
+
|
|
1538
|
+
- If *x* and/or *y* are 2D arrays, a separate data set will be drawn
|
|
1539
|
+
for every column. If both *x* and *y* are 2D, they must have the
|
|
1540
|
+
same shape. If only one of them is 2D with shape (N, m) the other
|
|
1541
|
+
must have length N and will be used for every data set m.
|
|
1542
|
+
|
|
1543
|
+
Example:
|
|
1544
|
+
|
|
1545
|
+
>>> x = [1, 2, 3]
|
|
1546
|
+
>>> y = np.array([[1, 2], [3, 4], [5, 6]])
|
|
1547
|
+
>>> plot(x, y)
|
|
1548
|
+
|
|
1549
|
+
is equivalent to:
|
|
1550
|
+
|
|
1551
|
+
>>> for col in range(y.shape[1]):
|
|
1552
|
+
... plot(x, y[:, col])
|
|
1553
|
+
|
|
1554
|
+
- The third way is to specify multiple sets of *[x]*, *y*, *[fmt]*
|
|
1555
|
+
groups::
|
|
1556
|
+
|
|
1557
|
+
>>> plot(x1, y1, 'g^', x2, y2, 'g-')
|
|
1558
|
+
|
|
1559
|
+
In this case, any additional keyword argument applies to all
|
|
1560
|
+
datasets. Also, this syntax cannot be combined with the *data*
|
|
1561
|
+
parameter.
|
|
1562
|
+
|
|
1563
|
+
By default, each line is assigned a different style specified by a
|
|
1564
|
+
'style cycle'. The *fmt* and line property parameters are only
|
|
1565
|
+
necessary if you want explicit deviations from these defaults.
|
|
1566
|
+
Alternatively, you can also change the style cycle using
|
|
1567
|
+
axes.prop_cycle.
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
Parameters
|
|
1571
|
+
----------
|
|
1572
|
+
x, y : array-like or float
|
|
1573
|
+
The horizontal / vertical coordinates of the data points.
|
|
1574
|
+
*x* values are optional and default to ``range(len(y))``.
|
|
1575
|
+
|
|
1576
|
+
duration : float
|
|
1577
|
+
Duration of the animation
|
|
1578
|
+
delay : float, default=0
|
|
1579
|
+
Delay before starting
|
|
1580
|
+
easing : callable, optional
|
|
1581
|
+
Easing function
|
|
1582
|
+
axis : matplotlib.axes.Axes, optional
|
|
1583
|
+
Axis to plot on
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
Commonly, these parameters are 1D arrays.
|
|
1587
|
+
|
|
1588
|
+
They can also be scalars, or two-dimensional (in that case, the
|
|
1589
|
+
columns represent separate data sets).
|
|
1590
|
+
|
|
1591
|
+
These arguments cannot be passed as keywords.
|
|
1592
|
+
|
|
1593
|
+
fmt : str, optional
|
|
1594
|
+
A format string, e.g. 'ro' for red circles. See the *Notes*
|
|
1595
|
+
section for a full description of the format strings.
|
|
1596
|
+
|
|
1597
|
+
Format strings are just an abbreviation for quickly setting
|
|
1598
|
+
basic line properties. All of these and more can also be
|
|
1599
|
+
controlled by keyword arguments.
|
|
1600
|
+
|
|
1601
|
+
This argument cannot be passed as keyword.
|
|
1602
|
+
|
|
1603
|
+
data : indexable object, optional
|
|
1604
|
+
An object with labelled data. If given, provide the label names to
|
|
1605
|
+
plot in *x* and *y*.
|
|
1606
|
+
|
|
1607
|
+
.. note::
|
|
1608
|
+
Technically there's a slight ambiguity in calls where the
|
|
1609
|
+
second label is a valid *fmt*. ``plot('n', 'o', data=obj)``
|
|
1610
|
+
could be ``plt(x, y)`` or ``plt(y, fmt)``. In such cases,
|
|
1611
|
+
the former interpretation is chosen, but a warning is issued.
|
|
1612
|
+
You may suppress the warning by adding an empty format string
|
|
1613
|
+
``plot('n', 'o', '', data=obj)``.
|
|
1614
|
+
|
|
1615
|
+
Returns
|
|
1616
|
+
-------
|
|
1617
|
+
list of `.Line2D`
|
|
1618
|
+
A list of lines representing the plotted data.
|
|
1619
|
+
|
|
1620
|
+
Other Parameters
|
|
1621
|
+
----------------
|
|
1622
|
+
scalex, scaley : bool, default: True
|
|
1623
|
+
These parameters determine if the view limits are adapted to the
|
|
1624
|
+
data limits. The values are passed on to
|
|
1625
|
+
`~.axes.Axes.autoscale_view`.
|
|
1626
|
+
|
|
1627
|
+
**kwargs : `~matplotlib.lines.Line2D` properties, optional
|
|
1628
|
+
*kwargs* are used to specify properties like a line label (for
|
|
1629
|
+
auto legends), linewidth, antialiasing, marker face color.
|
|
1630
|
+
Example::
|
|
1631
|
+
|
|
1632
|
+
>>> plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2)
|
|
1633
|
+
>>> plot([1, 2, 3], [1, 4, 9], 'rs', label='line 2')
|
|
1634
|
+
|
|
1635
|
+
If you specify multiple lines with one plot call, the kwargs apply
|
|
1636
|
+
to all those lines. In case the label object is iterable, each
|
|
1637
|
+
element is used as labels for each set of data.
|
|
1638
|
+
|
|
1639
|
+
Here is a list of available `.Line2D` properties:
|
|
1640
|
+
|
|
1641
|
+
Properties:
|
|
1642
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
1643
|
+
alpha: float or None
|
|
1644
|
+
animated: bool
|
|
1645
|
+
antialiased or aa: bool
|
|
1646
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
1647
|
+
clip_on: bool
|
|
1648
|
+
clip_path: Patch or (Path, Transform) or None
|
|
1649
|
+
color or c: color
|
|
1650
|
+
dash_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
1651
|
+
dash_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
1652
|
+
dashes: sequence of floats (on/off ink in points) or (None, None)
|
|
1653
|
+
data: (2, N) array or two 1D arrays
|
|
1654
|
+
drawstyle or ds: {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}, default: 'default'
|
|
1655
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
1656
|
+
fillstyle: {'full', 'left', 'right', 'bottom', 'top', 'none'}
|
|
1657
|
+
gapcolor: color or None
|
|
1658
|
+
gid: str
|
|
1659
|
+
in_layout: bool
|
|
1660
|
+
label: object
|
|
1661
|
+
linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
|
|
1662
|
+
linewidth or lw: float
|
|
1663
|
+
marker: marker style string, `~.path.Path` or `~.markers.MarkerStyle`
|
|
1664
|
+
markeredgecolor or mec: color
|
|
1665
|
+
markeredgewidth or mew: float
|
|
1666
|
+
markerfacecolor or mfc: color
|
|
1667
|
+
markerfacecoloralt or mfcalt: color
|
|
1668
|
+
markersize or ms: float
|
|
1669
|
+
markevery: None or int or (int, int) or slice or list[int] or float or (float, float) or list[bool]
|
|
1670
|
+
mouseover: bool
|
|
1671
|
+
path_effects: list of `.AbstractPathEffect`
|
|
1672
|
+
picker: float or callable[[Artist, Event], tuple[bool, dict]]
|
|
1673
|
+
pickradius: float
|
|
1674
|
+
rasterized: bool
|
|
1675
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
1676
|
+
snap: bool or None
|
|
1677
|
+
solid_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
1678
|
+
solid_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
1679
|
+
transform: unknown
|
|
1680
|
+
url: str
|
|
1681
|
+
visible: bool
|
|
1682
|
+
xdata: 1D array
|
|
1683
|
+
ydata: 1D array
|
|
1684
|
+
zorder: float
|
|
1685
|
+
|
|
1686
|
+
See Also
|
|
1687
|
+
--------
|
|
1688
|
+
scatter : XY scatter plot with markers of varying size and/or color (
|
|
1689
|
+
sometimes also called bubble chart).
|
|
1690
|
+
|
|
1691
|
+
Notes
|
|
1692
|
+
-----
|
|
1693
|
+
|
|
1694
|
+
.. note::
|
|
1695
|
+
|
|
1696
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.plot`.
|
|
1697
|
+
|
|
1698
|
+
**Format Strings**
|
|
1699
|
+
|
|
1700
|
+
A format string consists of a part for color, marker and line::
|
|
1701
|
+
|
|
1702
|
+
fmt = '[marker][line][color]'
|
|
1703
|
+
|
|
1704
|
+
Each of them is optional. If not provided, the value from the style
|
|
1705
|
+
cycle is used. Exception: If ``line`` is given, but no ``marker``,
|
|
1706
|
+
the data will be a line without markers.
|
|
1707
|
+
|
|
1708
|
+
Other combinations such as ``[color][marker][line]`` are also
|
|
1709
|
+
supported, but note that their parsing may be ambiguous.
|
|
1710
|
+
|
|
1711
|
+
**Markers**
|
|
1712
|
+
|
|
1713
|
+
============= ===============================
|
|
1714
|
+
character description
|
|
1715
|
+
============= ===============================
|
|
1716
|
+
``'.'`` point marker
|
|
1717
|
+
``','`` pixel marker
|
|
1718
|
+
``'o'`` circle marker
|
|
1719
|
+
``'v'`` triangle_down marker
|
|
1720
|
+
``'^'`` triangle_up marker
|
|
1721
|
+
``'<'`` triangle_left marker
|
|
1722
|
+
``'>'`` triangle_right marker
|
|
1723
|
+
``'1'`` tri_down marker
|
|
1724
|
+
``'2'`` tri_up marker
|
|
1725
|
+
``'3'`` tri_left marker
|
|
1726
|
+
``'4'`` tri_right marker
|
|
1727
|
+
``'8'`` octagon marker
|
|
1728
|
+
``'s'`` square marker
|
|
1729
|
+
``'p'`` pentagon marker
|
|
1730
|
+
``'P'`` plus (filled) marker
|
|
1731
|
+
``'*'`` star marker
|
|
1732
|
+
``'h'`` hexagon1 marker
|
|
1733
|
+
``'H'`` hexagon2 marker
|
|
1734
|
+
``'+'`` plus marker
|
|
1735
|
+
``'x'`` x marker
|
|
1736
|
+
``'X'`` x (filled) marker
|
|
1737
|
+
``'D'`` diamond marker
|
|
1738
|
+
``'d'`` thin_diamond marker
|
|
1739
|
+
``'|'`` vline marker
|
|
1740
|
+
``'_'`` hline marker
|
|
1741
|
+
============= ===============================
|
|
1742
|
+
|
|
1743
|
+
**Line Styles**
|
|
1744
|
+
|
|
1745
|
+
============= ===============================
|
|
1746
|
+
character description
|
|
1747
|
+
============= ===============================
|
|
1748
|
+
``'-'`` solid line style
|
|
1749
|
+
``'--'`` dashed line style
|
|
1750
|
+
``'-.'`` dash-dot line style
|
|
1751
|
+
``':'`` dotted line style
|
|
1752
|
+
============= ===============================
|
|
1753
|
+
|
|
1754
|
+
Example format strings::
|
|
1755
|
+
|
|
1756
|
+
'b' # blue markers with default shape
|
|
1757
|
+
'or' # red circles
|
|
1758
|
+
'-g' # green solid line
|
|
1759
|
+
'--' # dashed line with default color
|
|
1760
|
+
'^k:' # black triangle_up markers connected by a dotted line
|
|
1761
|
+
|
|
1762
|
+
**Colors**
|
|
1763
|
+
|
|
1764
|
+
The supported color abbreviations are the single letter codes
|
|
1765
|
+
|
|
1766
|
+
============= ===============================
|
|
1767
|
+
character color
|
|
1768
|
+
============= ===============================
|
|
1769
|
+
``'b'`` blue
|
|
1770
|
+
``'g'`` green
|
|
1771
|
+
``'r'`` red
|
|
1772
|
+
``'c'`` cyan
|
|
1773
|
+
``'m'`` magenta
|
|
1774
|
+
``'y'`` yellow
|
|
1775
|
+
``'k'`` black
|
|
1776
|
+
``'w'`` white
|
|
1777
|
+
============= ===============================
|
|
1778
|
+
|
|
1779
|
+
and the ``'CN'`` colors that index into the default property cycle.
|
|
1780
|
+
|
|
1781
|
+
If the color is the only part of the format string, you can
|
|
1782
|
+
additionally use any `matplotlib.colors` spec, e.g. full names
|
|
1783
|
+
(``'green'``) or hex strings (``'#008000'``).
|
|
1784
|
+
"""
|
|
1785
|
+
def __init__(self,x,y,easing=None,axis=None,*args,**kwargs):
|
|
1786
|
+
self.mpl_obj_type = mpl.lines.Line2D
|
|
1787
|
+
self.mpl_plot_type = plt.plot
|
|
1788
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
1789
|
+
|
|
1790
|
+
self.x = to_np_array(x)
|
|
1791
|
+
self.y = to_np_array(y)
|
|
1792
|
+
if self.x.size != self.y.size:
|
|
1793
|
+
raise ValueError("x and y must be the same size")
|
|
1794
|
+
|
|
1795
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1796
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
1797
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
1798
|
+
self.obj = self.axis.plot(data_x,data_y,**kwargs)
|
|
1799
|
+
|
|
1800
|
+
class step(Animation):
|
|
1801
|
+
"""
|
|
1802
|
+
Make a step plot.
|
|
1803
|
+
|
|
1804
|
+
Call signatures::
|
|
1805
|
+
|
|
1806
|
+
step(x, y, [fmt], *, data=None, where='pre', **kwargs)
|
|
1807
|
+
step(x, y, [fmt], x2, y2, [fmt2], ..., *, where='pre', **kwargs)
|
|
1808
|
+
|
|
1809
|
+
This is just a thin wrapper around `.plot` which changes some
|
|
1810
|
+
formatting options. Most of the concepts and parameters of plot can be
|
|
1811
|
+
used here as well.
|
|
1812
|
+
|
|
1813
|
+
.. note::
|
|
1814
|
+
|
|
1815
|
+
This method uses a standard plot with a step drawstyle: The *x*
|
|
1816
|
+
values are the reference positions and steps extend left/right/both
|
|
1817
|
+
directions depending on *where*.
|
|
1818
|
+
|
|
1819
|
+
For the common case where you know the values and edges of the
|
|
1820
|
+
steps, use `~.Axes.stairs` instead.
|
|
1821
|
+
|
|
1822
|
+
Parameters
|
|
1823
|
+
----------
|
|
1824
|
+
x : array-like
|
|
1825
|
+
1D sequence of x positions. It is assumed, but not checked, that
|
|
1826
|
+
it is uniformly increasing.
|
|
1827
|
+
|
|
1828
|
+
y : array-like
|
|
1829
|
+
1D sequence of y levels.
|
|
1830
|
+
|
|
1831
|
+
fmt : str, optional
|
|
1832
|
+
A format string, e.g. 'g' for a green line. See `.plot` for a more
|
|
1833
|
+
detailed description.
|
|
1834
|
+
|
|
1835
|
+
Note: While full format strings are accepted, it is recommended to
|
|
1836
|
+
only specify the color. Line styles are currently ignored (use
|
|
1837
|
+
the keyword argument *linestyle* instead). Markers are accepted
|
|
1838
|
+
and plotted on the given positions, however, this is a rarely
|
|
1839
|
+
needed feature for step plots.
|
|
1840
|
+
|
|
1841
|
+
where : {'pre', 'post', 'mid'}, default: 'pre'
|
|
1842
|
+
Define where the steps should be placed:
|
|
1843
|
+
|
|
1844
|
+
- 'pre': The y value is continued constantly to the left from
|
|
1845
|
+
every *x* position, i.e. the interval ``(x[i-1], x[i]]`` has the
|
|
1846
|
+
value ``y[i]``.
|
|
1847
|
+
- 'post': The y value is continued constantly to the right from
|
|
1848
|
+
every *x* position, i.e. the interval ``[x[i], x[i+1])`` has the
|
|
1849
|
+
value ``y[i]``.
|
|
1850
|
+
- 'mid': Steps occur half-way between the *x* positions.
|
|
1851
|
+
|
|
1852
|
+
data : indexable object, optional
|
|
1853
|
+
An object with labelled data. If given, provide the label names to
|
|
1854
|
+
plot in *x* and *y*.
|
|
1855
|
+
|
|
1856
|
+
**kwargs
|
|
1857
|
+
Additional parameters are the same as those for `.plot`.
|
|
1858
|
+
|
|
1859
|
+
Returns
|
|
1860
|
+
-------
|
|
1861
|
+
list of `.Line2D`
|
|
1862
|
+
Objects representing the plotted data.
|
|
1863
|
+
"""
|
|
1864
|
+
def __init__(self,x,y,easing=None,axis=None,*args, **kwargs):
|
|
1865
|
+
self.mpl_obj_type = mpl.lines.Line2D
|
|
1866
|
+
self.mpl_plot_type = plt.plot
|
|
1867
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
1868
|
+
|
|
1869
|
+
self.x = to_np_array(x)
|
|
1870
|
+
self.y = to_np_array(y)
|
|
1871
|
+
if self.x.size != self.y.size:
|
|
1872
|
+
raise ValueError("x and y must be the same size")
|
|
1873
|
+
|
|
1874
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
1875
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
1876
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
1877
|
+
|
|
1878
|
+
self.obj = self.axis.step(data_x,data_y,**kwargs)
|
|
1879
|
+
|
|
1880
|
+
class fill_between(Animation):
|
|
1881
|
+
"""
|
|
1882
|
+
Fill the area between two horizontal curves.
|
|
1883
|
+
|
|
1884
|
+
The curves are defined by the points (*x*, *y1*) and (*x*,
|
|
1885
|
+
*y2*). This creates one or multiple polygons describing the filled
|
|
1886
|
+
area.
|
|
1887
|
+
|
|
1888
|
+
You may exclude some horizontal sections from filling using *where*.
|
|
1889
|
+
|
|
1890
|
+
By default, the edges connect the given points directly. Use *step*
|
|
1891
|
+
if the filling should be a step function, i.e. constant in between
|
|
1892
|
+
*x*.
|
|
1893
|
+
|
|
1894
|
+
Parameters
|
|
1895
|
+
----------
|
|
1896
|
+
x : array-like
|
|
1897
|
+
The x coordinates of the nodes defining the curves.
|
|
1898
|
+
|
|
1899
|
+
duration : float
|
|
1900
|
+
Duration of the animation
|
|
1901
|
+
delay : float, default=0
|
|
1902
|
+
Delay before starting
|
|
1903
|
+
easing : callable, optional
|
|
1904
|
+
Easing function
|
|
1905
|
+
axis : matplotlib.axes.Axes, optional
|
|
1906
|
+
Axis to plot on
|
|
1907
|
+
|
|
1908
|
+
|
|
1909
|
+
y1 : array-like or float
|
|
1910
|
+
The y coordinates of the nodes defining the first curve.
|
|
1911
|
+
|
|
1912
|
+
y2 : array-like or float, default: 0
|
|
1913
|
+
The y coordinates of the nodes defining the second curve.
|
|
1914
|
+
|
|
1915
|
+
where : array-like of bool, optional
|
|
1916
|
+
Define *where* to exclude some horizontal regions from being filled.
|
|
1917
|
+
The filled regions are defined by the coordinates ``x[where]``.
|
|
1918
|
+
More precisely, fill between ``x[i]`` and ``x[i+1]`` if
|
|
1919
|
+
``where[i] and where[i+1]``. Note that this definition implies
|
|
1920
|
+
that an isolated *True* value between two *False* values in *where*
|
|
1921
|
+
will not result in filling. Both sides of the *True* position
|
|
1922
|
+
remain unfilled due to the adjacent *False* values.
|
|
1923
|
+
|
|
1924
|
+
interpolate : bool, default: False
|
|
1925
|
+
This option is only relevant if *where* is used and the two curves
|
|
1926
|
+
are crossing each other.
|
|
1927
|
+
|
|
1928
|
+
Semantically, *where* is often used for *y1* > *y2* or
|
|
1929
|
+
similar. By default, the nodes of the polygon defining the filled
|
|
1930
|
+
region will only be placed at the positions in the *x* array.
|
|
1931
|
+
Such a polygon cannot describe the above semantics close to the
|
|
1932
|
+
intersection. The x-sections containing the intersection are
|
|
1933
|
+
simply clipped.
|
|
1934
|
+
|
|
1935
|
+
Setting *interpolate* to *True* will calculate the actual
|
|
1936
|
+
intersection point and extend the filled region up to this point.
|
|
1937
|
+
|
|
1938
|
+
step : {'pre', 'post', 'mid'}, optional
|
|
1939
|
+
Define *step* if the filling should be a step function,
|
|
1940
|
+
i.e. constant in between *x*. The value determines where the
|
|
1941
|
+
step will occur:
|
|
1942
|
+
|
|
1943
|
+
- 'pre': The y value is continued constantly to the left from
|
|
1944
|
+
every *x* position, i.e. the interval ``(x[i-1], x[i]]``
|
|
1945
|
+
has the value ``y[i]``.
|
|
1946
|
+
- 'post': The y value is continued constantly to the right from
|
|
1947
|
+
every *x* position, i.e. the interval ``[x[i], x[i+1])``
|
|
1948
|
+
has the value ``y[i]``.
|
|
1949
|
+
- 'mid': Steps occur half-way between the *x* positions.
|
|
1950
|
+
|
|
1951
|
+
Returns
|
|
1952
|
+
-------
|
|
1953
|
+
`.FillBetweenPolyCollection`
|
|
1954
|
+
A `.FillBetweenPolyCollection` containing the plotted polygons.
|
|
1955
|
+
|
|
1956
|
+
Other Parameters
|
|
1957
|
+
----------------
|
|
1958
|
+
data : indexable object, optional
|
|
1959
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
1960
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
1961
|
+
|
|
1962
|
+
*x*, *y1*, *y2*, *where*
|
|
1963
|
+
|
|
1964
|
+
**kwargs
|
|
1965
|
+
All other keyword arguments are passed on to
|
|
1966
|
+
`.FillBetweenPolyCollection`. They control the `.Polygon` properties:
|
|
1967
|
+
|
|
1968
|
+
Properties:
|
|
1969
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
1970
|
+
alpha: array-like or float or None
|
|
1971
|
+
animated: bool
|
|
1972
|
+
antialiased or aa or antialiaseds: bool or list of bools
|
|
1973
|
+
array: array-like or None
|
|
1974
|
+
capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
1975
|
+
clim: (vmin: float, vmax: float)
|
|
1976
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
1977
|
+
clip_on: bool
|
|
1978
|
+
clip_path: Patch or (Path, Transform) or None
|
|
1979
|
+
cmap: `.Colormap` or str or None
|
|
1980
|
+
color: color or list of RGBA tuples
|
|
1981
|
+
data: array-like
|
|
1982
|
+
edgecolor or ec or edgecolors: color or list of color or 'face'
|
|
1983
|
+
facecolor or facecolors or fc: color or list of color
|
|
1984
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
1985
|
+
gid: str
|
|
1986
|
+
hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
|
|
1987
|
+
hatch_linewidth: unknown
|
|
1988
|
+
in_layout: bool
|
|
1989
|
+
joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
1990
|
+
label: object
|
|
1991
|
+
linestyle or dashes or linestyles or ls: str or tuple or list thereof
|
|
1992
|
+
linewidth or linewidths or lw: float or list of floats
|
|
1993
|
+
mouseover: bool
|
|
1994
|
+
norm: `.Normalize` or str or None
|
|
1995
|
+
offset_transform or transOffset: `.Transform`
|
|
1996
|
+
offsets: (N, 2) or (2,) array-like
|
|
1997
|
+
path_effects: list of `.AbstractPathEffect`
|
|
1998
|
+
paths: list of array-like
|
|
1999
|
+
picker: None or bool or float or callable
|
|
2000
|
+
pickradius: float
|
|
2001
|
+
rasterized: bool
|
|
2002
|
+
sizes: `numpy.ndarray` or None
|
|
2003
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
2004
|
+
snap: bool or None
|
|
2005
|
+
transform: `~matplotlib.transforms.Transform`
|
|
2006
|
+
url: str
|
|
2007
|
+
urls: list of str or None
|
|
2008
|
+
verts: list of array-like
|
|
2009
|
+
verts_and_codes: unknown
|
|
2010
|
+
visible: bool
|
|
2011
|
+
zorder: float
|
|
2012
|
+
|
|
2013
|
+
See Also
|
|
2014
|
+
--------
|
|
2015
|
+
fill_between : Fill between two sets of y-values.
|
|
2016
|
+
fill_betweenx : Fill between two sets of x-values.
|
|
2017
|
+
|
|
2018
|
+
Notes
|
|
2019
|
+
-----
|
|
2020
|
+
|
|
2021
|
+
.. note::
|
|
2022
|
+
|
|
2023
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.fill_between`.
|
|
2024
|
+
"""
|
|
2025
|
+
def __init__(self,x,y1,y2,easing=None,axis=None, *args, **kwargs):
|
|
2026
|
+
self.mpl_obj_type = mpl.collections.FillBetweenPolyCollection
|
|
2027
|
+
self.mpl_plot_type = plt.fill_between
|
|
2028
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2029
|
+
self.x = to_np_array(x)
|
|
2030
|
+
self.y = to_np_array(x)
|
|
2031
|
+
self.y1 = to_np_array(y1).reshape(-1)
|
|
2032
|
+
self.y2 = to_np_array(y2).reshape(-1)
|
|
2033
|
+
if self.y1.size != self.x.size:
|
|
2034
|
+
self.y1 = np.ones_like(self.x)*self.y1[0]
|
|
2035
|
+
if self.y2.size != self.x.size:
|
|
2036
|
+
self.y2 = np.ones_like(self.x)*self.y2[0]
|
|
2037
|
+
|
|
2038
|
+
def clean(self,x,clear_anims=True):
|
|
2039
|
+
if self.obj is not None and self.base_color is None:
|
|
2040
|
+
self.base_color = self.obj.get_facecolor()
|
|
2041
|
+
if 'facecolor' not in self.kwargs:
|
|
2042
|
+
self.kwargs['facecolor'] = self.base_color
|
|
2043
|
+
super().clean(x,clear_anims)
|
|
2044
|
+
|
|
2045
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2046
|
+
self.obj = self.axis.fill_between(x=data_x,**kwargs)
|
|
2047
|
+
|
|
2048
|
+
class fill_betweenx(Animation):
|
|
2049
|
+
"""
|
|
2050
|
+
Fill the area between two vertical curves.
|
|
2051
|
+
|
|
2052
|
+
The curves are defined by the points (*y*, *x1*) and (*y*,
|
|
2053
|
+
*x2*). This creates one or multiple polygons describing the filled
|
|
2054
|
+
area.
|
|
2055
|
+
|
|
2056
|
+
You may exclude some vertical sections from filling using *where*.
|
|
2057
|
+
|
|
2058
|
+
By default, the edges connect the given points directly. Use *step*
|
|
2059
|
+
if the filling should be a step function, i.e. constant in between
|
|
2060
|
+
*y*.
|
|
2061
|
+
|
|
2062
|
+
Parameters
|
|
2063
|
+
----------
|
|
2064
|
+
y : array-like
|
|
2065
|
+
The y coordinates of the nodes defining the curves.
|
|
2066
|
+
|
|
2067
|
+
duration : float
|
|
2068
|
+
Duration of the animation
|
|
2069
|
+
delay : float, default=0
|
|
2070
|
+
Delay before starting
|
|
2071
|
+
easing : callable, optional
|
|
2072
|
+
Easing function
|
|
2073
|
+
axis : matplotlib.axes.Axes, optional
|
|
2074
|
+
Axis to plot on
|
|
2075
|
+
|
|
2076
|
+
|
|
2077
|
+
x1 : array-like or float
|
|
2078
|
+
The x coordinates of the nodes defining the first curve.
|
|
2079
|
+
|
|
2080
|
+
x2 : array-like or float, default: 0
|
|
2081
|
+
The x coordinates of the nodes defining the second curve.
|
|
2082
|
+
|
|
2083
|
+
where : array-like of bool, optional
|
|
2084
|
+
Define *where* to exclude some vertical regions from being filled.
|
|
2085
|
+
The filled regions are defined by the coordinates ``y[where]``.
|
|
2086
|
+
More precisely, fill between ``y[i]`` and ``y[i+1]`` if
|
|
2087
|
+
``where[i] and where[i+1]``. Note that this definition implies
|
|
2088
|
+
that an isolated *True* value between two *False* values in *where*
|
|
2089
|
+
will not result in filling. Both sides of the *True* position
|
|
2090
|
+
remain unfilled due to the adjacent *False* values.
|
|
2091
|
+
|
|
2092
|
+
interpolate : bool, default: False
|
|
2093
|
+
This option is only relevant if *where* is used and the two curves
|
|
2094
|
+
are crossing each other.
|
|
2095
|
+
|
|
2096
|
+
Semantically, *where* is often used for *x1* > *x2* or
|
|
2097
|
+
similar. By default, the nodes of the polygon defining the filled
|
|
2098
|
+
region will only be placed at the positions in the *y* array.
|
|
2099
|
+
Such a polygon cannot describe the above semantics close to the
|
|
2100
|
+
intersection. The y-sections containing the intersection are
|
|
2101
|
+
simply clipped.
|
|
2102
|
+
|
|
2103
|
+
Setting *interpolate* to *True* will calculate the actual
|
|
2104
|
+
intersection point and extend the filled region up to this point.
|
|
2105
|
+
|
|
2106
|
+
step : {'pre', 'post', 'mid'}, optional
|
|
2107
|
+
Define *step* if the filling should be a step function,
|
|
2108
|
+
i.e. constant in between *y*. The value determines where the
|
|
2109
|
+
step will occur:
|
|
2110
|
+
|
|
2111
|
+
- 'pre': The x value is continued constantly to the left from
|
|
2112
|
+
every *y* position, i.e. the interval ``(y[i-1], y[i]]``
|
|
2113
|
+
has the value ``x[i]``.
|
|
2114
|
+
- 'post': The y value is continued constantly to the right from
|
|
2115
|
+
every *y* position, i.e. the interval ``[y[i], y[i+1])``
|
|
2116
|
+
has the value ``x[i]``.
|
|
2117
|
+
- 'mid': Steps occur half-way between the *y* positions.
|
|
2118
|
+
|
|
2119
|
+
Returns
|
|
2120
|
+
-------
|
|
2121
|
+
`.FillBetweenPolyCollection`
|
|
2122
|
+
A `.FillBetweenPolyCollection` containing the plotted polygons.
|
|
2123
|
+
|
|
2124
|
+
Other Parameters
|
|
2125
|
+
----------------
|
|
2126
|
+
data : indexable object, optional
|
|
2127
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
2128
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
2129
|
+
|
|
2130
|
+
*y*, *x1*, *x2*, *where*
|
|
2131
|
+
|
|
2132
|
+
**kwargs
|
|
2133
|
+
All other keyword arguments are passed on to
|
|
2134
|
+
`.FillBetweenPolyCollection`. They control the `.Polygon` properties:
|
|
2135
|
+
|
|
2136
|
+
Properties:
|
|
2137
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
2138
|
+
alpha: array-like or float or None
|
|
2139
|
+
animated: bool
|
|
2140
|
+
antialiased or aa or antialiaseds: bool or list of bools
|
|
2141
|
+
array: array-like or None
|
|
2142
|
+
capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
2143
|
+
clim: (vmin: float, vmax: float)
|
|
2144
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
2145
|
+
clip_on: bool
|
|
2146
|
+
clip_path: Patch or (Path, Transform) or None
|
|
2147
|
+
cmap: `.Colormap` or str or None
|
|
2148
|
+
color: color or list of RGBA tuples
|
|
2149
|
+
data: array-like
|
|
2150
|
+
edgecolor or ec or edgecolors: color or list of color or 'face'
|
|
2151
|
+
facecolor or facecolors or fc: color or list of color
|
|
2152
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
2153
|
+
gid: str
|
|
2154
|
+
hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
|
|
2155
|
+
hatch_linewidth: unknown
|
|
2156
|
+
in_layout: bool
|
|
2157
|
+
joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
2158
|
+
label: object
|
|
2159
|
+
linestyle or dashes or linestyles or ls: str or tuple or list thereof
|
|
2160
|
+
linewidth or linewidths or lw: float or list of floats
|
|
2161
|
+
mouseover: bool
|
|
2162
|
+
norm: `.Normalize` or str or None
|
|
2163
|
+
offset_transform or transOffset: `.Transform`
|
|
2164
|
+
offsets: (N, 2) or (2,) array-like
|
|
2165
|
+
path_effects: list of `.AbstractPathEffect`
|
|
2166
|
+
paths: list of array-like
|
|
2167
|
+
picker: None or bool or float or callable
|
|
2168
|
+
pickradius: float
|
|
2169
|
+
rasterized: bool
|
|
2170
|
+
sizes: `numpy.ndarray` or None
|
|
2171
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
2172
|
+
snap: bool or None
|
|
2173
|
+
transform: `~matplotlib.transforms.Transform`
|
|
2174
|
+
url: str
|
|
2175
|
+
urls: list of str or None
|
|
2176
|
+
verts: list of array-like
|
|
2177
|
+
verts_and_codes: unknown
|
|
2178
|
+
visible: bool
|
|
2179
|
+
zorder: float
|
|
2180
|
+
|
|
2181
|
+
See Also
|
|
2182
|
+
--------
|
|
2183
|
+
fill_between : Fill between two sets of y-values.
|
|
2184
|
+
fill_betweenx : Fill between two sets of x-values.
|
|
2185
|
+
|
|
2186
|
+
Notes
|
|
2187
|
+
-----
|
|
2188
|
+
|
|
2189
|
+
.. note::
|
|
2190
|
+
|
|
2191
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.fill_betweenx`.
|
|
2192
|
+
"""
|
|
2193
|
+
def __init__(self,y,x1,x2,easing=None,axis=None, *args, **kwargs):
|
|
2194
|
+
self.mpl_obj_type = mpl.collections.FillBetweenPolyCollection
|
|
2195
|
+
self.mpl_plot_type = plt.fill_betweenx
|
|
2196
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2197
|
+
self.x = to_np_array(y)
|
|
2198
|
+
self.y = to_np_array(y)
|
|
2199
|
+
self.x1 = to_np_array(x1).reshape(-1)
|
|
2200
|
+
self.x2 = to_np_array(x2).reshape(-1)
|
|
2201
|
+
if self.x1.size != self.y.size:
|
|
2202
|
+
self.x1 = np.ones_like(self.y)*self.x1[0]
|
|
2203
|
+
if self.x2.size != self.y.size:
|
|
2204
|
+
self.x2 = np.ones_like(self.y)*self.x2[0]
|
|
2205
|
+
|
|
2206
|
+
def clean(self,x,clear_anims=True):
|
|
2207
|
+
if self.obj is not None and self.base_color is None:
|
|
2208
|
+
self.base_color = self.obj.get_facecolor()
|
|
2209
|
+
if 'facecolor' not in self.kwargs:
|
|
2210
|
+
self.kwargs['facecolor'] = self.base_color
|
|
2211
|
+
super().clean(x,clear_anims)
|
|
2212
|
+
|
|
2213
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2214
|
+
self.obj = self.axis.fill_betweenx(y=data_x,**kwargs)
|
|
2215
|
+
|
|
2216
|
+
class axvline(Animation):
|
|
2217
|
+
"""
|
|
2218
|
+
Add a vertical line spanning the whole or fraction of the Axes.
|
|
2219
|
+
|
|
2220
|
+
Note: If you want to set y-limits in data coordinates, use
|
|
2221
|
+
`~.Axes.vlines` instead.
|
|
2222
|
+
|
|
2223
|
+
Parameters
|
|
2224
|
+
----------
|
|
2225
|
+
x : float, default: 0
|
|
2226
|
+
x position in :ref:`data coordinates <coordinate-systems>`.
|
|
2227
|
+
|
|
2228
|
+
duration : float
|
|
2229
|
+
Duration of the animation
|
|
2230
|
+
delay : float, default=0
|
|
2231
|
+
Delay before starting
|
|
2232
|
+
easing : callable, optional
|
|
2233
|
+
Easing function
|
|
2234
|
+
axis : matplotlib.axes.Axes, optional
|
|
2235
|
+
Axis to plot on
|
|
2236
|
+
|
|
2237
|
+
|
|
2238
|
+
ymin : float, default: 0
|
|
2239
|
+
The start y-position in :ref:`axes coordinates <coordinate-systems>`.
|
|
2240
|
+
Should be between 0 and 1, 0 being the bottom of the plot, 1 the
|
|
2241
|
+
top of the plot.
|
|
2242
|
+
|
|
2243
|
+
ymax : float, default: 1
|
|
2244
|
+
The end y-position in :ref:`axes coordinates <coordinate-systems>`.
|
|
2245
|
+
Should be between 0 and 1, 0 being the bottom of the plot, 1 the
|
|
2246
|
+
top of the plot.
|
|
2247
|
+
|
|
2248
|
+
Returns
|
|
2249
|
+
-------
|
|
2250
|
+
`~matplotlib.lines.Line2D`
|
|
2251
|
+
A `.Line2D` specified via two points ``(x, ymin)``, ``(x, ymax)``.
|
|
2252
|
+
Its transform is set such that *x* is in
|
|
2253
|
+
:ref:`data coordinates <coordinate-systems>` and *y* is in
|
|
2254
|
+
:ref:`axes coordinates <coordinate-systems>`.
|
|
2255
|
+
|
|
2256
|
+
This is still a generic line and the vertical character is only
|
|
2257
|
+
realized through using identical *x* values for both points. Thus,
|
|
2258
|
+
if you want to change the *x* value later, you have to provide two
|
|
2259
|
+
values ``line.set_xdata([3, 3])``.
|
|
2260
|
+
|
|
2261
|
+
Other Parameters
|
|
2262
|
+
----------------
|
|
2263
|
+
**kwargs
|
|
2264
|
+
Valid keyword arguments are `.Line2D` properties, except for
|
|
2265
|
+
'transform':
|
|
2266
|
+
|
|
2267
|
+
Properties:
|
|
2268
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
2269
|
+
alpha: float or None
|
|
2270
|
+
animated: bool
|
|
2271
|
+
antialiased or aa: bool
|
|
2272
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
2273
|
+
clip_on: bool
|
|
2274
|
+
clip_path: Patch or (Path, Transform) or None
|
|
2275
|
+
color or c: color
|
|
2276
|
+
dash_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
2277
|
+
dash_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
2278
|
+
dashes: sequence of floats (on/off ink in points) or (None, None)
|
|
2279
|
+
data: (2, N) array or two 1D arrays
|
|
2280
|
+
drawstyle or ds: {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}, default: 'default'
|
|
2281
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
2282
|
+
fillstyle: {'full', 'left', 'right', 'bottom', 'top', 'none'}
|
|
2283
|
+
gapcolor: color or None
|
|
2284
|
+
gid: str
|
|
2285
|
+
in_layout: bool
|
|
2286
|
+
label: object
|
|
2287
|
+
linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
|
|
2288
|
+
linewidth or lw: float
|
|
2289
|
+
marker: marker style string, `~.path.Path` or `~.markers.MarkerStyle`
|
|
2290
|
+
markeredgecolor or mec: color
|
|
2291
|
+
markeredgewidth or mew: float
|
|
2292
|
+
markerfacecolor or mfc: color
|
|
2293
|
+
markerfacecoloralt or mfcalt: color
|
|
2294
|
+
markersize or ms: float
|
|
2295
|
+
markevery: None or int or (int, int) or slice or list[int] or float or (float, float) or list[bool]
|
|
2296
|
+
mouseover: bool
|
|
2297
|
+
path_effects: list of `.AbstractPathEffect`
|
|
2298
|
+
picker: float or callable[[Artist, Event], tuple[bool, dict]]
|
|
2299
|
+
pickradius: float
|
|
2300
|
+
rasterized: bool
|
|
2301
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
2302
|
+
snap: bool or None
|
|
2303
|
+
solid_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
2304
|
+
solid_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
2305
|
+
transform: unknown
|
|
2306
|
+
url: str
|
|
2307
|
+
visible: bool
|
|
2308
|
+
xdata: 1D array
|
|
2309
|
+
ydata: 1D array
|
|
2310
|
+
zorder: float
|
|
2311
|
+
|
|
2312
|
+
See Also
|
|
2313
|
+
--------
|
|
2314
|
+
vlines : Add vertical lines in data coordinates.
|
|
2315
|
+
axvspan : Add a vertical span (rectangle) across the axis.
|
|
2316
|
+
axline : Add a line with an arbitrary slope.
|
|
2317
|
+
|
|
2318
|
+
Notes
|
|
2319
|
+
-----
|
|
2320
|
+
|
|
2321
|
+
.. note::
|
|
2322
|
+
|
|
2323
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.axvline`.
|
|
2324
|
+
|
|
2325
|
+
Examples
|
|
2326
|
+
--------
|
|
2327
|
+
* draw a thick red vline at *x* = 0 that spans the yrange::
|
|
2328
|
+
|
|
2329
|
+
>>> axvline(linewidth=4, color='r')
|
|
2330
|
+
|
|
2331
|
+
* draw a default vline at *x* = 1 that spans the yrange::
|
|
2332
|
+
|
|
2333
|
+
>>> axvline(x=1)
|
|
2334
|
+
|
|
2335
|
+
* draw a default vline at *x* = .5 that spans the middle half of
|
|
2336
|
+
the yrange::
|
|
2337
|
+
|
|
2338
|
+
>>> axvline(x=.5, ymin=0.25, ymax=0.75)
|
|
2339
|
+
"""
|
|
2340
|
+
def __init__(self, x,easing=None,axis=None, *args, **kwargs):
|
|
2341
|
+
self.mpl_obj_type = mpl.lines.Line2D
|
|
2342
|
+
self.mpl_plot_type = plt.axvline
|
|
2343
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2344
|
+
self.x = x
|
|
2345
|
+
|
|
2346
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2347
|
+
if 'ymax' in kwargs:
|
|
2348
|
+
kwargs['ymax'] = kwargs['ymax'][0]
|
|
2349
|
+
if 'ymin' in kwargs:
|
|
2350
|
+
kwargs['ymin'] = kwargs['ymin'][0]
|
|
2351
|
+
|
|
2352
|
+
if len(data_x) > 0:
|
|
2353
|
+
self.obj = [self.axis.axvline(data_x,**kwargs)]
|
|
2354
|
+
|
|
2355
|
+
class axhline(Animation):
|
|
2356
|
+
"""
|
|
2357
|
+
Add a horizontal line spanning the whole or fraction of the Axes.
|
|
2358
|
+
|
|
2359
|
+
Note: If you want to set x-limits in data coordinates, use
|
|
2360
|
+
`~.Axes.hlines` instead.
|
|
2361
|
+
|
|
2362
|
+
Parameters
|
|
2363
|
+
----------
|
|
2364
|
+
y : float, default: 0
|
|
2365
|
+
y position in :ref:`data coordinates <coordinate-systems>`.
|
|
2366
|
+
|
|
2367
|
+
xmin : float, default: 0
|
|
2368
|
+
The start x-position in :ref:`axes coordinates <coordinate-systems>`.
|
|
2369
|
+
Should be between 0 and 1, 0 being the far left of the plot,
|
|
2370
|
+
1 the far right of the plot.
|
|
2371
|
+
|
|
2372
|
+
xmax : float, default: 1
|
|
2373
|
+
The end x-position in :ref:`axes coordinates <coordinate-systems>`.
|
|
2374
|
+
Should be between 0 and 1, 0 being the far left of the plot,
|
|
2375
|
+
1 the far right of the plot.
|
|
2376
|
+
|
|
2377
|
+
Returns
|
|
2378
|
+
-------
|
|
2379
|
+
`~matplotlib.lines.Line2D`
|
|
2380
|
+
A `.Line2D` specified via two points ``(xmin, y)``, ``(xmax, y)``.
|
|
2381
|
+
Its transform is set such that *x* is in
|
|
2382
|
+
:ref:`axes coordinates <coordinate-systems>` and *y* is in
|
|
2383
|
+
:ref:`data coordinates <coordinate-systems>`.
|
|
2384
|
+
|
|
2385
|
+
This is still a generic line and the horizontal character is only
|
|
2386
|
+
realized through using identical *y* values for both points. Thus,
|
|
2387
|
+
if you want to change the *y* value later, you have to provide two
|
|
2388
|
+
values ``line.set_ydata([3, 3])``.
|
|
2389
|
+
|
|
2390
|
+
Other Parameters
|
|
2391
|
+
----------------
|
|
2392
|
+
**kwargs
|
|
2393
|
+
Valid keyword arguments are `.Line2D` properties, except for
|
|
2394
|
+
'transform':
|
|
2395
|
+
|
|
2396
|
+
%(Line2D:kwdoc)s
|
|
2397
|
+
|
|
2398
|
+
See Also
|
|
2399
|
+
--------
|
|
2400
|
+
hlines : Add horizontal lines in data coordinates.
|
|
2401
|
+
axhspan : Add a horizontal span (rectangle) across the axis.
|
|
2402
|
+
axline : Add a line with an arbitrary slope.
|
|
2403
|
+
|
|
2404
|
+
Examples
|
|
2405
|
+
--------
|
|
2406
|
+
* draw a thick red hline at 'y' = 0 that spans the xrange::
|
|
2407
|
+
|
|
2408
|
+
>>> axhline(linewidth=4, color='r')
|
|
2409
|
+
|
|
2410
|
+
* draw a default hline at 'y' = 1 that spans the xrange::
|
|
2411
|
+
|
|
2412
|
+
>>> axhline(y=1)
|
|
2413
|
+
|
|
2414
|
+
* draw a default hline at 'y' = .5 that spans the middle half of
|
|
2415
|
+
the xrange::
|
|
2416
|
+
|
|
2417
|
+
>>> axhline(y=.5, xmin=0.25, xmax=0.75)
|
|
2418
|
+
"""
|
|
2419
|
+
def __init__(self, y,easing=None,axis=None, *args, **kwargs):
|
|
2420
|
+
self.mpl_obj_type = mpl.lines.Line2D
|
|
2421
|
+
self.mpl_plot_type = plt.axvline
|
|
2422
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2423
|
+
self.x = y
|
|
2424
|
+
|
|
2425
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2426
|
+
if 'xmax' in kwargs:
|
|
2427
|
+
kwargs['xmax'] = kwargs['xmax'][0]
|
|
2428
|
+
if 'xmin' in kwargs:
|
|
2429
|
+
kwargs['xmin'] = kwargs['xmin'][0]
|
|
2430
|
+
if len(data_x) > 0:
|
|
2431
|
+
self.obj = [self.axis.axhline(data_x,**kwargs)]
|
|
2432
|
+
|
|
2433
|
+
class errorbar(Animation):
|
|
2434
|
+
"""
|
|
2435
|
+
Plot y versus x as lines and/or markers with attached errorbars.
|
|
2436
|
+
|
|
2437
|
+
*x*, *y* define the data locations, *xerr*, *yerr* define the errorbar
|
|
2438
|
+
sizes. By default, this draws the data markers/lines as well as the
|
|
2439
|
+
errorbars. Use fmt='none' to draw errorbars without any data markers.
|
|
2440
|
+
|
|
2441
|
+
.. versionadded:: 3.7
|
|
2442
|
+
Caps and error lines are drawn in polar coordinates on polar plots.
|
|
2443
|
+
|
|
2444
|
+
|
|
2445
|
+
Parameters
|
|
2446
|
+
----------
|
|
2447
|
+
x, y : float or array-like
|
|
2448
|
+
The data positions.
|
|
2449
|
+
|
|
2450
|
+
duration : float
|
|
2451
|
+
Duration of the animation
|
|
2452
|
+
delay : float, default=0
|
|
2453
|
+
Delay before starting
|
|
2454
|
+
easing : callable, optional
|
|
2455
|
+
Easing function
|
|
2456
|
+
axis : matplotlib.axes.Axes, optional
|
|
2457
|
+
Axis to plot on
|
|
2458
|
+
|
|
2459
|
+
|
|
2460
|
+
xerr, yerr : float or array-like, shape(N,) or shape(2, N), optional
|
|
2461
|
+
The errorbar sizes:
|
|
2462
|
+
|
|
2463
|
+
- scalar: Symmetric +/- values for all data points.
|
|
2464
|
+
- shape(N,): Symmetric +/-values for each data point.
|
|
2465
|
+
- shape(2, N): Separate - and + values for each bar. First row
|
|
2466
|
+
contains the lower errors, the second row contains the upper
|
|
2467
|
+
errors.
|
|
2468
|
+
- *None*: No errorbar.
|
|
2469
|
+
|
|
2470
|
+
All values must be >= 0.
|
|
2471
|
+
|
|
2472
|
+
fmt : str, default: ''
|
|
2473
|
+
The format for the data points / data lines. See `.plot` for
|
|
2474
|
+
details.
|
|
2475
|
+
|
|
2476
|
+
Use 'none' (case-insensitive) to plot errorbars without any data
|
|
2477
|
+
markers.
|
|
2478
|
+
|
|
2479
|
+
ecolor : color, default: None
|
|
2480
|
+
The color of the errorbar lines. If None, use the color of the
|
|
2481
|
+
line connecting the markers.
|
|
2482
|
+
|
|
2483
|
+
elinewidth : float, default: None
|
|
2484
|
+
The linewidth of the errorbar lines. If None, the linewidth of
|
|
2485
|
+
the current style is used.
|
|
2486
|
+
|
|
2487
|
+
capsize : float, default: errorbar.capsize
|
|
2488
|
+
The length of the error bar caps in points.
|
|
2489
|
+
|
|
2490
|
+
capthick : float, default: None
|
|
2491
|
+
An alias to the keyword argument *markeredgewidth* (a.k.a. *mew*).
|
|
2492
|
+
This setting is a more sensible name for the property that
|
|
2493
|
+
controls the thickness of the error bar cap in points. For
|
|
2494
|
+
backwards compatibility, if *mew* or *markeredgewidth* are given,
|
|
2495
|
+
then they will over-ride *capthick*. This may change in future
|
|
2496
|
+
releases.
|
|
2497
|
+
|
|
2498
|
+
barsabove : bool, default: False
|
|
2499
|
+
If True, will plot the errorbars above the plot
|
|
2500
|
+
symbols. Default is below.
|
|
2501
|
+
|
|
2502
|
+
lolims, uplims, xlolims, xuplims : bool or array-like, default: False
|
|
2503
|
+
These arguments can be used to indicate that a value gives only
|
|
2504
|
+
upper/lower limits. In that case a caret symbol is used to
|
|
2505
|
+
indicate this. *lims*-arguments may be scalars, or array-likes of
|
|
2506
|
+
the same length as *xerr* and *yerr*. To use limits with inverted
|
|
2507
|
+
axes, `~.Axes.set_xlim` or `~.Axes.set_ylim` must be called before
|
|
2508
|
+
:meth:`errorbar`. Note the tricky parameter names: setting e.g.
|
|
2509
|
+
*lolims* to True means that the y-value is a *lower* limit of the
|
|
2510
|
+
True value, so, only an *upward*-pointing arrow will be drawn!
|
|
2511
|
+
|
|
2512
|
+
errorevery : int or (int, int), default: 1
|
|
2513
|
+
draws error bars on a subset of the data. *errorevery* =N draws
|
|
2514
|
+
error bars on the points (x[::N], y[::N]).
|
|
2515
|
+
*errorevery* =(start, N) draws error bars on the points
|
|
2516
|
+
(x[start::N], y[start::N]). e.g. errorevery=(6, 3)
|
|
2517
|
+
adds error bars to the data at (x[6], x[9], x[12], x[15], ...).
|
|
2518
|
+
Used to avoid overlapping error bars when two series share x-axis
|
|
2519
|
+
values.
|
|
2520
|
+
|
|
2521
|
+
Returns
|
|
2522
|
+
-------
|
|
2523
|
+
`.ErrorbarContainer`
|
|
2524
|
+
The container contains:
|
|
2525
|
+
|
|
2526
|
+
- data_line : A `~matplotlib.lines.Line2D` instance of x, y plot markers
|
|
2527
|
+
and/or line.
|
|
2528
|
+
- caplines : A tuple of `~matplotlib.lines.Line2D` instances of the error
|
|
2529
|
+
bar caps.
|
|
2530
|
+
- barlinecols : A tuple of `.LineCollection` with the horizontal and
|
|
2531
|
+
vertical error ranges.
|
|
2532
|
+
|
|
2533
|
+
Other Parameters
|
|
2534
|
+
----------------
|
|
2535
|
+
data : indexable object, optional
|
|
2536
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
2537
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
2538
|
+
|
|
2539
|
+
*x*, *y*, *xerr*, *yerr*
|
|
2540
|
+
|
|
2541
|
+
**kwargs
|
|
2542
|
+
All other keyword arguments are passed on to the `~.Axes.plot` call
|
|
2543
|
+
drawing the markers. For example, this code makes big red squares
|
|
2544
|
+
with thick green edges::
|
|
2545
|
+
|
|
2546
|
+
x, y, yerr = rand(3, 10)
|
|
2547
|
+
errorbar(x, y, yerr, marker='s', mfc='red',
|
|
2548
|
+
mec='green', ms=20, mew=4)
|
|
2549
|
+
|
|
2550
|
+
where *mfc*, *mec*, *ms* and *mew* are aliases for the longer
|
|
2551
|
+
property names, *markerfacecolor*, *markeredgecolor*, *markersize*
|
|
2552
|
+
and *markeredgewidth*.
|
|
2553
|
+
|
|
2554
|
+
Valid kwargs for the marker properties are:
|
|
2555
|
+
|
|
2556
|
+
- *dashes*
|
|
2557
|
+
- *dash_capstyle*
|
|
2558
|
+
- *dash_joinstyle*
|
|
2559
|
+
- *drawstyle*
|
|
2560
|
+
- *fillstyle*
|
|
2561
|
+
- *linestyle*
|
|
2562
|
+
- *marker*
|
|
2563
|
+
- *markeredgecolor*
|
|
2564
|
+
- *markeredgewidth*
|
|
2565
|
+
- *markerfacecolor*
|
|
2566
|
+
- *markerfacecoloralt*
|
|
2567
|
+
- *markersize*
|
|
2568
|
+
- *markevery*
|
|
2569
|
+
- *solid_capstyle*
|
|
2570
|
+
- *solid_joinstyle*
|
|
2571
|
+
|
|
2572
|
+
Refer to the corresponding `.Line2D` property for more details:
|
|
2573
|
+
|
|
2574
|
+
Properties:
|
|
2575
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
2576
|
+
alpha: float or None
|
|
2577
|
+
animated: bool
|
|
2578
|
+
antialiased or aa: bool
|
|
2579
|
+
clip_box: `~matplotlib.transforms.BboxBase` or None
|
|
2580
|
+
clip_on: bool
|
|
2581
|
+
clip_path: Patch or (Path, Transform) or None
|
|
2582
|
+
color or c: color
|
|
2583
|
+
dash_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
2584
|
+
dash_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
2585
|
+
dashes: sequence of floats (on/off ink in points) or (None, None)
|
|
2586
|
+
data: (2, N) array or two 1D arrays
|
|
2587
|
+
drawstyle or ds: {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}, default: 'default'
|
|
2588
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
2589
|
+
fillstyle: {'full', 'left', 'right', 'bottom', 'top', 'none'}
|
|
2590
|
+
gapcolor: color or None
|
|
2591
|
+
gid: str
|
|
2592
|
+
in_layout: bool
|
|
2593
|
+
label: object
|
|
2594
|
+
linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
|
|
2595
|
+
linewidth or lw: float
|
|
2596
|
+
marker: marker style string, `~.path.Path` or `~.markers.MarkerStyle`
|
|
2597
|
+
markeredgecolor or mec: color
|
|
2598
|
+
markeredgewidth or mew: float
|
|
2599
|
+
markerfacecolor or mfc: color
|
|
2600
|
+
markerfacecoloralt or mfcalt: color
|
|
2601
|
+
markersize or ms: float
|
|
2602
|
+
markevery: None or int or (int, int) or slice or list[int] or float or (float, float) or list[bool]
|
|
2603
|
+
mouseover: bool
|
|
2604
|
+
path_effects: list of `.AbstractPathEffect`
|
|
2605
|
+
picker: float or callable[[Artist, Event], tuple[bool, dict]]
|
|
2606
|
+
pickradius: float
|
|
2607
|
+
rasterized: bool
|
|
2608
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
2609
|
+
snap: bool or None
|
|
2610
|
+
solid_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}
|
|
2611
|
+
solid_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}
|
|
2612
|
+
transform: unknown
|
|
2613
|
+
url: str
|
|
2614
|
+
visible: bool
|
|
2615
|
+
xdata: 1D array
|
|
2616
|
+
ydata: 1D array
|
|
2617
|
+
zorder: float
|
|
2618
|
+
|
|
2619
|
+
Notes
|
|
2620
|
+
-----
|
|
2621
|
+
|
|
2622
|
+
.. note::
|
|
2623
|
+
|
|
2624
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.errorbar`.
|
|
2625
|
+
"""
|
|
2626
|
+
def __init__(self,x,y,xerr=None,yerr=None,easing=None,axis=None, *args, **kwargs):
|
|
2627
|
+
self.mpl_obj_type = mpl.lines.Line2D
|
|
2628
|
+
self.mpl_plot_type = plt.axvline
|
|
2629
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2630
|
+
self.x = x
|
|
2631
|
+
self.y = y
|
|
2632
|
+
if xerr is None:
|
|
2633
|
+
xerr = np.zeros_like(x)
|
|
2634
|
+
if yerr is None:
|
|
2635
|
+
yerr = np.zeros_like(y)
|
|
2636
|
+
self.xerr = xerr
|
|
2637
|
+
self.yerr = yerr
|
|
2638
|
+
|
|
2639
|
+
def morph(self,new_x,new_y,duration,new_xerr=None,new_yerr=None,delay=0,easing=None,persistent=True):
|
|
2640
|
+
if new_xerr is None:
|
|
2641
|
+
new_xerr = self.xerr
|
|
2642
|
+
if new_yerr is None:
|
|
2643
|
+
new_yerr = self.yerr
|
|
2644
|
+
if isinstance(new_x,numbers.Number):
|
|
2645
|
+
new_x = [new_x]
|
|
2646
|
+
new_y = [new_y]
|
|
2647
|
+
new_xerr = [new_xerr]
|
|
2648
|
+
new_yerr = [new_yerr]
|
|
2649
|
+
|
|
2650
|
+
self.anims.append({
|
|
2651
|
+
'name':'morph',
|
|
2652
|
+
'duration':duration,
|
|
2653
|
+
'delay':delay,
|
|
2654
|
+
'easing':easing,
|
|
2655
|
+
'new_x':new_x,
|
|
2656
|
+
'new_y':new_y,
|
|
2657
|
+
'new_x_err':new_xerr,
|
|
2658
|
+
'new_y_err':new_yerr,
|
|
2659
|
+
'persistent':persistent,
|
|
2660
|
+
'played':False
|
|
2661
|
+
})
|
|
2662
|
+
self.compute_timings()
|
|
2663
|
+
return self
|
|
2664
|
+
|
|
2665
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2666
|
+
obj = self.axis.errorbar(data_x,data_y,**kwargs)
|
|
2667
|
+
obj = [obj.lines[0]] + list(obj.lines[1]) + list(obj.lines[2])
|
|
2668
|
+
self.obj = obj
|
|
2669
|
+
|
|
2670
|
+
class hist(Animation):
|
|
2671
|
+
"""
|
|
2672
|
+
Compute and plot a histogram.
|
|
2673
|
+
|
|
2674
|
+
This method uses `numpy.histogram` to bin the data in *x* and count the
|
|
2675
|
+
number of values in each bin, then draws the distribution either as a
|
|
2676
|
+
`.BarContainer` or `.Polygon`. The *bins*, *range*, *density*, and
|
|
2677
|
+
*weights* parameters are forwarded to `numpy.histogram`.
|
|
2678
|
+
|
|
2679
|
+
If the data has already been binned and counted, use `~.bar` or
|
|
2680
|
+
`~.stairs` to plot the distribution::
|
|
2681
|
+
|
|
2682
|
+
counts, bins = np.histogram(x)
|
|
2683
|
+
plt.stairs(counts, bins)
|
|
2684
|
+
|
|
2685
|
+
Alternatively, plot pre-computed bins and counts using ``hist()`` by
|
|
2686
|
+
treating each bin as a single point with a weight equal to its count::
|
|
2687
|
+
|
|
2688
|
+
plt.hist(bins[:-1], bins, weights=counts)
|
|
2689
|
+
|
|
2690
|
+
The data input *x* can be a singular array, a list of datasets of
|
|
2691
|
+
potentially different lengths ([*x0*, *x1*, ...]), or a 2D ndarray in
|
|
2692
|
+
which each column is a dataset. Note that the ndarray form is
|
|
2693
|
+
transposed relative to the list form. If the input is an array, then
|
|
2694
|
+
the return value is a tuple (*n*, *bins*, *patches*); if the input is a
|
|
2695
|
+
sequence of arrays, then the return value is a tuple
|
|
2696
|
+
([*n0*, *n1*, ...], *bins*, [*patches0*, *patches1*, ...]).
|
|
2697
|
+
|
|
2698
|
+
Masked arrays are not supported.
|
|
2699
|
+
|
|
2700
|
+
Parameters
|
|
2701
|
+
----------
|
|
2702
|
+
x : (n,) array or sequence of (n,) arrays
|
|
2703
|
+
Input values, this takes either a single array or a sequence of
|
|
2704
|
+
arrays which are not required to be of the same length.
|
|
2705
|
+
|
|
2706
|
+
duration : float
|
|
2707
|
+
Duration of the animation
|
|
2708
|
+
delay : float, default=0
|
|
2709
|
+
Delay before starting
|
|
2710
|
+
easing : callable, optional
|
|
2711
|
+
Easing function
|
|
2712
|
+
axis : matplotlib.axes.Axes, optional
|
|
2713
|
+
Axis to plot on
|
|
2714
|
+
|
|
2715
|
+
|
|
2716
|
+
bins : int or sequence or str, default: hist.bins
|
|
2717
|
+
If *bins* is an integer, it defines the number of equal-width bins
|
|
2718
|
+
in the range.
|
|
2719
|
+
|
|
2720
|
+
If *bins* is a sequence, it defines the bin edges, including the
|
|
2721
|
+
left edge of the first bin and the right edge of the last bin;
|
|
2722
|
+
in this case, bins may be unequally spaced. All but the last
|
|
2723
|
+
(righthand-most) bin is half-open. In other words, if *bins* is::
|
|
2724
|
+
|
|
2725
|
+
[1, 2, 3, 4]
|
|
2726
|
+
|
|
2727
|
+
then the first bin is ``[1, 2)`` (including 1, but excluding 2) and
|
|
2728
|
+
the second ``[2, 3)``. The last bin, however, is ``[3, 4]``, which
|
|
2729
|
+
*includes* 4.
|
|
2730
|
+
|
|
2731
|
+
If *bins* is a string, it is one of the binning strategies
|
|
2732
|
+
supported by `numpy.histogram_bin_edges`: 'auto', 'fd', 'doane',
|
|
2733
|
+
'scott', 'stone', 'rice', 'sturges', or 'sqrt'.
|
|
2734
|
+
|
|
2735
|
+
range : tuple or None, default: None
|
|
2736
|
+
The lower and upper range of the bins. Lower and upper outliers
|
|
2737
|
+
are ignored. If not provided, *range* is ``(x.min(), x.max())``.
|
|
2738
|
+
Range has no effect if *bins* is a sequence.
|
|
2739
|
+
|
|
2740
|
+
If *bins* is a sequence or *range* is specified, autoscaling
|
|
2741
|
+
is based on the specified bin range instead of the
|
|
2742
|
+
range of x.
|
|
2743
|
+
|
|
2744
|
+
density : bool, default: False
|
|
2745
|
+
If ``True``, draw and return a probability density: each bin
|
|
2746
|
+
will display the bin's raw count divided by the total number of
|
|
2747
|
+
counts *and the bin width*
|
|
2748
|
+
(``density = counts / (sum(counts) * np.diff(bins))``),
|
|
2749
|
+
so that the area under the histogram integrates to 1
|
|
2750
|
+
(``np.sum(density * np.diff(bins)) == 1``).
|
|
2751
|
+
|
|
2752
|
+
If *stacked* is also ``True``, the sum of the histograms is
|
|
2753
|
+
normalized to 1.
|
|
2754
|
+
|
|
2755
|
+
weights : (n,) array-like or None, default: None
|
|
2756
|
+
An array of weights, of the same shape as *x*. Each value in
|
|
2757
|
+
*x* only contributes its associated weight towards the bin count
|
|
2758
|
+
(instead of 1). If *density* is ``True``, the weights are
|
|
2759
|
+
normalized, so that the integral of the density over the range
|
|
2760
|
+
remains 1.
|
|
2761
|
+
|
|
2762
|
+
cumulative : bool or -1, default: False
|
|
2763
|
+
If ``True``, then a histogram is computed where each bin gives the
|
|
2764
|
+
counts in that bin plus all bins for smaller values. The last bin
|
|
2765
|
+
gives the total number of datapoints.
|
|
2766
|
+
|
|
2767
|
+
If *density* is also ``True`` then the histogram is normalized such
|
|
2768
|
+
that the last bin equals 1.
|
|
2769
|
+
|
|
2770
|
+
If *cumulative* is a number less than 0 (e.g., -1), the direction
|
|
2771
|
+
of accumulation is reversed. In this case, if *density* is also
|
|
2772
|
+
``True``, then the histogram is normalized such that the first bin
|
|
2773
|
+
equals 1.
|
|
2774
|
+
|
|
2775
|
+
bottom : array-like or float, default: 0
|
|
2776
|
+
Location of the bottom of each bin, i.e. bins are drawn from
|
|
2777
|
+
``bottom`` to ``bottom + hist(x, bins)`` If a scalar, the bottom
|
|
2778
|
+
of each bin is shifted by the same amount. If an array, each bin
|
|
2779
|
+
is shifted independently and the length of bottom must match the
|
|
2780
|
+
number of bins. If None, defaults to 0.
|
|
2781
|
+
|
|
2782
|
+
histtype : {'bar', 'barstacked', 'step', 'stepfilled'}, default: 'bar'
|
|
2783
|
+
The type of histogram to draw.
|
|
2784
|
+
|
|
2785
|
+
- 'bar' is a traditional bar-type histogram. If multiple data
|
|
2786
|
+
are given the bars are arranged side by side.
|
|
2787
|
+
- 'barstacked' is a bar-type histogram where multiple
|
|
2788
|
+
data are stacked on top of each other.
|
|
2789
|
+
- 'step' generates a lineplot that is by default unfilled.
|
|
2790
|
+
- 'stepfilled' generates a lineplot that is by default filled.
|
|
2791
|
+
|
|
2792
|
+
align : {'left', 'mid', 'right'}, default: 'mid'
|
|
2793
|
+
The horizontal alignment of the histogram bars.
|
|
2794
|
+
|
|
2795
|
+
- 'left': bars are centered on the left bin edges.
|
|
2796
|
+
- 'mid': bars are centered between the bin edges.
|
|
2797
|
+
- 'right': bars are centered on the right bin edges.
|
|
2798
|
+
|
|
2799
|
+
orientation : {'vertical', 'horizontal'}, default: 'vertical'
|
|
2800
|
+
If 'horizontal', `~.Axes.barh` will be used for bar-type histograms
|
|
2801
|
+
and the *bottom* kwarg will be the left edges.
|
|
2802
|
+
|
|
2803
|
+
rwidth : float or None, default: None
|
|
2804
|
+
The relative width of the bars as a fraction of the bin width. If
|
|
2805
|
+
``None``, automatically compute the width.
|
|
2806
|
+
|
|
2807
|
+
Ignored if *histtype* is 'step' or 'stepfilled'.
|
|
2808
|
+
|
|
2809
|
+
log : bool, default: False
|
|
2810
|
+
If ``True``, the histogram axis will be set to a log scale.
|
|
2811
|
+
|
|
2812
|
+
color : color or list of color or None, default: None
|
|
2813
|
+
Color or sequence of colors, one per dataset. Default (``None``)
|
|
2814
|
+
uses the standard line color sequence.
|
|
2815
|
+
|
|
2816
|
+
label : str or list of str, optional
|
|
2817
|
+
String, or sequence of strings to match multiple datasets. Bar
|
|
2818
|
+
charts yield multiple patches per dataset, but only the first gets
|
|
2819
|
+
the label, so that `~.Axes.legend` will work as expected.
|
|
2820
|
+
|
|
2821
|
+
stacked : bool, default: False
|
|
2822
|
+
If ``True``, multiple data are stacked on top of each other If
|
|
2823
|
+
``False`` multiple data are arranged side by side if histtype is
|
|
2824
|
+
'bar' or on top of each other if histtype is 'step'
|
|
2825
|
+
|
|
2826
|
+
Returns
|
|
2827
|
+
-------
|
|
2828
|
+
n : array or list of arrays
|
|
2829
|
+
The values of the histogram bins. See *density* and *weights* for a
|
|
2830
|
+
description of the possible semantics. If input *x* is an array,
|
|
2831
|
+
then this is an array of length *nbins*. If input is a sequence of
|
|
2832
|
+
arrays ``[data1, data2, ...]``, then this is a list of arrays with
|
|
2833
|
+
the values of the histograms for each of the arrays in the same
|
|
2834
|
+
order. The dtype of the array *n* (or of its element arrays) will
|
|
2835
|
+
always be float even if no weighting or normalization is used.
|
|
2836
|
+
|
|
2837
|
+
bins : array
|
|
2838
|
+
The edges of the bins. Length nbins + 1 (nbins left edges and right
|
|
2839
|
+
edge of last bin). Always a single array even when multiple data
|
|
2840
|
+
sets are passed in.
|
|
2841
|
+
|
|
2842
|
+
patches : `.BarContainer` or list of a single `.Polygon` or list of such objects
|
|
2843
|
+
Container of individual artists used to create the histogram
|
|
2844
|
+
or list of such containers if there are multiple input datasets.
|
|
2845
|
+
|
|
2846
|
+
Other Parameters
|
|
2847
|
+
----------------
|
|
2848
|
+
data : indexable object, optional
|
|
2849
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
2850
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
2851
|
+
|
|
2852
|
+
*x*, *weights*
|
|
2853
|
+
|
|
2854
|
+
**kwargs
|
|
2855
|
+
`~matplotlib.patches.Patch` properties. The following properties
|
|
2856
|
+
additionally accept a sequence of values corresponding to the
|
|
2857
|
+
datasets in *x*:
|
|
2858
|
+
*edgecolor*, *facecolor*, *linewidth*, *linestyle*, *hatch*.
|
|
2859
|
+
|
|
2860
|
+
.. versionadded:: 3.10
|
|
2861
|
+
Allowing sequences of values in above listed Patch properties.
|
|
2862
|
+
|
|
2863
|
+
See Also
|
|
2864
|
+
--------
|
|
2865
|
+
hist2d : 2D histogram with rectangular bins
|
|
2866
|
+
hexbin : 2D histogram with hexagonal bins
|
|
2867
|
+
stairs : Plot a pre-computed histogram
|
|
2868
|
+
bar : Plot a pre-computed histogram
|
|
2869
|
+
|
|
2870
|
+
Notes
|
|
2871
|
+
-----
|
|
2872
|
+
|
|
2873
|
+
.. note::
|
|
2874
|
+
|
|
2875
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.hist`.
|
|
2876
|
+
|
|
2877
|
+
For large numbers of bins (>1000), plotting can be significantly
|
|
2878
|
+
accelerated by using `~.Axes.stairs` to plot a pre-computed histogram
|
|
2879
|
+
(``plt.stairs(*np.histogram(data))``), or by setting *histtype* to
|
|
2880
|
+
'step' or 'stepfilled' rather than 'bar' or 'barstacked'.
|
|
2881
|
+
"""
|
|
2882
|
+
def __init__(self,x,easing=None,axis=None, *args, **kwargs):
|
|
2883
|
+
self.mpl_obj_type = mpl.patches.Rectangle
|
|
2884
|
+
self.mpl_plot_type = plt.hist
|
|
2885
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
2886
|
+
self.x = to_np_array(x)
|
|
2887
|
+
self.y = np.zeros_like(self.x)
|
|
2888
|
+
|
|
2889
|
+
def clean(self,x,clear_anims=True):
|
|
2890
|
+
if self.obj is not None and self.base_color is None:
|
|
2891
|
+
self.base_color = self.obj[0].get_facecolor()
|
|
2892
|
+
if 'color' not in self.kwargs:
|
|
2893
|
+
self.kwargs['color'] = self.base_color
|
|
2894
|
+
super().clean(x,clear_anims)
|
|
2895
|
+
|
|
2896
|
+
def morph(self,new_x,duration,delay=0,easing=None,persistent=True,**kwargs):
|
|
2897
|
+
if isinstance(new_x,numbers.Number):
|
|
2898
|
+
new_x = [new_x]
|
|
2899
|
+
|
|
2900
|
+
self.anims.append({
|
|
2901
|
+
'name':'morph',
|
|
2902
|
+
'duration':duration,
|
|
2903
|
+
'delay':delay,
|
|
2904
|
+
'easing':easing,
|
|
2905
|
+
'new_x':new_x,
|
|
2906
|
+
'new_y':np.zeros_like(self.y),
|
|
2907
|
+
'persistent':persistent,
|
|
2908
|
+
'played':False
|
|
2909
|
+
})
|
|
2910
|
+
self.compute_timings()
|
|
2911
|
+
return self
|
|
2912
|
+
|
|
2913
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
2914
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
2915
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
2916
|
+
|
|
2917
|
+
if 'bins' in kwargs:
|
|
2918
|
+
kwargs['bins'] = to_np_array(kwargs['bins'])
|
|
2919
|
+
|
|
2920
|
+
if 'bins' in kwargs and len(kwargs['bins']) == 1:
|
|
2921
|
+
kwargs['bins'] = int(kwargs['bins'][0])
|
|
2922
|
+
|
|
2923
|
+
h,edges,self.obj = self.axis.hist(data_x,**kwargs)
|
|
2924
|
+
|
|
2925
|
+
class hist2d(Animation):
|
|
2926
|
+
"""
|
|
2927
|
+
Make a 2D histogram plot.
|
|
2928
|
+
|
|
2929
|
+
Parameters
|
|
2930
|
+
----------
|
|
2931
|
+
x, y : array-like, shape (n, )
|
|
2932
|
+
Input values
|
|
2933
|
+
|
|
2934
|
+
duration : float
|
|
2935
|
+
Duration of the animation
|
|
2936
|
+
delay : float, default=0
|
|
2937
|
+
Delay before starting
|
|
2938
|
+
easing : callable, optional
|
|
2939
|
+
Easing function
|
|
2940
|
+
axis : matplotlib.axes.Axes, optional
|
|
2941
|
+
Axis to plot on
|
|
2942
|
+
|
|
2943
|
+
|
|
2944
|
+
bins : None or int or [int, int] or array-like or [array, array]
|
|
2945
|
+
|
|
2946
|
+
The bin specification:
|
|
2947
|
+
|
|
2948
|
+
- If int, the number of bins for the two dimensions
|
|
2949
|
+
(``nx = ny = bins``).
|
|
2950
|
+
- If ``[int, int]``, the number of bins in each dimension
|
|
2951
|
+
(``nx, ny = bins``).
|
|
2952
|
+
- If array-like, the bin edges for the two dimensions
|
|
2953
|
+
(``x_edges = y_edges = bins``).
|
|
2954
|
+
- If ``[array, array]``, the bin edges in each dimension
|
|
2955
|
+
(``x_edges, y_edges = bins``).
|
|
2956
|
+
|
|
2957
|
+
The default value is 10.
|
|
2958
|
+
|
|
2959
|
+
range : array-like shape(2, 2), optional
|
|
2960
|
+
The leftmost and rightmost edges of the bins along each dimension
|
|
2961
|
+
(if not specified explicitly in the bins parameters): ``[[xmin,
|
|
2962
|
+
xmax], [ymin, ymax]]``. All values outside of this range will be
|
|
2963
|
+
considered outliers and not tallied in the histogram.
|
|
2964
|
+
|
|
2965
|
+
density : bool, default: False
|
|
2966
|
+
Normalize histogram. See the documentation for the *density*
|
|
2967
|
+
parameter of `~.Axes.hist` for more details.
|
|
2968
|
+
|
|
2969
|
+
weights : array-like, shape (n, ), optional
|
|
2970
|
+
An array of values w_i weighing each sample (x_i, y_i).
|
|
2971
|
+
|
|
2972
|
+
cmin, cmax : float, default: None
|
|
2973
|
+
All bins that has count less than *cmin* or more than *cmax* will not be
|
|
2974
|
+
displayed (set to NaN before passing to `~.Axes.pcolormesh`) and these count
|
|
2975
|
+
values in the return value count histogram will also be set to nan upon
|
|
2976
|
+
return.
|
|
2977
|
+
|
|
2978
|
+
Returns
|
|
2979
|
+
-------
|
|
2980
|
+
h : 2D array
|
|
2981
|
+
The bi-dimensional histogram of samples x and y. Values in x are
|
|
2982
|
+
histogrammed along the first dimension and values in y are
|
|
2983
|
+
histogrammed along the second dimension.
|
|
2984
|
+
xedges : 1D array
|
|
2985
|
+
The bin edges along the x-axis.
|
|
2986
|
+
yedges : 1D array
|
|
2987
|
+
The bin edges along the y-axis.
|
|
2988
|
+
image : `~.matplotlib.collections.QuadMesh`
|
|
2989
|
+
|
|
2990
|
+
Other Parameters
|
|
2991
|
+
----------------
|
|
2992
|
+
cmap : str or `~matplotlib.colors.Colormap`, default: image.cmap
|
|
2993
|
+
The Colormap instance or registered colormap name used to map scalar data
|
|
2994
|
+
to colors.
|
|
2995
|
+
|
|
2996
|
+
norm : str or `~matplotlib.colors.Normalize`, optional
|
|
2997
|
+
The normalization method used to scale scalar data to the [0, 1] range
|
|
2998
|
+
before mapping to colors using *cmap*. By default, a linear scaling is
|
|
2999
|
+
used, mapping the lowest value to 0 and the highest to 1.
|
|
3000
|
+
|
|
3001
|
+
If given, this can be one of the following:
|
|
3002
|
+
|
|
3003
|
+
- An instance of `.Normalize` or one of its subclasses
|
|
3004
|
+
(see :ref:`colormapnorms`).
|
|
3005
|
+
- A scale name, i.e. one of "linear", "log", "symlog", "logit", etc. For a
|
|
3006
|
+
list of available scales, call `matplotlib.scale.get_scale_names()`.
|
|
3007
|
+
In that case, a suitable `.Normalize` subclass is dynamically generated
|
|
3008
|
+
and instantiated.
|
|
3009
|
+
|
|
3010
|
+
vmin, vmax : float, optional
|
|
3011
|
+
When using scalar data and no explicit *norm*, *vmin* and *vmax* define
|
|
3012
|
+
the data range that the colormap covers. By default, the colormap covers
|
|
3013
|
+
the complete value range of the supplied data. It is an error to use
|
|
3014
|
+
*vmin*/*vmax* when a *norm* instance is given (but using a `str` *norm*
|
|
3015
|
+
name together with *vmin*/*vmax* is acceptable).
|
|
3016
|
+
|
|
3017
|
+
colorizer : `~matplotlib.colorizer.Colorizer` or None, default: None
|
|
3018
|
+
The Colorizer object used to map color to data. If None, a Colorizer
|
|
3019
|
+
object is created from a *norm* and *cmap*.
|
|
3020
|
+
|
|
3021
|
+
alpha : ``0 <= scalar <= 1`` or ``None``, optional
|
|
3022
|
+
The alpha blending value.
|
|
3023
|
+
|
|
3024
|
+
data : indexable object, optional
|
|
3025
|
+
If given, the following parameters also accept a string ``s``, which is
|
|
3026
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``:
|
|
3027
|
+
|
|
3028
|
+
*x*, *y*, *weights*
|
|
3029
|
+
|
|
3030
|
+
**kwargs
|
|
3031
|
+
Additional parameters are passed along to the
|
|
3032
|
+
`~.Axes.pcolormesh` method and `~matplotlib.collections.QuadMesh`
|
|
3033
|
+
constructor.
|
|
3034
|
+
|
|
3035
|
+
See Also
|
|
3036
|
+
--------
|
|
3037
|
+
hist : 1D histogram plotting
|
|
3038
|
+
hexbin : 2D histogram with hexagonal bins
|
|
3039
|
+
|
|
3040
|
+
Notes
|
|
3041
|
+
-----
|
|
3042
|
+
|
|
3043
|
+
.. note::
|
|
3044
|
+
|
|
3045
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.hist2d`.
|
|
3046
|
+
|
|
3047
|
+
- Currently ``hist2d`` calculates its own axis limits, and any limits
|
|
3048
|
+
previously set are ignored.
|
|
3049
|
+
- Rendering the histogram with a logarithmic color scale is
|
|
3050
|
+
accomplished by passing a `.colors.LogNorm` instance to the *norm*
|
|
3051
|
+
keyword argument. Likewise, power-law normalization (similar
|
|
3052
|
+
in effect to gamma correction) can be accomplished with
|
|
3053
|
+
`.colors.PowerNorm`.
|
|
3054
|
+
"""
|
|
3055
|
+
def __init__(self,x,y,easing=None,axis=None, *args, **kwargs):
|
|
3056
|
+
self.mpl_obj_type = mpl.collections.QuadMesh
|
|
3057
|
+
self.mpl_plot_type = plt.hist2d
|
|
3058
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
3059
|
+
self.x = to_np_array(x)
|
|
3060
|
+
self.y = to_np_array(y)
|
|
3061
|
+
|
|
3062
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
3063
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
3064
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
3065
|
+
|
|
3066
|
+
if 'bins' in kwargs:
|
|
3067
|
+
kwargs['bins'] = to_np_array(kwargs['bins'])
|
|
3068
|
+
|
|
3069
|
+
if 'bins' in kwargs and len(kwargs['bins']) == 1:
|
|
3070
|
+
kwargs['bins'] = int(kwargs['bins'][0])
|
|
3071
|
+
|
|
3072
|
+
if 'color' in kwargs:
|
|
3073
|
+
kwargs.pop('color')
|
|
3074
|
+
|
|
3075
|
+
#Have to reset xlim and ylim because hist2d does not respect the imposed limits
|
|
3076
|
+
old_xlim = self.axis.get_xlim()
|
|
3077
|
+
old_ylim = self.axis.get_ylim()
|
|
3078
|
+
h,xedges,yedges,self.obj = self.axis.hist2d(data_x,data_y,**kwargs)
|
|
3079
|
+
self.axis.set_xlim(old_xlim)
|
|
3080
|
+
self.axis.set_ylim(old_ylim)
|
|
3081
|
+
|
|
3082
|
+
class contourf(Animation):
|
|
3083
|
+
"""
|
|
3084
|
+
Plot filled contours.
|
|
3085
|
+
|
|
3086
|
+
Call signature::
|
|
3087
|
+
|
|
3088
|
+
contourf([X, Y,] Z, /, [levels], **kwargs)
|
|
3089
|
+
|
|
3090
|
+
The arguments *X*, *Y*, *Z* are positional-only.
|
|
3091
|
+
|
|
3092
|
+
`.contour` and `.contourf` draw contour lines and filled contours,
|
|
3093
|
+
respectively. Except as noted, function signatures and return values
|
|
3094
|
+
are the same for both versions.
|
|
3095
|
+
|
|
3096
|
+
Parameters
|
|
3097
|
+
----------
|
|
3098
|
+
X, Y : array-like, optional
|
|
3099
|
+
The coordinates of the values in *Z*.
|
|
3100
|
+
|
|
3101
|
+
duration : float
|
|
3102
|
+
Duration of the animation
|
|
3103
|
+
delay : float, default=0
|
|
3104
|
+
Delay before starting
|
|
3105
|
+
easing : callable, optional
|
|
3106
|
+
Easing function
|
|
3107
|
+
axis : matplotlib.axes.Axes, optional
|
|
3108
|
+
Axis to plot on
|
|
3109
|
+
|
|
3110
|
+
|
|
3111
|
+
*X* and *Y* must both be 2D with the same shape as *Z* (e.g.
|
|
3112
|
+
created via `numpy.meshgrid`), or they must both be 1-D such
|
|
3113
|
+
that ``len(X) == N`` is the number of columns in *Z* and
|
|
3114
|
+
``len(Y) == M`` is the number of rows in *Z*.
|
|
3115
|
+
|
|
3116
|
+
*X* and *Y* must both be ordered monotonically.
|
|
3117
|
+
|
|
3118
|
+
If not given, they are assumed to be integer indices, i.e.
|
|
3119
|
+
``X = range(N)``, ``Y = range(M)``.
|
|
3120
|
+
|
|
3121
|
+
Z : (M, N) array-like
|
|
3122
|
+
The height values over which the contour is drawn. Color-mapping is
|
|
3123
|
+
controlled by *cmap*, *norm*, *vmin*, and *vmax*.
|
|
3124
|
+
|
|
3125
|
+
levels : int or array-like, optional
|
|
3126
|
+
Determines the number and positions of the contour lines / regions.
|
|
3127
|
+
|
|
3128
|
+
If an int *n*, use `~matplotlib.ticker.MaxNLocator`, which tries
|
|
3129
|
+
to automatically choose no more than *n+1* "nice" contour levels
|
|
3130
|
+
between minimum and maximum numeric values of *Z*.
|
|
3131
|
+
|
|
3132
|
+
If array-like, draw contour lines at the specified levels.
|
|
3133
|
+
The values must be in increasing order.
|
|
3134
|
+
|
|
3135
|
+
Returns
|
|
3136
|
+
-------
|
|
3137
|
+
`~.contour.QuadContourSet`
|
|
3138
|
+
|
|
3139
|
+
Other Parameters
|
|
3140
|
+
----------------
|
|
3141
|
+
corner_mask : bool, default: contour.corner_mask
|
|
3142
|
+
Enable/disable corner masking, which only has an effect if *Z* is
|
|
3143
|
+
a masked array. If ``False``, any quad touching a masked point is
|
|
3144
|
+
masked out. If ``True``, only the triangular corners of quads
|
|
3145
|
+
nearest those points are always masked out, other triangular
|
|
3146
|
+
corners comprising three unmasked points are contoured as usual.
|
|
3147
|
+
|
|
3148
|
+
colors : color or list of color, optional
|
|
3149
|
+
The colors of the levels, i.e. the lines for `.contour` and the
|
|
3150
|
+
areas for `.contourf`.
|
|
3151
|
+
|
|
3152
|
+
The sequence is cycled for the levels in ascending order. If the
|
|
3153
|
+
sequence is shorter than the number of levels, it's repeated.
|
|
3154
|
+
|
|
3155
|
+
As a shortcut, a single color may be used in place of one-element lists, i.e.
|
|
3156
|
+
``'red'`` instead of ``['red']`` to color all levels with the same color.
|
|
3157
|
+
|
|
3158
|
+
.. versionchanged:: 3.10
|
|
3159
|
+
Previously a single color had to be expressed as a string, but now any
|
|
3160
|
+
valid color format may be passed.
|
|
3161
|
+
|
|
3162
|
+
By default (value *None*), the colormap specified by *cmap*
|
|
3163
|
+
will be used.
|
|
3164
|
+
|
|
3165
|
+
alpha : float, default: 1
|
|
3166
|
+
The alpha blending value, between 0 (transparent) and 1 (opaque).
|
|
3167
|
+
|
|
3168
|
+
cmap : str or `~matplotlib.colors.Colormap`, default: image.cmap
|
|
3169
|
+
The Colormap instance or registered colormap name used to map scalar data
|
|
3170
|
+
to colors.
|
|
3171
|
+
|
|
3172
|
+
This parameter is ignored if *colors* is set.
|
|
3173
|
+
|
|
3174
|
+
norm : str or `~matplotlib.colors.Normalize`, optional
|
|
3175
|
+
The normalization method used to scale scalar data to the [0, 1] range
|
|
3176
|
+
before mapping to colors using *cmap*. By default, a linear scaling is
|
|
3177
|
+
used, mapping the lowest value to 0 and the highest to 1.
|
|
3178
|
+
|
|
3179
|
+
If given, this can be one of the following:
|
|
3180
|
+
|
|
3181
|
+
- An instance of `.Normalize` or one of its subclasses
|
|
3182
|
+
(see :ref:`colormapnorms`).
|
|
3183
|
+
- A scale name, i.e. one of "linear", "log", "symlog", "logit", etc. For a
|
|
3184
|
+
list of available scales, call `matplotlib.scale.get_scale_names()`.
|
|
3185
|
+
In that case, a suitable `.Normalize` subclass is dynamically generated
|
|
3186
|
+
and instantiated.
|
|
3187
|
+
|
|
3188
|
+
This parameter is ignored if *colors* is set.
|
|
3189
|
+
|
|
3190
|
+
vmin, vmax : float, optional
|
|
3191
|
+
When using scalar data and no explicit *norm*, *vmin* and *vmax* define
|
|
3192
|
+
the data range that the colormap covers. By default, the colormap covers
|
|
3193
|
+
the complete value range of the supplied data. It is an error to use
|
|
3194
|
+
*vmin*/*vmax* when a *norm* instance is given (but using a `str` *norm*
|
|
3195
|
+
name together with *vmin*/*vmax* is acceptable).
|
|
3196
|
+
|
|
3197
|
+
If *vmin* or *vmax* are not given, the default color scaling is based on
|
|
3198
|
+
*levels*.
|
|
3199
|
+
|
|
3200
|
+
This parameter is ignored if *colors* is set.
|
|
3201
|
+
|
|
3202
|
+
colorizer : `~matplotlib.colorizer.Colorizer` or None, default: None
|
|
3203
|
+
The Colorizer object used to map color to data. If None, a Colorizer
|
|
3204
|
+
object is created from a *norm* and *cmap*.
|
|
3205
|
+
|
|
3206
|
+
This parameter is ignored if *colors* is set.
|
|
3207
|
+
|
|
3208
|
+
origin : {*None*, 'upper', 'lower', 'image'}, default: None
|
|
3209
|
+
Determines the orientation and exact position of *Z* by specifying
|
|
3210
|
+
the position of ``Z[0, 0]``. This is only relevant, if *X*, *Y*
|
|
3211
|
+
are not given.
|
|
3212
|
+
|
|
3213
|
+
- *None*: ``Z[0, 0]`` is at X=0, Y=0 in the lower left corner.
|
|
3214
|
+
- 'lower': ``Z[0, 0]`` is at X=0.5, Y=0.5 in the lower left corner.
|
|
3215
|
+
- 'upper': ``Z[0, 0]`` is at X=N+0.5, Y=0.5 in the upper left
|
|
3216
|
+
corner.
|
|
3217
|
+
- 'image': Use the value from image.origin.
|
|
3218
|
+
|
|
3219
|
+
extent : (x0, x1, y0, y1), optional
|
|
3220
|
+
If *origin* is not *None*, then *extent* is interpreted as in
|
|
3221
|
+
`.imshow`: it gives the outer pixel boundaries. In this case, the
|
|
3222
|
+
position of Z[0, 0] is the center of the pixel, not a corner. If
|
|
3223
|
+
*origin* is *None*, then (*x0*, *y0*) is the position of Z[0, 0],
|
|
3224
|
+
and (*x1*, *y1*) is the position of Z[-1, -1].
|
|
3225
|
+
|
|
3226
|
+
This argument is ignored if *X* and *Y* are specified in the call
|
|
3227
|
+
to contour.
|
|
3228
|
+
|
|
3229
|
+
locator : ticker.Locator subclass, optional
|
|
3230
|
+
The locator is used to determine the contour levels if they
|
|
3231
|
+
are not given explicitly via *levels*.
|
|
3232
|
+
Defaults to `~.ticker.MaxNLocator`.
|
|
3233
|
+
|
|
3234
|
+
extend : {'neither', 'both', 'min', 'max'}, default: 'neither'
|
|
3235
|
+
Determines the ``contourf``-coloring of values that are outside the
|
|
3236
|
+
*levels* range.
|
|
3237
|
+
|
|
3238
|
+
If 'neither', values outside the *levels* range are not colored.
|
|
3239
|
+
If 'min', 'max' or 'both', color the values below, above or below
|
|
3240
|
+
and above the *levels* range.
|
|
3241
|
+
|
|
3242
|
+
Values below ``min(levels)`` and above ``max(levels)`` are mapped
|
|
3243
|
+
to the under/over values of the `.Colormap`. Note that most
|
|
3244
|
+
colormaps do not have dedicated colors for these by default, so
|
|
3245
|
+
that the over and under values are the edge values of the colormap.
|
|
3246
|
+
You may want to set these values explicitly using
|
|
3247
|
+
`.Colormap.set_under` and `.Colormap.set_over`.
|
|
3248
|
+
|
|
3249
|
+
.. note::
|
|
3250
|
+
|
|
3251
|
+
An existing `.QuadContourSet` does not get notified if
|
|
3252
|
+
properties of its colormap are changed. Therefore, an explicit
|
|
3253
|
+
call `~.ContourSet.changed()` is needed after modifying the
|
|
3254
|
+
colormap. The explicit call can be left out, if a colorbar is
|
|
3255
|
+
assigned to the `.QuadContourSet` because it internally calls
|
|
3256
|
+
`~.ContourSet.changed()`.
|
|
3257
|
+
|
|
3258
|
+
Example::
|
|
3259
|
+
|
|
3260
|
+
x = np.arange(1, 10)
|
|
3261
|
+
y = x.reshape(-1, 1)
|
|
3262
|
+
h = x * y
|
|
3263
|
+
|
|
3264
|
+
cs = plt.contourf(h, levels=[10, 30, 50],
|
|
3265
|
+
colors=['#808080', '#A0A0A0', '#C0C0C0'], extend='both')
|
|
3266
|
+
cs.cmap.set_over('red')
|
|
3267
|
+
cs.cmap.set_under('blue')
|
|
3268
|
+
cs.changed()
|
|
3269
|
+
|
|
3270
|
+
xunits, yunits : registered units, optional
|
|
3271
|
+
Override axis units by specifying an instance of a
|
|
3272
|
+
:class:`matplotlib.units.ConversionInterface`.
|
|
3273
|
+
|
|
3274
|
+
antialiased : bool, optional
|
|
3275
|
+
Enable antialiasing, overriding the defaults. For
|
|
3276
|
+
filled contours, the default is *False*. For line contours,
|
|
3277
|
+
it is taken from lines.antialiased.
|
|
3278
|
+
|
|
3279
|
+
nchunk : int >= 0, optional
|
|
3280
|
+
If 0, no subdivision of the domain. Specify a positive integer to
|
|
3281
|
+
divide the domain into subdomains of *nchunk* by *nchunk* quads.
|
|
3282
|
+
Chunking reduces the maximum length of polygons generated by the
|
|
3283
|
+
contouring algorithm which reduces the rendering workload passed
|
|
3284
|
+
on to the backend and also requires slightly less RAM. It can
|
|
3285
|
+
however introduce rendering artifacts at chunk boundaries depending
|
|
3286
|
+
on the backend, the *antialiased* flag and value of *alpha*.
|
|
3287
|
+
|
|
3288
|
+
linewidths : float or array-like, default: contour.linewidth
|
|
3289
|
+
*Only applies to* `.contour`.
|
|
3290
|
+
|
|
3291
|
+
The line width of the contour lines.
|
|
3292
|
+
|
|
3293
|
+
If a number, all levels will be plotted with this linewidth.
|
|
3294
|
+
|
|
3295
|
+
If a sequence, the levels in ascending order will be plotted with
|
|
3296
|
+
the linewidths in the order specified.
|
|
3297
|
+
|
|
3298
|
+
If None, this falls back to lines.linewidth.
|
|
3299
|
+
|
|
3300
|
+
linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, optional
|
|
3301
|
+
*Only applies to* `.contour`.
|
|
3302
|
+
|
|
3303
|
+
If *linestyles* is *None*, the default is 'solid' unless the lines are
|
|
3304
|
+
monochrome. In that case, negative contours will instead take their
|
|
3305
|
+
linestyle from the *negative_linestyles* argument.
|
|
3306
|
+
|
|
3307
|
+
*linestyles* can also be an iterable of the above strings specifying a set
|
|
3308
|
+
of linestyles to be used. If this iterable is shorter than the number of
|
|
3309
|
+
contour levels it will be repeated as necessary.
|
|
3310
|
+
|
|
3311
|
+
negative_linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, optional
|
|
3312
|
+
*Only applies to* `.contour`.
|
|
3313
|
+
|
|
3314
|
+
If *linestyles* is *None* and the lines are monochrome, this argument
|
|
3315
|
+
specifies the line style for negative contours.
|
|
3316
|
+
|
|
3317
|
+
If *negative_linestyles* is *None*, the default is taken from
|
|
3318
|
+
contour.negative_linestyle.
|
|
3319
|
+
|
|
3320
|
+
*negative_linestyles* can also be an iterable of the above strings
|
|
3321
|
+
specifying a set of linestyles to be used. If this iterable is shorter than
|
|
3322
|
+
the number of contour levels it will be repeated as necessary.
|
|
3323
|
+
|
|
3324
|
+
hatches : list[str], optional
|
|
3325
|
+
*Only applies to* `.contourf`.
|
|
3326
|
+
|
|
3327
|
+
A list of cross hatch patterns to use on the filled areas.
|
|
3328
|
+
If None, no hatching will be added to the contour.
|
|
3329
|
+
|
|
3330
|
+
algorithm : {'mpl2005', 'mpl2014', 'serial', 'threaded'}, optional
|
|
3331
|
+
Which contouring algorithm to use to calculate the contour lines and
|
|
3332
|
+
polygons. The algorithms are implemented in
|
|
3333
|
+
`ContourPy <https://github.com/contourpy/contourpy>`_, consult the
|
|
3334
|
+
`ContourPy documentation <https://contourpy.readthedocs.io>`_ for
|
|
3335
|
+
further information.
|
|
3336
|
+
|
|
3337
|
+
The default is taken from contour.algorithm.
|
|
3338
|
+
|
|
3339
|
+
clip_path : `~matplotlib.patches.Patch` or `.Path` or `.TransformedPath`
|
|
3340
|
+
Set the clip path. See `~matplotlib.artist.Artist.set_clip_path`.
|
|
3341
|
+
|
|
3342
|
+
.. versionadded:: 3.8
|
|
3343
|
+
|
|
3344
|
+
data : indexable object, optional
|
|
3345
|
+
If given, all parameters also accept a string ``s``, which is
|
|
3346
|
+
interpreted as ``data[s]`` if ``s`` is a key in ``data``.
|
|
3347
|
+
|
|
3348
|
+
Notes
|
|
3349
|
+
-----
|
|
3350
|
+
|
|
3351
|
+
.. note::
|
|
3352
|
+
|
|
3353
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.contourf`.
|
|
3354
|
+
|
|
3355
|
+
1. `.contourf` differs from the MATLAB version in that it does not draw
|
|
3356
|
+
the polygon edges. To draw edges, add line contours with calls to
|
|
3357
|
+
`.contour`.
|
|
3358
|
+
|
|
3359
|
+
2. `.contourf` fills intervals that are closed at the top; that is, for
|
|
3360
|
+
boundaries *z1* and *z2*, the filled region is::
|
|
3361
|
+
|
|
3362
|
+
z1 < Z <= z2
|
|
3363
|
+
|
|
3364
|
+
except for the lowest interval, which is closed on both sides (i.e.
|
|
3365
|
+
it includes the lowest value).
|
|
3366
|
+
|
|
3367
|
+
3. `.contour` and `.contourf` use a `marching squares
|
|
3368
|
+
<https://en.wikipedia.org/wiki/Marching_squares>`_ algorithm to
|
|
3369
|
+
compute contour locations. More information can be found in
|
|
3370
|
+
`ContourPy documentation <https://contourpy.readthedocs.io>`_.
|
|
3371
|
+
"""
|
|
3372
|
+
def __init__(self, z, x=None, y=None,easing=None,axis=None, *args, **kwargs):
|
|
3373
|
+
self.mpl_obj_type = mpl.contour.QuadContourSet
|
|
3374
|
+
self.mpl_plot_type = plt.contourf
|
|
3375
|
+
super().__init__(easing=easing,axis=axis,*args,**kwargs)
|
|
3376
|
+
self.x = np.ravel(z)
|
|
3377
|
+
self.y = np.ravel(z)
|
|
3378
|
+
self._x = x
|
|
3379
|
+
self._y = y
|
|
3380
|
+
if self._x is None:
|
|
3381
|
+
self._x = range(z.shape[0])
|
|
3382
|
+
if self._y is None:
|
|
3383
|
+
self._y = range(z.shape[1])
|
|
3384
|
+
self._x = np.array(self._x)
|
|
3385
|
+
self._y = np.array(self._y)
|
|
3386
|
+
self.init_shape = z.shape
|
|
3387
|
+
|
|
3388
|
+
def morph(self,new_z,duration,delay=0,easing=None,persistent=True,**kwargs):
|
|
3389
|
+
self.anims.append({
|
|
3390
|
+
'name':'morph',
|
|
3391
|
+
'duration':duration,
|
|
3392
|
+
'delay':delay,
|
|
3393
|
+
'easing':easing,
|
|
3394
|
+
'new_x':np.ravel(new_z),
|
|
3395
|
+
'new_y':np.ravel(new_z),
|
|
3396
|
+
'persistent':persistent,
|
|
3397
|
+
'played':False
|
|
3398
|
+
})
|
|
3399
|
+
self.compute_timings()
|
|
3400
|
+
return self
|
|
3401
|
+
|
|
3402
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
3403
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
3404
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
3405
|
+
|
|
3406
|
+
if 'bins' in kwargs:
|
|
3407
|
+
kwargs['bins'] = to_np_array(kwargs['bins'])
|
|
3408
|
+
|
|
3409
|
+
if 'bins' in kwargs and len(kwargs['bins']) == 1:
|
|
3410
|
+
kwargs['bins'] = int(kwargs['bins'][0])
|
|
3411
|
+
|
|
3412
|
+
if 'color' in kwargs:
|
|
3413
|
+
kwargs.pop('color')
|
|
3414
|
+
|
|
3415
|
+
kwargs.pop('animated')
|
|
3416
|
+
|
|
3417
|
+
if len(np.array(data_x).shape) == 1:
|
|
3418
|
+
new_data_x = np.zeros(self.init_shape)
|
|
3419
|
+
for i in range(0, len(data_x)):
|
|
3420
|
+
new_data_x[i//self.init_shape[0],i%self.init_shape[0]] = data_x[i]
|
|
3421
|
+
data_x = new_data_x
|
|
3422
|
+
|
|
3423
|
+
#Have to reset xlim and ylim because contourf does not respect the imposed limits
|
|
3424
|
+
old_xlim = self.axis.get_xlim()
|
|
3425
|
+
old_ylim = self.axis.get_ylim()
|
|
3426
|
+
z = data_x
|
|
3427
|
+
self.obj = self.axis.contourf(self._x,self._y,z,**kwargs)
|
|
3428
|
+
self.axis.set_xlim(old_xlim)
|
|
3429
|
+
self.axis.set_ylim(old_ylim)
|
|
3430
|
+
|
|
3431
|
+
class text(Animation):
|
|
3432
|
+
"""
|
|
3433
|
+
Add text to the Axes.
|
|
3434
|
+
|
|
3435
|
+
Add the text *s* to the Axes at location *x*, *y* in data coordinates,
|
|
3436
|
+
with a default ``horizontalalignment`` on the ``left`` and
|
|
3437
|
+
``verticalalignment`` at the ``baseline``.
|
|
3438
|
+
|
|
3439
|
+
Parameters
|
|
3440
|
+
----------
|
|
3441
|
+
x, y : float
|
|
3442
|
+
The position to place the text. By default, this is in data
|
|
3443
|
+
coordinates. The coordinate system can be changed using the
|
|
3444
|
+
*transform* parameter.
|
|
3445
|
+
|
|
3446
|
+
duration : float
|
|
3447
|
+
Duration of the animation
|
|
3448
|
+
delay : float, default=0
|
|
3449
|
+
Delay before starting
|
|
3450
|
+
easing : callable, optional
|
|
3451
|
+
Easing function
|
|
3452
|
+
axis : matplotlib.axes.Axes, optional
|
|
3453
|
+
Axis to plot on
|
|
3454
|
+
|
|
3455
|
+
|
|
3456
|
+
s : str
|
|
3457
|
+
The text.
|
|
3458
|
+
|
|
3459
|
+
fontdict : dict, default: None
|
|
3460
|
+
|
|
3461
|
+
.. admonition:: Discouraged
|
|
3462
|
+
|
|
3463
|
+
The use of *fontdict* is discouraged. Parameters should be passed as
|
|
3464
|
+
individual keyword arguments or using dictionary-unpacking
|
|
3465
|
+
``text(..., **fontdict)``.
|
|
3466
|
+
|
|
3467
|
+
A dictionary to override the default text properties. If fontdict
|
|
3468
|
+
is None, the defaults are determined by `.rcParams`.
|
|
3469
|
+
|
|
3470
|
+
Returns
|
|
3471
|
+
-------
|
|
3472
|
+
`.Text`
|
|
3473
|
+
The created `.Text` instance.
|
|
3474
|
+
|
|
3475
|
+
Other Parameters
|
|
3476
|
+
----------------
|
|
3477
|
+
**kwargs : `~matplotlib.text.Text` properties.
|
|
3478
|
+
Other miscellaneous text parameters.
|
|
3479
|
+
|
|
3480
|
+
Properties:
|
|
3481
|
+
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
|
|
3482
|
+
alpha: float or None
|
|
3483
|
+
animated: bool
|
|
3484
|
+
antialiased: bool
|
|
3485
|
+
backgroundcolor: color
|
|
3486
|
+
bbox: dict with properties for `.patches.FancyBboxPatch`
|
|
3487
|
+
clip_box: unknown
|
|
3488
|
+
clip_on: unknown
|
|
3489
|
+
clip_path: unknown
|
|
3490
|
+
color or c: color
|
|
3491
|
+
figure: `~matplotlib.figure.Figure` or `~matplotlib.figure.SubFigure`
|
|
3492
|
+
fontfamily or family or fontname: {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
|
|
3493
|
+
fontproperties or font or font_properties: `.font_manager.FontProperties` or `str` or `pathlib.Path`
|
|
3494
|
+
fontsize or size: float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
|
|
3495
|
+
fontstretch or stretch: {a numeric value in range 0-1000, 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'}
|
|
3496
|
+
fontstyle or style: {'normal', 'italic', 'oblique'}
|
|
3497
|
+
fontvariant or variant: {'normal', 'small-caps'}
|
|
3498
|
+
fontweight or weight: {a numeric value in range 0-1000, 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'}
|
|
3499
|
+
gid: str
|
|
3500
|
+
horizontalalignment or ha: {'left', 'center', 'right'}
|
|
3501
|
+
in_layout: bool
|
|
3502
|
+
label: object
|
|
3503
|
+
linespacing: float (multiple of font size)
|
|
3504
|
+
math_fontfamily: str
|
|
3505
|
+
mouseover: bool
|
|
3506
|
+
multialignment or ma: {'left', 'right', 'center'}
|
|
3507
|
+
parse_math: bool
|
|
3508
|
+
path_effects: list of `.AbstractPathEffect`
|
|
3509
|
+
picker: None or bool or float or callable
|
|
3510
|
+
position: (float, float)
|
|
3511
|
+
rasterized: bool
|
|
3512
|
+
rotation: float or {'vertical', 'horizontal'}
|
|
3513
|
+
rotation_mode: {None, 'default', 'anchor'}
|
|
3514
|
+
sketch_params: (scale: float, length: float, randomness: float)
|
|
3515
|
+
snap: bool or None
|
|
3516
|
+
text: object
|
|
3517
|
+
transform: `~matplotlib.transforms.Transform`
|
|
3518
|
+
transform_rotates_text: bool
|
|
3519
|
+
url: str
|
|
3520
|
+
usetex: bool, default: text.usetex
|
|
3521
|
+
verticalalignment or va: {'baseline', 'bottom', 'center', 'center_baseline', 'top'}
|
|
3522
|
+
visible: bool
|
|
3523
|
+
wrap: bool
|
|
3524
|
+
x: float
|
|
3525
|
+
y: float
|
|
3526
|
+
zorder: float
|
|
3527
|
+
|
|
3528
|
+
Notes
|
|
3529
|
+
-----
|
|
3530
|
+
|
|
3531
|
+
.. note::
|
|
3532
|
+
|
|
3533
|
+
This is the :ref:`pyplot wrapper <pyplot_interface>` for `.axes.Axes.text`.
|
|
3534
|
+
|
|
3535
|
+
Examples
|
|
3536
|
+
--------
|
|
3537
|
+
Individual keyword arguments can be used to override any given
|
|
3538
|
+
parameter::
|
|
3539
|
+
|
|
3540
|
+
>>> text(x, y, s, fontsize=12)
|
|
3541
|
+
|
|
3542
|
+
The default transform specifies that text is in data coords,
|
|
3543
|
+
alternatively, you can specify text in axis coords ((0, 0) is
|
|
3544
|
+
lower-left and (1, 1) is upper-right). The example below places
|
|
3545
|
+
text in the center of the Axes::
|
|
3546
|
+
|
|
3547
|
+
>>> text(0.5, 0.5, 'matplotlib', horizontalalignment='center',
|
|
3548
|
+
... verticalalignment='center', transform=ax.transAxes)
|
|
3549
|
+
|
|
3550
|
+
You can put a rectangular box around the text instance (e.g., to
|
|
3551
|
+
set a background color) by using the keyword *bbox*. *bbox* is
|
|
3552
|
+
a dictionary of `~matplotlib.patches.Rectangle`
|
|
3553
|
+
properties. For example::
|
|
3554
|
+
|
|
3555
|
+
>>> text(x, y, s, bbox=dict(facecolor='red', alpha=0.5))
|
|
3556
|
+
"""
|
|
3557
|
+
def __init__(self,x,y,string,easing=None,axis=None, *args, **kwargs):
|
|
3558
|
+
self.mpl_obj_type = mpl.patches.PathPatch
|
|
3559
|
+
self.mpl_plot_type = plt.text
|
|
3560
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
3561
|
+
self.x = x
|
|
3562
|
+
self.y = y
|
|
3563
|
+
self.string = string
|
|
3564
|
+
|
|
3565
|
+
def anim_function(self,x,kwargs):
|
|
3566
|
+
s = self.string
|
|
3567
|
+
for anim in self.anims:
|
|
3568
|
+
if anim['name'] not in ['draw','sequence']:
|
|
3569
|
+
continue
|
|
3570
|
+
t = self.get_t_from_x(anim,x)
|
|
3571
|
+
if anim['name'] == 'sequence':
|
|
3572
|
+
if x < anim['delay'] or x > anim['delay'] + anim['duration']:
|
|
3573
|
+
continue
|
|
3574
|
+
_i = max(min(round(t*len(s)),len(s)-1),0)
|
|
3575
|
+
s = s[_i]
|
|
3576
|
+
elif anim['name'] == 'draw':
|
|
3577
|
+
if anim['reverse']:
|
|
3578
|
+
i_max = max(round((1-t)*len(s)),0)
|
|
3579
|
+
else:
|
|
3580
|
+
i_max = min(round(t*len(s)),len(s))
|
|
3581
|
+
s = s[:i_max]
|
|
3582
|
+
|
|
3583
|
+
self.function(self.x,self.y,s,kwargs)
|
|
3584
|
+
|
|
3585
|
+
def function(self,data_x,data_y,s,kwargs):
|
|
3586
|
+
if len(s) == 0:
|
|
3587
|
+
return
|
|
3588
|
+
if 'fontsize' in kwargs:
|
|
3589
|
+
fp = FontProperties(size=kwargs['fontsize'])
|
|
3590
|
+
else:
|
|
3591
|
+
fp = FontProperties()
|
|
3592
|
+
tp = TextPath((data_x, data_y), s, prop=fp)
|
|
3593
|
+
patch = PathPatch(tp, **kwargs)
|
|
3594
|
+
self.axis.add_patch(patch)
|
|
3595
|
+
|
|
3596
|
+
px_per_pt = self.axis.get_figure().dpi / 72.0
|
|
3597
|
+
dx_per_px = (self.axis.get_xlim()[1] - self.axis.get_xlim()[0]) / self.axis.bbox.width
|
|
3598
|
+
dy_per_px = (self.axis.get_ylim()[1] - self.axis.get_ylim()[0]) / self.axis.bbox.height
|
|
3599
|
+
sx = px_per_pt * dx_per_px
|
|
3600
|
+
sy = px_per_pt * dy_per_px
|
|
3601
|
+
|
|
3602
|
+
T = (
|
|
3603
|
+
transforms.Affine2D()
|
|
3604
|
+
.scale(sx, sy)
|
|
3605
|
+
)
|
|
3606
|
+
patch.set_path(patch.get_path().transformed(T))
|
|
3607
|
+
self.path = patch.get_path()
|
|
3608
|
+
self.obj = patch
|
|
3609
|
+
|
|
3610
|
+
class svg(Animation):
|
|
3611
|
+
"""A vector SVG object.
|
|
3612
|
+
|
|
3613
|
+
Parameters
|
|
3614
|
+
----------
|
|
3615
|
+
data : str
|
|
3616
|
+
SVG object as a string.
|
|
3617
|
+
fc : color, default=None
|
|
3618
|
+
the face color.
|
|
3619
|
+
ec : color, default='k'
|
|
3620
|
+
the edge color.
|
|
3621
|
+
lw : float, default=2
|
|
3622
|
+
the line width.
|
|
3623
|
+
"""
|
|
3624
|
+
def __init__(self, data, fc=None, ec='k', lw=2,easing=None,axis=None, *args, **kwargs):
|
|
3625
|
+
self.mpl_obj_type = mpl.patches.PathPatch
|
|
3626
|
+
kwargs['facecolor'] = fc
|
|
3627
|
+
kwargs['edgecolor'] = ec
|
|
3628
|
+
kwargs['linewidth'] = lw
|
|
3629
|
+
super().__init__(easing=easing,axis=axis,*args, **kwargs)
|
|
3630
|
+
self.data = data
|
|
3631
|
+
self.path = None
|
|
3632
|
+
|
|
3633
|
+
def draw_svg(self,kwargs):
|
|
3634
|
+
self.obj = mpl.patches.PathPatch(self.path,**kwargs)
|
|
3635
|
+
self.axis.add_patch(self.obj)
|
|
3636
|
+
|
|
3637
|
+
def _slice_path(self, path, i0, i1):
|
|
3638
|
+
verts = path.vertices[i0:i1]
|
|
3639
|
+
if len(verts) == 0:
|
|
3640
|
+
return None
|
|
3641
|
+
codes = np.full(len(verts), mpl.path.Path.LINETO, dtype=np.uint8)
|
|
3642
|
+
codes[0] = mpl.path.Path.MOVETO
|
|
3643
|
+
return mpl.path.Path(verts, codes)
|
|
3644
|
+
|
|
3645
|
+
def anim_function(self,x,kwargs):
|
|
3646
|
+
self.path = parse_path(self.data)
|
|
3647
|
+
path = self.path
|
|
3648
|
+
n = len(path.vertices)
|
|
3649
|
+
|
|
3650
|
+
i0, i1 = 0, n
|
|
3651
|
+
has_path_anim = False
|
|
3652
|
+
|
|
3653
|
+
for anim in self.anims:
|
|
3654
|
+
if anim['name'] not in ['draw','sequence']:
|
|
3655
|
+
continue
|
|
3656
|
+
if x < anim['delay'] or x > anim['delay'] + anim['duration']:
|
|
3657
|
+
continue
|
|
3658
|
+
|
|
3659
|
+
has_path_anim = True
|
|
3660
|
+
t = self.get_t_from_x(anim,x)
|
|
3661
|
+
|
|
3662
|
+
if anim['name'] == 'draw':
|
|
3663
|
+
if anim['reverse']:
|
|
3664
|
+
i0, i1 = 0, max(round((1 - t) * n), 0)
|
|
3665
|
+
else:
|
|
3666
|
+
i0, i1 = 0, min(round(t * n), n)
|
|
3667
|
+
elif anim['name'] == 'sequence':
|
|
3668
|
+
i = max(min(round(t * (n - 1)), n - 1), 0)
|
|
3669
|
+
i0, i1 = max(i - 1, 0), min(i + 1, n)
|
|
3670
|
+
|
|
3671
|
+
frame_path = self._slice_path(path, i0, i1) if has_path_anim else path
|
|
3672
|
+
if frame_path is None:
|
|
3673
|
+
return
|
|
3674
|
+
self.path = frame_path
|
|
3675
|
+
self.function(self.x, self.y, None, kwargs)
|
|
3676
|
+
|
|
3677
|
+
def function(self,data_x,data_y,x,kwargs):
|
|
3678
|
+
if isinstance(kwargs['alpha'],np.ndarray):
|
|
3679
|
+
kwargs['alpha'] = kwargs['alpha'][0]
|
|
3680
|
+
if kwargs['facecolor'] is None:
|
|
3681
|
+
kwargs['facecolor'] = self.axis._get_lines.get_next_color()
|
|
3682
|
+
|
|
3683
|
+
if 'color' in kwargs:
|
|
3684
|
+
kwargs.pop('color')
|
|
3685
|
+
|
|
3686
|
+
self.draw_svg(kwargs)
|