{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Plotting API\n", "---\n", "\n", "UXarray provides a feature-rich plotting API for visualizing unstructured grids, with or without data variables.\n", "\n", "This notebook introduces how to interface with the plotting methods through UXarray's core data structures and provides an introduction to methods that are covered in detail in the next sections." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "
\n", "

See also:

\n", " This notebook acts as an introduction into using the UXarray plotting API. Please refer to the following notebooks in this chapter for a detailed\n", " overview of visualization techniques for different purposes (e.g. Grid Topology, Polygons)\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## UXarray Plotting API Design" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before jumping into any code, let's take a look at a high-level snapshot of UXarray's API design from an Unifed Modeling Language (UML)-like standpoint.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"UXarray\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Key takeaways from this design are that:\n", "\n", "- UXarray's unified grid representation (through the UGRID conventions) means that all visualization functionality is agnostic to the grid format initially provided by the user.\n", "- Each Uxarray data structure (i.e. `Grid`, `UxDataset`, `UxDataArray`) has its own `.plot` accessor, which is used to call plotting routines.\n", "- The visualization functionality through these `.plot` accessors use HoloViz packages' plotting functions, wrapping them in a way to exploit all the information that comes from unstructured grids (e.g. connectivity) and provide our unstructured grids-specific functions in the most convenient way for the user.\n", "- `Grid` additionally provides conversion functions that generate `SpatialPandas.GeoDataFrame` as well as `Matplotlib.PolyCollection` and `Matplotlib.LineCollection` data structures to be visualized in HoloViz packages and Matplotlib, respectively, at the user's own convenience.\n", "\n", "Now, we can see the API in action on a sample dataset." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "import uxarray as ux" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "## Data\n", "\n", "The grid and data files used in this notebook are from 480km MPAS Ocean model output.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "base_path = \"../../meshfiles/\"\n", "grid_filename = base_path + \"oQU480.grid.nc\"\n", "data_filename = base_path + \"oQU480.data.nc\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "grid = ux.open_grid(grid_filename)\n", "grid" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "uxds = ux.open_dataset(grid_filename, data_filename)\n", "uxds" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "## Grid\n", "\n", "Since a `Grid` instance only contains information about the topology of an unstructured grid (a.k.a. no data variables), the visualizations generated from the `Grid` class only showcase the coordinates and connectivity.\n", "\n", "By default, the `Grid.plot` method renders the borders of each of the faces." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "grid.plot(title=\"Default Grid Plot\")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "The UXarray plotting API is written with HoloViews, with the default backend used for generating plots being `bokeh`. This means that by default, all plots are enabled with interactive features such as panning and zooming. In addition to `bokeh`, UXarray also supports the `matplotlib` backend.\n", "\n", "For the remainder of this notebook, we will use the `matplotlib` backend to generate static plots." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "grid.plot(\n", " title=\"Default Grid Plot with Matplotlib\",\n", " backend=\"matplotlib\",\n", " aspect=2,\n", " fig_size=500,\n", ")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "\n", "\n", "You can call specific plotting routines through the `plot` accessor" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "grid.plot.nodes(title=\"Grid Node Plot\", backend=\"matplotlib\", aspect=2, fig_size=500)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "Since each `UxDataset` and `UxDataArray` is always linked to a `Grid` instance through the `uxgrid` attribute, all of these grid-specific visualizations are accessible by using that attribute.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "uxds.uxgrid.plot(\n", " title=\"Grid plot through uxgrid attribute\",\n", " backend=\"matplotlib\",\n", " aspect=2,\n", " fig_size=500,\n", ")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "## UxDataArray Plotting" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "The default plotting method is a great starting point for visualizations. It selects what visualization method to use based on the grid element that the data is mapped to (nodes, edges, faces) and the number of elements in the mesh. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "uxds[\"bottomDepth\"].plot(\n", " title=\"Default UxDataArray Plot\", backend=\"matplotlib\", aspect=2, fig_size=500\n", ")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "We can also call other plotting methods through the `plot` accessor, as was the case with the `Grid` class.\n", "\n", "For example, if we wanted to rasterize the polygons and exclude the ones that cross the antimeridian, it would look something like the following." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "uxds[\"bottomDepth\"].plot.polygons(\n", " exclude_antimeridian=False,\n", " title=\"Vector Polygon Plot\",\n", " backend=\"matplotlib\",\n", " aspect=2,\n", " fig_size=500,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## UxDataset Plotting\n", "\n", "As of the most recent release, UXarray does not support plotting functionality through a `ux.UxDataset`. For instance, if the following commented out code was executed, it would throw an exception.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# uxds.plot()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.5" }, "nbdime-conflicts": { "local_diff": [ { "diff": [ { "diff": [ { "key": 0, "op": "addrange", "valuelist": [ "Python 3" ] }, { "key": 0, "length": 1, "op": "removerange" } ], "key": "display_name", "op": "patch" } ], "key": "kernelspec", "op": "patch" } ], "remote_diff": [ { "diff": [ { "diff": [ { "key": 0, "op": "addrange", "valuelist": [ "Python3" ] }, { "key": 0, "length": 1, "op": "removerange" } ], "key": "display_name", "op": "patch" } ], "key": "kernelspec", "op": "patch" } ] }, "toc-autonumbering": false }, "nbformat": 4, "nbformat_minor": 4 }