Visualising field using holoviews#

There are several ways how a field can be visualised, using:

  • matplotlib

  • k3d

  • holoviews

  • vtk-based libraries, e.g. pyvista

holoviews provides interactive two-dimensional plots of fields. Different from the matplotlib interface it is not required to first slice the field using sel method to obtain a two dimensional field. Instead, a slider is automatically created for the out-of-plane component of the 3d field, for example.

import discretisedfield as df

As an example we study an eliptical cylinder. We initialise the field such that its x and y component describe a vortex-like object (with the vortex core position changing along z direction) and the z component changing (and swapping sign) with the position in z direction. We set valid="norm" to automatically hide the cells outside the cylinder in all plots.

mesh = df.Mesh(
    p1=(-20e-9, -10e-9, -5e-9), p2=(20e-9, 10e-9, 5e-9), cell=(1e-9, 1e-9, 1e-9)

def value(p):
    x, y, z = p
    return -y + z, x + z, z

def norm(p):
    x, y, _ = p
    if (x / 2) ** 2 + y**2 > 10e-9**2:
        return 0
        return 1

field = df.Field(mesh, nvdim=3, value=value, norm=norm, valid="norm")

We can create a simple plot by calling hv. We have to pass two of the spatial directions out of x, y, and z to the kdims variable. We choose the x and y directions. This defines the plot x and plot y direction. Furthermore, we automatically get a slider to select a value for the remaining out-of-plane direction.

# Note for web users: You should have an active notebook session to interact with the plot
field.hv(kdims=["x", "y"])

If there is only one element in the out-of-plane directon the slider is omitted. Note, that holoviews by default picks different colourmaps depending on the type of data (and the symmetries it detects in them). Changing the colourmap is explained below.

field.sel("z").hv(kdims=["x", "y"])

Internally, the field is converted to an xarray DataArray and hvplot is used to create the plot. The plot consists of two parts, a “scalar” part for the out-of-plane component that is visualised with the colour and an in-plane-component part visualised with arrows. We now discuss how to create and modify these individually and in the end come back to the combined plot.

Scalar plot#

To create a scalar plot we use hv.scalar.

field.z.hv.scalar(kdims=["x", "y"], clim=(-1, 1))

In the above example we have extracted a single component for the scalar plot. The hv interface additionally allows us to do this interactively with a separate widget.

field.hv.scalar(kdims=["x", "y"])

To filter out parts of the field we can pass an additional variable roi. For this example we plot the field in the xy plane, normal to the z direction and remove all values where the absolute value of the z component of the vector field is smaller than 0.5. We can pass additional keyword arguments that are directly forwarded to xarray.hvplot, e.g. clim and cmap. For all available options please refer to the documentation of holoviews.

roi = df.Field(field.mesh, nvdim=1, value=abs(field.z.array) < 0.5)

field.z.hv.scalar(kdims=["x", "y"], roi=roi, clim=(-1, 1), cmap="plasma")

It is possible to reduce the number of points show in the plot with parameter n. This functionality is rarely needed for scalar plots, refer to the explanation for vector plots below for more details.

field.hv.scalar(kdims=["x", "y"], n=(10, 10), clim=(-1, 1), cmap="plasma")
field.hv.scalar(kdims=["x", "y"], clim=(-1, 1), cmap="plasma")

Vector plot#

For vector fields we can create a vector plot where the arrows show direction and length of the in-plane-component and the arrow colour for the out-of-plane component.

field.hv.vector(kdims=["x", "y"]).opts(colorbar=True)

To uses a different component of the same field for colouring we can pass the name of that component.

field.hv.vector(kdims=["x", "y"], cdim="y", cmap="plasma")

To disable automatic colouring we can pass use_color=False. By default the arrows are then shown in black. We can use a different uniform colour by passing color.

field.hv.vector(kdims=["x", "y"], use_color=False, color="blue")

For vector plots it is sometimes necessary to reduce the number of arrows shown on the plot. This can be accomplished with the parameter n. This parameter specifies the number of points show for different dimensions. A tuple with two int values can be passed. These are interpreted as the number of points in the two kdims. Internally, a very basic re-sampling is performed (without any interpolation). The extreme points are always kept and additional points are chosen equally distributed in between. Note that this might potentially hide features in complicated situations and should be used with care.

field.hv.vector(kdims=["x", "y"], n=(20, 10))

For 3d vector fields we internally assume, that the first field component points in spatial x direction, the second in y direction, and the third in z direction. If we have a 2d vector field (e.g. a projection in some direction) we do no know which vector components correspond to which spatial directions. Therefore, one has to explicitly select components to be plotted in the plot x and plot y directions using vdims. Here we take the first two components of our field to create a new 2d vector field.

field_2d = field.x << field.y

To avoid confusions we rename the components:

field_2d.vdims = ["a", "b"]
  • Mesh
    • Region
      • pmin = [-2e-08, -1e-08, -5e-09]
      • pmax = [2e-08, 1e-08, 5e-09]
      • dims = ['x', 'y', 'z']
      • units = ['m', 'm', 'm']
    • n = [40, 20, 10]
  • nvdim = 2
  • vdims:
    • a
    • b

To create a vector plot for a non-three-dimensional field we have to pass vdims.

First, we assume that the first component a points in x direction and the second b in y direction. We pass a list to vdims. Furthermore, we disable automatic colouring because it is not supported for 2d vector fields. (If we wouldn’t specify use_color=False we would see a warning that automatic colouring is not supported and that it is disabled. By explicitly setting use_color to False we can avoid this warning.)

field_2d.hv.vector(kdims=["x", "y"], vdims=["a", "b"], use_color=False)