Skip to content

Add documentation for Dask/Multiprocessing support and Xarray accessor - #878

Open
rhugonnet wants to merge 4 commits into
GlacioHack:mainfrom
rhugonnet:add_accessor_daskmp_doc
Open

Add documentation for Dask/Multiprocessing support and Xarray accessor#878
rhugonnet wants to merge 4 commits into
GlacioHack:mainfrom
rhugonnet:add_accessor_daskmp_doc

Conversation

@rhugonnet

@rhugonnet rhugonnet commented Mar 6, 2026

Copy link
Copy Markdown
Member

This PR finally adds the documentation for the Xarray accessor rst, as well as the Dask and Multiprocessing support through chunked implementations that we have been steadily developing for the last 2-3 years! 🥳

Thanks in particular to @vschaffn @ameliefroessl for their big contributions at various stages!

Link to the new doc (landing on the Scalability page with schematics that was a bit of work!): https://geoutils-rhugonnet.readthedocs.io/en/add_accessor_daskmp_doc/scalability_logic.html

Details

The documentation changes are the following:

  • Added a whole new "Scalability" section in "Features" with 4 sub-pages "Usage and good practices" (intro with summary and short examples; for those who want to get directly into it), "Concept definition" (explanation of scalability concepts with small examples; for those who want to learn), "Supported operations" (detailed table of scalability support across methods/object types; for those who want to know scalability exactly), and "Implementation strategies" with diagrams and details of implementation (for interested users debugging their memory or who want to learn, or developers/contributors to get a grasp of the code logic),
  • Re-worked a page "Feature and scalability overview" in "Getting started" that is very high-level (no code run, just tables and summaries),
  • Added a new page "Cheatsheet: From GDAL" + "Ecosystem" pages in a new "Resources" area (not so happy with the ecosystem page yet, need to buff it up a bit more),
  • Edited page "The georeferenced raster" to work for both Raster and accessor,
  • Removed page "Implicit lazy loading" in "Fundamentals" (as now covered in new "Scalability/Concept definition" page),
  • Updated the "API reference" to explain the mirrored API + to have a custom template showing Raster.method() or ds.rst.method() for each method linked through a single RasterBase call with RasterBase itself not being visible (for users using the search button). Also added full Raster + RasterAccessor full autoclass summary for those also curious to search through the class details. But those two pages are "hidden" in the table-of-content structure to avoid duplicating the main API page (users can only land there through search or clicking the class object name); and the page starts with a link pointing back to the main API, if that's not where they wanted to land.

I haven't yet updated the "Quick start", but I think we really need a better example there, and we should use the Xarray/Pandas accessor directly.
Same for the "Fundamentals" section, there's some editing to do there so that's it's not too "GeoUtils object-focused", but balanced whether it's about accessors or GeoUtils objects.
Finally, we have to see for the "Examples" (in feature pages, and in the Sphinx gallery), do we switch all to Xarray/Pandas accessor?

In particular, as I was already doing diagrams in Python code for something else, I kept my inertia and decided to add some to the PR to describe our implementations visually! 😄
We might think of doing something similar to describe functions themselves in the future (interpolation, etc).

Finally, I realized that it was annoying to explain the mirror for Raster/rst but not for vector/point cloud at the same time, even though the accessors for those 2 are much easier to add.
So I might add them when I get the chance in the next weeks while this PR is being reviewed 😉

Resolves #677
Resolves #673

TO-DO TO FINALIZE

  • Uncomment Multiprocessing config page, and add link to it where mentioned
  • Add section on reading/writing with Dask/Multiprocessing (filetypes, functions)
  • Decide on proximity support status with map_overlap (yes, and report caveat of max distance?)
  • Fix to_file from accessor, and uncomment in "Usage" page,
  • Polygonize on "Implementation page": Explain and justify default strategy.
  • Subsample on "Implementation page": Write 0.25 subsample x 39 valid values = 9 on figure + text to clarify example.
  • Clarify organization of "Scalability" section by stating the first is a summary page ("Usage and good practices"), with more in-depth details in the others.
  • Add edit and fill-nodata mirroring GDAL,
  • Quick start: add tabs for accessor VS package-type,
  • Move plot() to RasterBase (API not showing, also for Scalability?).

@rhugonnet

rhugonnet commented Mar 10, 2026

Copy link
Copy Markdown
Member Author

@belletva @adehecq @atedstone @adebardo @marinebcht @erikmannerfelt @ould-a This new documentation draft is ready for your review! 😄
@remi-braun @guillaumeeb @fmaussion @friedrichknuth If you have the time to provide comments, that'd be amazing as well!

The link is here: https://geoutils-rhugonnet.readthedocs.io/en/add_accessor_daskmp_doc/feature_overview.html
I think I'll wait for 2-3 weeks to leave time to get everyone's feedback, then consolidate.

I suggest you start by reading the new "Feature and scalability overview" in the "Getting started" section, then move on to the "Scalability" section which essentially contains all the novelty.
Then, there are smaller changes in specific pages. On GitHub, you can ignore the plotting scripts for the new diagrams, and simply comment about the rendering of those on the related page ("Implementation strategies"), that'll make it easier.

I also added this new "Cheasheet: From GDAL" page to help users make the link. We could also add other Python packages there (i.e. table that @remi-braun started)?
Finally, you'll notice that we (mostly unintentionally) converged almost exactly towards the same API as the new overhauled GDAL CLI, which is great news (even "footprint" or "info" are the same)! At this stage, we could almost think of updating the last few functions to match that API entirely. (Move crop to clip, for instance)
I let you comment on that as well 😉

Very happy to see this in a near-finalized stage after so many years of us working on it! 😊

@remi-braun

remi-braun commented Mar 10, 2026

Copy link
Copy Markdown

Hi @rhugonnet,
Your doc is simply amazing! I bow before such hard work 👏
I particularly love how you explained the different scalability concepts and the supported operations summary 💖

I have some comments, but honestly it's not much:

  • In Feature and scalability overview
    • In Summary paragraph, I would highlight the paragraph about you making sure that all methods produce identical outputs. This is extremely important and often not clearly stated in other libs
    • In Data operations, maybe a bit more explanations about what "scalable means" (just a hyperlink is enough), as it is explained after in the docs
  • In Supported operations, it seems lacking some methods (i.e. merge_rasters). Maybe adding the methods that will arrive in a near future could be useful too, but this is maybe a bad idea haha
  • In Cheatsheet (I also love this page)
    • I would go for a 100% match with GDAL honestly, IMO the field suffers from varying vocabulary across libraries
    • The footprint corresponds to the extent of the raster (=bbox in STAC) or the area without nodata ? (I am used to this definition). Maybe this is worth adding in the docs (here is what I tried to do)
  • In Ecosystem
    • Thank you for mentioning EOReader ❤️
    • Don't you want to mention rioxarray and rasterio here?
  • I think your Mission page is very important to define what this lib is about, maybe it would be useful to link it somewhere in the first pages as an hyperlink (even in ReadMe)

And again: such a wonderful job

@remi-braun

Copy link
Copy Markdown

I forgot a point :

  • In Cheatsheet
    • Maybe add the rasterio equivalence at least and / or maybe link the rioxarray / rasterio equivalences (here)

Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_support.md
Comment thread doc/source/scalability_support.md
Comment thread doc/source/scalability_support.md
Comment thread doc/source/scalability_logic.md
Comment thread doc/source/scalability_logic.md
Comment thread doc/source/code/diagram_chunked_reproject.py
Comment thread doc/source/scalability_logic.md
Comment thread doc/source/scalability_logic.md
Comment thread doc/source/scalability_logic.md
@rhugonnet

Copy link
Copy Markdown
Member Author

Thanks!
@adehecq @belletva Don't forget to comment on the important generic aspects:

  • Should we mirror the new GDAL CLI exactly? (a few functions: bounds to bbox, crop to clip, etc)?
  • Should we update the main pages/Sphinx-gallery example with accessor examples instead of GeoUtils classes?
  • Reworking the Quick start fully?

@belletva

Copy link
Copy Markdown
Contributor

Thanks! @adehecq @belletva Don't forget to comment on the important generic aspects:

  • Should we mirror the new GDAL CLI exactly? (a few functions: bounds to bbox, crop to clip, etc)?
  • Should we update the main pages/Sphinx-gallery example with accessor examples instead of GeoUtils classes?
  • Reworking the Quick start fully?

And again, congratulation for your amazing work !!

Comment thread doc/source/cheatsheet_osgeo.md
Comment thread doc/source/cheatsheet_osgeo.md
Comment thread doc/source/cheatsheet_osgeo.md
Comment thread doc/source/ecosystem.md
Comment thread doc/source/ecosystem.md
Comment thread doc/source/ecosystem.md
Comment thread doc/source/raster_class.md
Comment thread doc/source/raster_class.md
Comment thread doc/source/raster_class.md
Comment thread doc/source/raster_class.md
Comment thread doc/source/raster_class.md
@adehecq

adehecq commented Mar 18, 2026

Copy link
Copy Markdown
Member

I just finished my 2nd round of reviews. Very nice documentation ! 😍 Thanks for all the effort you made to explain the concepts and write a clear documentation!! 🙌

Replying to your main questions below:

* Should we mirror the new GDAL CLI exactly? (a few functions: `bounds` to `bbox`, `crop` to `clip`, etc)?

If not too much effort, yes I would encourage going in that direction! It is so much easier when different tools use the same naming convention and I like that we "accidentally" end up with most of the same terms 😆 I actually suggested having an edit method, but the other functions can also be useful.
Like @remi-braun, it is unclear to me if footprint refers to the bounding box, or the actual raster footprint. The latter would be useful, and I think we have a tool to calculate box of valid areas only.

* Should we update the main pages/Sphinx-gallery example with accessor examples instead of GeoUtils classes?

Since I am still a big user of the Geoutils classes, I would keep those examples. Also a lot of our base users are used to this system now, so I think it is too early to completely change the structure. Something to re-evaluate later?
We could of course provide some examples with the accessor in a few places (using tab, see below).

* Reworking the Quick start fully?

Maybe we could show the same example with the 2 approaches? Using tabs, like in xDEM CLI documentation could be a nice way to avoid long pages?
I also think we need a more interesting example than this one. But this would require new example datasets maybe. Should we have a brainstorming at our next meeting?

Comment thread doc/source/ecosystem.md
Comment thread doc/source/ecosystem.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/feature_overview.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_usage.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_concept.md
Comment thread doc/source/scalability_support.md
Comment thread doc/source/scalability_support.md
Comment thread doc/source/scalability_logic.md

@marinebcht marinebcht left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

@rhugonnet

Copy link
Copy Markdown
Member Author

Thanks for the feedback! 😉
The reviewer distribution is currently biased pretty heavily towards non-Xarray users. It would be good to hear more from those experienced with Xarray/Dask for this PR specifically, if some of you have the time @atedstone @erikmannerfelt @friedrichknuth @fmaussion @scottyhq @guillaumeeb 🙂

@rhugonnet

Copy link
Copy Markdown
Member Author

Reminder: Last week for feedback, then I'll consolidate and merge!

@friedrichknuth

Copy link
Copy Markdown
Contributor

This is fantastic - thank you for all the hard work on bridging xDEM with Xarray! 🚀 The documentation is very helpful and really nice to see supported operations in the Table summary 🤩

After browsing the documentation I have a few comments:

  • There seem to be two methods for opening a file from disk (gu.Raster(fn) or gu.open_raster(fn)). Ideally, there is only one way. gu.Raster(fn) has been nice. To keep the API consistent, perhaps gu.Raster(fn) can adopt the functionality provided in gu.open_raster(fn) and simply convert numpy arrays to dask arrays in memory, if passed a rasterio dataset with chunks argument.
  • I frequently use dask.array.rechunk to determine optimal chunk sizes using the block_size_limit and balance arguments and rarely have to think about defining multiples of the pixel size. Adding a pointer to this API might be helpful to others as well in the Good practices with chunked and lazy operations section.
  • The APIs for chunk size definition are slightly different, e.g. gu.open_raster(filename_rast, chunks={"x": 200, "y": 200}) and gu.multiproc.MultiprocConfig(chunk_size=200). Given that pixels don't have to be square in dimension, gu.multiproc.MultiprocConfig(chunks={"x": 200, "y": 200}) could be more explicit, consistent, and give better control?
  • Is gu.multiproc.MultiprocConfig(chunk_size='auto') currently supported?
  • Is there an example for writing a COG to disk? With enhanced lazy IO and multiprocessing support in GeoUtils / xDEM it might be helpful to state which modern cloud optimized formats are supported and how to work with them.
  • While dask will parallelize tasks by default, setting up a cluster (even locally) is much more powerful. I see the MultiprocConfig page. Similarly, one might point users to the dask documentation to instantiate a cluster with dask, before using it under the hood in GeoUtils.
  • Xvec may be of interest when tackling vector support in the future https://xvec.readthedocs.io/en/stable/

@marinebcht

Copy link
Copy Markdown
Contributor

I did not find how do you set a mask in a Xarray (ds.rst.set_mask do not work) and how to you cast an Raster to an Xarray ?
Thanks :)

@rhugonnet

Copy link
Copy Markdown
Member Author

Thanks a lot @friedrichknuth! 😉

On @marinebcht's question:

I did not find how do you set a mask in a Xarray (ds.rst.set_mask do not work) and how to you cast an Raster to an Xarray ? Thanks :)

No masked arrays through Xarray, so the arrays are forced to floating type to support NaNs instead. So an equivalent would be simply: ds[mask] = np.nan (and you lose the original data under the mask).

For conversion: Raster.to_xarray() or ds.rst.to_geoutils() depending on the direction. If you want to compare them, note that raster_equal() and raster_allclose() already support both input types (Raster or xr.DataArray). 🙂

@remi-braun

Copy link
Copy Markdown

Hello,

I don't want to put pressure or whatever, but @rhugonnet do you have a release date in mind? 😇
Thanks a lot!

@rhugonnet

Copy link
Copy Markdown
Member Author

Hello,

I don't want to put pressure or whatever, but @rhugonnet do you have a release date in mind? 😇 Thanks a lot!

Yes, sorry, I was busy with deadlines on research projects the past weeks 😅
I finalized the related accessor in xDEM early April, so I should be able to merge both fairly quickly now. I'll dedicate some of the next weekends on this (to account for everyone's comments), so I think it'll be done around mid-June (I leave on holidays after that). 🙂

For a raster output, one typically wants to write to file lazily to avoid loading it in-memory:

```{code-cell} python
# ds_reproj.rst.to_file("reproj_rast.tif", compute=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, I was trying to use this function but it does not work. Just saw the commented line. It is in progress ? Thanks 😊

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

erratum !! Just saw your corrected it in this pr :) thanks :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to use this, but I add errors :

ds = gu.open_raster(gu.examples.get_path("exploradores_aster_dem"))
ds.rst.to_file("myraster_input.tif")

gives ValueError: Key '_FillValue' already exists in attrs, and will not be overwritten. This is probably an encoding field used by xarray to describe how a variable is serialized. To proceed, remove this key from the variable's attributes manually.

ds = gu.open_raster(gu.examples.get_path("exploradores_aster_dem"), chunks={"x": 200, "y": 200})
out_res = (ds.rst.res[0] * 2, ds.rst.res[1] / 2)
ds_reproj = ds.rst.reproject(res=out_res, resampling="bilinear")
ds_reproj = ds_reproj.compute()
ds_reproj.rst.to_file("myraster_reproj.tif")

gives rioxarray.exceptions.InvalidDimensionOrder: Invalid dimension order. Expected order: ('y', 'x'). You can use DataArray.transpose('y', 'x') to reorder your dimensions. Data variable: concatenate-450f8600ebabf585198dedfd53dc348d

I need to move now so I can't investigate. So I put this here in case...

@rhugonnet

Copy link
Copy Markdown
Member Author

Hello,
I don't want to put pressure or whatever, but @rhugonnet do you have a release date in mind? 😇 Thanks a lot!

Yes, sorry, I was busy with deadlines on research projects the past weeks 😅 I finalized the related accessor in xDEM early April, so I should be able to merge both fairly quickly now. I'll dedicate some of the next weekends on this (to account for everyone's comments), so I think it'll be done around mid-June (I leave on holidays after that). 🙂

Didn't fully get to it, but I got everything else out of the way. So I can merge this when I come back from holidays in ~2 weeks! 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Finalize Multiprocessing API ahead of documentation Multiprocessing/Tiling Documentation

7 participants