13.10. Visualization Toolkit

The simulation scripts described in this chapter are available at STEPS_Example repository.

In this chapter, we’ll use simple models as examples to introduce the use of visualization toolkit described in Python-based geometry preparation and simulation visualization toolkits for STEPS.

API reference of this module can be accessed via API Reference: steps.API_1.visual (Visualization Toolkit)

13.10.1. Prerequisites

The following third-party python packages are required to use the visualization toolkit.

  1. NumPy

  2. PyQt

  3. PyQtGraph

13.10.2. Installation

If the prerequsite packages are installed, the visualization toolkit will be installed along with STEPS following the standard installation.

The toolkit module can be import in Python by

import steps.visual

13.10.3. Examples

13.10.3.1. Visualization of Spatial IP3 Receptor Model

Here we use the IP3 receptor model described in Surface-Volume Reactions (Example: IP3 Model) and its spatial extension in Spatial IP3 Receptor Model to demostrate how to use the visualization toolkit in practice.

13.10.3.1.1. Biochemical Model

We stored the biochemical model as a individual python script, ip3r_model.py,

# IP3 receptor model

import steps.model as smodel
import steps.geom as sgeom

###############################################################################

def getModel():
    mdl = smodel.Model()

    # chemical species objects
    Ca = smodel.Spec('Ca', mdl)                             # Calcium
    IP3 = smodel.Spec('IP3', mdl)                   # IP3

    # receptor state objects
    R = smodel.Spec('R', mdl)                               # IP3 receptor in 'naive' state
    RIP3 = smodel.Spec('RIP3', mdl)                 # bound IP3
    Ropen = smodel.Spec('Ropen', mdl)               # bound IP3 and Ca (open)
    RCa = smodel.Spec('RCa', mdl)                   # 1 bound Ca to inactivation site
    R2Ca = smodel.Spec('R2Ca', mdl)                 # 2 bound Ca to inactivation sites
    R3Ca = smodel.Spec('R3Ca', mdl)                 # 3 bound Ca to inactivation sites
    R4Ca = smodel.Spec('R4Ca', mdl)                 # 4 bound Ca to inactivation sites

    surfsys = smodel.Surfsys('ssys', mdl)

    # The 'forward' binding reactions:
    R_bind_IP3_f = smodel.SReac('R_bind_IP3_f', surfsys, \
        olhs=[IP3], slhs=[R], srhs=[RIP3])
    RIP3_bind_Ca_f = smodel.SReac('RIP3_bind_Ca_f', surfsys, \
        olhs=[Ca], slhs=[RIP3], srhs = [Ropen])
    R_bind_Ca_f = smodel.SReac('R_bind_Ca_f', surfsys, \
        olhs=[Ca], slhs=[R], srhs=[RCa])
    RCa_bind_Ca_f = smodel.SReac('RCa_bind_Ca_f', surfsys, \
        olhs=[Ca], slhs=[RCa],srhs = [R2Ca])
    R2Ca_bind_Ca_f = smodel.SReac('R2Ca_bind_Ca_f', surfsys, \
        olhs=[Ca], slhs= [R2Ca], srhs = [R3Ca])
    R3Ca_bind_Ca_f = smodel.SReac('R3Ca_bind_ca_f', surfsys, \
        olhs=[Ca], slhs=[R3Ca], srhs=[R4Ca])

    # The 'backward' binding reactions:
    R_bind_IP3_b = smodel.SReac('R_bind_IP3_b', surfsys, \
        slhs=[RIP3], orhs=[IP3], srhs=[R])
    RIP3_bind_Ca_b = smodel.SReac('RIP3_bind_Ca_b', surfsys, \
        slhs=[Ropen], orhs=[Ca], srhs=[RIP3])
    R_bind_Ca_b = smodel.SReac('R_bind_Ca_b', surfsys, \
        slhs=[RCa], orhs=[Ca], srhs=[R])
    RCa_bind_Ca_b = smodel.SReac('RCa_bind_Ca_b', surfsys, \
        slhs=[R2Ca], orhs=[Ca], srhs=[RCa])
    R2Ca_bind_Ca_b = smodel.SReac('R2Ca_bind_Ca_b', surfsys, \
        slhs=[R3Ca], orhs=[Ca], srhs= [R2Ca])
    R3Ca_bind_Ca_b = smodel.SReac('R3Ca_bind_ca_b', surfsys, \
        slhs=[R4Ca], orhs=[Ca], srhs=[R3Ca])

    # Ca ions passing through open IP3R channel
    R_Ca_channel_f = smodel.SReac('R_Ca_channel_f', surfsys, \
        ilhs=[Ca], slhs=[Ropen], orhs=[Ca], srhs=[Ropen])
    R_Ca_channel_b = smodel.SReac('R_Ca_channel_b', surfsys, \
        olhs=[Ca], slhs=[Ropen], irhs=[Ca], srhs=[Ropen])

    # The reaction constants
    R_bind_IP3_f.setKcst(1000e6)
    R_bind_IP3_b.setKcst(25800)
    RIP3_bind_Ca_f.setKcst(8000e6)
    RIP3_bind_Ca_b.setKcst(2000)
    R_bind_Ca_f.setKcst(8.889e6)
    R_bind_Ca_b.setKcst(5)
    RCa_bind_Ca_f.setKcst(20e6)
    RCa_bind_Ca_b.setKcst(10)
    R2Ca_bind_Ca_f.setKcst(40e6)
    R2Ca_bind_Ca_b.setKcst(15)
    R3Ca_bind_Ca_f.setKcst(60e6)
    R3Ca_bind_Ca_b.setKcst(20)

    # Corresponds to Ca input ~ 20000/ms for open receptor
    R_Ca_channel_f.setKcst(8e6)
    R_Ca_channel_b.setKcst(8e6)

    return mdl

13.10.3.1.2. Typical STEPS Simulation Routine

In the simulation script, we first import the biocemical model and some standard STEPS modules. We also define the diffuson constants according to publication.

# IP3 receptor mesh simulation

import steps.model as smodel
import steps.geom as swm
import steps.rng as srng
import steps.solver as ssolver

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# DIFFUSION

# Source:
#   Allbritton, N.L., Meyer, T., and Stryer, L. (1992).
#   Range of messenger action of calcium ion and inositol
#   1,4,5-triphosphate. Science 258, 1812-1815.
DCST_Ca = 0.065e-9
DCST_IP3 = 0.283e-9

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

import ip3r_model

# Import model
mdl = ip3r_model.getModel()

We then add a steps.API_1.model.Volsys volume system to the model to host the steps.API_1.model.Diff diffution rules for Calcium and IP3.

volsys = smodel.Volsys('vsys', mdl)

# Fetch reference to Calcium and IP3 Spec objects
Ca = mdl.getSpec('Ca')
IP3 = mdl.getSpec('IP3')

# Create diffusion rules
Ca_diff = smodel.Diff('Ca_diff', volsys, Ca, DCST_Ca)
IP3_diff = smodel.Diff('IP3_diff', volsys, IP3, DCST_IP3)

Now we load the steps.API_1.geom.Tetmesh from file prepared in Spatial IP3 Receptor Model, using steps.API_1.utilities.meshio.loadMesh().

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Import mesh
import steps.utilities.meshio as meshio

mesh = meshio.loadMesh("ip3r_mesh")[0]

We then create the random number generator and the steps.API_1.solver.Tetexact solver, and initialize the simulation by adding molecules into compartments and patch.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Create random number generator
r = srng.create('mt19937', 512)
r.initialize(456)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Create reaction-diffusion solver object
sim = ssolver.Tetexact(mdl, mesh, r)

# Setup initial condition
sim.setCompConc('cyt', 'Ca', 3.30657e-8)
sim.setCompConc('cyt', 'IP3', 2.5e-6)
sim.setCompConc('ER', 'Ca', 150e-6)
sim.setPatchCount('memb', 'R', 16)

The above scripts are typical STEPS simulation routines. With the model, geometry and simulation solver ready, we can now work on constructing the visualization system.

13.10.3.1.3. Visualization Routine

First, we import the visualization module and pyqtgraph module, also create a standard QApplication instance.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Visualization
import pyqtgraph as pg
import steps.visual as visual

# Visualization initialization
app = pg.mkQApp()
13.10.3.1.3.1. Plot Display

Now let’s create a plot display so that we can have a quantitative view of the simulation. We first create a steps.API_1.visual.PlotDisplay instance, which will be the host of all our plots.

# Create plot display
plots = visual.PlotDisplay("IP3 Receptor Model", size = (600, 400))

The steps.API_1.visual.PlotDisplay class provides varies functions for different plotting requirements. For example, steps.API_1.visual.PlotDisplay.addCompSpecPlot() adds a plot to the display, which displays molecule count/Concentration changes during simulation. We can also setup different display features for the plot, such as axis labels, data style, etc. The following code creates a plot showing calcium Concentration changes in cytosol.

# Create Plots
pen = pg.mkPen(color=(255,255,255), width=2)
p = plots.addCompSpecPlot("<span style='font-size: 16pt'>Ca_cyt", sim, "cyt", "Ca", data_size = 1000,y_range= [0, 1e-5], measure = "conc", pen=(255, 0.647 * 255, 0))
p.getAxis('left').setPen(pen)
p.getAxis('bottom').setPen(pen)
p.showGrid(x=True, y=True)
labelStyle = {'color': '#ffffff', 'font-size': '16px'}
p.setLabel('bottom', 'Time', 's', **labelStyle)

The plot display arrange plot items in a grid system. As we’ve completed the above plot, we switch to next row and start creating a new plot which displays molecule changes of “Ropen” species (that is the IP3 receptor at open state) on the membrane patch.

plots.nextRow()

p = plots.addPatchSpecPlot("<span style='font-size: 16pt'>Ropen_memb", sim, "memb", "Ropen", data_size = 1000,y_range= [0, 10], pen=(255, 0, 255))
p.getAxis('left').setPen(pen)
p.getAxis('bottom').setPen(pen)
p.showGrid(x=True, y=True)
p.setLabel('bottom', 'Time', 's', **labelStyle)
13.10.3.1.3.2. Simulation Display

We start working on the actual simulation displays. In this example, we would like to create multiple display windows, one for overview of the complete system, and several others for varies components.

A simulation display can be constructed by creating a steps.API_1.visual.SimDisplay object.

# Create simulation displays
full_display = visual.SimDisplay("Full View", w = 600, h = 400)
ER_display = visual.SimDisplay("ER", w = 600, h = 400)
cytIP3_display = visual.SimDisplay("Cyt IP3", w = 600, h = 400)
cytCa_display = visual.SimDisplay("Cyt Calcium", w = 600, h = 400)
memb_display = visual.SimDisplay("memb", w = 600, h = 400)

Now it is time to add different visual components to the displays. The Visualization toolkit provides two major types of visual components, static and dynamic.

Static components include steps.API_1.visual.VisualCompMesh for Visualizing compartment mesh, and steps.API_1.visual.VisualPatchMesh for Visualizing patch mesh. We create two steps.API_1.visual.VisualCompMesh instances for both cytosol and ER, and a steps.API_1.visual.VisualPatchMesh instance for ER membrane.

# Create static mesh components
ER_view = visual.VisualCompMesh("ER", full_display, mesh, "ER", color = [0.678, 1.000, 0.184, 0.05])
cyt_view = visual.VisualCompMesh("cyt", full_display, mesh, "cyt", color = [0.941, 1.000, 0.941, 0.05])
memb_view = visual.VisualPatchMesh("memb", full_display, mesh, "memb", color = [1.000, 0.973, 0.863, 0.05])

Dynamic components include several variations of molecule visualization components for species in compartments or on patches. Here we use two different components, steps.API_1.visual.VisualCompSpec for visualizing compartmental species such as calcium in ER and cytosol, as well as IP3 in cytosol. And steps.API_1.visual.VisualPatchChannel for visualizing different states of IP3 receptors on ER membrane.

# Create dynamic species components
Ca_ER = visual.VisualCompSpec("Ca_ER", full_display, mesh, sim, "ER", "Ca", [1.000, 0.647, 0.000, 1.0], spec_size = 0.005)
IP3_cyt = visual.VisualCompSpec("IP3_cyt", full_display, mesh, sim, "cyt", "IP3", [1.0, 0.0, 0.0, 1.0], spec_size = 0.005)
Ca_cyt = visual.VisualCompSpec("Ca_cyt", full_display, mesh, sim, "cyt", "Ca", [1.000, 0.647, 0.000, 1.0], spec_size = 0.005)
IP3R_MEMB = visual.VisualPatchChannel("IP3R_memb", full_display, mesh, sim, "memb", {"R" : [0.0, 0.0, 1.0, 1.0], "RIP3" : [1.0, 0.0, 1.0, 0.2], "Ropen" : [1.0, 0.0, 1.0, 1.0], "RCa" : [0.0, 0.0, 1.0, 0.8], "R2Ca" : [0.0, 0.0, 1.0, 0.6], "R3Ca" : [0.0, 0.0, 1.0, 0.4], "R4Ca" : [0.0, 0.0, 1.0, 0.2]}, spec_size = 0.01)

We then add these visual components to associated simulation displays

# Add associated components to individual displays

ER_display.addItem(ER_view) ER_display.addItem(Ca_ER)

cytCa_display.addItem(cyt_view) cytCa_display.addItem(Ca_cyt)

cytIP3_display.addItem(cyt_view) cytIP3_display.addItem(IP3_cyt)

memb_display.addItem(memb_view) memb_display.addItem(IP3R_MEMB)

13.10.3.1.3.3. Simulation Control

The final task is to create a steps.API_1.visual.SimControl controller and assigned simulation and displays to it.

# Add simulation and displays to control
x = visual.SimControl([sim], [ER_display, cytIP3_display, cytCa_display, memb_display, full_display],[plots], end_time= 1.0, upd_interval = 0.0001)

# Enter visualization loop
app.exec_()

13.10.4. Showcase: Plots and Visual Components

One essential step of STEPS simulation visualization is to choose suitable plotting function and visual component based on project requirement. To provide an intuitive concept of each component, here we showcase some examples of them in practice.

13.10.4.1. Plots

13.10.4.1.1. Count/Concentration Plot

13.10.4.1.2. Distribution Plot

13.10.4.2. Visual Component

13.10.4.2.1. Static Component

13.10.4.2.2. Dynamic Component

13.10.4.2.2.1. Diffusive Species
13.10.4.2.2.2. Non-diffusive Channel Species