Skip to content

Visualizer

COMORBUSS comes with a dynamic visualizer used mostly to monitor particles attributes during simulations and debug new mechanics/modules.

Visualizer module can be loaded by setting the visualizer parameter:

parameters['visualizer'] = {
    'size': (800, 1000),
    'elements': [
        visualizer.elements.AgentsStates(),
        visualizer.elements.AgentsSymptoms(),
        visualizer.elements.Split(
            visualizer.elements.AgentsPlacement(mask="self.comm.srv['Hospitals'].workers_ids"),
            visualizer.elements.AgentsSymptoms(mask="self.comm.srv['Hospitals'].workers_ids"),
            visualizer.elements.AgentsDiagnostics(mask="self.comm.srv['Hospitals'].workers_ids"),
            label = "Hospital workers"
        )
    ],
}

Attention

The visualizer module requires pygame to be installed in the python environment:

python -m pip install pygame

Elements

The visualizations are loaded by passing an list of VisualizerElement objects to the elements parameter.

Available elements:

AgentsConfigs

Parent class for pre-configured agents visualizations.

Parameters:

Name Type Description Default
mask str

An expression to be used as an mask to select agents.

required
label str

An label to show in the visualization.

required

AgentsDiagnostics

Shows diagnostics of agents in the simulation.

AgentsPlacement

Shows placements of agents in the simulation.

AgentsStates

Shows states of agents in the simulation.

AgentsSymptoms

Shows symptoms of agents in the simulation.

AgentsVisualizer

Shows a grid with color coded values for each agent.

Parameters:

Name Type Description Default
expression str or callable

An expression to be evaluated to get agents data or an function that accepts the community as argument and return values.

required
colors list

An list of tuples in the form [(value1, color1), ..., (valuen, colorn)]. Values in between defined colors the color will be interpolated between closest values. 'min' and 'max' keywords can be used instead of absolute values to set the color of the minimum and maximum value respectively. User can pass ('random', seed) to generate random colors to each unique value, where seed is an integer value to a seed a random number generator.

required
legends list

An list of tuples in the form [(value1, label), ..., (valuen, labeln)]. With labels to be used in the legend. If ['unique'] is passed each unique value will be printed in the legend. It can be passed as an functions that accepts the community as argument and returns the label value.

required
label str

Label for the visualization, if not given will use the expression as label.

required

internal_init(self, screen, comm)

Initialization routine, is called during the visualizer module initialization.

Parameters:

Name Type Description Default
screen pygame.surface

Available surface for the element.

required
comm comorbuss.community

Simulation's community.

required
Source code in comorbuss/modules/visualizer/elements.py
303
304
305
306
307
308
309
310
311
312
313
314
def internal_init(self, screen, comm):
    super().internal_init(screen, comm)

    self.labels = pygame.font.SysFont("Liberation Mono", 12)

    self.init_legends(self.param)

    self.subscreen = self.screen.subsurface(
        (2, 16, self.width - self.legend_width - 2, self.height - 16)
    )
    text = self.labels.render(format(self.title), True, (255, 255, 255))
    self.screen.blit(text, (2, 2))

update(self)

Updates the element

Source code in comorbuss/modules/visualizer/elements.py
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
def update(self):
    array = self.eval()
    if self.random_colors:
        unique_values = np.unique(array)
        for value in unique_values:
            if value not in [x for x, _ in self.colors]:
                random_color = self.rng.uniform(0, 1, size=3)
                self.colors.append((value, random_color))
    if self.has_legends:
        if self.unique_legends:
            self.update_legends([(v, str(v)) for v in np.unique(array)])
    plot_array(
        self.subscreen,
        array,
        min_color=self.min_color,
        max_color=self.max_color,
        intermediary_colors=self.colors,
    )

update_legends(self, legends)

Updates the legends as needed.

Parameters:

Name Type Description Default
legends list

List of legends.

required
Source code in comorbuss/modules/visualizer/elements.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def update_legends(self, legends):
    """Updates the legends as needed.

    Args:
        legends (list): List of legends.
    """
    self.legend_screen.fill((0, 0, 0))
    legends.sort(key=lambda x: x[0])
    nlegend = len(legends)
    box_height = 16 * nlegend
    if box_height > self.legend_screen.get_height():
        nlegend = int(self.legend_screen.get_height() / 16)
        legends = legends[:nlegend]
        box_height = 16 * nlegend
    legend_array = np.array([v for v, _ in legends])
    legend_boxes = self.legend_screen.subsurface((2, 0, 16, box_height))
    plot_array(
        legend_boxes,
        legend_array,
        min_color=self.min_color,
        max_color=self.max_color,
        intermediary_colors=self.colors,
    )
    for i in range(nlegend):
        text = self.labels.render(legends[i][1], True, (255, 255, 255))
        self.legend_screen.blit(text, (20, i * 16 + 2))

DiagnosticsPlot

Shows a plot of the percentage of particles in quarantine during the simulation.

EncountersPlot

Shows a plot of the number of encounters during the simulation.

HistogramPlot

Shows a histogram plot using matplotlib.

Parameters:

Name Type Description Default
expression str or callable

An expression to be evaluated to get plot data or an function that accepts the community as argument and return values.

required

update(self)

Updates the element

Source code in comorbuss/modules/visualizer/elements.py
193
194
195
196
197
def update(self):
    self.get_fig()
    array = self.eval()
    self.plt.hist(array, **self.hist_params)
    self.show_fig()

LinesPlot

Shows an lines plot using matplotlib.

Parameters:

Name Type Description Default
lines list or dict

List or dict of expressions to be evaluated to get plot data or an function that accepts the community as argument and return values. Dictionaries indexes will be used as labels in the plot.

required
x str or callable

An expression to be evaluated to get x values or an function that accepts the community as argument and return x values. X values must have same shape of each line.

required

internal_init(self, screen, comm)

Initialization routine, is called during the visualizer module initialization.

Parameters:

Name Type Description Default
screen pygame.surface

Available surface for the element.

required
comm comorbuss.community

Simulation's community.

required
Source code in comorbuss/modules/visualizer/elements.py
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
def internal_init(self, screen, comm):
    super().internal_init(screen, comm)

    # Check of lines is callable
    if callable(self.lines):
        self.lines = self.lines(self.comm)
    # Stores lines and labels as lists
    if type(self.lines) is dict:
        self.lines_labels = [l for l in self.lines]
        self.lines = [v for v in self.lines.values()]
    else:
        self.lines_labels = self.lines

    # If has no colors and not many lines apply default comorbuss color pallet
    if not self.has_colors and len(self.lines) <= len(S.COLORS_LIST):
        self.colors = S.COLORS_LIST
        self.has_colors = True

update(self)

Updates the element

Source code in comorbuss/modules/visualizer/elements.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
def update(self):
    self.get_fig()
    if self.has_x:
        self.expression = self.param["x"]
        x = self.eval()
    for i in range(len(self.lines)):
        if self.lines_labels[i] not in self.skip:
            self.expression = self.lines[i]
            array = self.eval()
            if self.has_x:
                args = (x, array)
            else:
                args = array
            if self.has_colors:
                kwargs = dict(label=self.lines_labels[i], color=self.colors[i])
            else:
                kwargs = dict(label=self.lines_labels[i])
            self.plt.plot(*args, **kwargs)
    self.plt.legend()
    self.show_fig()

LinesPlotsConfigs

Parent class for pre-configured line plots visualizations.

Parameters:

Name Type Description Default
skip list

List of curves to skip.

required

QuarantinesPlot

Shows a plot of the percentage of particles in quarantine during the simulation.

Split

Splits available space between multiple elements.

Parameters:

Name Type Description Default
*elements VisualizerElement

Elements to show.

required
vertical bool

Splits vertical space instead of horizontal space.

required

cleanup(self)

Cleanup the element.

Source code in comorbuss/modules/visualizer/elements.py
118
119
120
121
def cleanup(self):
    # Cleanup each child element
    for element in self.elements:
        element.cleanup()

internal_init(self, screen, comm)

Initialization routine, is called during the visualizer module initialization.

Parameters:

Name Type Description Default
screen pygame.surface

Available surface for the element.

required
comm comorbuss.community

Simulation's community.

required
Source code in comorbuss/modules/visualizer/elements.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
def internal_init(self, screen, comm):
    super().internal_init(screen, comm)

    # Check if this split has a title,if yes apply it and define subscreen for child elements
    if hasattr(self, "label"):
        self.subscreen = self.screen.subsurface(
            (2, 16, self.width - 2, self.height - 16)
        )
        labels = pygame.font.SysFont("Liberation Mono", 12)
        text = labels.render(format(self.label), True, (255, 255, 255))
        self.screen.blit(text, (2, 2))
    else:
        self.subscreen = self.screen

    # Get number of child elements and available space for each
    nelements = len(self.elements)
    width, height = self.subscreen.get_size()
    if self.vertical:
        element_size = int(height / nelements)
    else:
        element_size = int(width / nelements)
    # Initialize child elements with its respective subscreen
    for i in range(nelements):
        if self.vertical:
            screen = self.subscreen.subsurface(
                (0, i * element_size, width, element_size)
            )
        else:
            screen = self.subscreen.subsurface(
                (i * element_size, 0, element_size, height)
            )
        self.elements[i].internal_init(screen, self.comm)

update(self)

Updates the element

Source code in comorbuss/modules/visualizer/elements.py
113
114
115
116
def update(self):
    # Updates each child element
    for element in self.elements:
        element.update()

StatesPlot

Shows a plot of the percentage of particles in each state during the simulation.

SymptomaticStatesPlot

Shows a plot of the percentage of particles in each symptomatic state in time during the simulation.