Skip to content

Also save the grid during obj.to_netcdf(); create Grid.to_netcdf() #1836

Open
0 of 1 issue completed
Open

Description

@Sevans711

…, or, provide some other public API for saving uxarray arrays/datasets to files along with the underlying grid.

Right now, obj.to_netcdf(filename) is equivalent to obj.to_xarray().to_netcdf(filename), i.e. all grid information is being lost (for obj a UxDataArray or UxDataset). The result can be loaded via xr.open_dataset(filename), but attempting to load the result via ux.open_dataset(filename) produces a GridInvalidError: Failed to parse uxgrid information from xarray.Dataset..

One "obvious" workaround to attempt is to try to also save obj.uxgrid.to_netcdf(gridfile) and then do ux.open_dataset(gridfile, filename), however this crashes with AttributeError: 'Grid' object has no attribute 'to_netcdf'.

uxarray should implement some clear and simple interface for round-trips from local memory to files, allowing people to save their uxarray data, share it with other people if desired, and load it later.

The simplest user experience, in my opinion, would be for obj.to_netcdf(filename) to save a single dataset which includes the grid information by default, compatible with the "single-file ux.open_dataset" feature (see #1479). That way, the round-trip syntax is extremely simple: obj.to_netcdf(filename) followed by ux.open_dataset(filename) will recover a dataset with all the same values as in obj (though, possibly with some extra data_vars related to the grid, too, so they wouldn't be exactly equal). An optional kwarg like grid_file could also enable workflows like obj.to_netcdf(filename, grid_file=gridfile) followed by ux.open_dataset(gridfile, filename), to get a result which equals obj, exactly.

A full solution to this issue must provide some way for obj.to_netcdf() to save the grid too, and must also implement Grid.to_netcdf. If for some reason it is decided that some paths of obj.to_netcdf() should not save the grid, a warning should be raised whenever the grid is not saved (users wanting to avoid saving the grid should just use obj.to_xarray().to_netcdf() instead.

Activity

  1. erogluorhan commented on Oct 22, 2026

    @erogluorhan
    Member

    As a design choice, we implemented to_xarray() out of our objects (including Grid) and deferred file writes, i.e. to_netcdf(), to xarray. I get that to_netcdf() is still callable for UxDataset and UxDataArraythrough their xarray parent classes, but that's implicit, and the explicitly documented UXarray way should still be:

    uxds.to_xarray().to_netcdf()
    uxda.to_xarray().to_netcdf()
    uxds.uxgrid.to_xarray().to_netcdf()
    uxda.uxgrid.to_xarray().to_netcdf()
    

    That said, if we haven't done great job documenting this through user guides or usage examples, we should do that shouldn't introduce file writes in our API.

  2. erogluorhan commented on Oct 22, 2026

    @erogluorhan
    Member

    Also, IIRC, it was intentional to not handle Grid's xarray conversion as part of UXDataset's or UxDataArray's to_xarray() to emphasize Grid was not a native xarray object and should be dealt with explicitly if desired

  3. Sevans711 commented on Oct 22, 2026

    @Sevans711
    CollaboratorAuthor

    @erogluorhan Thank you for providing the extra context here, and for pointing out the option to use uxgrid.to_xarray().to_netcdf(), that makes a lot of sense. I agree it is important to document how to write to files. It should be easy for users to discover how to save UxDataArrays/UxDatasets as a file (or multiple files) that can be later loaded back into memory.

    Due to the inheritance, for better or for worse, file writes are already part of the API. E.g., calling help(uxarr) or help(uxds) includes the to_netcdf() method details. Just confirming, even if we don't override UxDataset.to_netcdf() or UxDataArray.to_netcdf(), are you also opposed to adding Grid.to_netcdf()? The fact that it is missing, while the former two exist in the API (via inheritance), made me think there was no canonical way to write grids to files.

    The implementation would be simple, something like:

    class Grid:
        # ... other methods
    
        def to_netcdf(self, path, *args, **kwargs):
            """writes this Grid's dataset to the file or file-like object specified by `path`.
            *args and **kwargs passed directly to :meth:`xr.Dataset.to_netcdf()`.
            """
            return self.to_xarray().to_netcdf(path, *args, **kwargs)

    Possibly-related: #1647

    Also, IIRC, it was intentional to not handle Grid's xarray conversion as part of UXDataset's or UxDataArray's to_xarray() to emphasize Grid was not a native xarray object and should be dealt with explicitly if desired

    Agreed, the uxgrid should definitely be dropped during UxDataset.to_xarray()!

  4. erogluorhan commented on Oct 23, 2026

    @erogluorhan
    Member

    Thanks for the further discussion, Sam!

    Just confirming, even if we don't override UxDataset.to_netcdf() or UxDataArray.to_netcdf(), are you also opposed to adding Grid.to_netcdf()?

    I think I am still opposed to it and would rather want only better documentation about how to use to_xarray().to_netcdf() for any of them instead (despite seeing your point with it due to inheritance with dataset and data array). Implementation-wise though, I agree it would be straightforward (my concern is whether we should implement it though).

    @dylannelson @cmdupuis3 @rajeeja any thoughts?

  5. moved this from 📚 Backlog to 📝 To-Do in UXarray Developmenton Oct 26, 2026
  6. Sevans711 commented on Oct 26, 2026

    @Sevans711
    CollaboratorAuthor

    From internal discussion today: triaged as "to-do" in the sense that adding something into the docs / user guide should be prioritized soon-ish. However, we didn't yet decide the way to proceed with the API itself (e.g., whether to add Grid.to_netcdf() or not add it); that should be discussed further before working on API changes.

    Also note, there are other methods to input/output files, such as to_zarr(), which should be considered here too.

  7. moved this from 📝 To-Do to On Pause in UXarray Developmenton Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

new featureNew user-facing functionality

Type

No type

Fields

Priority

Low

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions