pencil.visu.pv_plotter

These are generic requirements for all PyVista plotter tools including pv_plotter.py, pv_volume_plotter.py and pv_plotter_utils.py.

  • pyvista

    -> latest version (version >= 0.31.3) otherwise there might be issues with the pyvista.streamlines_from_source() function

  • imageio-ffmpeg

  • tqdm

  • numpy

  • sklearn — necessary for pv_volume_plotter.py parameter tests.

All of these can be installed by: ` pip3 install <Library name> `

All pyvista plotting tools are tested to work with versions: VTK==9.0.3 and pyvista==0.31.3.

Furthermore, in order to save videos, PyVista requires imageio-ffmpeg. Note that saving only images is faster and should be used instead in combination with e.g. imagemagick on command line. If using progress_bar parameter, tqdm is needed.

Pyvista plot generation does not work on CSC Puhti without loading the module mesa-settings.

General

This file defines a routine for generating 3D visualisation from video slices. It is able to generate both images (e.g. png) and videos (mp4/gif). This uses PyVista in order to generate plots in cartesian | spherical | cylindrical coordinates.

User should call the function plot() to generate the visualizations. See documentation of plot() for further usage examples and parameters.

Plot availability for each coordinate system

Plot type | Cartesian | Spherical | Cylinder |

|-----------------------|———–|-----------|———-| | Scalars | X | X | X | | + surface vectors | X | X | - | | + surface streamlines | X | X | - |

Things to note

STREAMLINES: increasing number of source points, steps in integration or even field itself can have a large effect on the used memory / time that takes to create one frame.

Attributes

XYZPLANE_KEYS

CONSTANT_SEED

Classes

PlotSettings

Defines all possible settings and defaults for all plots. Defining

Functions

plot([debug, settings])

Create plot from slice data in cartesian | spherical | cylindrical

Module Contents

pencil.visu.pv_plotter.XYZPLANE_KEYS = ['xy', 'xy2', 'xz', 'yz']
pencil.visu.pv_plotter.CONSTANT_SEED
class pencil.visu.pv_plotter.PlotSettings

Defines all possible settings and defaults for all plots. Defining this as a class has the advantage of keeping all default and parameter settings in one maintainable place and removes the hassle of e.g. using kwargs.

Quick Tutorial

Class PlotSettings() defines all possible settings in addition to the parameters function plot() takes in. For further information about all the possible parameters, see documentation of PlotSettings.

The class can be initialized in at least three ways:

1. Pass in the parameters: >>> settings = PlotSettings(off_screen=True, preview=False, …)

2. Define a dictionary and pass that in using asterisk notation: >>> params = {

‘off_screen’: True, ‘preview’: False, …

} >>> settings = PlotSettings(**params)

3. Initialize class and change the values in more ‘object-oriented’ way: >>> settings = PlotSettings() >>> settings.off_screen = True >>> settings.preview = False

GENERAL PARAMETERS

off_screen: bool

Whether plotting should be done on screen or off screen

preview: bool

Interactive preview, specific slice can be set by islice parameter in plot()

window_size: tuple

should be multiple of macro_block_size=16 for imageio-ffmpeg

progress_bar: bool

Enable tqdm progress bar

videoformat: str

Options: None | ‘mp4’ | ‘gif’

imageformat: str

Options: None | ‘png’ | ‘jpeg’ | etc., any Pillow compatible imageformat

framerate: int

Movie framerate. Does not affect gif.

figdir: str

Path to save images

moviedir: str

Path to save movies

bg_color: str or 3 item list

Background color. Either string or 3 tuple in RGB format.

timestamp: bool

Add timestamp to saved output filename.

PLOT PARAMETERS

norm: str

Normalization applied. Options: ‘linear’ | ‘log’

coordinates: str

Options: ‘cartesian’ | ‘spherical’ | ‘cylinder’

opacities: dict

Opacities per slice. Should be dict with keys ‘xy’, ‘xy2’, ‘yz’ and ‘xz’.

COORDINATE SPECIFIC PARAMETERS

offset: float

Offset for the bottom slice. Z-coordinate of the bottom mesh is set to -zn / offset, where zn is the number of points in z-direction.

spherical_xz_pos: float

Options: None | -1 | <angle in radians>. Position for xz slice in spherical coordinates. If None, position inferred from slice data. If -1, slice set to close the gap between meridional slices in one end.

VECTOR PLOT PARAMS

n_vectors: int
Depending on chosen vector_method:
  1. method==’every_nth’: Plot only every n_vectors vectors

  2. method==’random’: Plot a total of n_vectors, source point chosen

    randomly

vector_size: float

Affects the size of plotted vectors.

vector_method: str
Options:
  1. ‘random’ = random sampled points

  2. ‘every_nth’ = plot every nth vector (defined by n_vectors)

vector_scaling: str
Scaling of vectors. Options:
  1. None, no scaling applied

2. ‘magnitude’, vectors scaled by their magnitude (to max size defined vector_max) 3. ‘scalars’, vectors scaled based on the scalar data on the surface.

vector_max: float

Maximum value for vector size. Useful, e.g. if vectors scaled by their magnitude that they’re not arbitrarily large.

surface_vectors: bool

If True, always one vector component set to zero (depending on which mesh were on). If False, the plotted vectors have also their 3rd component, i.e. not constrained on to the 2D surface.

STREAMLINE PARAMS

streamlines: bool

Enable streamlines. If False, and vectors are supplied vectors are plotted instead.

stream_tube_radius: float

Radius for the streamline tubes.

stream_variable_radius: str

Enable scaling of stream tube radius. Input should be name of the scalar array used for scaling. Available arrays include ‘Magnitude’ and ‘scalars’. If None, streamline tube radius stays constant

Extra: PyVista includes some internal scalar arrays if stream_params has ‘compute_vorticity’=True. This includes e.g. ‘Vorticity’ array. The names of these are the easiest found by modifying __addSurfaceStreamlines function, see output of: print(stream.point_arrays) for available arrays.

stream_radius_factor: float

Maximal radius of stream tube as a multiple of stream_tube_radius.

stream_src_points: int or dict

Number of source points given either as an integer (all meshes have same number of src points) or as a dictionary containing keys ‘xy’, ‘xy2’, ‘xz’ and ‘yz’ defining number of source points for each mesh.

stream_show_source: bool

Show source points as spheres in the plot.

stream_log_scale: bool

Enables pyvista.add_mesh log_scale, i.e. applies logarithm for the values to be added to the colorbar.

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,

}

RANDOM SAMPLING PARAMS

set_seed_1: bool

For debugging, always sets random seed to 1, thus all sampled points are the same. Makes comparing streamlines easier for debugging

constant_seed: bool

Sets random seed once in the beginning and resets the random generator always with this seed. This has the consequence of randomizing initial points, keeping them constant, e.g. throught the movie. Makes streamlines jump less around the meshes.

CAMERA PARAMS

camera_centre: tuple of floats

Coordinates for camera centre in form (x, y, z).

focal_point: tuple of floats

Focal point for the camera in form (x, y, z).

AXES PARAMS

show_axes: bool

Show axes or not.

axes_labels: tuple of str

Labels for the axes. Should be tuple of length 3 containing strings.

axes_font: int

Font for the axes labels

COLORBAR PROPERTIES: field specific (vectors | streamlines)

show_field_sbar: bool

Show scalarbar for vectors / streamlines

field_cmap: str

Matplotlib compatible colormap for vectors / streamlines

field_sbar_title: str

Title for fields scalarbar.

pos_x and pos_y are given as a float between 0 and 1 (percentage). That is it defines the distance from leftmost edge (pos_x) and bottom most edge (pos_y). E.g. pos_x = 0 would mean colorbar is set at the very leftmost edge. NOTE! if both None, colorbars set automatically, also works for multiple colorbars set nicely next to each other.

field_sbar_pos_x: float

If None set automatically. Else float in range [0,1]. Note, 0.03 is pretty good value (fairly close to left edge)

field_sbar_pos_y: float

None or float between [0,1]. None works well

COLORBAR PROPERTIES: scalar specific

show_scalar_sbar: bool

Show scalarbar for scalars

scalar_cmap: str

Matplotlib compatible colormap for scalars.

scalar_sbar_title: str

Title for scalar scalarbar.

scalar_sbar_pos_x: float

None or float between [0,1]. Note, 0.88 is pretty good value (enough close to right edge). See notes above for detailed explanation of pos_x

scalar_sbar_pos_y: float

None or float between [0,1]. Note, None works well. See notes above for detailed explanation of pos_y

COLORBAR PROPERTIES: Generic properties

Following parameters apply both to field and scalar colorbars.

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

cbar_label_font: int

Label font size for scalarbar

n_colors: int

Number of colors for the scalarbar.

_sbar_args: dict

INTERNAL VALUE. SHOULD NOT BE USED.

TITLE ANNOTATIONS

title_position: str

Options: ‘lower_left’, ‘lower_right’, ‘upper_left’, ‘upper_right’, ‘lower_edge’, ‘upper_edge’, ‘right_edge’, and ‘left_edge’.

title_font: int

Font size for the title.

str_unit: str

Unit added behind the timestamp in the title. I.e. title is form ‘<current time step><str_unit>’

tscale: float

Multiplicative scaling for the timestamp in title.

time_precision: int

Number of decimals shown for the timestamp.

off_screen: bool = True
preview: bool = False
window_size: tuple = (1024, 768)
progress_bar: bool = True
videoformat: str = None
imageformat: str = 'png'
framerate: int = 15
figdir: str = './images/'
moviedir: str = './movies/'
bg_color: str = 'white'
timestamp: bool = True
norm: str = 'linear'
coordinates: str = 'cartesian'
opacities: dict = None
offset: float = 2.0
spherical_xz_pos: float = -1
n_vectors: int = 500
vector_size: float = 7
vector_method: str = 'random'
vector_scaling: str = 'magnitude'
vector_max: float = None
surface_vectors: bool = True
streamlines: bool = False
stream_tube_radius: float = 0.05
stream_variable_radius: str = 'Magnitude'
stream_radius_factor: float = 10
stream_src_points: int = 50
stream_show_source: bool = False
stream_log_scale: bool = False
stream_params: dict = None
set_seed_1: bool = False
constant_seed: bool = False
camera_centre: tuple = None
focal_point: tuple = None
show_axes: bool = True
axes_labels: tuple = ('x', 'y', 'z')
axes_font: int = 16
show_field_sbar: bool = True
field_cmap: str = 'bwr'
field_sbar_title: str = ''
field_sbar_pos_x: float = None
field_sbar_pos_y: float = None
show_scalar_sbar: bool = True
scalar_cmap: str = 'bwr'
scalar_sbar_title: str = ''
scalar_sbar_pos_x: float = None
scalar_sbar_pos_y: float = None
cbar_width: float = 0.06
cbar_height: float = 0.65
cbar_title_font: int = 10
cbar_label_font: int = 8
n_colors: int = 256
title_position: str = 'upper_left'
title_font: int = 20
str_unit: str = ''
tscale: float = 1
time_precision: int = 3
pencil.visu.pv_plotter.plot(slice_obj=None, datadir='./data', precision='f', fields=['uu1'], xyzplane={'xy2': 'xy2', 'xy': 'xy', 'yz': 'yz', 'xz': 'xz'}, vectors=None, tstart=0.0, tend=1e+38, islice=-1, istart=None, iend=None, color_range=None, color_levels=None, unit='unit_velocity', rescale=1.0, par=list(), debug=True, settings=PlotSettings()) None

Create plot from slice data in cartesian | spherical | cylindrical coordinates and saves the output as images and / or videos. Creates plots for times [tstart, tend] of all the fields specified in fields argument. Internally calls __plot_field() to handle plotting of a given field over all time instants. By default this function creates images off screen without creating interactive plot window. If plotting done on screen (i.e. off_screen=False) and creating a video, one can see the video live and the video angle can be rotated, also affecting the output video.

In case of fine tuning the plot parameters, e.g. camera position / focal point, one can turn preview on (in settings) to see an interactive plot window that can be rotated around and outputs the camera parameters on both command line and the plot window.

Parameters:
  • slice_obj (pencil.read.allslices.SliceSeries, optional) – Pencil slice data, if supplied no slice data is read. If None, slice data is automatically read from datadir. Default: None.

  • datadir (str, optional) – Directory of the data. Default: ‘./data’.

  • precision (str, optional) – Precision for the data read, parameter e.g. pencil.read.slices() takes in. Can be ‘half’, ‘f’ or ‘d’. Default: ‘f’.

  • fields (list of strings, optional) – Fields that are plotted. Default: [‘uu1’,].

  • xyzplane (dictionary, optional) – Dictionary having allowed keys defined by XYZPLANE_KEYS. Values should be the matching data that is plotted on each of these surfaces. See “Coordinate systems” below.

  • vectors (list, optional) – List of 3 strings defining the vector components of the vector field. This is used to create streamlines / vectors.

  • tstart (float, optional) – Start time instant. See parameter islice for more details. Default: 0.

  • tend (float, optional) – End time instant. See parameter islice for more details. Default: 1e38

  • islice (int, optional) – Sequential integer number of a slice in given period (starting from 0). If set to -1, generates all slices in given period [tstart, tend]. Else generates only visualisations of the given slice number islice. Default: -1.

  • istart (int, optional) – First index to start plotting from. This index corresponds to time instant slice_obj.t[istart]. istart is used if it is not None, otherwise tstart is used.

  • iend (int, optional) – Similar to istart, end time index corresponding to time slice_obj.t[iend]

  • color_range (list of 2, optional) – If supplied, list containing [cmin,cmax] for the colorbar.

  • color_levels (string, optional) – If set to ‘common’, then all times and fields have same colorbar min and max values. Default: None.

  • unit (string, optional) – Unit (string) appended to the end of the timestamp in the title.

  • rescale (int, optional) – TODO!

  • par (list, optional) – TODO!

  • debug (boolean, optional) – Enable debugging prints. Default: False.

  • **settings (optional) – Dictionary of possible settings for the plot. See docstring at the start of this file for an ready dictionary input of all possible parameters settings could take in.

  • systems (Coordinate)

  • ------------------

  • ['xy' (Allowed keys for xyzplane are defined by XYZPLANE_KEYS =)

  • 'xy2'

  • 'xz'

  • 'yz'].

  • system (In case of each coordinate)

  • to (these surfaces correspond)

  • Cartesian (-) –

    • xy = bottom

    • xy2 = top

    • xz = right vertical slice

    • yz = left verical slice

  • Spherical (-) –

    • xy = r-theta slice, 1st meridional slice

    • xy2 = r-theta slice, 2nd meridional slice

    • xz = r-phi slice, “plane slice” between meridionals and yz

    • yz = theta-phi slice, spherical surface at the back (or part of it)

  • Cylinder (-) –

    • xy = r-theta slice, bottom of the cylinder (circle)

    • xy2 = r-theta slice 2, top of the cylinder (circle)

    • xz = r-z slice, “radial cut”, rectangle between top/bottom

    • yz = theta-z slice, shell of the cylinder (or part of it)

Examples

Minimal usage example, this saves by default ‘png’ images at all timesteps of field ‘uu1’ to figure directory ./images (creating the directory if it does not exist). Debug should be left on so one can see that the script runs properly. By default this creates a cartesian plot (i.e. box plot).

>>> from pencil.visu.pv_plotter import plot, PlotSettings
>>> plot(debug=True)

This plotter uses a settings object (dataclass) PlotSettings that contains all possible extra settings that can be varied. See documentation on PlotSettings for further information on all of the parameters. This can be used in the following way:

>>> settings = {
            'imageformat': None,
            'videoformat': 'mp4',
            'coordinates': 'cartesian'
            'cbar_title': 'TITLE',
            'n_colors': 100,
            'camera_centre': (-170, -140, 125),
            'focal_point': (30, 30, 16),
            'offset': 2.5
            }
>>> settings = PlotSettings(**settings)
>>> plot(debug=True settings=settings)

Furthermore, 2D slices to be plotted can be modified by passing in xyzplane parameter

>>> xyzplane = {'xy2': 'xy2','xy': 'xy', 'xz': 'xz', 'yz': 'yz'}

where the string values represent the slices to be plotted on the meshes (see “Coordinate systems” for what which mesh each key corresponds given coordinate system). These values should be found in slices.__dict__.keys().

Notes

  • NOTE! The default camera angle is most likely horrible and may not even show

the data at all. This should be manually modified and e.g. easily found using preview=True that shows an interactive plot window that can be rotated around and print out the camera parameters at the same time. - NOTE! On CSC computers module ‘mesa-settings’ needs to be loaded (works at least on Puhti).