9 jupytext_version: 1.3.4
11 display_name: Python 3
16 <!-- #region Collapsed="false" -->
17 Data from [European Centre for Disease Prevention and Control](https://www.ecdc.europa.eu/en/publications-data/download-todays-data-geographic-distribution-covid-19-cases-worldwide)
20 ```python Collapsed="false"
26 from scipy.stats import gmean
29 import matplotlib as mpl
30 import matplotlib.pyplot as plt
34 ```python Collapsed="false"
35 DEATH_COUNT_THRESHOLD = 10
36 COUNTRIES_CORE = 'IT DE UK ES IE FR BE'.split()
37 COUNTRIES_NORDIC = 'SE NO DK FI UK'.split()
38 COUNTRIES_FRIENDS = 'IT UK ES BE SI MX'.split()
39 # COUNTRIES_FRIENDS = 'IT UK ES BE SI PT'.split()
41 COUNTRIES_AMERICAS = ['AG', 'AR', 'AW', 'BS', 'BB', 'BZ', 'BM', 'BO', 'BR', 'VG', 'KY', # excluding Canada and USA
42 'CL', 'CO', 'CR', 'CU', 'CW', 'DM', 'DO', 'EC', 'SV', 'GL', 'GD', 'GT',
43 'GY', 'HT', 'HN', 'JM', 'MX', 'MS', 'NI', 'PA', 'PY', 'PE', 'PR', 'KN',
44 'LC', 'VC', 'SX', 'SR', 'TT', 'TC', 'VI', 'UY', 'VE']
45 COUNTRIES_OF_INTEREST = list(set(COUNTRIES_CORE + COUNTRIES_FRIENDS))
46 COUNTRIES_ALL = list(set(COUNTRIES_CORE + COUNTRIES_FRIENDS + COUNTRIES_NORDIC + COUNTRIES_AMERICAS))
49 ```python Collapsed="false"
50 !curl https://opendata.ecdc.europa.eu/covid19/casedistribution/csv/ > covid.csv
53 ```python Collapsed="false"
54 # First col is a date, treat geoId of NA as 'Namibia', not "NA" value
55 raw_data = pd.read_csv('covid.csv',
56 parse_dates=[0], dayfirst=True,
57 keep_default_na=False, na_values = [''],
58 # dtype = {'day': np.int64,
63 # 'countriesAndTerritories': str,
65 # 'countryterritoryCode': str,
66 # 'popData2019': np.int64,
67 # 'continentExp': str,
72 ```python Collapsed="false"
76 ```python Collapsed="false"
77 raw_data.fillna(0, inplace=True)
80 ```python Collapsed="false"
84 ```python Collapsed="false"
88 ```python Collapsed="false"
89 # raw_data = raw_data.astype({'dateRep': np.datetime64,
95 # 'countriesAndTerritories': str,
97 # 'countryterritoryCode': str,
98 # 'popData2019': np.int64,
99 # 'continentExp': str })
100 raw_data = raw_data.astype({'dateRep': np.datetime64,
106 'countriesAndTerritories': str,
108 'countryterritoryCode': str,
109 'popData2019': np.int64,
110 'continentExp': str })
113 ```python Collapsed="false"
117 ```python Collapsed="false"
118 raw_data[((raw_data.geoId == 'UK') & (raw_data.dateRep >= '2020-07-10'))]
121 ```python Collapsed="false"
122 # raw_data = raw_data[~ ((raw_data.geoId == 'ES') & (raw_data.dateRep >= '2020-05-22'))]
125 ```python Collapsed="false"
126 base_data = raw_data.set_index(['geoId', 'dateRep'])
127 base_data.sort_index(inplace=True)
131 ```python Collapsed="false"
132 base_data.loc['ES'].loc['2020-05-10':]
135 ```python Collapsed="false"
136 countries = raw_data[['geoId', 'countriesAndTerritories', 'popData2019', 'continentExp']]
137 countries = countries[countries['popData2019'] != '']
138 countries = countries.drop_duplicates()
139 countries.set_index('geoId', inplace=True)
140 countries = countries.astype({'popData2019': 'int64'})
144 ```python Collapsed="false"
148 ```python Collapsed="false"
149 countries[countries.countriesAndTerritories == 'Finland']
152 ```python Collapsed="false"
153 countries.loc[COUNTRIES_OF_INTEREST]
156 ```python Collapsed="false"
157 countries[countries.continentExp == 'America'].index
160 ```python Collapsed="false"
161 data_by_date = base_data[['cases', 'deaths']]
165 ```python Collapsed="false"
166 data_by_date.loc['UK']
169 ```python Collapsed="false"
170 # data_by_date.deaths.drop_duplicates().sort_values().to_csv('dth.csv', header=True)
173 ```python Collapsed="false"
174 data_by_date.groupby(level=0).cumsum()
177 ```python Collapsed="false"
178 data_by_date = data_by_date.merge(
179 data_by_date.groupby(level=0).cumsum(),
180 suffixes=('', '_culm'),
181 left_index=True, right_index=True)
185 ```python Collapsed="false"
186 data_by_date = data_by_date.merge(
187 data_by_date[['cases', 'deaths']].groupby(level=0).diff(),
188 suffixes=('', '_diff'),
189 left_index=True, right_index=True)
193 ```python Collapsed="false"
194 data_by_date.loc['UK', '2020-04-17']
197 ```python Collapsed="false"
198 data_by_date.loc['UK']
201 ```python Collapsed="false"
202 # data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD]
205 ```python Collapsed="false"
206 # days_since_threshold = data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD].groupby(level=0).cumcount()
207 # days_since_threshold.rename('since_threshold', inplace=True)
210 ```python Collapsed="false"
211 dbd = data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD].reset_index(level=1)
212 dbd['since_threshold'] = dbd.dateRep
213 dbd.set_index('dateRep', append=True, inplace=True)
214 dbd.sort_index(inplace=True)
215 days_since_threshold = dbd.groupby(level=0).diff().since_threshold.dt.days.fillna(0).astype(int).groupby(level=0).cumsum()
216 # days_since_threshold.groupby(level=0).cumsum()
218 # days_since_threshold = dbd.rename('since_threshold')
222 ```python Collapsed="false"
223 # days_since_threshold = (data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD]
224 # .reset_index(level=1).groupby(level=0)
225 # .diff().dateRep.dt.days
226 # .groupby(level=0).cumcount()
228 # days_since_threshold.rename('since_threshold', inplace=True)
229 # days_since_threshold
232 ```python Collapsed="false"
233 data_since_threshold = data_by_date.merge(days_since_threshold,
234 left_index=True, right_index=True)
238 ```python Collapsed="false"
239 data_since_threshold = data_since_threshold.set_index('since_threshold', append=True
240 ).reorder_levels(['since_threshold', 'geoId', 'dateRep']
241 ).reset_index('dateRep')
242 data_since_threshold.sort_index(inplace=True)
246 ```python Collapsed="false"
247 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
250 ```python Collapsed="false"
251 data_since_threshold.loc[(slice(None), ['ES']), :].tail(8)
254 ```python Collapsed="false"
255 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), ['deaths_culm']].unstack().plot(logy=True)
258 ```python Collapsed="false"
259 # deaths = data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT', 'IE']), ['deaths_culm']].unstack().xs('deaths_culm', axis=1, drop_level=True)
262 ```python Collapsed="false"
263 deaths = data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_culm']].unstack().sort_index().xs('deaths_culm', axis=1, drop_level=True)
264 deaths_by_date = data_by_date.loc[COUNTRIES_ALL, ['deaths_culm']].unstack().sort_index().xs('deaths_culm', axis=1, drop_level=True).T
267 ```python Collapsed="false"
268 cases = data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['cases_culm']].unstack().sort_index().xs('cases_culm', axis=1, drop_level=True)
269 cases_by_date = data_by_date.loc[ COUNTRIES_ALL, ['cases_culm']].unstack().sort_index().xs('cases_culm', axis=1, drop_level=True).T
272 ```python Collapsed="false"
273 COUNTRIES_AMERICAS_DEAD = list(set(deaths.columns) & set(COUNTRIES_AMERICAS))
276 ```python Collapsed="false"
277 data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId'])
280 ```python Collapsed="false"
281 data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId']).sort_index(inplace=True)
284 ```python Collapsed="false"
285 data_since_threshold_per_capita = data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId'])
286 data_since_threshold_per_capita['cases_culm_pc'] = data_since_threshold_per_capita.cases_culm / data_since_threshold_per_capita.popData2019
287 data_since_threshold_per_capita['deaths_culm_pc'] = data_since_threshold_per_capita.deaths_culm / data_since_threshold_per_capita.popData2019
288 data_since_threshold_per_capita
291 ```python Collapsed="false"
292 deaths_pc = data_since_threshold_per_capita.loc[(slice(None), ['UK', 'DE', 'IT', 'IE']), ['deaths_culm_pc']].unstack().sort_index().xs('deaths_culm_pc', axis=1, drop_level=True)
295 ```python Collapsed="false"
299 ```python Collapsed="false"
300 deaths_pc = data_since_threshold_per_capita.loc[(slice(None), COUNTRIES_ALL), ['deaths_culm_pc']].unstack().xs('deaths_culm_pc', axis=1, drop_level=True)
303 ```python Collapsed="false"
304 deaths[COUNTRIES_CORE].plot()
307 ```python Collapsed="false"
308 deaths[COUNTRIES_FRIENDS].plot()
311 ```python Collapsed="false"
312 ax = deaths[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Total deaths, linear")
313 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
314 for c in COUNTRIES_FRIENDS:
315 lvi = deaths[c].last_valid_index()
316 ax.text(x = lvi + 1, y = deaths[c][lvi], s = f"{c}: {deaths[c][lvi]:.0f}")
317 # plt.savefig('covid_deaths_total_linear.png')
320 ```python Collapsed="false"
321 ax = deaths[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total deaths, linear")
322 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
323 for c in COUNTRIES_CORE:
324 lvi = deaths[c].last_valid_index()
325 ax.text(x = lvi + 1, y = deaths[c][lvi], s = f"{c}: {deaths[c][lvi]:.0f}")
326 # plt.savefig('covid_deaths_total_linear.png')
329 ```python Collapsed="false"
330 ax = deaths_by_date.loc['2020-03-15':, COUNTRIES_CORE].plot(figsize=(10, 6), title="Total deaths, linear")
331 # data_by_date.loc[COUNTRIES_CORE]
332 # deaths_by_date = data_by_date.loc[COUNTRIES_ALL, ['deaths_culm']].unstack().sort_index().xs('deaths_culm', axis=1, drop_level=True)
333 ax.set_xlabel(f"Date")
334 for c in COUNTRIES_CORE:
335 lvi = deaths_by_date[c].last_valid_index()
336 ax.text(x = lvi + pd.Timedelta(days=1), y = deaths_by_date[c][lvi], s = f"{c}: {deaths_by_date[c][lvi]:.0f}")
337 plt.savefig('covid_deaths_total_linear.png')
340 ```python Collapsed="false"
341 deaths_prime = deaths[COUNTRIES_CORE].copy()
342 deaths_prime.loc[73:, 'ES'] = np.NaN
343 # deaths_prime['ES'][70:]
346 ```python Collapsed="false"
347 ax = deaths_prime[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total deaths, linear")
348 for c in COUNTRIES_CORE:
349 lvi = deaths_prime[c].last_valid_index()
350 ax.text(x = lvi + 1, y = deaths_prime[c][lvi], s = f"{c}: {deaths_prime[c][lvi]:.0f}")
351 # plt.savefig('covid_deaths_total_linear.png')
354 ```python Collapsed="false"
355 ax = cases[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total cases, linear")
356 for c in COUNTRIES_CORE:
357 lvi = cases[c].last_valid_index()
358 ax.text(x = lvi + 1, y = cases[c][lvi], s = c)
359 plt.savefig('covid_cases_total_linear.png')
362 ```python Collapsed="false"
363 ax = deaths[COUNTRIES_AMERICAS_DEAD].plot(figsize=(10, 6), title="Total deaths, linear")
364 for c in COUNTRIES_AMERICAS_DEAD:
365 lvi = deaths[c].last_valid_index()
366 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
367 # plt.savefig('covid_deaths_total_linear.png')
370 ```python Collapsed="false"
371 ax = deaths[COUNTRIES_CORE + ['BR', 'MX']].plot(figsize=(10, 6), title="Total deaths, linear")
372 for c in COUNTRIES_CORE + ['BR', 'MX']:
373 lvi = deaths[c].last_valid_index()
374 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
375 # plt.savefig('covid_deaths_total_linear.png')
378 ```python Collapsed="false"
379 ax = deaths[COUNTRIES_NORDIC].plot(figsize=(10, 6), title="Total deaths, linear")
380 for c in COUNTRIES_NORDIC:
381 lvi = deaths[c].last_valid_index()
382 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
383 # plt.savefig('covid_deaths_total_linear.png')
386 ```python Collapsed="false"
387 ax = deaths[COUNTRIES_OF_INTEREST].plot(figsize=(10, 6), title="Total deaths, linear")
388 for c in COUNTRIES_OF_INTEREST:
389 lvi = deaths[c].last_valid_index()
390 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
391 plt.savefig('covid_deaths_total_linear_of_interest.png')
394 ```python Collapsed="false"
395 ax = deaths[COUNTRIES_CORE].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
396 for c in COUNTRIES_CORE:
397 lvi = deaths[c].last_valid_index()
398 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
400 plt.savefig('covid_deaths_total_log.png')
403 ```python Collapsed="false"
404 ylim = (5*10**3, 5*10**4)
405 ax = deaths[COUNTRIES_CORE].plot(logy=True, figsize=(10, 6), ylim=ylim, title="Total deaths, log")
406 for c in COUNTRIES_CORE:
407 lvi = deaths[c].last_valid_index()
408 if ylim[0] < deaths[c][lvi] < ylim[1]:
409 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
411 # plt.savefig('covid_deaths_total_log.png')
414 ```python Collapsed="false"
415 ax = deaths[COUNTRIES_FRIENDS].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
416 for c in COUNTRIES_FRIENDS:
417 lvi = deaths[c].last_valid_index()
418 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
420 # plt.savefig('covid_deaths_total_log.png')
423 ```python Collapsed="false"
424 ax = deaths[COUNTRIES_NORDIC].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
425 for c in COUNTRIES_NORDIC:
426 lvi = deaths[c].last_valid_index()
427 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
429 # plt.savefig('covid_deaths_total_log.png')
432 ```python Collapsed="false"
433 ax = deaths[COUNTRIES_OF_INTEREST].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
434 for c in COUNTRIES_OF_INTEREST:
435 lvi = deaths[c].last_valid_index()
436 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
438 plt.savefig('covid_deaths_total_log.png')
441 ```python Collapsed="false"
442 ax = deaths_pc.plot(figsize=(10, 6), title="Deaths per capita, linear")
443 for c in deaths_pc.columns:
444 lvi = deaths_pc[c].last_valid_index()
445 ax.text(x = lvi + 1, y = deaths_pc[c][lvi], s = c)
446 plt.savefig('covid_deaths_per_capita_linear.png')
449 ```python Collapsed="false"
450 ax = deaths_pc.plot(logy=True, figsize=(10, 6), title="Deaths per capita, log")
451 for c in deaths_pc.columns:
452 lvi = deaths_pc[c].last_valid_index()
453 ax.text(x = lvi + 1, y = deaths_pc[c][lvi], s = c)
456 ```python Collapsed="false"
457 deaths_pc[['UK', 'IE']].plot( figsize=(10, 6), title="Deaths per capita, linear")
460 ```python Collapsed="false"
461 deaths_pc[['UK', 'IE']].plot(logy=True, figsize=(10, 6), title="Deaths per capita, log")
464 ```python Collapsed="false"
465 deaths[['UK', 'ES', 'IT']].plot(logy=True, figsize=(10, 6), title="Deaths, log")
466 plt.savefig('covid_deaths_selected_log.png')
469 ```python Collapsed="false"
470 deaths[['UK', 'ES', 'IT', 'MX']].plot(logy=True, figsize=(10, 6), title="Deaths, log")
473 ```python Collapsed="false"
474 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
477 ```python Collapsed="false"
478 data_since_threshold['deaths_m4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).mean())
479 data_since_threshold['deaths_m7'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(7, 1).mean())
480 data_since_threshold['cases_m7'] = data_since_threshold.groupby(level=1)['cases'].transform(lambda x: x.rolling(7, 1).mean())
481 # data_since_threshold['deaths_diff_m4'] = data_since_threshold.groupby(level=1)['deaths_diff'].transform(lambda x: x.rolling(4, 1).mean())
482 # data_since_threshold['deaths_diff_m7'] = data_since_threshold.groupby(level=1)['deaths_diff'].transform(lambda x: x.rolling(7, 1).mean())
483 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
486 ```python Collapsed="false"
487 deaths_m4 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_m4']]
488 .unstack().sort_index().xs('deaths_m4', axis=1, drop_level=True))
491 ```python Collapsed="false"
492 deaths_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_m7']]
493 .unstack().sort_index().xs('deaths_m7', axis=1, drop_level=True))
496 ```python Collapsed="false"
497 cases_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['cases_m7']]
498 .unstack().sort_index().xs('cases_m7', axis=1, drop_level=True))
501 ```python Collapsed="false"
502 data_by_date['cases_m7'] = data_by_date.groupby(level=0)['cases'].transform(lambda x: x.rolling(7, 1).mean())
503 data_by_date['deaths_m7'] = data_by_date.groupby(level=0)['deaths'].transform(lambda x: x.rolling(7, 1).mean())
507 ```python Collapsed="false"
508 data_by_date.loc[('UK', '2020-07-15'):'UK', 'cases'].plot()
511 ```python Collapsed="false"
512 cases_by_date_m7 = data_by_date.loc[COUNTRIES_ALL, 'cases_m7'].unstack(level=0).sort_index()
513 cases_by_date_m7[COUNTRIES_CORE].plot()
516 ```python Collapsed="false"
517 deaths_by_date_m7 = data_by_date.loc[COUNTRIES_ALL, 'deaths_m7'].unstack(level=0).sort_index()
518 deaths_by_date_m7[COUNTRIES_CORE].plot()
521 ```python Collapsed="false"
522 ax = deaths_m4.plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
523 for c in deaths_m4.columns:
524 lvi = deaths_m4[c].last_valid_index()
525 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
526 plt.savefig('covid_deaths_per_day.png')
529 ```python Collapsed="false"
530 ax = deaths_m4[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
531 for c in COUNTRIES_CORE:
532 lvi = deaths_m4[c].last_valid_index()
533 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
534 plt.savefig('covid_deaths_per_day-core.png')
537 ```python Collapsed="false"
538 ax = deaths_m4[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
539 for c in COUNTRIES_FRIENDS:
540 lvi = deaths_m4[c].last_valid_index()
541 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
542 # plt.savefig('covid_deaths_per_day-friends.png')
545 ```python Collapsed="false"
546 C7s = 'ES FR IT UK'.split()
547 ax = deaths_m7[C7s].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
549 lvi = deaths_m7[c].last_valid_index()
550 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
551 # plt.savefig('covid_deaths_per_day-friends.png')
554 ```python Collapsed="false"
555 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
556 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
557 for c in COUNTRIES_CORE:
558 lvi = deaths_m7[c].last_valid_index()
559 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
560 # plt.axhline(0, color='0.7')
561 plt.savefig('covid_deaths_per_day_7.png')
564 ```python Collapsed="false"
565 ax = deaths_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
566 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
567 for c in COUNTRIES_FRIENDS:
568 lvi = deaths_m7[c].last_valid_index()
569 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
570 # plt.axhline(0, color='0.7')
571 plt.savefig('covid_deaths_per_day-friends.png')
574 ```python Collapsed="false"
575 deaths_m7_prime = deaths_m7[COUNTRIES_CORE].copy()
576 deaths_m7_prime.loc[73:, 'ES'] = np.NaN
577 deaths_m7_prime['ES'][70:]
580 ```python Collapsed="false"
581 ax = deaths_m7_prime[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
582 for c in COUNTRIES_CORE:
583 lvi = deaths_m7_prime[c].last_valid_index()
584 ax.text(x = lvi + 1, y = deaths_m7_prime[c][lvi], s = c)
585 plt.savefig('covid_deaths_per_day_7.png') # see below for where this is written, with the projection
588 ```python Collapsed="false"
589 ax = deaths_by_date_m7.loc['2020-03-01':, COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
590 ax.set_xlabel('Date')
591 for c in COUNTRIES_CORE:
592 lvi = deaths_by_date_m7[c].last_valid_index()
593 ax.text(x = lvi + pd.Timedelta(days=1), y = deaths_by_date_m7[c][lvi], s = c)
594 plt.savefig('covid_deaths_per_day_7.png')
597 ```python Collapsed="false"
598 ax = deaths_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
599 for c in COUNTRIES_FRIENDS:
600 lvi = deaths_m7[c].last_valid_index()
601 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
602 plt.savefig('covid_deaths_per_day_friends_7.png')
605 ```python Collapsed="false"
606 ax = deaths_m7[COUNTRIES_CORE + ['BR', 'MX']].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
607 for c in COUNTRIES_CORE + ['BR', 'MX']:
608 lvi = deaths_m7[c].last_valid_index()
609 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
610 # plt.savefig('covid_deaths_per_day_7.png')
613 ```python Collapsed="false"
614 ax = deaths_by_date_m7.iloc[-30:][COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")#, ylim=(-10, 100))
615 ax.set_xlabel("Date")
617 text_x_pos = deaths_by_date_m7.last_valid_index() + pd.Timedelta(days=1)
619 for c in COUNTRIES_CORE:
620 lvi = deaths_by_date_m7[c].last_valid_index()
622 ax.text(x = text_x_pos, y = deaths_by_date_m7[c][lvi], s = f"{c}: {deaths_by_date_m7[c][lvi]:.0f}")
623 plt.savefig('deaths_by_date_last_30_days.png')
626 ```python Collapsed="false"
627 ax = deaths_by_date_m7.iloc[-30:][COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")#, ylim=(-10, 100))
628 ax.set_xlabel("Date")
630 text_x_pos = deaths_by_date_m7.last_valid_index() + pd.Timedelta(days=1)
632 for c in COUNTRIES_FRIENDS:
633 lvi = deaths_by_date_m7[c].last_valid_index()
635 ax.text(x = text_x_pos, y = deaths_by_date_m7[c][lvi], s = f"{c}: {deaths_by_date_m7[c][lvi]:.0f}")
636 plt.savefig('deaths_by_date_last_30_days_friends.png')
639 ```python Collapsed="false"
640 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
641 for c in COUNTRIES_CORE:
642 lvi = cases_m7[c].last_valid_index()
643 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
644 plt.savefig('covid_cases_per_day-core.png')
647 ```python Collapsed="false"
648 ax = cases_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
649 for c in COUNTRIES_FRIENDS:
650 lvi = cases_m7[c].last_valid_index()
651 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
652 plt.savefig('covid_cases_per_day-core.png')
655 ```python Collapsed="false"
656 ax = cases_by_date_m7.iloc[-30:][COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")#, ylim=(-10, 100))
657 ax.set_xlabel("Date")
659 text_x_pos = cases_by_date_m7.last_valid_index() + pd.Timedelta(days=1)
661 for c in COUNTRIES_FRIENDS:
662 lvi = cases_by_date_m7[c].last_valid_index()
664 ax.text(x = text_x_pos, y = cases_by_date_m7[c][lvi], s = f"{c}: {cases_by_date_m7[c][lvi]:.0f}")
665 plt.savefig('cases_by_date_last_30_days_friends.png')
668 ```python Collapsed="false"
669 def gmean_scale(items):
670 return gmean(items) / items[-1]
673 ```python Collapsed="false"
674 def doubling_time(df):
675 return np.log(2) / np.log((df.deaths_culm + df.deaths_g4) / df.deaths_culm)
677 def doubling_time_7(df):
678 return np.log(2) / np.log((df.deaths_culm + df.deaths_g7) / df.deaths_culm)
681 ```python Collapsed="false"
682 # data_since_threshold['deaths_g4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).apply(gmean_scale, raw=True))
683 # data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
686 ```python Collapsed="false"
687 data_since_threshold['deaths_g4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).apply(gmean, raw=True))
688 data_since_threshold['deaths_g7'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(7, 1).apply(gmean, raw=True))
689 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
692 ```python Collapsed="false"
693 data_since_threshold['doubling_time'] = data_since_threshold.groupby(level=1).apply(doubling_time).reset_index(level=0, drop=True).sort_index()
694 data_since_threshold['doubling_time_7'] = data_since_threshold.groupby(level=1).apply(doubling_time_7).reset_index(level=0, drop=True).sort_index()
695 # data_since_threshold.loc[(slice(None), 'UK'), :]
698 ```python Collapsed="false"
699 data_by_date['deaths_g4'] = data_by_date.groupby(level=0)['deaths'].transform(lambda x: x.rolling(4, 1).apply(gmean, raw=True))
700 data_by_date['deaths_g7'] = data_by_date.groupby(level=0)['deaths'].transform(lambda x: x.rolling(7, 1).apply(gmean, raw=True))
701 data_by_date['doubling_time'] = data_by_date.groupby(level=0).apply(doubling_time).reset_index(level=0, drop=True).sort_index()
702 data_by_date['doubling_time_7'] = data_by_date.groupby(level=0).apply(doubling_time_7).reset_index(level=0, drop=True).sort_index()
703 data_by_date.loc['UK']
706 ```python Collapsed="false"
707 doubling_times = (data_since_threshold.loc[(slice(None), COUNTRIES_OF_INTEREST), ['doubling_time']]
708 .unstack().sort_index().xs('doubling_time', axis=1, drop_level=True))
709 doubling_times.replace([np.inf, -np.inf], np.nan, inplace=True)
712 ```python Collapsed="false"
713 doubling_times_7 = (data_since_threshold.loc[(slice(None), COUNTRIES_OF_INTEREST), ['doubling_time_7']]
714 .unstack().sort_index().xs('doubling_time_7', axis=1, drop_level=True))
715 doubling_times_7.replace([np.inf, -np.inf], np.nan, inplace=True)
718 ```python Collapsed="false"
719 ax = doubling_times.plot(figsize=(10, 6), title="Doubling times, 4 day average")
720 for c in doubling_times.columns:
721 lvi = doubling_times[c].last_valid_index()
722 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
723 # plt.savefig('covid_deaths_per_day.png')
726 ```python Collapsed="false"
727 ax = doubling_times_7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Doubling times, 7 day average")
728 ax.legend(loc="upper left")
729 for c in COUNTRIES_CORE:
730 lvi = doubling_times_7[c].last_valid_index()
731 ax.text(x = lvi + 1, y = doubling_times_7[c][lvi], s = c)
732 plt.savefig('covid_doubling_times_7.png')
735 ```python Collapsed="false"
736 ax = doubling_times[COUNTRIES_CORE].plot(figsize=(10, 6), title="Doubling times, 4 day average")
737 for c in COUNTRIES_CORE:
738 lvi = doubling_times[c].last_valid_index()
739 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
740 plt.savefig('covid_doubling_times.png')
743 ```python Collapsed="false"
744 ax = doubling_times[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Doubling times")
745 for c in COUNTRIES_FRIENDS:
746 lvi = doubling_times[c].last_valid_index()
747 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
748 plt.savefig('covid_doubling_times_friends.png')
751 ```python Collapsed="false"
752 ax = doubling_times[C7s].plot(figsize=(10, 6), title="Doubling times")
754 lvi = doubling_times[c].last_valid_index()
755 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
756 # plt.savefig('covid_doubling_times_friends.png')
759 ```python Collapsed="false"
760 # deaths_diff_m4 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_diff_m4']]
761 # .unstack().sort_index().xs('deaths_diff_m4', axis=1, drop_level=True))
764 ```python Collapsed="false"
765 # deaths_diff_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_diff_m7']]
766 # .unstack().sort_index().xs('deaths_diff_m7', axis=1, drop_level=True))
769 ```python Collapsed="false"
773 ```python Collapsed="false"
774 # data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last().loc[COUNTRIES_ALL]#, [doubling_time]]
777 ```python Collapsed="false"
778 dstl = data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last()
779 dstl.loc[dstl.index.intersection(COUNTRIES_ALL)]
782 ```python Collapsed="false"
783 # data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last().loc[['UK', 'DE', 'IT']]#, [doubling_time]]
784 dstl.loc[['UK', 'DE', 'IT', 'FR', 'ES']]
787 ```python Collapsed="false"
788 data_since_threshold.loc[(slice(None), ['UK']), :].tail(20)
791 ```python Collapsed="false"
792 data_since_threshold.loc[(slice(None), ['ES']), :].tail(20)
795 <!-- #region Collapsed="false" -->
799 ```python Collapsed="false"
800 data_since_threshold.loc[(slice(None), ['UK']), :].tail(15)
803 ```python Collapsed="false"
804 it_since_threshold = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['IT']), :]
805 s_end = it_since_threshold.index.max()[0]
809 ```python Collapsed="false"
810 uk_projection = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), :]
811 uk_current_end = uk_projection.index.max()[0] + 1
812 # s_start = uk_projection.index.max()[0] + 1
816 ```python Collapsed="false"
817 current_uk_deaths_m7 = uk_projection[uk_projection.deaths_m7 >= 0].iloc[-1].deaths_m7
821 ```python Collapsed="false"
822 it_since_threshold[it_since_threshold.deaths_m7 <= current_uk_deaths_m7].loc[60:].first_valid_index()[0]
825 ```python Collapsed="false"
826 s_start = it_since_threshold[it_since_threshold.deaths_m7 <= current_uk_deaths_m7].loc[60:].first_valid_index()[0]
830 ```python Collapsed="false"
831 s_start_date = data_since_threshold.loc[(89, 'IT'), 'dateRep']# .iloc[0]
835 ```python Collapsed="false"
839 ```python Collapsed="false"
840 uk_end = s_end - s_start + uk_current_end
844 ```python Collapsed="false"
845 proj = it_since_threshold.loc[(slice(s_start, s_end), slice(None)), ['cases', 'deaths', 'deaths_m7']]
846 ndiff = uk_current_end - s_start
847 proj.index = pd.MultiIndex.from_tuples([(n + ndiff, 'UK') for n, _ in proj.index], names=proj.index.names)
851 ```python Collapsed="false"
852 it_since_threshold.loc[(slice(s_start - 8, s_start + 2), slice(None)), ['cases', 'deaths', 'deaths_m7']]
855 ```python Collapsed="false"
856 uk_projection[['cases', 'deaths', 'deaths_m7']].tail()
859 ```python Collapsed="false"
860 # proj['deaths_m7'] = proj['deaths_m7'] + 20
864 <!-- #region Collapsed="false" -->
865 Projected deaths, UK following IT trend from now.
868 ```python Collapsed="false"
869 uk_projection = uk_projection.append(proj, sort=True)
870 uk_projection.deaths.sum()
873 ```python Collapsed="false"
874 uk_projection = uk_projection.droplevel(1)
878 ```python Collapsed="false"
879 uk_projection.loc[152, 'deaths']
882 <!-- #region Collapsed="false" -->
883 ## Correction for cumulative deaths correction on 14 August
886 ```python Collapsed="false"
887 # uk_projection.loc[152, 'deaths'] = 50
890 ```python Collapsed="false"
891 uk_projection['deaths_m7'] = uk_projection['deaths'].transform(lambda x: x.rolling(7, 1).mean())
892 uk_projection.loc[(uk_current_end - 20):(uk_current_end + 5)]
895 ```python Collapsed="false"
896 uk_projection.loc[(uk_current_end - 5):]
899 ```python Collapsed="false"
900 uk_projection.deaths_m7.plot()
903 ```python Collapsed="false"
904 proj.droplevel(level=1)
907 ```python Collapsed="false"
908 ax = deaths_m7[COUNTRIES_CORE].plot()
909 # uk_projection['deaths_m7'].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average", label="Projection", style='--', ax=ax)
910 proj.droplevel(level=1)['deaths_m7'].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average", label="Projection", style='--', ax=ax)
911 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
912 for c in COUNTRIES_CORE:
913 lvi = deaths_m7[c].last_valid_index()
914 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
915 # plt.savefig('covid_deaths_per_day_7.png')
918 ```python Collapsed="false"
919 it_since_threshold.deaths.sum()
922 <!-- #region Collapsed="false" -->
923 # Excess deaths calculation
926 ```python Collapsed="false"
927 with open('excess_deaths.json') as f:
928 excess_deaths_data = json.load(f)
930 # with open('excess_death_accuracy.json') as f:
931 # excess_death_accuracy = json.load(f)
936 ```python Collapsed="false"
937 additional_deaths = data_by_date.loc[('UK', excess_deaths_data['end_date']):('UK')].iloc[1:].deaths.sum()
941 ```python Collapsed="false"
942 uk_covid_deaths = data_by_date.loc['UK'].deaths.sum()
946 ```python Collapsed="false"
947 uk_deaths_to_date = int(excess_deaths_data['excess_deaths']) + additional_deaths
951 ```python Collapsed="false"
952 # excess_deaths_upto = '2020-05-08'
953 # excess_deaths = 54500
956 ```python Collapsed="false"
957 # excess_deaths_upto = excess_deaths_data['end_date']
958 # excess_deaths = excess_deaths_data['excess_deaths']
961 <!-- #region Collapsed="false" -->
962 Recorded deaths in period where ONS has reported total deaths
965 ```python Collapsed="false"
966 # ons_reported_deaths = base_data.loc['UK'][:excess_deaths_upto]['deaths'].sum()
967 # ons_reported_deaths
970 ```python Collapsed="false"
974 <!-- #region Collapsed="false" -->
975 ## Correction for deaths total correction on 14 August
978 ```python Collapsed="false"
979 # ons_unreported_deaths_data = base_data.loc['UK'][excess_deaths_upto:].iloc[1:]['deaths']
980 # ons_unreported_deaths_data['2020-08-14'] = 50
983 ```python Collapsed="false"
984 # ons_unreported_deaths = ons_unreported_deaths_data.sum()
985 # ons_unreported_deaths
988 ```python Collapsed="false"
989 # scaled_ons_unreported_deaths = ons_unreported_deaths * excess_death_accuracy
990 # scaled_ons_unreported_deaths
993 ```python Collapsed="false"
994 # uk_deaths_to_date = excess_deaths + scaled_ons_unreported_deaths
998 ```python Collapsed="false"
999 # data_since_threshold.loc[(slice(None), 'UK'), :][data_since_threshold.dateRep == excess_deaths_data['end_date']]
1002 ```python Collapsed="false"
1003 # data_since_threshold[data_since_threshold.dateRep == excess_deaths_data['end_date']].loc[(slice(None), 'UK'), :]
1006 ```python Collapsed="false"
1007 # ons_unreported_start = data_since_threshold[data_since_threshold.dateRep == excess_deaths_data['end_date']].loc[(slice(None), 'UK'), :].first_valid_index()[0] + 1
1008 # ons_unreported_start
1011 ```python Collapsed="false"
1012 # unreported_projected_deaths = uk_projection.loc[ons_unreported_start:].deaths.sum()
1013 # unreported_projected_deaths
1016 ```python Collapsed="false"
1017 # unreported_projected_deaths_scaled = unreported_projected_deaths * excess_death_accuracy
1018 # unreported_projected_deaths_scaled
1021 ```python Collapsed="false"
1022 # uk_projection.loc[(s_start):].deaths.sum()
1025 ```python Collapsed="false"
1026 # deaths_actual_projected_scaled = uk_deaths_to_date + uk_projection.loc[(s_start):].deaths.sum() * excess_death_accuracy
1027 # deaths_actual_projected_scaled
1030 ```python Collapsed="false"
1031 # excess_deaths / reported_deaths
1034 <!-- #region Collapsed="false" -->
1035 True deaths to date, if we follow the scaling of excess deaths over reported deaths so far.
1038 ```python Collapsed="false"
1039 # uk_covid_deaths = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths_culm'].iloc[-1]
1043 ```python Collapsed="false"
1044 # uk_covid_deaths_scaled = excess_deaths + unreported_deaths * excess_death_accuracy
1045 # uk_covid_deaths_scaled
1048 ```python Collapsed="false"
1049 # data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['IT']), 'dateRep'].iloc[-1] + pd.Timedelta(s_end - s_start, unit='days')
1052 ```python Collapsed="false"
1053 # data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'dateRep'].iloc[-1].strftime("%Y-%m-%d")
1056 ```python Collapsed="false"
1057 # uk_covid_deaths * excess_deaths / reported_deaths
1060 ```python Collapsed="false"
1061 # uk_projection.deaths.sum() * excess_deaths / reported_deaths
1064 ```python Collapsed="false"
1065 # data_since_threshold.loc[(slice(None), 'FR'), :]
1066 # data_since_threshold[data_since_threshold.dateRep == '2020-05-18'].loc[(slice(None), 'FR'), :]
1069 <!-- #region Collapsed="false" -->
1070 ## School reopenings
1073 ```python Collapsed="false"
1074 school_reopenings = {
1075 'ES': {'date': '2020-05-18'},
1076 'FR': {'date': '2020-05-18'}, # some areas only
1077 # 'IT': {'date': '2020-09-01'},
1078 # 'IE': {'date': '2020-09-01'},
1079 'DE': {'date': '2020-05-04'},
1080 'UK': {'date': '2020-06-01'}
1084 ```python Collapsed="false"
1085 data_since_threshold[data_since_threshold.dateRep == '2020-05-04'].loc[(slice(None), ['DE']), :].first_valid_index()
1088 ```python Collapsed="false"
1089 data_since_threshold[data_since_threshold.dateRep == '2020-05-04'].loc[(slice(None), ['DE']), :].iloc[0].deaths_m7
1092 ```python Collapsed="false"
1093 for cID in school_reopenings:
1094 dst_in = data_since_threshold[data_since_threshold.dateRep == (school_reopenings[cID]['date'])].loc[(slice(None), [cID]), :]
1095 dst_i = dst_in.first_valid_index()
1096 dst_n = dst_in.iloc[0].deaths_m7
1097 school_reopenings[cID]['since_threshold'] = dst_i[0]
1098 school_reopenings[cID]['deaths_m7'] = dst_n
1102 ```python Collapsed="false"
1103 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average")
1104 # uk_projection.deaths_m7.plot(ax=ax)
1105 for c in COUNTRIES_CORE:
1106 lvi = deaths_m7[c].last_valid_index()
1107 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}")
1108 if c in school_reopenings:
1109 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1110 ax.plot(school_reopenings[c]['since_threshold'], school_reopenings[c]['deaths_m7'], '*',
1111 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1112 ax.text(x = school_reopenings[c]['since_threshold'] + 1, y = school_reopenings[c]['deaths_m7'],
1113 s = f"{school_reopenings[c]['date']}: {school_reopenings[c]['deaths_m7']:.0f}")
1114 plt.savefig('school_reopenings.png')
1117 ```python Collapsed="false"
1118 # ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average",
1119 # xlim=(46, 91), ylim=(0, 400))
1120 # # uk_projection.deaths_m7.plot(ax=ax)
1121 # for c in COUNTRIES_CORE:
1122 # lvi = deaths_m7[c].last_valid_index()
1123 # ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}", fontsize=14)
1124 # if c in school_reopenings:
1125 # marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1126 # ax.plot(school_reopenings[c]['since_threshold'], school_reopenings[c]['deaths_m7'], '*',
1127 # markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1128 # ax.text(x = school_reopenings[c]['since_threshold'] + 1, y = school_reopenings[c]['deaths_m7'],
1129 # s = f"{school_reopenings[c]['date']}: {school_reopenings[c]['deaths_m7']:.0f}",
1131 # plt.savefig('school_reopenings_detail.png')
1134 <!-- #region Collapsed="false" -->
1138 ```python Collapsed="false"
1140 'ES': { 'part_start': {'date': '2020-03-14'}
1141 , 'full_start': {'date': '2020-03-15'}
1142 , 'part_finish': {'date': '2020-05-18'}
1144 'FR': { 'part_start': {'date': '2020-03-13'}
1145 , 'full_start': {'date': '2020-03-17'}
1146 , 'part_finish': {'date': '2020-05-11'}
1148 'IT': { 'part_start': {'date': '2020-03-08'}
1149 , 'full_start': {'date': '2020-03-10'}
1150 , 'part_finish': {'date': '2020-05-04'}
1152 'DE': { #'part_start': {'date': '2020-03-13'}
1153 'full_start': {'date': '2020-03-22'}
1154 , 'part_finish': {'date': '2020-05-06'}
1156 'UK': { 'part_start': {'date': '2020-03-23'}
1157 , 'full_start': {'date': '2020-03-23'}
1158 , 'part_finish': {'date': '2020-05-31'}
1160 'IE': { #'part_start': {'date': '2020-03-12'}
1161 'full_start': {'date': '2020-03-27'}
1162 , 'part_finish': {'date': '2020-05-18'}
1167 ```python Collapsed="false"
1168 for cID in lockdown_dates:
1169 for phase in lockdown_dates[cID]:
1170 dst_in = data_since_threshold[data_since_threshold.dateRep == (lockdown_dates[cID][phase]['date'])].loc[(slice(None), [cID]), :]
1171 dst_i = dst_in.first_valid_index()
1172 dst_n = dst_in.iloc[0].deaths_m7
1173 dst_c = dst_in.iloc[0].cases_m7
1174 lockdown_dates[cID][phase]['since_threshold'] = dst_i[0]
1175 lockdown_dates[cID][phase]['deaths_m7'] = dst_n
1176 lockdown_dates[cID][phase]['cases_m7'] = dst_c
1181 ```python Collapsed="false"
1182 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving averagee, with lockdown dates")
1183 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1184 # uk_projection.deaths_m7.plot(ax=ax)
1185 for c in COUNTRIES_CORE:
1186 lvi = deaths_m7[c].last_valid_index()
1188 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}")
1189 if c in lockdown_dates:
1190 for phase in lockdown_dates[c]:
1191 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1192 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['deaths_m7'], '*',
1193 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1194 if 'start' not in phase:
1195 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 1, y = lockdown_dates[c][phase]['deaths_m7'],
1196 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['deaths_m7']:.0f}")
1197 # plt.savefig('school_reopenings.png')
1200 ```python Collapsed="false"
1201 ax = cases_m7.iloc[-50:][COUNTRIES_CORE].plot(figsize=(15, 9), title="Cases per day, 7 day moving average, with lockdown dates") #, ylim=(-10, 1500))
1202 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1203 # uk_projection.deaths_m7.plot(ax=ax)
1204 for c in COUNTRIES_CORE:
1205 lvi = cases_m7[c].last_valid_index()
1207 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = f"{c}: {cases_m7[c][lvi]:.0f}")
1211 ```python Collapsed="false"
1212 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Cases per day, 7 day moving average, with lockdown dates")
1213 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1214 # uk_projection.deaths_m7.plot(ax=ax)
1215 for c in COUNTRIES_CORE:
1216 lvi = cases_m7[c].last_valid_index()
1218 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = f"{c}: {cases_m7[c][lvi]:.0f}")
1219 if c in lockdown_dates:
1220 for phase in lockdown_dates[c]:
1221 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1222 if 'start' in phase:
1226 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['cases_m7'],
1228 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1229 if 'start' not in phase:
1230 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 1, y = lockdown_dates[c][phase]['cases_m7'],
1231 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['cases_m7']:.0f}")
1232 # plt.savefig('cases_per_day_with_lockdown.png')
1235 ```python Collapsed="false"
1236 plot_start_date = '2020-03-01'
1237 ax = cases_by_date_m7.loc[plot_start_date:, COUNTRIES_CORE].plot(figsize=(15, 9), title="Cases per day, 7 day moving average, with lockdown dates")
1238 ax.set_xlabel(f"Date")
1239 ax.set_ylabel("Number of cases")
1240 # uk_projection.deaths_m7.plot(ax=ax)
1241 for c in COUNTRIES_CORE:
1242 lvi = cases_by_date_m7[c].last_valid_index()
1244 ax.text(x = lvi + pd.Timedelta(days=1), y = cases_by_date_m7[c][lvi], s = f"{c}: {cases_by_date_m7[c][lvi]:.0f}")
1245 if c in lockdown_dates:
1246 for phase in lockdown_dates[c]:
1247 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1248 if 'start' in phase:
1252 marker_x_pos = ax.get_xlim()[0] + mpl.dates.date2num(pd.to_datetime(lockdown_dates[c][phase]['date'])) - mpl.dates.date2num(pd.to_datetime(plot_start_date))
1253 ax.plot(marker_x_pos, lockdown_dates[c][phase]['cases_m7'],
1255 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1256 if 'start' not in phase:
1257 ax.text(x = marker_x_pos + 3, y = lockdown_dates[c][phase]['cases_m7'],
1258 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['cases_m7']:.0f}")
1259 plt.savefig('cases_per_day_with_lockdown.png')
1262 ```python Collapsed="false"
1263 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
1264 for c in COUNTRIES_CORE:
1265 lvi = cases_m7[c].last_valid_index()
1266 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
1267 plt.savefig('covid_cases_per_day-core.png')
1270 ```python Collapsed="false"
1271 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average",
1275 # uk_projection.deaths_m7.plot(ax=ax)
1276 for c in COUNTRIES_CORE:
1277 lvi = deaths_m7[c].last_valid_index()
1278 if c in lockdown_dates:
1279 for phase in lockdown_dates[c]:
1280 if 'start' in phase:
1282 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1283 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['deaths_m7'], '*',
1284 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1285 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 0.3, y = lockdown_dates[c][phase]['deaths_m7'],
1286 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['deaths_m7']:.0f}")
1287 # plt.savefig('school_reopenings.png')
1290 ```python Collapsed="false"
1294 ```python Collapsed="false"
1298 <!-- #region Collapsed="false" -->
1299 # Write results to summary file
1302 ```python Collapsed="false"
1303 with open('covid_summary.md', 'w') as f:
1304 f.write('% Covid death data summary\n')
1305 f.write('% Neil Smith\n')
1306 f.write(f'% Created on {datetime.datetime.now().strftime("%Y-%m-%d")}\n')
1309 last_uk_date = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'dateRep'].iloc[-1]
1310 f.write(f'> Last UK data from {last_uk_date.strftime("%Y-%m-%d")}\n')
1314 ```python Collapsed="false"
1315 with open('covid_summary.md', 'a') as f:
1316 f.write('## Headlines\n')
1318 f.write('| []() | |\n')
1319 f.write('|:---|---:|\n')
1320 f.write(f'| Deaths reported so far | {uk_covid_deaths} | \n')
1321 f.write(f'| Total Covid deaths to date (estimated) | {uk_deaths_to_date:.0f} |\n')
1322 projection_date = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['IT']), 'dateRep'].iloc[-1] + pd.Timedelta(s_end - s_start, unit='days')
1323 # f.write(f'| Projected total deaths up to {projection_date.strftime("%Y-%m-%d")} | {deaths_actual_projected_scaled:.0f} | \n')
1327 ```python Collapsed="false"
1328 with open('covid_summary.md', 'a') as f:
1329 f.write('## Total deaths\n')
1330 # f.write(f'Time based on days since {DEATH_COUNT_THRESHOLD} deaths\n')
1332 f.write('![Total deaths](covid_deaths_total_linear.png)\n')
1334 f.write('| Country ID | Country name | Total deaths |\n')
1335 f.write('|:-----------|:-------------|-------------:|\n')
1336 for c in sorted(COUNTRIES_CORE):
1337 lvi = deaths_by_date[c].last_valid_index()
1338 f.write(f'| {c} | {countries.loc[c].countriesAndTerritories} | {int(deaths_by_date[c][lvi])} |\n')
1342 ```python Collapsed="false"
1343 with open('covid_summary.md', 'a') as f:
1344 f.write('## All-causes deaths, UK\n')
1346 f.write('![All-causes deaths](deaths-radar.png)\n')
1348 f.write('### True deaths\n')
1350 f.write(f'The number of deaths reported in official statistics, {uk_covid_deaths}, is an underestimate '
1351 'of the true number of Covid deaths.\n'
1352 'This is especially true early in the pandemic, approximately March to May 2020.\n')
1353 f.write('We can get a better understanding of the impact of Covid by looking at the number of deaths, '
1354 'over and above what would be expected at each week of the year.\n')
1355 f.write(f'The ONS (and other bodies in Scotland and Northern Ireland) have released data on the number of deaths '
1356 f'up to {pd.to_datetime(excess_deaths_data["end_date"]).strftime("%d %B %Y")}.\n\n')
1357 f.write('If, for each of those weeks, I take the largest of the excess deaths or the reported Covid deaths, ')
1358 f.write(f'I estimate there have been **{uk_deaths_to_date}** total deaths so far.\n')
1362 ```python Collapsed="false"
1363 # with open('covid_summary.md', 'a') as f:
1364 # f.write(f'In that period, the UK reported {ons_reported_deaths} Covid deaths.\n')
1365 # f.write(f'In the last three weeks for which excess deaths have been reported, the excess deaths have been {excess_death_accuracy:.3f} higher than the Covid-reported deaths.\n')
1366 # # f.write(f'That means the actual number of Covid death is about {excess_deaths / reported_deaths:.2f} times higher than the reported figures.\n')
1368 # f.write(f'The UK has reported {uk_covid_deaths} deaths so far.\n')
1369 # f.write(f'Using the scaling factor above (for Covid-19 deaths after the ONS figures), I infer that there have been **{uk_deaths_to_date:.0f}** total deaths so far.\n')
1373 ```python Collapsed="false"
1374 with open('covid_summary.md', 'a') as f:
1375 f.write('## Deaths per day\n')
1376 f.write(f'Based on a 7-day moving average\n')
1378 f.write('![Deaths per day](covid_deaths_per_day_7.png)\n')
1380 f.write('![Deaths per day, last 30 days](deaths_by_date_last_30_days.png)\n')
1384 ```python Collapsed="false"
1388 ```python Collapsed="false"
1389 with open('covid_summary.md', 'a') as f:
1390 f.write('## Projected deaths\n')
1391 f.write("Previously, I was using Italy's deaths data to predict the UK's deaths data. "
1392 "This worked when both countries' trends of deaths were falling or constant, "
1393 "as they were until September.\n")
1395 f.write("As of mid-September, with cases rising in both countries at around the same time, "
1396 "I can't use Italian data to predict the UK's future deaths.\n")
1398 # f.write(f"The UK's daily deaths data is very similar to Italy's.\n")
1399 # f.write(f'If I use the Italian data for the next {s_end - s_start - 1} days (from {s_start_date.strftime("%d %B %Y")} onwards),')
1400 # f.write(f' the UK will report {uk_projection.deaths.sum()} deaths on day {uk_end} of the epidemic.\n')
1402 # f.write('Using the excess deaths scaling from above, that will translate into ')
1403 # f.write(f'**{deaths_actual_projected_scaled:.0f}** Covid deaths total.\n')
1407 ```python Collapsed="false"
1408 with open('covid_summary.md', 'a') as f:
1409 f.write('## Deaths doubling times\n')
1410 f.write(f'Based on a 7-day moving average\n')
1412 f.write('![Deaths doubling times](covid_doubling_times_7.png)\n')
1416 ```python Collapsed="false"
1417 with open('covid_summary.md', 'a') as f:
1419 f.write('## Cases per day and lockdown dates\n')
1420 f.write(f'Based on a 7-day moving average\n')
1422 f.write('![Cases per day](cases_per_day_with_lockdown.png)\n')
1426 ```python Collapsed="false"
1427 with open('covid_summary.md', 'a') as f:
1428 f.write('| Country ID | Country name | Most recent daily cases | Most recent daily deaths |\n')
1429 f.write('|:-----------|:-------------|------------------------:|-------------------------:|\n')
1430 for c in sorted(COUNTRIES_CORE):
1431 lvic = cases_m7[c].last_valid_index()
1432 lvid = deaths_m7[c].last_valid_index()
1433 f.write(f'| {c} | {countries.loc[c].countriesAndTerritories} | {cases_m7[c][lvic]:.0f} | {deaths_m7[c][lvid]:.0f} | \n')
1435 f.write('(Figures are 7-day averages)\n')
1439 ```python Collapsed="false"
1440 with open('hospital_normalisation_date.json') as f:
1441 hospital_normalisation_date_data = json.load(f)
1444 ```python Collapsed="false"
1445 with open('covid_summary.md', 'a') as f:
1446 f.write('## Hospital care\n')
1447 f.write(f'Based on a 7-day moving average\n')
1449 f.write('![Cases, admissions, deaths](cases_admissions_deaths.png)\n')
1451 # f.write('Admissions are shifted by 10 days, deaths by 25 days. '
1452 # 'This reflects the typical timescales of infection: '
1453 # 'patients are admitted 10 days after onset of symptoms, '
1454 # 'and die 15 days after admission.\n')
1456 # f.write('Plotting this data with offsets shows more clearly '
1457 # 'the relative changes in these three metrics.\n')
1458 f.write('Due to the large scale differences between the three '
1459 'measures, they are all normalised to show changes ')
1460 f.write(f'since {pd.to_datetime(hospital_normalisation_date_data["hospital_normalisation_date"]).strftime("%d %B %Y")}.\n')
1464 ```python Collapsed="false"
1465 with open('covid_summary.md', 'a') as f:
1466 f.write('## Testing effectiveness\n')
1468 f.write('A question about testing is whether more detected cases is a result of more tests being '
1469 'done or is because the number of cases is increasing. One way of telling the differeence '
1470 'is by looking at the fraction of tests that are positive.\n')
1472 f.write('![Positive tests and cases](tests_and_cases.png)\n')
1474 f.write('Numbers of positive tests and cases, '
1475 '7-day moving average.\n'
1476 'Note the different y-axes\n')
1478 f.write('![Fraction of tests with positive result](fraction_positive_tests.png)\n')
1480 f.write('Fraction of tests with a positive result, both daily figures and '
1481 '7-day moving average.\n')
1484 f.write('![Tests against fraction positive, trajectory](fraction_positive_tests_vs_tests.png)\n')
1486 f.write('The trajectory of tests done vs fraction positive tests.\n')
1488 f.write('Points higher indicate more tests; points to the right indicate more positive tests.'
1489 'More tests being done with the same infection prevelance will move the point up '
1490 'and to the left.\n')
1493 f.write('![Tests against fraction positive, trajectory](tests_vs_fraction_positive_animation.png)\n')
1497 ```python Collapsed="false"
1501 ```python Collapsed="false"
1502 with open('covid_summary.md', 'a') as f:
1503 f.write('# Data sources\n')
1505 f.write('> Covid data from [European Centre for Disease Prevention and Control](https://www.ecdc.europa.eu/en/publications-data/download-todays-data-geographic-distribution-covid-19-cases-worldwide)\n')
1507 f.write("""> Population data from:
1509 * [Office of National Statistics](https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/deaths/datasets/weeklyprovisionalfiguresondeathsregisteredinenglandandwales) (Endland and Wales) Weeks start on a Saturday.
1510 * [Northern Ireland Statistics and Research Agency](https://www.nisra.gov.uk/publications/weekly-deaths) (Northern Ireland). Weeks start on a Saturday. Note that the week numbers don't match the England and Wales data.
1511 * [National Records of Scotland](https://www.nrscotland.gov.uk/statistics-and-data/statistics/statistics-by-theme/vital-events/general-publications/weekly-and-monthly-data-on-births-and-deaths/weekly-data-on-births-and-deaths) (Scotland). Note that Scotland uses ISO8601 week numbers, which start on a Monday.""")
1514 f.write('> [Source code available](https://git.njae.me.uk/?p=covid19.git;a=tree)\n')
1519 ```python Collapsed="false"
1520 !pandoc --toc -s covid_summary.md > covid_summary.html
1523 ```python Collapsed="false"
1524 !scp covid_summary.html neil@ogedei:/var/www/scripts.njae.me.uk/covid/index.html
1525 !scp covid_deaths_total_linear.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1526 !scp deaths-radar.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1527 !scp covid_deaths_per_day_7.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1528 !scp covid_doubling_times_7.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1529 !scp cases_per_day_with_lockdown.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1530 !scp cases_admissions_deaths.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1531 !scp fraction_positive_tests.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1532 !scp tests_and_cases.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1533 !scp deaths_by_date_last_30_days.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1534 !scp fraction_positive_tests_vs_tests.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1535 !scp tests_vs_fraction_positive_animation.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1538 ```python Collapsed="false"
1539 with open('uk_covid_deaths.js', 'w') as f:
1540 f.write(f"document.write('{uk_covid_deaths}');")
1542 with open('estimated_total_deaths.js', 'w') as f:
1543 f.write(f"document.write('{uk_deaths_to_date:.0f}');")
1545 # with open('projection_date.js', 'w') as f:
1546 # f.write(f"document.write(\'{projection_date.strftime('%d %B %Y')}\');")
1548 # with open('projected_deaths.js', 'w') as f:
1549 # f.write(f"document.write('{uk_projection.deaths.sum():.0f}');")
1551 # with open('projected_excess_deaths.js', 'w') as f:
1552 # f.write(f"document.write('{deaths_actual_projected_scaled:.0f}');")
1554 edut = pd.to_datetime(excess_deaths_data["end_date"]).strftime('%d %B %Y')
1555 with open('excess_deaths_upto.js', 'w') as f:
1556 f.write(f"document.write('{edut}');")
1558 # with open('excess_deaths.js', 'w') as f:
1559 # f.write(f"document.write('{excess_deaths:.0f}');")
1561 # with open('reported_deaths.js', 'w') as f:
1562 # f.write(f"document.write('{ons_reported_deaths:.0f}');")
1564 # with open('scaling_factor.js', 'w') as f:
1565 # f.write(f"document.write('{excess_death_accuracy:.2f}');")
1567 # with open('projection_length.js', 'w') as f:
1568 # f.write(f"document.write('{s_end - s_start - 1}');")
1570 # with open('s_end.js', 'w') as f:
1571 # f.write(f"document.write('{s_end}');")
1573 # s_start_date_str = s_start_date.strftime("%d %B %Y")
1574 # with open('s_start_date.js', 'w') as f:
1575 # f.write(f"document.write('{s_start_date_str}');")
1577 # with open('uk_end.js', 'w') as f:
1578 # f.write(f"document.write('{uk_end}');")
1580 with open('last_uk_date.js', 'w') as f:
1581 f.write(f"document.write('{pd.to_datetime(last_uk_date).strftime('%d %B %Y')}');")
1584 ```python Collapsed="false"
1585 # pd.to_datetime(excess_deaths_upto).strftime('%d %B %Y')
1588 ```python Collapsed="false"
1589 !scp uk_covid_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1590 !scp estimated_total_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1591 # !scp projection_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1592 # !scp projected_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1593 # !scp projected_excess_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1594 !scp excess_deaths_upto.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1595 # !scp excess_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1596 # !scp reported_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1597 # !scp scaling_factor.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1598 # !scp projection_length.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1599 # !scp s_end.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1600 # !scp s_start_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1601 # !scp uk_end.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1602 !scp last_uk_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1603 !scp hospital_normalisation_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1606 ```python Collapsed="false"
1607 data_by_date.loc['UK'].to_csv('data_by_day_uk.csv', header=True, index=True)
1608 data_by_date.loc['BE'].to_csv('data_by_day_be.csv', header=True, index=True)
1611 ```python Collapsed="false"
1612 ukd = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), ['deaths', 'deaths_m7']].droplevel(1)
1613 ax = ukd.deaths.plot.bar(figsize=(12, 8))
1614 ukd.deaths_m7.plot.line(ax=ax, color='red')
1615 # ax = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths_m7'].plot.line(figsize=(12, 8), color='red')
1616 # ax = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths'].plot.bar(ax=ax)
1617 ax.set_xticks(range(0, 120, 20))
1620 ```python Collapsed="false"
1621 ukdd = data_by_date.loc['UK'].iloc[-30:]
1622 ax = ukdd.deaths_m7.plot.line(figsize=(12, 8), color='red')
1623 # ukdd.deaths.plot.bar(ax=ax)
1624 ax.bar(ukdd.index, ukdd.deaths)
1627 ```python Collapsed="false"
1631 ```python Collapsed="false"
1632 np.arange(0, 130, 20)
1635 ```python Collapsed="false"
1636 data_by_date.loc['UK']
1639 ```python Collapsed="false"
1640 data_by_date.loc['UK'].plot(x='deaths_culm', y='deaths', logx=True, logy=True)
1643 ```python Collapsed="false"
1644 data_by_date.loc['UK'].plot(x='cases_culm', y='cases')
1647 ```python Collapsed="false"
1648 ukdbd = data_by_date.loc['UK'].copy()
1649 ukdbd['deaths_m7'] = ukdbd.deaths.transform(lambda x: x.rolling(7, 1).mean())
1650 ukdbd['cases_m7'] = ukdbd.cases.transform(lambda x: x.rolling(7, 1).mean())
1654 ```python Collapsed="false"
1655 ukdbd.plot(x='deaths_culm', y='deaths_m7', logx=True, logy=True)
1658 ```python Collapsed="false"
1659 fig, ax = plt.subplots(figsize=(12, 8))
1661 for c in COUNTRIES_CORE:
1662 if data_since_threshold.loc[(slice(None), c), 'deaths_culm'].max() > xmax:
1663 xmax = data_since_threshold.loc[(slice(None), c), 'deaths_culm'].max()
1664 data_since_threshold.loc[(slice(None), c), :].plot(x='deaths_culm', y='deaths_m7', logx=True, logy=True, xlim=(10, xmax * 1.1), label=c, ax=ax)
1667 ```python Collapsed="false"
1668 data_since_threshold.loc[(slice(None), 'UK'), 'deaths_culm'].max()
1671 ```python Collapsed="false"
1672 countries.continentExp.unique()
1675 ```python Collapsed="false"
1679 ```python Collapsed="false"
1680 data_by_date.groupby(level=0)['deaths'].shift(-25)
1683 ```python Collapsed="false"
1684 offset_data = data_by_date.loc[:, ['cases']]
1685 offset_data['deaths'] = data_by_date.groupby(level=0)['deaths'].shift(-25)
1686 offset_data['cases_m7'] = offset_data.groupby(level=0)['cases'].transform(lambda x: x.rolling(7, 1).mean())
1687 offset_data['deaths_m7'] = offset_data['deaths'].dropna().groupby(level=0).transform(lambda x: x.rolling(7, 1).mean())
1688 offset_data['deaths_per_case'] = offset_data.deaths_m7 / offset_data.cases_m7
1692 ```python Collapsed="false"
1696 ```python Collapsed="false"
1697 offset_deaths_m7 = (offset_data.loc[COUNTRIES_ALL, ['deaths_m7']]
1698 .unstack().sort_index().xs('deaths_m7', axis=1, drop_level=True)).T.sort_index()
1702 ```python Collapsed="false"
1703 offset_deaths_m7['UK']
1706 ```python Collapsed="false"
1707 data_since_threshold.loc[(slice(None), 'UK'), :].tail()
1710 ```python Collapsed="false"
1714 ```python Collapsed="false"
1715 ax = cases_by_date_m7.iloc[-50:][COUNTRIES_FRIENDS].plot(figsize=(15, 9), title="Cases per day, 7 day moving average")#, ylim=(-10, 1500))
1716 # ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1717 # uk_projection.deaths_m7.plot(ax=ax)
1718 for c in COUNTRIES_FRIENDS:
1719 lvi = cases_by_date_m7[c].last_valid_index()
1720 ax.text(x = lvi + pd.Timedelta(days=1), y = cases_by_date_m7[c][lvi], s = f"{c}: {cases_by_date_m7[c][lvi]:.0f}")
1724 ```python Collapsed="false"
1725 ax = deaths_by_date_m7.iloc[-50:][COUNTRIES_FRIENDS].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average")#, ylim=(-10, 100))
1726 # ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1727 # uk_projection.deaths_m7.plot(ax=ax)
1728 for c in COUNTRIES_FRIENDS:
1729 lvi = deaths_by_date_m7[c].last_valid_index()
1731 ax.text(x = lvi + pd.Timedelta(days=1), y = deaths_by_date_m7[c][lvi], s = f"{c}: {deaths_by_date_m7[c][lvi]:.0f}")
1734 ```python Collapsed="false"