[Matplotlib-users] Replacing deprecated use of pyplot.subplot

Eric Firing efiring at hawaii.edu
Sat Jan 20 16:52:37 EST 2018


Rory,

The general direction of Matplotlib's evolution is toward encouraging 
more explicit code, so that the programmer or user has more 
responsibility for specifying which figure and axes are to be used, 
rather than relying on the state machine and the concepts of "current 
figure" and "current axes".  Therefore we recommend using pyplot 
functions very sparingly.

If you need to keep your API exactly as it is, your approach using 
labels looks reasonable.  I think it can be simplified, though, by 
defining a helper function something like this:

def _get_bode_axes():
     fig = plt.gcf()
     if not hasattr(fig, '_bode_axes'):
         fig.clf()
         fig._bode_axes = fig.subplots(2, 1, sharex=True)
     return fig._bode_axes

Then, outside any loop in plot_bode but conditional on the Plot kwarg, 
use a single call:

     ax_mag, ax_phase = _get_bode_axes()

Also conditional on Plot, put your loop over syslist to do the plotting. 
  I would make that loop separate from the calculation.  In general, 
code is clearer and easier to test when calculations are separated from 
plotting, ideally with separate functions.

You could also use the initialization block inside _get_bode_axes to 
customize the axes with respect to grid, labels...anything that you 
don't want to change as you add lines to the plot, and that you can set 
once with the first call to plot_bode and won't potentially need to 
change in subsequent calls that write to the same figure.  Or you could 
do that sort of customization outside and after the loop that plots the 
lines.

Eric


On 2018/01/20 9:44 AM, Rory Yorke wrote:
> Hi,
> 
> I'm a contributor to the Python Control Systems Library [1], which uses
> Matplotlib for plotting.
> 
> We recently noticed deprecation warnings due to how we use
> pyplot.subplot.  We use it in the Matlab manner of either getting a
> handle to an existing axis, or creating one if no suitable axis exists.
> 
> The warning is
> 
>    MatplotlibDeprecationWarning: Adding an axes using the same arguments
>    as a previous axes currently reuses the earlier instance.  In a future
>    version, a new instance will always be created and returned.
>    Meanwhile, this warning can be suppressed, and the future behavior
>    ensured, by passing a unique label to each axes instance.
> 
> For example, to plot the frequency response a linear dynamical system
> (AKA Bode plot of the system), the relevant function could be simplified
> to:
> 
>      def bode_plot(g):
>         freq, mag, phase = freq_resp(g)
>         subplot(211)
>         semilogx(freq, 20*log10(mag))
>         subplot(212)
>         semilogx(freq, phase)
> 
> We've replaced that with code like this:
> 
>      def bode_plot(g):
>         freq, mag, phase = freq_resp(g)
> 
>         ax_mag = None
>         ax_phase = None
>         for ax in gcf.axes():
>             if ax.get_label() == 'control-bode-magnitude':
>               ax_mag = ax
>             elif ax.get_label() == 'control-bode-phase':
>               ax_phase = ax
> 
>         if ax_mag is None or ax_phase is None:
>           clf()
>           ax_mag = subplot(211, label = 'control-bode-magnitude')
>           ax_phase = subplot(212, label = 'control-bode-phase)
> 
>         ax_mag.semilogx(freq, 20*log10(mag))
>         ax_phase.semilogx(freq, phase)
>         
> This means that calls like
> 
>      bode_plot(g)
>      bode_plot(h)
> 
> will show the response of g and h on the same figure.
> 
> Is this method of using labels to check for existing axes reasonable?
> Is there a better way?
> 
> Actual code exhibiting warnings at [2]; new code at [3].  The latter
> link is to an as-yet unmerged branch, and may disappear.
> 
> Thanks,
> 
> Rory
> 
> [1] https://github.com/python-control/python-control
> [2] https://github.com/python-control/python-control/blob/af8d4ee39dfa574c2b3b335f4cdb4be858ae469a/control/freqplot.py#L175
> [3] https://github.com/murrayrm/python-control/blob/dc1820a4e64d73937c7de8df078c41ec1773e048/control/freqplot.py#L138
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users
> 



More information about the Matplotlib-users mailing list