10000 implement pole_zero_subplots · toaster-code/python-control@4f3d618 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f3d618

Browse files
committed
implement pole_zero_subplots
1 parent 0103fe7 commit 4f3d618

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

control/ctrlplot.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#
7373
# return ControlPlot(lines, ax_array, fig, legend=legend_map)
7474

75+
import itertools
7576
import warnings
7677
from os.path import commonprefix
7778

@@ -81,7 +82,7 @@
8182

8283
from . import config
8384

84-
__all__ = ['ControlPlot', 'suptitle', 'get_plot_axes']
85+
__all__ = ['ControlPlot', 'suptitle', 'get_plot_axes', 'pole_zero_subplots']
8586

8687
#
8788
# Style parameters
@@ -241,14 +242,76 @@ def get_plot_axes(line_array):
241242
else:
242243
return _get_axes(line_array)
243244

245+
246+
def pole_zero_subplots(
247+
nrows, ncols, grid=None, dt=None, fig=None, scaling=None,
248+
rcParams=None):
249+
"""Create axes for pole/zero plot.
250+
251+
Parameters
252+
----------
253+
nrows, ncols : int
254+
Number of rows and columns
255+
grid : True, False, or 'empty', optional
256+
Grid style to use. Can also be a list, in which case each subplot
257+
will have a different style (columns then rows).
258+
dt : timebase, option
259+
Timebase for each subplot (or a list of timebases).
260+
scaling : 'auto', 'equal', or None
261+
Scaling to apply to the subplots.
262+
fig : :class:`matplotlib.figure.Figure`
263+
Figure to use for creating subplots.
264+
265+
Returns
266+
-------
267+
ax_array : array
268+
2D array of axes
269+
270+
"""
271+
from .grid import sgrid, zgrid, nogrid
272+
from .iosys import isctime
273+
274+
if rcParams is None:
275+
rcParams = _ctrlplot_rcParams
276+
277+
if fig is None:
278+
fig = plt.gcf()
279+
280+
if not isinstance(grid, list):
281+
grid = [grid] * nrows * ncols
282+
if not isinstance(dt, list):
283+
dt = [dt] * nrows * ncols
284+
285+
ax_array = np.full((nrows, ncols), None)
286+
index = 0
287+
with plt.rc_context(rcParams):
288+
for row, col in itertools.product(range(nrows), range(ncols)):
289+
match grid[index], isctime(dt=dt[index]):
290+
case 'empty', _: # empty grid
291+
ax_array[row, col] = fig.add_subplot(nrows, ncols, index+1)
292+
293+
case True, True: # continuous time grid
294+
ax_array[row, col], _ = sgrid(
295+
(nrows, ncols, index+1), scaling=scaling)
296+
297+
case True, False: # discrete time grid
298+
ax_array[row, col] = fig.add_subplot(nrows, ncols, index+1)
299+
zgrid(ax=ax_array[row, col], scaling=scaling)
300+
301+
case False | None, _: # no grid (just stability boundaries)
302+
ax_array[row, col] = fig.add_subplot(nrows, ncols, index+1)
303+
nogrid(
304+
ax=ax_array[row, col], dt=dt[index], scaling=scaling)
305+
index += 1
306+
return ax_array
307+
244308
#
245309
# Utility functions
246310
#
247311
# These functions are used by plotting routines to provide a consistent way
248312
# of processing and displaying information.
249313
#
250314

251-
252315
def _process_ax_keyword(
253316
axs, shape=(1, 1), rcParams=None, squeeze=False, clear_text=False,
254317
create_axes=True):

control/grid.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def __call__(self, transform_xy, x1, y1, x2, y2):
7474
return lon_min, lon_max, lat_min, lat_max
7575

7676

77-
def sgrid(scaling=None):
77+
def sgrid(subplot=(1, 1, 1), scaling=None):
7878
# From matplotlib demos:
7979
# https://matplotlib.org/gallery/axisartist/demo_curvelinear_grid.html
8080
# https://matplotlib.org/gallery/axisartist/demo_floating_axis.html
@@ -101,7 +101,7 @@ def sgrid(scaling=None):
101101

102102
# Set up an axes with a specialized grid helper
103103
fig = plt.gcf()
104-
ax = SubplotHost(fig, 1, 1, 1, grid_helper=grid_helper)
104+
ax = SubplotHost(fig, *subplot, grid_helper=grid_helper)
105105

106106
# make ticklabels of right invisible, and top axis visible.
107107
visible = True

control/sisotool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def sisotool(sys, initial_gain=None, xlim_rlocus=None, ylim_rlocus=None,
136136
# ax=fig.axes[1])
137137
ax_rlocus = fig.axes[1]
138138
root_locus_map(sys[0, 0]).plot(
139-
xlim=xlim_rlocus, ylim=ylim_rlocus, grid=rlocus_grid,
139+
xlim=xlim_rlocus, ylim=ylim_rlocus,
140140
initial_gain=initial_gain, ax=ax_rlocus)
141141
if rlocus_grid is False:
142142
# Need to generate grid manually, since root_locus_plot() won't

examples/plot_gallery.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,13 @@ def invpend_update(t, x, u, params):
120120

121121
# root locus
122122
with create_figure("Root locus plot") as fig:
123-
ax1, ax2 = fig.subplots(2, 1)
123+
ax_array = ct.pole_zero_subplots(2, 1, grid=[True, False])
124+
ax1, ax2 = ax_array[:, 0]
124125
sys1 = ct.tf([1, 2], [1, 2, 3], name='sys1')
125126
sys2 = ct.tf([1, 0.2], [1, 1, 3, 1, 1], name='sys2')
126-
ct.root_locus_plot([sys1, sys2], grid=True, ax=ax1)
127-
ct.root_locus_plot([sys1, sys2], grid=False, ax=ax2)
128-
ct.suptitle("Root locus plots (w/ specified axes)")
129-
print(" -- BUG: should have 2 x 1 array of plots")
127+
ct.root_locus_plot([sys1, sys2], ax=ax1)
128+
ct.root_locus_plot([sys1, sys2], ax=ax2)
129+
plt.suptitle("Root locus plots (w/ specified axes)", fontsize='medium')
130130

131131
# sisotool
132132
with create_figure("sisotool"):

0 commit comments

Comments
 (0)
0