Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6ede92e

Browse files
authored
Merge pull request#456 from bnavigator/fix-mpl-grid
Fix pzmap grid (matplotlib angle_helper)
2 parents08d5e6c +5632796 commit6ede92e

File tree

4 files changed

+147
-13
lines changed

4 files changed

+147
-13
lines changed

‎control/grid.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,20 @@
1212
classFormatterDMS(object):
1313
'''Transforms angle ticks to damping ratios'''
1414
def__call__(self,direction,factor,values):
15-
angles_deg=values/factor
15+
angles_deg=np.asarray(values)/factor
1616
damping_ratios=np.cos((180-angles_deg)*np.pi/180)
1717
ret= ["%.2f"%valforvalindamping_ratios]
1818
returnret
1919

2020

2121
classModifiedExtremeFinderCycle(angle_helper.ExtremeFinderCycle):
22-
'''Changed to allow only left hand-side polar grid'''
22+
'''Changed to allow only left hand-side polar grid
23+
24+
https://matplotlib.org/_modules/mpl_toolkits/axisartist/angle_helper.html#ExtremeFinderCycle.__call__
25+
'''
2326
def__call__(self,transform_xy,x1,y1,x2,y2):
24-
x_,y_=np.linspace(x1,x2,self.nx),np.linspace(y1,y2,self.ny)
25-
x,y=np.meshgrid(x_,y_)
27+
x,y=np.meshgrid(
28+
np.linspace(x1,x2,self.nx),np.linspace(y1,y2,self.ny))
2629
lon,lat=transform_xy(np.ravel(x),np.ravel(y))
2730

2831
withnp.errstate(invalid='ignore'):
@@ -31,17 +34,33 @@ def __call__(self, transform_xy, x1, y1, x2, y2):
3134
# Changed from 180 to 360 to be able to span only
3235
# 90-270 (left hand side)
3336
lon-=360.* ((lon-lon0)>360.)
34-
ifself.lat_cycleisnotNone:
37+
ifself.lat_cycleisnotNone:# pragma: no cover
3538
lat0=np.nanmin(lat)
36-
# Changed from 180 to 360 to be able to span only
37-
# 90-270 (left hand side)
38-
lat-=360.* ((lat-lat0)>360.)
39+
lat-=360.* ((lat-lat0)>180.)
3940

4041
lon_min,lon_max=np.nanmin(lon),np.nanmax(lon)
4142
lat_min,lat_max=np.nanmin(lat),np.nanmax(lat)
4243

4344
lon_min,lon_max,lat_min,lat_max= \
44-
self._adjust_extremes(lon_min,lon_max,lat_min,lat_max)
45+
self._add_pad(lon_min,lon_max,lat_min,lat_max)
46+
47+
# check cycle
48+
ifself.lon_cycle:
49+
lon_max=min(lon_max,lon_min+self.lon_cycle)
50+
ifself.lat_cycle:# pragma: no cover
51+
lat_max=min(lat_max,lat_min+self.lat_cycle)
52+
53+
ifself.lon_minmaxisnotNone:
54+
min0=self.lon_minmax[0]
55+
lon_min=max(min0,lon_min)
56+
max0=self.lon_minmax[1]
57+
lon_max=min(max0,lon_max)
58+
59+
ifself.lat_minmaxisnotNone:
60+
min0=self.lat_minmax[0]
61+
lat_min=max(min0,lat_min)
62+
max0=self.lat_minmax[1]
63+
lat_max=min(max0,lat_max)
4564

4665
returnlon_min,lon_max,lat_min,lat_max
4766

‎control/pzmap.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
# TODO: Implement more elegant cross-style axes. See:
5959
# http://matplotlib.sourceforge.net/examples/axes_grid/demo_axisline_style.html
6060
# http://matplotlib.sourceforge.net/examples/axes_grid/demo_curvelinear_grid.html
61-
defpzmap(sys,plot=True,grid=False,title='Pole Zero Map',**kwargs):
61+
defpzmap(sys,plot=None,grid=None,title='Pole Zero Map',**kwargs):
6262
"""
6363
Plot a pole/zero map for a linear system.
6464
@@ -87,8 +87,8 @@ def pzmap(sys, plot=True, grid=False, title='Pole Zero Map', **kwargs):
8787
plot=kwargs['Plot']
8888

8989
# Get parameter values
90-
plot=config._get_param('rlocus','plot',plot,True)
91-
grid=config._get_param('rlocus','grid',grid,False)
90+
plot=config._get_param('pzmap','plot',plot,True)
91+
grid=config._get_param('pzmap','grid',grid,False)
9292

9393
ifnotisinstance(sys,LTI):
9494
raiseTypeError('Argument ``sys``: must be a linear system.')

‎control/tests/conftest.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
11
# contest.py - pytest local plugins and fixtures
22

3-
importcontrol
43
importos
54

5+
importmatplotlibasmpl
66
importpytest
77

8+
importcontrol
9+
810

911
@pytest.fixture(scope="session",autouse=True)
1012
defuse_numpy_ndarray():
1113
"""Switch the config to use ndarray instead of matrix"""
1214
ifos.getenv("PYTHON_CONTROL_STATESPACE_ARRAY")=="1":
1315
control.config.defaults['statesp.use_numpy_matrix']=False
16+
17+
18+
@pytest.fixture(scope="function")
19+
defeditsdefaults():
20+
"""Make sure any changes to the defaults only last during a test"""
21+
restore=control.config.defaults.copy()
22+
yield
23+
control.config.defaults.update(restore)
24+
25+
26+
@pytest.fixture(scope="function")
27+
defmplcleanup():
28+
"""Workaround for python2
29+
30+
python 2 does not like to mix the original mpl decorator with pytest
31+
fixtures. So we roll our own.
32+
"""
33+
save=mpl.units.registry.copy()
34+
try:
35+
yield
36+
finally:
37+
mpl.units.registry.clear()
38+
mpl.units.registry.update(save)
39+
mpl.pyplot.close("all")

‎control/tests/pzmap_test.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# -*- coding: utf-8 -*-
2+
""" pzmap_test.py - test pzmap()
3+
4+
Created on Thu Aug 20 20:06:21 2020
5+
6+
@author: bnavigator
7+
"""
8+
9+
importmatplotlib
10+
importnumpyasnp
11+
importpytest
12+
frommatplotlibimportpyplotasplt
13+
frommpl_toolkits.axisartistimportAxesasmpltAxes
14+
15+
fromcontrolimportTransferFunction,config,pzmap
16+
17+
18+
@pytest.mark.parametrize("kwargs",
19+
[pytest.param(dict(),id="default"),
20+
pytest.param(dict(plot=False),id="plot=False"),
21+
pytest.param(dict(plot=True),id="plot=True"),
22+
pytest.param(dict(grid=True),id="grid=True"),
23+
pytest.param(dict(title="My Title"),id="title")])
24+
@pytest.mark.parametrize("setdefaults", [False,True],ids=["kw","config"])
25+
@pytest.mark.parametrize("dt", [0,1],ids=["s","z"])
26+
deftest_pzmap(kwargs,setdefaults,dt,editsdefaults,mplcleanup):
27+
"""Test pzmap"""
28+
# T from from pvtol-nested example
29+
T=TransferFunction([-9.0250000e-01,-4.7200750e+01,-8.6812900e+02,
30+
+5.6261850e+03,+2.1258472e+05,+8.4724600e+05,
31+
+1.0192000e+06,+2.3520000e+05],
32+
[9.02500000e-03,9.92862812e-01,4.96974094e+01,
33+
1.35705659e+03,2.09294163e+04,1.64898435e+05,
34+
6.54572220e+05,1.25274600e+06,1.02420000e+06,
35+
2.35200000e+05],
36+
dt)
37+
38+
Pref= [-23.8877+19.3837j,-23.8877-19.3837j,-23.8349+15.7846j,
39+
-23.8349-15.7846j,-5.2320+0.4117j,-5.2320-0.4117j,
40+
-2.2246+0.0000j,-1.5160+0.0000j,-0.3627+0.0000j]
41+
Zref= [-23.8877+19.3837j,-23.8877-19.3837j,+14.3637+0.0000j,
42+
-14.3637+0.0000j,-2.2246+0.0000j,-2.0000+0.0000j,
43+
-0.3000+0.0000j]
44+
45+
pzkwargs=kwargs.copy()
46+
ifsetdefaults:
47+
forkin ['plot','grid']:
48+
ifkinpzkwargs:
49+
v=pzkwargs.pop(k)
50+
config.set_defaults('pzmap',**{k:v})
51+
52+
P,Z=pzmap(T,**pzkwargs)
53+
54+
np.testing.assert_allclose(P,Pref,rtol=1e-3)
55+
np.testing.assert_allclose(Z,Zref,rtol=1e-3)
56+
57+
ifkwargs.get('plot',True):
58+
ax=plt.gca()
59+
60+
assertax.get_title()==kwargs.get('title','Pole Zero Map')
61+
62+
# FIXME: This won't work when zgrid and sgrid are unified
63+
children=ax.get_children()
64+
has_zgrid=False
65+
forcinchildren:
66+
ifisinstance(c,matplotlib.text.Annotation):
67+
ifr'\pi'inc.get_text():
68+
has_zgrid=True
69+
has_sgrid=isinstance(ax,mpltAxes)
70+
71+
ifkwargs.get('grid',False):
72+
assertdt==has_zgrid
73+
assertdt!=has_sgrid
74+
else:
75+
assertnothas_zgrid
76+
assertnothas_sgrid
77+
else:
78+
assertnotplt.get_fignums()
79+
80+
81+
deftest_pzmap_warns():
82+
withpytest.warns(FutureWarning):
83+
pzmap(TransferFunction([1], [1,2]),Plot=True)
84+
85+
86+
deftest_pzmap_raises():
87+
withpytest.raises(TypeError):
88+
# not an LTI system
89+
pzmap(([1], [1,2]))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp