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