Repository: mwaskom/seaborn

Issue:
Scale has no effect for Pair plots in next-gen interface
The `objects` interface looks great, in particular the ability to have combination pair and facet plots. However, I ran into a bug when attempting to log-scale an axis for a `pair`ed plot with `seaborn==0.12.0b2`.

**Expected behavior** (no log-scaling where none applied):
```python
import seaborn as sns
import seaborn.objects as so
diamonds = sns.load_dataset("diamonds")

(
    so.Plot(
        diamonds, 
        x="carat", 
    )
    .pair(y=(
        "price", 
        "price", 
    ))
    .add(so.Scatter())
)
```
![image](https://user-images.githubusercontent.com/6835724/179394391-3d20b7e3-0b02-4b38-bae4-7ee0cb154f7e.png)

**Unexpected behavior** (no log-scaling even when calling `scale(y="log")`):

```python
import seaborn as sns
import seaborn.objects as so
diamonds = sns.load_dataset("diamonds")

(
    so.Plot(
        diamonds, 
        x="carat", 
    )
    .pair(y=(
        "price", 
        "price", 
    ))
    .scale(y="log")
    .add(so.Scatter())
)
```
![image](https://user-images.githubusercontent.com/6835724/179394381-897e9b5e-957a-4a52-b56d-7f953a4ece65.png)

**Expected behavior** (log-scaling works without `pair`ing):

```python
import seaborn as sns
import seaborn.objects as so
diamonds = sns.load_dataset("diamonds")

(
    so.Plot(
        diamonds, 
        x="carat", 
        y="price"
    )
    .scale(y="log")
    .add(so.Scatter())
)
```
![image](https://user-images.githubusercontent.com/6835724/179394515-ec87e88f-c11a-4f45-abbb-b377405ac0c7.png)


Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom) Report
> Merging [#3458](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom) (3f81b67) into [master](https://app.codecov.io/gh/mwaskom/seaborn/commit/082486d8505cee37416a855da65ff6349c7259e2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom) (082486d) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458/graphs/tree.svg?width=650&height=150&src=pr&token=SLuzHnA9Bl&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom)](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom)

```diff
@@           Coverage Diff           @@
##           master    #3458   +/-   ##
=======================================
  Coverage   98.33%   98.33%           
=======================================
  Files          75       75           
  Lines       24438    24449   +11     
=======================================
+ Hits        24030    24041   +11     
  Misses        408      408           
```


| [Files Changed](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom) | Coverage Δ | |
|---|---|---|
| [seaborn/\_core/plot.py](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom#diff-c2VhYm9ybi9fY29yZS9wbG90LnB5) | `98.30% <100.00%> (+<0.01%)` | :arrow_up: |
| [tests/\_core/test\_plot.py](https://app.codecov.io/gh/mwaskom/seaborn/pull/3458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Michael+Waskom#diff-dGVzdHMvX2NvcmUvdGVzdF9wbG90LnB5) | `98.82% <100.00%> (+<0.01%)` | :arrow_up: |

</details>

Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 6c25b01c..74efcb54 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -21,7 +21,7 @@ jobs:
   build-docs:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
 
       - name: Setup Python 3.11
         uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
@@ -69,7 +69,7 @@ jobs:
             deps: latest
 
     steps:
-      - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
 
       - name: Setup Python ${{ matrix.python }}
         uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
@@ -97,7 +97,7 @@ jobs:
     steps:
 
       - name: Checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
 
       - name: Setup Python
         uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
diff --git a/seaborn/_core/plot.py b/seaborn/_core/plot.py
index b8bcc00f..2723d2a0 100644
--- a/seaborn/_core/plot.py
+++ b/seaborn/_core/plot.py
@@ -1256,11 +1256,16 @@ class Plotter:
                     data.frame = res
 
     def _get_scale(
-        self, spec: Plot, var: str, prop: Property, values: Series
+        self, p: Plot, var: str, prop: Property, values: Series
     ) -> Scale:
 
-        if var in spec._scales:
-            arg = spec._scales[var]
+        if re.match(r"[xy]\d+", var):
+            key = var if var in p._scales else var[0]
+        else:
+            key = var
+
+        if key in p._scales:
+            arg = p._scales[key]
             if arg is None or isinstance(arg, Scale):
                 scale = arg
             else:
@@ -1293,7 +1298,8 @@ class Plotter:
         return seed_values
 
     def _setup_scales(
-        self, p: Plot,
+        self,
+        p: Plot,
         common: PlotData,
         layers: list[Layer],
         variables: list[str] | None = None,
@@ -1786,9 +1792,9 @@ class Plotter:
                 axis_obj = getattr(ax, f"{axis}axis")
 
                 # Axis limits
-                if axis_key in p._limits:
+                if axis_key in p._limits or axis in p._limits:
                     convert_units = getattr(ax, f"{axis}axis").convert_units
-                    a, b = p._limits[axis_key]
+                    a, b = p._limits.get(axis_key) or p._limits[axis]
                     lo = a if a is None else convert_units(a)
                     hi = b if b is None else convert_units(b)
                     if isinstance(a, str):


Test patch:
diff --git a/tests/_core/test_plot.py b/tests/_core/test_plot.py
index f61c0ae0..91e10085 100644
--- a/tests/_core/test_plot.py
+++ b/tests/_core/test_plot.py
@@ -397,6 +397,16 @@ class TestScaling:
         xfm_log = ax_log.xaxis.get_transform().transform
         assert_array_equal(xfm_log([1, 10, 100]), [0, 1, 2])
 
+    def test_paired_with_common_fallback(self):
+
+        x0, x1 = [1, 2, 3], [1, 10, 100]
+        p = Plot().pair(x=[x0, x1]).scale(x="pow", x1="log").plot()
+        ax_pow, ax_log = p._figure.axes
+        xfm_pow = ax_pow.xaxis.get_transform().transform
+        assert_array_equal(xfm_pow([1, 2, 3]), [1, 4, 9])
+        xfm_log = ax_log.xaxis.get_transform().transform
+        assert_array_equal(xfm_log([1, 10, 100]), [0, 1, 2])
+
     @pytest.mark.xfail(reason="Custom log scale needs log name for consistency")
     def test_log_scale_name(self):
 
@@ -1734,10 +1744,10 @@ class TestPairInterface:
 
     def test_limits(self, long_df):
 
-        limit = (-2, 24)
-        p = Plot(long_df, y="y").pair(x=["x", "z"]).limit(x1=limit).plot()
-        ax1 = p._figure.axes[1]
-        assert ax1.get_xlim() == limit
+        lims = (-3, 10), (-2, 24)
+        p = Plot(long_df, y="y").pair(x=["x", "z"]).limit(x=lims[0], x1=lims[1]).plot()
+        for ax, lim in zip(p._figure.axes, lims):
+            assert ax.get_xlim() == lim
 
     def test_labels(self, long_df):