9 jupytext_version: 1.3.4
11 display_name: Python 3
16 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)
24 from scipy.stats import gmean
27 import matplotlib as mpl
28 import matplotlib.pyplot as plt
33 DEATH_COUNT_THRESHOLD = 10
34 COUNTRIES_CORE = 'IT DE UK ES IE FR'.split()
35 COUNTRIES_NORDIC = 'SE NO DK FI UK'.split()
36 # COUNTRIES_FRIENDS = 'IT UK ES BE SI MX'.split()
37 COUNTRIES_FRIENDS = 'IT UK ES BE SI PT'.split()
39 COUNTRIES_AMERICAS = ['AG', 'AR', 'AW', 'BS', 'BB', 'BZ', 'BM', 'BO', 'BR', 'VG', 'KY', # excluding Canada and USA
40 'CL', 'CO', 'CR', 'CU', 'CW', 'DM', 'DO', 'EC', 'SV', 'GL', 'GD', 'GT',
41 'GY', 'HT', 'HN', 'JM', 'MX', 'MS', 'NI', 'PA', 'PY', 'PE', 'PR', 'KN',
42 'LC', 'VC', 'SX', 'SR', 'TT', 'TC', 'VI', 'UY', 'VE']
43 COUNTRIES_OF_INTEREST = list(set(COUNTRIES_CORE + COUNTRIES_FRIENDS))
44 COUNTRIES_ALL = list(set(COUNTRIES_CORE + COUNTRIES_FRIENDS + COUNTRIES_NORDIC + COUNTRIES_AMERICAS))
48 !curl https://opendata.ecdc.europa.eu/covid19/casedistribution/csv/ > covid.csv
52 # First col is a date, treat geoId of NA as 'Namibia', not "NA" value
53 raw_data = pd.read_csv('covid.csv',
54 parse_dates=[0], dayfirst=True,
55 keep_default_na=False, na_values = [''],
56 # dtype = {'day': np.int64,
61 # 'countriesAndTerritories': str,
63 # 'countryterritoryCode': str,
64 # 'popData2019': np.int64,
65 # 'continentExp': str,
75 raw_data.fillna(0, inplace=True)
87 raw_data = raw_data.astype({'dateRep': np.datetime64,
93 'countriesAndTerritories': str,
95 'countryterritoryCode': str,
96 'popData2019': np.int64,
97 'continentExp': str })
105 raw_data[((raw_data.geoId == 'UK') & (raw_data.dateRep >= '2020-07-10'))]
109 # raw_data = raw_data[~ ((raw_data.geoId == 'ES') & (raw_data.dateRep >= '2020-05-22'))]
113 base_data = raw_data.set_index(['geoId', 'dateRep'])
114 base_data.sort_index(inplace=True)
119 base_data.loc['ES'].loc['2020-05-10':]
123 countries = raw_data[['geoId', 'countriesAndTerritories', 'popData2019', 'continentExp']]
124 countries = countries[countries['popData2019'] != '']
125 countries = countries.drop_duplicates()
126 countries.set_index('geoId', inplace=True)
127 countries = countries.astype({'popData2019': 'int64'})
136 countries[countries.countriesAndTerritories == 'Finland']
140 countries.loc[COUNTRIES_OF_INTEREST]
144 countries[countries.continentExp == 'America'].index
148 data_by_date = base_data[['cases', 'deaths']]
153 data_by_date.loc['UK']
157 # data_by_date.deaths.drop_duplicates().sort_values().to_csv('dth.csv', header=True)
161 data_by_date.groupby(level=0).cumsum()
165 data_by_date = data_by_date.merge(
166 data_by_date.groupby(level=0).cumsum(),
167 suffixes=('', '_culm'),
168 left_index=True, right_index=True)
173 data_by_date = data_by_date.merge(
174 data_by_date[['cases', 'deaths']].groupby(level=0).diff(),
175 suffixes=('', '_diff'),
176 left_index=True, right_index=True)
181 data_by_date.loc['UK', '2020-04-17']
185 data_by_date.loc['UK']
189 # data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD]
193 # days_since_threshold = data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD].groupby(level=0).cumcount()
194 # days_since_threshold.rename('since_threshold', inplace=True)
198 dbd = data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD].reset_index(level=1)
199 dbd['since_threshold'] = dbd.dateRep
200 dbd.set_index('dateRep', append=True, inplace=True)
201 dbd.sort_index(inplace=True)
202 days_since_threshold = dbd.groupby(level=0).diff().since_threshold.dt.days.fillna(0).astype(int).groupby(level=0).cumsum()
203 # days_since_threshold.groupby(level=0).cumsum()
205 # days_since_threshold = dbd.rename('since_threshold')
210 # days_since_threshold = (data_by_date[data_by_date.deaths_culm > DEATH_COUNT_THRESHOLD]
211 # .reset_index(level=1).groupby(level=0)
212 # .diff().dateRep.dt.days
213 # .groupby(level=0).cumcount()
215 # days_since_threshold.rename('since_threshold', inplace=True)
216 # days_since_threshold
220 data_since_threshold = data_by_date.merge(days_since_threshold,
221 left_index=True, right_index=True)
226 data_since_threshold = data_since_threshold.set_index('since_threshold', append=True
227 ).reorder_levels(['since_threshold', 'geoId', 'dateRep']
228 ).reset_index('dateRep')
229 data_since_threshold.sort_index(inplace=True)
234 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
238 data_since_threshold.loc[(slice(None), ['ES']), :].tail(8)
242 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), ['deaths_culm']].unstack().plot(logy=True)
246 # deaths = data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT', 'IE']), ['deaths_culm']].unstack().xs('deaths_culm', axis=1, drop_level=True)
250 deaths = data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_culm']].unstack().sort_index().xs('deaths_culm', axis=1, drop_level=True)
254 cases = data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['cases_culm']].unstack().sort_index().xs('cases_culm', axis=1, drop_level=True)
258 COUNTRIES_AMERICAS_DEAD = list(set(deaths.columns) & set(COUNTRIES_AMERICAS))
262 data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId'])
266 data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId']).sort_index(inplace=True)
270 data_since_threshold_per_capita = data_since_threshold.reset_index().merge(countries, on='geoId').set_index(['since_threshold', 'geoId'])
271 data_since_threshold_per_capita['cases_culm_pc'] = data_since_threshold_per_capita.cases_culm / data_since_threshold_per_capita.popData2019
272 data_since_threshold_per_capita['deaths_culm_pc'] = data_since_threshold_per_capita.deaths_culm / data_since_threshold_per_capita.popData2019
273 data_since_threshold_per_capita
277 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)
285 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)
289 deaths[COUNTRIES_CORE].plot()
293 deaths[COUNTRIES_FRIENDS].plot()
297 ax = deaths[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Total deaths, linear")
298 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
299 for c in COUNTRIES_FRIENDS:
300 lvi = deaths[c].last_valid_index()
301 ax.text(x = lvi + 1, y = deaths[c][lvi], s = f"{c}: {deaths[c][lvi]:.0f}")
302 # plt.savefig('covid_deaths_total_linear.png')
306 ax = deaths[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total deaths, linear")
307 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
308 for c in COUNTRIES_CORE:
309 lvi = deaths[c].last_valid_index()
310 ax.text(x = lvi + 1, y = deaths[c][lvi], s = f"{c}: {deaths[c][lvi]:.0f}")
311 plt.savefig('covid_deaths_total_linear.png')
315 deaths_prime = deaths[COUNTRIES_CORE].copy()
316 deaths_prime.loc[73:, 'ES'] = np.NaN
317 # deaths_prime['ES'][70:]
321 ax = deaths_prime[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total deaths, linear")
322 for c in COUNTRIES_CORE:
323 lvi = deaths_prime[c].last_valid_index()
324 ax.text(x = lvi + 1, y = deaths_prime[c][lvi], s = f"{c}: {deaths_prime[c][lvi]:.0f}")
325 # plt.savefig('covid_deaths_total_linear.png')
329 ax = cases[COUNTRIES_CORE].plot(figsize=(10, 6), title="Total cases, linear")
330 for c in COUNTRIES_CORE:
331 lvi = cases[c].last_valid_index()
332 ax.text(x = lvi + 1, y = cases[c][lvi], s = c)
333 plt.savefig('covid_cases_total_linear.png')
337 ax = deaths[COUNTRIES_AMERICAS_DEAD].plot(figsize=(10, 6), title="Total deaths, linear")
338 for c in COUNTRIES_AMERICAS_DEAD:
339 lvi = deaths[c].last_valid_index()
340 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
341 # plt.savefig('covid_deaths_total_linear.png')
345 ax = deaths[COUNTRIES_CORE + ['BR', 'MX']].plot(figsize=(10, 6), title="Total deaths, linear")
346 for c in COUNTRIES_CORE + ['BR', 'MX']:
347 lvi = deaths[c].last_valid_index()
348 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
349 # plt.savefig('covid_deaths_total_linear.png')
353 ax = deaths[COUNTRIES_NORDIC].plot(figsize=(10, 6), title="Total deaths, linear")
354 for c in COUNTRIES_NORDIC:
355 lvi = deaths[c].last_valid_index()
356 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
357 # plt.savefig('covid_deaths_total_linear.png')
361 ax = deaths[COUNTRIES_OF_INTEREST].plot(figsize=(10, 6), title="Total deaths, linear")
362 for c in COUNTRIES_OF_INTEREST:
363 lvi = deaths[c].last_valid_index()
364 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
365 plt.savefig('covid_deaths_total_linear_of_interest.png')
369 ax = deaths[COUNTRIES_CORE].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
370 for c in COUNTRIES_CORE:
371 lvi = deaths[c].last_valid_index()
372 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
374 plt.savefig('covid_deaths_total_log.png')
378 ylim = (5*10**3, 5*10**4)
379 ax = deaths[COUNTRIES_CORE].plot(logy=True, figsize=(10, 6), ylim=ylim, title="Total deaths, log")
380 for c in COUNTRIES_CORE:
381 lvi = deaths[c].last_valid_index()
382 if ylim[0] < deaths[c][lvi] < ylim[1]:
383 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
385 # plt.savefig('covid_deaths_total_log.png')
389 ax = deaths[COUNTRIES_FRIENDS].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
390 for c in COUNTRIES_FRIENDS:
391 lvi = deaths[c].last_valid_index()
392 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
394 # plt.savefig('covid_deaths_total_log.png')
398 ax = deaths[COUNTRIES_NORDIC].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
399 for c in COUNTRIES_NORDIC:
400 lvi = deaths[c].last_valid_index()
401 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
403 # plt.savefig('covid_deaths_total_log.png')
407 ax = deaths[COUNTRIES_OF_INTEREST].plot(logy=True, figsize=(10, 6), title="Total deaths, log")
408 for c in COUNTRIES_OF_INTEREST:
409 lvi = deaths[c].last_valid_index()
410 ax.text(x = lvi + 1, y = deaths[c][lvi], s = c)
412 plt.savefig('covid_deaths_total_log.png')
416 ax = deaths_pc.plot(figsize=(10, 6), title="Deaths per capita, linear")
417 for c in deaths_pc.columns:
418 lvi = deaths_pc[c].last_valid_index()
419 ax.text(x = lvi + 1, y = deaths_pc[c][lvi], s = c)
420 plt.savefig('covid_deaths_per_capita_linear.png')
424 ax = deaths_pc.plot(logy=True, figsize=(10, 6), title="Deaths per capita, log")
425 for c in deaths_pc.columns:
426 lvi = deaths_pc[c].last_valid_index()
427 ax.text(x = lvi + 1, y = deaths_pc[c][lvi], s = c)
431 deaths_pc[['UK', 'IE']].plot( figsize=(10, 6), title="Deaths per capita, linear")
435 deaths_pc[['UK', 'IE']].plot(logy=True, figsize=(10, 6), title="Deaths per capita, log")
439 deaths[['UK', 'ES', 'IT']].plot(logy=True, figsize=(10, 6), title="Deaths, log")
440 plt.savefig('covid_deaths_selected_log.png')
444 deaths[['UK', 'ES', 'IT', 'MX']].plot(logy=True, figsize=(10, 6), title="Deaths, log")
448 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
452 data_since_threshold['deaths_m4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).mean())
453 data_since_threshold['deaths_m7'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(7, 1).mean())
454 data_since_threshold['cases_m7'] = data_since_threshold.groupby(level=1)['cases'].transform(lambda x: x.rolling(7, 1).mean())
455 # data_since_threshold['deaths_diff_m4'] = data_since_threshold.groupby(level=1)['deaths_diff'].transform(lambda x: x.rolling(4, 1).mean())
456 # data_since_threshold['deaths_diff_m7'] = data_since_threshold.groupby(level=1)['deaths_diff'].transform(lambda x: x.rolling(7, 1).mean())
457 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
461 deaths_m4 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_m4']]
462 .unstack().sort_index().xs('deaths_m4', axis=1, drop_level=True))
466 deaths_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_m7']]
467 .unstack().sort_index().xs('deaths_m7', axis=1, drop_level=True))
471 cases_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['cases_m7']]
472 .unstack().sort_index().xs('cases_m7', axis=1, drop_level=True))
476 ax = deaths_m4.plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
477 for c in deaths_m4.columns:
478 lvi = deaths_m4[c].last_valid_index()
479 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
480 plt.savefig('covid_deaths_per_day.png')
484 ax = deaths_m4[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
485 for c in COUNTRIES_CORE:
486 lvi = deaths_m4[c].last_valid_index()
487 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
488 plt.savefig('covid_deaths_per_day-core.png')
492 ax = deaths_m4[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 4 day moving average")
493 for c in COUNTRIES_FRIENDS:
494 lvi = deaths_m4[c].last_valid_index()
495 ax.text(x = lvi + 1, y = deaths_m4[c][lvi], s = c)
496 plt.savefig('covid_deaths_per_day-friends.png')
500 C7s = 'ES FR IT UK'.split()
501 ax = deaths_m7[C7s].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
503 lvi = deaths_m7[c].last_valid_index()
504 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
505 # plt.savefig('covid_deaths_per_day-friends.png')
509 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
510 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
511 for c in COUNTRIES_CORE:
512 lvi = deaths_m7[c].last_valid_index()
513 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
514 # plt.axhline(0, color='0.7')
515 plt.savefig('covid_deaths_per_day_7.png')
519 ax = deaths_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
520 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
521 for c in COUNTRIES_FRIENDS:
522 lvi = deaths_m7[c].last_valid_index()
523 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
524 # plt.axhline(0, color='0.7')
525 # plt.savefig('covid_deaths_per_day_7.png')
529 deaths_m7_prime = deaths_m7[COUNTRIES_CORE].copy()
530 deaths_m7_prime.loc[73:, 'ES'] = np.NaN
531 deaths_m7_prime['ES'][70:]
535 ax = deaths_m7_prime[COUNTRIES_CORE].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
536 for c in COUNTRIES_CORE:
537 lvi = deaths_m7_prime[c].last_valid_index()
538 ax.text(x = lvi + 1, y = deaths_m7_prime[c][lvi], s = c)
539 # plt.savefig('covid_deaths_per_day_7.png') # see below for where this is written, with the projection
543 ax = deaths_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
544 for c in COUNTRIES_FRIENDS:
545 lvi = deaths_m7[c].last_valid_index()
546 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
547 plt.savefig('covid_deaths_per_day_friends_7.png')
551 ax = deaths_m7[COUNTRIES_CORE + ['BR', 'MX']].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average")
552 for c in COUNTRIES_CORE + ['BR', 'MX']:
553 lvi = deaths_m7[c].last_valid_index()
554 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
555 # plt.savefig('covid_deaths_per_day_7.png')
559 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
560 for c in COUNTRIES_CORE:
561 lvi = cases_m7[c].last_valid_index()
562 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
563 plt.savefig('covid_cases_per_day-core.png')
567 ax = cases_m7[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
568 for c in COUNTRIES_FRIENDS:
569 lvi = cases_m7[c].last_valid_index()
570 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
571 # plt.savefig('covid_cases_per_day-core.png')
575 def gmean_scale(items):
576 return gmean(items) / items[-1]
580 def doubling_time(df):
581 return np.log(2) / np.log((df.deaths_culm + df.deaths_g4) / df.deaths_culm)
583 def doubling_time_7(df):
584 return np.log(2) / np.log((df.deaths_culm + df.deaths_g7) / df.deaths_culm)
588 # data_since_threshold['deaths_g4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).apply(gmean_scale, raw=True))
589 # data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
593 data_since_threshold['deaths_g4'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(4, 1).apply(gmean, raw=True))
594 data_since_threshold['deaths_g7'] = data_since_threshold.groupby(level=1)['deaths'].transform(lambda x: x.rolling(7, 1).apply(gmean, raw=True))
595 data_since_threshold.loc[(slice(None), ['UK', 'DE', 'IT']), :]
599 data_since_threshold['doubling_time'] = data_since_threshold.groupby(level=1).apply(doubling_time).reset_index(level=0, drop=True).sort_index()
600 data_since_threshold['doubling_time_7'] = data_since_threshold.groupby(level=1).apply(doubling_time_7).reset_index(level=0, drop=True).sort_index()
601 # data_since_threshold.loc[(slice(None), 'UK'), :]
605 doubling_times = (data_since_threshold.loc[(slice(None), COUNTRIES_OF_INTEREST), ['doubling_time']]
606 .unstack().sort_index().xs('doubling_time', axis=1, drop_level=True))
607 doubling_times.replace([np.inf, -np.inf], np.nan, inplace=True)
611 doubling_times_7 = (data_since_threshold.loc[(slice(None), COUNTRIES_OF_INTEREST), ['doubling_time_7']]
612 .unstack().sort_index().xs('doubling_time_7', axis=1, drop_level=True))
613 doubling_times_7.replace([np.inf, -np.inf], np.nan, inplace=True)
617 ax = doubling_times.plot(figsize=(10, 6), title="Doubling times, 4 day average")
618 for c in doubling_times.columns:
619 lvi = doubling_times[c].last_valid_index()
620 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
621 # plt.savefig('covid_deaths_per_day.png')
625 ax = doubling_times_7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Doubling times, 7 day average")
626 ax.legend(loc="upper left")
627 for c in COUNTRIES_CORE:
628 lvi = doubling_times_7[c].last_valid_index()
629 ax.text(x = lvi + 1, y = doubling_times_7[c][lvi], s = c)
630 plt.savefig('covid_doubling_times_7.png')
634 ax = doubling_times[COUNTRIES_CORE].plot(figsize=(10, 6), title="Doubling times, 4 day average")
635 for c in COUNTRIES_CORE:
636 lvi = doubling_times[c].last_valid_index()
637 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
638 plt.savefig('covid_doubling_times.png')
642 ax = doubling_times[COUNTRIES_FRIENDS].plot(figsize=(10, 6), title="Doubling times")
643 for c in COUNTRIES_FRIENDS:
644 lvi = doubling_times[c].last_valid_index()
645 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
646 plt.savefig('covid_doubling_times_friends.png')
650 ax = doubling_times[C7s].plot(figsize=(10, 6), title="Doubling times")
652 lvi = doubling_times[c].last_valid_index()
653 ax.text(x = lvi + 1, y = doubling_times[c][lvi], s = c)
654 # plt.savefig('covid_doubling_times_friends.png')
658 # deaths_diff_m4 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_diff_m4']]
659 # .unstack().sort_index().xs('deaths_diff_m4', axis=1, drop_level=True))
663 # deaths_diff_m7 = (data_since_threshold.loc[(slice(None), COUNTRIES_ALL), ['deaths_diff_m7']]
664 # .unstack().sort_index().xs('deaths_diff_m7', axis=1, drop_level=True))
672 # data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last().loc[COUNTRIES_ALL]#, [doubling_time]]
676 dstl = data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last()
677 dstl.loc[dstl.index.intersection(COUNTRIES_ALL)]
681 # data_since_threshold.replace([np.inf, -np.inf], np.nan).groupby(level=1).last().loc[['UK', 'DE', 'IT']]#, [doubling_time]]
682 dstl.loc[['UK', 'DE', 'IT', 'FR', 'ES']]
686 data_since_threshold.loc[(slice(None), ['UK']), :].tail(20)
690 data_since_threshold.loc[(slice(None), ['ES']), :].tail(20)
696 data_since_threshold.loc[(slice(None), ['UK']), :].tail(15)
700 it_since_threshold = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['IT']), :]
701 s_end = it_since_threshold.index.max()[0]
706 uk_projection = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), :]
707 uk_current_end = uk_projection.index.max()[0] + 1
708 # s_start = uk_projection.index.max()[0] + 1
713 current_uk_deaths_m7 = uk_projection[uk_projection.deaths_m7 >= 0].iloc[-1].deaths_m7
718 it_since_threshold[it_since_threshold.deaths_m7 <= current_uk_deaths_m7].loc[60:].first_valid_index()[0]
722 s_start = it_since_threshold[it_since_threshold.deaths_m7 <= current_uk_deaths_m7].loc[60:].first_valid_index()[0]
727 s_start_date = data_since_threshold.loc[(89, 'IT'), 'dateRep']# .iloc[0]
736 uk_end = s_end - s_start + uk_current_end
741 proj = it_since_threshold.loc[(slice(s_start, s_end), slice(None)), ['cases', 'deaths', 'deaths_m7']]
742 ndiff = uk_current_end - s_start
743 proj.index = pd.MultiIndex.from_tuples([(n + ndiff, 'UK') for n, _ in proj.index], names=proj.index.names)
748 it_since_threshold.loc[(slice(s_start - 8, s_start + 2), slice(None)), ['cases', 'deaths', 'deaths_m7']]
752 uk_projection[['cases', 'deaths', 'deaths_m7']].tail()
756 # proj['deaths_m7'] = proj['deaths_m7'] + 20
760 Projected deaths, UK following IT trend from now.
763 uk_projection = uk_projection.append(proj, sort=True)
764 uk_projection.deaths.sum()
768 uk_projection = uk_projection.droplevel(1)
773 uk_projection.loc[152, 'deaths']
776 ## Correction for cumulative deaths correction on 14 August
779 # uk_projection.loc[152, 'deaths'] = 50
783 uk_projection['deaths_m7'] = uk_projection['deaths'].transform(lambda x: x.rolling(7, 1).mean())
784 uk_projection.loc[(uk_current_end - 20):(uk_current_end + 5)]
788 uk_projection.loc[(uk_current_end - 5):]
792 uk_projection.deaths_m7.plot()
796 proj.droplevel(level=1)
800 ax = deaths_m7[COUNTRIES_CORE].plot()
801 # uk_projection['deaths_m7'].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average", label="Projection", style='--', ax=ax)
802 proj.droplevel(level=1)['deaths_m7'].plot(figsize=(10, 6), title="Deaths per day, 7 day moving average", label="Projection", style='--', ax=ax)
803 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
804 for c in COUNTRIES_CORE:
805 lvi = deaths_m7[c].last_valid_index()
806 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = c)
807 plt.savefig('covid_deaths_per_day_7.png')
811 it_since_threshold.deaths.sum()
814 # Excess deaths calculation
817 with open('excess_deaths.json') as f:
818 excess_deaths_data = json.load(f)
820 with open('excess_death_accuracy.json') as f:
821 excess_death_accuracy = json.load(f)
823 excess_deaths_data, excess_death_accuracy
827 # excess_deaths_upto = '2020-05-08'
828 # excess_deaths = 54500
832 excess_deaths_upto = excess_deaths_data['end_date']
833 excess_deaths = excess_deaths_data['excess_deaths']
836 Recorded deaths in period where ONS has reported total deaths
839 ons_reported_deaths = base_data.loc['UK'][:excess_deaths_upto]['deaths'].sum()
847 ## Correction for deaths total correction on 14 August
850 ons_unreported_deaths_data = base_data.loc['UK'][excess_deaths_upto:].iloc[1:]['deaths']
851 # ons_unreported_deaths_data['2020-08-14'] = 50
855 ons_unreported_deaths = ons_unreported_deaths_data.sum()
856 ons_unreported_deaths
860 scaled_ons_unreported_deaths = ons_unreported_deaths * excess_death_accuracy
861 scaled_ons_unreported_deaths
865 uk_deaths_to_date = excess_deaths + scaled_ons_unreported_deaths
870 # data_since_threshold.loc[(slice(None), 'UK'), :][data_since_threshold.dateRep == excess_deaths_data['end_date']]
874 data_since_threshold[data_since_threshold.dateRep == excess_deaths_data['end_date']].loc[(slice(None), 'UK'), :]
878 ons_unreported_start = data_since_threshold[data_since_threshold.dateRep == excess_deaths_data['end_date']].loc[(slice(None), 'UK'), :].first_valid_index()[0] + 1
883 unreported_projected_deaths = uk_projection.loc[ons_unreported_start:].deaths.sum()
884 unreported_projected_deaths
888 unreported_projected_deaths_scaled = unreported_projected_deaths * excess_death_accuracy
889 unreported_projected_deaths_scaled
893 uk_projection.loc[(s_start):].deaths.sum()
897 deaths_actual_projected_scaled = uk_deaths_to_date + uk_projection.loc[(s_start):].deaths.sum() * excess_death_accuracy
898 deaths_actual_projected_scaled
902 # excess_deaths / reported_deaths
905 True deaths to date, if we follow the scaling of excess deaths over reported deaths so far.
908 uk_covid_deaths = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths_culm'].iloc[-1]
913 # uk_covid_deaths_scaled = excess_deaths + unreported_deaths * excess_death_accuracy
914 # uk_covid_deaths_scaled
918 # 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')
922 # data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'dateRep'].iloc[-1].strftime("%Y-%m-%d")
926 # uk_covid_deaths * excess_deaths / reported_deaths
930 # uk_projection.deaths.sum() * excess_deaths / reported_deaths
934 # data_since_threshold.loc[(slice(None), 'FR'), :]
935 # data_since_threshold[data_since_threshold.dateRep == '2020-05-18'].loc[(slice(None), 'FR'), :]
941 school_reopenings = {
942 'ES': {'date': '2020-05-18'},
943 'FR': {'date': '2020-05-18'}, # some areas only
944 # 'IT': {'date': '2020-09-01'},
945 # 'IE': {'date': '2020-09-01'},
946 'DE': {'date': '2020-05-04'},
947 'UK': {'date': '2020-06-01'}
952 data_since_threshold[data_since_threshold.dateRep == '2020-05-04'].loc[(slice(None), ['DE']), :].first_valid_index()
956 data_since_threshold[data_since_threshold.dateRep == '2020-05-04'].loc[(slice(None), ['DE']), :].iloc[0].deaths_m7
960 for cID in school_reopenings:
961 dst_in = data_since_threshold[data_since_threshold.dateRep == (school_reopenings[cID]['date'])].loc[(slice(None), [cID]), :]
962 dst_i = dst_in.first_valid_index()
963 dst_n = dst_in.iloc[0].deaths_m7
964 school_reopenings[cID]['since_threshold'] = dst_i[0]
965 school_reopenings[cID]['deaths_m7'] = dst_n
970 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average")
971 # uk_projection.deaths_m7.plot(ax=ax)
972 for c in COUNTRIES_CORE:
973 lvi = deaths_m7[c].last_valid_index()
974 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}")
975 if c in school_reopenings:
976 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
977 ax.plot(school_reopenings[c]['since_threshold'], school_reopenings[c]['deaths_m7'], '*',
978 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
979 ax.text(x = school_reopenings[c]['since_threshold'] + 1, y = school_reopenings[c]['deaths_m7'],
980 s = f"{school_reopenings[c]['date']}: {school_reopenings[c]['deaths_m7']:.0f}")
981 plt.savefig('school_reopenings.png')
985 # ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average",
986 # xlim=(46, 91), ylim=(0, 400))
987 # # uk_projection.deaths_m7.plot(ax=ax)
988 # for c in COUNTRIES_CORE:
989 # lvi = deaths_m7[c].last_valid_index()
990 # ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}", fontsize=14)
991 # if c in school_reopenings:
992 # marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
993 # ax.plot(school_reopenings[c]['since_threshold'], school_reopenings[c]['deaths_m7'], '*',
994 # markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
995 # ax.text(x = school_reopenings[c]['since_threshold'] + 1, y = school_reopenings[c]['deaths_m7'],
996 # s = f"{school_reopenings[c]['date']}: {school_reopenings[c]['deaths_m7']:.0f}",
998 # plt.savefig('school_reopenings_detail.png')
1005 'ES': { 'part_start': {'date': '2020-03-14'}
1006 , 'full_start': {'date': '2020-03-15'}
1007 , 'part_finish': {'date': '2020-05-18'}
1009 'FR': { 'part_start': {'date': '2020-03-13'}
1010 , 'full_start': {'date': '2020-03-17'}
1011 , 'part_finish': {'date': '2020-05-11'}
1013 'IT': { 'part_start': {'date': '2020-03-08'}
1014 , 'full_start': {'date': '2020-03-10'}
1015 , 'part_finish': {'date': '2020-05-04'}
1017 'DE': { #'part_start': {'date': '2020-03-13'}
1018 'full_start': {'date': '2020-03-22'}
1019 , 'part_finish': {'date': '2020-05-06'}
1021 'UK': { 'part_start': {'date': '2020-03-23'}
1022 , 'full_start': {'date': '2020-03-23'}
1023 , 'part_finish': {'date': '2020-05-31'}
1025 'IE': { #'part_start': {'date': '2020-03-12'}
1026 'full_start': {'date': '2020-03-27'}
1027 , 'part_finish': {'date': '2020-05-18'}
1033 for cID in lockdown_dates:
1034 for phase in lockdown_dates[cID]:
1035 dst_in = data_since_threshold[data_since_threshold.dateRep == (lockdown_dates[cID][phase]['date'])].loc[(slice(None), [cID]), :]
1036 dst_i = dst_in.first_valid_index()
1037 dst_n = dst_in.iloc[0].deaths_m7
1038 dst_c = dst_in.iloc[0].cases_m7
1039 lockdown_dates[cID][phase]['since_threshold'] = dst_i[0]
1040 lockdown_dates[cID][phase]['deaths_m7'] = dst_n
1041 lockdown_dates[cID][phase]['cases_m7'] = dst_c
1047 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving averagee, with lockdown dates")
1048 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1049 # uk_projection.deaths_m7.plot(ax=ax)
1050 for c in COUNTRIES_CORE:
1051 lvi = deaths_m7[c].last_valid_index()
1053 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}")
1054 if c in lockdown_dates:
1055 for phase in lockdown_dates[c]:
1056 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1057 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['deaths_m7'], '*',
1058 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1059 if 'start' not in phase:
1060 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 1, y = lockdown_dates[c][phase]['deaths_m7'],
1061 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['deaths_m7']:.0f}")
1062 # plt.savefig('school_reopenings.png')
1066 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))
1067 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1068 # uk_projection.deaths_m7.plot(ax=ax)
1069 for c in COUNTRIES_CORE:
1070 lvi = cases_m7[c].last_valid_index()
1072 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = f"{c}: {cases_m7[c][lvi]:.0f}")
1077 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Cases per day, 7 day moving average, with lockdown dates")
1078 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1079 # uk_projection.deaths_m7.plot(ax=ax)
1080 for c in COUNTRIES_CORE:
1081 lvi = cases_m7[c].last_valid_index()
1083 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = f"{c}: {cases_m7[c][lvi]:.0f}")
1084 if c in lockdown_dates:
1085 for phase in lockdown_dates[c]:
1086 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1087 if 'start' in phase:
1091 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['cases_m7'],
1093 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1094 if 'start' not in phase:
1095 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 1, y = lockdown_dates[c][phase]['cases_m7'],
1096 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['cases_m7']:.0f}")
1097 plt.savefig('cases_per_day_with_lockdown.png')
1101 ax = cases_m7[COUNTRIES_CORE].plot(figsize=(10, 6), title="Cases per day, 7 day moving average")
1102 for c in COUNTRIES_CORE:
1103 lvi = cases_m7[c].last_valid_index()
1104 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = c)
1105 plt.savefig('covid_cases_per_day-core.png')
1109 ax = deaths_m7[COUNTRIES_CORE].plot(figsize=(15, 9), title="Deaths per day, 7 day moving average",
1113 # uk_projection.deaths_m7.plot(ax=ax)
1114 for c in COUNTRIES_CORE:
1115 lvi = deaths_m7[c].last_valid_index()
1116 if c in lockdown_dates:
1117 for phase in lockdown_dates[c]:
1118 if 'start' in phase:
1120 marker_col = [l for l in ax.lines if l.get_label() == c][0].get_color()
1121 ax.plot(lockdown_dates[c][phase]['since_threshold'], lockdown_dates[c][phase]['deaths_m7'], '*',
1122 markersize=18, markerfacecolor=marker_col, markeredgecolor=marker_col)
1123 ax.text(x = lockdown_dates[c][phase]['since_threshold'] + 0.3, y = lockdown_dates[c][phase]['deaths_m7'],
1124 s = f"{lockdown_dates[c][phase]['date']}: {lockdown_dates[c][phase]['deaths_m7']:.0f}")
1125 # plt.savefig('school_reopenings.png')
1136 # Write results to summary file
1139 with open('covid_summary.md', 'w') as f:
1140 f.write('% Covid death data summary\n')
1141 f.write('% Neil Smith\n')
1142 f.write(f'% Created on {datetime.datetime.now().strftime("%Y-%m-%d")}\n')
1145 last_uk_date = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'dateRep'].iloc[-1]
1146 f.write(f'> Last UK data from {last_uk_date.strftime("%Y-%m-%d")}\n')
1150 with open('covid_summary.md', 'a') as f:
1152 f.write('## Headlines\n')
1154 f.write('| []() | |\n')
1155 f.write('|:---|---:|\n')
1156 f.write(f'| Deaths reported so far | {uk_covid_deaths} | \n')
1157 f.write(f'| Total Covid deaths to date (estimated) | {uk_deaths_to_date:.0f} |\n')
1158 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')
1159 f.write(f'| Projected total deaths up to {projection_date.strftime("%Y-%m-%d")} | {deaths_actual_projected_scaled:.0f} | \n')
1164 with open('covid_summary.md', 'a') as f:
1166 f.write('## Total deaths\n')
1167 f.write(f'Time based on days since {DEATH_COUNT_THRESHOLD} deaths\n')
1169 f.write('![Total deaths](covid_deaths_total_linear.png)\n')
1171 f.write('| Country ID | Country name | Total deaths |\n')
1172 f.write('|:-----------|:-------------|-------------:|\n')
1173 for c in sorted(COUNTRIES_CORE):
1174 lvi = deaths[c].last_valid_index()
1175 f.write(f'| {c} | {countries.loc[c].countriesAndTerritories} | {int(deaths[c][lvi])} |\n')
1180 with open('covid_summary.md', 'a') as f:
1182 f.write('## All-causes deaths, UK\n')
1184 f.write('![All-causes deaths](deaths-radar.png)\n')
1186 f.write('### Excess deaths\n')
1188 f.write(f'From week ending 20 March 2020 until week ending {pd.to_datetime(excess_deaths_upto).strftime("%d %B %Y")}, ')
1189 f.write(f'there were approximately **{excess_deaths:.0f}** excess deaths, over the average for the previous five years.\n')
1194 with open('covid_summary.md', 'a') as f:
1195 f.write(f'In that period, the UK reported {ons_reported_deaths} Covid deaths.\n')
1196 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')
1197 # 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')
1199 f.write(f'The UK has reported {uk_covid_deaths} deaths so far.\n')
1200 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')
1205 with open('covid_summary.md', 'a') as f:
1207 f.write('## Deaths per day\n')
1208 f.write(f'Based on a 7-day moving average\n')
1210 f.write('![Deaths per day](covid_deaths_per_day_7.png)\n')
1219 with open('covid_summary.md', 'a') as f:
1221 f.write('## Projected deaths\n')
1222 f.write(f"The UK's daily deaths data is very similar to Italy's.\n")
1223 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),')
1224 f.write(f' the UK will report {uk_projection.deaths.sum()} deaths on day {uk_end} of the epidemic.\n')
1226 f.write('Using the excess deaths scaling from above, that will translate into ')
1227 f.write(f'**{deaths_actual_projected_scaled:.0f}** Covid deaths total.\n')
1232 with open('covid_summary.md', 'a') as f:
1234 f.write('## Deaths doubling times\n')
1235 f.write(f'Based on a 7-day moving average\n')
1237 f.write('![Deaths doubling times](covid_doubling_times_7.png)\n')
1242 with open('covid_summary.md', 'a') as f:
1244 f.write('## Cases per day and lockdown dates\n')
1245 f.write(f'Based on a 7-day moving average\n')
1247 f.write('![Cases per day](cases_per_day_with_lockdown.png)\n')
1252 with open('covid_summary.md', 'a') as f:
1254 f.write('| Country ID | Country name | Most recent daily cases | Most recent daily deaths |\n')
1255 f.write('|:-----------|:-------------|------------------------:|-------------------------:|\n')
1256 for c in sorted(COUNTRIES_CORE):
1257 lvic = cases_m7[c].last_valid_index()
1258 lvid = deaths_m7[c].last_valid_index()
1259 f.write(f'| {c} | {countries.loc[c].countriesAndTerritories} | {cases_m7[c][lvic]:.0f} | {deaths_m7[c][lvid]:.0f} | \n')
1261 f.write('(Figures are 7-day averages)\n')
1266 with open('covid_summary.md', 'a') as f:
1267 f.write('# Data sources\n')
1269 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')
1271 f.write("""> Population data from:
1273 * [Office of National Statistics](https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/deaths/datasets/weeklyprovisionalfiguresondeathsregisteredinenglandandwales) (Endland and Wales) Weeks start on a Saturday.
1274 * [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.
1275 * [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.""")
1278 f.write('> [Source code available](https://git.njae.me.uk/?p=covid19.git;a=tree)\n')
1284 !pandoc -s covid_summary.md > covid_summary.html
1288 !scp covid_summary.html neil@ogedei:/var/www/scripts.njae.me.uk/covid/index.html
1289 !scp covid_deaths_total_linear.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1290 !scp deaths-radar.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1291 !scp covid_deaths_per_day_7.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1292 !scp covid_doubling_times_7.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1293 !scp cases_per_day_with_lockdown.png neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1297 with open('uk_covid_deaths.js', 'w') as f:
1298 f.write(f"document.write('{uk_covid_deaths}');")
1300 with open('estimated_total_deaths.js', 'w') as f:
1301 f.write(f"document.write('{uk_deaths_to_date:.0f}');")
1303 with open('projection_date.js', 'w') as f:
1304 f.write(f"document.write(\'{projection_date.strftime('%d %B %Y')}\');")
1306 with open('projected_deaths.js', 'w') as f:
1307 f.write(f"document.write('{uk_projection.deaths.sum():.0f}');")
1309 with open('projected_excess_deaths.js', 'w') as f:
1310 f.write(f"document.write('{deaths_actual_projected_scaled:.0f}');")
1312 with open('excess_deaths_upto.js', 'w') as f:
1313 f.write(f"document.write('{pd.to_datetime(excess_deaths_upto).strftime('%d %B %Y')}');")
1315 with open('excess_deaths.js', 'w') as f:
1316 f.write(f"document.write('{excess_deaths:.0f}');")
1318 with open('reported_deaths.js', 'w') as f:
1319 f.write(f"document.write('{ons_reported_deaths:.0f}');")
1321 with open('scaling_factor.js', 'w') as f:
1322 f.write(f"document.write('{excess_death_accuracy:.2f}');")
1324 with open('projection_length.js', 'w') as f:
1325 f.write(f"document.write('{s_end - s_start - 1}');")
1327 with open('s_end.js', 'w') as f:
1328 f.write(f"document.write('{s_end}');")
1330 s_start_date_str = s_start_date.strftime("%d %B %Y")
1331 with open('s_start_date.js', 'w') as f:
1332 f.write(f"document.write('{s_start_date_str}');")
1334 with open('uk_end.js', 'w') as f:
1335 f.write(f"document.write('{uk_end}');")
1337 with open('last_uk_date.js', 'w') as f:
1338 f.write(f"document.write('{pd.to_datetime(last_uk_date).strftime('%d %B %Y')}');")
1342 pd.to_datetime(excess_deaths_upto).strftime('%d %B %Y')
1346 !scp uk_covid_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1347 !scp estimated_total_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1348 !scp projection_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1349 !scp projected_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1350 !scp projected_excess_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1351 !scp excess_deaths_upto.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1352 !scp excess_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1353 !scp reported_deaths.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1354 !scp scaling_factor.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1355 !scp projection_length.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1356 !scp s_end.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1357 !scp s_start_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1358 !scp uk_end.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1359 !scp last_uk_date.js neil@ogedei:/var/www/scripts.njae.me.uk/covid/
1363 data_by_date.loc['UK'].to_csv('data_by_day_uk.csv', header=True, index=True)
1367 ukd = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), ['deaths', 'deaths_m7']].droplevel(1)
1368 ax = ukd.deaths.plot.bar(figsize=(12, 8))
1369 ukd.deaths_m7.plot.line(ax=ax, color='red')
1370 # ax = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths_m7'].plot.line(figsize=(12, 8), color='red')
1371 # ax = data_since_threshold.replace([np.inf, -np.inf], np.nan).loc[(slice(None), ['UK']), 'deaths'].plot.bar(ax=ax)
1372 ax.set_xticks(range(0, 120, 20))
1376 np.arange(0, 130, 20)
1380 data_by_date.loc['UK']
1384 data_by_date.loc['UK'].plot(x='deaths_culm', y='deaths', logx=True, logy=True)
1388 data_by_date.loc['UK'].plot(x='cases_culm', y='cases')
1392 ukdbd = data_by_date.loc['UK'].copy()
1393 ukdbd['deaths_m7'] = ukdbd.deaths.transform(lambda x: x.rolling(7, 1).mean())
1394 ukdbd['cases_m7'] = ukdbd.cases.transform(lambda x: x.rolling(7, 1).mean())
1399 ukdbd.plot(x='deaths_culm', y='deaths_m7', logx=True, logy=True)
1403 fig, ax = plt.subplots(figsize=(12, 8))
1405 for c in COUNTRIES_CORE:
1406 if data_since_threshold.loc[(slice(None), c), 'deaths_culm'].max() > xmax:
1407 xmax = data_since_threshold.loc[(slice(None), c), 'deaths_culm'].max()
1408 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)
1412 data_since_threshold.loc[(slice(None), 'UK'), 'deaths_culm'].max()
1416 countries.continentExp.unique()
1424 data_by_date.groupby(level=0)['deaths'].shift(-25)
1428 offset_data = data_by_date.loc[:, ['cases']]
1429 offset_data['deaths'] = data_by_date.groupby(level=0)['deaths'].shift(-25)
1430 offset_data['cases_m7'] = offset_data.groupby(level=0)['cases'].transform(lambda x: x.rolling(7, 1).mean())
1431 offset_data['deaths_m7'] = offset_data['deaths'].dropna().groupby(level=0).transform(lambda x: x.rolling(7, 1).mean())
1432 offset_data['deaths_per_case'] = offset_data.deaths_m7 / offset_data.cases_m7
1441 offset_deaths_m7 = (offset_data.loc[COUNTRIES_ALL, ['deaths_m7']]
1442 .unstack().sort_index().xs('deaths_m7', axis=1, drop_level=True)).T.sort_index()
1447 offset_deaths_m7['UK']
1451 data_since_threshold.loc[(slice(None), 'UK'), :].tail()
1459 ax = cases_m7.iloc[-50:][COUNTRIES_FRIENDS].plot(figsize=(15, 9), title="Cases per day, 7 day moving average", ylim=(-10, 1500))
1460 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1461 # uk_projection.deaths_m7.plot(ax=ax)
1462 for c in COUNTRIES_FRIENDS:
1463 lvi = cases_m7[c].last_valid_index()
1465 ax.text(x = lvi + 1, y = cases_m7[c][lvi], s = f"{c}: {cases_m7[c][lvi]:.0f}")
1470 ax = deaths_m7.iloc[-50:][COUNTRIES_FRIENDS].plot(figsize=(15, 9), title="Cases per day, 7 day moving average", ylim=(-10, 100))
1471 ax.set_xlabel(f"Days since {DEATH_COUNT_THRESHOLD} deaths")
1472 # uk_projection.deaths_m7.plot(ax=ax)
1473 for c in COUNTRIES_FRIENDS:
1474 lvi = deaths_m7[c].last_valid_index()
1476 ax.text(x = lvi + 1, y = deaths_m7[c][lvi], s = f"{c}: {deaths_m7[c][lvi]:.0f}")