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
Add assign_(coord/mask/attr) methods of data_array #3110
Conversation
…luding basic tests
I have a question! Should we check if the given |
Any reason why we don't implement the entire thing in Python? |
You mean if we are replacing existing coords? I think I would not check. After all, |
No... drop_* were in cpp so I just kept there together. We can write all of them in python, sure. |
👍 |
No, I meant when you want to assign multiple of them, for example
|
This will never reach |
In this case below it will survive but the keyword arguments will be used. I guess that's fine...? Or should we allow only one of them...?
|
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.
Comments below. Everything I said for the coords
case applies to the others as well.
src/scipp/core/assignments.py
Outdated
|
||
|
||
def assign_coords( | ||
self, coords: Optional[Dict] = None, **coords_kwargs |
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.
coords
should be position-only, such that it does not prevent the use of a keyword arg of that name.
src/scipp/core/assignments.py
Outdated
collected_coords = coords_kwargs | ||
|
||
for coord_key, coord in collected_coords.items(): | ||
self.coords[coord_key] = coord |
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.
We should not change the input. Must make a shallow copy first (self = self.copy(deep=False)
)
tests/data_array_test.py
Outdated
da = sc.DataArray(data) | ||
coord0 = sc.linspace('x', start=0.2, stop=1.61, num=4) | ||
coord1 = sc.linspace('y', start=1, stop=4, num=3) | ||
da.assign_coords({'coord0': coord0, 'coord1': coord1}) |
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.
da
should be kept unchanged. Make sure to also a a test for that.
Co-authored-by: Simon Heybrock <12912489+SimonHeybrock@users.noreply.github.com>
Co-authored-by: Simon Heybrock <12912489+SimonHeybrock@users.noreply.github.com>
…opy before modification
src/scipp/core/assignments.py
Outdated
from ..typing import DataArray, Dataset | ||
|
||
|
||
def assign_coords(self, coords: Dict) -> Union[DataArray, Dataset]: |
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.
Why did you remove the keyword-arg syntax?
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.
coords
should be position-only, such that it does not prevent the use of a keyword arg of that name.
Sorry I misunderstood this comment. Then... what do you mean by position-only
here ...?
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.
I meant the dict should be position-only, but keep the keyword args.
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.
def assign_coords(self, coords: Dict[str, Variable], /, **kwargs):
or something like that
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.
Ah, I see. My question was more like, should we allow only either of them
More specifically, will this be allowed?
da.assign_coords({'coord0': coord0_a}, coord0=coord0_b)
Currently, the keyword argument will overwrite the positional argument in this case.
…s with better overlapping key-words handling
|
src/scipp/core/assignments.py
Outdated
coords_posarg = {} if coords is None else coords | ||
collected_coords = {**coords_posarg, **coords_kwargs} | ||
|
||
if len(collected_coords) != len(coords_posarg) + len(coords_kwargs): | ||
overlapped = set(coords).intersection(coords_kwargs) | ||
raise ValueError( | ||
'The names of coords passed in the dict ' | ||
'and as keyword arguments must be distinct.' | ||
f'Following names were used in both places: {overlapped}.' | ||
) |
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.
Can all this code duplication be avoided?
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.
I can write a general function that combines positional dictionary argument and keyword arguments I guess...?
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.
Looks like it exists already:
scipp/src/scipp/core/dimensions.py
Lines 12 to 21 in 62778d2
def _combine_dims( | |
dims_dict: Optional[Dict[str, str]], names: Dict[str, str] | |
) -> Dict[str, str]: | |
dims_dict = {} if dims_dict is None else dims_dict | |
if set(dims_dict).intersection(names): | |
raise ValueError( | |
'The names passed in the dict and as keyword arguments must be distinct.' | |
f'Got {dims_dict} and {names}' | |
) | |
return {**dims_dict, **names} |
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.
Yes, that what I referenced from.
It prints all dictionaries here but since coords
/attrs
/masks
are Variable
,
but I didn't want to print them all so I just changed the message a little.
src/scipp/core/assignments.py
Outdated
@@ -8,6 +8,21 @@ | |||
from ..typing import DataArray, Dataset, Variable | |||
|
|||
|
|||
def _combine_args(arg0: Optional[Dict[str, Variable]] = None, /, **kwargs): |
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.
Still duplicate with
scipp/src/scipp/core/dimensions.py
Lines 12 to 21 in 62778d2
def _combine_dims( | |
dims_dict: Optional[Dict[str, str]], names: Dict[str, str] | |
) -> Dict[str, str]: | |
dims_dict = {} if dims_dict is None else dims_dict | |
if set(dims_dict).intersection(names): | |
raise ValueError( | |
'The names passed in the dict and as keyword arguments must be distinct.' | |
f'Got {dims_dict} and {names}' | |
) | |
return {**dims_dict, **names} |
src/scipp/core/argument_handlers.py
Outdated
from typing import Dict, Optional | ||
|
||
|
||
def combine_dict_args(arg: Optional[Dict], /, **kwargs): |
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.
type hints missing now
Fixes #2960
TODO: python binding is not implemented yet
I used the name
assign
since I thought it should also be able to update the existing one.Like this: https://docs.xarray.dev/en/stable/generated/xarray.DataArray.assign_coords.html
In the xarray, the syntax is like below
But since we are using the
Variable
which already has dimension name, it should be like below...?