imod.visualize - Customized plots

Module to provide functions to create customized plots.

These functions build on existing libraries, and merely serve as a shorthand for plots that may be useful to evaluate groundwater models. All xarray.DataArray and pandas.DataFrame objects have .plot() or .imshow() methods to plot them directly.

class imod.visualize.GridAnimation3D(da, vertical_exaggeration=30.0, mesh_kwargs={}, plotter_kwargs={})[source]

Bases: object

Class to easily setup 3D animations for transient data. Use the imod.visualize.StaticGridAnimation3D when the location of the displayed cells is constant over time: it will render much faster.

You can iteratively add or change settings to the plotter, until you’re satisfied. Call the .peek() method to take a look. When satisfied, call .output() to write to a file.

Parameters
  • da (xr.DataArray) – The dataarray with transient data. Must contain a “time” dimension.

  • vertical_exaggeration (float, defaults to 30.0) –

  • mesh_kwargs (dict) – keyword arguments that are forwarded to the pyvista mesh representing “da”. If “stitle” is given as one of the arguments, the special keyword “timestamp” can be used to render the plotted time as part of the title. See example.

  • plotter_kwargs (dict) – keyword arguments that are forwarded to the pyvista plotter.

Examples

Initialize the animation:

>>> animation = imod.visualize.GridAnimation3D(concentration, mesh_kwargs=dict(cmap="jet"))

Check what it looks like (if a window pops up: press “q” instead of the X to return):

>>> animation.peek()

Change the camera position, add bounding box, and check the result:

>>> animation.plotter.camera_position = (2, 1, 0.5)
>>> animation.plotter.add_bounding_box()
>>> animation.peek()

When it looks good, write to a file:

>>> animation.write("example.mp4")

If you’ve made some changes that don’t look good, call .reset() to start over:

>>> animation.reset()

Note that .reset() is automatically called when the animation has finished writing.

You can use “stitle” in mesh_kwargs in conjunction with the “timestamp” keyword to print a formatted timestamp in the animation:

>>> animation = imod.visualize.GridAnimation3D(concentration, mesh_kwargs=dict(stitle="Concentration on {timestamp:%Y-%m-%d}"))
peek()[source]

Display the current state of the animation plotter.

reset()[source]

Reset the plotter to its base state.

write(filename, framerate=24)[source]

Write the animation to a video or gif.

Resets the plotter when finished animating.

Parameters
  • filename (str, pathlib.Path) – Filename to write the video to. Should be an .mp4 or .gif.

  • framerate (int, optional) – Frames per second. Not honoured for gif.

class imod.visualize.StaticGridAnimation3D(da, vertical_exaggeration=30.0, mesh_kwargs={}, plotter_kwargs={})[source]

Bases: imod.visualize.pyvista.GridAnimation3D

Class to easily setup 3D animations for transient data; Should only be used when the location of the displayed cells is constant over time. It will render much faster than imod.visualize.GridAnimation3D.

Refer to examples of imod.visualize.GridAnimation3D.

imod.visualize.cross_section(da, colors, levels, layers=False, aquitards=None, kwargs_pcolormesh={}, kwargs_colorbar={}, kwargs_aquitards=None, return_cmap_norm=False, fig=None, ax=None)[source]

Wraps matplotlib.pcolormesh to draw cross-sections, drawing cell boundaries accurately. Aquitards can be plotted on top of the cross-section, by providing a DataArray with the aquitard location for aquitards.

Parameters
  • da (xr.DataArray) –

    Two dimensional DataArray containing data of the cross section. One dimension must be “layer”, and the second dimension will be used as the x-axis for the cross-section.

    Coordinates “top” and “bottom” must be present, and must have at least the “layer” dimension (voxels) or both the “layer” and x-coordinate dimension.

    Use imod.select.cross_section_line() or cross_section_linestring() to obtain the required DataArray.

  • colors (list of str, or list of RGB tuples) –

    Matplotlib acceptable list of colors. Length N. Accepts both tuples of (R, G, B) and hexidecimal (e.g. “#7ec0ee”).

    Looking for good colormaps? Try: http://colorbrewer2.org/ Choose a colormap, and use the HEX JS array.

  • levels (listlike of floats or integers) – Boundaries between the legend colors/classes. Length: N - 1.

  • layers (boolean, optional) – Whether to draw lines separating the layers.

  • aquitards (xr.DataArray, optional) – Datarray containing data on location of aquitard layers.

  • kwargs_pcolormesh (dict) – Other optional keyword arguments for matplotlib.pcolormesh.

  • kwargs_colorbar (dict) – Optional keyword argument whiten_triangles whitens respective colorbar triangle if data is not larger/smaller than legend_levels-range. Defaults to True. Other arguments are forwarded to fig.colorbar()

  • kwargs_aquitards (dict) – These arguments are forwarded to matplotlib.fill_between to draw the aquitards.

  • return_cmap_norm (boolean, optional) – Return the cmap and norm of the plot, default False

  • fig (matplotlib Figure instance, optional) – Figure to write plot to. If not supplied, a Figure instance is created

  • ax (matplotlib Axes instance, optional) – Axes to write plot to. If not supplied, an Axes instance is created

Returns

  • fig (matplotlib.figure)

  • ax (matplotlig.ax)

  • if return_cmap_norm == True

  • cmap (matplotlib.colors.ListedColormap)

  • norm (matplotlib.colors.BoundaryNorm)

Examples

Basic cross section:

>>> imod.visualize.cross_section(da, colors, levels)

Aquitards can be styled in multiple ways. For a transparent grey overlay (the default):

>>> kwargs_aquitards = {"alpha": 0.5, "facecolor": "grey"}
>>> imod.visualize.cross_section(da, colors, levels, aquitards=aquitards, kwargs_aquitards)

For a hatched overlay:

>>> kwargs_aquitards = {"hatch": "/", "edgecolor": "k"}
>>> imod.visualize.cross_section(da, colors, levels, aquitards=aquitards, kwargs_aquitards)
imod.visualize.grid_3d(da, vertical_exaggeration=30.0, exterior_only=True, exterior_depth=1, return_index=False)[source]

Constructs a 3D PyVista representation of a DataArray. DataArrays should be two-dimensional or three-dimensional:

  • 2D: dimensions should be {"y", "x"}. E.g. a DEM.

  • 3D: dimensions should be {"z", "y", "x"}, for a voxel model.

  • 3D: dimensions should be {"layer", "y", "x"}, with coordinates

    "top"({"layer", "y", "x"}) and "bottom"({"layer", "y", "x"}).

Parameters
  • da (xr.DataArray) –

  • vertical_exaggeration (float, default 30.0) –

  • exterior_only (bool, default True) – Whether or not to only draw the exterior. Greatly speeds up rendering, but it means that pyvista slices and filters produce “hollowed out” results.

  • exterior_depth (int, default 1) – How many cells to consider as exterior. In case of large jumps, holes can occur. By settings this argument to a higher value, more of the inner cells will be rendered, reducing the chances of gaps occurring.

  • return_index (bool, default False) –

Returns

Return type

pyvista.UnstructuredGrid

Examples

>>> grid = imod.visualize.grid_3d(da)

To plot the grid, call the .plot() method.

>>> grid.plot()

Use .assign_coords to assign tops and bottoms to layer models:

>>> top = imod.idf.open("top*.idf")
>>> bottom = imod.idf.open("bot*.idf")
>>> kd = imod.idf.open("kd*.idf")
>>> kd = kd.assign_coords(top=(("layer", "y", "x"), top))
>>> kd = kd.assign_coords(bottom=(("layer", "y", "x"), bottom))
>>> grid = imod.visualize.grid_3d(kd)
>>> grid.plot()

Refer to the PyVista documentation on how to customize plots: https://docs.pyvista.org/index.html

imod.visualize.imshow_topview(da, name, directory='.', cmap='viridis', overlays=[], quantile_colorscale=True, figsize=8, 8, levels=None)[source]

Automatically colors by quantile.

Dumps PNGs into directory of choice.

imod.visualize.line_3d(polygon, z=0.0)[source]

Returns the exterior line of a shapely polygon.

Parameters
  • polygon (shapely.geometry.Polygon) –

  • z (float or xr.DataArray) – z-coordinate to assign to line. If DataArray, assigns z-coordinate based on xy locations in DataArray.

Returns

Return type

pyvista.PolyData

imod.visualize.plot_map(raster, colors, levels, overlays=[], kwargs_raster=None, kwargs_colorbar=None, figsize=None, return_cbar=False)[source]
Parameters
  • raster (xr.DataArray) – 2D grid to plot.

  • colors (list of str, list of RGBA/RGBA tuples, colormap name (str), or) –

    LinearSegmentedColormap If list, it should be a Matplotlib acceptable list of colors. Length N. Accepts both tuples of (R, G, B) and hexidecimal (e.g. #7ec0ee).

    If str, use an existing Matplotlib colormap. This function will autmatically add distinctive colors for pixels lower or high than the given min respectivly max level. If LinearSegmentedColormap, you can use something like matplotlib.cm.get_cmap(‘jet’) as input. This function will not alter the colormap, so add under- and over-colors yourself.

    Looking for good colormaps? Try: http://colorbrewer2.org/ Choose a colormap, and use the HEX JS array.

  • levels (listlike of floats or integers) – Boundaries between the legend colors/classes. Length: N - 1.

  • overlays (list of dicts, optional) – Dicts contain geodataframe (key is “gdf”), and the keyword arguments for plotting the geodataframe.

  • kwargs_raster (dict of keyword arguments, optional) – These arguments are forwarded to ax.imshow()

  • kwargs_colorbar (dict of keyword arguments, optional) – These arguments are forwarded to fig.colorbar()

  • figsize (tuple of two floats or integers, optional) – This is used in plt.subplots(figsize)

  • return_cbar (boolean, optional) – Return the matplotlib.Colorbar instance. Defaults to False.

Returns

  • fig (matplotlib.figure)

  • ax (matplotlig.ax)

  • if return_cbar == True

  • cbar (matplotlib.Colorbar)

Examples

Plot with an overlay:

>>> overlays = [{"gdf": geodataframe, "edgecolor": "black"}]
>>> imod.visualize.spatial.plot_map(raster, legend, overlays)

Label the colorbar and the colorbar ticks

imod.visualize.read_imod_legend(path)[source]
Parameters

path (str) – Path to iMOD .leg file.

Returns

  • colors (List of hex colors of length N.)

  • levels (List of floats of length N-1. These are the boundaries between) – the legend colors/classes.

imod.visualize.waterbalance_barchart(df, inflows, outflows, datecolumn=None, format='%Y-%m-%d', ax=None, unit=None, colors=None)[source]
Parameters
  • df (pandas.DataFrame) – The dataframe containing the water balance data.

  • inflows (listlike of str) –

  • outflows (listlike of str) –

  • datecolumn (str, optional) –

  • format (str, optional,) –

  • ax (matplotlib.Axes, optional) –

  • unit (str, optional) –

  • colors (listlike of strings or tuples) –

Returns

ax

Return type

matplotlib.Axes

Examples

>>> fig, ax = plt.subplots()
>>> imod.visualize.waterbalance_barchart(
>>>    ax=ax,
>>>    df=df,
>>>    inflows=["Rainfall", "River upstream"],
>>>    outflows=["Evapotranspiration", "Discharge to Sea"],
>>>    datecolumn="Time",
>>>    format="%Y-%m-%d",
>>>    unit="m3/d",
>>>    colors=["#ca0020", "#f4a582", "#92c5de", "#0571b0"],
>>>    )
>>> fig.savefig("Waterbalance.png", dpi=300, bbox_inches="tight")