Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xarray.core.variable.as_variable part of the public API #1422

Merged
merged 8 commits into from
Jun 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ Advanced API

Variable
IndexVariable
as_variable
register_dataset_accessor
register_dataarray_accessor

Expand Down
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Enhancements
to ``py.test`` (:issue:`1393`).
By `Matthew Gidden <https://github.com/gidden>`_.

- ``xarray.core.variable.as_variable`` is now part of the public API and
can be accessed using :py:meth:`~xarray.as_variable` (:issue:`1303`).
By `Benoit Bovy <https://github.com/benbovy>`_.

- :py:func:`~xarray.align` now supports ``join='exact'``, which raises
an error instead of aligning when indexes to be aligned are not equal.
By `Stephan Hoyer <https://github.com/shoyer>`_.
Expand Down
2 changes: 1 addition & 1 deletion xarray/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .core.combine import concat, auto_combine
from .core.extensions import (register_dataarray_accessor,
register_dataset_accessor)
from .core.variable import Variable, IndexVariable, Coordinate
from .core.variable import as_variable, Variable, IndexVariable, Coordinate
from .core.dataset import Dataset
from .core.dataarray import DataArray
from .core.merge import merge, MergeError
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ def _combine(self, applied, shortcut=False):
combined = self._restore_dim_order(combined)
if coord is not None:
if shortcut:
combined._coords[coord.name] = as_variable(coord, copy=True)
combined._coords[coord.name] = as_variable(coord)
else:
combined.coords[coord.name] = coord
combined = self._maybe_restore_empty_groups(combined)
Expand Down
41 changes: 31 additions & 10 deletions xarray/core/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,32 @@
pass


def as_variable(obj, name=None, copy=False):
"""Convert an object into an Variable.

- If the object is already an `Variable`, return a shallow copy.
- Otherwise, if the object has 'dims' and 'data' attributes, convert
it into a new `Variable`.
- If all else fails, attempt to convert the object into an `Variable` by
unpacking it into the arguments for `Variable.__init__`.
def as_variable(obj, name=None):
"""Convert an object into a Variable.

Parameters
----------
obj : object
Object to convert into a Variable.

- If the object is already a Variable, return a shallow copy.
- Otherwise, if the object has 'dims' and 'data' attributes, convert
it into a new Variable.
- If all else fails, attempt to convert the object into a Variable by
unpacking it into the arguments for creating a new Variable.
name : str, optional
If provided:

- `obj` can be a 1D array, which is assumed to label coordinate values
along a dimension of this given name.
- Variables with name matching one of their dimensions are converted
into `IndexVariable` objects.

Returns
-------
var : Variable
The newly created variable.

"""
# TODO: consider extending this method to automatically handle Iris and
# pandas objects.
Expand All @@ -47,7 +65,10 @@ def as_variable(obj, name=None, copy=False):
obj = obj.copy(deep=False)
elif hasattr(obj, 'dims') and (hasattr(obj, 'data') or
hasattr(obj, 'values')):
obj = Variable(obj.dims, getattr(obj, 'data', obj.values),
obj_data = getattr(obj, 'data', None)
if obj_data is None:
obj_data = getattr(obj, 'values')
obj = Variable(obj.dims, obj_data,
getattr(obj, 'attrs', None),
getattr(obj, 'encoding', None))
elif isinstance(obj, tuple):
Expand Down Expand Up @@ -75,7 +96,7 @@ def as_variable(obj, name=None, copy=False):
'explicit list of dimensions: %r' % obj)

if name is not None and name in obj.dims:
# convert the into an Index
# convert the Variable into an Index
if obj.ndim != 1:
raise ValueError(
'%r has more than 1-dimension and the same name as one of its '
Expand Down
30 changes: 27 additions & 3 deletions xarray/tests/test_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,20 +609,35 @@ def test_no_conflicts(self):
def test_as_variable(self):
data = np.arange(10)
expected = Variable('x', data)
expected_extra = Variable('x', data, attrs={'myattr': 'val'},
encoding={'scale_factor': 1})

self.assertVariableIdentical(expected, as_variable(expected))

ds = Dataset({'x': expected})
self.assertVariableIdentical(expected, as_variable(ds['x']).to_base_variable())
var = as_variable(ds['x']).to_base_variable()
self.assertVariableIdentical(expected, var)
self.assertNotIsInstance(ds['x'], Variable)
self.assertIsInstance(as_variable(ds['x']), Variable)

FakeVariable = namedtuple('FakeVariable', 'values dims')
fake_xarray = FakeVariable(expected.values, expected.dims)
self.assertVariableIdentical(expected, as_variable(fake_xarray))

xarray_tuple = (expected.dims, expected.values)
self.assertVariableIdentical(expected, as_variable(xarray_tuple))
FakeVariable = namedtuple('FakeVariable', 'data dims')
fake_xarray = FakeVariable(expected.data, expected.dims)
self.assertVariableIdentical(expected, as_variable(fake_xarray))

FakeVariable = namedtuple('FakeVariable',
'data values dims attrs encoding')
fake_xarray = FakeVariable(expected_extra.data, expected_extra.values,
expected_extra.dims, expected_extra.attrs,
expected_extra.encoding)
self.assertVariableIdentical(expected_extra, as_variable(fake_xarray))

xarray_tuple = (expected_extra.dims, expected_extra.values,
expected_extra.attrs, expected_extra.encoding)
self.assertVariableIdentical(expected_extra, as_variable(xarray_tuple))

with self.assertRaisesRegexp(TypeError, 'tuples to convert'):
as_variable(tuple(data))
Expand All @@ -637,6 +652,15 @@ def test_as_variable(self):
expected = Variable([], 0)
self.assertVariableIdentical(expected, actual)

data = np.arange(9).reshape((3, 3))
expected = Variable(('x', 'y'), data)
with self.assertRaisesRegexp(
ValueError, 'without explicit dimension names'):
as_variable(data, name='x')
with self.assertRaisesRegexp(
ValueError, 'has more than 1-dimension'):
as_variable(expected, name='x')

def test_repr(self):
v = Variable(['time', 'x'], [[1, 2, 3], [4, 5, 6]], {'foo': 'bar'})
expected = dedent("""
Expand Down