#!/usr/bin/env python # coding: utf-8 # # Field visualisation using `pyvista` # # **Note:** If you experience any problems in plotting with `pyvista`, please make sure you run the Jupyter notebook in Google Chrome. # # There are several ways how a field can be visualised, using: # # - `matplotlib` # -`pyvista` # - `holoviews` # - vtk-based libraries, e.g. `pyvista` # # # `pyvista` provides three-dimensional interactive plots of fields inside Jupyter notebook. # # Let us say we have a sample, which is an ellipsoid # # $$\frac{x^2}{a^2} + \frac{y^2}{b^2} + \frac{z^2}{c^2} <= 1$$ # # with $a=5\,\text{nm}$, $b=3\,\text{nm}$, and $c=2\,\text{nm}$. The space is discretised into cells with dimensions $(0.5\,\text{nm}, 0.5\,\text{nm}, 0.5\,\text{nm})$. The value of the field at $(x, y, z)$ point is $(-cy, cx, cz)$, with $c=10^{9}$. The norm of the field inside the cylinder is $10^{6}$. # # Let us first build that field. # In[1]: import discretisedfield as df a, b, c = 5e-9, 3e-9, 2e-9 cell = (0.5e-9, 0.5e-9, 0.5e-9) mesh = df.Mesh(p1=(-a, -b, -c), p2=(a, b, c), cell=cell) def norm_fun(pos): x, y, z = pos if (x / a) ** 2 + (y / b) ** 2 + (z / c) ** 2 <= 1: return 1e6 else: return 0 def value_fun(pos): x, y, z = pos c = 1e9 return (-c * y, c * x, c * z) field = df.Field(mesh, nvdim=3, value=value_fun, norm=norm_fun, valid="norm") # The most basic plot we can show is the plot of all the cells where the value is valid. # In[2]: field.pyvista.valid() # The plot is interactive, so it can be manipulated using a mouse. To change the color of voxels, we can pass the new color via `color` argument. # In[3]: field.pyvista.valid(color="red") # Next, we can plot a scalar field. For plotting a scalar field, we are using `discretisedfield.Field.pyvista.scalar()` method. This produces an interactive slice of the field. # In[4]: field.pyvista.scalar() # By default, this plots the last `vdims`. However, we can plot any `vdims` by using the `scalars` argument. # In[5]: field.pyvista.scalar(scalars="x") # Alternatively, we can also create a scalar field using `discreitsedfield` syntax and plot that. # In[6]: field.pyvista.scalar() # To further modify the plot, keyword arguments for `pyvista.plotter.add_mesh` function are accepted. Please refer to its [documentation](https://docs.pyvista.org/version/stable/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html) # # Next, we can plot the vector field itself. # In[7]: field.pyvista.vector() # By cascading, we can plot its slice at $x=0$. # In[8]: field.orientation.sel(x=(0, 0)).pyvista.vector() # To improve the understanding of the plot, we can colour the vectors plotted. For that, we need to tell it according to which the vectors will be coloured. # In[9]: field.pyvista.vector(scalars="x") # We can also colour by any field by using the `color_field` argument # In[10]: field.pyvista.vector(color_field=field.x**2) # Plotting a scalar can also be done using `volume`. The density and color within the volume represent the scalar value at each point. # In[11]: field.pyvista.volume() # Isosurfaces of a scalar field can also be plotted using `contour` # In[12]: field.pyvista.contour() # `contour_scalars` can be used to select the dimension for which the isosurfaces are plotted. If `isosurfaces` controls the number of isosurfaces plotted. # In[13]: field.pyvista.contour(isosurfaces=4, contour_scalars="x") # If `isosurfaces` is an iterable, then an isosurface will be plotted at each specific value. # In[14]: field.pyvista.contour(isosurfaces=[-6e5, 0.0, 2e5], contour_scalars="x") # Streamlines can also be plotted. However, it is common for the default values not to produce desired plots as the optimal values of the arguments can very unique to the specific field being plotted. # In[15]: field.pyvista.streamlines() # ### Multiple visualisation on the same plot # # Sometimes, it is necessary to show, for example, multiple planes of the sample on the same plot. This can be done by exposing the `pyvista.Plotter` and passing it to different plotting methods. For instance. # In[16]: import pyvista plotter = pyvista.Plotter() field.pyvista.vector(plotter=plotter, scalars="y", cmap="hsv") field.pyvista.contour(plotter=plotter, isosurfaces=4, contour_scalars="x") plotter.show()