Over the past couple of months, I’ve been interning at Wolfram and developing a video course on COVID-19 Data Analysis and Visualization.The journey of making this course was extremely rewarding and fun, and I actually just wrote an article on the Wolfram Blog about it! You can read it here. In the process of making this video course, I came across a particular package by Robert Nachbar, a project director at Wolfram Solution. His “CompartmentalModeling” package proved to be very helpful in visually explaining compartmental models and helped me understand them much better early on.
Compartmental models are mathematical models of the evolution of infectious diseases like the flu and COVID-19. They are huge in epidemiology and are the backbone of many public health policy decisions. The essence of these models is people transitioning between multiple "compartments," essentially health states. The simplest is the SIR, or Susceptible-Infected-Recovered, model, in which a susceptible population can contract a disease, move into the infected compartment and then finally into the recovered compartment after they recover. However, as these models get more complex (through adding more compartments such as exposed, quarantined, deceased, etc), they become increasingly hard to visualize and wrap your head around. I thought I'd share a simple way to generate effective diagrams explaining these models, as seen above, using Robert Nachbar's package.

Importing the Package

The package can be obtained from https://www.wolframcloud.com/obj/rnachbar/Published/CompartmentalModeling.wl. To load it into a notebook, we can simply use the Needs function and follow the package name with a backquote (`):
In[]:=
Needs["CompartmentalModeling`"]

Generating the Backbone

We will start with the simple text diagram, something like this one:

βλ[t]
→
ℐ
infection
ℐ
γ
→
ℛ
recovery
This model outlines that the compartmental model is an SIR model where S feeds into I, and I feeds into R, and the rates of change are β λ[t] and γ, respectively. This diagram does not actually need the CompartmentalModeling package. In fact, one can generate this representation using the Grid function.
In[]:=

βλ[t]
→
ℐ,"infection",ℐ
γ
→
ℛ,"recovery"​​Grid
βλ[t]
→
ℐ,"infection",ℐ
γ
→
ℛ,"recovery",Alignment{{Center,Left}},Spacings3,BaseStyle{18}
Out[]=

βλ[t]
→
ℐ,infection,ℐ
γ
→
ℛ,recovery
Out[]=

βλ[t]
→
ℐ
infection
ℐ
γ
→
ℛ
recovery
To enter text above the arrows, simply select them and press Ctrl+7.
​
We can vary some of the options here:
In[]:=
Grid
βλ[t]
→
ℐ,"infection",ℐ
γ
→
ℛ,"recovery",Alignment{{Left,Right}},Spacings5,BaseStyle{24},BackgroundLightBlue
Out[]=

βλ[t]
→
ℐ
infection
ℐ
γ
→
ℛ
recovery

Using the Package to get the Diagram

The next step, generating the schematic diagram, is also very simple. One can simply take the code we typed above and insert it into the CompartmentalModelGraph function from our package.
In[]:=
?CompartmentalModelGraph
Out[]=
Symbol
CompartmentalModelGraph[model] gives a Graph of model comprised of Transitions after converting to a Petri net. Vertices representing compartments are colored blue, and those representing Transitions are colored red.
In[]:=
CompartmentalModelGraph
βλ[t]
→
ℐ,ℐ
γ
→
ℛ
Out[]=
The blue boxes are compartments while the red boxes indicate the rates of change. This diagram is really a representation of a set of differential equations describing the evolution of a particular infectious disease.

Customizing the Diagram

There are many options we can customize here. What we are dealing with is a graph, so we can use the GraphLayout option and others relevant to graphs to customize our schematic diagram.
CompartmentalModelGraph
βλ[t]
→
ℐ,ℐ
γ
→
ℛ,GraphLayout{"LayeredDigraphEmbedding","Orientation"Left},BaseStyle{18},ImageSizeLarge
Out[]=
Here’s another graph layout:
In[]:=
CompartmentalModelGraph
βλ[t]
→
ℐ,ℐ
γ
→
ℛ,GraphLayout{"LayeredEmbedding","Orientation"Left},BaseStyle{18},ImageSizeLarge
Out[]=
​
And another one:
In[]:=
CompartmentalModelGraph
βλ[t]
→
ℐ,ℐ
γ
→
ℛ,GraphLayout{"TutteEmbedding"},BaseStyle{18},ImageSizeLarge
Out[]=
We can even keep the graph as an abstract set of vertices and edges:
In[]:=
CompartmentalModelGraph
βλ[t]
→
ℐ,ℐ
γ
→
ℛ,GraphLayout{"None"},BaseStyle{18},ImageSizeLarge
Out[]=
Graph
Vertex count: 5
Edge count: 4

My favorite layout by far is the LayeredDigraphEmbedding, but to each their own! We can also try out different, more complex models. Let’s take a look at the SEIQRD, or Susceptible-Exposed-Infected-Quarantined-Recovered-Deceased, model.
In[]:=
GridmodelGrid=
βλ[t]
→
ℰ,"infection",ℰ
ζ
→
ℐ,"incubation",ℐ
δ
→
,"quarantine",ℐ
γ
→
ℛ,"recovery",
γ
→
ℛ,"recovery",ℐ
μ
→
,"death",
μ
→
,"death",Alignment{{Center,Left}},Spacings3,BaseStyle{18}
Out[]=

βλ[t]
→
ℰ
infection
ℰ
ζ
→
ℐ
incubation
ℐ
δ
→

quarantine
ℐ
γ
→
ℛ
recovery

γ
→
ℛ
recovery
ℐ
μ
→

death

μ
→

death
Now putting our input into the CompartmentalModelGraph function:
In[]:=
model=First/@modelGrid;​​CompartmentalModelGraph[model,GraphLayout{"LayeredDigraphEmbedding","Orientation"Left},BaseStyle{18},ImageSizeLarge]
This would have been very difficult to do by hand! That is why the CompartmentalModelGraph function can be so useful. Through its simplicity and quickness, it can be used in many ways to teach, apply, and research compartmental models. This package has much more to it, and a lot of the applications can be found in Robert Nachbar’s community post: https://community.wolfram.com/groups/-/m/t/1896178.
​
Will you be using this package? Let me know!