Repository: statsmodels/statsmodels

Issue:
BUG: fix wrong axis label in qqplot_2samples
The label location is wrong in qqplot_2samples. When data1 and data2 are of equal sizes, x_label will correspond to data2, which is wrong, (it should correspond to data1). 

BTW, why permitting different data sizes here? To me, it doesn't make sense for a Q-Q plot to have different sample sizes on data1 and data2.

Not sure how to add a test for plot, but this code can produce results needed:

d1 = np.arange(3)
d2 = np.arange(0,30,10)
pp_x = sm.ProbPlot(d1)
pp_y = sm.ProbPlot(d2)
qqplot_2samples(pp_x, pp_y,xlabel="d1")
new_qqplot_2samples(pp_x, pp_y,xlabel="d1")


- [ ] closes #xxxx
- [x] tests added / passed. 
- [ ] code/documentation is well formatted.  
- [ ] properly formatted commit message. See 
      [NumPy's guide](https://docs.scipy.org/doc/numpy-1.15.1/dev/gitwash/development_workflow.html#writing-the-commit-message). 

<details>


**Notes**:

* It is essential that you add a test when making code changes. Tests are not 
  needed for doc changes.
* When adding a new function, test values should usually be verified in another package (e.g., R/SAS/Stata).
* When fixing a bug, you must add a test that would produce the bug in main and
  then show that it is fixed with the new code.
* New code additions must be well formatted. Changes should pass flake8. If on Linux or OSX, you can
  verify you changes are well formatted by running 
  ```
  git diff upstream/main -u -- "*.py" | flake8 --diff --isolated
  ```
  assuming `flake8` is installed. This command is also available on Windows 
  using the Windows System for Linux once `flake8` is installed in the 
  local Linux environment. While passing this test is not required, it is good practice and it help 
  improve code quality in `statsmodels`.
* Docstring additions must render correctly, including escapes and LaTeX.

</details>



Discussion:

Resolving patch:
diff --git a/statsmodels/graphics/gofplots.py b/statsmodels/graphics/gofplots.py
--- a/statsmodels/graphics/gofplots.py
+++ b/statsmodels/graphics/gofplots.py
@@ -392,6 +392,7 @@ def qqplot(
         line=None,
         other=None,
         ax=None,
+        swap: bool = False,
         **plotkwargs,
     ):
         """
@@ -432,6 +433,8 @@ def qqplot(
         ax : AxesSubplot, optional
             If given, this subplot is used to plot in instead of a new figure
             being created.
+        swap : bool, optional
+            Flag indicating to swap the x and y labels.
         **plotkwargs
             Additional arguments to be passed to the `plot` command.
 
@@ -459,7 +462,6 @@ def qqplot(
                 # the larger data set
                 p = plotting_pos(self.nobs, self.a)
                 s_other = stats.mstats.mquantiles(s_other, p)
-
             fig, ax = _do_plot(
                 s_other, s_self, self.dist, ax=ax, line=line, **plotkwargs
             )
@@ -468,6 +470,8 @@ def qqplot(
                 xlabel = "Quantiles of 2nd Sample"
             if ylabel is None:
                 ylabel = "Quantiles of 1st Sample"
+            if swap:
+                xlabel, ylabel = ylabel, xlabel
 
         else:
             fig, ax = _do_plot(
@@ -770,11 +774,16 @@ def qqplot_2samples(
         data2 = ProbPlot(data2)
     if data2.data.shape[0] >= data1.data.shape[0]:
         fig = data1.qqplot(
-            xlabel=xlabel, ylabel=ylabel, line=line, other=data2, ax=ax
+            xlabel=ylabel, ylabel=xlabel, line=line, other=data2, ax=ax
         )
     else:
         fig = data2.qqplot(
-            xlabel=ylabel, ylabel=xlabel, line=line, other=data1, ax=ax
+            xlabel=ylabel,
+            ylabel=xlabel,
+            line=line,
+            other=data1,
+            ax=ax,
+            swap=True,
         )
 
     return fig


Test patch:
diff --git a/statsmodels/graphics/tests/test_gofplots.py b/statsmodels/graphics/tests/test_gofplots.py
--- a/statsmodels/graphics/tests/test_gofplots.py
+++ b/statsmodels/graphics/tests/test_gofplots.py
@@ -423,19 +423,31 @@ def test_with_ax(self, close_figures):
     @pytest.mark.matplotlib
     def test_plot_full_options(self, close_figures):
         gofplots._do_plot(
-            self.x, self.y, ax=self.ax, step=False, **self.full_options,
+            self.x,
+            self.y,
+            ax=self.ax,
+            step=False,
+            **self.full_options,
         )
 
     @pytest.mark.matplotlib
     def test_step_baseline(self, close_figures):
         gofplots._do_plot(
-            self.x, self.y, ax=self.ax, step=True, **self.step_options,
+            self.x,
+            self.y,
+            ax=self.ax,
+            step=True,
+            **self.step_options,
         )
 
     @pytest.mark.matplotlib
     def test_step_full_options(self, close_figures):
         gofplots._do_plot(
-            self.x, self.y, ax=self.ax, step=True, **self.full_options,
+            self.x,
+            self.y,
+            ax=self.ax,
+            step=True,
+            **self.full_options,
         )
 
     @pytest.mark.matplotlib
@@ -616,3 +628,34 @@ def test_param_unpacking():
     assert_equal(pp.fit_params, expected)
     pp = ProbPlot(np.empty(100), stats.beta(a=2, b=3, loc=4, scale=5))
     assert_equal(pp.fit_params, expected)
+
+
+@pytest.mark.matplotlib
+@pytest.mark.parametrize("labels", [{}, {"xlabel": "X", "ylabel": "Y"}])
+@pytest.mark.parametrize("x_size", [30, 50])
+@pytest.mark.parametrize("y_size", [30, 50])
+@pytest.mark.parametrize("line", [None, "45", "s", "r", "q"])
+def test_correct_labels(reset_randomstate, line, x_size, y_size, labels):
+    rs = np.random.RandomState(9876554)
+    x = rs.normal(loc=0, scale=0.1, size=x_size)
+    y = rs.standard_t(3, size=y_size)
+    pp_x = sm.ProbPlot(x)
+    pp_y = sm.ProbPlot(y)
+    fig = qqplot_2samples(pp_x, pp_y, line=line, **labels)
+    ax = fig.get_axes()[0]
+    x_label = ax.get_xlabel()
+    y_label = ax.get_ylabel()
+    if x_size <= y_size:
+        if not labels:
+            assert "2nd" in x_label
+            assert "1st" in y_label
+        else:
+            assert "Y" in x_label
+            assert "X" in y_label
+    else:
+        if not labels:
+            assert "1st" in x_label
+            assert "2nd" in y_label
+        else:
+            assert "X" in x_label
+            assert "Y" in y_label