31
31
@pytest .mark .parametrize (
32
32
"sys" , [
33
33
ct .tf ([1 ], [1 , 2 , 1 ], name = 'System 1' ), # SISO
34
- manual_response , # simple MIMO
34
+ manual_response , # simple MIMO
35
35
])
36
36
# @pytest.mark.parametrize("pltmag", [True, False])
37
37
# @pytest.mark.parametrize("pltphs", [True, False])
40
40
# @pytest.mark.parametrize("shrfrq", ['col', 'all', False, None])
41
41
# @pytest.mark.parametrize("secsys", [False, True])
42
42
@pytest .mark .parametrize ( # combinatorial-style test (faster)
43
- "pltmag, pltphs, shrmag, shrphs, shrfrq, secsys" ,
44
- [(True , True , None , None , None , False ),
45
- (True , False , None , None , None , False ),
46
- (False , True , None , None , None , False ),
47
- (True , True , None , None , None , True ),
48
- (True , True , 'row' , 'row' , 'col' , False ),
49
- (True , True , 'row' , 'row' , 'all' , True ),
50
- (True , True , 'all' , 'row' , None , False ),
51
- (True , True , 'row' , 'all' , None , True ),
52
- (True , True , 'none' , 'none' , None , True ),
53
- (True , False , 'all' , 'row' , None , False ),
54
- (True , True , True , 'row' , None , True ),
55
- (True , True , None , 'row' , True , False ),
56
- (True , True , 'row' , None , None , True ),
43
+ "pltmag, pltphs, shrmag, shrphs, shrfrq, ovlout, ovlinp, secsys" ,
44
+ [(True , True , None , None , None , False , False , False ),
45
+ (True , False , None , None , None , True , False , False ),
46
+ (False , True , None , None , None , False , True , False ),
47
+ (True , True , None , None , None , False , False , True ),
48
+ (True , True , 'row' , 'row' , 'col' , False , False , False ),
49
+ (True , True , 'row' , 'row' , 'all' , False , False , True ),
50
+ (True , True , 'all' , 'row' , None , False , False , False ),
51
+ (True , True , 'row' , 'all' , None , False , False , True ),
52
+ (True , True , 'none' , 'none' , None , False , False , True ),
53
+ (True , False , 'all' , 'row' , None , False , False , False ),
54
+ (True , True , True , 'row' , None , False , False , True ),
55
+ (True , True , None , 'row' , True , False , False , False ),
56
+ (True , True , 'row' , None , None , False , False , True ),
57
57
])
58
58
def test_response_plots (
59
- sys , pltmag , pltphs , shrmag , shrphs , shrfrq , secsys , clear = True ):
59
+ sys , pltmag , pltphs , shrmag , shrphs , shrfrq , ovlout , ovlinp ,
60
+ secsys , clear = True ):
60
61
61
62
# Save up the keyword arguments
62
63
kwargs = dict (
63
64
plot_magnitude = pltmag , plot_phase = pltphs ,
64
65
share_magnitude = shrmag , share_phase = shrphs , share_frequency = shrfrq ,
65
- # overlay_outputs=ovlout, overlay_inputs=ovlinp
66
+ overlay_outputs = ovlout , overlay_inputs = ovlinp
66
67
)
67
68
68
69
# Create the response
@@ -79,6 +80,16 @@ def test_response_plots(
79
80
plt .figure ()
80
81
out = response .plot (** kwargs )
81
82
83
+ # Check the shape
84
+ if ovlout and ovlinp :
85
+ assert out .shape == (pltmag + pltphs , 1 )
86
+ elif ovlout :
87
+ assert out .shape == (pltmag + pltphs , sys .ninputs )
88
+ elif ovlinp :
89
+ assert out .shape == (sys .noutputs * (pltmag + pltphs ), 1 )
90
+ else :
91
+ assert out .shape == (sys .noutputs * (pltmag + pltphs ), sys .ninputs )
92
+
82
93
# Make sure all of the outputs are of the right type
83
94
nlines_plotted = 0
84
95
for ax_lines in np .nditer (out , flags = ["refs_ok" ]):
@@ -198,19 +209,83 @@ def test_first_arg_listable(response_cmd, return_type):
198
209
result = response_cmd (sys )
199
210
assert isinstance (result , return_type )
200
211
212
+ # Save the results from a single plot
213
+ lines_single = result .plot ()
214
+
201
215
# If we pass a list of systems, we should get back a list
202
216
result = response_cmd ([sys , sys , sys ])
203
217
assert isinstance (result , list )
204
218
assert len (result ) == 3
205
219
assert all ([isinstance (item , return_type ) for item in result ])
206
220
221
+ # Make sure that plot works
222
+ lines_list = result .plot ()
223
+ if response_cmd == ct .frequency_response :
224
+ assert lines_list .shape == lines_single .shape
225
+ assert len (lines_list .reshape (- 1 )[0 ]) == \
226
+ 3 * len (lines_single .reshape (- 1 )[0 ])
227
+ else :
228
+ assert lines_list .shape [0 ] == 3 * lines_single .shape [0 ]
229
+
207
230
# If we pass a singleton list, we should get back a list
208
231
result = response_cmd ([sys ])
209
232
assert isinstance (result , list )
210
233
assert len (result ) == 1
211
234
assert isinstance (result [0 ], return_type )
212
235
213
236
237
+ def test_bode_share_options ():
238
+ # Default sharing should share along rows and cols for mag and phase
239
+ lines = ct .bode_plot (manual_response )
240
+ axs = ct .get_plot_axes (lines )
241
+ for i in range (axs .shape [0 ]):
242
+ for j in range (axs .shape [1 ]):
243
+ # Share y limits along rows
244
+ assert axs [i , j ].get_ylim () == axs [i , 0 ].get_ylim ()
245
+
246
+ # Share x limits along columns
247
+ assert axs [i , j ].get_xlim () == axs [- 1 , j ].get_xlim ()
248
+
249
+ # Sharing along y axis for mag but not phase
250
+ plt .figure ()
251
+ lines = ct .bode_plot (manual_response , share_phase = 'none' )
252
+ axs = ct .get_plot_axes (lines )
253
+ for i in range (int (axs .shape [0 ] / 2 )):
254
+ for j in range (axs .shape [1 ]):
255
+ if i != 0 :
256
+ # Different rows are different
257
+ assert axs [i * 2 + 1 , 0 ].get_ylim () != axs [1 , 0 ].get_ylim ()
258
+ elif j != 0 :
259
+ # Different columns are different
260
+ assert axs [i * 2 + 1 , j ].get_ylim () != axs [i * 2 + 1 , 0 ].get_ylim ()
261
+
262
+ # Turn off sharing for magnitude and phase
263
+ plt .figure ()
264
+ lines = ct .bode_plot (manual_response , sharey = 'none' )
265
+ axs = ct .get_plot_axes (lines )
266
+ for i in range (int (axs .shape [0 ] / 2 )):
267
+ for j in range (axs .shape [1 ]):
268
+ if i != 0 :
269
+ # Different rows are different
270
+ assert axs [i * 2 , 0 ].get_ylim () != axs [0 , 0 ].get_ylim ()
271
+ assert axs [i * 2 + 1 , 0 ].get_ylim () != axs [1 , 0 ].get_ylim ()
272
+ elif j != 0 :
273
+ # Different columns are different
274
+ assert axs [i * 2 , j ].get_ylim () != axs [i * 2 , 0 ].get_ylim ()
275
+ assert axs [i * 2 + 1 , j ].get_ylim () != axs [i * 2 + 1 , 0 ].get_ylim ()
276
+
277
+ # Turn off sharing in x axes
278
+ plt .figure ()
279
+ lines = ct .bode_plot (manual_response , sharex = 'none' )
280
+ # TODO: figure out what to check
281
+
282
+
283
+ def test_bode_errors ():
284
+ # Turning off both magnitude and phase
285
+ with pytest .raises (ValueError , match = "no data to plot" ):
286
+ ct .bode_plot (manual_response , plot_magnitude = False , plot_phase = False )
287
+
288
+
214
289
if __name__ == "__main__" :
215
290
#
216
291
# Interactive mode: generate plots for manual viewing
0 commit comments