Skip to content

Commit 1c391c6

Browse files
committed
minor refactor of panel4d to use factory methods from panelnd
bug in _get_plane_axes definition in panelnd updated to docs of panel4d to list currenctly disabled methods
1 parent 9a81dab commit 1c391c6

File tree

5 files changed

+83
-131
lines changed

5 files changed

+83
-131
lines changed

doc/source/dsintro.rst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,9 @@ containers.
814814

815815

816816
``Panel4D`` is a sub-class of ``Panel``, so most methods that work on Panels are
817-
applicable to Panel4D.
817+
applicable to Panel4D. The following methods are disabled:
818+
819+
- ``join , to_frame , to_excel , to_sparse , groupby``
818820

819821
Construction of Panel4D works in a very similar manner to a ``Panel``
820822

@@ -897,7 +899,8 @@ Here we slice to a Panel4D.
897899
Panel5D = panelnd.create_nd_panel_factory(
898900
klass_name = 'Panel5D',
899901
axis_orders = [ 'cool', 'labels','items','major_axis','minor_axis'],
900-
axis_slices = { 'labels' : 'labels', 'items' : 'items', 'major_axis' : 'major_axis', 'minor_axis' : 'minor_axis' },
902+
axis_slices = { 'labels' : 'labels', 'items' : 'items',
903+
'major_axis' : 'major_axis', 'minor_axis' : 'minor_axis' },
901904
slicer = Panel4D,
902905
axis_aliases = { 'major' : 'major_axis', 'minor' : 'minor_axis' },
903906
stat_axis = 2)
@@ -911,6 +914,6 @@ Here we slice to a Panel4D.
911914
# transpose it
912915
p5d.transpose(1,2,3,4,0)
913916
914-
# look at the values & dim
915-
p5d.values.shape
916-
p5d.values.ndim
917+
# look at the shape & dim
918+
p5d.shape
919+
p5d.ndim

doc/source/v0.10.0.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ Updated PyTables Support
110110
import os
111111
os.remove('store.h5')
112112

113-
NDim Panels (Experimental)
114-
~~~~~~~~~~~~~~~~~~~~~~~~~~
113+
N Dimensional Panels (Experimental)
114+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115115

116116
Adding experimental support for Panel4D and factory functions to create n-dimensional named panels.
117117
:ref:`Docs <dsintro-panel4d>` for NDim. Here is a taste of what to expect.

pandas/core/panel.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,9 @@ def ix(self):
495495
return self._ix
496496

497497
def _wrap_array(self, arr, axes, copy=False):
498-
items, major, minor = axes
499-
return self._constructor(arr, items=items, major_axis=major,
500-
minor_axis=minor, copy=copy)
498+
d = dict([ (a,ax) for a,ax in zip(self._AXIS_ORDERS,axes) ])
499+
d['copy'] = False
500+
return self._constructor(arr, **d)
501501

502502
fromDict = from_dict
503503

@@ -1433,8 +1433,8 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
14331433
contain data in the same place.
14341434
"""
14351435

1436-
if not isinstance(other, Panel):
1437-
other = Panel(other)
1436+
if not isinstance(other, self._constructor):
1437+
other = self._constructor(other)
14381438

14391439
other = other.reindex(items=self.items)
14401440

pandas/core/panel4d.py

Lines changed: 32 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,39 @@
11
""" Panel4D: a 4-d dict like collection of panels """
22

33
from pandas.core.panel import Panel
4+
from pandas.core import panelnd
45
import pandas.lib as lib
56

7+
Panel4D = panelnd.create_nd_panel_factory(
8+
klass_name = 'Panel4D',
9+
axis_orders = [ 'labels','items','major_axis','minor_axis'],
10+
axis_slices = { 'labels' : 'labels', 'items' : 'items', 'major_axis' : 'major_axis', 'minor_axis' : 'minor_axis' },
11+
slicer = Panel,
12+
axis_aliases = { 'major' : 'major_axis', 'minor' : 'minor_axis' },
13+
stat_axis = 2)
14+
15+
16+
17+
def panel4d_init(self, data=None, labels=None, items=None, major_axis=None, minor_axis=None, copy=False, dtype=None):
18+
"""
19+
Represents a 4 dimensonal structured
20+
21+
Parameters
22+
----------
23+
data : ndarray (labels x items x major x minor), or dict of Panels
24+
25+
labels : Index or array-like : axis=0
26+
items : Index or array-like : axis=1
27+
major_axis : Index or array-like: axis=2
28+
minor_axis : Index or array-like: axis=3
29+
30+
dtype : dtype, default None
31+
Data type to force, otherwise infer
32+
copy : boolean, default False
33+
Copy data from inputs. Only affects DataFrame / 2d ndarray input
34+
"""
35+
self._init_data( data=data, labels=labels, items=items, major_axis=major_axis, minor_axis=minor_axis,
36+
copy=copy, dtype=dtype)
37+
Panel4D.__init__ = panel4d_init
638

7-
class Panel4D(Panel):
8-
_AXIS_ORDERS = ['labels','items','major_axis','minor_axis']
9-
_AXIS_NUMBERS = dict([ (a,i) for i, a in enumerate(_AXIS_ORDERS) ])
10-
_AXIS_ALIASES = {
11-
'major' : 'major_axis',
12-
'minor' : 'minor_axis'
13-
}
14-
_AXIS_NAMES = dict([ (i,a) for i, a in enumerate(_AXIS_ORDERS) ])
15-
_AXIS_SLICEMAP = {
16-
'items' : 'items',
17-
'major_axis' : 'major_axis',
18-
'minor_axis' : 'minor_axis'
19-
}
20-
_AXIS_LEN = len(_AXIS_ORDERS)
21-
22-
# major
23-
_default_stat_axis = 2
24-
25-
# info axis
26-
_het_axis = 0
27-
_info_axis = _AXIS_ORDERS[_het_axis]
28-
29-
labels = lib.AxisProperty(0)
30-
items = lib.AxisProperty(1)
31-
major_axis = lib.AxisProperty(2)
32-
minor_axis = lib.AxisProperty(3)
33-
34-
_constructor_sliced = Panel
35-
36-
def __init__(self, data=None, labels=None, items=None, major_axis=None, minor_axis=None, copy=False, dtype=None):
37-
"""
38-
Represents a 4 dimensonal structured
39-
40-
Parameters
41-
----------
42-
data : ndarray (labels x items x major x minor), or dict of Panels
43-
44-
labels : Index or array-like : axis=0
45-
items : Index or array-like : axis=1
46-
major_axis : Index or array-like: axis=2
47-
minor_axis : Index or array-like: axis=3
48-
49-
dtype : dtype, default None
50-
Data type to force, otherwise infer
51-
copy : boolean, default False
52-
Copy data from inputs. Only affects DataFrame / 2d ndarray input
53-
"""
54-
self._init_data( data=data, labels=labels, items=items, major_axis=major_axis, minor_axis=minor_axis,
55-
copy=copy, dtype=dtype)
56-
57-
def _get_plane_axes(self, axis):
58-
axis = self._get_axis_name(axis)
59-
60-
if axis == 'major_axis':
61-
items = self.labels
62-
major = self.items
63-
minor = self.minor_axis
64-
elif axis == 'minor_axis':
65-
items = self.labels
66-
major = self.items
67-
minor = self.major_axis
68-
elif axis == 'items':
69-
items = self.labels
70-
major = self.major_axis
71-
minor = self.minor_axis
72-
elif axis == 'labels':
73-
items = self.items
74-
major = self.major_axis
75-
minor = self.minor_axis
76-
77-
return items, major, minor
78-
79-
def _combine(self, other, func, axis=0):
80-
if isinstance(other, Panel4D):
81-
return self._combine_panel4d(other, func)
82-
return super(Panel4D, self)._combine(other, func, axis=axis)
83-
84-
def _combine_panel4d(self, other, func):
85-
labels = self.labels + other.labels
86-
items = self.items + other.items
87-
major = self.major_axis + other.major_axis
88-
minor = self.minor_axis + other.minor_axis
89-
90-
# could check that everything's the same size, but forget it
91-
this = self.reindex(labels=labels, items=items, major=major, minor=minor)
92-
other = other.reindex(labels=labels, items=items, major=major, minor=minor)
93-
94-
result_values = func(this.values, other.values)
95-
96-
return self._constructor(result_values, labels, items, major, minor)
97-
98-
def join(self, other, how='left', lsuffix='', rsuffix=''):
99-
if isinstance(other, Panel4D):
100-
join_major, join_minor = self._get_join_index(other, how)
101-
this = self.reindex(major=join_major, minor=join_minor)
102-
other = other.reindex(major=join_major, minor=join_minor)
103-
merged_data = this._data.merge(other._data, lsuffix, rsuffix)
104-
return self._constructor(merged_data)
105-
return super(Panel4D, self).join(other=other,how=how,lsuffix=lsuffix,rsuffix=rsuffix)
106-
107-
### remove operations ####
108-
def to_frame(self, *args, **kwargs):
109-
raise NotImplementedError
110-
def to_excel(self, *args, **kwargs):
111-
raise NotImplementedError
11239

pandas/core/panelnd.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def create_nd_panel_factory(klass_name, axis_orders, axis_slices, slicer, axis_a
4646
for i, a in enumerate(axis_orders):
4747
setattr(klass,a,lib.AxisProperty(i))
4848

49-
# define the __init__
49+
#### define the methods ####
5050
def __init__(self, *args, **kwargs):
5151
if not (kwargs.get('data') or len(args)):
5252
raise Exception("must supply at least a data argument to [%s]" % klass_name)
@@ -57,27 +57,49 @@ def __init__(self, *args, **kwargs):
5757
self._init_data( *args, **kwargs)
5858
klass.__init__ = __init__
5959

60-
# define _get_place_axes
6160
def _get_plane_axes(self, axis):
61+
6262
axis = self._get_axis_name(axis)
6363
index = self._AXIS_ORDERS.index(axis)
6464

6565
planes = []
6666
if index:
6767
planes.extend(self._AXIS_ORDERS[0:index])
6868
if index != self._AXIS_LEN:
69-
planes.extend(self._AXIS_ORDERS[index:])
70-
71-
return planes
72-
klass._get_plane_axes
73-
74-
# remove these operations
75-
def to_frame(self, *args, **kwargs):
76-
raise NotImplementedError
77-
klass.to_frame = to_frame
78-
def to_excel(self, *args, **kwargs):
79-
raise NotImplementedError
80-
klass.to_excel = to_excel
69+
planes.extend(self._AXIS_ORDERS[index+1:])
70+
71+
return [ getattr(self,p) for p in planes ]
72+
klass._get_plane_axes = _get_plane_axes
73+
74+
def _combine(self, other, func, axis=0):
75+
if isinstance(other, klass):
76+
return self._combine_with_constructor(other, func)
77+
return super(klass, self)._combine(other, func, axis=axis)
78+
klass._combine = _combine
79+
80+
def _combine_with_constructor(self, other, func):
81+
82+
# combine labels to form new axes
83+
new_axes = []
84+
for a in self._AXIS_ORDERS:
85+
new_axes.append(getattr(self,a) + getattr(other,a))
86+
87+
# reindex: could check that everything's the same size, but forget it
88+
d = dict([ (a,ax) for a,ax in zip(self._AXIS_ORDERS,new_axes) ])
89+
d['copy'] = False
90+
this = self.reindex(**d)
91+
other = other.reindex(**d)
92+
93+
result_values = func(this.values, other.values)
94+
95+
return self._constructor(result_values, **d)
96+
klass._combine_with_constructor = _combine_with_constructor
97+
98+
# set as NonImplemented operations which we don't support
99+
for f in ['to_frame','to_excel','to_sparse','groupby','join','_get_join_index']:
100+
def func(self, *args, **kwargs):
101+
raise NotImplementedError
102+
setattr(klass,f,func)
81103

82104
return klass
83105

0 commit comments

Comments
 (0)