In the previous article, I posted a program that predicts the behavior of the new coronavirus in the SEIR model. This time, we have made the program into a GUI, so we will share the contents.
`Previous article: I tried to predict the behavior of the new coronavirus with the SEIR model. `` Link: https://qiita.com/kotai2003/items/ed28fb723a335a873061

Currently, many research papers have been published to estimate SEIR parameters from the cases of new coronavirus cases. This time, I will calculate the SEIR model with the parameter estimates published in the paper published on February 16. (Reference 2)
| Parameter | Mainland China (excluding Hubei) | Hubei (excluding Wuhan) | Wuhan |
|---|---|---|---|
| Population N(million) | 1340 | 45 | 14 |
| Infection rate[beta] | 1.0 | 1.0 | 1.0 |
| Latency period (days) | 2 | 2 | 2 |
| infectious_period (days) | 6.6 | 7.2 | 7.4 |
| E_0 | 696 | 592 | 318 |
| I_0 | 652 | 515 | 389 |
For example, [Social Distance Strategy](https://ja.wikipedia.org/wiki/%E7%A4%BE%E4%BC%9A%E8%B7%9D%E9%9B%A2%E6%88%A6 With% E7% 95% A5), it is possible to simulate how the peak of infected people fluctuates when the infection rate drops from 0.5 to 0.4.
### Case 2: Infection rate 0.4
The peak of Infections has dropped and the timing has moved to the right.
With such calculations, it is possible to confirm the effect of the "Purpose of Countermeasures (Basic Concept)" announced on February 23 by the government's Headquarters for Countermeasures against Coronavirus Infectious Diseases.
main_routine.py
import tkinter as tk
from tkinter import ttk
from tkinter import Menu
from tkinter import messagebox
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from calcSEIR import SEIR_EQ
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()
self.master.geometry("1000x600")
self.master.title("SEIR Epidemic Model Simulator")
self.create_widgets()
def create_widgets(self):
#Canvas Frame
self.canvas_frame = tk.Frame(self)
self.canvas_frame.configure(width=600, height=480)
self.canvas_frame.grid(row=0, column=0)
self.canvas_frame.grid(padx = 20, pady=20)
#Label Frame for Input Parameters
self.frame_param = tk.LabelFrame( self )
self.frame_param.configure( text=' Input Paramaters ' )
self.frame_param.grid( row=0, column=1 )
self.frame_param.grid( padx=20, pady=20 )
#1. Population
#Label_population
self.label_popu = tk.Label( self.frame_param)
self.label_popu.configure(text ='Population (Million)')
self.label_popu.grid(row =0, column = 0)
#Scale population
self.var_popu = tk.DoubleVar() #scale variable
self.scale_popu = tk.Scale( self.frame_param)
self.scale_popu.configure(orient="horizontal")
self.scale_popu.configure(from_=1, to= 1350)
self.scale_popu.configure(variable=self.var_popu)
self.scale_popu.grid(row=0, column=1)
#2. Infection Rate
# Label_Infection_Rate
self.label_IR = tk.Label( self.frame_param )
self.label_IR.configure( text='Infection Rate' )
self.label_IR.grid( row=1, column=0 )
# Scale Infection_Rate
self.var_IR = tk.DoubleVar() # scale variable
self.scale_IR = tk.Scale( self.frame_param )
self.scale_IR.configure( orient="horizontal" )
self.scale_IR.configure( from_=0.1, to=2 , resolution=0.1)
self.scale_IR.configure( variable=self.var_IR )
self.scale_IR.grid( row=1, column=1 )
#3. Latency Period
# Label_
self.label_LP = tk.Label( self.frame_param )
self.label_LP.configure( text='Latency Period (days)' )
self.label_LP.grid( row=2, column=0 )
# Scale
self.var_LP = tk.IntVar() # scale variable
self.scale_LP = tk.Scale( self.frame_param )
self.scale_LP.configure( orient="horizontal" )
self.scale_LP.configure( from_=1, to=14 , resolution=0.1)
self.scale_LP.configure( variable=self.var_LP )
self.scale_LP.grid( row=2, column=1 )
# 3.5 Infection Period
# Label_
self.label_IP = tk.Label( self.frame_param )
self.label_IP.configure( text='Infections Period (days)' )
self.label_IP.grid( row=3, column=0 )
# Scale
self.var_IP = tk.IntVar() # scale variable
self.scale_IP = tk.Scale( self.frame_param )
self.scale_IP.configure( orient="horizontal" )
self.scale_IP.configure( from_=1, to=14, resolution=0.1 )
self.scale_IP.configure( variable=self.var_IP )
self.scale_IP.grid( row=3, column=1 )
#4 E_0
self.label_E0 = tk.Label( self.frame_param )
self.label_E0.configure( text='E(t=0)' )
self.label_E0.grid( row=4, column=0 )
#Entry
self.Entry_E0 = tk.Entry(self.frame_param)
self.Entry_E0.grid(row=4, column=1)
self.Entry_E0.insert(tk.END,"696")
#5 I_0
self.label_I0 = tk.Label( self.frame_param )
self.label_I0.configure( text='I(t=0)' )
self.label_I0.grid( row=5, column=0 )
# Entry
self.Entry_I0 = tk.Entry( self.frame_param )
self.Entry_I0.grid( row=5, column=1 )
self.Entry_I0.insert( tk.END, "652" )
#6 R_0
self.label_R0 = tk.Label( self.frame_param )
self.label_R0.configure( text='E(t=0)' )
self.label_R0.grid( row=6, column=0 )
# Entry
self.Entry_R0 = tk.Entry( self.frame_param )
self.Entry_R0.grid( row=6, column=1 )
self.Entry_R0.insert( tk.END, "0" )
#7 Time
self.label_time = tk.Label(self.frame_param)
self.label_time.configure( text = 'Time [days]')
self.label_time.grid(row=7, column=0)
self.var_time = tk.IntVar() # scale variable
self.scale_time = tk.Scale( self.frame_param )
self.scale_time.configure( orient="horizontal" )
self.scale_time.configure( from_=10, to=500, resolution=1 )
self.scale_time.configure( variable=self.var_time )
self.scale_time.grid( row=7, column=1 )
#Basic Reproduction Number
# Label Frame result
self.frame_basicR0 = tk.LabelFrame( self )
self.frame_basicR0.configure( text=' Basic Reproduction Number ' )
self.frame_basicR0.grid( row=2, column=1 )
self.frame_basicR0.grid( padx=20, pady=20 )
self.label_basicR0 = tk.Label(self.frame_basicR0)
self.label_basicR0.grid(row = 0, column=0)
self.label_basicR0.configure(text = ' R0 is ')
self.msg_basicR0 = tk.Message(self.frame_basicR0)
self.msg_basicR0.grid(row=0, column=1)
self.msg_basicR0.configure(text ='')
# Button
##Label Frame for Buttons
# Label Frame for Input Parameters
self.frame_button = tk.LabelFrame( self )
self.frame_button.configure( text=' Operation ' )
self.frame_button.grid( row=2, column=0 )
self.frame_param.grid( padx=20, pady=20 )
#button
# Plot (Rungekutta. Plot..Canvas..)
self.button_plot = tk.Button( self.frame_button )
self.button_plot.configure( text='Calculate & Plot' )
self.button_plot.grid( column=0, row=1 )
self.button_plot.configure( command=self.plotCalc )
self.button_plot.configure(width = 20, height=2)
# Quit Button
self.button_quit = tk.Button( self.frame_button )
self.button_quit.config( text='Quit' )
self.button_quit.grid( column=2, row=1 )
self.button_quit.configure( command=self.quit_app )
self.button_quit.configure( width = 15, height=2 )
## Event Call Back
def plotCalc(self):
# parameters
self.t_max = self.var_time.get() # days
self.dt = 0.01
# initial_state
self.N_pop = 1e6*self.var_popu.get()
self.E_0 = int(self.Entry_E0.get())
self.I_0 = int(self.Entry_I0.get())
self.R_0 = int(self.Entry_R0.get())
self.S_0 = self.N_pop - (self.E_0 + self.I_0 + self.R_0)
self.ini_state = [self.S_0, self.E_0, self.I_0, self.R_0] # [S[0],E,[0], I[0], R[0]]
#Infection rate
self.beta_const = self.var_IR.get() #Infection rate
#Rate of getting infection after exposure
self.epsilon_const = 1 / self.var_LP.get()
#Recovery rate and quarantine rate
self.gamma_const = 1 / self.var_IP.get()
#Basic Reproduction number in SEIR model
self.basicR0 = self.beta_const/self.gamma_const +self.beta_const/self.epsilon_const
self.msg_basicR0.configure( text=str(self.basicR0) )
#https://www.fields.utoronto.ca/programs/scientific/10-11/drugresistance/emergence/fred1.pdf
# numerical integration
self.times = np.arange( 0, self.t_max, self.dt )
self.args = (self.beta_const, self.epsilon_const, self.gamma_const, self.N_pop)
# Numerical Solution using scipy.integrate
# Solver SEIR model
self.result = odeint(SEIR_EQ, self.ini_state, self.times, self.args )
## Plotting
# Generate Figure instance
self.fig = plt.Figure()
#Generate Axe instance
#ax1
self.ax1 = self.fig.add_subplot(111)
self.ax1.plot(self.times, self.result)
self.ax1.set_title('SEIR Epidemic model')
self.ax1.set_xlabel('time [days]')
self.ax1.set_ylabel('population [persons]')
self.ax1.legend(['Susceptible', 'Exposed', 'Infectious', 'Removed'])
self.ax1.grid()
#Link to Axe instance to Canvas
#Then show Canvas onto canvas_Frame
self.canvas = FigureCanvasTkAgg( self.fig, self.canvas_frame )
self.canvas.draw()
self.canvas.get_tk_widget().grid(column=0, row=0)
def quit_app(self):
self.Msgbox = tk.messagebox.askquestion( "Exit Applictaion", "Are you sure?", icon="warning" )
if self.Msgbox == "yes":
self.master.destroy()
else:
tk.messagebox.showinfo( "Return", "you will now return to application screen" )
def main():
root = tk.Tk()
app = Application(master=root)#Inherit
app.mainloop()
if __name__ == "__main__":
main()
calcSEIR.py
# Define differential equation of SEIR model
'''
dS/dt = -beta * S * I / N
dE/dt = beta* S * I / N - epsilon * E
dI/dt = epsilon * E - gamma * I
dR/dt = gamma * I
[v[0], v[1], v[2], v[3]]=[S, E, I, R]
dv[0]/dt = -beta * v[0] * v[2] / N
dv[1]/dt = beta * v[0] * v[2] / N - epsilon * v[1]
dv[2]/dt = epsilon * v[1] - gamma * v[2]
dv[3]/dt = gamma * v[2]
'''
def SEIR_EQ(v, t, beta, epsilon, gamma, N ):
return [-beta * v[0] * v[2] / N ,beta * v[0] * v[2] / N - epsilon * v[1],
epsilon * v[1] - gamma * v[2],gamma * v[2]]