diff --git a/plot.py b/plot.py index d47c463..326b3c4 100644 --- a/plot.py +++ b/plot.py @@ -15,14 +15,10 @@ import locale import os.path import shutil import math -from functools import reduce -from matplotlib.dates import date2num, DateFormatter, WeekdayLocator -import matplotlib.dates as mdates +from matplotlib.dates import date2num import matplotlib.ticker as mtick -from isoweek import Week - locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8') site_folder = 'site/' @@ -37,7 +33,7 @@ print_today = today.isoformat() filename_now = datetime.datetime.now().strftime("%Y%m%d%H%M%S") -force_renew = True + # https://www.tagesschau.de/ausland/europa/ursula-von-der-leyen-zu-corona-impfstoffen-101.html target_date_for_herd_immunity = datetime.date(2021, 9, 22) @@ -65,7 +61,7 @@ raw_data = rki_file['Impfungen_proTag'] impfungen = raw_data[:-1].dropna(subset=['Datum'])#.fillna(0) -impfungen.drop(impfungen.tail(3).index,inplace=True) # remove Gesamt row +impfungen.drop(impfungen.tail(1).index,inplace=True) # remove Gesamt row dates = impfungen['Datum'] @@ -91,17 +87,6 @@ def calculate_vaccination_data(data): mean_all_time = np.mean(valid_data) mean_seven_days = np.mean(data[-7:]) - vaccinations_by_week_map = map(lambda x: (Week.withdate(x[0]), x[1]), zip(dates, data)) - - vaccinations_by_week = {} - - for w, v in vaccinations_by_week_map: - if w in vaccinations_by_week: - vaccinations_by_week[w] = vaccinations_by_week[w] + v - else: - vaccinations_by_week[w] = v - - def extrapolate(rate, to_be_vaccinated): days_extrapolated = int(np.ceil(to_be_vaccinated / rate)) extrapolated_dates = np.array([dates[0] + datetime.timedelta(days=i) for i in range(days_extrapolated)]) @@ -146,7 +131,6 @@ def calculate_vaccination_data(data): 'days_since_start': days_since_start_of_vaccination + 1, # Shift from zero to one-based-index 'start_of_vaccination_date': start_of_vaccination_date, 'start_of_vaccination_date_str': start_of_vaccination_date.strftime('%d. %B %Y'), - 'vaccinations_by_week': vaccinations_by_week, 'extrapolation_mean_all_time': extrapolation_mean_all_time, 'extrapolation_last_rate': extrapolation_last_rate, 'extrapolation_mean_seven_days': extrapolation_mean_seven_days, @@ -287,12 +271,90 @@ else: + +def plot_extrapolation_portion(percentage): + + print_percentage = int(percentage * 100) + archive_plot_filename = '{}/extrapolated_to_{}_percent'.format(archive_folder, print_percentage) + latest_plot_filename = '{}/extrapolated_to_{}_percent'.format(site_folder, print_percentage) + + if os.path.isfile(archive_plot_filename + '.pdf'): + print('Plot {} already exists'.format(archive_plot_filename)) + return + + fig, ax = plt.subplots(1) + + + plt.title( + 'Tägliche Impfrate (Erst- und Zweitimpfung übereinander), kumulierte Impfungen und lineare Extrapolation bis {:n} % der Bevölkerung Deutschlands\n' + 'Datenquelle: RKI, Stand: {}. Erstellung: {}, Ersteller: Benedikt Bastin, Lizenz: CC BY-SA 4.0\n' + 'Erstimpfungen: {:n} ({:n} %), Durchschnittliche Impfrate: {:n} Impfungen/Tag (läuft seit {:n} Tagen)\n' + 'Zweitimpfungen: {:n} ({:n} %), Durchschnittliche Impfrate: {:n} Impfungen/Tag (läuft seit {:n} Tagen)'.format( + print_percentage, + print_stand, print_today, + data_first_vaccination['total'], np.round(data_first_vaccination['total_percentage'], 2), data_first_vaccination['extrapolation_mean_all_time']['rate'], data_first_vaccination['days_since_start'], + data_second_vaccination['total'], np.round(data_second_vaccination['total_percentage'], 2), data_second_vaccination['extrapolation_mean_all_time']['rate'], data_second_vaccination['days_since_start'] + ) + ) + + ax2 = ax.twinx() + + ax.bar(dates, data_first_vaccination['daily'], label='Tägliche Erstimpfungen', color='blue') + ax.bar(dates, data_second_vaccination['daily'], label='Tägliche Zweitimpfungen', color='lightblue', bottom=data_first_vaccination['daily']) + + ax.plot(dates, data_first_vaccination['mean_vaccination_rates_daily'], color='violet', label='Durchschnittliche Erstimpfrate\nbis zu diesem Tag (inkl.)') + ax.plot(dates, data_second_vaccination['mean_vaccination_rates_daily'], color='magenta', label='Durchschnittliche Zweitimpfrate\nbis zu diesem Tag (inkl.)') + + ax2.set_ylim([0, einwohner_deutschland * percentage]) + ax2.set_xlim(xmax=dates[0] + datetime.timedelta(days=percentage * data_first_vaccination['extrapolation_mean_all_time']['days_extrapolated'])) + ax2.grid(True) + + ax2.plot(dates, data_first_vaccination['cumulative'], color='red', label='Kumulierte Erstimpfungen') + ax2.plot(dates, data_second_vaccination['cumulative'], color='indianred', label='Kumulierte Zweitimpfungen') + + ax2.plot(data_first_vaccination['extrapolation_mean_all_time']['dates'], data_first_vaccination['extrapolation_mean_all_time']['extrapolated_vaccinations'], color='orange', label='Extrap. kumulierte Erstimpfungen (Ø gesamt)\n{:n} Impfungen/Tag'.format(data_first_vaccination['extrapolation_mean_all_time']['rate_int'])) + ax2.plot(data_first_vaccination['extrapolation_mean_seven_days']['dates'], data_first_vaccination['extrapolation_mean_seven_days']['extrapolated_vaccinations'], color='goldenrod', label='Extrap. kumulierte Erstimpfungen (Ø 7 Tage)\n{:n} Impfungen/Tag'.format(data_first_vaccination['extrapolation_mean_seven_days']['rate_int'])) + ax2.plot() + + ax2.plot(data_second_vaccination['extrapolation_mean_all_time']['dates'], data_second_vaccination['extrapolation_mean_all_time']['extrapolated_vaccinations'], color='orange', label='Extrap. kumulierte Zweitimpfungen (Ø gesamt)\n{:n} Impfungen/Tag'.format(data_second_vaccination['extrapolation_mean_all_time']['rate_int'])) + ax2.plot(data_second_vaccination['extrapolation_mean_seven_days']['dates'], data_second_vaccination['extrapolation_mean_seven_days']['extrapolated_vaccinations'], color='goldenrod', label='Extrap. kumulierte Zweitimpfungen (Ø 7 Tage)\n{:n} Impfungen/Tag'.format(data_second_vaccination['extrapolation_mean_seven_days']['rate_int'])) + #ax2.plot() + + ax.legend(loc='upper left') + ax.get_yaxis().get_major_formatter().set_scientific(False) + + ax.set_xlabel('Datum') + ax.set_ylabel('Tägliche Impfungen') + + ax2.legend(loc='lower right') + ax2.get_yaxis().get_major_formatter().set_scientific(False) + + # Estimated percentage for herd immunity + #ax2.axline((0, einwohner_deutschland * 0.7), slope=0, color='green') + + ax2.set_ylabel('Kumulierte Impfungen') + + plt.savefig(archive_plot_filename + '.pdf') + plt.savefig(archive_plot_filename + '.png') + plt.savefig(latest_plot_filename + '.pdf') + plt.savefig(latest_plot_filename + '.png') + plt.close() + + print('Created plot {} as pdf and png'.format(archive_plot_filename)) + + +plot_extrapolation_portion(0.1) +#plot_extrapolation_portion(0.7) +plot_extrapolation_portion(1.0) + + + def plot_vaccination_bar_graph_total_time(): archive_plot_filename = '{}/vaccination_bar_graph_total_time'.format(archive_folder) latest_plot_filename = '{}/vaccination_bar_graph_total_time'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -330,76 +392,12 @@ def plot_vaccination_bar_graph_total_time(): plot_vaccination_bar_graph_total_time() -def plot_vaccination_bar_graph_total_time_by_week(): - - archive_plot_filename = '{}/vaccination_bar_graph_total_time_by_week'.format(archive_folder) - latest_plot_filename = '{}/vaccination_bar_graph_total_time_by_week'.format(site_folder) - - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: - print('Plot {} already exists'.format(archive_plot_filename)) - return - - fig, ax = plt.subplots(1) - - - plt.title( - 'Wöchentliche Impfrate (Erst- und Zweitimpfung übereinander)\n' - 'Datenquelle: RKI, Stand: {}. Erstellung: {}, Ersteller: Benedikt Bastin, Lizenz: CC BY-SA 4.0\n'.format( - print_stand, print_today - ) - ) - - ax.grid() - - w = [w.day(3) for w in data_first_vaccination['vaccinations_by_week'].keys()] - - f = list(data_first_vaccination['vaccinations_by_week'].values()) - s = list(data_second_vaccination['vaccinations_by_week'].values()) - - bar1 = ax.bar(w, f, label='Wöchentliche Erstimpfungen', color='blue', width=6.8) - bar2 = ax.bar(w, s, label='Wöchentliche Zweitimpfungen', color='lightblue', width=6.8, bottom=f) - - for r1, r2 in zip(bar1, bar2): - - x = r1.get_x() + r1.get_width() / 2.0 - - h1 = math.floor(r1.get_height() / 1000) - h2 = math.floor(r2.get_height() / 1000) - hg = math.floor((r1.get_height() + r2.get_height()) / 1000) - - if h1 > 30: - plt.text(x, h1 * 500, f'{h1:5n} k'.replace('.', ' '), ha='center', va='center', color='white') - - if h2 > 30: - plt.text(x, h1 * 1000 + h2 * 500, f'{h2:5n} k'.replace('.', ' '), ha='center', va='center', color='black') - - plt.text(x, hg * 1000, f'{hg:5n} k'.replace('.', ' '), ha='center', va='bottom') - - ax.legend(loc='upper left') - ax.get_xaxis().set_major_formatter(DateFormatter('%Y-w%W')) - ax.get_xaxis().set_major_locator(WeekdayLocator(3, 2)) - ax.get_yaxis().get_major_formatter().set_scientific(False) - - ax.set_xlabel('Datum') - ax.set_ylabel('Wöchentliche Impfungen') - - - plt.savefig(archive_plot_filename + '.pdf') - plt.savefig(archive_plot_filename + '.png') - plt.savefig(latest_plot_filename + '.pdf') - plt.savefig(latest_plot_filename + '.png') - plt.close() - - print('Created plot {} as pdf and png'.format(archive_plot_filename)) - -plot_vaccination_bar_graph_total_time_by_week() - def plot_vaccination_bar_graph_total_time_two_bars(): archive_plot_filename = '{}/vaccination_bar_graph_total_time_two_bars'.format(archive_folder) latest_plot_filename = '{}/vaccination_bar_graph_total_time_two_bars'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -445,7 +443,7 @@ def plot_vaccination_bar_graph_compare_both_vaccinations(): archive_plot_filename = '{}/vaccination_bar_graph_compare_both_vaccinations'.format(archive_folder) latest_plot_filename = '{}/vaccination_bar_graph_compare_both_vaccinations'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -491,7 +489,7 @@ def plot_cumulative_two_vaccinations(): archive_plot_filename = '{}/cumulative_two_vaccinations'.format(archive_folder) latest_plot_filename = '{}/cumulative_two_vaccinations'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -538,7 +536,7 @@ def plot_cumulative_two_vaccinations_percentage(): archive_plot_filename = '{}/cumulative_two_vaccinations_percentage'.format(archive_folder) latest_plot_filename = '{}/cumulative_two_vaccinations_percentage'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -587,7 +585,7 @@ def plot_people_between_first_and_second(): archive_plot_filename = '{}/people_between_first_and_second'.format(archive_folder) latest_plot_filename = '{}/people_between_first_and_second'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -637,7 +635,7 @@ def plot_vaccination_rate(): archive_plot_filename = '{}/vaccination_rate'.format(archive_folder) latest_plot_filename = '{}/vaccination_rate'.format(site_folder) - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: + if os.path.isfile(archive_plot_filename + '.pdf'): print('Plot {} already exists'.format(archive_plot_filename)) return @@ -681,117 +679,13 @@ def plot_vaccination_rate(): plot_vaccination_rate() -def plot_vaccination_done_days(): - - archive_plot_filename = '{}/vaccination_done_days'.format(archive_folder) - latest_plot_filename = '{}/vaccination_done_days'.format(site_folder) - - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: - print('Plot {} already exists'.format(archive_plot_filename)) - return - - fig, ax = plt.subplots(1) - - - plt.title( - 'Lin. Extrapolation der Erstimpfungen bis 70 % der Bevölkerung anhand der durchschn. Impfrate (Anzahl Tage, Gesamt und 7 Tage)\n' - 'Datenquelle: RKI, Stand: {}. Erstellung: {}, Ersteller: Benedikt Bastin, Lizenz: CC BY-SA 4.0\n'.format( - print_stand, print_today - ) - ) - d = data_first_vaccination - - days_remaining_daily = np.ceil((einwohner_deutschland * 0.7 - d['cumulative']) / (d['mean_vaccination_rates_daily'])) - days_remaining_rolling = np.ceil((einwohner_deutschland * 0.7 - d['cumulative']) / (d['vaccination_rates_daily_rolling_average'])) - - ax.set_ylim(0, 2500) - - ax.plot(dates, days_remaining_daily, label='Durchschnitt Gesamt', linewidth=0.5) - ax.plot(dates, days_remaining_rolling, label='Durchschnitt 7 Tage', linewidth=2) - - ax.grid(True) - - - ax.legend(loc='upper right') - ax.get_yaxis().get_major_formatter().set_scientific(False) - - ax.set_xlabel('Datum') - ax.set_ylabel('Tage, bis 70 % erreicht sind') - - plt.savefig(archive_plot_filename + '.pdf') - plt.savefig(archive_plot_filename + '.png') - plt.savefig(latest_plot_filename + '.pdf') - plt.savefig(latest_plot_filename + '.png') - plt.close() - - print('Created plot {} as pdf and png'.format(archive_plot_filename)) - -plot_vaccination_done_days() - -def plot_vaccination_done_dates(): - - archive_plot_filename = '{}/vaccination_done_dates'.format(archive_folder) - latest_plot_filename = '{}/vaccination_done_dates'.format(site_folder) - - if os.path.isfile(archive_plot_filename + '.pdf') and not force_renew: - print('Plot {} already exists'.format(archive_plot_filename)) - return - - fig, ax = plt.subplots(1) - - - plt.title( - 'Lin. Extrapolation der Erstimpfungen bis 70 % der Bevölkerung anhand der durchschn. Impfrate (Datum, Gesamt und 7 Tage)\n' - 'Datenquelle: RKI, Stand: {}. Erstellung: {}, Ersteller: Benedikt Bastin, Lizenz: CC BY-SA 4.0\n'.format( - print_stand, print_today - ) - ) - d = data_first_vaccination - - #print(d['cumulative']) - #print(np.sum(d['daily'])) - - #print((einwohner_deutschland - d['cumulative'])[:-1] - d['to_be_vaccinated']) - - - days_remaining_daily = np.ceil((einwohner_deutschland * 0.7 - d['cumulative']) / (d['mean_vaccination_rates_daily'])) - days_remaining_rolling = np.ceil((einwohner_deutschland * 0.7 - d['cumulative']) / (d['vaccination_rates_daily_rolling_average'])) - - dates_daily = [today + datetime.timedelta(days) for days in days_remaining_daily] - dates_rolling = [today + datetime.timedelta(days) for days in days_remaining_rolling.dropna()] - - #print(dates_rolling) - - ax.set_ylim(today, today + datetime.timedelta(int(np.max(days_remaining_rolling) * 1.05))) - - ax.plot(dates, dates_daily, label='Durchschnitt Gesamt', linewidth=0.5) - ax.plot(dates[6:], dates_rolling, label='Durchschnitt 7 Tage', linewidth=2) - - ax.grid(True) - - - ax.legend(loc='upper right') - - ax.set_xlabel('Datum') - ax.set_ylabel('Datum, an dem 70 % erreicht sind') - - plt.savefig(archive_plot_filename + '.pdf') - plt.savefig(archive_plot_filename + '.png') - plt.savefig(latest_plot_filename + '.pdf') - plt.savefig(latest_plot_filename + '.png') - plt.close() - - print('Created plot {} as pdf and png'.format(archive_plot_filename)) - -plot_vaccination_done_dates() - def render_dashboard(): dashboard_filename = 'site/index.xhtml' dashboard_archive_filename = 'site/archive/{}/index.xhtml'.format(filename_stand) stylesheet_filename = 'site/rki-dashboard.css' stylesheet_archive_filename = 'site/archive/{}/rki-dashboard.css'.format(filename_stand) - if os.path.isfile(dashboard_archive_filename) and not force_renew: + if os.path.isfile(dashboard_archive_filename): print('Dashboard {} already exists'.format(dashboard_archive_filename)) return @@ -826,44 +720,44 @@ def render_dashboard(): figures = [ { 'index': 1, + 'filename': 'extrapolated_to_10_percent', + 'caption': 'Tägliche Impfquote, kumulierte Impfungen und lineare Extrapolation bis 10 % der Bevölkerung Deutschlands' + },{ + 'index': 2, + 'filename': 'extrapolated_to_70_percent', + 'caption': 'Tägliche Impfquote, kumulierte Impfungen und lineare Extrapolation bis 70 % der Bevölkerung Deutschlands' + },{ + 'index': 3, + 'filename': 'extrapolated_to_100_percent', + 'caption': 'Tägliche Impfquote, kumulierte Impfungen und lineare Extrapolation bis 100 % der Bevölkerung Deutschlands' + },{ + 'index': 4, 'filename': 'vaccination_bar_graph_total_time', 'caption': 'Tägliche Impfrate (Erst- und Zweitimpfung übereinander)' },{ - 'index': 2, - 'filename': 'vaccination_bar_graph_total_time_by_week', - 'caption': 'Wöchentliche Impfrate (Erst- und Zweitimpfung übereinander)' - },{ - 'index': 3, + 'index': 5, 'filename': 'vaccination_bar_graph_total_time_two_bars', 'caption': 'Tägliche Impfrate (Erst- und Zweitimpfung nebeneinander)' },{ - 'index': 4, + 'index': 6, 'filename': 'vaccination_bar_graph_compare_both_vaccinations', 'caption': 'Tägliche Impfrate (Erst- und Zweitimpfung nebeneinander)' },{ - 'index': 5, + 'index': 7, 'filename': 'cumulative_two_vaccinations', 'caption': 'Kumulative Impfrate (Erst- und Zweitimpfung)' },{ - 'index': 6, + 'index': 8, 'filename': 'cumulative_two_vaccinations_percentage', 'caption': 'Kumulative Impfrate (Erst- und Zweitimpfung) in Prozent der Bevölkerung Deutschlands' },{ - 'index': 7, + 'index': 9, 'filename': 'people_between_first_and_second', 'caption': 'Anzahl der Personen zwischen Erst- und Zweitimpfung, also Personen, die die erste Impfung erhalten haben, die zweite aber noch nicht' },{ - 'index': 8, + 'index': 10, 'filename': 'vaccination_rate', 'caption': 'Tägliche Impfrate sowie durchschnittliche Impfrate' - },{ - 'index': 9, - 'filename': 'vaccination_done_days', - 'caption': 'Lineare Extrapolation bis 70 % der Bevölkerung anhand der Erstimpfungen der durchschnittlichen Impfrate (Anzahl Tage, Gesamt und 7 Tage)' - },{ - 'index': 10, - 'filename': 'vaccination_done_dates', - 'caption': 'Lineare Extrapolation bis 70 % der Bevölkerung anhand der Erstimpfungen der durchschnittlichen Impfrate (Datum, Gesamt und 7 Tage)' } ] ).dump('site/index.xhtml') diff --git a/requirements.txt b/requirements.txt index b1176b4..1e70fad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,4 @@ pandas openpyxl requests jinja2 -isoweek