From 8a29d965666ab28f226c9892f468ecc1a448c50b Mon Sep 17 00:00:00 2001 From: Philip Chmielowiec <67855069+philipc2@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:19:23 -0500 Subject: [PATCH] Doc Cleanup (#977) * start refactoring api reference * update order of user guide * work on api reference * update reference api * fix typo * start refactoring README * fix typo * update api ref * add plotting methods to api * update plotting docstrings * o Fix spelling and try to fix the usage code-block * o update example * update docstrings * update backend parameter * update private API blurb * o Try Usage to Examples which is more standard in docstrings for example usage. * one more usage to example * remove private api blurb * update plotting user guide notebook * update remapping docstrings * cleanup more docstrings * clean up object docstrings * cleanup plotting docstrings * update name of gca_const_lat_intersection * update data array conersion methods * update README * fix gradient example * o Add backend to doc * update README * add units for descriptors --------- Co-authored-by: Rajeev Jain --- README.md | 40 ++- ci/docs.yml | 1 + docs/api.rst | 396 ++++++++++++++++++++++++- docs/conf.py | 3 + docs/index.rst | 5 +- docs/user-guide/plotting.ipynb | 9 +- docs/user_api/index.rst | 437 ---------------------------- docs/userguide.rst | 5 +- test/test_intersections.py | 10 +- uxarray/core/api.py | 13 +- uxarray/core/dataarray.py | 69 ++--- uxarray/core/dataset.py | 15 +- uxarray/grid/grid.py | 44 ++- uxarray/grid/integrate.py | 4 +- uxarray/grid/intersections.py | 2 +- uxarray/plot/accessor.py | 48 +-- uxarray/remap/dataarray_accessor.py | 10 +- uxarray/remap/dataset_accessor.py | 10 +- 18 files changed, 525 insertions(+), 596 deletions(-) delete mode 100644 docs/user_api/index.rst diff --git a/README.md b/README.md index e1f5903c1..701220a5e 100644 --- a/README.md +++ b/README.md @@ -42,34 +42,42 @@ commonly-used for structured grids recognition, to support reading and recognizing unstructured grid model outputs. We picked the name "UXarray" (pronounced "you-ex-array"), with the "U" representing unstructured grids. -## UXarray Functionality - -The following intended functionality has been inspired by discussions with +## Features + +* ``Grid`` class for storing grid information and providing grid-specific functionality + * Support for reading UGRID, MPAS, ESMF, ICON, GEOS-CS, SCRIP, and EXODUS grid formats +* Extension of xarray's ``DataArray`` and ``Dataset`` classe to support unstructured grid operations + * ``uxarray.UxDataArray`` inherits ``xarray.DataArray`` and is attached to a ``Grid`` instance through the ``.uxgrid`` accessor + * ``uxarray.UxDataset`` inherits ``xarray.Dataset`` and is attached to a ``Grid`` instance through the ``.uxgrid`` accessor +* Extension of xarray's ``open_dataset`` and ``open_mfdataset`` methods to support reading grid and data files +* Plotting + * Native visualization of unstructured grids written using the ``hvPlot`` package + * Support for grid topology visualization (i.e. exploring the geometry of a grid) and data visualization (i.e. data mapped to each face) +* Subsetting + * Ability to select arbitrary regions of a grid using different selection methods (nearest neighbor, bounding circle, bounding box) +* Remapping + * Support for nearest neighbor and inverse distance weighted unstructured to unstructured remapping +* Topological Aggregations + * Perform aggregations within different topology elements using connectivity information +* Mathematical Operators + * Support for Integral, Difference, and Gradient calculations + + +## Intended Features + +The following intended features have been inspired by discussions with members of the scientific community, within the SEATS Project and Project Raijin, and on several community platforms such as [Xarray GitHub Repository](https://github.com/pydata/xarray/issues/4222). The UXarray team is receptive to additional functionality requests. -## Intended Functionality for Grids -* Support for reading and writing UGRID, SCRIP ESMF, and Exodus formatted grids. -* Support for reading and writing shapefiles. * Support for arbitrary structured and unstructured grids on the sphere, including latitude-longitude grids, grids with only partial coverage of the sphere, and grids with concave faces. * Support for finite volume and finite element outputs. -* Support for edges that are either great circle arcs or lines of constant - latitude. -* Calculation of face areas, centroids, and bounding latitude-longitude boxes. * Triangular decompositions. * Calculation of supermeshes (consisting of grid lines from two input grids). - -## Intended Functionality for DataArrays on Grids - -* Regridding of data between unstructured grids. -* Global and regional integration of fields, including zonal averages. -* Application of calculus operations, including divergence, curl, Laplacian - and gradient. * Snapshots and composites following particular features. ## Documentation diff --git a/ci/docs.yml b/ci/docs.yml index 7fd333cc9..a7411af73 100644 --- a/ci/docs.yml +++ b/ci/docs.yml @@ -20,6 +20,7 @@ dependencies: - scikit-learn - sphinx-book-theme - sphinx-autosummary-accessors + - sphinx-remove-toctrees - myst-nb - sphinx-design - nbsphinx diff --git a/docs/api.rst b/docs/api.rst index 5b4b2d6f4..1c5b62ef6 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -2,19 +2,395 @@ .. _api: -API Reference + +API reference ============= +This page provides an auto-generated summary of UXarray's API. For more details +and examples, refer to the relevant chapters in the main part of the +documentation. + +Top Level Functions +------------------- + +.. autosummary:: + :toctree: generated/ + + open_grid + open_dataset + open_mfdataset + + +Grid +---- + +Constructor +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Grid + +I/O & Conversion +~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Grid.from_dataset + Grid.from_file + Grid.from_topology + Grid.to_xarray + Grid.to_geodataframe + Grid.to_polycollection + Grid.to_linecollection + +Indexing +~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.isel + +Dimensions +~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.dims + Grid.sizes + Grid.n_node + Grid.n_edge + Grid.n_face + Grid.n_max_face_nodes + Grid.n_max_face_edges + Grid.n_max_face_faces + Grid.n_max_edge_edges + Grid.n_max_node_faces + Grid.n_max_node_edges + Grid.n_nodes_per_face + +Spherical Coordinates +~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Grid.node_lon + Grid.node_lat + Grid.edge_lon + Grid.edge_lat + Grid.face_lon + Grid.face_lat + +Cartesian Coordinates +~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Grid.node_x + Grid.node_y + Grid.node_z + Grid.edge_x + Grid.edge_y + Grid.edge_z + Grid.face_x + Grid.face_y + Grid.face_z + +Connectivity +~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.connectivity + Grid.face_node_connectivity + Grid.face_edge_connectivity + Grid.face_face_connectivity + Grid.edge_node_connectivity + Grid.edge_edge_connectivity + Grid.edge_face_connectivity + Grid.node_node_connectivity + Grid.node_edge_connectivity + Grid.node_face_connectivity + +Descriptors +~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.descriptors + Grid.face_areas + Grid.bounds + Grid.edge_node_distances + Grid.edge_face_distances + Grid.antimeridian_face_indices + Grid.hole_edge_indices + +Attributes +~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.attrs + +Methods +~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Grid.copy + Grid.chunk + Grid.validate + Grid.compute_face_areas + Grid.calculate_total_face_area + Grid.normalize_cartesian_coordinates + Grid.construct_face_centers + +Inheritance of Xarray Functionality +----------------------------------- + +The primary data structures in UXarray, ``uxarray.UxDataArray`` and ``uxarray.UxDataset`` inherit from ``xarray.DataArray`` and +``xarray.Dataset`` respectively. This means that they contain the same methods and attributes that are present in Xarray, with +new additions and some overloaded as discussed in the next sections. For a detailed list of Xarray specific behavior +and functionality, please refer to Xarray's `documentation `_. + +UxDataArray +----------- + +Constructor +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + UxDataArray + +Grid Accessor +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + UxDataArray.uxgrid + +I/O & Conversion +~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + UxDataArray.to_geodataframe + UxDataArray.to_polycollection + UxDataArray.to_dataset + +UxDataset +----------- + +Constructor +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + UxDataset + +Grid Accessor +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + UxDataset.uxgrid + + +Plotting +-------- + + +UXarray's plotting API is written using `hvPlot `_. + +.. seealso:: + + `Plotting User Guide Section `_ + +Grid +~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + Grid.plot + Grid.plot.mesh + Grid.plot.edges + Grid.plot.node_coords + Grid.plot.nodes + Grid.plot.face_coords + Grid.plot.face_centers + Grid.plot.edge_coords + Grid.plot.edge_centers + + +UxDataArray +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + UxDataArray.plot + UxDataArray.plot.polygons + UxDataArray.plot.points + +UxDataset +~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + UxDataset.plot + + + + +Subsetting +---------- + +.. seealso:: + + `Subsetting User Guide Section `_ + + +Grid +~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + Grid.subset + Grid.subset.nearest_neighbor + Grid.subset.bounding_box + Grid.subset.bounding_circle + + +UxDataArray +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + UxDataArray.subset + UxDataArray.subset.nearest_neighbor + UxDataArray.subset.bounding_box + UxDataArray.subset.bounding_circle + + +Remapping +--------- + +.. seealso:: + + `Remapping User Guide Section `_ + +UxDataArray +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + UxDataArray.remap + UxDataArray.remap.nearest_neighbor + UxDataArray.remap.inverse_distance_weighted + +UxDataset +~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + :template: autosummary/accessor_method.rst + + UxDataset.remap + UxDataset.remap.nearest_neighbor + UxDataset.remap.inverse_distance_weighted + + +Mathematical Operators +---------------------- + +.. autosummary:: + :toctree: generated/ + + UxDataArray.integrate + UxDataArray.gradient + UxDataArray.difference + +Aggregations +------------ + +Topological +~~~~~~~~~~~ + +Topological aggregations apply an aggregation (i.e. averaging) on a per-element basis. For example, instead of computing +the average across all values, we can compute the average of all the nodes that surround each face and store the result +on each face. + +.. seealso:: + + `Topological Aggregations User Guide Section `_ + + +.. autosummary:: + :toctree: generated/ + + UxDataArray.topological_mean + UxDataArray.topological_min + UxDataArray.topological_max + UxDataArray.topological_median + UxDataArray.topological_std + UxDataArray.topological_var + UxDataArray.topological_sum + UxDataArray.topological_prod + UxDataArray.topological_all + UxDataArray.topological_any + + + + +Spherical Geometry +------------------ + +Intersections +~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + grid.intersections.gca_gca_intersection + grid.intersections.gca_const_lat_intersection + +Arcs +~~~~ + +.. autosummary:: + :toctree: generated/ + + grid.arcs.in_between + grid.arcs.point_within_gca + grid.arcs.extreme_gca_latitude -Below user API and internal API pages show already-implemented UXarray functionality. -You can also check the `UXarray Milestones `_ -and `UXarray Roadmap `_ for a -high-level understanding of UXarray's future function development milestones and roadmap. -Please let us know if you have any feedback! +Accurate Computing +------------------ -.. toctree:: - :maxdepth: 1 +.. autosummary:: + :toctree: generated/ - user_api/index.rst - internal_api/index.rst + utils.computing.cross_fma + utils.computing.dot_fma diff --git a/docs/conf.py b/docs/conf.py index 6d93b3295..07c2f083c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,6 +56,7 @@ def __getattr__(cls, name): "nbsphinx", "IPython.sphinxext.ipython_directive", "IPython.sphinxext.ipython_console_highlighting", + "sphinx_remove_toctrees", ] mathjax_config = { @@ -96,6 +97,8 @@ def __getattr__(cls, name): "xarray": ("http://xarray.pydata.org/en/stable/", None), } +remove_from_toctrees = ["generated/*"] + napoleon_use_admonition_for_examples = True napoleon_include_special_with_doc = True diff --git a/docs/index.rst b/docs/index.rst index 0943a0224..9d1744059 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -24,8 +24,9 @@ UXarray Documentation ===================== -UXarray provides Xarray-styled functionality for working with unstructured grids build around the -`UGRID `_ conventions. +Xarray extension for unstructured climate and global weather data analysis and visualization written +around the `UGRID `_ conventions. + diff --git a/docs/user-guide/plotting.ipynb b/docs/user-guide/plotting.ipynb index 1abb6255b..900b493e8 100644 --- a/docs/user-guide/plotting.ipynb +++ b/docs/user-guide/plotting.ipynb @@ -2927,7 +2927,7 @@ "source": [ "## Geographic Projections & Features\n", "\n", - "Geographic projections & features can be added using the same syntax as \n", + "Geographic projections & features can be added using the GeoViews package. \n", "\n", "```{seealso}\n", "[Geographic Data](https://hvplot.holoviz.org/user_guide/Geographic_Data.html) user guide section from ``hvPlot``\n", @@ -3166,13 +3166,6 @@ " title=\"Projected Polygon Plot (Centered about 180 degrees longitude)\",\n", ") * gf.coastline(projection=ccrs.Orthographic(central_longitude=central_longitude))" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/user_api/index.rst b/docs/user_api/index.rst deleted file mode 100644 index 3e5e8b568..000000000 --- a/docs/user_api/index.rst +++ /dev/null @@ -1,437 +0,0 @@ -.. currentmodule:: uxarray - -######## -User API -######## - -This page shows already-implemented Uxarray user API functions. You can also -check the `UXarray Milestones `_ and -`UXarray RoadMap `_ for a high -level understanding of UXarray's future function development milestones and roadmap. -Please let us know if you have any feedback! - -UxDataset -========= -A ``xarray.Dataset``-like, multi-dimensional, in memory, array database. -Inherits from ``xarray.Dataset`` and has its own unstructured grid-aware -dataset operators and attributes through the ``uxgrid`` accessor. - -Below is a list of features explicitly added to `UxDataset` to work on -Unstructured Grids: - -Class ------ -.. autosummary:: - :toctree: generated/ - - UxDataset - -IO --- -.. autosummary:: - :toctree: generated/ - - open_dataset - open_mfdataset - -Attributes ----------- -.. autosummary:: - :toctree: generated/ - - UxDataset.uxgrid - UxDataset.source_datasets - -Methods -------- -.. autosummary:: - :toctree: generated/ - - UxDataset.info - - -Remapping ---------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataArray.remap - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataset.remap.nearest_neighbor - UxDataset.remap.inverse_distance_weighted - -Plotting --------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataset.plot - - - - - -UxDataArray -=========== -N-dimensional ``xarray.DataArray``-like array. Inherits from `xarray.DataArray` -and has its own unstructured grid-aware array operators and attributes through -the ``uxgrid`` accessor. - -Below is a list of features explicitly added to `UxDataset` to work on -Unstructured Grids: - -Class ------ -.. autosummary:: - :toctree: generated/ - - UxDataArray - -IO --- -.. autosummary:: - :toctree: generated/ - - UxDataArray.to_dataset - UxDataArray.to_geodataframe - UxDataArray.to_polycollection - - -Attributes ----------- -.. autosummary:: - :toctree: generated/ - - UxDataArray.uxgrid - -Topological Aggregations ----------- -.. autosummary:: - :toctree: generated/ - - UxDataArray.topological_mean - UxDataArray.topological_max - UxDataArray.topological_min - UxDataArray.topological_prod - UxDataArray.topological_sum - UxDataArray.topological_std - UxDataArray.topological_var - UxDataArray.topological_median - UxDataArray.topological_all - UxDataArray.topological_any - -Methods -------- -.. autosummary:: - :toctree: generated/ - - UxDataArray.integrate - UxDataArray.isel - - -Remapping ---------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataArray.remap - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor_method.rst - - UxDataArray.remap.nearest_neighbor - UxDataArray.remap.inverse_distance_weighted - -Plotting --------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataArray.plot - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor_method.rst - - UxDataArray.plot.datashade - UxDataArray.plot.rasterize - UxDataArray.plot.polygons - UxDataArray.plot.points - -Subsetting ----------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - UxDataArray.subset - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor_method.rst - - UxDataArray.subset.nearest_neighbor - UxDataArray.subset.bounding_circle - UxDataArray.subset.bounding_box - -Calculus Operators ------------------- -.. autosummary:: - :toctree: generated/ - - UxDataArray.integrate - UxDataArray.gradient - UxDataArray.difference - - - - -Grid -==== -Unstructured grid topology definition to store stores grid topology dimensions, -coordinates, variables and provides grid-specific functions. - -Can be used standalone to explore an unstructured grid topology, or can be -seen as the property of ``uxarray.UxDataset`` and ``uxarray.DataArray`` to make -them unstructured grid-aware data sets and arrays. - -Class ------ -.. autosummary:: - :toctree: generated/ - - Grid - -IO --- -.. autosummary:: - :toctree: generated/ - - open_grid - Grid.from_dataset - Grid.from_face_vertices - Grid.to_geodataframe - Grid.to_polycollection - Grid.to_linecollection - Grid.validate - Grid.hole_edge_indices - - -Methods -------- -.. autosummary:: - :toctree: generated/ - - Grid.calculate_total_face_area - Grid.compute_face_areas - Grid.encode_as - Grid.get_ball_tree - Grid.get_kd_tree - Grid.copy - Grid.isel - Grid.construct_face_centers - Grid.chunk - - -Dimensions ----------- -.. autosummary:: - :toctree: generated/ - - Grid.n_node - Grid.n_edge - Grid.n_face - Grid.n_max_face_nodes - Grid.n_max_face_edges - Grid.n_max_face_faces - Grid.n_max_edge_edges - Grid.n_max_node_faces - Grid.n_max_node_edges - Grid.n_max_node_nodes - Grid.n_nodes_per_face - -Spherical Coordinates ---------------------- -.. autosummary:: - :toctree: generated/ - - Grid.node_lon - Grid.node_lat - Grid.edge_lon - Grid.edge_lat - Grid.face_lon - Grid.face_lat - -Cartesian Coordinates ---------------------- -.. autosummary:: - :toctree: generated/ - - Grid.node_x - Grid.node_y - Grid.node_z - Grid.edge_x - Grid.edge_y - Grid.edge_z - Grid.face_x - Grid.face_y - Grid.face_z - -Connectivity ------------- -.. autosummary:: - :toctree: generated/ - - Grid.face_node_connectivity - Grid.face_edge_connectivity - Grid.face_face_connectivity - Grid.edge_node_connectivity - Grid.edge_edge_connectivity - Grid.edge_face_connectivity - Grid.node_edge_connectivity - Grid.node_face_connectivity - -Grid Descriptors ----------------- -.. autosummary:: - :toctree: generated/ - - Grid.face_areas - Grid.antimeridian_face_indices - Grid.bounds - - -Attributes ----------- -.. autosummary:: - :toctree: generated/ - - Grid.grid_spec - Grid.attrs - - -Plotting --------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - Grid.plot - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor_method.rst - - Grid.plot.node_coords - Grid.plot.nodes - Grid.plot.face_coords - Grid.plot.face_centers - Grid.plot.edge_coords - Grid.plot.edge_centers - Grid.plot.mesh - Grid.plot.edges - -Subsetting ----------- -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor.rst - - Grid.subset - -.. autosummary:: - :toctree: generated/ - :template: autosummary/accessor_method.rst - - Grid.subset.nearest_neighbor - Grid.subset.bounding_circle - Grid.subset.bounding_box - - -Nearest Neighbor Data Structures -================================ - -KDTree ------- -.. autosummary:: - :toctree: generated/ - - grid.neighbors.KDTree - grid.neighbors.KDTree.query - grid.neighbors.KDTree.query_radius - -BallTree --------- -.. autosummary:: - :toctree: generated/ - - grid.neighbors.BallTree - grid.neighbors.BallTree.query - grid.neighbors.BallTree.query_radius - - -Helpers -======= - -Face Area ----------- -.. autosummary:: - :toctree: generated/ - - grid.area.calculate_face_area - grid.area.get_all_face_area_from_coords - grid.area.calculate_spherical_triangle_jacobian - grid.area.calculate_spherical_triangle_jacobian_barycentric - grid.area.get_gauss_quadratureDG - grid.area.get_tri_quadratureDG - -Connectivity ------------- -.. autosummary:: - :toctree: generated/ - - grid.connectivity.close_face_nodes - -Arcs ----- -.. autosummary:: - :toctree: generated/ - - grid.arcs.in_between - grid.arcs.point_within_gca - grid.arcs.extreme_gca_latitude - -Intersections -------------- -.. autosummary:: - :toctree: generated/ - - grid.intersections.gca_gca_intersection - grid.intersections.gca_constLat_intersection - -Accurate Computing Utils ------ -.. autosummary:: - :toctree: generated/ - - utils.computing.cross_fma - utils.computing.dot_fma - -Numba ------ -.. autosummary:: - :toctree: generated/ - - utils.enable_jit_cache - utils.disable_jit_cache - utils.enable_jit - utils.disable_jit diff --git a/docs/userguide.rst b/docs/userguide.rst index 98618cfe4..3342d99f7 100644 --- a/docs/userguide.rst +++ b/docs/userguide.rst @@ -79,8 +79,9 @@ These user guides provide additional detail about specific features in UXarray. user-guide/mpl.ipynb user-guide/advanced-plotting.ipynb user-guide/subset.ipynb + user-guide/remapping.ipynb user-guide/topological-aggregations.ipynb + user-guide/calculus.ipynb + user-guide/tree_structures.ipynb user-guide/area_calc.ipynb user-guide/holoviz.ipynb - user-guide/remapping.ipynb - user-guide/tree_structures.ipynb diff --git a/test/test_intersections.py b/test/test_intersections.py index 769859b51..0f3c62607 100644 --- a/test/test_intersections.py +++ b/test/test_intersections.py @@ -6,7 +6,7 @@ # from uxarray.grid.coordinates import node_lonlat_rad_to_xyz, node_xyz_to_lonlat_rad from uxarray.grid.coordinates import _lonlat_rad_to_xyz, _xyz_to_lonlat_rad -from uxarray.grid.intersections import gca_gca_intersection, gca_constLat_intersection +from uxarray.grid.intersections import gca_gca_intersection, gca_const_lat_intersection class TestGCAGCAIntersection(TestCase): @@ -108,7 +108,7 @@ def test_GCA_constLat_intersections_antimeridian(self): np.deg2rad(10.0)) ]) - res = gca_constLat_intersection(GCR1_cart, np.sin(np.deg2rad(60.0)), verbose=True) + res = gca_const_lat_intersection(GCR1_cart, np.sin(np.deg2rad(60.0)), verbose=True) res_lonlat_rad = _xyz_to_lonlat_rad(*(res[0].tolist())) self.assertTrue( np.allclose(res_lonlat_rad, @@ -123,7 +123,7 @@ def test_GCA_constLat_intersections_empty(self): np.deg2rad(10.0)) ]) - res = gca_constLat_intersection(GCR1_cart, np.sin(np.deg2rad(-10.0)), verbose=False) + res = gca_const_lat_intersection(GCR1_cart, np.sin(np.deg2rad(-10.0)), verbose=False) self.assertTrue(res.size == 0) def test_GCA_constLat_intersections_two_pts(self): @@ -137,7 +137,7 @@ def test_GCA_constLat_intersections_two_pts(self): query_lat = (np.deg2rad(10.0) + max_lat) / 2.0 - res = gca_constLat_intersection(GCR1_cart, np.sin(query_lat), verbose=False) + res = gca_const_lat_intersection(GCR1_cart, np.sin(query_lat), verbose=False) self.assertTrue(res.shape[0] == 2) @@ -149,5 +149,5 @@ def test_GCA_constLat_intersections_no_convege(self): constZ = -0.5150380749100542 with self.assertWarns(UserWarning): - res = gca_constLat_intersection(GCR1_cart, constZ, verbose=False) + res = gca_const_lat_intersection(GCR1_cart, constZ, verbose=False) self.assertTrue(res.shape[0] == 1) diff --git a/uxarray/core/api.py b/uxarray/core/api.py index 204b10e31..f64340586 100644 --- a/uxarray/core/api.py +++ b/uxarray/core/api.py @@ -21,8 +21,7 @@ def open_grid( use_dual: Optional[bool] = False, **kwargs: Dict[str, Any], ) -> Grid: - """Constructs and returns an ``uxarray.Grid`` object from a grid topology - definition. + """Constructs and returns a ``Grid`` from a grid file. Parameters ---------- @@ -102,9 +101,8 @@ def open_dataset( grid_kwargs: Optional[Dict[str, Any]] = {}, **kwargs: Dict[str, Any], ) -> UxDataset: - """Wraps ``xarray.open_dataset()`` and creates a ``uxarray.UxDataset`` - object, given a grid topology definition with a single dataset file or - object with corresponding data. + """Wraps ``xarray.open_dataset()`` to support reading in a grid and data + file together. Parameters ---------- @@ -193,9 +191,8 @@ def open_mfdataset( grid_kwargs: Optional[Dict[str, Any]] = {}, **kwargs: Dict[str, Any], ) -> UxDataset: - """Wraps ``xarray.open_mfdataset()`` and creates a ``uxarray.UxDataset`` - object, given a single grid topology file with multiple dataset paths with - corresponding data. + """Wraps ``xarray.open_dataset()`` to support reading in a grid and + multiple data files together. Parameters ---------- diff --git a/uxarray/core/dataarray.py b/uxarray/core/dataarray.py index aa4e9a7b4..3b64814da 100644 --- a/uxarray/core/dataarray.py +++ b/uxarray/core/dataarray.py @@ -38,9 +38,8 @@ class UxDataArray(xr.DataArray): - """N-dimensional ``xarray.DataArray``-like array. Inherits from - ``xarray.DataArray`` and has its own unstructured grid-aware array - operators and attributes through the ``uxgrid`` accessor. + """Grid informed ``xarray.DataArray`` with an attached ``Grid`` accessor + and grid-specific functionality. Parameters ---------- @@ -123,14 +122,9 @@ def _replace(self, *args, **kwargs): @property def uxgrid(self): - """``uxarray.Grid`` property for ``uxarray.UxDataArray`` to make it - unstructured grid-aware. + """Linked ``Grid`` representing to the unstructured grid the data + resides on.""" - Examples - -------- - uxds = ux.open_dataset(grid_path, data_path) - uxds..uxgrid - """ return self._uxgrid # a setter function @@ -138,6 +132,18 @@ def uxgrid(self): def uxgrid(self, ugrid_obj): self._uxgrid = ugrid_obj + @property + def data_mapping(self): + """Returns which unstructured grid a data variable is mapped to.""" + if self._face_centered(): + return "faces" + elif self._edge_centered(): + return "edges" + elif self._node_centered(): + return "nodes" + else: + return None + def to_geodataframe( self, periodic_elements: Optional[str] = "exclude", @@ -148,10 +154,9 @@ def to_geodataframe( engine: Optional[str] = "spatialpandas", exclude_antimeridian: Optional[bool] = None, ): - """Constructs a ``spatialpandas.GeoDataFrame`` with a "geometry" - column, containing a collection of Shapely Polygons or MultiPolygons - representing the geometry of the unstructured grid paired with a slice - of data mapped to the polygons. + """Constructs a ``GeoDataFrame`` consisting of polygons representing + the faces of the current ``Grid`` with a face-centered data variable + mapped to them. Periodic polygons (i.e. those that cross the antimeridian) can be handled using the ``periodic_elements`` parameter. Setting ``periodic_elements='split'`` will split each periodic polygon along the antimeridian. @@ -258,9 +263,9 @@ def to_polycollection( override: Optional[bool] = False, **kwargs, ): - """Converts a ``UxDataArray`` to a - ``matplotlib.collections.PolyCollection``, representing each face as a - polygon shaded with a face-centered data variable. + """Constructs a ``matplotlib.collections.PolyCollection``` consisting + of polygons representing the faces of the current ``UxDataArray`` with + a face-centered data variable mapped to them. Parameters ---------- @@ -340,7 +345,7 @@ def to_dataset( name: Hashable = None, promote_attrs: bool = False, ) -> UxDataset: - """Convert a UxDataArray to a UxDataset. + """Convert a ``UxDataArray`` to a ``UxDataset``. Parameters ---------- @@ -366,8 +371,7 @@ def to_dataset( def integrate( self, quadrature_rule: Optional[str] = "triangular", order: Optional[int] = 4 ) -> UxDataArray: - """Computes the integral of a data variable residing on an unstructured - grid. + """Computes the integral of a data variable. Parameters ---------- @@ -383,10 +387,10 @@ def integrate( Examples -------- + Open a Uxarray dataset and compute the integral + >>> import uxarray as ux >>> uxds = ux.open_dataset("grid.ug", "centroid_pressure_data_ug") - - # Compute the integral >>> integral = uxds['psi'].integrate() """ if self.values.shape[-1] == self.uxgrid.n_face: @@ -864,8 +868,7 @@ def topological_any( def gradient( self, normalize: Optional[bool] = False, use_magnitude: Optional[bool] = True ): - """Computes the horizontal gradient of a data variable residing on an - unstructured grid. + """Computes the horizontal gradient of a data variable. Currently only supports gradients of face-centered data variables, with the resulting gradient being stored on each edge. The gradient of a node-centered data variable can be approximated by computing the nodal average @@ -888,9 +891,7 @@ def gradient( Example ------- - Face-centered variable >>> uxds['var'].gradient() - Node-centered variable >>> uxds['var'].topological_mean(destination="face").gradient() """ @@ -927,7 +928,7 @@ def gradient( return uxda def difference(self, destination: Optional[str] = "edge"): - """Computes the absolute difference between a data variable. + """Computes the absolute difference of a data variable. The difference for a face-centered data variable can be computed on each edge using the ``edge_face_connectivity``, specified by ``destination='edge'``. @@ -1012,20 +1013,6 @@ def difference(self, destination: Optional[str] = "edge"): return uxda - pass - - @property - def data_mapping(self): - """TODO:""" - if self._face_centered(): - return "faces" - elif self._edge_centered(): - return "edges" - elif self._node_centered(): - return "nodes" - else: - return None - def _face_centered(self) -> bool: """Returns whether the data stored is Face Centered (i.e. contains the "n_face" dimension)""" diff --git a/uxarray/core/dataset.py b/uxarray/core/dataset.py index 23843f9ee..fe61bbf34 100644 --- a/uxarray/core/dataset.py +++ b/uxarray/core/dataset.py @@ -26,9 +26,8 @@ class UxDataset(xr.Dataset): - """A ``xarray.Dataset``-like, multi-dimensional, in memory, array database. - Inherits from ``xarray.Dataset`` and has its own unstructured grid-aware - dataset operators and attributes through the ``uxgrid`` accessor. + """Grid informed ``xarray.Dataset`` with an attached ``Grid`` accessor and + grid-specific functionality. Parameters ---------- @@ -134,14 +133,8 @@ def source_datasets(self, source_datasets_input): @property def uxgrid(self): - """``uxarray.Grid`` property for ``uxarray.UxDataset`` to make it - unstructured grid-aware. - - Examples - -------- - uxds = ux.open_dataset(grid_path, data_path) - uxds.uxgrid - """ + """Linked ``Grid`` representing to the unstructured grid the data + resides on.""" return self._uxgrid # a setter function diff --git a/uxarray/grid/grid.py b/uxarray/grid/grid.py index 72b5aee19..3c19609f1 100644 --- a/uxarray/grid/grid.py +++ b/uxarray/grid/grid.py @@ -278,10 +278,10 @@ def from_file( backend : str, default='geopandas' Backend to use to read the file, xarray or geopandas. - Usage - ----- + Examples + -------- >>> import uxarray as ux - >>> grid = ux.Grid.from_file("path/to/file.shp") + >>> grid = ux.Grid.from_file("path/to/file.shp", backend='geopandas') Note ---- @@ -324,7 +324,7 @@ def from_topology( Note ---- - To construct a UGRID-complient grid, the user must provide at least ``node_lon``, ``node_lat`` and ``face_node_connectivity`` + To construct a UGRID-compliant grid, the user must provide at least ``node_lon``, ``node_lat`` and ``face_node_connectivity`` Parameters ---------- @@ -342,8 +342,8 @@ def from_topology( Dictionary of dimension names mapped to the ugrid conventions (i.e. {"nVertices": "n_node}) **kwargs : - Usage - ----- + Examples + -------- >>> import uxarray as ux >>> node_lon, node_lat, face_node_connectivity, fill_value = ... >>> uxgrid = ux.Grid.from_ugrid(node_lon, node_lat, face_node_connectivity, fill_value) @@ -399,11 +399,9 @@ def from_face_vertices( return cls(grid_ds, source_grid_spec="Face Vertices") def validate(self): - """Validate a grid object check for common errors, such as: + """Validates the current ``Grid``, checking for Duplicate Nodes, + Present Connectivity, and Non-Zero Face Areas. - - Duplicate nodes - - Connectivity - - Face areas (non zero) Raises ------ RuntimeError @@ -524,8 +522,8 @@ def __getitem__(self, item): """Implementation of getitem operator for indexing a grid to obtain variables. - Usage - ----- + Examples + -------- >>> uxgrid['face_node_connectivity'] """ return getattr(self, item) @@ -1113,7 +1111,7 @@ def node_face_connectivity(self, value): @property def edge_node_distances(self): - """Distances between the two nodes that surround each edge. + """Distances between the two nodes that surround each edge in degrees. Dimensions ``(n_edge, )`` """ @@ -1129,7 +1127,8 @@ def edge_node_distances(self, value): @property def edge_face_distances(self): - """Distances between the centers of the faces that saddle each edge. + """Distances between the centers of the faces that saddle each edge in + degrees. Dimensions ``(n_edge, )`` """ @@ -1562,8 +1561,8 @@ def normalize_cartesian_coordinates(self): self.face_z.data = face_z def to_xarray(self, grid_format: Optional[str] = "ugrid"): - """Returns a xarray Dataset representation in a specific grid format - from the Grid object. + """Returns an ``xarray.Dataset`` with the variables stored under the + ``Grid`` encoded in a specific grid format. Parameters ---------- @@ -1610,9 +1609,8 @@ def to_geodataframe( return_non_nan_polygon_indices: Optional[bool] = False, exclude_nan_polygons: Optional[bool] = True, ): - """Constructs a ``spatialpandas.GeoDataFrame`` with a "geometry" - column, containing a collection of Shapely Polygons or MultiPolygons - representing the geometry of the unstructured grid. + """Constructs a ``GeoDataFrame`` consisting of polygons representing + the faces of the current ``Grid`` Periodic polygons (i.e. those that cross the antimeridian) can be handled using the ``periodic_elements`` parameter. Setting ``periodic_elements='split'`` will split each periodic polygon along the antimeridian. @@ -1732,8 +1730,8 @@ def to_polycollection( return_non_nan_polygon_indices: Optional[bool] = False, **kwargs, ): - """Converts a ``Grid`` to a ``matplotlib.collections.PolyCollection``, - representing each face as a polygon. + """Constructs a ``matplotlib.collections.PolyCollection``` consisting + of polygons representing the faces of the current ``Grid`` Parameters ---------- @@ -1815,8 +1813,8 @@ def to_linecollection( override: Optional[bool] = False, **kwargs, ): - """Converts a ``Grid`` to a ``matplotlib.collections.LineCollection``, - representing each edge as a line. + """Constructs a ``matplotlib.collections.LineCollection``` consisting + of lines representing the edges of the current ``Grid`` Parameters ---------- diff --git a/uxarray/grid/integrate.py b/uxarray/grid/integrate.py index a562fc2ca..5f0135573 100644 --- a/uxarray/grid/integrate.py +++ b/uxarray/grid/integrate.py @@ -1,6 +1,6 @@ import numpy as np from uxarray.constants import ERROR_TOLERANCE, INT_FILL_VALUE -from uxarray.grid.intersections import gca_constLat_intersection +from uxarray.grid.intersections import gca_const_lat_intersection from uxarray.grid.coordinates import _xyz_to_lonlat_rad import pandas as pd @@ -244,7 +244,7 @@ def _get_faces_constLat_intersection_info( # Calculate intersections (assuming a batch-capable intersection function) for idx, edge in enumerate(valid_edges): if is_GCA[idx]: - intersections = gca_constLat_intersection( + intersections = gca_const_lat_intersection( edge, latitude_cart, is_directed=is_directed ) diff --git a/uxarray/grid/intersections.py b/uxarray/grid/intersections.py index 21daab6dd..ccf767df5 100644 --- a/uxarray/grid/intersections.py +++ b/uxarray/grid/intersections.py @@ -115,7 +115,7 @@ def gca_gca_intersection(gca1_cart, gca2_cart, fma_disabled=True): return np.array(res) -def gca_constLat_intersection( +def gca_const_lat_intersection( gca_cart, constZ, fma_disabled=True, verbose=False, is_directed=False ): """Calculate the intersection point(s) of a Great Circle Arc (GCA) and a diff --git a/uxarray/plot/accessor.py b/uxarray/plot/accessor.py index b835ab790..bfaa3c16e 100644 --- a/uxarray/plot/accessor.py +++ b/uxarray/plot/accessor.py @@ -18,8 +18,10 @@ class GridPlotAccessor: - """Plotting Accessor for Grid, accessed through ``Grid.plot()`` or - ``Grid.plot.specific_routine()``""" + """Plotting accessor for ``Grid``. + + Accessed through `Grid.plot()` or `Grid.plot.specific_routine()` + """ _uxgrid: Grid __slots__ = ("_uxgrid",) @@ -47,7 +49,7 @@ def points(self, element="nodes", backend=None, **kwargs): - "faces" or "face centers" or "face_latlon" for grid face centers, - "edges" or "edge centers" or "edge_latlon" for grid edges. backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.points`. For a full list of supported arguments, please refer to https://hvplot.holoviz.org/user_guide/Customization.html @@ -72,7 +74,7 @@ def points(self, element="nodes", backend=None, **kwargs): elif element in ["edges", "edge centers", "edge_latlon"]: lon, lat = self._uxgrid.edge_lon.values, self._uxgrid.edge_lat.values else: - raise ValueError("TODO: ") + raise ValueError(f"Unsupported element {element}") verts = {"lon": lon, "lat": lat} @@ -92,7 +94,7 @@ def nodes(self, backend=None, **kwargs): Parameters ---------- backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.points`. For a full list of supported arguments, please refer to https://hvplot.holoviz.org/user_guide/Customization.html @@ -116,12 +118,12 @@ def corner_nodes(self, backend=None, **kwargs): corner_nodes.__doc__ = nodes.__doc__ def edge_coords(self, backend=None, **kwargs): - """Wrapper for ``Grid.plot.points(element='edge centers') + """Wrapper for ``Grid.plot.points(element='edge centers')`` Parameters ---------- backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.points`. For a full list of supported arguments, please refer to https://hvplot.holoviz.org/user_guide/Customization.html @@ -139,12 +141,12 @@ def edge_centers(self, backend=None, **kwargs): edge_centers.__doc__ = edge_coords.__doc__ def face_coords(self, backend=None, **kwargs): - """Wrapper for ``Grid.plot.points(element='face centers') + """Wrapper for ``Grid.plot.points(element='face centers')`` Parameters ---------- backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.points`. For a full list of supported arguments, please refer to https://hvplot.holoviz.org/user_guide/Customization.html @@ -162,7 +164,7 @@ def face_centers(self, backend=None, **kwargs): face_centers.__doc__ = face_coords.__doc__ def edges(self, periodic_elements="exclude", backend=None, **kwargs): - """Plots the edges of a grid as a path plot. + """Plots the edges of a Grid. This function plots the edges of the grid as geographical paths using `hvplot`. The plot can ignore, exclude, or split periodic elements based on the provided option. @@ -179,7 +181,7 @@ def edges(self, periodic_elements="exclude", backend=None, **kwargs): - "ignore": Include periodic elements without any corrections - "split": Split periodic elements. backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.paths`. These can include: - "rasterize" (bool): Whether to rasterize the plot (default: False), @@ -222,8 +224,11 @@ def mesh(self, periodic_elements="exclude", backend=None, **kwargs): class UxDataArrayPlotAccessor: - """Plotting Accessor for UxDataArray, accessed through - ``UxDataArray.plot()`` or ``UxDataArray.plot.specific_routine()``""" + """Plotting Accessor for ``UxDataArray``. + + Accessed through `UxDataArray.plot()` or + `UxDataArray.plot.specific_routine()` + """ _uxda: UxDataArray __slots__ = ("_uxda",) @@ -256,12 +261,12 @@ def __getattr__(self, name: str) -> Any: raise AttributeError(f"Unsupported Plotting Method: '{name}'") def polygons(self, periodic_elements="exclude", backend=None, *args, **kwargs): - """Generated a shaded polygon plot. + """Generate a shaded polygon plot of a face-centered data variable. - This function plots the faces of an unstructured grid shaded with a face-centered data variable using `hvplot. + This function plots the faces of an unstructured grid shaded with a face-centered data variable using hvplot. It allows for rasterization, projection settings, and labeling of the data variable to be customized through keyword arguments. The backend for plotting can also be specified. - If a data array (`_uxda`) has a name, its name is used for color label. + If a data array has a name, its name is used for color label. Parameters ---------- @@ -269,10 +274,10 @@ def polygons(self, periodic_elements="exclude", backend=None, *args, **kwargs): Specifies whether to include or exclude periodic elements in the grid. Options are: - "exclude": Exclude periodic elements, - - "split": Split periodic elements. + - "split": Split periodic elements. - "ignore": Include periodic elements without any corrections backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) *args : tuple Additional positional arguments to be passed to `hvplot.polygons`. **kwargs : dict @@ -326,7 +331,7 @@ def points(self, backend=None, *args, **kwargs): Parameters ---------- backend : str or None, optional - The plotting backend to use. Defaults to None, which uses the default backend. + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) **kwargs : dict Additional keyword arguments passed to `hvplot.points`. For a full list of supported arguments, please refer to https://hvplot.holoviz.org/user_guide/Customization.html @@ -395,7 +400,7 @@ def rasterize( method: str Selects what type of element to rasterize (point, trimesh, polygon). backend: str - Selects whether to use Holoview's "matplotlib" or "bokeh" backend for rendering plots + Plotting backend to use. One of ['matplotlib', 'bokeh']. Equivalent to running holoviews.extension(backend) projection: ccrs Custom projection to transform (lon, lat) coordinates for rendering pixel_ratio: float @@ -442,8 +447,7 @@ def rasterize( class UxDatasetPlotAccessor: - """Plotting Accessor for UxDataset, accessed through ``UxDataset.plot()`` - or ``UxDataset.plot.specific_routine()``""" + """Plotting accessor for ``UxDataset``.""" _uxds: UxDataset __slots__ = ("_uxds",) diff --git a/uxarray/remap/dataarray_accessor.py b/uxarray/remap/dataarray_accessor.py index 3ea5f78db..a3c44105d 100644 --- a/uxarray/remap/dataarray_accessor.py +++ b/uxarray/remap/dataarray_accessor.py @@ -13,6 +13,8 @@ class UxDataArrayRemapAccessor: + """Remapping accessor for ``UxDataArray``""" + def __init__(self, uxda: UxDataArray): self.uxda = uxda @@ -33,8 +35,8 @@ def nearest_neighbor( remap_to: str = "face centers", coord_type: str = "spherical", ): - """Nearest Neighbor Remapping between a source (``UxDataArray``) and - destination.`. + """Nearest Neighbor Remapping between a source ``UxDataArray`` and + destination ``Grid`` Parameters --------- @@ -56,8 +58,8 @@ def inverse_distance_weighted( power=2, k=8, ): - """Inverse Distance Weighted Remapping between a source - (``UxDataArray``) and destination.`. + """Inverse Distance Weighted Remapping between a source ``UxDataArray`` + and destination ``Grid`` Parameters --------- diff --git a/uxarray/remap/dataset_accessor.py b/uxarray/remap/dataset_accessor.py index dbf58e4ad..59a8694cb 100644 --- a/uxarray/remap/dataset_accessor.py +++ b/uxarray/remap/dataset_accessor.py @@ -13,6 +13,8 @@ class UxDatasetRemapAccessor: + """Remapping accessor for ``UxDataset``""" + def __init__(self, uxds: UxDataset): self.uxds = uxds @@ -33,8 +35,8 @@ def nearest_neighbor( remap_to: str = "face centers", coord_type: str = "spherical", ): - """Nearest Neighbor Remapping between a source (``UxDataset``) and - destination.`. + """Nearest Neighbor Remapping between a source ``UxDataset`` and + destination ``Grid`` Parameters --------- @@ -56,8 +58,8 @@ def inverse_distance_weighted( power=2, k=8, ): - """Inverse Distance Weighted Remapping between a source (``UxDataset``) - and destination.`. + """Inverse Distance Weighted Remapping between a source ``UxDataset`` + and destination ``Grid`` Parameters ---------