Holoviews usage#
Good resource: https://holoviews.org/getting_started/Gridded_Datasets.html
Doing n-dimensional plots with traditional plotting libraries can be tedious. Holoviews
is a library designed for creating multidimensional (especially useful for > 2) plots easily. It is very well suited if you want to explore your data interactively. As we will see, converting xarray
objects (the most common type of output in postopus) to holoviews
objects is trivial. The customization level of a holoviews
plot is very high, because it supports multiple backends, here we will
cover matplotlib
and bokeh
(the default backend).
[1]:
import numpy as np
from matplotlib import pyplot as plt
from postopus.octopus_run import Run
from pathlib import Path
%config InlineBackend.figure_formats = ['svg']
input file is already defined in the folder (s. GitLab repo), otherwise we recommend defining it in the notebook
[2]:
cd ../octopus_data/benzene/
/builds/lang-m/postopus/docs/octopus_data/benzene
Assuming you have octopus in your PATH:
[3]:
!octopus > out_gs.log 2>&1
[4]:
run = Run(".")
[5]:
xa = run.default.scf.density(source="cube").isel(step=-1) # postopus XArray
xa
[5]:
<xarray.DataArray 'density' (x: 47, y: 49, z: 33)> Size: 608kB [75999 values with dtype=float64] Coordinates: step int64 8B 16 * x (x) float64 376B -13.04 -12.47 -11.91 -11.34 ... 11.91 12.47 13.04 * y (y) float64 392B -13.61 -13.04 -12.47 -11.91 ... 12.47 13.04 13.61 * z (z) float64 264B -9.071 -8.504 -7.937 -7.37 ... 7.937 8.504 9.071 Attributes: units: au
Importing holoviews#
[6]:
import holoviews as hv
from holoviews import opts # For setting defaults
hv.extension("bokeh", "matplotlib") # Allow for interactive plots
In the following, we are going to convert an xarray
to a holoviews Dataset
and then to a holoviews Image
. Actually, holoviews Images
are used for 2D plots. Since we have 3D data, it will be converted to a Holomap
of Images
. (If we would want to plot for example 1D data, instead of holoviews Images
, we would use holoviews Curve
s. The code would be analogous.) This image allows you to slide across time and space and visualize the resulting structure. (If you want
to move step-by-step, just select a dimension and use the left and right arrows to navigate). We can use the kdims
argument to specify which coordinates will serve as the visible axes on the plots (in this example we will choose x
and y
). The ones that are left will be controlled by a slider (in this example t
and step
will get a slider and a dropdown). When building the image, the default behavior of holoviews
is to preload the whole data at once with javascript. The
loading of the image can be very slow, especially if the amount of data is high. Don’t worry, we’ll learn how to make it faster!
Generating a holoviews Dataset#
[7]:
hv_ds = hv.Dataset(xa)
Generating a holoviews Image#
[8]:
hv_im = hv_ds.to(hv.Image, kdims=["x", "y"])
The following two plots will be slowish.
[9]:
hv_im
[9]:
[10]:
type(hv_im)
[10]:
holoviews.core.spaces.HoloMap
[11]:
hv_im.data # one can see here that each of the samples within the Holomap is an Image
[11]:
{(np.float64(-9.070685),): :Image [x,y] (density),
(np.float64(-8.503767),): :Image [x,y] (density),
(np.float64(-7.936848999999999),): :Image [x,y] (density),
(np.float64(-7.369930999999999),): :Image [x,y] (density),
(np.float64(-6.803012999999999),): :Image [x,y] (density),
(np.float64(-6.236094999999999),): :Image [x,y] (density),
(np.float64(-5.6691769999999995),): :Image [x,y] (density),
(np.float64(-5.102258999999999),): :Image [x,y] (density),
(np.float64(-4.535340999999999),): :Image [x,y] (density),
(np.float64(-3.9684229999999987),): :Image [x,y] (density),
(np.float64(-3.4015049999999984),): :Image [x,y] (density),
(np.float64(-2.834586999999999),): :Image [x,y] (density),
(np.float64(-2.267668999999999),): :Image [x,y] (density),
(np.float64(-1.7007509999999986),): :Image [x,y] (density),
(np.float64(-1.1338329999999992),): :Image [x,y] (density),
(np.float64(-0.5669149999999981),): :Image [x,y] (density),
(np.float64(3.0000000013075123e-06),): :Image [x,y] (density),
(np.float64(0.5669210000000007),): :Image [x,y] (density),
(np.float64(1.1338390000000018),): :Image [x,y] (density),
(np.float64(1.7007570000000012),): :Image [x,y] (density),
(np.float64(2.2676750000000023),): :Image [x,y] (density),
(np.float64(2.8345930000000017),): :Image [x,y] (density),
(np.float64(3.401511000000001),): :Image [x,y] (density),
(np.float64(3.968429000000002),): :Image [x,y] (density),
(np.float64(4.535347000000002),): :Image [x,y] (density),
(np.float64(5.102265000000001),): :Image [x,y] (density),
(np.float64(5.669183000000002),): :Image [x,y] (density),
(np.float64(6.2361010000000014),): :Image [x,y] (density),
(np.float64(6.803019000000001),): :Image [x,y] (density),
(np.float64(7.369937000000002),): :Image [x,y] (density),
(np.float64(7.936855000000003),): :Image [x,y] (density),
(np.float64(8.503773),): :Image [x,y] (density),
(np.float64(9.070691000000002),): :Image [x,y] (density)}
Customizing plot parameters with opts
#
[12]:
# Sets defaults for all the interactive images in this notebook
# Warning: Currently, there is no way to reset the default settings:
# https://stackoverflow.com/questions/68748393/how-do-i-clear-all-custom-opts-that-ive-set-for-holoviews.
# The only method that works is restarting the kernel, so think about setting anything to default.
opts.defaults(
opts.Image(cmap="viridis", width=400, height=400),
)
# <hv object>.opts.clear() / <hv object>.opts(clone=False) to rollback to default settings if desired,
# from https://holoviews.org/user_guide/Applying_Customizations.html.
[13]:
hv_im.opts(opts.Image(title="title")) # Sets specific opts for a single plot
[13]:
[14]:
# hv.help(hv.Image) # Lists all the tunable parameters, for the active backend
# hv.help(hv_im) # Lists the actual configuration of a specific object
Time dependent plots#
Methane example#
To fasten up the loading process we can make use of the parameter dynamic=True
. When this parameter is set as True
, the frames will be loaded one by one, on-demand. (This means that in the background the Dataset
will be converted into a DynamicMap
instead of a Holomap
). Note: if the style of the plotting is not the one that you expected, rerun the cell. The dynamic plots will always take the last used plotting settings, independently of what was declared in the cell. Second
note: The dynamic plots cannot be rendered in HTML. If you are viewing this from your webbrowser, you will just see GIFs that should emulate the real plot. If you happen to be in an active notebook session, you can play with them interactively!
[15]:
cd ../methane
/builds/lang-m/postopus/docs/octopus_data/methane
[16]:
!octopus > out_gs.log 2>&1
[17]:
run = Run(".")
[18]:
xat = run.default.scf.density(source="vtk") # XArray Time-dependent
[19]:
hv_dst = hv.Dataset(xat) # convert to holoviews Dataset
hv_imt = hv_dst.to(hv.Image) # convert to holoviews Image
hv.output(
max_frames=10000
) # sets the max number of frames that we can have in a slider-plot
[20]:
# hv_imt # Would be very slow! Minutes long!
[21]:
hv_dst = hv.Dataset(xat)
hv_imt = hv_dst.to(hv.Image, kdims=["x", "y"], dynamic=True)
hv.output(max_frames=10000)
[22]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt # fast!
[22]:
[23]:
type(hv_imt)
[23]:
holoviews.core.spaces.DynamicMap
[24]:
hv_imt.data # the number of images saved in cache will update if you scroll the plot. The default cache_size is 500
[24]:
{(np.int64(1), np.float64(-7.36993)): :Image [x,y] (density)}
[25]:
hv_imt.cache_size
[25]:
500
Histogram of the data#
[26]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt.hist(num_bins=100, log=True).opts(
opts.Image(
colorbar=True, # we set the opts for each hv object independently
clabel=f"{xat.name} ({xat.units})",
), # holoviews doesn't support the labeling of the cmap out of the box
opts.Histogram(xlim=(0, 0.5), ylim=(0, 50)),
) # use base 10 logarithmic samples for the bin edges (width)
[26]:
[27]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt.hist(num_bins=100).opts(
opts.Image(colorbar=True, clabel=f"{xat.name} ({xat.units})"),
opts.Histogram(xlim=(0, 0.5), ylim=(0, 50)),
) # comparison without log
[27]:
Swapping kdims#
[28]:
hv_imt_step_z = hv_dst.to(hv.Image, kdims=["step", "z"], dynamic=True)
[29]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt_step_z
[29]:
Interference z=0 (slice)#
http://holoviews.org/user_guide/Styling_Plots.html https://holoviews.org/user_guide/Colormaps.html might come handy for customizing plots
[30]:
cd ../interference/
/builds/lang-m/postopus/docs/octopus_data/interference
[31]:
!octopus > out_td.log 2>&1
[32]:
run = Run(".")
[33]:
xa = run.Maxwell.td.b_field(source="z=0")
[34]:
hv_dst = hv.Dataset(xa.vx)
hv_imt = hv_dst.to(hv.Image, ["x", "y"]) # needed for generating output files
hv_imt_dynamic = hv_dst.to(hv.Image, ["x", "y"], dynamic=True)
hv.output(max_frames=3000)
Custom plotting options#
[35]:
xa
[35]:
<xarray.Dataset> Size: 687kB Dimensions: (t: 17, x: 41, y: 41) Coordinates: step (t) int64 136B 0 10 20 30 40 50 60 ... 100 110 120 130 140 150 160 * t (t) float64 136B 0.0 0.02107 0.04213 0.0632 ... 0.2949 0.316 0.337 * x (x) float64 328B -10.0 -9.5 -9.0 -8.5 -8.0 ... 8.0 8.5 9.0 9.5 10.0 * y (y) float64 328B -10.0 -9.5 -9.0 -8.5 -8.0 ... 8.0 8.5 9.0 9.5 10.0 Data variables: vx (t, x, y) float64 229kB ... vy (t, x, y) float64 229kB ... vz (t, x, y) float64 229kB ... Attributes: units: au
[36]:
# cmap: Which colors should be used
# If cmap is not specified, and dynamic=True, it will change while we scroll. If dynamic=False, it will be fix.
# color_levels: in which ranges should these colors be used
# clim: what is the absolute scale of the colorbar
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt_dynamic.opts(
colorbar=True,
width=500,
height=400,
# cmap=['#0000ff', '#89cff0', '#f75e25', '#ff0000'],
# color_levels=[-10**-3, -10**-4, 0, 10**-4, 10**-3],
cmap="seismic",
clim=(-(10**-3), 10**-3),
clabel=f"{xa.vx.name} ({xa.vx.units})",
)
[36]:
The middle of the colormap will be in the middle of the min and max values of clim, so e.g. if you want the color map to be symmetric around 0, you should climmin == -climmax
.
Saving gifs, htmls, images and videos of plots#
Bokeh for (gifs and) htmls#
The recommended output format for interactive plots is html
. If needed, one can also generate gifs and mp4s with holoviews.
sudo apt install geckodriver
(or conda install -c conda-forge geckodriver
) for generating the bokeh gif
, although one can generate matplotlib gif
s without it.sudo apt install ffmpeg
(or conda install -c conda-forge ffmpeg
) for generating matplotlib mp4
s. It is also possible to generate them in RAVEN (s. Advanced section)The gif and the mp4 generations were commented out because the CI would need geckodriver and ffmpeg. If you have them, just uncomment the code bits!
Note that we are using hv_imt and NOT hv_imt_dynamic!
[37]:
hv.save(
hv_imt.opts(
colorbar=True,
width=500,
height=400,
cmap="seismic",
clim=(-(10**-3), 10**-3), # hv.Image args
),
fmt="html",
backend="bokeh",
filename="test2", # hv.save args
)
# uncomment if you have `geckodriver`
"""
hv.save(
hv_imt.opts(
colorbar=True, width=500, height=400, cmap='seismic', clim=(-10**-3, 10**-3)
),
fmt="gif", backend="bokeh", filename="test3", fps=1
)
"""
hv.save(
hv_imt.opts(
colorbar=True,
width=500,
height=400,
cmap="seismic",
clim=(-(10**-3), 10**-3),
),
fmt="scrubber",
backend="bokeh",
filename="test20",
fps=1,
)
Look into the notebooks
folder, you should see new files in it!
Matplotlib for gifs and mp4#
Bokeh is the default backend when working with holowiews. Although, bokeh doesn’t currently support the output of mp4s (Also: the gif generation in bokeh can be slower than with matplotlib). So that the holoviews
object should be ported to a matploib backend. This shouldn’t be complicated. Probably, the only thing one needs to change isfig_size
instead of height
and width
. Recall: hv.help(hv.Image)
lists all the tunable parameters, for the active backend.
[38]:
hv.extension("matplotlib")
For Linux users: VLC player may needed for opening the mp4.
[39]:
# uncomment if you have `ffmpeg`
"""
hv.save(
hv_imt.opts(colorbar=True, fig_inches=10, cmap='seismic', clim=(-10**-3, 10**-3)
),
fmt="mp4", backend="matplotlib", filename="test4", fps=1)
"""
[39]:
'\nhv.save(\n hv_imt.opts(colorbar=True, fig_inches=10, cmap=\'seismic\', clim=(-10**-3, 10**-3)\n ),\n fmt="mp4", backend="matplotlib", filename="test4", fps=1) \n'
[40]:
hv.save(
hv_imt.opts(
colorbar=True, cmap="seismic", fig_inches=10, clim=(-(10**-3), 10**-3)
),
fmt="gif",
backend="matplotlib",
filename="test5",
fps=1,
)
[41]:
hv.extension("bokeh") # go back to bokeh as default
Export individual images#
For exporting individual png’s the easiest way, is while interacting with a dynamic plot: go to the frame that you are interested in, and click on the save button in the right-hand-bokeh-menu. That’s it:
[42]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt_dynamic
[42]:
In case you need an svg
, you will need to use matplotlib. Just slice the original xarray at the point where you are interested in:
[43]:
xa00 = xa.sel(
t=0.0
) # from the plot above look at which step interests you most, let's say t=0.0.
hv_dst00 = hv.Dataset(xa00)
hv_imt00 = hv_dst00.to(hv.Image, ["x", "y"])
[44]:
hv.extension("matplotlib")
For some reason, the following cell causes trouble in the CI pipeline, although when executing it in a notebook there is no problem (problem started end of august). We are going to comment it and maybe address this in the future:
[45]:
"""
hv.save(
hv_imt00.opts(
colorbar=True, title="step300", fig_size=500, cmap='seismic', clim=(-10**-3, 10**-3), xticks="auto", yticks="auto",
),
fmt="svg", backend="matplotlib", filename="test6", fps=1
)
"""
[45]:
'\nhv.save(\n hv_imt00.opts(\n colorbar=True, title="step300", fig_size=500, cmap=\'seismic\', clim=(-10**-3, 10**-3), xticks="auto", yticks="auto",\n ),\n fmt="svg", backend="matplotlib", filename="test6", fps=1\n)\n'
[46]:
hv.help(hv_imt00.opts())
Image: Image
Online example: https://holoviews.org/reference/elements/matplotlib/Image.html
---------------------
Target Specifications
---------------------
Targets in this object available for customization:
Element: Image.Image
To see the options info for one of these target specifications,
which are of the form {type}[.{group}[.{label}]], do holoviews.help({type}).
-------------
Style Options
-------------
alpha, clims, cmap, filterrad, interpolation, norm, visible
(Consult matplotlib's documentation for more information.)
------------
Plot Options
------------
The plot options are the parameters of the plotting class:
Parameters of 'RasterPlot'
==========================
Parameters changed from their default values are marked in red.
Soft bound values are marked in cyan.
C/V= Constant/Variable, RO/RW = ReadOnly/ReadWrite, AN=Allow None
Name Value Type Bounds Mode
fontsize None Parameter V RW AN
fontscale None Number V RW AN
show_title True Boolean V RW
title '{label} {group}\n{dimensions}' String V RW
normalize True Boolean V RW
projection None Parameter V RW AN
backend_opts {} Dict V RW
fig_alpha 1.0 Number (0, 1) V RW
fig_bounds (0.15, 0.15, 0.85, 0.85) NumericTuple V RW
fig_inches 4 Parameter V RW
fig_latex False Boolean V RW
fig_rcparams {} Dict V RW
fig_size 100.0 Number (1, None) V RW
initial_hooks [] HookList (0, None) V RW
sublabel_format None String V RW AN
sublabel_position (-0.35, 0.85) NumericTuple V RW
sublabel_size 18 Number V RW
show_frame False Boolean V RW
apply_ranges True Boolean V RW
apply_extents True Boolean V RW
bgcolor None ClassSelector V RW AN
default_span 2.0 ClassSelector V RW
hooks [] HookList (0, None) V RW
invert_axes False Boolean V RW
invert_xaxis False Boolean V RW
invert_yaxis False Boolean V RW
logx False Boolean V RW
logy False Boolean V RW
padding 0 ClassSelector V RW
show_legend False Boolean V RW
show_grid False Boolean V RW
xaxis 'bottom' ObjectSelector V RW
yaxis 'left' ObjectSelector V RW
xlabel None String V RW AN
ylabel None String V RW AN
xlim (nan, nan) Tuple V RW
ylim (nan, nan) Tuple V RW
zlim (nan, nan) Tuple V RW
xrotation None Integer (0, 360) V RW AN
yrotation None Integer (0, 360) V RW AN
xticks None ClassSelector V RW AN
yticks None ClassSelector V RW AN
apply_ticks True Boolean V RW
aspect 'equal' Parameter V RW
data_aspect None Number V RW AN
invert_zaxis False Boolean V RW
labelled ['x', 'y'] List (0, None) V RW
logz False Boolean V RW
xformatter None ClassSelector V RW AN
yformatter None ClassSelector V RW AN
zformatter None ClassSelector V RW AN
zaxis True Boolean V RW
zlabel None String V RW AN
zrotation 0 Integer (0, 360) V RW
zticks None Parameter V RW AN
clabel None String V RW AN
clim (nan, nan) Tuple V RW
clim_percentile False ClassSelector V RW
cformatter None ClassSelector V RW AN
colorbar False Boolean V RW
colorbar_opts {} Dict V RW
color_levels None ClassSelector V RW AN
cnorm 'linear' ObjectSelector V RW
clipping_colors {'NaN': 'transparent'} Dict V RW
cbar_padding 0.01 Number V RW
cbar_ticks None Parameter V RW AN
cbar_width 0.05 Number V RW
cbar_extend None ObjectSelector V RW
rescale_discrete_levels True Boolean V RW
symmetric False Boolean V RW
nodata None Integer V RW AN
situate_axes True Boolean V RW
Parameter docstrings:
=====================
fontsize: Specifies various font sizes of the displayed text.
Finer control is available by supplying a dictionary where any
unmentioned keys revert to the default sizes, e.g:
{'ticks':20, 'title':15,
'ylabel':5, 'xlabel':5, 'zlabel':5,
'legend':8, 'legend_title':13}
You can set the font size of 'zlabel', 'ylabel' and 'xlabel'
together using the 'labels' key.
fontscale: Scales the size of all fonts.
show_title: Whether to display the plot title.
title: The formatting string for the title of this plot, allows defining
a label group separator and dimension labels.
normalize: Whether to compute ranges across all Elements at this level
of plotting. Allows selecting normalization at different levels
for nested data containers.
projection: The projection of the plot axis, default of None is equivalent to
2D plot, '3d' and 'polar' are also supported by matplotlib by default.
May also supply a custom projection that is either a matplotlib
projection type or implements the `_as_mpl_axes` method.
backend_opts: A dictionary of custom options to apply to the plot or
subcomponents of the plot. The keys in the dictionary mirror
attribute access on the underlying models stored in the plot's
handles, e.g. {'colorbar.margin': 10} will index the colorbar
in the Plot.handles and then set the margin to 10.
fig_alpha: Alpha of the overall figure background.
fig_bounds: The bounds of the overall figure as a 4-tuple of the form
(left, bottom, right, top), defining the size of the border
around the subplots.
fig_inches: The overall matplotlib figure size in inches. May be set as
an integer in which case it will be used to autocompute a
size. Alternatively may be set with an explicit tuple or list,
in which case it will be applied directly after being scaled
by fig_size. If either the width or height is set to None,
it will be computed automatically.
fig_latex: Whether to use LaTeX text in the overall figure.
fig_rcparams: matplotlib rc parameters to apply to the overall figure.
fig_size: Size relative to the supplied overall fig_inches in percent.
initial_hooks: Optional list of hooks called before plotting the data onto
the axis (now marked for deprecation). The hook is passed the
plot object and the displayed object; other plotting handles
can be accessed via plot.handles.
sublabel_format: Allows labeling the subaxes in each plot with various formatters
including {Alpha}, {alpha}, {numeric} and {roman}.
sublabel_position: Position relative to the plot for placing the optional subfigure label.
sublabel_size: Size of optional subfigure label.
show_frame: Whether or not to show a complete frame around the plot.
apply_ranges: Whether to compute the plot bounds from the data itself.
apply_extents: Whether to apply extent overrides on the Elements
bgcolor: If set bgcolor overrides the background color of the axis.
default_span: Defines the span of an axis if the axis range is zero, i.e. if
the lower and upper end of an axis are equal or no range is
defined at all. For example if there is a single datapoint at
0 a default_span of 2.0 will result in axis ranges spanning
from -1 to 1.
hooks: Optional list of hooks called when finalizing a plot. The
hook is passed the plot object and the displayed element, and
other plotting handles can be accessed via plot.handles.
invert_axes: Whether to invert the x- and y-axis
invert_xaxis: Whether to invert the plot x-axis.
invert_yaxis: Whether to invert the plot y-axis.
logx: Whether the x-axis of the plot will be a log axis.
logy: Whether the y-axis of the plot will be a log axis.
padding: Fraction by which to increase auto-ranged extents to make
datapoints more visible around borders.
To compute padding, the axis whose screen size is largest is
chosen, and the range of that axis is increased by the
specified fraction along each axis. Other axes are then
padded ensuring that the amount of screen space devoted to
padding is equal for all axes. If specified as a tuple, the
int or float values in the tuple will be used for padding in
each axis, in order (x,y or x,y,z).
For example, for padding=0.2 on a 800x800-pixel plot, an x-axis
with the range [0,10] will be padded by 20% to be [-1,11], while
a y-axis with a range [0,1000] will be padded to be [-100,1100],
which should make the padding be approximately the same number of
pixels. But if the same plot is changed to have a height of only
200, the y-range will then be [-400,1400] so that the y-axis
padding will still match that of the x-axis.
It is also possible to declare non-equal padding value for the
lower and upper bound of an axis by supplying nested tuples,
e.g. padding=(0.1, (0, 0.1)) will pad the x-axis lower and
upper bound as well as the y-axis upper bound by a fraction of
0.1 while the y-axis lower bound is not padded at all.
show_legend: Whether to show legend for the plot.
show_grid: Whether to show a Cartesian grid on the plot.
xaxis: Whether and where to display the xaxis.
The "bare" options allow suppressing all axis labels, including ticks and xlabel.
Valid options are 'top', 'bottom', 'bare', 'top-bare' and 'bottom-bare'.
yaxis: Whether and where to display the yaxis.
The "bare" options allow suppressing all axis labels, including ticks and ylabel.
Valid options are 'left', 'right', 'bare', 'left-bare' and 'right-bare'.
xlabel: An explicit override of the x-axis label, if set takes precedence
over the dimension label.
ylabel: An explicit override of the y-axis label, if set takes precedence
over the dimension label.
xlim: User-specified x-axis range limits for the plot, as a tuple (low,high).
If specified, takes precedence over data and dimension ranges.
ylim: User-specified y-axis range limits for the plot, as a tuple (low,high).
If specified, takes precedence over data and dimension ranges.
zlim: User-specified z-axis range limits for the plot, as a tuple (low,high).
If specified, takes precedence over data and dimension ranges.
xrotation: Rotation angle of the xticks.
yrotation: Rotation angle of the yticks.
xticks: Ticks along x-axis specified as an integer, explicit list of
tick locations. If set to None default ticking behavior is applied.
yticks: Ticks along y-axis specified as an integer, explicit list of
tick locations. If set to None default ticking behavior is applied.
apply_ticks: Whether to apply custom ticks.
aspect: Raster elements respect the aspect ratio of the
Images by default but may be set to an explicit
aspect ratio or to 'square'.
data_aspect: Defines the aspect of the axis scaling, i.e. the ratio of
y-unit to x-unit.
invert_zaxis: Whether to invert the plot z-axis.
labelled: Whether to plot the 'x' and 'y' labels.
logz: Whether to apply log scaling to the y-axis of the Chart.
xformatter: Formatter for ticks along the x-axis.
yformatter: Formatter for ticks along the y-axis.
zformatter: Formatter for ticks along the z-axis.
zaxis: Whether to display the z-axis.
zlabel: An explicit override of the z-axis label, if set takes precedence
over the dimension label.
zrotation: Rotation angle of the zticks.
zticks: Ticks along z-axis specified as an integer, explicit list of
tick locations, list of tuples containing the locations and
labels or a matplotlib tick locator object. If set to None
default matplotlib ticking behavior is applied.
clabel: An explicit override of the color bar label, if set takes precedence
over the title key in colorbar_opts.
clim: User-specified colorbar axis range limits for the plot, as a
tuple (low,high). If specified, takes precedence over data
and dimension ranges.
clim_percentile: Percentile value to compute colorscale robust to outliers. If
True, uses 2nd and 98th percentile; otherwise uses the specified
numerical percentile value.
cformatter: Formatter for ticks along the colorbar axis.
colorbar: Whether to draw a colorbar.
colorbar_opts: Allows setting specific styling options for the colorbar.
color_levels: Number of discrete colors to use when colormapping or a set of color
intervals defining the range of values to map each color to.
cnorm: Color normalization to be applied during colormapping.
clipping_colors: Dictionary to specify colors for clipped values, allows
setting color for NaN values and for values above and below
the min and max value. The min, max or NaN color may specify
an RGB(A) color as a color hex string of the form #FFFFFF or
#FFFFFFFF or a length 3 or length 4 tuple specifying values in
the range 0-1 or a named HTML color.
cbar_padding: Padding between colorbar and other plots.
cbar_ticks: Ticks along colorbar-axis specified as an integer, explicit
list of tick locations, list of tuples containing the
locations and labels or a matplotlib tick locator object. If
set to None default matplotlib ticking behavior is
applied.
cbar_width: Width of the colorbar as a fraction of the main plot
cbar_extend: If not 'neither', make pointed end(s) for out-of- range values.
rescale_discrete_levels: If ``cnorm='eq_hist`` and there are only a few discrete values,
then ``rescale_discrete_levels=True`` decreases the lower
limit of the autoranged span so that the values are rendering
towards the (more visible) top of the palette, thus
avoiding washout of the lower values. Has no effect if
``cnorm!=`eq_hist``. Set this value to False if you need to
match historical unscaled behavior, prior to HoloViews 1.14.4.
symmetric: Whether to make the colormap symmetric around zero.
nodata: Optional missing-data value for integer data.
If non-None, data with this value will be replaced with NaN so
that it is transparent (by default) when plotted.
situate_axes: Whether to situate the image relative to other plots.
[47]:
hv.extension("bokeh", "matplotlib") # go back to bokeh as default
Vectorfields#
Colormap plot#
[48]:
xav = run.Maxwell.td.b_field(source="z=0") # XArray Vector
[49]:
hv_dst = hv.Dataset(xav)
hv_imt = hv_dst.to(hv.Image, ["x", "y"]) # needed for generating outputs
hv_imt_dynamic = hv_dst.to(hv.Image, ["x", "y"], dynamic=True)
hv.output(max_frames=3000)
hv_imt_dynamic
[49]:
[50]:
# Note for web users: You should have an active notebook session to interact with the plot
hv_imt_dynamic.opts(
colorbar=True,
width=500,
height=400,
cmap="seismic",
clabel=f"{xav.vx.name} ({xav.units})",
clim=(-(10**-3), 10**-3),
)
[50]:
Arrow plot#
[51]:
import numpy as np
import xarray as xr
[52]:
ds = xr.Dataset(
{
"Angle": np.arctan2(
xav.sel(x=slice(-10, 10), y=slice(-10, 10)).vy,
xav.sel(x=slice(-10, 10), y=slice(-10, 10)).vx,
),
"Magnitude": np.sqrt(
xav.sel(x=slice(-10, 10), y=slice(-10, 10)).vx ** 2
+ xav.sel(x=slice(-10, 10), y=slice(-10, 10)).vy ** 2
),
}
) # polar coordinates required for plotting arrows
[53]:
xav.vx.attrs
[53]:
{'units': 'au'}
[54]:
def _vectorplot(val):
plot = hv.VectorField(
data=ds.sel(t=val, method="nearest"),
kdims=["x", "y"],
vdims=["Angle", "Magnitude"],
)
for dim in plot.kdims: # keep the units
dim.unit = xav[f"v{dim}"].units
return plot
[55]:
# Note for web users: You should have an active notebook session to interact with the plot
arrow_plot = (
hv.DynamicMap(_vectorplot, kdims="t")
.redim.values(t=xav.t.values)
.opts(color="blue", width=500, height=400)
) # Zoom-in for seeing the arrows!
arrow_plot.kdims[0].unit = xav.t.units
arrow_plot
[55]:
Advanced#
Advanced plotting#
If the holoviews default plotting does not offer enough customization to your needs, one has two possibilites: - Use the holoviews hooks. These hooks will offer the underlying plot
object from the backend to you. In the case of matplotlib e.g. in the function that you hook to, you could use fig = plot.handles["fig"]
and ax = plot.handles["axis"]
. These fig
and axes
objects are the ones that you probably
know from matplotlib already. You can customize them as you are used to within the function. An example for this can be found in the case_study_all_final
example, which is referenced under Application examples
. We recommend exploiting this possibily first, before going to the second one, for still being able of having interactive plots. - Render the holoviews object into a backend object, e.g. matplotlib, to directly
use the classic matplotlib functionalities: fig = hv.render(hv_object, backend="matplotlib")
, where ax = fig.axes
. An example for this can be found in the case_study_all_in_one_exploration
example, which is referenced under Application examples
.
Using conda-forge packages on RAVEN.#
bokeh
gif
s and matplotlib
mp4
s, one needs geckodriver
and ffmpeg
, respectively. The latter two are not Python
packages. Therefore, one cannot install them via pip
, so they are not installed by default along with postopus
. Nonetheless, they can be installed via conda-forge
. The problem is that the standard
MPCDF-RVS-Service for visualizing notebooks doesn’t allow to use custom anaconda
environments. But there is a rather simple way to overcome this: 1) Login to your raven-account via ssh
in a terminalname: holoviews-env
channels:
- conda-forge
- defaults
dependencies:
- python=3.9
- matplotlib
- numpy=1.21.5
- netCDF4
- pandas
- prettytable
- pyvista
- xarray
- psutil
- holoviews
- datashader
- selenium
- pytest
- Jinja2==3.0.1
- pip
- ipykernel
- geckodriver
- ffmpeg
- pip:
- ase @ git+https://gitlab.com/dremerb/ase.git@xsf_and_cube_merge
- postopus @ git+https://gitlab.com/octopus-code/postopus.git
Create a conda environment with the requirements of the yaml:
conda env create -p /u/user_name/name_of_conda_environment --file=path_to_conf_yml.yml
conda deactivate
andconda activate path_to_conda_env
conda install -c conda-forge jupyterlab
jupyter-lab
After a few seconds, a new browser window will pop-up with a jupyter notebook hosted on raven that has all the packages that you need.
Final notes#
This tutorial is intended to be an introduction to holoviews. We didn’t cover everything here. For example, there is another notebook under /dev
that handles reduction methods in order to plot very dense data. If you need something more sophisticated for large datasets we could think about exploring the dask functionalities, which are also supported by holoviews. Just contact us if you have any questions!