diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index e0904dd4..a4fc0c36 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -1,7 +1,12 @@ +import base64 from datetime import datetime +import io from pathlib import Path import jinja2 +import matplotlib +matplotlib.use('agg') +import matplotlib.pyplot as plt import numpy as np from cara import models @@ -10,13 +15,19 @@ from .model_generator import FormData def calculate_report_data(model: models.Model): resolution = 600 - times = list(np.linspace(0, 10, resolution)) + + # TODO: Have this for exposed not infected. + t_start = model.infected.presence.boundaries()[0][0] + t_end = model.infected.presence.boundaries()[-1][1] + + times = list(np.linspace(t_start, t_end, resolution)) concentrations = [model.concentration(time) for time in times] highest_const = max(concentrations) prob = model.infection_probability() er = model.infected.emission_rate(0.1) exposed_occupants = model.exposed_occupants r0 = prob * exposed_occupants / 100 + return { "times": times, "concentrations": concentrations, @@ -25,14 +36,46 @@ def calculate_report_data(model: models.Model): "emission_rate": er, "exposed_occupants": exposed_occupants, "R0": r0, + "scenario_plot_src": embed_figure(plot(times, concentrations)), } + +def embed_figure(figure) -> str: + # Draw the scenario graph. + img_data = io.BytesIO() + + figure.savefig(img_data, format='png', bbox_inches="tight") + plt.close() + img_data.seek(0) + pic_hash = base64.b64encode(img_data.read()).decode('ascii') + # A src suitable for a tag such as f'. + return f'data:image/png;base64,{pic_hash}' + + +def plot(times, concentrations): + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1) + ax.plot(times, concentrations) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + + ax.set_xlabel('Hours from start of event') + ax.set_ylabel('Concentration ($q/m^3$)') + ax.set_title('Concentration of infectious quanta aerosols') + + # top = max([0.75, max(concentrations)]) + # print(max(concentrations)) + # ax.set_ylim(bottom=1e-4, top=top) + return fig + + def build_report(model: models.Model, form: FormData): now = datetime.now() time = now.strftime("%d/%m/%Y %H:%M:%S") request = {"the": "form", "request": "data"} + context = { - 'model': model, + 'model': model, 'request': request, 'creation_date': time, 'model_version': 'Beta v1.0.0', @@ -65,8 +108,6 @@ def build_report(model: models.Model, form: FormData): 'coffee_duration': form.coffee_duration, 'coffee_times': [['00:00','00:00'], ['00:00','00:00'], ['00:00','00:00'], ['00:00','00:00']], 'mask_wearing': form.mask_wearing, - 'infection_probability': round(model.infection_probability(), 2), - 'reproduction_rate': 2 } context.update(calculate_report_data(model)) diff --git a/cara/apps/calculator/templates/report.html.j2 b/cara/apps/calculator/templates/report.html.j2 index 86a7af7e..b716814f 100644 --- a/cara/apps/calculator/templates/report.html.j2 +++ b/cara/apps/calculator/templates/report.html.j2 @@ -121,8 +121,11 @@

Results:

-

In this scenario, the estimated probability of one exposed occupant getting infected P(i) is {{ infection_probability }} % and the estimated basic reproduction rate (R0) is {{ reproduction_rate }}.

+

+ In this scenario, the estimated probability of one exposed occupant getting infected P(i) is {{ "{:#.2g}".format(prob_inf) }}% and the estimated basic reproduction rate (R0) is {{ "{:#.2g}".format(R0) }}. +

Exposure graph:

+