Using python to interact with sisl’s GUI¶
This notebook will show you how you can benefit from knowing how to interact with the graphical interface. Some things just make no sense to do with just clicks, but having a dashboard to visualize and layout your automatically-generated plots is great. However there are some things that the GUI can already help you do automatically. You will be a true master in the moment you know how to use sisl plots in pyton, how to use the GUI and how to make the two worlds interact.
But don’t worry, it is not that difficult really to become a true master :)
You will also understand that you can build your own custom sessions to adapt to your needs, boost your productivity and save you hours of work.
Disclaimer: This notebook will be very simple and straightforward.
[1]:
%%html
<! RUN ME PLEASEEEEEE>
<style>
.user {
background:aliceblue;
padding:5px 10px;
margin 0px 10px;
border-radius: 3px;
color: darkblue;
font-style:italic
}
</style>
[2]:
# This is just for convenience to retreive files
import sisl
siesta_files = sisl._environ.get_environ_variable("SISL_FILES_TESTS") / "sisl" / "io" / "siesta"
1. LAUNCHING THE GUI¶
[3]:
import sisl_gui
sisl_gui.launch()
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
/tmp/ipykernel_3167/2871562012.py in <module>
----> 1 import sisl_gui
2
3 sisl_gui.launch()
ModuleNotFoundError: No module named 'sisl_gui'
A browser tab should have opened. Do you see it?
Yeees!
2. UNDERSTANDING HOW THE GUI WORKS¶
Well, it’s not magic. It uses a structure that you will probably be familiar with already.
There is a session. This session contains tabs. Tabs contain plots.
How can I see that session?
[4]:
session = sisl_gui.get_session()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/1546544291.py in <module>
----> 1 session = sisl_gui.get_session()
NameError: name 'sisl_gui' is not defined
What can I do with it?
Use half screen for the GUI and another half for this notebook and I will show you. Or, you know, use two monitors in case you are living a fancy life.
[5]:
# Let's write the session to a new variable for convenience
session = sisl_gui.get_session()
# Then add a new tab ( run help(session) to see all the available methods )
session.add_tab("Tab added from jupyter")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/3882033278.py in <module>
1 # Let's write the session to a new variable for convenience
----> 2 session = sisl_gui.get_session()
3
4 # Then add a new tab ( run help(session) to see all the available methods )
5 session.add_tab("Tab added from jupyter")
NameError: name 'sisl_gui' is not defined
Do you see the magic?
No.
Yeah me neither. You have added a new tab, but the GUI still doesn’t know about it. One way of solving this is to refresh the browser with F5.
Lame.
I know. That’s why there are better ways. You can either emit the changes when you are ready:
[6]:
session.emit()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/2393031917.py in <module>
----> 1 session.emit()
NameError: name 'session' is not defined
Or use the magic of autosync:
[7]:
session.autosync.add_tab("This is syncing!")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/3990576989.py in <module>
----> 1 session.autosync.add_tab("This is syncing!")
NameError: name 'session' is not defined
That’s cool, but do I have to write autosync each time?.
No, the autosync property basically returns your session with autosyncing super-powers. So, you can store that and then run your methods happily:
[8]:
# From now on we are going to just the autosynced version of the
# session. We could keep the other one, but we just don't care
# so we will overwrite it
session = session.autosync
# Just delete our useless tabs
session.remove_tab('This is syncing!')
session.remove_tab('Tab added from jupyter')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/2649324768.py in <module>
2 # session. We could keep the other one, but we just don't care
3 # so we will overwrite it
----> 4 session = session.autosync
5
6 # Just delete our useless tabs
NameError: name 'session' is not defined
We can now start to add plots.
[9]:
from sisl.viz.plotly import Plot
# Let's start a PDOS plot
plot = Plot(siesta_files / "SrTiO3.PDOS")
session.add_plot(plot, "First tab")
info:0: SislInfo:
The plot has been initialized correctly, but the current settings were not enough to generate the figure.
Error: Could not read or generate data for PdosPlot from any of the possible sources.
Here are the errors for each source:
- TB trans: TypeError.expected str, bytes or os.PathLike object, not NoneType
- hamiltonian: TypeError.expected str, bytes or os.PathLike object, not NoneType
- siesta output: FileNotFoundError.[Errno 2] No such file or directory: '_THIS_DIRECTORY_DOES_NOT_EXIST_/sisl/io/siesta/SrTiO3.PDOS'
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/3810488281.py in <module>
4 plot = Plot(siesta_files / "SrTiO3.PDOS")
5
----> 6 session.add_plot(plot, "First tab")
NameError: name 'session' is not defined
Can you see it?
No.
Maybe you don’t have the tab open in the GUI.
Now, you should be able to interact as you wish with it. Since the reference is kept, you are able to run the methods on your notebook variable directly. Like so:
[10]:
plot.autosync.split_DOS(on="species")
# Yes, plots can also autosync after they have been bound to a session
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_3167/3147319848.py in <module>
----> 1 plot.autosync.split_DOS(on="species")
2 # Yes, plots can also autosync after they have been bound to a session
~/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/sisl/viz/plotly/plot.py in __getattr__(self, key)
734 pass
735
--> 736 raise AttributeError(f"The attribute '{key}' was not found either in the plot, its figure, or in shared attributes.")
737
738 def __setattr__(self, key, val):
AttributeError: The attribute 'autosync' was not found either in the plot, its figure, or in shared attributes.
Let’s add two more plots to this tab.
[11]:
bands = Plot(siesta_files / "SrTiO3.bands")
rho = Plot(siesta_files / "SrTiO3.RHO")
for pt in (rho, bands):
session.add_plot(pt, "First tab")
info:0: SislInfo:
The plot has been initialized correctly, but the current settings were not enough to generate the figure.
Error: Could not read or generate data for BandsPlot from any of the possible sources.
Here are the errors for each source:
- aiida bands: AttributeError.'NoneType' object has no attribute '_get_bandplot_data'
- path: ValueError.You need to provide at least 2 points of the path to draw the bands. Please update the 'path' setting. The current path is: []
- band structure: ValueError.No band structure (k points path) was provided
- bands file: FileNotFoundError.[Errno 2] No such file or directory: '_THIS_DIRECTORY_DOES_NOT_EXIST_/sisl/io/siesta/SrTiO3.bands'
info:0: SislInfo:
The plot has been initialized correctly, but the current settings were not enough to generate the figure.
Error: Could not read or generate data for GridPlot from any of the possible sources.
Here are the errors for each source:
- grid file: SileError.rhoSileSiesta(SrTiO3.RHO, base=/home/docs/checkouts/readthedocs.org/user_builds/sisl/checkouts/v0.11.0/docs/visualization/plotly/basic-tutorials/_THIS_DIRECTORY_DOES_NOT_EXIST_/sisl/io/siesta).read_grid_size could not read grid sizes. (ierr=2)
- grid: ValueError.grid was not set
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/2701097848.py in <module>
3
4 for pt in (rho, bands):
----> 5 session.add_plot(pt, "First tab")
NameError: name 'session' is not defined
3. CHANGING THE GUI’S LAYOUT¶
Each tab has a layouts
attribute:
[12]:
session.tab("First tab")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/3949681589.py in <module>
----> 1 session.tab("First tab")
NameError: name 'session' is not defined
This layouts
attribute is a dictionary stating how plots should be displayed in different screen sizes (e.g. lg
is the largest and xxs
is the smallest). You can change this very easily using the GUI by resizing and dragging your plots, but if you need the same layout every time it is definitely not ideal.
The layouts
structure seems a bit complicated. But don’t worry, usually you just need to set the lg
size, because this is how you see it in a computer. Just ignore the other sizes.
As you can see, the lg
size is a list of dicts, each dict contains: - w
: The width of the plot in columns out of a total of { lg: 12, sm: 6, xs: 4, xxs: 2 } columns. - h
: The height of the plot. I don’t really know the scale of this honestly. Just try to see what fits best for you. - x
: The position along the x axis of the left side of the plot (in columns). - y
: The position along the y axis of the top part of the plot. - id
: The ID of the plot to which this properties
apply. It is available under plot.id
- moved
: Whether the plot has been moved. - static
: Whether the GUI should prevent users from resizing/dragging this plot.
I’d say the best strategy is probably to set the layout in the GUI and then copy it to build your automatic layouts. In my case, I like how this one looks:
[{'w': 6, 'h': 28, 'x': 0, 'y': 0,
'i': '26c94e23-9f6b-4bce-b0a4-3363e69f0fd3',
'moved': False,
'static': False},
{'w': 12, 'h': 14, 'x': 0, 'y': 28,
'i': '0a2f9502-3fbb-4c06-a402-8d46518d3bc3',
'moved': False,
'static': False},
{'w': 6, 'h': 28, 'x': 6, 'y': 0,
'i': 'f6ae7c4a-38c6-4d36-81cb-04c73a794555',
'moved': False,
'static': False}]
So I’m just going to use it automating the ID stuff:
[13]:
struct = "SrTiO3"
tab_name = "Layout attempt"
session.add_tab(tab_name)
# Get all the plots
plots = [Plot(siesta_files / f'{struct}.{ext}') for ext in ("PDOS", "RHO", "bands")]
for plot in plots:
session.add_plot(plot, tab_name)
# This is how you update tab parameters
# (in this case, we want to update the layouts parameter)
session.update_tab(
tab_name,
layouts = {'lg': [
{'w': 6, 'h': 28, 'x': 0, 'y': 0, 'i': plots[0].id, 'static': False},
{'w': 12, 'h': 14, 'x': 0, 'y': 28, 'i': plots[1].id, 'static': False},
{'w': 6, 'h': 28, 'x': 6, 'y': 0, 'i': plots[2].id, 'static': False}
]}
)
# And also I'd like the PDOS to be splitted on species
plots[0].split_DOS(on="species").update_settings(Erange=[-10,10]).emit()
# And the bands to show the gap
plots[2].update_settings(gap=True, Erange=[-10,10]).emit()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/2797782125.py in <module>
2 tab_name = "Layout attempt"
3
----> 4 session.add_tab(tab_name)
5
6 # Get all the plots
NameError: name 'session' is not defined
You can check the “Layout attempt” tab to see that we really achieved what we wanted.
4. BUILDING YOUR OWN CUSTOM SESSIONS¶
Well, at this point there is not much mistery to it. Specially if you have gone through the guide on how to build plots You just need to extend the Session
class. Session
, as Plot
, inherits from Configurable
, so you have exactly the same management of settings.
If you have not read the guide for plots, don’t worry. The basics to build a session class are very simple.
Let’s build a session using what we wrote in the previous section. We really just need to change the session
variable for self
and we have a method!
[14]:
# Import the parent class
from sisl.viz.plotly import Session
# Start building our session
class VeryCoolSession(Session):
# Add the method to see PDOS, bands and RHO of a structure
def see_results(self, struct, wdir=siesta_files, tab_name=None):
if tab_name is None:
tab_name = struct
self.add_tab(tab_name)
plots = [Plot(wdir / f'{struct}.{ext}') for ext in ("PDOS", "RHO", "bands")]
for plot in plots:
self.add_plot(plot, tab_name)
# This is how you update tab parameters
self.update_tab(
tab_name,
layouts = {'lg': [
{'w': 6, 'h': 28, 'x': 0, 'y': 0, 'i': plots[0].id, 'static': False},
{'w': 12, 'h': 14, 'x': 0, 'y': 28, 'i': plots[1].id, 'static': False},
{'w': 6, 'h': 28, 'x': 6, 'y': 0, 'i': plots[2].id, 'static': False}
]}
)
# And also I'd like the PDOS to be splitted ¿on species
plots[0].split_DOS(on="species").update_settings(Erange=[-10,10])
# And the bands to show the gap
plots[2].update_settings(gap=True, Erange=[-10,10])
And that’s basically it.
Yeah nice but how do I use this session now
You just need to set the session of the GUI:
[15]:
# Maybe you want to save the existing one?
# session.save("My first try.session")
# We initialize the session
new_session = VeryCoolSession()
# And then we just tell the GUI to use it
sisl_gui.set_session(new_session)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_3167/4189676402.py in <module>
5 new_session = VeryCoolSession()
6 # And then we just tell the GUI to use it
----> 7 sisl_gui.set_session(new_session)
NameError: name 'sisl_gui' is not defined
Now, let’s see if this works:
[16]:
new_session.autosync.see_results("SrTiO3")
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_3167/3914800996.py in <module>
----> 1 new_session.autosync.see_results("SrTiO3")
AttributeError: 'VeryCoolSession' object has no attribute 'autosync'
Just take a moment now to admire the simplicity of the previous line and the beauty and usefulness that it can bring to your research.
With this, we end this short but intense tutorial. I hope that I have been able to convince you of the power this gives to you, but if not, thanks for the read anyway :)
Just as a last thing, notice that you can add parameters to the session and they can be tweaked from the GUI. Give a glimpse at the notebook where plot building is explained if you are further interested, there’s a section where parameters are introduced, close to the beggining.
Oh, and by the way, you can load saved sessions just as we did with plots in the Demo Notebook
If there is a request for further tutorials on sessions, we will extend more on the topic, so don’t hesitate to ask.
Cheers!