Skip to content

Commit bcf5382

Browse files
authored
Merge pull request #262 from roryyorke/rory/no-mplib-find
Fix: don't called deprecated Matplotlib functions find and frange
2 parents eeb7c2f + 9e41ae7 commit bcf5382

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

control/phaseplot.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,20 @@
3939

4040
import numpy as np
4141
import matplotlib.pyplot as mpl
42-
from matplotlib.mlab import frange, find
42+
4343
from scipy.integrate import odeint
4444
from .exception import ControlNotImplemented
4545

4646
__all__ = ['phase_plot', 'box_grid']
4747

48+
49+
def _find(condition):
50+
"""Returns indices where ravel(a) is true.
51+
Private implementation of deprecated matplotlib.mlab.find
52+
"""
53+
return np.nonzero(np.ravel(condition))[0]
54+
55+
4856
def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None,
4957
lingrid=None, lintime=None, logtime=None, timepts=None,
5058
parms=(), verbose=True):
@@ -70,11 +78,11 @@ def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None,
7078
dxdt = F(x, t) that accepts a state x of dimension 2 and
7179
returns a derivative dx/dt of dimension 2.
7280
73-
X, Y: ndarray, optional
74-
Two 1-D arrays representing x and y coordinates of a grid.
75-
These arguments are passed to meshgrid and generate the lists
76-
of points at which the vector field is plotted. If absent (or
77-
None), the vector field is not plotted.
81+
X, Y: 3-element sequences, optional, as [start, stop, npts]
82+
Two 3-element sequences specifying x and y coordinates of a
83+
grid. These arguments are passed to linspace and meshgrid to
84+
generate the points at which the vector field is plotted. If
85+
absent (or None), the vector field is not plotted.
7886
7987
scale: float, optional
8088
Scale size of arrows; default = 1
@@ -145,8 +153,10 @@ def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None,
145153
#! TODO: Add sanity checks
146154
elif (X is not None and Y is not None):
147155
(x1, x2) = np.meshgrid(
148-
frange(X[0], X[1], float(X[1]-X[0])/X[2]),
149-
frange(Y[0], Y[1], float(Y[1]-Y[0])/Y[2]));
156+
np.linspace(X[0], X[1], X[2]),
157+
np.linspace(Y[0], Y[1], Y[2]))
158+
Narrows = len(x1)
159+
150160
else:
151161
# If we weren't given any grid points, don't plot arrows
152162
Narrows = 0;
@@ -234,12 +244,12 @@ def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None,
234244
elif (logtimeFlag):
235245
# Use an exponential time vector
236246
# MATLAB: tind = find(time < (j-k) / lambda, 1, 'last');
237-
tarr = find(time < (j-k) / timefactor);
247+
tarr = _find(time < (j-k) / timefactor);
238248
tind = tarr[-1] if len(tarr) else 0;
239249
elif (timeptsFlag):
240250
# Use specified time points
241251
# MATLAB: tind = find(time < Y[j], 1, 'last');
242-
tarr = find(time < timepts[j]);
252+
tarr = _find(time < timepts[j]);
243253
tind = tarr[-1] if len(tarr) else 0;
244254

245255
# For tailless arrows, skip the first point
@@ -295,8 +305,8 @@ def box_grid(xlimp, ylimp):
295305
box defined by the corners [xmin ymin] and [xmax ymax].
296306
"""
297307

298-
sx10 = frange(xlimp[0], xlimp[1], float(xlimp[1]-xlimp[0])/xlimp[2])
299-
sy10 = frange(ylimp[0], ylimp[1], float(ylimp[1]-ylimp[0])/ylimp[2])
308+
sx10 = np.linspace(xlimp[0], xlimp[1], xlimp[2])
309+
sy10 = np.linspace(ylimp[0], ylimp[1], ylimp[2])
300310

301311
sx1 = np.hstack((0, sx10, 0*sy10+sx10[0], sx10, 0*sy10+sx10[-1]))
302312
sx2 = np.hstack((0, 0*sx10+sy10[0], sy10, 0*sx10+sy10[-1], sy10))

examples/genswitch.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import numpy as np
99
import matplotlib.pyplot as mpl
1010
from scipy.integrate import odeint
11-
from matplotlib.mlab import frange
1211
from control import phase_plot, box_grid
1312

1413
# Simple model of a genetic switch
@@ -34,7 +33,7 @@ def genswitch(y, t, mu=4, n=2):
3433
sol2 = odeint(genswitch, sol1[-1,:] + [2, -2], tim2)
3534

3635
# First plot out the curves that define the equilibria
37-
u = frange(0, 4.5, 0.1)
36+
u = np.linspace(0, 4.5, 46)
3837
f = np.divide(mu, (1 + u**n)) # mu / (1 + u^n), elementwise
3938

4039
mpl.figure(1); mpl.clf();

examples/phaseplots.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def invpend_ode(x, t, m=1., l=1., b=0.2, g=1):
2323
# Set up the figure the way we want it to look
2424
mpl.figure(); mpl.clf();
2525
mpl.axis([-2*pi, 2*pi, -2.1, 2.1]);
26-
mpl.title('Inverted pendlum')
26+
mpl.title('Inverted pendulum')
2727

2828
# Outer trajectories
2929
phase_plot(invpend_ode,
@@ -35,9 +35,7 @@ def invpend_ode(x, t, m=1., l=1., b=0.2, g=1):
3535
logtime = (3, 0.7) )
3636

3737
# Separatrices
38-
mpl.hold(True);
3938
phase_plot(invpend_ode, X0 = [[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0)
40-
mpl.show();
4139

4240
#
4341
# Systems of ODEs: damped oscillator example (simulation + phase portrait)
@@ -49,9 +47,10 @@ def oscillator_ode(x, t, m=1., b=1, k=1):
4947
# Generate a vector plot for the damped oscillator
5048
mpl.figure(); mpl.clf();
5149
phase_plot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15);
52-
mpl.hold(True); mpl.plot([0], [0], '.');
50+
#mpl.plot([0], [0], '.');
5351
# a=gca; set(a,'FontSize',20); set(a,'DataAspectRatio',[1,1,1]);
54-
mpl.xlabel('x1'); mpl.ylabel('x2');
52+
mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$');
53+
mpl.title('Damped oscillator, vector field')
5554

5655
# Generate a phase plot for the damped oscillator
5756
mpl.figure(); mpl.clf();
@@ -61,11 +60,10 @@ def oscillator_ode(x, t, m=1., b=1, k=1):
6160
[-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1],
6261
[1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1]
6362
], T = np.linspace(0, 8, 80), timepts = [0.25, 0.8, 2, 3])
64-
mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
63+
mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
6564
# set(gca,'DataAspectRatio',[1,1,1]);
66-
mpl.xlabel('x1'); mpl.ylabel('x2');
67-
68-
mpl.show()
65+
mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$');
66+
mpl.title('Damped oscillator, vector field and stream lines')
6967

7068
#
7169
# Stability definitions
@@ -88,9 +86,10 @@ def saddle_ode(x, t):
8886
[-1.3,-1]
8987
], T = np.linspace(0, 10, 100),
9088
timepts = [0.3, 1, 2, 3], parms = (m, b, k));
91-
mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
89+
mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
9290
# set(gca,'FontSize', 16);
93-
mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2');
91+
mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$');
92+
mpl.title('Asymptotically stable point')
9493

9594
# Saddle
9695
mpl.figure(); mpl.clf();
@@ -103,9 +102,10 @@ def saddle_ode(x, t):
103102
[0.95, 1], [0.9, 1], [0.8, 1], [0.6, 1], [0.4, 1], [0.2, 1],
104103
[-0.5, -0.45], [-0.45, -0.5], [0.5, 0.45], [0.45, 0.5],
105104
[-0.04, 0.04], [0.04, -0.04] ], T = np.linspace(0, 2, 20));
106-
mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
105+
mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3);
107106
# set(gca,'FontSize', 16);
108-
mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2');
107+
mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$');
108+
mpl.title('Saddle point')
109109

110110
# Stable isL
111111
m = 1; b = 0; k = 1; # zero damping
@@ -115,8 +115,9 @@ def saddle_ode(x, t):
115115
[pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi],
116116
X0 = [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ],
117117
T = np.linspace(0, 20, 200), parms = (m, b, k));
118-
mpl.hold(True); mpl.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3);
118+
mpl.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3);
119119
# set(gca,'FontSize', 16);
120-
mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2');
120+
mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$');
121+
mpl.title('Undamped system\nLyapunov stable, not asympt. stable')
121122

122123
mpl.show()

0 commit comments

Comments
 (0)