Note
This tutorial can be downloaded and run as a Jupyter Notebook: visualising_graphs.ipynb
The provenance graph of a database can be visually inspected, via graphviz, using both the python API and command-line interface.
verdi graph generate -h
We first load the database and required modules:
from aiida import load_profile
profile = load_profile()
from aiida.common import LinkType
from aiida.orm.utils.links import LinkPair
from aiida.backends.tests.utils.archives import get_archive_file
from aiida.tools.visualization import Graph, pstate_node_styles
The example provenance graph, used in this tutorial, can then be imported into the database:
archive_path = get_archive_file('graph1.aiida', 'graphs')
!verdi import -n {archive_path}
dict1_uuid = '0ea79a16-501f-408a-8c84-a2704a778e4b'
calc1_uuid = 'b23e692e-4e01-48dd-b515-4c63877d73a4'
The :py~aiida.tools.visualization.graph.Graph
class is used to store visual representations of the nodes and edges, which can be added separately or cumulatively by one of the graph traversal methods. The :py~aiida.tools.visualization.graph.Graph.graphviz
attribute returns a graphviz.Digraph instance, which will auto-magically render the graph in the notebook, or can be used to save the graph to file.
graph = Graph()
graph.add_node(dict1_uuid)
graph.add_node(calc1_uuid)
graph.graphviz
graph.add_edge(
dict1_uuid, calc1_uuid,
link_pair=LinkPair(LinkType.INPUT_CALC, "input1"))
graph.graphviz
graph.add_incoming(calc1_uuid)
graph.add_outgoing(calc1_uuid)
graph.graphviz
The :py~aiida.tools.visualization.graph.Graph
can also be initialized with global style attributes, as outlined in the graphviz attributes table.
graph = Graph(node_id_type="uuid",
global_node_style={"penwidth": 1},
global_edge_style={"color": "blue"},
graph_attr={"size": "6,6!", "rankdir": "LR"})
graph.add_incoming(calc1_uuid)
graph.add_outgoing(calc1_uuid)
graph.graphviz
Additionally functions can be parsed to the :py~aiida.tools.visualization.graph.Graph
initializer, to specify exactly how each node will be represented. For example, the :py~aiida.tools.visualization.graph.pstate_node_styles
function colors process nodes by their process state.
def link_style(link_pair, **kwargs):
return {"color": "blue"}
graph = Graph(node_style_fn=pstate_node_styles,
link_style_fn=link_style,
graph_attr={"size": "6,6!", "rankdir": "LR"})
graph.add_incoming(calc1_uuid)
graph.add_outgoing(calc1_uuid)
graph.graphviz
Edges can be annotated by one or both of their edge label and link type.
graph = Graph(graph_attr={"size": "6,6!", "rankdir": "LR"})
graph.add_incoming(calc1_uuid,
annotate_links="both")
graph.add_outgoing(calc1_uuid,
annotate_links="both")
graph.graphviz
The ~aiida.tools.visualization.graph.Graph.recurse_descendants
and ~aiida.tools.visualization.graph.Graph.recurse_ancestors
methods can be used to construct a full provenance graph.
graph = Graph(graph_attr={"size": "8,8!", "rankdir": "LR"})
graph.recurse_descendants(
dict1_uuid,
include_process_inputs=True,
annotate_links="both"
)
graph.graphviz
The link types can also be filtered, to view only the ‘data’ or ‘logical’ provenance.
graph = Graph(graph_attr={"size": "8,8!", "rankdir": "LR"})
graph.recurse_descendants(
dict1_uuid,
include_process_inputs=True,
annotate_links="both",
link_types=("input_calc", "create")
)
graph.graphviz
graph = Graph(graph_attr={"size": "8,8!", "rankdir": "LR"})
graph.recurse_descendants(
dict1_uuid,
include_process_inputs=True,
annotate_links="both",
link_types=("input_work", "return")
)
graph.graphviz