Repository: mwaskom/seaborn

Issue:
map_* methods of PairGrid broken in 0.11.0
Hi,

I discovered that the map_* methods of PairGrid seem to be broken in version 0.11.0 for user defined functions. See reproducible example below with a corrfunc defined to plot the pearson correlation value on the lower plots. The function doesn't seem to get evaluated in version 0.11.0. When I pip install seaborn==0.10.1, I get the desired result. Plots from both cases also attached.

```import numpy as np
from scipy import stats
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="white")

mean = np.zeros(3)
cov = np.random.uniform(.2, .4, (3, 3))
cov += cov.T
cov[np.diag_indices(3)] = 1
data = np.random.multivariate_normal(mean, cov, 100)
df = pd.DataFrame(data, columns=["X", "Y", "Z"])

def corrfunc(x, y,**kws):
    r, _ = stats.pearsonr(x, y)
    ax = plt.gca()
    ax.annotate("r = {:.2f}".format(r),
                xy=(.1, .9), xycoords=ax.transAxes)

g = sns.PairGrid(df, palette=["red"])
g.map_upper(plt.scatter, s=10)
g.map_diag(sns.distplot, kde=False)
g.map_lower(sns.kdeplot, cmap="Blues_d")
g.map_lower(corrfunc)
plt.show()

```

![seaborn-0-11-0](https://user-images.githubusercontent.com/3239171/94969718-380d3e00-04d1-11eb-821b-9aad80ec696e.png)

![seaborn-0-10-1](https://user-images.githubusercontent.com/3239171/94969722-3a6f9800-04d1-11eb-8ef1-861d9beb1f26.png)





Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=h1) Report
> Merging [#2368](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=desc) (8a40b88) into [master](https://codecov.io/gh/mwaskom/seaborn/commit/2717408b564994002fe08f72ba2dd7e1acf359b6?el=desc) (2717408) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/mwaskom/seaborn/pull/2368/graphs/tree.svg?width=650&height=150&src=pr&token=SLuzHnA9Bl)](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #2368   +/-   ##
=======================================
  Coverage   96.95%   96.95%           
=======================================
  Files          17       17           
  Lines        6042     6042           
=======================================
  Hits         5858     5858           
  Misses        184      184           
```


| [Impacted Files](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [seaborn/axisgrid.py](https://codecov.io/gh/mwaskom/seaborn/pull/2368/diff?src=pr&el=tree#diff-c2VhYm9ybi9heGlzZ3JpZC5weQ==) | `95.51% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=footer). Last update [2717408...8a40b88](https://codecov.io/gh/mwaskom/seaborn/pull/2368?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/seaborn/axisgrid.py b/seaborn/axisgrid.py
index 04b243e7..7ab30cac 100644
--- a/seaborn/axisgrid.py
+++ b/seaborn/axisgrid.py
@@ -1207,11 +1207,19 @@ class PairGrid(Grid):
         # Sort out the hue variable
         self._hue_var = hue
         if hue is None:
-            self.hue_names = ["_nolegend_"]
+            self.hue_names = hue_order = ["_nolegend_"]
             self.hue_vals = pd.Series(["_nolegend_"] * len(data),
                                       index=data.index)
         else:
-            hue_names = categorical_order(data[hue], hue_order)
+            # We need hue_order and hue_names because the former is used to control
+            # the order of drawing and the latter is used to control the order of
+            # the legend. hue_names can become string-typed while hue_order must
+            # retain the type of the input data. This is messy but results from
+            # the fact that PairGrid can implement the hue-mapping logic itself
+            # (and was originally written exclusively that way) but now can delegate
+            # to the axes-level functions, while always handling legend creation.
+            # See GH2307
+            hue_names = hue_order = categorical_order(data[hue], hue_order)
             if dropna:
                 # Filter NA from the list of unique hue names
                 hue_names = list(filter(pd.notnull, hue_names))
@@ -1397,7 +1405,7 @@ class PairGrid(Grid):
 
             plt.sca(ax)
 
-            for k, label_k in enumerate(self.hue_names):
+            for k, label_k in enumerate(self._hue_order):
 
                 # Attempt to get data for this level, allowing for empty
                 try:
@@ -1489,7 +1497,7 @@ class PairGrid(Grid):
             axes_vars = [x_var, y_var]
 
         hue_grouped = self.data.groupby(self.hue_vals)
-        for k, label_k in enumerate(self.hue_names):
+        for k, label_k in enumerate(self._hue_order):
 
             kws = kwargs.copy()
 


Test patch:
diff --git a/seaborn/tests/test_axisgrid.py b/seaborn/tests/test_axisgrid.py
index 782f5a5e..96c550c8 100644
--- a/seaborn/tests/test_axisgrid.py
+++ b/seaborn/tests/test_axisgrid.py
@@ -829,6 +829,21 @@ class TestPairGrid:
             ax = g.axes[i, j]
             assert len(ax.collections) == 0
 
+    def test_map_mixed_funcsig(self):
+
+        vars = ["x", "y", "z"]
+        g = ag.PairGrid(self.df, vars=vars)
+        g.map_lower(scatterplot)
+        g.map_upper(plt.scatter)
+
+        for i, j in zip(*np.triu_indices_from(g.axes, 1)):
+            ax = g.axes[i, j]
+            x_in = self.df[vars[j]]
+            y_in = self.df[vars[i]]
+            x_out, y_out = ax.collections[0].get_offsets().T
+            npt.assert_array_equal(x_in, x_out)
+            npt.assert_array_equal(y_in, y_out)
+
     def test_map_diag(self):
 
         g = ag.PairGrid(self.df)