Skip to content

Commit a4b6dd9

Browse files
authored
Merge branch 'develop' into issue_155
2 parents 5a0abfa + 0c0115e commit a4b6dd9

File tree

15 files changed

+351
-346
lines changed

15 files changed

+351
-346
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: General bug report
3+
about: Create an report to help us improve.
4+
title: [bug]
5+
labels: 'bug'
6+
assignees: ''
7+
8+
---
9+
10+
<!--
11+
Before you begin, please help us manage volume by checking if this could be submitted another way:
12+
- Usage questions? Ask in Slack [#chime-help](https://codeforphilly.org/chat?channel=chime-help).
13+
- Feature ideas? Propose in Slack for discussion.
14+
- Is this something you can debug and fix? Pull requests are very welcome.
15+
-->
16+
17+
### Description:
18+
19+
### Steps to reproduce:
20+
1.
21+
2.
22+
3.
23+
24+
### Expected behavior:
25+
26+
### What I got instead:
27+
(screenshots if applicable)

.github/ISSUE_TEMPLATE/model.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: Bug report for model
3+
about: Feedback or bug report for the epidemiological model and analysis.
4+
title: [model]
5+
labels: 'models'
6+
assignees: ''
7+
8+
---
9+
10+
<!--
11+
Please note: Any changes to the model have a huge impact on rapidly evolving hospital system & public health decisions. The current model has been in use for a while now, and it has been validated against other similar models, so any changes to the model must meet a very high bar.
12+
13+
However, these 2 types of issue reports are very welcome:
14+
- Bugs causing this model to produce invalid results. In this case, please include details and a suggested fix.
15+
- If this model is producing a significantly different result than another well-known epidemiological model. In this case, please include proof of this difference and a suggested fix to our approach.
16+
17+
For questions or early discussion, please join us in [#chime-analysis](https://codeforphilly.org/chat?channel=chime-analysis) in Slack instead.
18+
-->
19+
20+
### Summary
21+
22+
23+
### Additional details
24+
25+
26+
### Suggested fix

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The **C**OVID-19 **H**ospital **I**mpact **M**odel for **E**pidemics ([penn-chim
77
## Background
88
The [CHIME](https://penn-chime.phl.io/) (COVID-19 Hospital Impact Model for Epidemics) Application is designed to assist hospitals and public health officials with understanding hospital capacity needs as they relate to the COVID pandemic. CHIME enables capacity planning by providing estimates of total daily (i.e. new) and running totals of (i.e. census) inpatient hospitalizations, ICU admissions, and patients requiring ventilation. These estimates are generated using a [SIR (Susceptible, Infected, Recovered)](https://mathworld.wolfram.com/SIRModel.html) model, a standard epidemiological modeling technique. Our model has been validated by several epidemiologists including [Michael Z. Levy, PhD](https://www.dbei.med.upenn.edu/bio/michael-z-levy-phd), Associate Professor of Epidemiology, Department of Biostatistics, Epidemiology and Informatics at the Perelman School of Medicine.
99

10-
Originally developed in `github.com/pennsignals/chime`, active development is now at `github.com/pennsignals/chime`.
10+
Originally developed in `github.com/pennsignals/chime`, active development is now at `github.com/CodeForPhilly/chime`.
1111

1212
### Documentation
1313

docs/getting-started/try-online.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Try this link: https://pennchime.herokuapp.com/
1212

1313
### Run Your Own Copy Locally
1414

15-
If you're comfortable working on your computer's command line, you can head over to the [Getting Started: Run Locally](getting-started/run-locally.md) guide to run a private instance on your own computer.
15+
If you're comfortable working on your computer's command line, you can head over to the [Getting Started: Run Locally](run-locally.md) guide to run a private instance on your own computer.
1616

1717
### Run a Shared Copy Online for Your Organization
1818

script/server

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env sh
1+
#!/usr/bin/env bash
22

33
# script/server: Launch the application and any extra required processes
44
# locally.

src/app.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
write_footer,
1818
)
1919
from penn_chime.settings import DEFAULTS
20-
from penn_chime.models import sim_sir_df, build_admissions_df, build_census_df
21-
from penn_chime.charts import (additional_projections_chart,
22-
admitted_patients_chart,
23-
new_admissions_chart,
24-
chart_descriptions)
20+
from penn_chime.models import SimSirModel
21+
from penn_chime.charts import (
22+
additional_projections_chart,
23+
admitted_patients_chart,
24+
new_admissions_chart,
25+
chart_descriptions
26+
)
2527

2628
# This is somewhat dangerous:
2729
# Hide the main menu with "Rerun", "run on Save", "clear cache", and "record a screencast"
@@ -30,55 +32,52 @@
3032
st.markdown(hide_menu_style, unsafe_allow_html=True)
3133

3234
p = display_sidebar(st, DEFAULTS)
35+
m = SimSirModel(p)
3336

34-
display_header(st, p)
37+
display_header(st, m, p)
3538

3639
if st.checkbox("Show more info about this tool"):
3740
notes = "The total size of the susceptible population will be the entire catchment area for Penn Medicine entities (HUP, PAH, PMC, CCH)"
38-
show_more_info_about_this_tool(st=st, parameters=p, inputs=DEFAULTS, notes=notes)
39-
40-
41-
# begin format data
42-
admissions_df = build_admissions_df(p=p) # p.n_days, *p.dispositions)
43-
census_df = build_census_df(admissions_df, parameters=p)
44-
# end format data
41+
show_more_info_about_this_tool(st=st, model=m, parameters=p, defaults=DEFAULTS, notes=notes)
4542

4643
st.subheader("New Admissions")
4744
st.markdown("Projected number of **daily** COVID-19 admissions at Penn hospitals")
48-
new_admit_chart = new_admissions_chart(alt, admissions_df, parameters=p)
45+
new_admit_chart = new_admissions_chart(alt, m.admits_df, parameters=p)
4946
st.altair_chart(
50-
new_admit_chart, use_container_width=True
47+
new_admissions_chart(alt, m.admits_df, parameters=p),
48+
use_container_width=True,
5149
)
5250

53-
st.markdown(chart_descriptions(new_admit_chart))
51+
st.markdown(chart_descriptions(new_admit_chart, p.labels))
5452

5553
if st.checkbox("Show Projected Admissions in tabular form"):
5654
if st.checkbox("Show Daily Counts"):
57-
draw_projected_admissions_table(st, admissions_df, as_date=p.as_date, daily_count=True)
55+
draw_projected_admissions_table(st, m.admits_df, p.labels, as_date=p.as_date, daily_count=True)
5856
else:
59-
draw_projected_admissions_table(st, admissions_df, as_date=p.as_date, daily_count=False)
57+
draw_projected_admissions_table(st, m.admits_df, p.labels, as_date=p.as_date, daily_count=False)
6058
build_download_link(st,
6159
filename="projected_admissions.csv",
62-
df=admissions_df,
60+
df=m.admits_df,
6361
parameters=p
6462
)
6563
st.subheader("Admitted Patients (Census)")
6664
st.markdown(
6765
"Projected **census** of COVID-19 patients, accounting for arrivals and discharges at Penn hospitals"
6866
)
69-
census_chart = admitted_patients_chart(alt=alt, census=census_df, parameters=p)
67+
census_chart = admitted_patients_chart(alt=alt, census=m.census_df, parameters=p)
7068
st.altair_chart(
71-
census_chart, use_container_width=True
69+
admitted_patients_chart(alt=alt, census=m.census_df, parameters=p),
70+
use_container_width=True,
7271
)
73-
st.markdown(chart_descriptions(census_chart, suffix=" Census"))
72+
st.markdown(chart_descriptions(census_chart, p.labels, suffix=" Census"))
7473
if st.checkbox("Show Projected Census in tabular form"):
7574
if st.checkbox("Show Daily Census Counts"):
76-
draw_census_table(st, admissions_df, as_date=p.as_date, daily_count=True)
75+
draw_census_table(st, m.census_df, p.labels, as_date=p.as_date, daily_count=True)
7776
else:
78-
draw_census_table(st, census_df, as_date=p.as_date, daily_count=False)
77+
draw_census_table(st, m.census_df, p.labels, as_date=p.as_date, daily_count=False)
7978
build_download_link(st,
8079
filename="projected_census.csv",
81-
df=census_df,
80+
df=m.census_df,
8281
parameters=p
8382
)
8483

@@ -87,9 +86,9 @@
8786
)
8887
if st.checkbox("Show Additional Projections"):
8988
show_additional_projections(
90-
st, alt, additional_projections_chart, parameters=p
89+
st, alt, additional_projections_chart, model=m, parameters=p
9190
)
9291
if st.checkbox("Show Raw SIR Simulation Data"):
93-
draw_raw_sir_simulation_table(st, parameters=p)
92+
draw_raw_sir_simulation_table(st, model=m, parameters=p)
9493
write_definitions(st)
9594
write_footer(st)

src/cli.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from pandas import DataFrame
1010

1111
from penn_chime.parameters import Parameters
12+
from penn_chime.models import SimSirModel
1213
from penn_chime.utils import RateLos
13-
from penn_chime.models import build_admissions_df, build_census_df
1414

1515
class FromFile(Action):
1616
"""From File."""
@@ -108,30 +108,22 @@ def main():
108108
doubling_time=a.doubling_time,
109109
known_infected=a.known_infected,
110110
market_share=a.market_share,
111+
n_days=a.n_days,
111112
relative_contact_rate=a.relative_contact_rate,
112113
susceptible=a.susceptible,
113-
n_days=a.n_days,
114+
114115
hospitalized=RateLos(a.hospitalized_rate, a.hospitalized_los),
115116
icu=RateLos(a.icu_rate, a.icu_los),
116117
ventilated=RateLos(a.ventilated_rate, a.ventilated_los),
117118
)
118119

119-
raw_df = DataFrame(
120-
{
121-
"Susceptible": p.susceptible_v,
122-
"Infected": p.infected_v,
123-
"Recovered": p.recovered_v,
124-
}
125-
)
126-
127-
admits_df = build_admissions_df(p)
128-
census_df = build_census_df(admits_df, p)
120+
m = SimSirModel(p)
129121

130122
prefix = a.prefix
131123
for df, name in (
132-
(raw_df, "raw"),
133-
(admits_df, "admits"),
134-
(census_df, "census"),
124+
(m.raw_df, "raw"),
125+
(m.admits_df, "admits"),
126+
(m.census_df, "census"),
135127
):
136128
df.to_csv(prefix + name + ".csv")
137129

src/penn_chime/charts.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11

22
from math import ceil
33
import datetime
4+
45
from altair import Chart # type: ignore
56
import pandas as pd # type: ignore
6-
import numpy as np # type: ignore
77

88
from .parameters import Parameters
99
from .utils import add_date_column
10+
from .presentation import DATE_FORMAT
1011

1112

1213
def new_admissions_chart(
@@ -26,13 +27,14 @@ def new_admissions_chart(
2627
tooltip_dict = {False: "day", True: "date:T"}
2728
if as_date:
2829
projection_admits = add_date_column(projection_admits)
29-
x_kwargs = {"shorthand": "date:T", "title": "Date"}
30+
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
3031
else:
3132
x_kwargs = {"shorthand": "day", "title": "Days from today"}
3233

34+
# TODO fix the fold to allow any number of dispositions
3335
return (
3436
alt.Chart(projection_admits.head(plot_projection_days))
35-
.transform_fold(fold=["Hospitalized", "ICU", "Ventilated"])
37+
.transform_fold(fold=["hospitalized", "icu", "ventilated"])
3638
.mark_line(point=True)
3739
.encode(
3840
x=alt.X(**x_kwargs),
@@ -58,7 +60,7 @@ def admitted_patients_chart(
5860
as_date = parameters.as_date
5961
if as_date:
6062
census = add_date_column(census)
61-
x_kwargs = {"shorthand": "date:T", "title": "Date"}
63+
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
6264
idx = "date:T"
6365
else:
6466
x_kwargs = {"shorthand": "day", "title": "Days from today"}
@@ -70,9 +72,10 @@ def admitted_patients_chart(
7072
y_scale.domain = (0, max_y_axis)
7173
y_scale.clamp = True
7274

75+
# TODO fix the fold to allow any number of dispositions
7376
return (
7477
alt.Chart(census.head(plot_projection_days))
75-
.transform_fold(fold=["Hospitalized", "ICU", "Ventilated"])
78+
.transform_fold(fold=["hospitalized", "icu", "ventilated"])
7679
.mark_line(point=True)
7780
.encode(
7881
x=alt.X(**x_kwargs),
@@ -89,19 +92,23 @@ def admitted_patients_chart(
8992

9093

9194
def additional_projections_chart(
92-
alt, parameters: Parameters
95+
alt, model, parameters
9396
) -> Chart:
94-
i = parameters.infected_v
95-
r = parameters.recovered_v
96-
dat = pd.DataFrame({"Infected": i, "Recovered": r})
97+
98+
# TODO use subselect of df_raw instead of creating a new df
99+
raw_df = model.raw_df
100+
dat = pd.DataFrame({
101+
"infected": raw_df.infected,
102+
"recovered": raw_df.recovered
103+
})
97104
dat["day"] = dat.index
98105

99106
as_date = parameters.as_date
100107
max_y_axis = parameters.max_y_axis
101108

102109
if as_date:
103110
dat = add_date_column(dat)
104-
x_kwargs = {"shorthand": "date:T", "title": "Date"}
111+
x_kwargs = {"shorthand": "date:T", "title": "Date", "axis": alt.Axis(format=(DATE_FORMAT))}
105112
else:
106113
x_kwargs = {"shorthand": "day", "title": "Days from today"}
107114

@@ -113,7 +120,7 @@ def additional_projections_chart(
113120

114121
return (
115122
alt.Chart(dat)
116-
.transform_fold(fold=["Infected", "Recovered"])
123+
.transform_fold(fold=["infected", "recovered"])
117124
.mark_line()
118125
.encode(
119126
x=alt.X(**x_kwargs),
@@ -125,7 +132,7 @@ def additional_projections_chart(
125132
)
126133

127134

128-
def chart_descriptions(chart: Chart, suffix: str = ""):
135+
def chart_descriptions(chart: Chart, labels, suffix: str = ""):
129136
"""
130137
131138
:param chart: Chart: The alt chart to be used in finding max points
@@ -136,7 +143,7 @@ def chart_descriptions(chart: Chart, suffix: str = ""):
136143
"""
137144
messages = []
138145

139-
cols = ["Hospitalized", "ICU", "Ventilated"]
146+
cols = ["hospitalized", "icu", "ventilated"]
140147
asterisk = False
141148
day = "date" if "date" in chart.data.columns else "day"
142149

@@ -152,7 +159,7 @@ def chart_descriptions(chart: Chart, suffix: str = ""):
152159

153160
messages.append(
154161
"{}{} peaks at {:,} on day {}{}".format(
155-
col,
162+
labels[col],
156163
suffix,
157164
ceil(chart.data[col].max()),
158165
on,

src/penn_chime/defaults.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,34 @@ def __init__(
2525
current_hospitalized: int,
2626
doubling_time: int,
2727
known_infected: int,
28-
n_days: int,
2928
relative_contact_rate: int,
3029
region: Regions,
30+
3131
hospitalized: RateLos,
3232
icu: RateLos,
3333
ventilated: RateLos,
34+
35+
as_date: bool = False,
3436
market_share: float = 1.0,
37+
max_y_axis: int = None,
38+
n_days: int = 60,
39+
recovery_days: int = 14,
3540
):
3641
self.region = region
37-
self.known_infected = known_infected
3842
self.current_hospitalized = current_hospitalized
43+
self.known_infected = known_infected
3944
self.doubling_time = doubling_time
40-
self.market_share = market_share
4145
self.relative_contact_rate = relative_contact_rate
4246

4347
self.hospitalized = hospitalized
4448
self.icu = icu
4549
self.ventilated = ventilated
50+
51+
self.as_date = as_date
52+
self.market_share = market_share
53+
self.max_y_axis = max_y_axis
4654
self.n_days = n_days
55+
self.recovery_days = recovery_days
4756

4857
def __repr__(self) -> str:
4958
return f"Constants(susceptible_default: {self.region.susceptible}, known_infected: {self.known_infected})"

0 commit comments

Comments
 (0)