The Susceptible-Exposed-Infected-Recovered (SEIR) model is a natural extension of the SIR Model, accounting for a fourth category of disease state, Exposure. For this PyFriday Tutorial, we’ll cover how to not only make a quick SEIR model but also how to graph the results. If you’d like a decent background on what all goes into the SIR model conceptually and mathematically, please check out our Epi Explained article for Understanding SIR Models , or to see the more simplistic model in action you can also check out the previous SIR model PyFriday Tutorial article. As usual, if you’d like to play with the code on your own, you can download it through Cody’s Github.

## Step 1: Installing and Loading Necessary Libraries

We have to start with setting up the Python environment by installing and importing the necessary libraries. For this tutorial, we’ll utilize `numpy`

for numerical operations, `scipy`

for solving differential equations, and `plotly`

for interactive visualizations.

`numpy`

is crucial for handling arrays and mathematical functions.`scipy`

offers powerful options for numerical integration and solving differential equations, playing a pivotal role in our model’s computation.`plotly`

enables the creation of dynamic plots, allowing us to present the SIR model’s dynamics, as well as allow for users to see more minute details that otherwise wouldn’t be available.

**Step 2: Defining the SEIR Model**

Incorporating the Exposed compartment modifies our approach from the original SIR model slightly. Now, we have four states: Susceptible (S), Exposed (E), Infected (I), and Recovered (R). The transitions now include a movement from Susceptible to Exposed before individuals become Infectious. Here’s how we set up the SEIR model in Python:

Now on first look this might be a bit strange even to experienced R users as the function seems to do very little with what we’re inputting, but in reality this is because we’re actually going to use this function in yet another function in Step 3. For now though, let’s do a quick run-through of what we’re just set up.

The function takes three arguments:

`time`

: The current time point. While not directly used in the differential equations, it is required by the`odeint`

function from the`scipy`

package.`variables`

: A vector containing the current numbers of susceptible, infected, and recovered individuals (S, E, I, R).`parameters`

: A vector of parameters for the model, specifically`beta`

,`gamma`

,`sigma`

, and`N`

(the total population).

Within the function, we use the `with`

function to combine `variables`

and `parameters`

into a single list, which simplifies accessing these values. The `with`

function allows us to refer to elements of the list directly by their names (e.g., `S`

, `E`

, `I`

, `R`

, `beta`

, `gamma`

, `sigma`

, `N`

) within its code block.

The rates of change for each compartment are then calculated according to the SEIR model equations:

`dS`

: The rate of change of susceptible individuals is the negative product of the infection rate (`beta`

), the number of susceptible individuals (`S`

), and the number of infected individuals (`I`

), divided by the total population (`N`

). This represents the number of new infections per time unit.`dE`

represents the rate of change for the Exposed population, transitioning from Susceptible due to infection and moving towards Infectious as the incubation period ends. The parameter`sigma`

controls the rate at which Exposed individuals become Infectious, adding a new dynamic to the model.`dI`

: The rate of change of infected individuals is the number of new infections (as calculated for`dS`

) minus the number of recoveries, which is the product of the recovery rate (`gamma`

) and the number of infected individuals (`I`

).`dR`

: The rate of change of recovered individuals is simply the number of recoveries, as calculated in the`dI`

equation.

Finally, the function returns a list containing the rates of change for each compartment, which is then used by the `odeint`

function to solve the model over time.

**Step 3: Initial Conditions, Parameters, and Solving**

Before solving the model, we need to specify the initial conditions (i.e., the starting numbers of susceptible, infected, and recovered individuals) and the parameters (`beta`

, `sigma`

, and `gamma`

) which control the disease transmission, incubation period and recovery rates, respectively. Here, we start with a population of 1000 individuals, with only one infected person as the outbreak begins. The parameter values are hypothetical and can be adjusted based on the disease’s characteristics you’re modeling (the incubation period is seen as an inverse, so we have an incubation period of five days, thus a parameter value of 1/5). With the function we already made and initial setup ready, we can now solve the differential equations using `scipy`

‘s `odeint`

function, which will return the solutions to every step from day 0 to day 50.

**Step 4: Visualizing the Outcome with Plotly**

Finally, to understand the dynamics of the disease through time, we’ll visualize the results using `plotly`

. This step transforms the output into a dynamic and interactive plot that can is much easier to understand, and can often wow your desired audience.

This is a fairly simply plotly graph, but it’s worth noting that for each class, we need to create a separate trace for each line, which allows them to act independently of one another.

It should be noted that in Python, graphs often require initialization (hence the empty ` go.Figure()`

call). Otherwise, a lot of this code is actually very similar to how R handles graphing if you are familiar with that. Below is our interactive output:

**Conclusion**

Through this tutorial, we’ve navigated the implementation and visualization of the SEIR model using Python, showcasing the model’s utility in understanding infectious disease dynamics. This model as mentioned earlier is a natural extension of the SIR compartmental model, though by no means should be seen as the last one. In fact, there are dozens of potential compartmental models that include things like vaccination, spatial relationships, and much more.

**Humanities Moment**

This PyFriday Tutorial’s featured image is The Fortune-teller (1857) by Adolph Tidemand (Norwegian, 1814-1876).Adolph Tidemand was a Norwegian romantic nationalism painter known for works like “The Haugeans” and “The Bridal Procession in Hardanger,” painted in collaboration with Hans Gude. He studied in Copenhagen and Düsseldorf, where he developed his style influenced by Norwegian history, eventually becoming renowned for his depictions of Norwegian farm life, contributing to the elevation of peasant culture in art.