Skip to content

Commit 3de0e64

Browse files
committed
DEPR: Panel deprecated
closes pandas-dev#13563
1 parent a347ecb commit 3de0e64

File tree

8 files changed

+2056
-1836
lines changed

8 files changed

+2056
-1836
lines changed

doc/source/whatsnew/v0.20.0.txt

+28
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Highlights include:
1111

1212
- Building pandas for development now requires ``cython >= 0.23`` (:issue:`14831`)
1313
- The ``.ix`` indexer has been deprecated, see :ref:`here <whatsnew_0200.api_breaking.deprecate_ix>`
14+
- ``Panel`` has been deprecated, see :ref:`here <whatsnew_0200.api_breaking.deprecate_panel>`
1415
- Switched the test framework to `pytest`_ (:issue:`13097`)
1516
- A new orient for JSON serialization, ``orient='table'``, that uses the Table Schema spec, see :ref: `here <whatsnew_0200.enhancements.table_schema>`
1617

@@ -284,6 +285,33 @@ Using ``.iloc``. Here we will get the location of the 'A' column, then use *posi
284285
df.iloc[[0, 2], df.columns.get_loc('A')]
285286

286287

288+
.. _whatsnew_0200.api_breaking.deprecate_panel:
289+
290+
Deprecate Panel
291+
^^^^^^^^^^^^^^^
292+
293+
- The ``Panel`` constructor is deprecated and will be removed in a future version. The recommended way to represent 3-D data are
294+
with a ``MultiIndex``on a ``DataFrame`` via the :meth:`~Panel.to_frame` or with the `xarray package <http://xarray.pydata.org/en/stable/>`__. Pandas
295+
provides a :meth:`~Panel.to_xarray` method to automate this conversion (:issue:`13563`).
296+
297+
.. ipython:: python
298+
:okwarning:
299+
300+
p = tm.makePanel()
301+
p
302+
303+
Convert to a MultiIndex DataFrame
304+
305+
.. ipython:: python
306+
307+
p.frame()
308+
309+
Convert to an xarray DataArray
310+
311+
.. ipython:: python
312+
313+
p.to_xarray()
314+
287315
.. _whatsnew.api_breaking.io_compat
288316

289317
Possible incompat for HDF5 formats for pandas < 0.13.0

pandas/core/panel.py

+12
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,18 @@ def _constructor(self):
132132

133133
def __init__(self, data=None, items=None, major_axis=None, minor_axis=None,
134134
copy=False, dtype=None):
135+
# deprecation GH13563
136+
warnings.warn("\nPanel is deprecated and will be removed in a "
137+
"future version.\nThe recommended way to represent "
138+
"these types of 3-dimensional data are with a "
139+
"MultiIndex on a DataFrame, via the "
140+
"Panel.to_frame() method\n"
141+
"alternatively, you can use the `xarray package "
142+
"<http://xarray.pydata.org/en/stable/>`__.\n"
143+
"Pandas provides a `.to_xarray()` method to help "
144+
"automate this conversion.\n",
145+
FutureWarning, stacklevel=3)
146+
135147
self._init_data(data=data, items=items, major_axis=major_axis,
136148
minor_axis=minor_axis, copy=copy, dtype=dtype)
137149

pandas/tests/test_generic.py

+95-76
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
from operator import methodcaller
55
from copy import copy, deepcopy
6+
from warnings import catch_warnings
7+
68
import pytest
79
import numpy as np
810
from numpy import nan
@@ -1570,17 +1572,18 @@ def test_to_xarray(self):
15701572
tm._skip_if_no_xarray()
15711573
from xarray import DataArray
15721574

1573-
p = tm.makePanel()
1575+
with catch_warnings(record=True):
1576+
p = tm.makePanel()
15741577

1575-
result = p.to_xarray()
1576-
self.assertIsInstance(result, DataArray)
1577-
self.assertEqual(len(result.coords), 3)
1578-
assert_almost_equal(list(result.coords.keys()),
1579-
['items', 'major_axis', 'minor_axis'])
1580-
self.assertEqual(len(result.dims), 3)
1578+
result = p.to_xarray()
1579+
self.assertIsInstance(result, DataArray)
1580+
self.assertEqual(len(result.coords), 3)
1581+
assert_almost_equal(list(result.coords.keys()),
1582+
['items', 'major_axis', 'minor_axis'])
1583+
self.assertEqual(len(result.dims), 3)
15811584

1582-
# idempotency
1583-
assert_panel_equal(result.to_pandas(), p)
1585+
# idempotency
1586+
assert_panel_equal(result.to_pandas(), p)
15841587

15851588

15861589
class TestPanel4D(tm.TestCase, Generic):
@@ -1590,15 +1593,12 @@ class TestPanel4D(tm.TestCase, Generic):
15901593
def test_sample(self):
15911594
pytest.skip("sample on Panel4D")
15921595

1593-
def test_copy_and_deepcopy(self):
1594-
pytest.skip("copy_and_deepcopy on Panel4D")
1595-
15961596
def test_to_xarray(self):
15971597

15981598
tm._skip_if_no_xarray()
15991599
from xarray import DataArray
16001600

1601-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1601+
with catch_warnings(record=True):
16021602
p = tm.makePanel4D()
16031603

16041604
result = p.to_xarray()
@@ -1624,12 +1624,20 @@ def test_to_xarray(self):
16241624
'test_stat_unexpected_keyword', 'test_api_compat',
16251625
'test_stat_non_defaults_args',
16261626
'test_clip', 'test_truncate_out_of_bounds', 'test_numpy_clip',
1627-
'test_metadata_propagation']:
1627+
'test_metadata_propagation', 'test_copy_and_deepcopy',
1628+
'test_sample']:
1629+
1630+
def f():
1631+
def tester(self):
1632+
with catch_warnings(record=True):
1633+
return getattr(super(TestPanel, self), t)()
1634+
return tester
1635+
1636+
setattr(TestPanel, t, f())
16281637

16291638
def f():
16301639
def tester(self):
1631-
with tm.assert_produces_warning(FutureWarning,
1632-
check_stacklevel=False):
1640+
with catch_warnings(record=True):
16331641
return getattr(super(TestPanel4D, self), t)()
16341642
return tester
16351643

@@ -1660,10 +1668,11 @@ def test_sample(sel):
16601668
with tm.assertRaises(ValueError):
16611669
s.sample(n=3, weights='weight_column')
16621670

1663-
panel = pd.Panel(items=[0, 1, 2], major_axis=[2, 3, 4],
1664-
minor_axis=[3, 4, 5])
1665-
with tm.assertRaises(ValueError):
1666-
panel.sample(n=1, weights='weight_column')
1671+
with catch_warnings(record=True):
1672+
panel = Panel(items=[0, 1, 2], major_axis=[2, 3, 4],
1673+
minor_axis=[3, 4, 5])
1674+
with tm.assertRaises(ValueError):
1675+
panel.sample(n=1, weights='weight_column')
16671676

16681677
with tm.assertRaises(ValueError):
16691678
df.sample(n=1, weights='weight_column', axis=1)
@@ -1726,14 +1735,15 @@ def test_sample(sel):
17261735
assert_frame_equal(sample1, df[['colString']])
17271736

17281737
# Test default axes
1729-
p = pd.Panel(items=['a', 'b', 'c'], major_axis=[2, 4, 6],
1730-
minor_axis=[1, 3, 5])
1731-
assert_panel_equal(
1732-
p.sample(n=3, random_state=42), p.sample(n=3, axis=1,
1733-
random_state=42))
1734-
assert_frame_equal(
1735-
df.sample(n=3, random_state=42), df.sample(n=3, axis=0,
1736-
random_state=42))
1738+
with catch_warnings(record=True):
1739+
p = Panel(items=['a', 'b', 'c'], major_axis=[2, 4, 6],
1740+
minor_axis=[1, 3, 5])
1741+
assert_panel_equal(
1742+
p.sample(n=3, random_state=42), p.sample(n=3, axis=1,
1743+
random_state=42))
1744+
assert_frame_equal(
1745+
df.sample(n=3, random_state=42), df.sample(n=3, axis=0,
1746+
random_state=42))
17371747

17381748
# Test that function aligns weights with frame
17391749
df = DataFrame(
@@ -1763,34 +1773,37 @@ def test_squeeze(self):
17631773
tm.assert_series_equal(s.squeeze(), s)
17641774
for df in [tm.makeTimeDataFrame()]:
17651775
tm.assert_frame_equal(df.squeeze(), df)
1766-
for p in [tm.makePanel()]:
1767-
tm.assert_panel_equal(p.squeeze(), p)
1768-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1776+
with catch_warnings(record=True):
1777+
for p in [tm.makePanel()]:
1778+
tm.assert_panel_equal(p.squeeze(), p)
1779+
with catch_warnings(record=True):
17691780
for p4d in [tm.makePanel4D()]:
17701781
tm.assert_panel4d_equal(p4d.squeeze(), p4d)
17711782

17721783
# squeezing
17731784
df = tm.makeTimeDataFrame().reindex(columns=['A'])
17741785
tm.assert_series_equal(df.squeeze(), df['A'])
17751786

1776-
p = tm.makePanel().reindex(items=['ItemA'])
1777-
tm.assert_frame_equal(p.squeeze(), p['ItemA'])
1787+
with catch_warnings(record=True):
1788+
p = tm.makePanel().reindex(items=['ItemA'])
1789+
tm.assert_frame_equal(p.squeeze(), p['ItemA'])
17781790

1779-
p = tm.makePanel().reindex(items=['ItemA'], minor_axis=['A'])
1780-
tm.assert_series_equal(p.squeeze(), p.loc['ItemA', :, 'A'])
1791+
p = tm.makePanel().reindex(items=['ItemA'], minor_axis=['A'])
1792+
tm.assert_series_equal(p.squeeze(), p.loc['ItemA', :, 'A'])
17811793

1782-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1794+
with catch_warnings(record=True):
17831795
p4d = tm.makePanel4D().reindex(labels=['label1'])
17841796
tm.assert_panel_equal(p4d.squeeze(), p4d['label1'])
17851797

1786-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1798+
with catch_warnings(record=True):
17871799
p4d = tm.makePanel4D().reindex(labels=['label1'], items=['ItemA'])
17881800
tm.assert_frame_equal(p4d.squeeze(), p4d.loc['label1', 'ItemA'])
17891801

17901802
# don't fail with 0 length dimensions GH11229 & GH8999
1791-
empty_series = pd.Series([], name='five')
1792-
empty_frame = pd.DataFrame([empty_series])
1793-
empty_panel = pd.Panel({'six': empty_frame})
1803+
empty_series = Series([], name='five')
1804+
empty_frame = DataFrame([empty_series])
1805+
with catch_warnings(record=True):
1806+
empty_panel = Panel({'six': empty_frame})
17941807

17951808
[tm.assert_series_equal(empty_series, higher_dim.squeeze())
17961809
for higher_dim in [empty_series, empty_frame, empty_panel]]
@@ -1825,13 +1838,15 @@ def test_transpose(self):
18251838
tm.assert_series_equal(s.transpose(), s)
18261839
for df in [tm.makeTimeDataFrame()]:
18271840
tm.assert_frame_equal(df.transpose().transpose(), df)
1828-
for p in [tm.makePanel()]:
1829-
tm.assert_panel_equal(p.transpose(2, 0, 1)
1830-
.transpose(1, 2, 0), p)
1831-
tm.assertRaisesRegexp(TypeError, msg, p.transpose,
1832-
2, 0, 1, axes=(2, 0, 1))
18331841

1834-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1842+
with catch_warnings(record=True):
1843+
for p in [tm.makePanel()]:
1844+
tm.assert_panel_equal(p.transpose(2, 0, 1)
1845+
.transpose(1, 2, 0), p)
1846+
tm.assertRaisesRegexp(TypeError, msg, p.transpose,
1847+
2, 0, 1, axes=(2, 0, 1))
1848+
1849+
with catch_warnings(record=True):
18351850
for p4d in [tm.makePanel4D()]:
18361851
tm.assert_panel4d_equal(p4d.transpose(2, 0, 3, 1)
18371852
.transpose(1, 3, 0, 2), p4d)
@@ -1853,12 +1868,13 @@ def test_numpy_transpose(self):
18531868
tm.assertRaisesRegexp(ValueError, msg,
18541869
np.transpose, df, axes=1)
18551870

1856-
p = tm.makePanel()
1857-
tm.assert_panel_equal(np.transpose(
1858-
np.transpose(p, axes=(2, 0, 1)),
1859-
axes=(1, 2, 0)), p)
1871+
with catch_warnings(record=True):
1872+
p = tm.makePanel()
1873+
tm.assert_panel_equal(np.transpose(
1874+
np.transpose(p, axes=(2, 0, 1)),
1875+
axes=(1, 2, 0)), p)
18601876

1861-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1877+
with catch_warnings(record=True):
18621878
p4d = tm.makePanel4D()
18631879
tm.assert_panel4d_equal(np.transpose(
18641880
np.transpose(p4d, axes=(2, 0, 3, 1)),
@@ -1880,15 +1896,16 @@ def test_take(self):
18801896
tm.assert_frame_equal(out, expected)
18811897

18821898
indices = [-3, 2, 0, 1]
1883-
for p in [tm.makePanel()]:
1884-
out = p.take(indices)
1885-
expected = Panel(data=p.values.take(indices, axis=0),
1886-
items=p.items.take(indices),
1887-
major_axis=p.major_axis,
1888-
minor_axis=p.minor_axis)
1889-
tm.assert_panel_equal(out, expected)
1890-
1891-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1899+
with catch_warnings(record=True):
1900+
for p in [tm.makePanel()]:
1901+
out = p.take(indices)
1902+
expected = Panel(data=p.values.take(indices, axis=0),
1903+
items=p.items.take(indices),
1904+
major_axis=p.major_axis,
1905+
minor_axis=p.minor_axis)
1906+
tm.assert_panel_equal(out, expected)
1907+
1908+
with catch_warnings(record=True):
18921909
for p4d in [tm.makePanel4D()]:
18931910
out = p4d.take(indices)
18941911
expected = Panel4D(data=p4d.values.take(indices, axis=0),
@@ -1902,9 +1919,9 @@ def test_take_invalid_kwargs(self):
19021919
indices = [-3, 2, 0, 1]
19031920
s = tm.makeFloatSeries()
19041921
df = tm.makeTimeDataFrame()
1905-
p = tm.makePanel()
19061922

1907-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
1923+
with catch_warnings(record=True):
1924+
p = tm.makePanel()
19081925
p4d = tm.makePanel4D()
19091926

19101927
for obj in (s, df, p, p4d):
@@ -2011,8 +2028,9 @@ def test_equals(self):
20112028
self.assertTrue(e.equals(f))
20122029

20132030
def test_describe_raises(self):
2014-
with tm.assertRaises(NotImplementedError):
2015-
tm.makePanel().describe()
2031+
with catch_warnings(record=True):
2032+
with tm.assertRaises(NotImplementedError):
2033+
tm.makePanel().describe()
20162034

20172035
def test_pipe(self):
20182036
df = DataFrame({'A': [1, 2, 3]})
@@ -2043,15 +2061,16 @@ def test_pipe_tuple_error(self):
20432061
df.A.pipe((f, 'y'), x=1, y=0)
20442062

20452063
def test_pipe_panel(self):
2046-
wp = Panel({'r1': DataFrame({"A": [1, 2, 3]})})
2047-
f = lambda x, y: x + y
2048-
result = wp.pipe(f, 2)
2049-
expected = wp + 2
2050-
assert_panel_equal(result, expected)
2051-
2052-
result = wp.pipe((f, 'y'), x=1)
2053-
expected = wp + 1
2054-
assert_panel_equal(result, expected)
2055-
2056-
with tm.assertRaises(ValueError):
2057-
result = wp.pipe((f, 'y'), x=1, y=1)
2064+
with catch_warnings(record=True):
2065+
wp = Panel({'r1': DataFrame({"A": [1, 2, 3]})})
2066+
f = lambda x, y: x + y
2067+
result = wp.pipe(f, 2)
2068+
expected = wp + 2
2069+
assert_panel_equal(result, expected)
2070+
2071+
result = wp.pipe((f, 'y'), x=1)
2072+
expected = wp + 1
2073+
assert_panel_equal(result, expected)
2074+
2075+
with tm.assertRaises(ValueError):
2076+
result = wp.pipe((f, 'y'), x=1, y=1)

0 commit comments

Comments
 (0)