===============
Plotting graphs
===============
Sometimes it is useful to visualize your scenario to understand the behavior of mosaik. The plotting helpers in ``mosaik.util`` take the world object and a ``folder`` argument that controls where image files are written.
Optional parameters are `slice` (see below) and `show_plot` (default: True). With `show_plot` you can control if a window is opened to show the plot in an interactive window. If set to false, the plot is stored directly. If set to true, you can interact with the plot and the chosen view in stored after you close the window.
There are five different plots available:
.. code-block:: Python
world = mosaik.World(SIM_CONFIG, debug=True)
...
mosaik.util.plot_df_graph(world, folder='util_figures') (uses Matplotlib)
mosaik.util.plot_df_graph_groups(world, html_folder='util_figures') (uses Plotly instead of Matplotlib)
mosaik.util.plot_execution_graph(world, folder='util_figures') (uses Matplotlib)
mosaik.util.plot_execution_time(world, folder='util_figures') (uses Matplotlib)
mosaik.util.plot_execution_time_per_simulator(world, folder='util_figures') (uses Matplotlib)
Depending on the function, you need to install either `matplotlib` or `plotly` in your environment beforehand.
Examples
========
The following examples will be done with the following scenario. This code is just to show
how the connections are set up, so that the graphs can be interpreted accordingly. The
important part is the part where the entities are connected.
.. code-block:: Python
:emphasize-lines: 30,31,32,33
import mosaik.util
# Sim config. and other parameters
SIM_CONFIG = {
'ExampleSim': {
'python': 'simulator_mosaik:ExampleSim',
},
'ExampleSim2': {
'python': 'simulator_mosaik:ExampleSim',
},
'Collector': {
'cmd': '%(python)s collector.py %(addr)s',
},
}
END = 10 # 10 seconds
# Create World
world = mosaik.World(SIM_CONFIG, debug=True)
# Start simulators
examplesim = world.start('ExampleSim', eid_prefix='Model_')
examplesim2 = world.start('ExampleSim2', eid_prefix='Model2_')
collector = world.start('Collector')
# Instantiate models
model = examplesim.ExampleModel(init_val=2)
model2 = examplesim2.ExampleModel(init_val=2)
monitor = collector.Monitor()
# Connect entities
world.connect(model2, model, 'val', 'delta')
world.connect(model, model2, 'val', 'delta', initial_data={"val": 1, "delta": 1}, time_shifted=True, weak=True)
world.connect(model, monitor, 'val', 'delta')
# Create more entities
more_models = examplesim.ExampleModel.create(2, init_val=3)
mosaik.util.connect_many_to_one(world, more_models, monitor, 'val', 'delta')
# Run simulation
world.run(until=END)
mosaik.util.plot_dataflow_graph(world, folder='util_figures')
#mosaik.util.plot_execution_graph(world, folder='util_figures')
#mosaik.util.plot_execution_time(world, folder='util_figures')
#mosaik.util.plot_execution_time_per_simulator(world, folder='util_figures')
Dataflow graph
==============
The dataflow graph shows the direction of the dataflow between the simulators. In the example below,
the ExampleSim simulator sends data to the Collector. The ExampleSim2 sends data to ExampleSim. The
dataflow connection from ExampleSim to ExampleSim2 is both weak (dotted line) and timeshifted (red line),
which can be seen in the red label.
.. figure:: /_static/graphs/dataflowGraph_timeshifted_weak.png
:width: 100%
:align: center
:alt: Dataflow Graph timeshifted weak
Plotly dataflow graph with groups
---------------------------------
If you want to highlight simulator groups directly inside the dataflow
graph, use :func:`mosaik.util.plot_df_graph_groups`. The helper
uses `Plotly `_, so install it via ``pip
install plotly`` before running the example below:
.. literalinclude:: code/dataflow_groups.py
:language: python
:linenos:
When you open the generated ``dataflow_groups.html`` after running the code above,
you should see a graph similar to the one below.
It shows the group overlays in the background (for example ``North Campus`` and
``North Campus / Solar Farm``) together with the weak dataflow edges.
Set ``show_plot=True`` if you want Plotly to immediately open the figure
while the script is running.
.. figure:: /_static/graphs/group_dataflow_graph_example.png
:width: 100%
:align: center
:alt: Group Dataflow Graph
Execution graph
===============
The execution graph shows the order in which the simulators are executed. Differing from the example above,
the connection between ExampleSim and ExampleSim2 is only marked as weak, not as timeshifted.
.. figure:: /_static/graphs/execution_graph_weak.png
:width: 100%
:align: center
:alt: Execution graph weak
If we add back the timeshift parameter, we get an additional arrow from ExampleSim to ExampleSim2. That
is because the data from ExampleSim is used in ExampleSim2 in a timeshifted manner, i.e., from the previous
step. This is the :ref:`Gauss-Seidel scheme `.
.. figure:: /_static/graphs/execution_graph_timeshifted_weak.png
:width: 100%
:align: center
:alt: Execution graph weak timeshifted
Execution time
==============
The execution time graph shows the execution time of the different simulators so that it can be seen
where the simulation takes more or less time. In the example below it can be seen that the Collector
uses comparatively more time than the ExampleSim simulators.
.. figure:: /_static/graphs/executiontime.png
:width: 100%
:align: center
:alt: Execution time
Execution time per simulator
============================
The execution time can also be plotted over the simulation steps per simulator, as can be seen
in the figure below. You can also set the parameter `plot_per_simulator=True`. In that case,
the plots for the different are separated. This is especially useful if the simulators have
different step sizes.
.. figure:: /_static/graphs/execution_time_simulator.png
:width: 100%
:align: center
:alt: Execution time per simulator
Slicing the graphs
==================
If you are especially interested in a certain part of the simulation to be shown you can slice the
time steps for the execution graph, the execution time graph, and the execution time per simulator.
You can use the slicing as with Python list slicing. Jumps are not possible. Below you can see
a few examples:
.. code-block:: Python
mosaik.util.plot_execution_graph(world, folder='util_figures', slice=[-5,-1])
mosaik.util.plot_execution_time(world, folder='util_figures', slice=[0,5])
mosaik.util.plot_execution_time_per_simulator(world, folder='util_figures', slice=[-4,-1])
Below is the execution graph sliced as shown in the example code above.
.. figure:: /_static/graphs/execution_graph_timeshifted_weak_sliced.png
:width: 100%
:align: center
:alt: Execution graph weak timeshifted sliced