Field visualisation using k3d
#
Note: If you experience any problems in plotting with k3d
, please make sure you run the Jupyter notebook in Google Chrome.
There are several ways how a field can be visualised, using:
matplotlib
-k3d
holoviews
vtk-based libraries, e.g.
pyvista
k3d
provides three-dimensional interactive plots of fields inside Jupyter notebook.
Let us say we have a sample, which is an ellipsoid
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.
[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)
The most basic plot we can show is the plot of all the cells where the value is non-zero. This can be useful, to inspect the domain created, by plotting the norm.
[2]:
field.norm.k3d.nonzero()
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.
[3]:
field.norm.k3d.nonzero(color=0x27AE60)
Next, we can plot a scalar field. For plotting a scalar field, we are using discretisedfield.Field.k3d.scalar()
method.
[4]:
field.k3d.scalar()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[4], line 1
----> 1 field.k3d.scalar()
File ~/repos/ubermag-devtools/repos/discretisedfield/discretisedfield/plotting/k3d_field.py:248, in K3dField.scalar(self, plot, filter_field, cmap, multiplier, interactive_field, **kwargs)
246 if self.data.nvdim != 1:
247 msg = f"Cannot plot nvdim={self.data.nvdim} field."
--> 248 raise ValueError(msg)
250 if plot is None:
251 plot = k3d.plot()
ValueError: Cannot plot nvdim=3 field.
An exception was raised because we attempted to plot a vector field using voxels. Therefore, we first need to extract a component of the field. Let us plot the \(x\) component.
[5]:
field.x.k3d.scalar()
However, we can see that the points which we consider to be outside the sample are also plotted. This is because, discretisedfield.Field.k3d.scalar()
method cannot determine the points where norm is zero from the passed scalar field. Therefore, we need to pass field.norm
as the filter_field.
[6]:
field.x.k3d.scalar(filter_field=field.norm, multiplier=1e-6)
By cascading operations, we can similarly plot the slice of the ellipsoid at \(z=0\).
[7]:
field.sel(x=(0, 0)).orientation.z.k3d.scalar()
To further modify the plot, keyword arguments for k3d.factory.voxels()
function are accepted. Please refer to its documentation
Next, we can plot the vector field itself.
[8]:
field.k3d.vector()
By default, points at the discretisation cell centres are plotted together with vectors to help understand the structure of the field. However, they can be deactivated by passing points=False
.
[9]:
field.k3d.vector(points=False)
It is difficult to understand the vector field from this plot. By cascading, we can plot its slice at \(x=0\).
[10]:
field.orientation.sel(x=(0, 0)).k3d.vector()
To improve the understanding of the plot, we can now colour the vectors plotted. For that, we need to pass a scalar field, according to which the vectors will be coloured.
[11]:
field.orientation.sel(x=(0, 0)).k3d.vector(color_field=field.x)
To further modify the plot, keyword arguments for k3d.factory.vectors()
function are accepted. Plese refer to its documentation.
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 k3d.plot
and passing it to different plotting methods. For instance.
[12]:
import k3d
plot = k3d.plot()
field.sel(x=(-3e-9, -3e-9)).k3d.vector(plot=plot, color_field=field.z)
field.sel(x=(0, 0)).k3d.vector(plot=plot, color_field=field.z, cmap="hsv")
field.sel(x=(3e-9, 3e-9)).k3d.vector(plot=plot, color_field=field.z)
plot.display()
k3d
interactive plots#
[13]:
field.sel(z=(0, 0)).z.k3d.scalar(filter_field=field.norm)
[14]:
import k3d
plot1 = k3d.plot()
@df.interact(z=field.mesh.slider("z", continuous_update=True))
def myplot(z):
field.z.sel(z=(z, z)).k3d.scalar(
filter_field=field.norm, interactive_field=field, plot=plot1
)
plot1.display()
[15]:
plot = k3d.plot()
@df.interact(
z=field.mesh.slider("z", continuous_update=True), axis=field.mesh.axis_selector()
)
def myplot(z, axis):
getattr(field, axis).sel(z=(z, z)).k3d.scalar(
filter_field=field.norm, interactive_field=field, plot=plot
)
plot.display()
[16]:
plot = k3d.plot()
@df.interact(
y=field.mesh.slider("y", continuous_update=True), axis=field.mesh.axis_selector()
)
def myplot(y, axis):
field.sel(y=(y, y)).k3d.vector(
color_field=getattr(field, axis), interactive_field=field, plot=plot
)
plot.display()