pencil.visu.pv_volume_plotter
pv_volume_plotter.py defines multiple different plotting routines for volume data from Pencil code VAR files. This includes methods such as:
- scalars — plots only scalar values on the plotter. Furthermore, scalars can
be just 2D surfaces, or a volume rendering (only in cartesian coordinates) or 3-orthogonal slices defined by the center of the 3 slices.
- vectors — Vectors can be overlayed on to the scalar data. Vectors can be either
constant in size or scaled by the magnitude of the vector field or the values on the scalar data.
- streamlines — Similarly to vectors, streamlines can be overlayed on to the scalar
data. The radius of the streamlines can be scaled e.g. by the cartesian norm of the vector field. In addition, a colormap can be applied on to the streamline tubes.
In addition, there are multiple source point sampling strategies for the vector field visualization methods (vectors|streamlines) such as: * random points in a volume * points on the surface of the volume, useful if streamlines are set to be
constrained on to the surface (by setting parameter surface_streamlines)
points on a plane that slices through the volume
points on 3-orthogonal planes that slice through the volume
- isosurfaces — Plots isosurfaces defined by its isovalues. These can be either
manually set or calculated automatically between the min max range of the supplied scalars. Furthermore, a moving isovalue gif can be generated that moves from first isovalue to last and back showing an moving representation of the isosurfaces.
For usage examples and tutorials, see Pyvista3DPlot docstring!
Requirements
sklearn
tqdm
numpy
pyvista (should be at least >= 0.31.3)
All of these can be installed by:
`
pip3 install <Library name>
`
Warning
I have experienced issues with volume rendering when using linux in VirtualBox due to missing 3D acceleration. HyperV seems to be able to access system hardware better and works on that. In my case I have a dedicated NVIDIA GPU - with different system hardware volume rendering might start throwing VTK warnings/errors and OpenGL related issues.
Notes
- Note! In order for streamlines_from_source() to work you need to update PyVista
to the latest version (at the moment 0.31.3)
Known Issues
- Interactive plotting windows have trouble closing sometimes - based on pyvista
Github this is a known issue in the VTK source.
Attributes
Classes
Class holding all plot customization parameters for the Pyvista3DPlot class. |
|
Implements 3D plotting routines from pencil var files. It is able to generate |
Functions
|
|
|
Module Contents
- pencil.visu.pv_volume_plotter.REASONS_FOR_TERMINATION
- pencil.visu.pv_volume_plotter.SAMPLING_METHODS = ['surface points', 'points', 'slice', 'slice orthogonal', 'default']
- pencil.visu.pv_volume_plotter.printTerminationReasons(arr, plotter, add_to_image=False)
- pencil.visu.pv_volume_plotter.meshSamplingMethods(method, mesh, surface_mesh, n_points=100, normal='x', origin=None, set_seed_1=False, alwaysReturnList=False, get_arrays=False)
- class pencil.visu.pv_volume_plotter.Plot3DSettings
Class holding all plot customization parameters for the Pyvista3DPlot class. NOTE! See Pyvista3DPlot docstrings for documentation on the parameter tests.
- Parameters:
title (str) – Title text to be added to the upper left corner. If set to ‘’ title is set automatically to contain some information, i.e. datadir, scalar key and vector keys. If you want title to be empty, set it to e.g. ‘ ‘
title_font_size (int) – Font size for the title text
n_points (int) – Total number of source points (vectors | streamlines)
set_seed_1 (bool) – If True, random seed is set to one, all sampled source points are the same
imageformat (str) – Any Python Pillow compatible image format, ‘png’, ‘jpeg’, etc.
off_screen (bool) – Plotting done on screen or off screen?
method (str) –
- Sampling method, how source points for vectors / streamlines are sampled:
- 1.’surface points’ — random sampled points from the surface of the
mesh
’points’ — random sampled points in the whole mesh
- ’slice’ — random sampled points on a slice defined by normal and
an origin
- ’slice_orthogonal’ — random sampled points on 3 orthogonal slices
defined by origin
- ’default’ — only to be used with streamlines, randomly samples
mesh in a sphere given radius.
show_axes (bool) – Show axes for the plot
show_grid (bool) – Shows a grid on the plotter.
scalars_norm (str) – Either ‘log’ or None
override_log (bool) – If False, and scalar_key contains ‘ln’ parameter scalars_norm is automatically set to None. Else if scalar_key does not contain ‘ln’, scalar_norm is set to ‘log’. If True, scalars_norm is kept to whatever user has set it to.
background_color (str or 3-tuple of ints) – Either a string e.g. ‘white’, ‘black’ or ‘gray’. Also can be a three int RGB tuple e.g (255, 255, 255)
Widgets
-------
add_volume_opacity_slider (bool) – Adds a slider widget controlling parameter volume_opacity. Only applies when mesh_type==”volume”, i.e. volume rendering enabled.
widget_type (type) –
Both of the available widget methods show an “arrow” that can be used to choose the angle of the sliced plane. Furthermore the plane itself can be moved up and down in the whole volume.
Available widget types are: 1) ‘clip slice’ — Only shows the current slice, noticeably faster than
clip box.
- ’clip box’ — Shows the current slice + the rest of the data “below”
the slice.
- ’plane vectors’ — Similar to ‘clip box’ except also vectors are added
on to the slice. The vectors can be controlled by changing Plot3DSettings vectors parameters.
’plane streamlines’ — same as plane vectors but with streamlines instead.
Camera
------
camera_centre (tuple of 3 floats) – Coordinates for the centre of the camera.
focal_point (tuple of 3 floats) – Coordinates for the camera focal point
view_up (tuple of 3 floats) – Vector defining up-direction of the camera. By default (0,0,1) i.e. “up” (z-direction).
zoom_factor (float) – Zoom multiplier added to the camera. Larger the value, the more it zooms in.
Streamlines
-----------
tube_radius (float) – Radius for stream tubes
show_source (bool) – Show source points for streamlines
surface_streamlines (bool) – If true streamlines are confined to a 2D surface
stream_params (dict) –
Any parameters pyvista streamlines_from_source() takes in OTHER THAN surface_streamlines and vectors. The following is the Pyvista’s own documentation on the pyvista.streamlines_from_source, see link for documentation after the list:
- integrator_type
The integrator type to be used for streamline generation. The default is Runge-Kutta45. The recognized solvers are: RUNGE_KUTTA2 (2), RUNGE_KUTTA4 (4), and RUNGE_KUTTA45 (45). Options are 2, 4, or 45. Default is 45.
- integration_direction
Specify whether the streamline is integrated in the upstream or downstream directions (or both). Options are ‘both’, ‘backward’, or ‘forward’.
- initial_step_length
Initial step size used for line integration, expressed in length unitsL or cell length units (see step_unit parameter). either the starting size for an adaptive integrator, e.g., RK45, or the constant / fixed size for non-adaptive ones, i.e., RK2 and RK4).
- step_unit
Uniform integration step unit. The valid unit is now limited to only LENGTH_UNIT (‘l’) and CELL_LENGTH_UNIT (‘cl’). Default is CELL_LENGTH_UNIT: ‘cl’.
- min_step_length
Minimum step size used for line integration, expressed in length or cell length units. Only valid for an adaptive integrator RK45.
- max_step_length
aximum step size used for line integration, expressed in length or cell length units. Only valid for an adaptive integrator RK45.
- max_steps
Maximum number of steps for integrating a streamline.
- terminal_speed
Terminal speed value, below which integration is terminated.
- max_error
Maximum error tolerated throughout streamline integration.
- max_time
Specify the maximum length of a streamline expressed in LENGTH_UNIT.
- compute_vorticity
Vorticity computation at streamline points (necessary for generating proper stream-ribbons using the vtkRibbonFilter.
- interpolator_type
Set the type of the velocity field interpolator to locate cells during streamline integration either by points or cells. The cell locator is more robust then the point locator. Options are ‘point’ or ‘cell’ (abbreviations of ‘p’ and ‘c’ are also supported).
- rotation_scale
This can be used to scale the rate with which the streamribbons twist. The default is 1
See https://docs.pyvista.org/core/filters.html?highlight=streamlines_from_source#pyvista.DataSetFilters.streamlines_from_source for more details on the parameters.
Note that if stream_params is None the following defaults are set: >>> self.stream_params = {
’max_steps’: 1000, ‘max_time’: 1e60, ‘terminal_speed’: 1e-60, ‘integration_direction’: ‘both’, ‘compute_vorticity’: False, ‘integrator_type’: 45,
}
are (The following parameters are used if method == 'default'. Then streamline source points)
source_center. (initialized from a sphere of radius source_radius and with center)
source_radius (float) – See description above. Radius for the sphere from which source points are sampled.
source_center (tuple) – Should be a tuple of 3 floats. Center for the sphere where source points are sampled from.
stream_variable_radius (str) – Enable variable radius on the streamlines. Name of the data array used to scale the radius, either ‘vector magnitude’, ‘scalars’ or None
stream_radius_factor (float) – Multiplicative factor for the stream variable tube radius scaling.
Vectors
-------
vector_scaling (str) –
- Scaling method for vectors, options:
None — no scaling
’scalars’ — scaled based on scalars no the mesh
’magnitude’ — scaled based on vector magnitude
vector_factor (float) – Multiplicative scaling for vectors
vector_max (float) – Maximum value for vector magnitude scaling. If None, set automatically to mean + one standard deviation
Mesh
----
show_mesh (bool) – Whether to show the mesh or not
mesh_type (str) – Rendering type for mesh, options: “volume”, “orthogonal slices” or “surface”
slice_pos (tuple) –
- Applies if mesh_type==’orthogonal slices’. 3-tuple of floats (x,y,z) where
x = The X location of the YZ slice
y = The Y location of the XZ slice
z = The Z location of the XY slice
volume_opacity (float) –
Value between [0,1]. 0 corresponds to “not see through” i.e. opacity=1 and 1 “see through” i.e. opacity=0. In reality it is not that straight forward since this is handled automatically by volume renderer.
What this parameter does is that pyvista.add_volume parameter unit_opacity_distance is set to value mesh.length * volume_opacity. See pyvista Documentation for more information on unit_opacity_distance. The default parameter 1/25 = 0.04 seems to work fairly well.
culling (str) – Does not render faces that are culled. Options are ‘front’ or ‘back’. This can be helpful for dense surface meshes, especially when edges are visible, but can cause flat meshes to be partially displayed. By default None, i.e. no culling applied.
Scalarbar (Vectors | Streamlines)
------------------
vertical_sbar (bool) – Scalarbar vertical or horizontal
cbar_width (float) – Width as a percentage, between 0 and 1
cbar_height (float) – Height as a percentage, between 0 and 1
cbar_title_font (int) – Title font size for scalarbar title.
cbar_label_font (int) – Label font size for scalarbar labels.
n_colors (int) – Number of colors for the colorbar.
_sbar_args (dict) – INTERNAL VALUE, SHOULD NOT BE USED
annotation_color (str) – Color for the annotations, i.e. scalarbar tick texts etc.
Scalarbar
---------------
scalar_sbar_title (str) – Title for the scalarbar for the mesh scalars.
show_mesh_sbar (bool) – Show scalarbar for the scalars on the mesh
mesh_opacity (float) – Opacity for the mesh
mesh_cmap (str) – matplotlib compatible colormap for the mesh
scalar_sbar_pos_x (float) – The percentage (0 to 1) along the window’s horizontal direction to place the bottom left corner of the colorbar. If None it is placed automatically.
scalar_sbar_pos_y (float) – The percentage (0 to 1) along the window’s vertical direction to place the bottom left corner of the colorbar. If None it is placed automatically.
Scalarbar
--------------------------------
field_sbar_title (str) – Title for the scalarbar for the mesh field (vectors|streamlines).
show_field_sbar (bool) – Show scalarbar for the vectors on the mesh (streamlines/vectors)
field_opacity (float) – Opacity for the plotted streamlines / vectors
field_cmap (str) – Colormap for the plotter streamlines / vectors
field_sbar_pos_x (float) – The percentage (0 to 1) along the window’s horizontal direction to place the bottom left corner of the colorbar. If None it is placed automatically.
field_sbar_pos_y (float) – The percentage (0 to 1) along the window’s vertical direction to place the bottom left corner of the colorbar. If None it is placed automatically.
gif (Orbit)
---------
orbital (Orbit gif creates a gif that circles around the plotted mesh. The)
have. (path is always 360 of how many points you)
orbit_gif (bool) – Whether to create an orbiting gif
orbit_points (int) – Number of points on the orbiting path
orbit_step (float) – Timestep between flying to each camera position
Slices
------
methods (This defines the parameters for the two slicing)
or (and 'slice'. Note that this only affects sampled source points for vectors)
streamlines.
normal (str) – tuple(float) or str. Length 3 tuple for the normal vector direction. Can also be specified as a string conventional direction as ‘x’ for (1,0,0) or ‘-x’ for (-1,0,0) etc.
origin (tuple) –
The center (x,y,z) coordinate of the plane on which the slice occurs. Note that if method == ‘slice orthogonal’ then we have that:
x corresponds to x location of the YZ slice
y corresponds to y location of the XZ slice
z corresponds to z location of the XY slice
- update(**kwargs)
For updating any key-value pair defined by the self.settings.
- class pencil.visu.pv_volume_plotter.Pyvista3DPlot(vector_key, scalar_key, datadir='./data', precision='f', magic='None', ivar=-1, coordinates='cartesian', outputdir=f'./stream_output', settings=Plot3DSettings(), debug=False, irange_x=None, irange_y=None, irange_z=None, range_x=None, range_y=None, range_z=None)
Implements 3D plotting routines from pencil var files. It is able to generate streamlines, vectors and isosurfaces. Optionally one can save the output as an image (any Python Pillow compatible image type) or as a gif that orbits (circles) around the plot.
Compatible coordinate systems are both cartesian and spherical coordinates. Note that there are multiple ways of sampling source points for the vector field (i.e. streamlines|vectors) and multiple ways of adding the scalars to the plot e.g. volume rendering (only cartesian supported), 3 orthogonal slices or surfaces.
Parameter tests
If at least one of the input settings is given as a dictionary parameter test will be enabled automatically. This enables one to input multiple values for settings in a list, and when running streamlines | vectors all these parameter combinations are tried automatically. This is implemented using
sklearn.ParameterGrid.Note that only methods streamlines() and vectors() support parameter tests.
This can be useful for finding good parameters from a large set of options.
- Log file is written containing an id and all settings matching to the outputted
pictures (id is added to the output image names too).
Interface
This class defines the following plotting utilities for the user:
- scalars — Adds just the scalar values to the visualization. Scalars can be added
as surfaces, volume rendering (only cartesian) and 3 orthogonal slices. This is defined by Plot3DSettings.mesh_type.
- streamlines — Adds streamlines to visualization. In addition scalars are added
to mesh in wanted way, i.e. volume rendering can be used in conjunction with streamlines.
- vectors — Adds vectors to visualization. Similarly to streamlines, scalars
can be added, e.g. as a volume rendering (only cartesian)
- contour — Adds isosurfaces to visualization. These can be either defined
manually or the number of isosurfaces can be set generating uniformly spaced isosurfaces between minimum and maximum value of scalars.
- movingIsovalue — Similar to contour except outputs a “moving” gif visualization
that loops from first isosurface to last and backwards.
Other utility functions:
- writeSettings — can be used to write the current Plot3DSettings to a json
file.
- loadSettings — can be used to load values for Plot3DSettings from a json
file.
- saveToVTK — saves the current mesh to a VTK file. This can be used later,
e.g. loaded in by PyVista.
- updateSettings — can be used to update one or multiple values of Plot3DSettings
without having to reinitialize the whole Pyvista3DPlot object.
- preview — Shows an interactive window that can be panned around showing
the camera parameters. This can be used to find good camera parameters.
Examples
Very simple usage example
Assuming your data is in ./data directory: >>> from pencil.visu.pv_volume_plotter import Pyvista3DPlot, Plot3DSettings >>> plotter = Pyvista3DPlot(vector_key=[‘ux’,’uy’,’uz’], scalar_key=’rho’,
outputdir=’./stream_output’, debug=True)
Then plot streamlines >>> plotter.streamlines()
This should show an interactive plotter window. If not parameter off_screen might be true. One way to change this is: >>> plotter.updateSettings(off_screen=False)
Now all plots should be done “on screen” that is interactively. When you are plotting surfaces, that is method=’surface’ it might be useful to turn mesh opacity to full 1.0. But then if you have for example streamlines inside the volume these are not visible? This can be fixed by setting parameter culling=’back’ from Plot3DSettings. This means that the front meshes in front of the camera are not rendered at all, only showing the back meshes.
How to do this? >>> plotter.updateSettings(culling=’back’, mesh_opacity=1.0) >>> plotter.streamlines()
VOLUME RENDERING SCALARS WITH STREAMLINES OR VECTORS.
This assumes your data is in cartesian coordinates. First create the settings object: >>> settings = {
‘off_screen’: False, # Plotting should be done on screen ‘method’: ‘points’, # Ensure streamline source points are taken from the whole volume ‘scalars_norm’: ‘log’, # This might be useful for the scalar data ‘stream_variable_radius’: ‘vector magnitude’, # Enable stream radius scaling ‘stream_radius_factor’: 4, # Might be necessary to add multiplicative factor if the radius
# doesnt show up (it is so small)
‘mesh_type’: ‘volume’, # Enable volume rendering #’volume_opacity’: 1/25, # Change this value if rendered volume is very faint
}
Now that we have settings in dictionary we can initialize the settings object: >>> settings = Plot3DSettings(**settings) >>> plotter = Pyvista3DPlot(vector_key=[‘ux’,’uy’,’uz’], scalar_key=’rho’,
outputdir=’./stream_output’, settings=settings, debug=True)
And finally create the streamlines + volume rendering of scalars >>> plotter.streamlines()
Furthermore you could try adding vectors instead of streamlines: >>> plotter.vectors()
If this looks bad, you need to tune the vector parameters, example: >>> plotter.updateSettings(vector_scaling=’magnitude’,
- vector_factor=1e-2, # Depending on data you need to adjust this smaller or larger
# in order to make all vectors smaller or larger
vector_max=13, # If the maximal length of vectors is way too large, tone this down )
Now try again: >>> plotter.vectors()
3) ISOSURFACES EXAMPLE: >>> plotter = Pyvista3DPlot(vector_key=[‘ux’,’uy’,’uz’], scalar_key=’rho’,
outputdir=’./stream_output’, debug=True)
>>> plotter.contour(isosurfaces=10)
Note, contour might sometimes print out warnings that isosurface has no points, this is most likely due to the isosurface value doesn’t correspond to any existing value in the dataset itself. Therefore, it might be more useful to specify manually the isovalues by setting the values parameter to some known values.
Notes on some missing functionality
- At the time of development pyvista.add_volume (volume rendering) method supported
only pyvista.UniformMesh which made it difficult if not impossible to add volume renderings of data in spherical coordinates.
Initialization for the Pyvista3DPlot object.
- param vector_key:
Keys defining the vector field. Either a single string e.g. ‘bb’ or a list of 3 strings e.g. [‘uu1’, ‘uu2’, ‘uu3’]. This is read from the var file.
- type vector_key:
str or list of strings
- param scalar_key:
Key defining the scalars in the volume. This is read from the var file.
- type scalar_key:
str
- param datadir:
Path to the data directory. By default ‘./data’
- type datadir:
str, optional
- param precision:
Precision for the pencil.read.var routine. By default ‘f’.
- type precision:
str, optional
- param magic:
Magic for the pencil.read.var routine. By default ‘bb’.
- type magic:
str, optional
- param ivar:
Index of the var file read. By default -1.
- type ivar:
int, optional
- param coordinates:
Either ‘cartesian’ or ‘spherical’. By default ‘cartesian’
- type coordinates:
str, optional
- param outputdir:
Path to the directory where the output is saved (images / gif). By default ‘./stream_output’
- type outputdir:
str, optional
- param settings:
Plot3DSettings object containing further settings for the plots. See source code for possible arguments, explanations and default values. By default Plot3DSettings().
- type settings:
Plot3DSettings, optional
- param debug:
Enable debug printing. By default False.
- type debug:
bool, optional
- datadir
- outputdir
- debug = False
- scalar_key
- vector_key
- var = False
- grid
- coordinates = 'cartesian'
- plotter = None
- mesh = None
- src = None
- id_counter = 0
- field = None
- surface_mesh
- writeSettings(filename)
Writes current Plot3DSettings to a json file for later use. These can be loaded in by using Pyvista3DPlot.loadSettings
Parameter
- filename: str
Name and path where settings are written to in json format. filename SHOULD CONTAIN THE SUFFIX .json
- saveToVTK(filename)
Saves the current mesh into a .vtk file. File is saved to outputdir and filename should not contain a suffix.
- loadSettings(settings)
Loads Plot3DSettings to the Pyvista3DPlotter object from the given json file.
- Parameters:
settings (str) – Path to json file containing the Plot3DSettings. This should be written by the method Pyvist3DPlot.writeSettings.
- updateSettings(**kwargs)
For updating any key-value pair in the dataclass Plot3DSettings. Multiple values can be passed at a time.
Example usage: >>> plotter = Pyvista3DPlot() >>> plotter.updateSettings(n_points=1, mesh_cmap=’bwr’)
- streamlines()
Add streamlines to plotter.
Note that this can be used in conjunction with different source point methods defined in Plot3DSettings.method and also the scalars can be added to the vectors in different ways defined by Plot3DSettings.mesh_type (e.g. just surfaces or volume rendering etc.)
streamlines support parameter tests, see docstring of Pyvista3DPlot for explanation.
- vectors()
Add vectors to plotter.
Note that this can be used in conjunction with different source point methods defined in Plot3DSettings.method and also the scalars can be added to the vectors in different ways defined by Plot3DSettings.mesh_type (e.g. just surfaces or volume rendering etc.)
streamlines support parameter tests, see docstring of Pyvista3DPlot for explanation.
- contour(values=None, isosurfaces=3, filename=f'contour_{int(time.time())}', cmap=None, use_vector_magnitude_as_scalars=False)
Similar to movingIsovalue() except an image is saved. Can be used to add or multiple isosurfaces to the image. Opens by default an interactive window in which camera angle can be adjusted, after which an image is saved.
- values: list of floats
Specific values for the isosurfaces. Each isosurface generated corresponds to a value given in this list. If None, automatically generates isosurfaces number of isosurfaces between [scalars.min, scalars.max]
- isosurfaces: int
Number of isosurfaces to be generated between scalars minimum and maximum. This applies if parameter values=None. Values for the isosurfaces are evenly spaced between the interval.
- filename: str
Output filename, should not contain the image format, it is added automatically based on the given Plot3DSettings.imageformat.
- cmap: str
Matplotlib compatible colormap
- use_vector_magnitude_as_scalars: bool
If true, calculates cartesian norm of the current vector field and uses that as the scalars.
- scalars()
Plot only the scalar values on to the plotter.
- movingIsovalue(values=None, filename=f'moving_isovalue_{time.time()}.gif', isosurfaces=30, show_outline=True, show_mesh_outline=True, cmap=None, use_vector_magnitude_as_scalars=False)
Creates a moving isovalue gif that cycles showing the isovalues from first to last and back making a “moving plot”. The isovalues itself can be defined, otherwise an isovalue range is created by default of isosurfaces amount of isosurfaces between minimum and maximum of scalars.
- values: list of floats
Specific values for the isosurfaces. Each isosurface generated corresponds to a value given in this list. If None, automatically generates isosurfaces number of isosurfaces between [scalars.min, scalars.max]
- filename: str
Output filename for the gif. Defaults to ‘moving_isovalue_<timestamp>.gif’
- isosurfaces: int
Number of isosurfaces to be generated between scalars minimum and maximum. This applies if parameter values=None. Values for the isosurfaces are evenly spaced between the interval.
- show_outline: bool
Shows an outline box in which the mesh is contained in.
- show_mesh_outline: bool
TODO!
- cmap: str
Matplotlib compatible colormap
- use_vector_magnitude_as_scalars: bool
If true, calculates cartesian norm of the current vector field and uses that as the scalars.
- preview()
!TODO!