# Load the default AiiDA profile.
from aiida import orm, load_profile
load_profile();

AiiDA Viewers#

This module contains the viewers, which are used to visualize AiiDA objects.

How to visualize an AiiDA object#

The simplest way is to import the viewer() function and call it with the object:

from aiidalab_widgets_base import viewer

p = orm.Dict(dict={
    'parameter 1' : 'some string',
    'parameter 2' : 2,
    'parameter 3' : 3.0,
    'parameter 4' : [1, 2, 3],
})
vwr = viewer(p.store(), downloadable=True)
display(vwr)

The function takes two inputs: the object to show and an optional flag for displaying the download button. The function gives back a viewer object for notebook display. If the viewer for the object is not available, the object itself is returned, allowing for a very basic representation of it.

An alternative way is to use the AiidaNodeViewWidget class:

from aiida import orm
from aiidalab_widgets_base import AiidaNodeViewWidget

p = orm.Dict(dict={
    'parameter 1' : 'some string',
    'parameter 2' : 2,
    'parameter 3' : 3.0,
    'parameter 4' : [1, 2, 3],
})
wdgt = AiidaNodeViewWidget(node=p.store())
display(wdgt)

Using the AiidaNodeViewWidget lets you visualize different AiiDA objects without making a new widget. Just update the node attribute of the widget as in the example below:

from aiida import plugins
from ase.build import molecule

m = molecule('H2O')
m.center(vacuum=2.0)

StructureData = plugins.DataFactory('core.structure')
s = StructureData(ase=m)

wdgt.node = s.store()

When you update the node attribute, the widget will automatically refresh and display the new object, such as a water molecule in this case.

Build-in viewers#

The viewers for several AiiDA objects are available:

  • DictViewer for the orm.Dict object representation.

  • StructureDataViewer for the orm.StructureData and orm.CifData object representation.

  • FolderDataViewer for the orm.FolderDataViewer object representation.

  • BandsDataViewer for the orm.BandsData object representation.

  • ProcessNodeViewerWidget for the orm.ProcessNode (and its children such as orm.CalcJobNode or orm.WorkChainNode) object representation.

  • and others…

To see the full list of available viewers, visit the module API documentation.

List of build-in viewers#

In this section, we list the build-in viewers and show how to use them.

Dict viewer#

The DictViewer is used to visualize dictionaries.

from aiidalab_widgets_base.viewers import DictViewer
from aiida import plugins

Dict = plugins.DataFactory('core.dict')
p = Dict(dict={
    'Parameter' :'super long string '*4,
    'parameter 2' :'value 2',
    'parameter 3' : 1,
    'parameter 4' : 2,
})
vwr = DictViewer(p.store(), downloadable=True)
display(vwr)

CifData and StructureData viewer#

The StructureDataViewer is used to visualize both CifData`` and StructureData`` objects.

from ase.build import molecule, bulk
from aiidalab_widgets_base.viewers import StructureDataViewer


# create bulk Pt
pt = bulk('Pt', cubic = True)

# Cif data.
CifData = plugins.DataFactory('core.cif')
s = CifData(ase=pt)
vwr_cif = StructureDataViewer(s.store())
display(vwr_cif)

# Structure data.
m = molecule('H2O')
m.center(vacuum=2.0)

StructureData = plugins.DataFactory('core.structure')
s = StructureData(ase=m)
vwr_structure = StructureDataViewer(s.store())
display(vwr_structure)

BandsData viewer#

The BandsDataViewer is used to visualize BandsData objects.

import numpy as np
from aiida import plugins
from aiidalab_widgets_base.viewers import BandsDataViewer

BandsData = plugins.DataFactory('core.array.bands')
bs = BandsData()
kpoints = np.array([[0.    , 0.    , 0.    ], # array shape is 12 * 3
       [0.1   , 0.    , 0.1   ],
       [0.2   , 0.    , 0.2   ],
       [0.3   , 0.    , 0.3   ],
       [0.4   , 0.    , 0.4   ],
       [0.5   , 0.    , 0.5   ],
       [0.5   , 0.    , 0.5   ],
       [0.525 , 0.05  , 0.525 ],
       [0.55  , 0.1   , 0.55  ],
       [0.575 , 0.15  , 0.575 ],
       [0.6   , 0.2   , 0.6   ],
       [0.625 , 0.25  , 0.625 ]])

bands = np.array([
    [-5.64024889,  6.66929678,  6.66929678,  6.66929678,  8.91047649], # array shape is 12 * 5, where 12 is the size of the kpoints mesh
    [-5.46976726,  5.76113772,  5.97844699,  5.97844699,  8.48186734], # and 5 is the number of states
    [-4.93870761,  4.06179965,  4.97235487,  4.97235488,  7.68276008],
    [-4.05318686,  2.21579935,  4.18048674,  4.18048675,  7.04145185],
    [-2.83974972,  0.37738276,  3.69024464,  3.69024465,  6.75053465],
    [-1.34041116, -1.34041115,  3.52500177,  3.52500178,  6.92381041],
    [-1.34041116, -1.34041115,  3.52500177,  3.52500178,  6.92381041],
    [-1.34599146, -1.31663872,  3.34867603,  3.54390139,  6.93928289],
    [-1.36769345, -1.24523403,  2.94149041,  3.6004033 ,  6.98809593],
    [-1.42050683, -1.12604118,  2.48497007,  3.69389815,  7.07537154],
    [-1.52788845, -0.95900776,  2.09104321,  3.82330632,  7.20537566],
    [-1.71354964, -0.74425095,  1.82242466,  3.98697455,  7.37979746]])
bs.set_kpoints(kpoints)
bs.set_bands(bands)
labels = [(0, u'GAMMA'),
          (5, u'X'),
          (6, u'Z'),
          (11, u'U')]
bs.labels = labels


vwr = BandsDataViewer(bs.store(), downloadable=True)
display(vwr)

FolderData viewer#

The FolderDataViewer is used to visualize FolderData objects.

import io
from aiida import plugins
from aiidalab_widgets_base.viewers import FolderDataViewer

FolderData = plugins.DataFactory('core.folder')
fd = FolderData()
with io.StringIO('content of test1 file') as fobj:
    fd.put_object_from_filelike(fobj, path='test1.txt')
with io.StringIO('content of test2 file') as fobj:
    fd.put_object_from_filelike(fobj, path='test2.txt')
with io.StringIO(u'content of test_long file'*1000) as fobj:
    fd.put_object_from_filelike(fobj, path='test_long.txt')
vwr = viewer(fd.store(), downloadable=True)
display(vwr)

ProcessNode viewer#

The ProcessNodeViewerWidget is used to visualize CalcFunctionNode and WorkFunctionNode objects.

from aiida.workflows.arithmetic.add_multiply import add, add_multiply
from aiida import engine, orm
from aiidalab_widgets_base.viewers import ProcessNodeViewerWidget
result, workfunction = engine.run_get_node(add_multiply, orm.Int(3), orm.Int(4), orm.Int(5))
vwr_workfunction = ProcessNodeViewerWidget(workfunction)
display(vwr_workfunction)

result, calcfunction = engine.run_get_node(add, orm.Int(3), orm.Int(4))
vwr_calcfunction = ProcessNodeViewerWidget(calcfunction)
display(vwr_calcfunction)

Create a custom viewer#

To create a custom viewer one usually inherits from an existing ipywidgets widget and implements the logic for displaying the object. The only requirement is that the first argument of the constructor is the object to visualize.

Also to make the new class recognizable by the viewer() function, the class should be decorated with the register_viewer_widget() decorator.

To demonstrate how this works we create a simple viewer for the orm.Int object:

from aiidalab_widgets_base import register_viewer_widget
import ipywidgets as ipw
from aiida.orm import Int

@register_viewer_widget('data.core.int.Int.')
class IntViewerWidget(ipw.HTML):
    def __init__(self, node, **kwargs):
        super().__init__(**kwargs)
        self.value = f'Int object: <b>{node.value}<b>'

vwr = viewer(orm.Int(3).store())
display(vwr)

The string to be put as an argument of the register_viewer_widget decorator can be obtained from the node_type property of an object.

i_node = orm.Int(1)
print(i_node.node_type)