1import numpy as np
2import numpy.testing as nptest
3from numpy.testing import assert_equal
4import pytest
5from scipy import stats
6
7import statsmodels.api as sm
8from statsmodels.graphics import gofplots
9from statsmodels.graphics.gofplots import (
10    ProbPlot,
11    qqline,
12    qqplot,
13    qqplot_2samples,
14)
15from statsmodels.graphics.utils import _import_mpl
16
17
18class BaseProbplotMixin:
19    def setup(self):
20        try:
21            import matplotlib.pyplot as plt
22
23            self.fig, self.ax = plt.subplots()
24        except ImportError:
25            pass
26        self.other_array = np.random.normal(size=self.prbplt.data.shape)
27        self.other_prbplot = ProbPlot(self.other_array)
28        self.plot_options = dict(
29            marker="d",
30            markerfacecolor="cornflowerblue",
31            markeredgecolor="white",
32            alpha=0.5,
33        )
34
35    @pytest.mark.matplotlib
36    def test_qqplot(self, close_figures):
37        self.prbplt.qqplot(ax=self.ax, line=self.line, **self.plot_options)
38
39    @pytest.mark.matplotlib
40    def test_ppplot(self, close_figures):
41        self.prbplt.ppplot(ax=self.ax, line=self.line)
42
43    @pytest.mark.matplotlib
44    def test_probplot(self, close_figures):
45        self.prbplt.probplot(ax=self.ax, line=self.line, **self.plot_options)
46
47    @pytest.mark.matplotlib
48    def test_probplot_exceed(self, close_figures):
49        self.prbplt.probplot(
50            ax=self.ax, exceed=True, line=self.line, **self.plot_options
51        )
52
53    @pytest.mark.matplotlib
54    def test_qqplot_other_array(self, close_figures):
55        self.prbplt.qqplot(
56            ax=self.ax,
57            line=self.line,
58            other=self.other_array,
59            **self.plot_options,
60        )
61
62    @pytest.mark.matplotlib
63    def test_ppplot_other_array(self, close_figures):
64        self.prbplt.ppplot(
65            ax=self.ax,
66            line=self.line,
67            other=self.other_array,
68            **self.plot_options,
69        )
70
71    @pytest.mark.xfail(strict=True)
72    @pytest.mark.matplotlib
73    def test_probplot_other_array(self, close_figures):
74        self.prbplt.probplot(
75            ax=self.ax,
76            line=self.line,
77            other=self.other_array,
78            **self.plot_options,
79        )
80
81    @pytest.mark.matplotlib
82    def test_qqplot_other_prbplt(self, close_figures):
83        self.prbplt.qqplot(
84            ax=self.ax,
85            line=self.line,
86            other=self.other_prbplot,
87            **self.plot_options,
88        )
89
90    @pytest.mark.matplotlib
91    def test_ppplot_other_prbplt(self, close_figures):
92        self.prbplt.ppplot(
93            ax=self.ax,
94            line=self.line,
95            other=self.other_prbplot,
96            **self.plot_options,
97        )
98
99    @pytest.mark.xfail(strict=True)
100    @pytest.mark.matplotlib
101    def test_probplot_other_prbplt(self, close_figures):
102        self.prbplt.probplot(
103            ax=self.ax,
104            line=self.line,
105            other=self.other_prbplot,
106            **self.plot_options,
107        )
108
109    @pytest.mark.matplotlib
110    def test_qqplot_custom_labels(self, close_figures):
111        self.prbplt.qqplot(
112            ax=self.ax,
113            line=self.line,
114            xlabel="Custom X-Label",
115            ylabel="Custom Y-Label",
116            **self.plot_options,
117        )
118
119    @pytest.mark.matplotlib
120    def test_ppplot_custom_labels(self, close_figures):
121        self.prbplt.ppplot(
122            ax=self.ax,
123            line=self.line,
124            xlabel="Custom X-Label",
125            ylabel="Custom Y-Label",
126            **self.plot_options,
127        )
128
129    @pytest.mark.matplotlib
130    def test_probplot_custom_labels(self, close_figures):
131        self.prbplt.probplot(
132            ax=self.ax,
133            line=self.line,
134            xlabel="Custom X-Label",
135            ylabel="Custom Y-Label",
136            **self.plot_options,
137        )
138
139    @pytest.mark.matplotlib
140    def test_qqplot_pltkwargs(self, close_figures):
141        self.prbplt.qqplot(
142            ax=self.ax,
143            line=self.line,
144            marker="d",
145            markerfacecolor="cornflowerblue",
146            markeredgecolor="white",
147            alpha=0.5,
148        )
149
150    @pytest.mark.matplotlib
151    def test_ppplot_pltkwargs(self, close_figures):
152        self.prbplt.ppplot(
153            ax=self.ax,
154            line=self.line,
155            marker="d",
156            markerfacecolor="cornflowerblue",
157            markeredgecolor="white",
158            alpha=0.5,
159        )
160
161    @pytest.mark.matplotlib
162    def test_probplot_pltkwargs(self, close_figures):
163        self.prbplt.probplot(
164            ax=self.ax,
165            line=self.line,
166            marker="d",
167            markerfacecolor="cornflowerblue",
168            markeredgecolor="white",
169            alpha=0.5,
170        )
171
172    def test_fit_params(self):
173        assert self.prbplt.fit_params[-2] == self.prbplt.loc
174        assert self.prbplt.fit_params[-1] == self.prbplt.scale
175
176
177class TestProbPlotLongelyNoFit(BaseProbplotMixin):
178    def setup(self):
179        np.random.seed(5)
180        self.data = sm.datasets.longley.load()
181        self.data.exog = sm.add_constant(self.data.exog, prepend=False)
182        self.mod_fit = sm.OLS(self.data.endog, self.data.exog).fit()
183        self.prbplt = ProbPlot(
184            self.mod_fit.resid, dist=stats.t, distargs=(4,), fit=False
185        )
186        self.line = "r"
187        super().setup()
188
189
190class TestProbPlotLongelyWithFit(BaseProbplotMixin):
191    def setup(self):
192        np.random.seed(5)
193        self.data = sm.datasets.longley.load()
194        self.data.exog = sm.add_constant(self.data.exog, prepend=False)
195        self.mod_fit = sm.OLS(self.data.endog, self.data.exog).fit()
196        self.prbplt = ProbPlot(
197            self.mod_fit.resid, dist=stats.t, distargs=(4,), fit=True
198        )
199        self.line = "r"
200        super().setup()
201
202
203class TestProbPlotRandomNormalMinimal(BaseProbplotMixin):
204    def setup(self):
205        np.random.seed(5)
206        self.data = np.random.normal(loc=8.25, scale=3.25, size=37)
207        self.prbplt = ProbPlot(self.data)
208        self.line = None
209        super(TestProbPlotRandomNormalMinimal, self).setup()
210
211
212class TestProbPlotRandomNormalWithFit(BaseProbplotMixin):
213    def setup(self):
214        np.random.seed(5)
215        self.data = np.random.normal(loc=8.25, scale=3.25, size=37)
216        self.prbplt = ProbPlot(self.data, fit=True)
217        self.line = "q"
218        super(TestProbPlotRandomNormalWithFit, self).setup()
219
220
221class TestProbPlotRandomNormalFullDist(BaseProbplotMixin):
222    def setup(self):
223        np.random.seed(5)
224        self.data = np.random.normal(loc=8.25, scale=3.25, size=37)
225        self.prbplt = ProbPlot(self.data, dist=stats.norm(loc=8.5, scale=3.0))
226        self.line = "45"
227        super().setup()
228
229    def test_loc_set(self):
230        assert self.prbplt.loc == 8.5
231
232    def test_scale_set(self):
233        assert self.prbplt.scale == 3.0
234
235    def test_exceptions(self):
236        with pytest.raises(ValueError):
237            ProbPlot(self.data, dist=stats.norm(loc=8.5, scale=3.0), fit=True)
238        with pytest.raises(ValueError):
239            ProbPlot(
240                self.data,
241                dist=stats.norm(loc=8.5, scale=3.0),
242                distargs=(8.5, 3.0),
243            )
244        with pytest.raises(ValueError):
245            ProbPlot(self.data, dist=stats.norm(loc=8.5, scale=3.0), loc=8.5)
246        with pytest.raises(ValueError):
247            ProbPlot(self.data, dist=stats.norm(loc=8.5, scale=3.0), scale=3.0)
248
249
250class TestCompareSamplesDifferentSize:
251    def setup(self):
252        np.random.seed(5)
253        self.data1 = ProbPlot(np.random.normal(loc=8.25, scale=3.25, size=37))
254        self.data2 = ProbPlot(np.random.normal(loc=8.25, scale=3.25, size=55))
255
256    @pytest.mark.matplotlib
257    def test_qqplot(self, close_figures):
258        self.data1.qqplot(other=self.data2)
259        with pytest.raises(ValueError):
260            self.data2.qqplot(other=self.data1)
261
262    @pytest.mark.matplotlib
263    def test_ppplot(self, close_figures):
264        self.data1.ppplot(other=self.data2)
265        self.data2.ppplot(other=self.data1)
266
267
268class TestProbPlotRandomNormalLocScaleDist(BaseProbplotMixin):
269    def setup(self):
270        np.random.seed(5)
271        self.data = np.random.normal(loc=8.25, scale=3.25, size=37)
272        self.prbplt = ProbPlot(self.data, loc=8, scale=3)
273        self.line = "45"
274        super(TestProbPlotRandomNormalLocScaleDist, self).setup()
275
276    def test_loc_set(self):
277        assert self.prbplt.loc == 8
278
279    def test_scale_set(self):
280        assert self.prbplt.scale == 3
281
282    def test_loc_set_in_dist(self):
283        assert self.prbplt.dist.mean() == 8.0
284
285    def test_scale_set_in_dist(self):
286        assert self.prbplt.dist.var() == 9.0
287
288
289class TestTopLevel:
290    def setup(self):
291        self.data = sm.datasets.longley.load()
292        self.data.exog = sm.add_constant(self.data.exog, prepend=False)
293        self.mod_fit = sm.OLS(self.data.endog, self.data.exog).fit()
294        self.res = self.mod_fit.resid
295        self.prbplt = ProbPlot(self.mod_fit.resid, dist=stats.t, distargs=(4,))
296        self.other_array = np.random.normal(size=self.prbplt.data.shape)
297        self.other_prbplot = ProbPlot(self.other_array)
298
299    @pytest.mark.matplotlib
300    def test_qqplot(self, close_figures):
301        qqplot(self.res, line="r")
302
303    @pytest.mark.matplotlib
304    def test_qqplot_pltkwargs(self, close_figures):
305        qqplot(
306            self.res,
307            line="r",
308            marker="d",
309            markerfacecolor="cornflowerblue",
310            markeredgecolor="white",
311            alpha=0.5,
312        )
313
314    @pytest.mark.matplotlib
315    def test_qqplot_2samples_prob_plot_objects(self, close_figures):
316        # also tests all valuesg for line
317        for line in ["r", "q", "45", "s"]:
318            # test with `ProbPlot` instances
319            qqplot_2samples(self.prbplt, self.other_prbplot, line=line)
320
321    @pytest.mark.matplotlib
322    def test_qqplot_2samples_arrays(self, close_figures):
323        # also tests all values for line
324        for line in ["r", "q", "45", "s"]:
325            # test with arrays
326            qqplot_2samples(self.res, self.other_array, line=line)
327
328
329def test_invalid_dist_config(close_figures):
330    # GH 4226
331    np.random.seed(5)
332    data = sm.datasets.longley.load()
333    data.exog = sm.add_constant(data.exog, prepend=False)
334    mod_fit = sm.OLS(data.endog, data.exog).fit()
335    with pytest.raises(TypeError, match=r"dist\(0, 1, 4, loc=0, scale=1\)"):
336        ProbPlot(mod_fit.resid, stats.t, distargs=(0, 1, 4))
337
338
339@pytest.mark.matplotlib
340def test_qqplot_unequal():
341    rs = np.random.RandomState(0)
342    data1 = rs.standard_normal(100)
343    data2 = rs.standard_normal(200)
344    fig1 = qqplot_2samples(data1, data2)
345    fig2 = qqplot_2samples(data2, data1)
346    x1, y1 = fig1.get_axes()[0].get_children()[0].get_data()
347    x2, y2 = fig2.get_axes()[0].get_children()[0].get_data()
348    np.testing.assert_allclose(x1, x2)
349    np.testing.assert_allclose(y1, y2)
350    numobj1 = len(fig1.get_axes()[0].get_children())
351    numobj2 = len(fig2.get_axes()[0].get_children())
352    assert numobj1 == numobj2
353
354    @pytest.mark.matplotlib
355    def test_qqplot(self, close_figures):
356        qqplot(self.res, line="r")
357
358    @pytest.mark.matplotlib
359    def test_qqplot_2samples_prob_plot_obj(self, close_figures):
360        # also tests all values for line
361        for line in ["r", "q", "45", "s"]:
362            # test with `ProbPlot` instances
363            qqplot_2samples(self.prbplt, self.other_prbplot, line=line)
364
365    @pytest.mark.matplotlib
366    def test_qqplot_2samples_arrays(self, close_figures):
367        # also tests all values for line
368        for line in ["r", "q", "45", "s"]:
369            # test with arrays
370            qqplot_2samples(self.res, self.other_array, line=line)
371
372
373class TestCheckDist:
374    def test_good(self):
375        gofplots._check_for(stats.norm, "ppf")
376        gofplots._check_for(stats.norm, "cdf")
377
378    def test_bad(self):
379        with pytest.raises(AttributeError):
380            gofplots._check_for("junk", "ppf")
381        with pytest.raises(AttributeError):
382            gofplots._check_for("junk", "cdf")
383
384
385class TestDoPlot:
386    def setup(self):
387        try:
388            import matplotlib.pyplot as plt
389
390            self.fig, self.ax = plt.subplots()
391        except ImportError:
392            pass
393
394        self.x = [0.2, 0.6, 2.0, 4.5, 10.0, 50.0, 83.0, 99.1, 99.7]
395        self.y = [1.2, 1.4, 1.7, 2.1, 3.2, 3.7, 4.5, 5.1, 6.3]
396        self.full_options = {
397            "marker": "s",
398            "markerfacecolor": "cornflowerblue",
399            "markeredgecolor": "firebrick",
400            "markeredgewidth": 1.25,
401            "linestyle": "--",
402        }
403        self.step_options = {"linestyle": "-", "where": "mid"}
404
405    @pytest.mark.matplotlib
406    def test_baseline(self, close_figures):
407        plt = _import_mpl()
408        fig, ax = gofplots._do_plot(self.x, self.y)
409        assert isinstance(fig, plt.Figure)
410        assert isinstance(ax, plt.Axes)
411        assert self.fig is not fig
412        assert self.ax is not ax
413
414    @pytest.mark.matplotlib
415    def test_with_ax(self, close_figures):
416        plt = _import_mpl()
417        fig, ax = gofplots._do_plot(self.x, self.y, ax=self.ax)
418        assert isinstance(fig, plt.Figure)
419        assert isinstance(ax, plt.Axes)
420        assert self.fig is fig
421        assert self.ax is ax
422
423    @pytest.mark.matplotlib
424    def test_plot_full_options(self, close_figures):
425        gofplots._do_plot(
426            self.x,
427            self.y,
428            ax=self.ax,
429            step=False,
430            **self.full_options,
431        )
432
433    @pytest.mark.matplotlib
434    def test_step_baseline(self, close_figures):
435        gofplots._do_plot(
436            self.x,
437            self.y,
438            ax=self.ax,
439            step=True,
440            **self.step_options,
441        )
442
443    @pytest.mark.matplotlib
444    def test_step_full_options(self, close_figures):
445        gofplots._do_plot(
446            self.x,
447            self.y,
448            ax=self.ax,
449            step=True,
450            **self.full_options,
451        )
452
453    @pytest.mark.matplotlib
454    def test_plot_qq_line(self, close_figures):
455        gofplots._do_plot(self.x, self.y, ax=self.ax, line="r")
456
457    @pytest.mark.matplotlib
458    def test_step_qq_line(self, close_figures):
459        gofplots._do_plot(self.x, self.y, ax=self.ax, step=True, line="r")
460
461
462class TestQQLine:
463    def setup(self):
464        np.random.seed(0)
465        self.x = np.sort(np.random.normal(loc=2.9, scale=1.2, size=37))
466        self.y = np.sort(np.random.normal(loc=3.0, scale=1.1, size=37))
467        try:
468            import matplotlib.pyplot as plt
469
470            self.fig, self.ax = plt.subplots()
471            self.ax.plot(self.x, self.y, "ko")
472        except ImportError:
473            pass
474
475        self.lineoptions = {
476            "linewidth": 2,
477            "dashes": (10, 1, 3, 4),
478            "color": "green",
479        }
480        self.fmt = "bo-"
481
482    @pytest.mark.matplotlib
483    def test_badline(self):
484        with pytest.raises(ValueError):
485            qqline(self.ax, "junk")
486
487    @pytest.mark.matplotlib
488    def test_non45_no_x(self, close_figures):
489        with pytest.raises(ValueError):
490            qqline(self.ax, "s", y=self.y)
491
492    @pytest.mark.matplotlib
493    def test_non45_no_y(self, close_figures):
494        with pytest.raises(ValueError):
495            qqline(self.ax, "s", x=self.x)
496
497    @pytest.mark.matplotlib
498    def test_non45_no_x_no_y(self, close_figures):
499        with pytest.raises(ValueError):
500            qqline(self.ax, "s")
501
502    @pytest.mark.matplotlib
503    def test_45(self, close_figures):
504        nchildren = len(self.ax.get_children())
505        qqline(self.ax, "45")
506        assert len(self.ax.get_children()) > nchildren
507
508    @pytest.mark.matplotlib
509    def test_45_fmt(self, close_figures):
510        qqline(self.ax, "45", fmt=self.fmt)
511
512    @pytest.mark.matplotlib
513    def test_45_fmt_lineoptions(self, close_figures):
514        qqline(self.ax, "45", fmt=self.fmt, **self.lineoptions)
515
516    @pytest.mark.matplotlib
517    def test_r(self, close_figures):
518        nchildren = len(self.ax.get_children())
519        qqline(self.ax, "r", x=self.x, y=self.y)
520        assert len(self.ax.get_children()) > nchildren
521
522    @pytest.mark.matplotlib
523    def test_r_fmt(self, close_figures):
524        qqline(self.ax, "r", x=self.x, y=self.y, fmt=self.fmt)
525
526    @pytest.mark.matplotlib
527    def test_r_fmt_lineoptions(self, close_figures):
528        qqline(
529            self.ax, "r", x=self.x, y=self.y, fmt=self.fmt, **self.lineoptions
530        )
531
532    @pytest.mark.matplotlib
533    def test_s(self, close_figures):
534        nchildren = len(self.ax.get_children())
535        qqline(self.ax, "s", x=self.x, y=self.y)
536        assert len(self.ax.get_children()) > nchildren
537
538    @pytest.mark.matplotlib
539    def test_s_fmt(self, close_figures):
540        qqline(self.ax, "s", x=self.x, y=self.y, fmt=self.fmt)
541
542    @pytest.mark.matplotlib
543    def test_s_fmt_lineoptions(self, close_figures):
544        qqline(
545            self.ax, "s", x=self.x, y=self.y, fmt=self.fmt, **self.lineoptions
546        )
547
548    @pytest.mark.matplotlib
549    def test_q(self, close_figures):
550        nchildren = len(self.ax.get_children())
551        qqline(self.ax, "q", dist=stats.norm, x=self.x, y=self.y)
552        assert len(self.ax.get_children()) > nchildren
553
554    @pytest.mark.matplotlib
555    def test_q_fmt(self, close_figures):
556        qqline(self.ax, "q", dist=stats.norm, x=self.x, y=self.y, fmt=self.fmt)
557
558    @pytest.mark.matplotlib
559    def test_q_fmt_lineoptions(self, close_figures):
560        qqline(
561            self.ax,
562            "q",
563            dist=stats.norm,
564            x=self.x,
565            y=self.y,
566            fmt=self.fmt,
567            **self.lineoptions,
568        )
569
570
571class TestPlottingPosition:
572    def setup(self):
573        self.N = 13
574        self.data = np.arange(self.N)
575
576    def do_test(self, alpha, beta):
577        smpp = gofplots.plotting_pos(self.N, a=alpha, b=beta)
578        sppp = stats.mstats.plotting_positions(
579            self.data, alpha=alpha, beta=beta
580        )
581
582        nptest.assert_array_almost_equal(smpp, sppp, decimal=5)
583
584    @pytest.mark.matplotlib
585    def test_weibull(self, close_figures):
586        self.do_test(0, 0)
587
588    @pytest.mark.matplotlib
589    def test_lininterp(self, close_figures):
590        self.do_test(0, 1)
591
592    @pytest.mark.matplotlib
593    def test_piecewise(self, close_figures):
594        self.do_test(0.5, 0.5)
595
596    @pytest.mark.matplotlib
597    def test_approx_med_unbiased(self, close_figures):
598        self.do_test(1.0 / 3.0, 1.0 / 3.0)
599
600    @pytest.mark.matplotlib
601    def test_cunnane(self, close_figures):
602        self.do_test(0.4, 0.4)
603
604
605def test_param_unpacking():
606    expected = np.array([2.0, 3, 0, 1])
607    pp = ProbPlot(np.empty(100), dist=stats.beta(2, 3))
608    assert_equal(pp.fit_params, expected)
609    pp = ProbPlot(np.empty(100), stats.beta(2, b=3))
610    assert_equal(pp.fit_params, expected)
611    pp = ProbPlot(np.empty(100), stats.beta(a=2, b=3))
612    assert_equal(pp.fit_params, expected)
613
614    expected = np.array([2.0, 3, 4, 1])
615    pp = ProbPlot(np.empty(100), stats.beta(2, 3, 4))
616    assert_equal(pp.fit_params, expected)
617    pp = ProbPlot(np.empty(100), stats.beta(a=2, b=3, loc=4))
618    assert_equal(pp.fit_params, expected)
619
620    expected = np.array([2.0, 3, 4, 5])
621    pp = ProbPlot(np.empty(100), stats.beta(2, 3, 4, 5))
622    assert_equal(pp.fit_params, expected)
623    pp = ProbPlot(np.empty(100), stats.beta(2, 3, 4, scale=5))
624    assert_equal(pp.fit_params, expected)
625    pp = ProbPlot(np.empty(100), stats.beta(2, 3, loc=4, scale=5))
626    assert_equal(pp.fit_params, expected)
627    pp = ProbPlot(np.empty(100), stats.beta(2, b=3, loc=4, scale=5))
628    assert_equal(pp.fit_params, expected)
629    pp = ProbPlot(np.empty(100), stats.beta(a=2, b=3, loc=4, scale=5))
630    assert_equal(pp.fit_params, expected)
631
632
633@pytest.mark.matplotlib
634@pytest.mark.parametrize("labels", [{}, {"xlabel": "X", "ylabel": "Y"}])
635@pytest.mark.parametrize("x_size", [30, 50])
636@pytest.mark.parametrize("y_size", [30, 50])
637@pytest.mark.parametrize("line", [None, "45", "s", "r", "q"])
638def test_correct_labels(
639    close_figures, reset_randomstate, line, x_size, y_size, labels
640):
641    rs = np.random.RandomState(9876554)
642    x = rs.normal(loc=0, scale=0.1, size=x_size)
643    y = rs.standard_t(3, size=y_size)
644    pp_x = sm.ProbPlot(x)
645    pp_y = sm.ProbPlot(y)
646    fig = qqplot_2samples(pp_x, pp_y, line=line, **labels)
647    ax = fig.get_axes()[0]
648    x_label = ax.get_xlabel()
649    y_label = ax.get_ylabel()
650    if x_size < y_size:
651        if not labels:
652            assert "2nd" in x_label
653            assert "1st" in y_label
654        else:
655            assert "Y" in x_label
656            assert "X" in y_label
657    else:
658        if not labels:
659            assert "1st" in x_label
660            assert "2nd" in y_label
661        else:
662            assert "X" in x_label
663            assert "Y" in y_label
664
665
666@pytest.mark.matplotlib
667def test_axis_order(close_figures):
668    xx = np.random.normal(10, 1, (100,))
669    xy = np.random.normal(1, 0.01, (100,))
670    fig = qqplot_2samples(xx, xy, "x", "y")
671    ax = fig.get_axes()[0]
672    y_range = np.diff(ax.get_ylim())[0]
673    x_range = np.diff(ax.get_xlim())[0]
674    assert y_range < x_range
675
676    xx_long = np.random.normal(10, 1, (1000,))
677    fig = qqplot_2samples(xx_long, xy, "x", "y")
678    ax = fig.get_axes()[0]
679    y_range = np.diff(ax.get_ylim())[0]
680    x_range = np.diff(ax.get_xlim())[0]
681    assert y_range < x_range
682
683    xy_long = np.random.normal(1, 0.01, (1000,))
684    fig = qqplot_2samples(xx, xy_long, "x", "y")
685    ax = fig.get_axes()[0]
686    y_range = np.diff(ax.get_ylim())[0]
687    x_range = np.diff(ax.get_xlim())[0]
688    assert x_range < y_range
689