Repository: pandas-dev/pandas

Issue:
NDFrame.interpolate(): variable 'ax' not assigned when axis='index'
The `NDFrame.interpolate` function fails when passing a string as axis. Example:

```python
>>> import numpy as np
>>> import pandas as pd
>>> df = pd.DataFrame(np.zeros((3,2)), columns=['a','b'])
>>> df.iloc[1] = np.nan
>>> df
     a    b
0  0.0  0.0
1  NaN  NaN
2  0.0  0.0
>>> df.interpolate(axis=0)
     a    b
0  0.0  0.0
1  0.0  0.0
2  0.0  0.0
>>> df.interpolate(axis='index')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/lehanson/anaconda3/envs/plots/lib/python3.7/site-packages/pandas/core/generic.py", line 7006, in interpolate
    ax = _maybe_transposed_self._get_axis_number(ax)
UnboundLocalError: local variable 'ax' referenced before assignment
```


From the documentation and from the function itself, it looks like `df.interpolate(axis='index')` was intended to work, but that maybe someone accidentally deleted a line in generic.py? The function seems to work properly if I add `ax = axis` in the else block here: 
https://github.com/pandas-dev/pandas/blob/171c71611886aab8549a8620c5b0071a129ad685/pandas/core/generic.py#L6998-L7006


I am using pandas version 0.25.1


Discussion:
Thanks for the report, confirmed on master.

We should have an `axis = self._get_axis_number(axis)` at the start of `NDFrame.interpolate` (and a whatsnew note & test to ensure we don't regress).
@TomAugspurger do you mean something like this? Also: there doesn't seem to be a whatsnew file since 0.25.2, does this go into v0.25.3.rst?

```
axis = self._get_axis_number(axis)
if axis == 0:
    ax = self._info_axis_name
    _maybe_transposed_self = self
elif axis == 1:
    _maybe_transposed_self = self.T
    ax = 1
else:
    ax = axis
    _maybe_transposed_self = self
ax = _maybe_transposed_self._get_axis_number(ax)
```

Edit: sorry @gabriellm1 I didn't see your comment!

whatsnew will go in v1.0.0.rst

On Mon, Oct 21, 2019 at 3:59 PM ellequelle <notifications@github.com> wrote:

> @TomAugspurger <https://github.com/TomAugspurger> do you mean something
> like this? Also: there doesn't seem to be a whatsnew file since 0.25.2,
> does this go into v0.25.3.rst?
>
> axis = self._get_axis_number(axis)
> if axis == 0:
>     ax = self._info_axis_name
>     _maybe_transposed_self = self
> elif axis == 1:
>     _maybe_transposed_self = self.T
>     ax = 1
> else:
>     ax = axis
>     _maybe_transposed_self = self
> ax = _maybe_transposed_self._get_axis_number(ax)
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pandas-dev/pandas/issues/29132?email_source=notifications&email_token=AAKAOIUOC55VGO2P4XPEPQ3QPYJ2TA5CNFSM4JC7IVS2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB3YWGA#issuecomment-544705304>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAKAOISKWQ3QQ7MB53HPSNLQPYJ2TANCNFSM4JC7IVSQ>
> .
>


Resolving patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -7023,14 +7023,15 @@ def interpolate(
         """
         inplace = validate_bool_kwarg(inplace, "inplace")
 
+        axis = self._get_axis_number(axis)
+
         if axis == 0:
             ax = self._info_axis_name
             _maybe_transposed_self = self
         elif axis == 1:
             _maybe_transposed_self = self.T
             ax = 1
-        else:
-            _maybe_transposed_self = self
+
         ax = _maybe_transposed_self._get_axis_number(ax)
 
         if _maybe_transposed_self.ndim == 2:


Test patch:
diff --git a/pandas/tests/frame/test_missing.py b/pandas/tests/frame/test_missing.py
--- a/pandas/tests/frame/test_missing.py
+++ b/pandas/tests/frame/test_missing.py
@@ -391,13 +391,15 @@ def test_fillna_categorical_nan(self):
         cat = Categorical([np.nan, 2, np.nan])
         val = Categorical([np.nan, np.nan, np.nan])
         df = DataFrame({"cats": cat, "vals": val})
-        res = df.fillna(df.median())
+        with tm.assert_produces_warning(RuntimeWarning):
+            res = df.fillna(df.median())
         v_exp = [np.nan, np.nan, np.nan]
         df_exp = DataFrame({"cats": [2, 2, 2], "vals": v_exp}, dtype="category")
         tm.assert_frame_equal(res, df_exp)
 
         result = df.cats.fillna(np.nan)
         tm.assert_series_equal(result, df.cats)
+
         result = df.vals.fillna(np.nan)
         tm.assert_series_equal(result, df.vals)
 
@@ -876,6 +878,23 @@ def test_interp_rowwise(self):
         expected = df.interpolate()
         assert_frame_equal(result, expected)
 
+    @pytest.mark.parametrize(
+        "axis_name, axis_number",
+        [
+            pytest.param("rows", 0, id="rows_0"),
+            pytest.param("index", 0, id="index_0"),
+            pytest.param("columns", 1, id="columns_1"),
+        ],
+    )
+    def test_interp_axis_names(self, axis_name, axis_number):
+        # GH 29132: test axis names
+        data = {0: [0, np.nan, 6], 1: [1, np.nan, 7], 2: [2, 5, 8]}
+
+        df = DataFrame(data, dtype=np.float64)
+        result = df.interpolate(axis=axis_name, method="linear")
+        expected = df.interpolate(axis=axis_number, method="linear")
+        assert_frame_equal(result, expected)
+
     def test_rowwise_alt(self):
         df = DataFrame(
             {