-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Multi-index levels as coordinates #947
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
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
f31a278
make multi-index levels visible as coordinates
5e8a677
make levels also visible for Dataset
19ec381
fix unnamed levels
1566938
allow providing multi-index levels in .sel
9f4e4e3
refactored _get_valid_indexers to get_dim_indexers
2679318
fix broken tests
723c99a
refactored accessibility and repr of index levels
6afcb4a
do not allow providing both level and dim indexers in .sel
76c937e
cosmetic changes
5009ba8
change signature of Coordinate.__init__
4c78ea9
check for uniqueness of multi-index level names
d28e829
no need to check for uniqueness of level names in _level_coords
810b4f9
rewritten checking uniqueness of multi-index level names
7738059
fix adding coords/vars with the same name than a multi-index level
62b46f2
check for level/var name conflicts in one place
936ec55
cosmetic changes
1d6a96f
fix Coordinate -> IndexVariable
ec67bbd
fix col width when formatting multi-index levels
f80d7a8
add tests for IndexVariable new methods and indexing
861c78b
fix bug in assert_unique_multiindex_level_names
37a0796
add tests for Dataset
fdbf4aa
fix appveyor tests
d237022
add tests for DataArray
949fb46
add docs
bdaad9b
review changes
a447767
remove name argument of IndexVariable
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,34 +33,48 @@ | |
'quarter'] | ||
|
||
|
||
def _get_virtual_variable(variables, key): | ||
"""Get a virtual variable (e.g., 'time.year') from a dict of | ||
xarray.Variable objects (if possible) | ||
def _get_virtual_variable(variables, key, level_vars={}): | ||
"""Get a virtual variable (e.g., 'time.year' or a MultiIndex level) | ||
from a dict of xarray.Variable objects (if possible) | ||
""" | ||
if not isinstance(key, basestring): | ||
raise KeyError(key) | ||
|
||
split_key = key.split('.', 1) | ||
if len(split_key) != 2: | ||
if len(split_key) == 2: | ||
ref_name, var_name = split_key | ||
elif len(split_key) == 1: | ||
ref_name, var_name = key, None | ||
else: | ||
raise KeyError(key) | ||
|
||
ref_name, var_name = split_key | ||
ref_var = variables[ref_name] | ||
if ref_var.ndim == 1: | ||
date = ref_var.to_index() | ||
elif ref_var.ndim == 0: | ||
date = pd.Timestamp(ref_var.values) | ||
if ref_name in level_vars: | ||
dim_var = variables[level_vars[ref_name]] | ||
ref_var = dim_var.to_index_variable().get_level_variable(ref_name) | ||
else: | ||
raise KeyError(key) | ||
ref_var = variables[ref_name] | ||
|
||
if var_name == 'season': | ||
# TODO: move 'season' into pandas itself | ||
seasons = np.array(['DJF', 'MAM', 'JJA', 'SON']) | ||
month = date.month | ||
data = seasons[(month // 3) % 4] | ||
if var_name is None: | ||
virtual_var = ref_var | ||
var_name = key | ||
else: | ||
data = getattr(date, var_name) | ||
return ref_name, var_name, Variable(ref_var.dims, data) | ||
if ref_var.ndim == 1: | ||
date = ref_var.to_index() | ||
elif ref_var.ndim == 0: | ||
date = pd.Timestamp(ref_var.values) | ||
else: | ||
raise KeyError(key) | ||
|
||
if var_name == 'season': | ||
# TODO: move 'season' into pandas itself | ||
seasons = np.array(['DJF', 'MAM', 'JJA', 'SON']) | ||
month = date.month | ||
data = seasons[(month // 3) % 4] | ||
else: | ||
data = getattr(date, var_name) | ||
virtual_var = Variable(ref_var.dims, data) | ||
|
||
return ref_name, var_name, virtual_var | ||
|
||
|
||
def calculate_dimensions(variables): | ||
|
@@ -424,6 +438,21 @@ def _subset_with_all_valid_coords(self, variables, coord_names, attrs): | |
|
||
return self._construct_direct(variables, coord_names, dims, attrs) | ||
|
||
@property | ||
def _level_coords(self): | ||
"""Return a mapping of all MultiIndex levels and their corresponding | ||
coordinate name. | ||
""" | ||
level_coords = OrderedDict() | ||
for cname in self._coord_names: | ||
var = self.variables[cname] | ||
if var.ndim == 1: | ||
level_names = var.to_index_variable().level_names | ||
if level_names is not None: | ||
dim, = var.dims | ||
level_coords.update({lname: dim for lname in level_names}) | ||
return level_coords | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I missing something here? Wouldn't this also work without the for name in self._coord_names:
var = self.variables[name]
if name == var.dims[0]:
level_coords.update(var.to_coord().get_level_coords())
return level_coords |
||
|
||
def _copy_listed(self, names): | ||
"""Create a new Dataset with the listed variables from this dataset and | ||
the all relevant coordinates. Skips all validation. | ||
|
@@ -436,7 +465,7 @@ def _copy_listed(self, names): | |
variables[name] = self._variables[name] | ||
except KeyError: | ||
ref_name, var_name, var = _get_virtual_variable( | ||
self._variables, name) | ||
self._variables, name, self._level_coords) | ||
variables[var_name] = var | ||
if ref_name in self._coord_names: | ||
coord_names.add(var_name) | ||
|
@@ -452,7 +481,8 @@ def _construct_dataarray(self, name): | |
try: | ||
variable = self._variables[name] | ||
except KeyError: | ||
_, name, variable = _get_virtual_variable(self._variables, name) | ||
_, name, variable = _get_virtual_variable( | ||
self._variables, name, self._level_coords) | ||
|
||
coords = OrderedDict() | ||
needed_dims = set(variable.dims) | ||
|
@@ -521,6 +551,7 @@ def __setitem__(self, key, value): | |
if utils.is_dict_like(key): | ||
raise NotImplementedError('cannot yet use a dictionary as a key ' | ||
'to set Dataset values') | ||
|
||
self.update({key: value}) | ||
|
||
def __delitem__(self, key): | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably good to clarify "Used for attribute style lookup. Not returned directly by any public methods."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this sentence on the line below...