"""
Utilities for uniform treatment of DataTable and numpy array objects for functions which can deal with them both.
"""
from . import column
from . import table as datatable, indexing
from . import table_storage
from ..utils import iterator as iterator_utils #@UnresolvedImport
import numpy as np
import pandas as pd
[docs]class IGenWrapper(object):
"""
The interface for a wrapper that gives a uniform access to basic methods of wrapped objects'.
"""
def __init__(self, container):
object.__init__(self)
self.cont=container
def __getitem__(self, idx):
return self.cont[idx]
def __setitem__(self, idx, val):
self.cont[idx]=val
def __iter__(self):
return self.cont.__iter__()
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
raise NotImplementedError("IGenWrapper.get_type")
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the object copy; otherwise, just return the copy."""
raise NotImplementedError("IGenWrapper.copy")
[docs] def ndim(self):
return self.cont.ndim
[docs] def shape(self):
return self.cont.shape
def __len__(self):
return self.shape()[0]
[docs]class I1DWrapper(IGenWrapper):
"""
A wrapper containing a 1D object (a 1D numpy array or a `IDataColumn` object).
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
IGenWrapper.__init__(self, container)
self.r=self.Accessor(self)
self.t=self.Accessor(self)
[docs] class Accessor(object):
"""
An accessor: creates a simple uniform interface to treat the wrapped object element-wise (get/set/iterate over elements).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper):
object.__init__(self)
self._wrapper=wrapper
def __iter__(self):
return self._wrapper.__iter__()
def __getitem__(self, idx):
return self._wrapper.subcolumn(idx,wrapped=False)
def __setitem__(self, idx, val):
self._wrapper[idx]=val
[docs] def subcolumn(self, idx, wrapped=True):
"""
Return a subcolumn at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
raise NotImplementedError("I1DWrapper.subtable")
[docs] @staticmethod
def from_array(array, force_copy=False, force_numpy=True, try_optimizing=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a 1D numpy array or a list).
If ``force_copy==True``, make a copy of supplied array.
For a :class:`Column1DWrapper`, if `column` is a list and ``force_numpy==True``, turn it into a numpy array and return :class:`.ArrayDataColumn`
(by default lists are wrapped into :class:`.ListDataColumn`).
For a :class:`Column1DWrapper`, if ``try_optimizing==True``, check if the column can be turned into a :class:`.LinearDataColumn`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
raise NotImplementedError("I1DWrapper.from_array")
[docs] @classmethod
def from_columns(cls, columns, column_names=None, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `columns` (a list of columns; only length-1 lists is supported).
`column_names` parameter is ignored.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
if len(columns)!=1:
raise ValueError("Array1DWrapper only supports single columns, got {} columns".format(len(columns)))
return cls.from_array(columns[0])
[docs] def array_replaced(self, array, force_copy=False, force_numpy=True, try_optimizing=False, wrapped=True):
"""
Return a copy of the column with the data replaced by `array`.
All of the parameters are the same as in :meth:`from_array`.
"""
return self.from_array(array, force_copy=force_copy, force_numpy=force_numpy, try_optimizing=try_optimizing, wrapped=wrapped)
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
raise NotImplementedError("I1DWrapper.get_type")
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the object copy; otherwise, just return the copy."""
raise NotImplementedError("I1DWrapper.copy")
[docs] def ndim(self):
return 1
[docs]class Array1DWrapper(I1DWrapper):
"""
A wrapper for a 1D numpy array.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
container=np.asarray(container)
if container.ndim!=1:
raise ValueError("Array1DWrapper only supports 1D arrays, got {}D array".format(container.ndim))
I1DWrapper.__init__(self, container)
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a copy of the column with the data at index `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=np.delete(self.cont, idx, axis=0)
return Array1DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
self.cont=self.get_deleted(idx,wrapped=False)
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a copy of the column with the data `val` added at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=np.insert(self.cont, idx, val, axis=0)
return Array1DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""Add data `val` to index `idx`."""
self.cont=self.get_inserted(idx,val,wrapped=False)
[docs] def get_appended(self, val, wrapped=True):
"""
Return a copy of the column with the data `val` appended at the end.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=np.append(self.cont, val, axis=0)
return Array1DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Append data `val` to the end."""
self.cont=self.get_appended(val,wrapped=False)
[docs] def subcolumn(self, idx, wrapped=True):
"""
Return a subcolumn at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Array1DWrapper(self.cont[idx]) if wrapped else self.cont[idx]
[docs] @staticmethod
def from_array(array, force_copy=False, force_numpy=True, try_optimizing=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a 1D numpy array or a list).
If ``force_copy==True``, make a copy of supplied array.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
`force_numpy` and `try_optimizing` parameters are ignored.
"""
new_cont=np.array(array) if force_copy else np.asarray(array)
return Array1DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "1d.array"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the object copy; otherwise, just return the copy."""
new_cont=self.cont.copy()
return Array1DWrapper(new_cont) if wrapped else new_cont
[docs]class Column1DWrapper(I1DWrapper):
"""
A wrapper for an :class:`.IDataColumn` object.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
if not isinstance(container, column.IDataColumn):
container=column.as_column(container,force_copy=False)
I1DWrapper.__init__(self, container)
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a copy of the column with the data at index `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self.cont.copy()
del self.cont[idx]
return Column1DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
del self.cont[idx]
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a copy of the column with the data `val` added at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self.cont.copy()
new_cont.insert(val,idx)
return Column1DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""Add data `val` to index `idx`."""
self.cont.insert(idx,val)
[docs] def get_appended(self, val, wrapped=True):
"""
Return a copy of the column with the data `val` appended at the end.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self.cont.copy()
new_cont.append(val)
return Column1DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Append data `val` to the end."""
self.cont.append(val)
[docs] def subcolumn(self, idx, wrapped=True):
"""
Return a subcolumn at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Column1DWrapper(self.cont.subcolumn(idx)) if wrapped else self.cont.subcolumn(idx)
[docs] @staticmethod
def from_array(array, force_copy=False, force_numpy=True, try_optimizing=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a 1D numpy array or a list).
If ``force_copy==True``, make a copy of supplied array.
If `column` is a list and ``force_numpy==True``, turn it into a numpy array and return :class:`.ArrayDataColumn`
(by default lists are wrapped into :class:`.ListDataColumn`).
If ``try_optimizing==True``, check if the column can be turned into a :class:`.LinearDataColumn`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=column.as_column(array,force_numpy=force_numpy,force_copy=force_copy,try_linear=try_optimizing)
return Column1DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "1d.column"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the object copy; otherwise, just return the copy."""
new_cont=self.cont.copy()
return Column1DWrapper(new_cont) if wrapped else new_cont
[docs]class Series1DWrapper(I1DWrapper):
"""
A wrapper for a pandas Series object.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
if not isinstance(container, pd.Series):
container=pd.Series(container)
I1DWrapper.__init__(self, container)
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a copy of the column with the data at index `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self.cont.drop(self.cont.index[idx])
return Series1DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
self.cont.drop(self.cont.index[idx],inplace=True)
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a copy of the column with the data `val` added at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=pd.concat([self.cont.iloc[:idx],pd.Series(val,copy=False),self.cont.iloc[idx:]])
return Series1DWrapper(new_cont) if wrapped else new_cont
[docs] def get_appended(self, val, wrapped=True):
"""
Return a copy of the column with the data `val` appended at the end.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self.cont.append(val)
return Series1DWrapper(new_cont) if wrapped else new_cont
[docs] def subcolumn(self, idx, wrapped=True):
"""
Return a subcolumn at index `idx`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Series1DWrapper(self.cont.iloc[idx]) if wrapped else self.cont.iloc[idx]
[docs] @staticmethod
def from_array(array, force_copy=False, force_numpy=True, try_optimizing=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a 1D numpy array or a list).
If ``force_copy==True``, make a copy of supplied array.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
`force_numpy` and `try_optimizing` parameters are ignored.
"""
new_cont=pd.Series(array,copy=force_copy)
return Series1DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "1d.column"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the object copy; otherwise, just return the copy."""
new_cont=self.cont.copy()
return Series1DWrapper(new_cont) if wrapped else new_cont
[docs]class I2DWrapper(IGenWrapper):
"""
A wrapper containing a 2D object (a 2D numpy array or a :class:`.DataTable` object).
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container, r=None, c=None, t=None):
IGenWrapper.__init__(self, container)
self.r=r
self.c=c
self.t=t
[docs] @staticmethod
def from_columns(columns, column_names=None, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `columns` (a list of columns).
`column_names` supplies names of the columns (only relevant for :class:`Table2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
raise NotImplementedError("I2DWrapper.from_columns")
[docs] def columns_replaced(self, columns, wrapped=True):
"""
Return copy of the object with the data replaced by `columns`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
return self.from_columns(columns, self.c.get_names(), wrapped=wrapped)
[docs] @staticmethod
def from_array(array, column_names=None, force_copy=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a list of rows or a 2D numpy array).
`column_names` supplies names of the columns (only relevant for :class:`Table2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
raise NotImplementedError("I2DWrapper.from_array")
[docs] def array_replaced(self, array, force_copy=False, wrapped=True):
"""
Return a copy of the column with the data replaced by `array`.
All of the parameters are the same as in :meth:`from_array`.
"""
return self.from_array(array, self.c.get_names(), force_copy=force_copy, wrapped=wrapped)
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
raise NotImplementedError("I2DWrapper.get_type")
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table."""
raise NotImplementedError("I2DWrapper.copy")
[docs] def column(self, idx, wrapped=True):
"""
Get a column at index `idx`.
Return a 1D numpy array for a 2D numpy array object, and an :class:`.IDataColumn` object for a :class:`.DataTable`.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
raise NotImplementedError("I2DWrapper.column")
[docs] def subtable(self, idx, wrapped=True):
"""
Return a subtable at index `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
raise NotImplementedError("I2DWrapper.subtable")
[docs] def ndim(self):
return 2
[docs]class Array2DWrapper(I2DWrapper):
"""
A wrapper for a 2D numpy array.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
container=np.asarray(container)
if container.ndim!=2:
raise ValueError("Array2DWrapper only supports 2D arrays, got {}D array".format(container.ndim))
I2DWrapper.__init__(self, container,
self.RowAccessor(self,container), self.ColumnAccessor(self,container), self.TableAccessor(container))
[docs] def set_container(self,cont):
self.cont=cont
self.r._storage=cont
self.c._storage=cont
self.t._storage=cont
[docs] class RowAccessor(object):
"""
A row accessor: creates a simple uniform interface to treat the wrapped object row-wise (append/insert/delete/iterate over rows).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return iterator_utils.AccessIterator(self._storage, lambda obj, idx: obj[idx])
def __getitem__(self, idx):
return self._storage[idx]
def __setitem__(self, idx, val):
self._storage[idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a new table with the rows at `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.delete(self._storage, idx, axis=0)
return Array2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
self._wrapper.set_container(self.get_deleted(idx,wrapped=False))
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a new table with new rows given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.insert(self._storage, idx, val, axis=0)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""
Insert new rows given by `val` at index `idx`.
"""
self._wrapper.set_container(self.get_inserted(idx,val,wrapped=False))
[docs] def get_appended(self, val, wrapped=True):
"""
Return a new table with new rows given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.append(self._storage, val, axis=0)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Insert new rows given by `val` to the end of the table."""
self._wrapper.set_container(self.get_appended(val,wrapped=False))
[docs] class ColumnAccessor(object):
"""
A column accessor: creates a simple uniform interface to treat the wrapped object column-wise (append/insert/delete/iterate over columns).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return iterator_utils.AccessIterator(self._storage, lambda obj, idx: obj[:,idx])
def __getitem__(self, idx):
return self._storage[:,idx]
def __setitem__(self, idx, val):
self._storage[:,idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a new table with the columns at `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.delete(self._storage, idx, axis=1)
return Array2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
self._wrapper.set_container(self.get_deleted(idx,wrapped=False))
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a new table with new columns given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.insert(self._storage, idx, val, axis=1)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""
Insert new columns given by `val` at index `idx`.
"""
self._wrapper.set_container(self.get_inserted(idx,val,wrapped=False))
[docs] def get_appended(self, val, wrapped=True):
"""
Return a new table with new columns given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=np.append(self._storage, val, axis=1)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Insert new columns given by `val` to the end of the table."""
self._wrapper.set_container(self.get_appended(val,wrapped=False))
[docs] def set_names(self, names):
"""Set column names (does nothing)."""
pass
[docs] def get_names(self):
"""Get column names (all names are ``None``)."""
return [None]*self._storage.shape[1]
[docs] def get_index(self, idx):
"""Get number index for a given column index"""
return (idx if idx>=0 else self._storage.shape[1]-idx)
[docs] class TableAccessor(object):
"""
A table accessor: acessing the table data through this interface returns an object of the appropriate type
(numpy array for numpy wrapped object, and :class:`.DataTable` for :class:`.DataTable` wrapped object).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, storage):
object.__init__(self)
self._storage=storage
def __iter__(self):
return iterator_utils.AccessIterator(self)
def __getitem__(self, idx):
return self._storage[idx]
def __setitem__(self, idx, val):
self._storage[idx]=val
[docs] def subtable(self, idx, wrapped=True):
"""
Return a subtable at index `idx` of the appropriate type (2D numpy array).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
return Array2DWrapper(self.cont[idx]) if wrapped else self.cont[idx]
[docs] def column(self, idx, wrapped=True):
"""
Get a column at index `idx` as a 1D numpy array.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Array1DWrapper(self.cont[:,idx]) if wrapped else self.cont[:,idx]
[docs] @staticmethod
def from_columns(columns, column_names=None, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `columns` (a list of columns).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
`column_names` parameter is ignored.
"""
new_cont=np.column_stack(columns)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] @staticmethod
def from_array(array, column_names=None, force_copy=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a list of rows or a 2D numpy array).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
`column_names` parameter is ignored.
"""
new_cont=np.array(array) if force_copy else np.asarray(array)
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "2d.array"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table."""
new_cont=self.cont.copy()
return Array2DWrapper(new_cont) if wrapped else new_cont
[docs]class Table2DWrapper(I2DWrapper):
"""
A wrapper for a :class:`.DataTable` object.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
if not isinstance(container, datatable.DataTable):
container=datatable.DataTable(container,force_copy=False)
if container.ndim!=2:
raise ValueError("Table2DWrapper only supports 2D arrays, got {}D array".format(container.ndim))
I2DWrapper.__init__(self, container,
self.RowAccessor(self,container), self.ColumnAccessor(self,container), self.TableAccessor(container))
[docs] class RowAccessor(object):
"""
A row accessor: creates a simple uniform interface to treat the wrapped object row-wise (append/insert/delete/iterate over rows).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return self._storage.ra.__iter__()
def __getitem__(self, idx):
return self._storage.ra[idx]
def __setitem__(self, idx, val):
self._storage.r[idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a new table with the rows at `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy()
del new_cont.r[idx]
return Table2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
del self._storage.r[idx]
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a new table with new rows given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy()
new_cont.r.insert(idx,val)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""
Insert new rows given by `val` at index `idx`.
"""
self._storage.r.insert(idx,val)
[docs] def get_appended(self, val, wrapped=True):
"""
Return a new table with new rows given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy()
new_cont.r.append(val)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Insert new rows given by `val` to the end of the table."""
self._storage.r.append(val)
[docs] class ColumnAccessor(object):
"""
A column accessor: creates a simple uniform interface to treat the wrapped object column-wise (append/insert/delete/iterate over columns).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return self._storage.c.__iter__()
def __getitem__(self, idx):
return self._storage.c[idx]
def __setitem__(self, idx, val):
self._storage.c[idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a new table with the columns at `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy(copy_columns=False)
del new_cont.c[idx]
return Table2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
del self._storage.c[idx]
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a new table with new columns given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy(copy_columns=False)
new_cont.c.insert(idx,val)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""Insert new columns given by `val` at index `idx`."""
self._storage.c.insert(idx,val)
[docs] def get_appended(self, val, wrapped=True):
"""
Return a new table with new columns given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.copy(copy_columns=False)
new_cont.c.append(val)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Insert new columns given by `val` to the end of the table."""
self._storage.c.append(val)
[docs] def set_names(self, names):
"""Set column names."""
self._storage.set_column_names(names)
[docs] def get_names(self):
"""Get column names."""
return self._storage.get_column_names()
[docs] def get_index(self, idx):
"""Get number index for a given column index"""
idx=indexing.to_list_idx(idx,self.get_names()).idx
return (idx if idx>=0 else self._storage.shape[1]-idx)
[docs] class TableAccessor(object):
"""
A table accessor: acessing the table data through this interface returns an object of the appropriate type
(numpy array for numpy wrapped object, and :class:`.DataTable` for :class:`.DataTable` wrapped object).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, storage):
object.__init__(self)
self._storage=storage
def __iter__(self):
return self._storage.t.__iter__()
def __getitem__(self, idx):
return self._storage.t[idx]
def __setitem__(self, idx, val):
self._storage.t[idx]=val
[docs] def subtable(self, idx, wrapped=True):
"""
Return a subtable at index `idx` of the appropriate type (:class:`.DataTable`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
return Table2DWrapper(self.cont.t[idx]) if wrapped else self.cont.t[idx]
[docs] def column(self, idx, wrapped=True):
"""
Get a column at index `idx` as an :class:`.IDataColumn` object.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Column1DWrapper(self.cont.c[idx]) if wrapped else self.cont.c[idx]
[docs] @staticmethod
def from_columns(columns, column_names=None, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `columns` (a list of columns).
`column_names` supplies names of the columns (only relevant for :class:`Table2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=datatable.DataTable(columns,column_names)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] @staticmethod
def from_array(array, column_names=None, force_copy=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a list of rows or a 2D numpy array).
`column_names` supplies names of the columns (only relevant for :class:`Table2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=datatable.DataTable(array,column_names,force_copy=force_copy)
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "2d.table"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table."""
new_cont=self.cont.copy()
return Table2DWrapper(new_cont) if wrapped else new_cont
[docs]class DataFrame2DWrapper(I2DWrapper):
"""
A wrapper for a pandas DataFrame object.
Provides a uniform access to basic methods of a wrapped object.
"""
def __init__(self, container):
if not isinstance(container, pd.DataFrame):
container=pd.DataFrame(container,copy=False)
if container.ndim!=2:
raise ValueError("DataFrame2DWrapper only supports 2D arrays, got {}D array".format(container.ndim))
I2DWrapper.__init__(self, container,
self.RowAccessor(self,container), self.ColumnAccessor(self,container), self.TableAccessor(container))
def __getitem__(self, idx):
res=self.cont.iloc[idx]
return np.asarray(res) if len(table_storage.get_shape(res))>0 else res
def __setitem__(self, idx, val):
self.cont.iloc[idx]=val
[docs] class RowAccessor(object):
"""
A row accessor: creates a simple uniform interface to treat the wrapped object row-wise (append/insert/delete/iterate over rows).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return self._storage.__iter__()
def __getitem__(self, idx):
return self._storage.iloc[idx]
def __setitem__(self, idx, val):
self._storage.iloc[idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a copy of the column with the data at index `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
new_cont=self._storage.drop(self._storage.index[idx])
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
self._storage.drop(self._storage.index[idx],inplace=True)
[docs] def get_inserted(self, idx, val, wrapped=True):
"""
Return a new table with new rows given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=pd.concat([self._storage.iloc[:idx],pd.DataFrame(val,copy=False),self._storage.iloc[idx:]])
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
[docs] def insert(self, idx, val):
"""
Insert new rows given by `val` at index `idx`.
"""
self._wrapper.set_container(self.get_inserted(idx,val,wrapped=False))
[docs] def get_appended(self, val, wrapped=True):
"""
Return a new table with new rows given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=self._storage.append(val)
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
[docs] def append(self, val):
"""Insert new rows given by `val` to the end of the table."""
self._wrapper.set_container(self.get_appended(val,wrapped=False))
[docs] class ColumnAccessor(object):
"""
A column accessor: creates a simple uniform interface to treat the wrapped object column-wise (append/insert/delete/iterate over columns).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, wrapper, storage):
object.__init__(self)
self._wrapper=wrapper
self._storage=storage
def __iter__(self):
return self._storage.c.__iter__()
def __getitem__(self, idx):
return self._storage.iloc[:,idx]
def __setitem__(self, idx, val):
self._storage.iloc[:,idx]=val
[docs] def get_deleted(self, idx, wrapped=True):
"""
Return a new table with the columns at `idx` deleted.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
try:
new_cont=self._storage.drop(idx,axis="columns")
except (TypeError,KeyError):
new_cont=self._storage.drop(self._storage.columns[idx],axis="columns")
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
def __delitem__(self, idx):
try:
self._storage.drop(idx,axis="columns",inplace=True)
except (TypeError,KeyError):
self._storage.drop(self._storage.columns[idx],axis="columns",inplace=True)
[docs] def get_inserted(self, idx, val, column_name=None, wrapped=True):
"""
Return a new table with new columns given by `val` inserted at `idx`.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_wrap=self._wrapper.copy()
new_wrap.insert(idx,val,column_name=column_name)
return new_wrap if wrapped else new_wrap.cont
[docs] def insert(self, idx, val, column_name=None):
"""Insert new columns given by `val` at index `idx`."""
if column_name is None:
column_name=self._storage.shape[1]
while column_name in self._storage.columns:
column_name+=1
self._storage.insert(idx,column_name,val)
[docs] def get_appended(self, val, column_name=None, wrapped=True):
"""
Return a new table with new columns given by `val` appended to the end of the table.
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
return self.get_inserted(-1,val,column_name=column_name,wrapped=wrapped)
[docs] def append(self, val, column_name=None):
"""Insert new columns given by `val` to the end of the table."""
return self.insert(-1,val,column_name=column_name)
[docs] def set_names(self, names):
"""Set column names."""
self._storage.columns=names
[docs] def get_names(self):
"""Get column names."""
return list(self._storage.columns)
[docs] def get_index(self, idx):
"""Get number index for a given column index"""
idx=indexing.to_list_idx(idx,self.get_names()).idx
return (idx if idx>=0 else self._storage.shape[1]-idx)
[docs] class TableAccessor(object):
"""
A table accessor: acessing the table data through this interface returns an object of the appropriate type
(numpy array for numpy wrapped object, and :class:`.DataTable` for :class:`.DataTable` wrapped object).
Generated automatically for each table on creation, doesn't need to be created explicitly.
"""
def __init__(self, storage):
object.__init__(self)
self._storage=storage
def __iter__(self):
return self._storage.iloc.__iter__()
def __getitem__(self, idx):
return self._storage.iloc[idx]
def __setitem__(self, idx, val):
self._storage.iloc[idx]=val
def _get_df_columns(self, idx):
try:
return self.cont.loc(axis="columns")[idx]
except (TypeError,KeyError):
return self.cont.iloc(axis="columns")[idx]
[docs] def subtable(self, idx, wrapped=True):
"""
Return a subtable at index `idx` of the appropriate type (:class:`.DataTable`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
return DataFrame2DWrapper(self._get_df_columns(idx)) if wrapped else self._get_df_columns(idx)
[docs] def column(self, idx, wrapped=True):
"""
Get a column at index `idx` as an :class:`.IDataColumn` object.
If ``wrapped==True``, return a new wrapper contating the column; otherwise, just return the column.
"""
return Series1DWrapper(self._get_df_columns(idx)) if wrapped else self._get_df_columns(idx)
[docs] @staticmethod
def from_columns(columns, column_names=None, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `columns` (a list of columns).
`column_names` supplies names of the columns (only relevant for :class:`DataFrame2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
if column_names is None:
column_names=list(range(len(columns)))
new_cont=pd.DataFrame(dict(zip(column_names,columns)),columns=column_names)
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
[docs] @staticmethod
def from_array(array, column_names=None, force_copy=False, wrapped=True):
"""
Build a new object of the type corresponding to the wrapper from the supplied `array` (a list of rows or a 2D numpy array).
`column_names` supplies names of the columns (only relevant for :class:`DataFrame2DWrapper`).
If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table.
"""
new_cont=pd.DataFrame(array,columns=column_names,copy=force_copy)
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
[docs] def get_type(self):
"""Get a string representing the wrapped object type"""
return "2d.pandas"
[docs] def copy(self, wrapped=True):
"""Copy the object. If ``wrapped==True``, return a new wrapper contating the table; otherwise, just return the table."""
new_cont=self.cont.copy()
return DataFrame2DWrapper(new_cont) if wrapped else new_cont
[docs]def wrap1d(container):
"""
Wrap a 1D container (a 1D numpy array or an :class:`.IDataColumn`) into an appropriate wrapper.
"""
if isinstance(container, column.IDataColumn):
return Column1DWrapper(container)
if isinstance(container, pd.Series):
return Series1DWrapper(container)
return Array1DWrapper(container)
[docs]def wrap2d(container):
"""
Wrap a 2D container (a 2D numpy array or a :class:`.DataTable`) into an appropriate wrapper.
"""
if isinstance(container, datatable.DataTable):
return Table2DWrapper(container)
if isinstance(container, pd.DataFrame):
return DataFrame2DWrapper(container)
return Array2DWrapper(container)
[docs]def wrap(container):
"""
Wrap container (a numpy array, an :class:`.IDataColumn` or a :class:`.DataTable`) into an appropriate wrapper.
"""
if isinstance(container,IGenWrapper):
return container
ndim=len(table_storage.get_shape(container))
if ndim==1:
return wrap1d(container)
elif ndim==2:
return wrap2d(container)
else:
raise ValueError("wrap only supports 1D and 2D arrays, got {}D".format(ndim))