@@ -140,6 +140,25 @@ def test_label_shift():
140
140
assert ax .yaxis .get_label ().get_horizontalalignment ()== "center"
141
141
142
142
143
+ @check_figures_equal (extensions = ["png" ])
144
+ def test_acorr (fig_test ,fig_ref ):
145
+ np .random .seed (19680801 )
146
+ Nx = 512
147
+ x = np .random .normal (0 ,1 ,Nx ).cumsum ()
148
+ maxlags = Nx - 1
149
+
150
+ ax_test = fig_test .subplots ()
151
+ ax_test .acorr (x ,maxlags = maxlags )
152
+
153
+ ax_ref = fig_ref .subplots ()
154
+ # Normalized autocorrelation
155
+ norm_auto_corr = np .correlate (x ,x ,mode = "full" )/ np .dot (x ,x )
156
+ lags = np .arange (- maxlags ,maxlags + 1 )
157
+ norm_auto_corr = norm_auto_corr [Nx - 1 - maxlags :Nx + maxlags ]
158
+ ax_ref .vlines (lags , [0 ],norm_auto_corr )
159
+ ax_ref .axhline (y = 0 ,xmin = 0 ,xmax = 1 )
160
+
161
+
143
162
@check_figures_equal (extensions = ["png" ])
144
163
def test_spy (fig_test ,fig_ref ):
145
164
np .random .seed (19680801 )
@@ -4706,6 +4725,255 @@ def test_subplot_key_hash():
4706
4725
assert ax .get_subplotspec ().get_geometry ()== (5 ,1 ,0 ,0 )
4707
4726
4708
4727
4728
+ @pytest .mark .filterwarnings (
4729
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4730
+ @image_comparison (
4731
+ ["specgram_freqs.png" ,"specgram_freqs_linear.png" ,
4732
+ "specgram_noise.png" ,"specgram_noise_linear.png" ],
4733
+ remove_text = True ,tol = 0.07 ,style = "default" )
4734
+ def test_specgram ():
4735
+ """Test axes.specgram in default (psd) mode."""
4736
+
4737
+ # use former defaults to match existing baseline image
4738
+ matplotlib .rcParams ['image.interpolation' ]= 'nearest'
4739
+
4740
+ n = 1000
4741
+ Fs = 10.
4742
+
4743
+ fstims = [[Fs / 4 ,Fs / 5 ,Fs / 11 ], [Fs / 4.7 ,Fs / 5.6 ,Fs / 11.9 ]]
4744
+ NFFT_freqs = int (10 * Fs / np .min (fstims ))
4745
+ x = np .arange (0 ,n ,1 / Fs )
4746
+ y_freqs = np .concatenate (
4747
+ np .sin (2 * np .pi * np .multiply .outer (fstims ,x )).sum (axis = 1 ))
4748
+
4749
+ NFFT_noise = int (10 * Fs / 11 )
4750
+ np .random .seed (0 )
4751
+ y_noise = np .concatenate ([np .random .standard_normal (n ),np .random .rand (n )])
4752
+
4753
+ all_sides = ["default" ,"onesided" ,"twosided" ]
4754
+ for y ,NFFT in [(y_freqs ,NFFT_freqs ), (y_noise ,NFFT_noise )]:
4755
+ noverlap = NFFT // 2
4756
+ pad_to = int (2 ** np .ceil (np .log2 (NFFT )))
4757
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4758
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4759
+ pad_to = pad_to ,sides = sides )
4760
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4761
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4762
+ pad_to = pad_to ,sides = sides ,
4763
+ scale = "linear" ,norm = matplotlib .colors .LogNorm ())
4764
+
4765
+
4766
+ @pytest .mark .filterwarnings (
4767
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4768
+ @image_comparison (
4769
+ ["specgram_magnitude_freqs.png" ,"specgram_magnitude_freqs_linear.png" ,
4770
+ "specgram_magnitude_noise.png" ,"specgram_magnitude_noise_linear.png" ],
4771
+ remove_text = True ,tol = 0.07 ,style = "default" )
4772
+ def test_specgram_magnitude ():
4773
+ """Test axes.specgram in magnitude mode."""
4774
+
4775
+ # use former defaults to match existing baseline image
4776
+ matplotlib .rcParams ['image.interpolation' ]= 'nearest'
4777
+
4778
+ n = 1000
4779
+ Fs = 10.
4780
+
4781
+ fstims = [[Fs / 4 ,Fs / 5 ,Fs / 11 ], [Fs / 4.7 ,Fs / 5.6 ,Fs / 11.9 ]]
4782
+ NFFT_freqs = int (100 * Fs / np .min (fstims ))
4783
+ x = np .arange (0 ,n ,1 / Fs )
4784
+ y = np .sin (2 * np .pi * np .multiply .outer (fstims ,x )).sum (axis = 1 )
4785
+ y [:,- 1 ]= 1
4786
+ y_freqs = np .hstack (y )
4787
+
4788
+ NFFT_noise = int (10 * Fs / 11 )
4789
+ np .random .seed (0 )
4790
+ y_noise = np .concatenate ([np .random .standard_normal (n ),np .random .rand (n )])
4791
+
4792
+ all_sides = ["default" ,"onesided" ,"twosided" ]
4793
+ for y ,NFFT in [(y_freqs ,NFFT_freqs ), (y_noise ,NFFT_noise )]:
4794
+ noverlap = NFFT // 2
4795
+ pad_to = int (2 ** np .ceil (np .log2 (NFFT )))
4796
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4797
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4798
+ pad_to = pad_to ,sides = sides ,mode = "magnitude" )
4799
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4800
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4801
+ pad_to = pad_to ,sides = sides ,mode = "magnitude" ,
4802
+ scale = "linear" ,norm = matplotlib .colors .LogNorm ())
4803
+
4804
+
4805
+ @pytest .mark .filterwarnings (
4806
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4807
+ @image_comparison (
4808
+ ["specgram_angle_freqs.png" ,"specgram_phase_freqs.png" ,
4809
+ "specgram_angle_noise.png" ,"specgram_phase_noise.png" ],
4810
+ remove_text = True ,tol = 0.07 ,style = "default" )
4811
+ def test_specgram_angle ():
4812
+ """Test axes.specgram in angle and phase modes."""
4813
+
4814
+ # use former defaults to match existing baseline image
4815
+ matplotlib .rcParams ['image.interpolation' ]= 'nearest'
4816
+
4817
+ n = 1000
4818
+ Fs = 10.
4819
+
4820
+ fstims = [[Fs / 4 ,Fs / 5 ,Fs / 11 ], [Fs / 4.7 ,Fs / 5.6 ,Fs / 11.9 ]]
4821
+ NFFT_freqs = int (10 * Fs / np .min (fstims ))
4822
+ x = np .arange (0 ,n ,1 / Fs )
4823
+ y = np .sin (2 * np .pi * np .multiply .outer (fstims ,x )).sum (axis = 1 )
4824
+ y [:,- 1 ]= 1
4825
+ y_freqs = np .hstack (y )
4826
+
4827
+ NFFT_noise = int (10 * Fs / 11 )
4828
+ np .random .seed (0 )
4829
+ y_noise = np .concatenate ([np .random .standard_normal (n ),np .random .rand (n )])
4830
+
4831
+ all_sides = ["default" ,"onesided" ,"twosided" ]
4832
+ for y ,NFFT in [(y_freqs ,NFFT_freqs ), (y_noise ,NFFT_noise )]:
4833
+ noverlap = NFFT // 2
4834
+ pad_to = int (2 ** np .ceil (np .log2 (NFFT )))
4835
+ for mode in ["angle" ,"phase" ]:
4836
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4837
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4838
+ pad_to = pad_to ,sides = sides ,mode = mode )
4839
+ with pytest .raises (ValueError ):
4840
+ ax .specgram (y ,NFFT = NFFT ,Fs = Fs ,noverlap = noverlap ,
4841
+ pad_to = pad_to ,sides = sides ,mode = mode ,
4842
+ scale = "dB" )
4843
+
4844
+
4845
+ @pytest .mark .filterwarnings (
4846
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4847
+ def test_specgram_fs_none ():
4848
+ """Test axes.specgram when Fs is None, should not throw error."""
4849
+ spec ,freqs ,t ,im = plt .specgram (np .ones (300 ),Fs = None ,scale = 'linear' )
4850
+ xmin ,xmax ,freq0 ,freq1 = im .get_extent ()
4851
+ assert xmin == 32 and xmax == 96
4852
+
4853
+
4854
+ @pytest .mark .filterwarnings (
4855
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4856
+ @check_figures_equal (extensions = ["png" ])
4857
+ def test_specgram_origin_rcparam (fig_test ,fig_ref ):
4858
+ """Test specgram ignores image.origin rcParam and uses origin 'upper'."""
4859
+ t = np .arange (500 )
4860
+ signal = np .sin (t )
4861
+
4862
+ plt .rcParams ["image.origin" ]= 'upper'
4863
+
4864
+ # Reference: First graph using default origin in imshow (upper),
4865
+ fig_ref .subplots ().specgram (signal )
4866
+
4867
+ # Try to overwrite the setting trying to flip the specgram
4868
+ plt .rcParams ["image.origin" ]= 'lower'
4869
+
4870
+ # Test: origin='lower' should be ignored
4871
+ fig_test .subplots ().specgram (signal )
4872
+
4873
+
4874
+ @pytest .mark .filterwarnings (
4875
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4876
+ def test_specgram_origin_kwarg ():
4877
+ """Ensure passing origin as a kwarg raises a TypeError."""
4878
+ t = np .arange (500 )
4879
+ signal = np .sin (t )
4880
+
4881
+ with pytest .raises (TypeError ):
4882
+ plt .specgram (signal ,origin = 'lower' )
4883
+
4884
+
4885
+ @pytest .mark .filterwarnings (
4886
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4887
+ @image_comparison (
4888
+ ["psd_freqs.png" ,"csd_freqs.png" ,"psd_noise.png" ,"csd_noise.png" ],
4889
+ remove_text = True ,tol = 0.002 )
4890
+ def test_psd_csd ():
4891
+ n = 10000
4892
+ Fs = 100.
4893
+
4894
+ fstims = [[Fs / 4 ,Fs / 5 ,Fs / 11 ], [Fs / 4.7 ,Fs / 5.6 ,Fs / 11.9 ]]
4895
+ NFFT_freqs = int (1000 * Fs / np .min (fstims ))
4896
+ x = np .arange (0 ,n ,1 / Fs )
4897
+ ys_freqs = np .sin (2 * np .pi * np .multiply .outer (fstims ,x )).sum (axis = 1 )
4898
+
4899
+ NFFT_noise = int (1000 * Fs / 11 )
4900
+ np .random .seed (0 )
4901
+ ys_noise = [np .random .standard_normal (n ),np .random .rand (n )]
4902
+
4903
+ all_kwargs = [{"sides" :"default" },
4904
+ {"sides" :"onesided" ,"return_line" :False },
4905
+ {"sides" :"twosided" ,"return_line" :True }]
4906
+ for ys ,NFFT in [(ys_freqs ,NFFT_freqs ), (ys_noise ,NFFT_noise )]:
4907
+ noverlap = NFFT // 2
4908
+ pad_to = int (2 ** np .ceil (np .log2 (NFFT )))
4909
+ for ax ,kwargs in zip (plt .figure ().subplots (3 ),all_kwargs ):
4910
+ ret = ax .psd (np .concatenate (ys ),NFFT = NFFT ,Fs = Fs ,
4911
+ noverlap = noverlap ,pad_to = pad_to ,** kwargs )
4912
+ assert len (ret )== 2 + kwargs .get ("return_line" ,False )
4913
+ ax .set (xlabel = "" ,ylabel = "" )
4914
+ for ax ,kwargs in zip (plt .figure ().subplots (3 ),all_kwargs ):
4915
+ ret = ax .csd (* ys ,NFFT = NFFT ,Fs = Fs ,
4916
+ noverlap = noverlap ,pad_to = pad_to ,** kwargs )
4917
+ assert len (ret )== 2 + kwargs .get ("return_line" ,False )
4918
+ ax .set (xlabel = "" ,ylabel = "" )
4919
+
4920
+
4921
+ @pytest .mark .filterwarnings (
4922
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4923
+ @image_comparison (
4924
+ ["magnitude_spectrum_freqs_linear.png" ,
4925
+ "magnitude_spectrum_freqs_dB.png" ,
4926
+ "angle_spectrum_freqs.png" ,
4927
+ "phase_spectrum_freqs.png" ,
4928
+ "magnitude_spectrum_noise_linear.png" ,
4929
+ "magnitude_spectrum_noise_dB.png" ,
4930
+ "angle_spectrum_noise.png" ,
4931
+ "phase_spectrum_noise.png" ],
4932
+ remove_text = True )
4933
+ def test_spectrum ():
4934
+ n = 10000
4935
+ Fs = 100.
4936
+
4937
+ fstims1 = [Fs / 4 ,Fs / 5 ,Fs / 11 ]
4938
+ NFFT = int (1000 * Fs / min (fstims1 ))
4939
+ pad_to = int (2 ** np .ceil (np .log2 (NFFT )))
4940
+
4941
+ x = np .arange (0 ,n ,1 / Fs )
4942
+ y_freqs = ((np .sin (2 * np .pi * np .outer (x ,fstims1 ))* 10 ** np .arange (3 ))
4943
+ .sum (axis = 1 ))
4944
+ np .random .seed (0 )
4945
+ y_noise = np .hstack ([np .random .standard_normal (n ),np .random .rand (n )])- .5
4946
+
4947
+ all_sides = ["default" ,"onesided" ,"twosided" ]
4948
+ kwargs = {"Fs" :Fs ,"pad_to" :pad_to }
4949
+ for y in [y_freqs ,y_noise ]:
4950
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4951
+ spec ,freqs ,line = ax .magnitude_spectrum (y ,sides = sides ,** kwargs )
4952
+ ax .set (xlabel = "" ,ylabel = "" )
4953
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4954
+ spec ,freqs ,line = ax .magnitude_spectrum (y ,sides = sides ,** kwargs ,
4955
+ scale = "dB" )
4956
+ ax .set (xlabel = "" ,ylabel = "" )
4957
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4958
+ spec ,freqs ,line = ax .angle_spectrum (y ,sides = sides ,** kwargs )
4959
+ ax .set (xlabel = "" ,ylabel = "" )
4960
+ for ax ,sides in zip (plt .figure ().subplots (3 ),all_sides ):
4961
+ spec ,freqs ,line = ax .phase_spectrum (y ,sides = sides ,** kwargs )
4962
+ ax .set (xlabel = "" ,ylabel = "" )
4963
+
4964
+
4965
+ @pytest .mark .filterwarnings (
4966
+ 'ignore::matplotlib._api.deprecation.MatplotlibDeprecationWarning' )
4967
+ def test_psd_csd_edge_cases ():
4968
+ # Inverted yaxis or fully zero inputs used to throw exceptions.
4969
+ axs = plt .figure ().subplots (2 )
4970
+ for ax in axs :
4971
+ ax .yaxis .set (inverted = True )
4972
+ with np .errstate (divide = "ignore" ):
4973
+ axs [0 ].psd (np .zeros (5 ))
4974
+ axs [1 ].csd (np .zeros (5 ),np .zeros (5 ))
4975
+
4976
+
4709
4977
@check_figures_equal (extensions = ['png' ])
4710
4978
def test_twin_remove (fig_test ,fig_ref ):
4711
4979
ax_test = fig_test .add_subplot ()