Visualizing Computation Graphs¶
Loman supports viewing computations as graphs using the open source Graphviz graph visualization software.
By default, in a Jupyter notebook, when a graph is evaluated, it will show a graphical representation of its computation dependencies and its state:
>>> from loman import *
>>> comp = Computation()
>>> comp.add_node('a', value=1)
>>> comp.add_node('b', lambda a: a + 1)
>>> comp.add_node('c', lambda a: 2 * a)
>>> comp.add_node('d', lambda b, c: b + c)
>>> comp.compute_all()
>>> comp
This can also be achieved using the .draw() method, which allows some customization of drawing:
>>> comp.draw()
And the .view() method will produce a graphical representation as a pdf,and display it in the default external pdf viewer - this can be useful to keep a view of the computation graph while making other changes in a notebook.
State information¶
The following example has been contrived to show every state currently supported by Loman:
>>> comp = Computation()
>>> comp.add_node('a', value=1)
>>> comp.add_node('e', lambda a: 1)
>>> comp.add_node('b', lambda a, doesnotexist: 1)
>>> comp.add_node('c', lambda a: a / 0.)
>>> comp.add_node('d', lambda b, c: b + c)
>>> comp.compute('c')
| Color | State | Meaning |
|---|---|---|
| Blue | UNINITIALIZED | Node has been created, but does not contain a value |
| Green | UPTODATE | Node has been set/calculated and is up-to-date |
| Yellow | STALE | Upstream nodes have been recalculated, so value is stale |
| Green-Yellow | COMPUTABLE | Value is stale/does not exist, but all immediate parent nodes are up-to-date, so node can be recalculated immediately |
| Red | ERROR | An error was encountered while calculating this node. Value will contain the Exception object and a Traceback object. |
| Orange | PLACEHOLDER | This node was referenced by another node, but has not yet been defined, so a placeholder has been created, pending the definition of this node. |
Showing timing information¶
Loman can also draw graph nodes to show timing information. In the following example, we deliberately create some nodes that are slow to calculate. We can the use Computation.draw(colors='timing') to show which nodes are slow to compute (green is fastest, red is slowest). This can be useful for diagnosing bottlenecks in complex computations.
from loman import *
import time
@ComputationFactory
class ExampleComputation:
a = input_node()
@calc_node
def b(self, a):
time.sleep(1)
return a + 1
@calc_node
def c(self, a):
time.sleep(2)
return 2 * a
@calc_node
def d(self, b, c):
time.sleep(3)
return b + c
>>> comp = ExampleComputation()
>>> comp.insert('a', 3)
>>> comp.compute_all()
>>> comp.draw(colors='timing')
Styling¶
You can control how nodes are rendered using the style keyword of the add_node method or calc_node decorator. Two styles are currently supported: 'small' and 'dot'. This can be useful to de-emphasize nodes in complex computations:
>>> comp = Computation()
>>> comp.add_node('a', value=1, style='small')
>>> comp.add_node('b', lambda a: a + 1, style='dot')
>>> comp.add_node('c', lambda a: 2 * a, style='dot')
>>> comp.add_node('d', lambda b, c: b + c)
>>> comp.compute_all()
>>> comp
Showing type information¶
You can ask loman to graphically show type information for nodes by calling draw with the keyword argument shape='type'. This example shows how different types are shown:
>>> import numpy as np, pandas as pd
>>> comp = Computation()
>>> comp.add_node('scalar', value=1)
>>> comp.add_node('array', lambda scalar: np.array([scalar]))
>>> comp.add_node('dataframe', lambda scalar: pd.DataFrame([[1]], columns=['A']))
>>> comp.add_node('list', lambda scalar: [scalar])
>>> comp.add_node('tuple', lambda scalar: (scalar,))
>>> comp.add_node('dict', lambda scalar: {'a': scalar})
>>> comp.add_node('computation', lambda scalar: Computation())
>>> comp.add_node('other', lambda scalar: object())
>>> comp.compute_all()
>>> comp.draw(shapes='type')