-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtask_plot_multipliers.py
More file actions
365 lines (324 loc) · 14.2 KB
/
task_plot_multipliers.py
File metadata and controls
365 lines (324 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
import matplotlib.pyplot as plt
import pandas as pd
import pytask
import seaborn as sns
from src.config import BLD
from src.config import PLOT_END_DATE
from src.config import PLOT_SIZE
from src.config import PLOT_START_DATE
from src.config import SRC
from src.plotting.plotting import BLUE
from src.plotting.plotting import ORANGE
from src.plotting.plotting import PURPLE
from src.plotting.plotting import style_plot
from src.plotting.plotting import YELLOW
from src.policies.enacted_policies import HYGIENE_MULTIPLIER
from src.policies.enacted_policies import OTHER_MULTIPLIER_SPECS
from src.simulation.seasonality import create_seasonality_series
from src.testing.shared import get_piecewise_linear_interpolation
_DEPENDENCIES = {
# modules
"plotting.py": SRC / "plotting" / "plotting.py",
"testing_shared.py": SRC / "testing" / "shared.py",
# data
"enacted_policies.py": SRC / "policies" / "enacted_policies.py",
"stringency_data": BLD / "data" / "raw_time_series" / "stringency_data.csv",
"work_multiplier": BLD / "policies" / "work_multiplier.csv",
"params": BLD / "params.pkl",
}
@pytask.mark.depends_on(_DEPENDENCIES)
@pytask.mark.produces(BLD / "figures" / "data" / "other_multiplier.pdf")
def task_plot_other_multiplier(depends_on, produces): # noqa: U100
other_multiplier = _get_other_multiplier(
PLOT_START_DATE, PLOT_END_DATE, OTHER_MULTIPLIER_SPECS
)
fig, ax = plt.subplots(figsize=PLOT_SIZE)
sns.lineplot(
x=other_multiplier.index,
y=other_multiplier,
linewidth=3.0,
alpha=0.6,
color=BLUE,
)
fig, ax = style_plot(fig, ax)
ax.set_ylabel("share of other pre-pandemic contacts taking place")
fig.tight_layout()
fig.savefig(produces)
plt.close()
_PRODUCTS = {
"school_comparison": BLD / "figures" / "data" / "school_multiplier_comparison.pdf",
"0_no_seasonality": BLD / "figures" / "data" / "stringency_no_seasonality.pdf",
"1_no_seasonality": BLD / "figures" / "data" / "stringency2_no_seasonality.pdf",
"0_with_seasonality": BLD / "figures" / "data" / "stringency_with_seasonality.pdf",
"1_with_seasonality": BLD / "figures" / "data" / "stringency2_with_seasonality.pdf",
"data": BLD / "tables" / "multiplier_data.csv",
}
@pytask.mark.depends_on(_DEPENDENCIES)
@pytask.mark.produces(_PRODUCTS)
def task_plot_multipliers_and_stringency_index(depends_on, produces):
home_office_share = pd.read_csv(
depends_on["work_multiplier"], parse_dates=["date"], index_col="date"
)
stringency_data = pd.read_csv(
depends_on["stringency_data"], low_memory=False, parse_dates=["Date"]
)
params = pd.read_pickle(depends_on["params"])
stringency, doubled_stringency = _prepare_stringency(
stringency_data, PLOT_START_DATE, PLOT_END_DATE
)
work_multiplier = home_office_share.loc[PLOT_START_DATE:PLOT_END_DATE, "Germany"]
work_multiplier["2020-11-01":] = HYGIENE_MULTIPLIER * work_multiplier["2020-11-01":]
scaled_work_multiplier = work_multiplier / work_multiplier[0]
other_multiplier = _get_other_multiplier(
PLOT_START_DATE, PLOT_END_DATE, OTHER_MULTIPLIER_SPECS
)
scaled_other_multiplier = other_multiplier / other_multiplier[0]
(
school_multiplier_without_vacations,
school_multiplier_with_vacations,
) = _get_school_multipliers(PLOT_START_DATE)
school_multiplier_without_vacations = school_multiplier_without_vacations[
PLOT_START_DATE:PLOT_END_DATE
]
school_multiplier_with_vacations = school_multiplier_with_vacations[
PLOT_START_DATE:PLOT_END_DATE
]
fig, ax = plt.subplots(figsize=PLOT_SIZE)
for sr, label, color in [
(school_multiplier_with_vacations, "with vacations", BLUE),
(school_multiplier_without_vacations, "without vacations", ORANGE),
]:
sns.lineplot(
x=sr.index, y=sr, label=label, alpha=0.6, linewidth=3.0, color=color
)
fig, ax = style_plot(fig, ax)
ax.set_ylabel("share of school contacts taking place")
fig.tight_layout()
fig.savefig(produces["school_comparison"])
our_stringency = pd.concat(
[work_multiplier, other_multiplier, school_multiplier_with_vacations], axis=1
).mean(axis=1)
weak_seasonality, mean_seasonality, strong_seasonality = _get_seasonalities(
params, PLOT_START_DATE, PLOT_END_DATE
)
for i, oxford_stringency in enumerate([stringency, doubled_stringency]):
fig = _create_multiplier_plot(
oxford_stringency=oxford_stringency,
work_multiplier=scaled_work_multiplier,
other_multiplier=scaled_other_multiplier,
school_multiplier=school_multiplier_with_vacations,
our_stringency=our_stringency,
ylabel="Oxford Response Stringency Index / \n"
"Infectiousness of contacts relative to Sept 2020",
)
fig.savefig(produces[f"{i}_no_seasonality"])
work_multiplier_seasonal = scaled_work_multiplier * weak_seasonality
work_multiplier_seasonal = work_multiplier_seasonal / work_multiplier_seasonal[0]
other_multiplier_seasonal = scaled_other_multiplier * strong_seasonality
other_multiplier_seasonal = other_multiplier_seasonal / other_multiplier_seasonal[0]
school_multiplier_seasonal = school_multiplier_with_vacations * weak_seasonality
school_multiplier_seasonal = (
school_multiplier_seasonal / school_multiplier_seasonal[0]
)
our_stringency_seasonal = our_stringency * mean_seasonality
our_stringency_seasonal = our_stringency_seasonal / our_stringency_seasonal[0]
for i, oxford_stringency in enumerate([stringency, doubled_stringency]):
fig = _create_multiplier_plot(
oxford_stringency=oxford_stringency,
work_multiplier=work_multiplier_seasonal,
other_multiplier=other_multiplier_seasonal,
school_multiplier=school_multiplier_seasonal,
our_stringency=our_stringency_seasonal,
ylabel="share of pre-pandemic risk contacts taking place\nfor each contact "
"type (adjusting for seasonality)",
)
fig.savefig(produces[f"{i}_with_seasonality"])
plt.close()
df = pd.DataFrame(
{
# seasonal
"work_multiplier_seasonal": work_multiplier_seasonal,
"work_multiplier_seasonal": work_multiplier_seasonal,
"other_multiplier_seasonal": other_multiplier_seasonal,
"other_multiplier_seasonal": other_multiplier_seasonal,
"school_multiplier_seasonal": school_multiplier_seasonal,
"school_multiplier_seasonal": school_multiplier_seasonal,
# oxford stringency indices
"stringency": stringency,
"doubled_stringency": doubled_stringency,
# multipliers without seasonality
"work_multiplier": scaled_work_multiplier,
"other_multiplier": scaled_other_multiplier,
"school_multiplier": school_multiplier_with_vacations,
# for completeness
"school_multiplier_without_vacations": school_multiplier_without_vacations,
"our_mean_stringency": our_stringency,
"our_mean_stringency_seasonal": our_stringency_seasonal,
}
)
df.round(3).to_csv(produces["data"])
def _prepare_stringency(df, start_date, end_date):
"""Prepare the Oxford stringency data.
Documentation of the data can be found at https://bit.ly/3cgBwOQ
The citation is Hale2020.
"""
df = df.query("CountryName == 'Germany'")
df = df.set_index("Date")
df = df[start_date:end_date]
stringency = 1 - df["StringencyIndex"] / 100
doubled_stringency = 2 * stringency
return stringency, doubled_stringency
def _get_other_multiplier(start_date, end_date, multiplier_spec):
date_range = pd.date_range(start_date, end_date)
sr = pd.Series(index=date_range, dtype=float)
for _, end_date, multiplier in multiplier_spec:
sr[start_date:] = multiplier
start_date = end_date
return sr
def _get_school_multipliers(start_date):
share_age_for_emergency_care = 0.5
share_in_graduating_classes = 0.25 # 16, 17 and 18 year olds
share_in_primary = 0.3
a_b_multiplier = 0.5
share_getting_strict_emergency_care = 0.2
share_getting_generous_emergency_care = 0.3
strict_emergency_care_multiplier = (
share_age_for_emergency_care
* share_getting_strict_emergency_care
* HYGIENE_MULTIPLIER
)
generous_emergency_care_multiplier = (
share_in_graduating_classes * a_b_multiplier
+ share_age_for_emergency_care * share_getting_generous_emergency_care
) * HYGIENE_MULTIPLIER
feb_to_march_a_b_share = (
share_in_primary + share_in_graduating_classes
) * a_b_multiplier
feb_to_march_emergency_share = (
share_age_for_emergency_care
* share_getting_generous_emergency_care
* a_b_multiplier
)
feb_to_march_multiplier = (
feb_to_march_a_b_share + feb_to_march_emergency_share
) * HYGIENE_MULTIPLIER
a_b_for_most_multiplier = (
a_b_multiplier + feb_to_march_emergency_share * a_b_multiplier
)
school_multiplier_without_vacations = pd.Series(
{
start_date: 1.0,
"2020-11-01": 1.0,
"2020-11-02": HYGIENE_MULTIPLIER,
"2020-12-15": HYGIENE_MULTIPLIER,
# strict emergency care
"2020-12-16": strict_emergency_care_multiplier,
"2021-01-10": strict_emergency_care_multiplier,
# generous emergency care
"2021-01-11": generous_emergency_care_multiplier,
"2021-02-21": generous_emergency_care_multiplier,
# primary and graduating in A / B
"2021-02-22": feb_to_march_multiplier,
"2021-03-14": feb_to_march_multiplier,
# mid March until Easter: A / B for most
"2021-03-15": a_b_for_most_multiplier,
"2021-04-05": a_b_for_most_multiplier,
# easter until may:
"2021-04-06": generous_emergency_care_multiplier,
"2021-04-30": generous_emergency_care_multiplier,
# may
"2021-05-01": a_b_for_most_multiplier,
"2021-05-31": a_b_for_most_multiplier,
}
)
school_multiplier_without_vacations = get_piecewise_linear_interpolation(
school_multiplier_without_vacations
)
school_multiplier_with_vacations = pd.Series(
{
start_date: 1.0,
# fall vacation:
# first start on 2020-10-05. last end 2020-11-06
# on average from 2020-10-13 to 2020-10-23
# there was no overlap in the fall vacation dates between states.
"2020-10-05": 1.0,
"2020-10-13": 0.3, # number to cover that many states had fall vacation
"2020-10-23": 0.3,
"2020-11-06": HYGIENE_MULTIPLIER,
# strict emergency care started in the week before Christmas
"2020-12-15": HYGIENE_MULTIPLIER,
"2020-12-16": strict_emergency_care_multiplier,
# Christmas vacations started on 2002-12-21 in most states.
# Christmas vacations ended between 2021-01-02 and 2021-01-10.
"2020-12-20": strict_emergency_care_multiplier,
"2020-12-21": 0.0,
"2021-01-02": 0.0,
"2021-01-10": strict_emergency_care_multiplier,
# generous emergency care
# winter vacations were from 2021-01-25 until 2021-03-12 depending on the
# state and only short so we ignore them here.
"2021-01-11": generous_emergency_care_multiplier,
"2021-02-21": generous_emergency_care_multiplier,
# primary and graduating in A / B
"2021-02-22": feb_to_march_multiplier,
"2021-03-14": feb_to_march_multiplier,
# mid March until Easter: A / B for most
"2021-03-15": a_b_for_most_multiplier,
"2021-03-26": a_b_for_most_multiplier,
# Easter vacations started on 2021-03-29 in most states
# and ended between 2021-04-05 and 2021-04-16, for most on 2021-04-10
"2021-03-29": 0.0,
"2021-04-06": 0.0,
"2021-04-10": 0.1, # some states started school before 2021-04-10
# easter until may:
"2021-04-11": generous_emergency_care_multiplier,
"2021-04-30": generous_emergency_care_multiplier,
# may
# we ignore Pentecoast vacation because it was <4 days on average
"2021-05-01": a_b_for_most_multiplier,
"2021-05-31": a_b_for_most_multiplier,
}
)
school_multiplier_with_vacations = get_piecewise_linear_interpolation(
school_multiplier_with_vacations
)
return school_multiplier_without_vacations, school_multiplier_with_vacations
def _create_multiplier_plot(
oxford_stringency,
work_multiplier,
other_multiplier,
school_multiplier,
our_stringency, # noqa: U100
ylabel=None,
):
fig, ax = plt.subplots(figsize=PLOT_SIZE)
named_lines = [
# (our_stringency, "mean of our multiplier", 1.0, 4, RED), # noqa: E800
(oxford_stringency, "rescaled Oxford stringency index", 1.0, 3, "k"),
(work_multiplier, "Work", 0.8, 3, PURPLE),
(school_multiplier, "School", 0.8, 3, ORANGE),
(other_multiplier, "Other", 0.8, 3, YELLOW),
]
for multiplier, label, alpha, linewidth, color in named_lines:
sns.lineplot(
x=multiplier.index,
y=multiplier.rolling(7).mean(),
label=label,
linewidth=linewidth,
alpha=alpha,
color=color,
)
style_plot(fig, ax)
ax.set_ylabel(ylabel)
fig.tight_layout()
return fig
def _get_seasonalities(params, start_date, end_date):
dates = pd.date_range(start_date, end_date)
weak_val = params.loc[("seasonality_effect", "seasonality_effect", "weak"), "value"]
strong_val = params.loc[
("seasonality_effect", "seasonality_effect", "strong"), "value"
]
weak_seasonality = create_seasonality_series(dates, weak_val)
mean_seasonality = create_seasonality_series(dates, 0.5 * (weak_val + strong_val))
strong_seasonality = create_seasonality_series(dates, strong_val)
return weak_seasonality, mean_seasonality, strong_seasonality