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/octopus-code/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]: