T6 - Using analyzers#

Analyzers are objects that do not change the behavior of a simulation, but just report on its internal state, almost always something to do with sim.people. This tutorial takes you through some of the built-in analyzers and gives a brief example of how to build your own.

Click here to open an interactive version of this notebook.

Age histograms and snapshots#

Age histograms and snapshots both take “pictures” of the sim.people object at specified points in time. This is because while most of the information from sim.people is retrievable at the end of the sim from the stored events, it’s much easier to see what’s going on at the time. While the snapshot literally just makes a copy of the people object, the age histogram calculates results for different age bins:

[1]:
import covasim as cv
cv.options(jupyter=True, verbose=0)

sim = cv.Sim(interventions=cv.test_prob(0.5), analyzers=cv.age_histogram())
sim.run()
agehist = sim.get_analyzer() # Only one analyzer so we can retrieve it like this
agehist.plot()
Covasim 3.1.6 (2024-01-28) — © 2020-2024 by IDM
../_images/tutorials_tut_analyzers_3_1.png

Transmission trees#

Another useful analysis to perform on the simulation is to calculate the transmission tree – i.e., who infected whom. Since all this information is stored in the sim, it doesn’t have to be inserted at run time; it can be added to an already finished simulation:

[2]:
tt = sim.make_transtree()
fig1 = tt.plot()
fig2 = tt.plot_histograms()
../_images/tutorials_tut_analyzers_5_0.png
../_images/tutorials_tut_analyzers_5_1.png

Custom analyzers#

Analyzers don’t have to be complicated. While analyzers can derive from the cv.Analyzer class, they can also just be simple functions, unless they need to keep track of or update internal state. Here’s an example of an analyzer that does keep track of internal state, namely by storing and plotting the S, E, I, and R compartments over time.

[3]:
import pylab as pl
import sciris as sc
import covasim as cv

class store_seir(cv.Analyzer):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs) # This is necessary to initialize the class properly
        self.t = []
        self.S = []
        self.E = []
        self.I = []
        self.R = []
        return

    def apply(self, sim):
        ppl = sim.people # Shorthand
        self.t.append(sim.t)
        self.S.append(ppl.susceptible.sum())
        self.E.append(ppl.exposed.sum() - ppl.infectious.sum())
        self.I.append(ppl.infectious.sum())
        self.R.append(ppl.recovered.sum() + ppl.dead.sum())
        return

    def plot(self):
        pl.figure()
        pl.plot(self.t, self.S, label='S')
        pl.plot(self.t, self.E, label='E')
        pl.plot(self.t, self.I, label='I')
        pl.plot(self.t, self.R, label='R')
        pl.legend()
        pl.xlabel('Day')
        pl.ylabel('People')
        sc.setylim() # Reset y-axis to start at 0
        sc.commaticks() # Use commas in the y-axis labels
        return

sim = cv.Sim(n_days=180, analyzers=store_seir(label='seir'))
sim.run()
seir = sim.get_analyzer('seir') # Retrieve by label
seir.plot()

And here’s an example of an analyzer that doesn’t need any internal state, so it can just be a function: it simply reports if anyone aged 88 is currently infected.

[4]:
def check_88(sim):
    people_who_are_88 = sim.people.age.round() == 88 # Find everyone who's aged 88 (to the nearest year)
    people_exposed = sim.people.exposed # Find everyone who's infected with COVID
    people_who_are_88_with_covid = cv.true(people_who_are_88 * people_exposed) # Multiplication is the same as logical "and"
    n = len(people_who_are_88_with_covid) # Count how many people there are
    if n:
        print(f'Oh no! {n} people aged 88 have covid on timestep {sim.t} {"🤯"*n}')
    return

sim = cv.Sim(n_days=120, analyzers=check_88, verbose=0)
sim.run()
Oh no! 2 people aged 88 have covid on timestep 20 🤯🤯
Oh no! 2 people aged 88 have covid on timestep 21 🤯🤯
Oh no! 2 people aged 88 have covid on timestep 22 🤯🤯
Oh no! 2 people aged 88 have covid on timestep 23 🤯🤯
Oh no! 3 people aged 88 have covid on timestep 24 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 25 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 26 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 27 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 28 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 29 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 30 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 31 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 32 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 33 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 34 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 35 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 36 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 37 🤯🤯🤯
Oh no! 4 people aged 88 have covid on timestep 38 🤯🤯🤯🤯
Oh no! 5 people aged 88 have covid on timestep 39 🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 40 🤯🤯🤯🤯🤯🤯
Oh no! 7 people aged 88 have covid on timestep 41 🤯🤯🤯🤯🤯🤯🤯
Oh no! 7 people aged 88 have covid on timestep 42 🤯🤯🤯🤯🤯🤯🤯
Oh no! 8 people aged 88 have covid on timestep 43 🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 12 people aged 88 have covid on timestep 44 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 12 people aged 88 have covid on timestep 45 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 14 people aged 88 have covid on timestep 46 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 15 people aged 88 have covid on timestep 47 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 15 people aged 88 have covid on timestep 48 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 16 people aged 88 have covid on timestep 49 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 17 people aged 88 have covid on timestep 50 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 16 people aged 88 have covid on timestep 51 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 15 people aged 88 have covid on timestep 52 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 18 people aged 88 have covid on timestep 53 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 19 people aged 88 have covid on timestep 54 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 20 people aged 88 have covid on timestep 55 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 21 people aged 88 have covid on timestep 56 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 21 people aged 88 have covid on timestep 57 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 22 people aged 88 have covid on timestep 58 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 25 people aged 88 have covid on timestep 59 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 28 people aged 88 have covid on timestep 60 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 28 people aged 88 have covid on timestep 61 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 28 people aged 88 have covid on timestep 62 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 27 people aged 88 have covid on timestep 63 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 28 people aged 88 have covid on timestep 64 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 28 people aged 88 have covid on timestep 65 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 27 people aged 88 have covid on timestep 66 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 27 people aged 88 have covid on timestep 67 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 25 people aged 88 have covid on timestep 68 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 22 people aged 88 have covid on timestep 69 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 19 people aged 88 have covid on timestep 70 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 18 people aged 88 have covid on timestep 71 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 16 people aged 88 have covid on timestep 72 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 15 people aged 88 have covid on timestep 73 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 13 people aged 88 have covid on timestep 74 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 75 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 76 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 77 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 78 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 79 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 8 people aged 88 have covid on timestep 80 🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 8 people aged 88 have covid on timestep 81 🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 9 people aged 88 have covid on timestep 82 🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 83 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 10 people aged 88 have covid on timestep 84 🤯🤯🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 8 people aged 88 have covid on timestep 85 🤯🤯🤯🤯🤯🤯🤯🤯
Oh no! 7 people aged 88 have covid on timestep 86 🤯🤯🤯🤯🤯🤯🤯
Oh no! 7 people aged 88 have covid on timestep 87 🤯🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 88 🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 89 🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 90 🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 91 🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 92 🤯🤯🤯🤯🤯🤯
Oh no! 6 people aged 88 have covid on timestep 93 🤯🤯🤯🤯🤯🤯
Oh no! 4 people aged 88 have covid on timestep 94 🤯🤯🤯🤯
Oh no! 4 people aged 88 have covid on timestep 95 🤯🤯🤯🤯
Oh no! 4 people aged 88 have covid on timestep 96 🤯🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 97 🤯🤯🤯
Oh no! 3 people aged 88 have covid on timestep 98 🤯🤯🤯
Oh no! 2 people aged 88 have covid on timestep 99 🤯🤯
Oh no! 2 people aged 88 have covid on timestep 100 🤯🤯
Oh no! 1 people aged 88 have covid on timestep 101 🤯
Oh no! 1 people aged 88 have covid on timestep 102 🤯
Oh no! 1 people aged 88 have covid on timestep 103 🤯
Oh no! 1 people aged 88 have covid on timestep 104 🤯
Oh no! 1 people aged 88 have covid on timestep 105 🤯
Oh no! 1 people aged 88 have covid on timestep 106 🤯
Oh no! 1 people aged 88 have covid on timestep 107 🤯
Oh no! 1 people aged 88 have covid on timestep 108 🤯
Oh no! 1 people aged 88 have covid on timestep 109 🤯
Oh no! 1 people aged 88 have covid on timestep 110 🤯
Oh no! 1 people aged 88 have covid on timestep 111 🤯
Oh no! 1 people aged 88 have covid on timestep 112 🤯
Oh no! 1 people aged 88 have covid on timestep 113 🤯
Oh no! 1 people aged 88 have covid on timestep 114 🤯
Oh no! 1 people aged 88 have covid on timestep 115 🤯
Oh no! 1 people aged 88 have covid on timestep 116 🤯
Oh no! 1 people aged 88 have covid on timestep 117 🤯
Oh no! 1 people aged 88 have covid on timestep 118 🤯
Oh no! 1 people aged 88 have covid on timestep 119 🤯
Oh no! 1 people aged 88 have covid on timestep 120 🤯
[4]:
Sim(<no label>; 2020-03-01 to 2020-06-29; pop: 20000 random; epi: 21222⚙, 119☠)