-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Recommended way to extend xarray Datasets using accessors? #2473
Comments
Your use of an xarray accessor class looks a little funny to me. Accessors should only accept one argument, which is an xarray.Dataset. If you want to make your own objects, that's fine, but I don't think there's any point in making them an accessor. What does your |
Ah - I misunderstood how they work, if I do this: @xr.register_dataset_accessor('bout')
class BoutDataset(object):
def __init__(self, ds_object):
self.data = ds_object
def plot_tokamak():
plot_in_bout_specific_way(self.data, self.extra_data) then I can successfully use it like this: ds = collect_data(path)
ds.bout.plot_tokamak()
print(ds.bout.data) Thanks!
My Also the philosophy of the BOUT framework encourages each group of users to add their own functionality depending on what exactly they are solving. Some kind of base (Sorry if this is too far off the topic of xarray, feel free to close it if you think this is not going to be relevant to any of the rest of the community.) |
Or alternatively I suppose I could just store my options as an attribute on the accessor: ds = collect_data(path)
ds.bout.options = options_obj
# Now I have an object which stores all the data I want
print(ds.bout.options) That seems to be what I should have tried first. In that case would it be possible to have multiple accessors, one for the core bout functionality and others for extensions for even-more-specific users? i.e an accessor for a code called Storm which is based on BOUT++: print(ds) # xarray dataset
print(ds.bout.options) # BOUT-specific extra information
print(ds.storm.special_storm_plot()) # storm-user-group-specific method Can an accessor inherit from another accessor class? |
Sorry for the triple comment, but I could also do this: If I do this: @xr.register_dataset_accessor('bout')
class BoutAccessor(object):
def __init__(self, ds_object):
self._data = ds_object
def set_options(self, options):
self.options = options
@register_dataset_accessor('storm')
class StormAccessor(BoutAccessor):
def __init__(self, ds_object):
super().__init__(ds_object)
def special_storm_plot()
special_storm_plot(self._data, self.options) then I can have BOUT-specific attributes and methods stored via the bout accessor, all of which are inherited by the more-specific storm accessor ds = collect_data(path)
options_obj = get_options(path)
ds.storm.set_options(options_obj) # access inherited methods from the bout accessor to store arbitrary extra data
ds.storm.special_storm_plot() # use data from the bout accessor when calling more-specific methods form the storm accessor However then my attached objects don't survive the calling of xarray methods: ds.storm.extra_info = 'options'
new_ds = ds.isel(t=-1)
print(new_ds.storm.extra_info) # AttributeError: 'StormAccessor' object has no attribute 'extra_info' |
I realised I'm massively overcomplicating this, I think all I need is the existing accessor functionality, and for attrs to always be preserved in order to get the behaviour I want. Therefore once #2482 is merged then I should be able to close this. |
#2482 has now been merged which means that I can get the behaviour I want by using globally-permanent attrs to store arbitrary objects, and using accessors to attach methods to datasets. |
Hi,
I'm now regularly using xarray (& dask) for organising and analysing the output of the simulation code I use (BOUT++) and it's very helpful, thank you!.
However my current approach is quite clunky at dealing the extra information and functionality that's specific to the simulation code I'm using, and I have questions about what the recommended way to extend the xarray Dataset class is. This seems like a general enough problem that I thought I would make an issue for it.
Desired
What I ideally want to do is extend the xarray.Dataset class to accommodate extra attributes and methods, while retaining as much xarray functionality as possible, but avoiding reimplementing any of the API. This might not be possible, but ideally I want to make a
BoutDataset
class which contains extra attributes to hold information about the run which doesn't naturally fit into the xarray data model, extra methods to perform analysis/plotting which only users of this code would require, but also be able to use xarray-specific methods and top-level functions:Problems with my current approach
I have read the documentation about extending xarray, and the issue threads about subclassing Datasets (#706) and accessors (#1080), but I wanted to check that what I'm doing is the recommended approach.
Right now I'm trying to do something like
which works in the sense that I can do
but not so well with
If I have to reimplement the APl for methods like
.isel()
and top-level functions likeconcat()
, then why should I not just subclassxr.Dataset
?There aren't very many top-level xarray functions so reimplementing them would be okay, but there are loads of Dataset methods. However I think I know how I want my
BoutDataset
class to behave when anxr.Dataset
method is called on it: I want it to implement that method on the underlying dataset and return the full BoutDatset with extra data and attributes still attached.Is it possible to do something like:
"if calling an
xr.Dataset
method on an instance ofBoutDataset
, call the corresponding method on the wrapped dataset and return a BoutDataset that has the extra BOUT-specific data propagated through"?Thanks in advance, apologies if this is either impossible or relatively trivial, I just thought other xarray users might have the same questions.
The text was updated successfully, but these errors were encountered: