<div dir="ltr">Errr, make that last line:<div><br></div><div><span style="font-size:12.8px;font-family:monospace,monospace">h_mpl = bode_plot(h, ax_mag=g_mpl['axes'][0], ax_phase=</span><span style="font-size:12.8px;font-family:monospace,monospace">g_mpl['axes']<b><u><i>[1]</i></u></b>)</span><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jan 20, 2018 at 1:02 PM, Paul Hobson <span dir="ltr"><<a href="mailto:pmhobson@gmail.com" target="_blank">pmhobson@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hey Rory,<div><br></div><div>In general, especially for library code, you should avoid relying on the pyplot state machine.</div><div><br></div><div>That means explicitly passing Axes and Figure object around to and from your functions.</div><div><br></div><div>For me, making that switch meant added an `ax=None` kwarg to the end of my function signatures.</div><div><br></div><div>Then I carry around an axes_validator function that looks something like this:</div><div><a href="https://github.com/matplotlib/mpl-probscale/blob/master/probscale/validate.py#L6" target="_blank">https://github.com/matplotlib/<wbr>mpl-probscale/blob/master/<wbr>probscale/validate.py#L6</a><br></div><div><br></div><div>But that's not really necessary. So in your case, I think you should do something like this:</div><div><br></div><div><br></div><div><div><font face="monospace, monospace"><span style="font-size:12.8px">import numpy as np</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px">import matplotlib.pyplot as plt</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px">def bode_plot(g, ax_mag=None, ax_phase=None, mag_opts=None, phase_opts=None):</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # create axes if they're not both supplied</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> if not ax_mag or not ax_phase:</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> fig, (ax_mag, ax_phase) = plt.subplots(nrows=2)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # make the plotting options empty dicts if</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # not supplied</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> if not mag_opts:</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> mag_opts = {}</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> if not phase_opts:</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> phase_opts = {}</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # compute signal stuff</span></font></div><span class=""><div><font face="monospace, monospace"><span style="font-size:12.8px"> freq, mag, phase = freq_resp(g)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div></span><div><font face="monospace, monospace"><span style="font-size:12.8px"> # 99% sure semilogx returns a tuple of artists, so I unpack it</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # you should check this though</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> mag_artist, = ax_mag.semilogx(freq, 20 * np.log10(mag), **mag_opts)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> phase_artist, = ax_phase.semilogx(freq, phase, **phase_opts)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> </span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> # package the output for later (if you want to modify artists)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> output = {</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> 'fig': fig,</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> 'axes': (ax_mag, ax_phase),</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> 'arists': (mag_artist, phase_artist)</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> }</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"> return output</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div>And then you'd use the code like this:<font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px"><br></span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px">fig, (ax_mag, ax_phase) = plt.subplots(nrows=2, figsize=(12, 6))</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px">g_mpl = bode_plot(g, ax_mag=ax_mag, ax_phase=ax_phase, color='r', linewidth=2, label='G')</span></font></div><div><font face="monospace, monospace"><span style="font-size:12.8px">h_mpl = bode_plot(h, ax_mag=ax_mag, ax_phase=ax_phase, color='b'm linewidth=1, label='H')</span></font></div></div><div><font face="monospace, monospace"><span style="font-size:12.8px">ax_mag.legend()</span></font></div><div><br></div><div><br></div><div>Or do something like this:</div><div><span style="font-family:monospace,monospace;font-size:12.8px">g_mpl = bode_plot(g, color='r', linewidth=2, label='G')</span><br></div><div><span style="font-family:monospace,monospace;font-size:12.8px">h_mpl = bode_plot(h, ax_mag=g_mpl['axes'][0], ax_phase=</span><span style="font-family:monospace,monospace;font-size:12.8px">g_mpl['axes'][0])</span><span style="font-family:monospace,monospace;font-size:12.8px"><br></span></div><div><span style="font-family:monospace,monospace;font-size:12.8px"><br></span></div><div><span style="font-family:monospace,monospace;font-size:12.8px"><br></span></div><div>Does that help?<span class="HOEnZb"><font color="#888888"><br></font></span></div><span class="HOEnZb"><font color="#888888"><div>-Paul</div><div><br></div></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jan 20, 2018 at 11:44 AM, Rory Yorke <span dir="ltr"><<a href="mailto:rory.yorke@gmail.com" target="_blank">rory.yorke@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
I'm a contributor to the Python Control Systems Library [1], which uses<br>
Matplotlib for plotting.<br>
<br>
We recently noticed deprecation warnings due to how we use<br>
pyplot.subplot. We use it in the Matlab manner of either getting a<br>
handle to an existing axis, or creating one if no suitable axis exists.<br>
<br>
The warning is<br>
<br>
MatplotlibDeprecationWarning: Adding an axes using the same arguments<br>
as a previous axes currently reuses the earlier instance. In a future<br>
version, a new instance will always be created and returned.<br>
Meanwhile, this warning can be suppressed, and the future behavior<br>
ensured, by passing a unique label to each axes instance.<br>
<br>
For example, to plot the frequency response a linear dynamical system<br>
(AKA Bode plot of the system), the relevant function could be simplified<br>
to:<br>
<br>
def bode_plot(g):<br>
freq, mag, phase = freq_resp(g)<br>
subplot(211)<br>
semilogx(freq, 20*log10(mag))<br>
subplot(212)<br>
semilogx(freq, phase)<br>
<br>
We've replaced that with code like this:<br>
<br>
def bode_plot(g):<br>
freq, mag, phase = freq_resp(g)<br>
<br>
ax_mag = None<br>
ax_phase = None<br>
for ax in gcf.axes():<br>
if ax.get_label() == 'control-bode-magnitude':<br>
ax_mag = ax<br>
elif ax.get_label() == 'control-bode-phase':<br>
ax_phase = ax<br>
<br>
if ax_mag is None or ax_phase is None:<br>
clf()<br>
ax_mag = subplot(211, label = 'control-bode-magnitude')<br>
ax_phase = subplot(212, label = 'control-bode-phase)<br>
<br>
ax_mag.semilogx(freq, 20*log10(mag))<br>
ax_phase.semilogx(freq, phase)<br>
<br>
This means that calls like<br>
<br>
bode_plot(g)<br>
bode_plot(h)<br>
<br>
will show the response of g and h on the same figure.<br>
<br>
Is this method of using labels to check for existing axes reasonable?<br>
Is there a better way?<br>
<br>
Actual code exhibiting warnings at [2]; new code at [3]. The latter<br>
link is to an as-yet unmerged branch, and may disappear.<br>
<br>
Thanks,<br>
<br>
Rory<br>
<br>
[1] <a href="https://github.com/python-control/python-control" rel="noreferrer" target="_blank">https://github.com/python-cont<wbr>rol/python-control</a><br>
[2] <a href="https://github.com/python-control/python-control/blob/af8d4ee39dfa574c2b3b335f4cdb4be858ae469a/control/freqplot.py#L175" rel="noreferrer" target="_blank">https://github.com/python-cont<wbr>rol/python-control/blob/af8d4e<wbr>e39dfa574c2b3b335f4cdb4be858ae<wbr>469a/control/freqplot.py#L175</a><br>
[3] <a href="https://github.com/murrayrm/python-control/blob/dc1820a4e64d73937c7de8df078c41ec1773e048/control/freqplot.py#L138" rel="noreferrer" target="_blank">https://github.com/murrayrm/py<wbr>thon-control/blob/dc1820a4e64d<wbr>73937c7de8df078c41ec1773e048/<wbr>control/freqplot.py#L138</a><br>
______________________________<wbr>_________________<br>
Matplotlib-users mailing list<br>
<a href="mailto:Matplotlib-users@python.org" target="_blank">Matplotlib-users@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/matplotlib-users" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/matplotlib-users</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>