Skip to content

Commit 4fa4b0c

Browse files
authored
Merge pull request #43 from wseis/evaluation
evaluation
2 parents 825c4c3 + e654857 commit 4fa4b0c

File tree

4 files changed

+205
-43
lines changed

4 files changed

+205
-43
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,5 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130-
qmra.db
130+
qmra.db
131+
notebooks

tools/qmratool/helper_functions.py

+118-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import plotly.express as px
22
import plotly.graph_objs as go
3-
3+
from django_pandas.io import read_frame
44

55
def plot_comparison(df, df2):
66
fig = px.box(
@@ -82,3 +82,120 @@ def plot_comparison(df, df2):
8282
marker_size=8, hovertemplate=None, hoverinfo="skip", line=dict(width=0)
8383
)
8484
return fig
85+
86+
87+
88+
def simulate_risk(ra):
89+
# Selecting inflow concentration based in source water type
90+
df_inflow = read_frame(
91+
Inflow.objects.filter(water_source=ra.source).values(
92+
"min", "max", "pathogen__pathogen", "water_source__water_source_name"
93+
)
94+
)
95+
df_inflow = df_inflow[
96+
df_inflow["pathogen__pathogen"].isin(
97+
["Rotavirus", "Campylobacter jejuni", "Cryptosporidium parvum"]
98+
)
99+
]
100+
# Querying dose response parameters based on pathogen inflow
101+
dr_models = read_frame(
102+
DoseResponse.objects.filter(
103+
pathogen__in=Pathogen.objects.filter(
104+
pathogen__in=df_inflow["pathogen__pathogen"]
105+
)
106+
)
107+
)
108+
109+
# Querying for Logremoval based on selected treatments
110+
df_treatment = read_frame(
111+
LogRemoval.objects.filter(treatment__in=ra.treatment.all()).values(
112+
"min", "max", "treatment__name", "pathogen_group__pathogen_group"
113+
)
114+
)
115+
116+
# Summarizing treatment to treatment max and treatment min
117+
# df_treatment_summary=df_treatment.groupby(["pathogen_group__pathogen_group"]).sum().reset_index()
118+
df_treatment_summary = (
119+
df_treatment.groupby(["pathogen_group__pathogen_group"])[["min", "max"]]
120+
.apply(lambda x: x.sum())
121+
.reset_index()
122+
)
123+
124+
results = pd.DataFrame()
125+
126+
for index, row in df_inflow.iterrows():
127+
d = df_inflow.loc[df_inflow["pathogen__pathogen"] == row["pathogen__pathogen"]]
128+
dr = dr_models.loc[dr_models["pathogen"] == row["pathogen__pathogen"]]
129+
130+
if row["pathogen__pathogen"] == "Rotavirus":
131+
selector = "Viruses"
132+
elif row["pathogen__pathogen"] == "Cryptosporidium parvum":
133+
selector = "Protozoa"
134+
else:
135+
selector = "Bacteria"
136+
# result.append(selector)
137+
138+
df_treat = df_treatment_summary[
139+
df_treatment_summary["pathogen_group__pathogen_group"] == selector
140+
]
141+
142+
risk_df = pd.DataFrame(
143+
{
144+
"inflow": np.random.normal(
145+
loc=(
146+
np.log10(float(d["min"]) + 10 ** (-8))
147+
+ np.log10(float(d["max"]))
148+
)
149+
/ 2,
150+
scale=(
151+
np.log10(float(d["max"]))
152+
- np.log10(float(d["min"]) + 10 ** (-8))
153+
)
154+
/ 4,
155+
size=10000,
156+
),
157+
"LRV": np.random.uniform(
158+
low=df_treat["min"], high=df_treat["min"], size=10000
159+
),
160+
"LRVmax": np.random.uniform(
161+
low=df_treat["max"], high=df_treat["max"], size=10000
162+
),
163+
}
164+
)
165+
risk_df["outflow"] = risk_df["inflow"] - risk_df["LRV"]
166+
risk_df["outflow_min"] = risk_df["inflow"] - risk_df["LRVmax"]
167+
168+
risk_df["dose"] = (10 ** risk_df["outflow"]) * float(
169+
ra.exposure.volume_per_event
170+
)
171+
risk_df["dose_min"] = (10 ** risk_df["outflow_min"]) * float(
172+
ra.exposure.volume_per_event
173+
)
174+
175+
if selector != "Protozoa":
176+
risk_df["probs"] = 1 - (
177+
1 + (risk_df["dose"]) * (2 ** (1 / float(dr.alpha)) - 1) / float(dr.n50)
178+
) ** -float(dr.alpha)
179+
risk_df["probs_min"] = 1 - (
180+
1
181+
+ (risk_df["dose_min"])
182+
* (2 ** (1 / float(dr.alpha)) - 1)
183+
/ float(dr.n50)
184+
) ** -float(dr.alpha)
185+
186+
else:
187+
risk_df["probs"] = 1 - np.exp(-float(dr.k) * (risk_df["dose"]))
188+
risk_df["probs_min"] = 1 - np.exp(-float(dr.k) * (risk_df["dose_min"]))
189+
190+
results[row["pathogen__pathogen"] + "_MinimumLRV"] = [
191+
annual_risk(int(ra.exposure.events_per_year), risk_df["probs"])
192+
for _ in range(1000)
193+
]
194+
results[row["pathogen__pathogen"] + "_MaximumLRV"] = [
195+
annual_risk(int(ra.exposure.events_per_year), risk_df["probs_min"])
196+
for _ in range(1000)
197+
]
198+
199+
results_long = pd.melt(results)
200+
results_long["log probability"] = np.log10(results_long["value"])
201+
return results_long

tools/qmratool/templates/qmratool/results.html

+19-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@
99
<a class = "btn btn-primary mt-3" href="{%url 'export' ra.id%}">Export summary as csv</a>
1010
</div>
1111
{%endif %}
12+
{% if risk%}
13+
<div class="alert alert-danger m-4" role="alert">
14+
At least one pathogen exeeds tolerable infection risk value of 1/10000 pppy (red line)
15+
</div>
16+
{%else %}
17+
<div class="alert alert-primary m-4" role="alert">
18+
All risk simulations stay well below tolerable limits of 1/10000 pppy (blue line)
19+
</div>
20+
{% endif %}
1221
<div id="hero-graph">
1322
{% autoescape off %}
1423
{{ risk_plot }}
@@ -22,7 +31,16 @@
2231
</p>
2332
</div>
2433
{%endif%}
25-
{%if ra.id %}
34+
{%if ra.id %}
35+
{% if dalyrisk%}
36+
<div class="alert alert-danger m-4" role="alert">
37+
At least one pathogen exeeds tolerable DALY risk value of 1µDALY pppy (red line)
38+
</div>
39+
{%else %}
40+
<div class="alert alert-primary m-4" role="alert">
41+
All risk simulations stay well below tolerable limits of 1µDALY pppy (blue line)
42+
</div>
43+
{% endif %}
2644
<div id="hero-graph">
2745
{% autoescape off %}
2846
{{ daly_plot }}

tools/qmratool/views.py

+66-40
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,30 @@
55
from django.shortcuts import render
66
from django.db import IntegrityError
77
from django.contrib.auth.decorators import login_required
8-
98
from qmratool.helper_functions import plot_comparison
9+
from django.urls import reverse_lazy
10+
from django.shortcuts import render, redirect
11+
from .forms import *
12+
from formtools.wizard.views import SessionWizardView
1013
from .forms import RAForm, SourceWaterForm, TreatmentForm, ExposureForm
1114
from .forms import LogRemovalForm, InflowForm, ComparisonForm
12-
1315
from .models import *
1416
from django.utils.encoding import force_str
15-
1617
django.utils.encoding.force_text = force_str
17-
1818
from django_pandas.io import read_frame
1919
from plotly.offline import plot
20-
2120
import numpy as np
2221
import pandas as pd
2322
import plotly.express as px
2423
import plotly.graph_objs as go
2524
import markdown2 as md
25+
from django.contrib import messages
26+
from django.contrib.auth import update_session_auth_hash
27+
from django.contrib.auth.forms import PasswordChangeForm
28+
from django.shortcuts import render, redirect
29+
30+
31+
2632

2733
# Create your views here.
2834

@@ -167,11 +173,6 @@ def new_assessment(request):
167173
return render(request, "qmratool/new_ra.html", {"form": form, "content": content})
168174

169175

170-
from django.urls import reverse_lazy
171-
from django.shortcuts import render, redirect
172-
from .forms import *
173-
174-
from formtools.wizard.views import SessionWizardView
175176

176177
TEMPLATES = {
177178
"0": "qmratool/step1.html",
@@ -431,17 +432,40 @@ def calculate_risk(request, ra_id):
431432
)
432433

433434
results_long = simulate_risk(ra)
435+
#results_long["value"] = round(results_long["value"],1)
434436

435437
results_long["pathogen"] = results_long["variable"].str.split("_", expand=True)[0]
436438
results_long["stat"] = results_long["variable"].str.split("_", expand=True)[1]
437439

440+
441+
442+
443+
438444
health = read_frame(Health.objects.all())
439445
results_long = pd.merge(results_long, health, on="pathogen")
440446
results_long["DALYs pppy"] = (
441447
results_long.value
442448
* results_long.infection_to_illness.astype(float)
443449
* results_long.dalys_per_case.astype(float)
444450
)
451+
summary = results_long.groupby(["pathogen", "stat"]).mean()
452+
risk = sum(summary["value"]>10**-4) > 0
453+
dalyrisk= sum(summary["DALYs pppy"]>10**-6) > 0
454+
455+
if risk:
456+
bgcolor = "rgba(245, 0, 0, 0.15)"
457+
lcolor = "firebrick"
458+
else:
459+
bgcolor = None
460+
lcolor = "#0003e2"
461+
462+
if dalyrisk:
463+
dalybgcolor = "rgba(245, 0, 0, 0.15)"
464+
dlcolor = "firebrick"
465+
else:
466+
dalybgcolor = None
467+
dlcolor = "#0003e2"
468+
445469

446470
risk_colors = ["#78BEF9", "#8081F1", "#5F60B3"]
447471
risk_colors_extended = [
@@ -463,37 +487,40 @@ def calculate_risk(request, ra_id):
463487
log_y=True,
464488
title="Risk as probability of infection per year",
465489
color_discrete_sequence=risk_colors,
490+
hover_data={'value': ':.2e'}
466491
)
467492

468493
fig.update_layout(
469494
font_family="Helvetica Neue, Helvetica, Arial, sans-serif",
470495
font_color="black",
496+
plot_bgcolor= bgcolor,
471497
title={"text": "Risk assessment as probability of infection per year"},
472498
xaxis_title="",
473499
yaxis_title="Probability of infection per year",
474500
# markersize= 12,
475501
)
476-
fig.add_hline(y=0.0001, line_dash="dashdot", line=dict(color="#0003e2", width=3))
502+
fig.add_hline(y=0.0001, line_dash="dashdot", line=dict(color=lcolor, width=3))
477503
fig.update_layout(
504+
# margin=dict(l=50, r=50, t=100, b=100), # Adjust the margins
478505
legend=dict(
479506
orientation="h",
480507
yanchor="top",
481508
# text= "Reference pathogen",
482-
y=-0.1,
509+
y=-0.3,
483510
xanchor="left",
484511
x=0,
485512
),
486-
annotations=[
487-
go.Annotation(
488-
y=-4,
489-
x=1.2,
490-
text="Tolerable risk level of 1/10000 infections pppy",
491-
bgcolor="#0003e2",
492-
bordercolor="white",
493-
borderpad=5,
494-
font=dict(color="white"),
495-
)
496-
],
513+
# annotations=[
514+
# go.Annotation(
515+
# y=-4,
516+
# x=1.2,
517+
# text="Tolerable risk level of 1/10000 infections pppy",
518+
# bgcolor="#0003e2",
519+
# bordercolor="white",
520+
# borderpad=5,
521+
# font=dict(color="white"),
522+
# )
523+
# ],
497524
)
498525

499526
# fig.update_annotations(y = 0.0001, x = 1, text = "Tolerable risk level")
@@ -522,17 +549,18 @@ def calculate_risk(request, ra_id):
522549
},
523550
xaxis_title="",
524551
yaxis_title="DALYs pppy",
525-
annotations=[
526-
go.Annotation(
527-
y=-6,
528-
x=1.2,
529-
text="Tolerable risk level of 1µDALY pppy",
530-
bgcolor="#0003e2",
531-
bordercolor="white",
532-
borderpad=5,
533-
font=dict(color="white"),
534-
)
535-
]
552+
plot_bgcolor= dalybgcolor,
553+
# annotations=[
554+
# go.Annotation(
555+
# y=-6,
556+
# x=1.2,
557+
# text="Tolerable risk level of 1µDALY pppy",
558+
# bgcolor="#0003e2",
559+
# bordercolor="white",
560+
# borderpad=5,
561+
# font=dict(color="white"),
562+
# )
563+
# ]
536564
# markersize= 12,
537565
)
538566

@@ -541,12 +569,12 @@ def calculate_risk(request, ra_id):
541569
orientation="h",
542570
yanchor="top",
543571
# text= "Reference pathogen",
544-
y=-0.1,
572+
y=-0.3,
545573
xanchor="left",
546574
x=0,
547575
)
548576
)
549-
fig.add_hline(y=0.000001, line_dash="dashdot", line=dict(color="#0003e2", width=3))
577+
fig.add_hline(y=0.000001, line_dash="dashdot", line=dict(color=dlcolor, width=3))
550578
# annotation_text="tolerable risk level")
551579
# annotation_position = "top left",
552580
# annotation=dict(font_size=20, font_family="Times New Roman"))
@@ -641,6 +669,8 @@ def calculate_risk(request, ra_id):
641669
"daly_plot": daly_plot,
642670
"risk_plot": risk_plot,
643671
"ra": ra,
672+
"risk": risk,
673+
"dalyrisk": risk
644674
},
645675
)
646676

@@ -701,10 +731,6 @@ def register(request):
701731
return render(request, "qmratool/register.html")
702732

703733

704-
from django.contrib import messages
705-
from django.contrib.auth import update_session_auth_hash
706-
from django.contrib.auth.forms import PasswordChangeForm
707-
from django.shortcuts import render, redirect
708734

709735

710736
@login_required(login_url="/login")

0 commit comments

Comments
 (0)