1
1
from matplotlib .animation import FuncAnimation , PillowWriter
2
+ from matplotlib .gridspec import GridSpec
2
3
from matplotlib .widgets import Button , Slider
3
4
import matplotlib .pyplot as plt
4
5
import numpy as np
@@ -42,6 +43,7 @@ def __init__(self, blocks, timeline=None, fig=None):
42
43
self .fig = plt .gcf () if fig is None else fig
43
44
self ._has_slider = False
44
45
self ._pause = False
46
+ self ._controls_gridspec_object = None
45
47
46
48
def animate (i ):
47
49
updates = []
@@ -58,6 +60,40 @@ def animate(i):
58
60
interval = 1000 / self .timeline .fps
59
61
)
60
62
63
+ @property
64
+ def _controls_gridspec (self ):
65
+ if self ._controls_gridspec_object is None :
66
+ # make the bottom of the subplots grid lower to fit the controls in
67
+ adjust_plot = {'bottom' : 0.03 }
68
+ plt .subplots_adjust (** adjust_plot )
69
+
70
+ controls_height = 0.2
71
+
72
+ # get gridspec to adjust
73
+ gs = (plt .gca ().get_gridspec ().get_topmost_subplotspec ()
74
+ .get_gridspec ())
75
+ nrows , ncols = gs .get_geometry ()
76
+ height_ratios = gs .get_height_ratios ()
77
+
78
+ # update parameters with a new row
79
+ if height_ratios is None :
80
+ # if height_ratios is None, all rows on the original gridspec
81
+ # are the same height
82
+ height_ratios = [(1. - controls_height )/ nrows
83
+ for i in range (nrows )]
84
+ else :
85
+ height_ratios = [r * (1. - controls_height ) for r in height_ratios ]
86
+ height_ratios .append (controls_height )
87
+ gs ._nrows += 1
88
+ gs .set_height_ratios (height_ratios )
89
+
90
+ # make a sub-grid in the bottom row
91
+ self ._controls_gridspec_object = gs [- 1 , :].subgridspec (
92
+ 1 ,3 , width_ratios = [.07 , .65 , .28 ], wspace = 0. , hspace = 0. )
93
+ gs .update ()
94
+
95
+ return self ._controls_gridspec_object
96
+
61
97
def toggle (self , ax = None ):
62
98
"""Creates a play/pause button to start/stop the animation
63
99
@@ -67,11 +103,20 @@ def toggle(self, ax=None):
67
103
The matplotlib axes to attach the button to.
68
104
"""
69
105
if ax is None :
70
- adjust_plot = {'bottom' : .2 }
71
- rect = [.78 , .03 , .1 , .07 ]
72
-
73
- plt .subplots_adjust (** adjust_plot )
74
- self .button_ax = plt .axes (rect )
106
+ try :
107
+ button_subplotspec = self ._controls_gridspec [0 , 2 ]
108
+ button_gridspec = button_subplotspec .subgridspec (
109
+ 3 , 3 , width_ratios = [0.45 , 0.45 , 0.1 ],
110
+ height_ratios = [.05 , .5 , .45 ], wspace = 0. , hspace = 0. )
111
+ self .button_ax = self .fig .add_subplot (button_gridspec [1 ,1 ])
112
+ except :
113
+ # editing the gridspec did not work for some reason, fall back to
114
+ # subplots_adjust
115
+ adjust_plot = {'bottom' : .2 }
116
+ rect = [.78 , .03 , .1 , .07 ]
117
+
118
+ plt .subplots_adjust (** adjust_plot )
119
+ self .button_ax = plt .axes (rect )
75
120
else :
76
121
self .button_ax = ax
77
122
@@ -113,11 +158,19 @@ def timeline_slider(self, text='Time', ax=None, valfmt=None, color=None):
113
158
The color of the slider.
114
159
"""
115
160
if ax is None :
116
- adjust_plot = {'bottom' : .2 }
117
- rect = [.18 , .05 , .5 , .03 ]
118
-
119
- plt .subplots_adjust (** adjust_plot )
120
- self .slider_ax = plt .axes (rect )
161
+ try :
162
+ slider_subplotspec = self ._controls_gridspec [0 , 1 ]
163
+ slider_gridspec = slider_subplotspec .subgridspec (
164
+ 3 , 1 , height_ratios = [.2 , .2 , .6 ], wspace = 0. ,
165
+ hspace = 0. )
166
+ self .slider_ax = self .fig .add_subplot (slider_gridspec [1 , 0 ])
167
+ except :
168
+ # editing the gridspec did not work for some reason, fall back to
169
+ # subplots_adjust
170
+ adjust_plot = {'bottom' : .2 }
171
+ rect = [.18 , .05 , .5 , .03 ]
172
+ plt .subplots_adjust (** adjust_plot )
173
+ self .slider_ax = plt .axes (rect )
121
174
else :
122
175
self .slider_ax = ax
123
176
0 commit comments