GridPlot¶
GridPlot
class will help you very easily display any Grid
.
Note
Dedicated software like VESTA might be faster in rendering big 3D grids, but the strength of this plot class lies in its great flexibility, tunability (change settings as you wish to customize the display from python) and convenience (no need to open another software, you can see the grid directly in your notebook). Also, you can combine your grid plots however you want with the other plot classes in the framework.
[1]:
import sisl
import sisl.viz.plotly
# This is just for convenience to retreive files
siesta_files = sisl._environ.get_environ_variable("SISL_FILES_TESTS") / "sisl" / "io" / "siesta"
The first thing that we need to do to plot a grid is having a grid, so let’s get one!
In this case, we are going to use an electronic density grid from a .RHO
file in SIESTA. There are multiple ways of getting the plot:
[2]:
rho_file = siesta_files / "SrTiO3.RHO"
# From a sisl grid, you can do grid.plot()
grid = sisl.get_sile(rho_file).read_grid()
plot = grid.plot()
# All siles that implement read_grid can also be directly plotted
plot = sisl.get_sile(rho_file).plot()
# Using the Plot class, perhaps the cleaner one, but needs an extra import
from sisl.viz.plotly import Plot
plot = Plot(rho_file)
---------------------------------------------------------------------------
SileError Traceback (most recent call last)
/tmp/ipykernel_4329/594157926.py in <module>
2
3 # From a sisl grid, you can do grid.plot()
----> 4 grid = sisl.get_sile(rho_file).read_grid()
5 plot = grid.plot()
6
~/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/sisl/io/siesta/binaries.py in read_grid(self, index, dtype, *args, **kwargs)
1129 index = kwargs.get('spin', index)
1130 # Read the sizes and cell
-> 1131 nspin, mesh = self.read_grid_size()
1132 sc = self.read_supercell()
1133 grid = _siesta.read_grid(self.file, nspin, mesh[0], mesh[1], mesh[2])
~/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/sisl/io/siesta/binaries.py in read_grid_size(self)
1111 # Read the sizes
1112 nspin, mesh = _siesta.read_grid_sizes(self.file)
-> 1113 _bin_check(self, 'read_grid_size', 'could not read grid sizes.')
1114 return nspin, mesh
1115
~/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/sisl/io/siesta/binaries.py in _bin_check(obj, method, message)
44 ierr = _siesta.io_m.iostat_query()
45 if ierr != 0:
---> 46 raise SileError(f'{str(obj)}.{method} {message} (ierr={ierr})')
47
48
SileError: rhoSileSiesta(SrTiO3.RHO, base=/home/docs/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/docs/visualization/plotly/showcase/_THIS_DIRECTORY_DOES_NOT_EXIST_/sisl/io/siesta).read_grid_size could not read grid sizes. (ierr=2)
Anyway, you will end up having the grid under plot.grid
.
Let’s see what we’ve got:
[3]:
plot
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/152242767.py in <module>
----> 1 plot
NameError: name 'plot' is not defined
Well, this doesn’t look much like a grid, does it? By default, GridPlot
only shows the third axis of the grid, while averaging along the others. This is because plotly can really struggle trying to plot an enormous 3d grid, to the point that it can leave your computer stuck.
Plotting in 3D, 2D and 1D¶
Much like GeometryPlot, you can select the axes of the grid that you want to display. In this case, the other axes will be averaged.
For example, if we want to see the xy plane of the electronic density, we can do:
[4]:
plot.update_settings(axes=[0,1])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/3882597334.py in <module>
----> 1 plot.update_settings(axes=[0,1])
NameError: name 'plot' is not defined
Note that you can make 2d representations look smoother without having to make the grid finer by using the zsmooth
setting, which is part of plotly’s go.Heatmap
trace options.
[5]:
plot.update_settings(zsmooth="best")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/1900555373.py in <module>
----> 1 plot.update_settings(zsmooth="best")
NameError: name 'plot' is not defined
3d representations of a grid will display isosurfaces:
[6]:
plot.update_settings(axes=[0,1,2])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/4104495374.py in <module>
----> 1 plot.update_settings(axes=[0,1,2])
NameError: name 'plot' is not defined
Isosurfaces and contours¶
There’s one parameter that controls both the display of isosurfaces (in 3d) and contours (in 2d): isos
.
isos
is a list of dicts where each dict asks for an isovalue. See the help message:
[7]:
print(plot.get_param("isos").help)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/899994802.py in <module>
----> 1 print(plot.get_param("isos").help)
NameError: name 'plot' is not defined
If no isos
is provided, 3d representations plot the 0.3 and 0.7 (frac
) isosurfaces. This is what you can see in the 3d plot that we displayed above.
Let’s play a bit with isos
. The first thing I will do is change the opacity of the outer isosurface, since there’s no way to see the inner one right now (although you can toggle it by clicking at the legend, courtesy of plotly :)).
[8]:
plot.update_settings(isos=[{"frac": 0.3, "opacity": 0.4}, {"frac": 0.7}])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/858790909.py in <module>
----> 1 plot.update_settings(isos=[{"frac": 0.3, "opacity": 0.4}, {"frac": 0.7}])
NameError: name 'plot' is not defined
Now we can see all the very interesting features of the inner isosurface! :)
Let’s now see how contours look in 2d:
[9]:
plot.update_settings(axes=[0,1])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/3882597334.py in <module>
----> 1 plot.update_settings(axes=[0,1])
NameError: name 'plot' is not defined
Not bad.
Colorscales¶
You might have already seen that 2d representations use a colorscale. You can change it with the colorscale
setting.
[10]:
plot.update_settings(isos=[], colorscale="temps")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/644206011.py in <module>
----> 1 plot.update_settings(isos=[], colorscale="temps")
NameError: name 'plot' is not defined
And you can control its range using crange
(min and max bounds of the colorscale) and cmid
(middle value of the colorscale, will take preference over crange
). In this way, you are able saturate the display as you wish.
For example, in this case, if we bring the lower bound up enough, we will be able to hide the Sr atoms that are in the corners. But be careful not to make it so high that you hide the oxygens as well!
[11]:
plot.update_settings(crange=[1,4])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/3348470972.py in <module>
----> 1 plot.update_settings(crange=[1,4])
NameError: name 'plot' is not defined
Using only part of the grid¶
As we can see in the 3d representation of the electronic density, there are two atoms contributing to the electronic density in the center, that’s why we get such a big difference in the 2d heatmap.
We can use the x_range
, ỳ_range
and z_range
settings to take into account only a certain part of the grid. for example, in this case we want only the grid where z
is in the [1,3]
interval so that we remove the influence of the oxygen atom that is on top.
[12]:
plot.update_settings(z_range=[1,3])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/2473428489.py in <module>
----> 1 plot.update_settings(z_range=[1,3])
NameError: name 'plot' is not defined
Now we are seeing the real difference between the Ti atom (in the center) and the O atoms (at the edges).
Applying transformations¶
One can apply as many transformations as it wishes to the grid by using the transforms
setting.
It should be a list where each item can be a string (the name of the function, e.g. "numpy.sin"
) or a function. Each transform is passed to Grid.apply
, see the method for more info.
[13]:
plot.update_settings(transforms=[abs, "numpy.sin"], crange=None)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/770663924.py in <module>
----> 1 plot.update_settings(transforms=[abs, "numpy.sin"], crange=None)
NameError: name 'plot' is not defined
Notice that the order of the transformations matter:
[14]:
plot.update_settings(transforms=["sin", abs], crange=None)
# If a string is provided with no module, it will be interpreted as a numpy function
# Therefore "sin" == "numpy.sin" and abs != "abs" == "numpy.abs"
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/2751520265.py in <module>
----> 1 plot.update_settings(transforms=["sin", abs], crange=None)
2 # If a string is provided with no module, it will be interpreted as a numpy function
3 # Therefore "sin" == "numpy.sin" and abs != "abs" == "numpy.abs"
NameError: name 'plot' is not defined
Visualizing supercells¶
Visualizing grid supercells is as easy as using the nsc
setting. If we want to repeat our grid visualization along the second axis 3 times, we just do:
[15]:
plot.update_settings(nsc=[1,3,1])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/198542688.py in <module>
----> 1 plot.update_settings(nsc=[1,3,1])
NameError: name 'plot' is not defined
Performing scans¶
We can use the scan
method to create a scan of the grid along a given direction. If we have a 2d representation, the scan will be performed along the other axis by default, but we can choose in which direction we want to scan.
[16]:
plot.scan(num=5)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/833497017.py in <module>
----> 1 plot.scan(num=5)
NameError: name 'plot' is not defined
Notice how the scan respected our z_range
from 1 to 3. If we want the rest of the grid, we can set z_range
back to None
before creating the scan, or we can indicate the bounds of the scan.
[17]:
plot.scan(along=2, start=0, stop=plot.grid.cell[2,2], num=10)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/3578519746.py in <module>
----> 1 plot.scan(along=2, start=0, stop=plot.grid.cell[2,2], num=10)
NameError: name 'plot' is not defined
This is the "moving_slice"
scan, but we can also display the scan as an animation:
[18]:
plot.scan(mode="as_is", num=15)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/3266223782.py in <module>
----> 1 plot.scan(mode="as_is", num=15)
NameError: name 'plot' is not defined
This mode is called "as_is"
because it creates an animation of the current representation. That is, it can scan through 1d, 2d and 3d representations and it keeps displaying the supercell.
Here’s a scan of 1d data:
[19]:
plot.update_settings(axes=[2]).scan(mode="as_is", num=15)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/1454031022.py in <module>
----> 1 plot.update_settings(axes=[2]).scan(mode="as_is", num=15)
NameError: name 'plot' is not defined
We hope you enjoyed what you learned!
This next cell is just to create the thumbnail for the notebook in the docs
[20]:
thumbnail_plot = plot.update_settings(axes=[1,0], z_range=[1.7, 1.9])
if thumbnail_plot:
thumbnail_plot.show("png")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_4329/461327816.py in <module>
----> 1 thumbnail_plot = plot.update_settings(axes=[1,0], z_range=[1.7, 1.9])
2
3 if thumbnail_plot:
4 thumbnail_plot.show("png")
NameError: name 'plot' is not defined