Skip to content

Commit

Permalink
Updated the sidebar to include our parameters. Does not yet have work…
Browse files Browse the repository at this point in the history
…ing import-export functionality.
  • Loading branch information
Max Taggart committed Apr 1, 2020
1 parent e44cfce commit ef6eb35
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 49 deletions.
81 changes: 81 additions & 0 deletions src/penn_chime/hc_param_import_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import base64
from datetime import (
datetime,
date,
)
import json
import io
from typing import Tuple

from .parameters import (
Parameters,
Regions,
Disposition,
)


def constants_from_uploaded_file(file: io.StringIO) -> Tuple[Parameters, dict]:
imported_params = json.loads(file.read())
constants = Parameters(
region=Regions(area=imported_params["RegionalPopulation"]),
doubling_time=float(imported_params["DoublingTimeBeforeSocialDistancing"]),
# known_infected=imported_params.get("CurrentlyKnownRegionalInfections", 510),
n_days=imported_params["NumberOfDaysToProject"],
market_share=float(imported_params["HospitalMarketShare"]),
relative_contact_rate=float(imported_params["SocialDistancingPercentReduction"]),
hospitalized=Disposition(float(imported_params["HospitalizationPercentage"]), imported_params["HospitalLengthOfStay"]),
icu=Disposition(float(imported_params["ICUPercentage"]), imported_params["ICULengthOfStay"]),
ventilators=Disposition(float(imported_params["VentilatorsPercentage"]),imported_params["VentLengthOfStay"]),

# total_beds=imported_params.get("TotalNumberOfBeds", 10),
total_non_covid_beds=imported_params["TotalNumberOfBedsForNCPatients"],
# total_icu_beds=imported_params.get("TotalNumberOfICUBeds", 10),
total_non_covid_icu_beds=imported_params["TotalNumberOfICUBedsForNCPatients"],
# total_vents=imported_params.get("TotalNumberOfVents", 10),
total_non_covid_vents=imported_params["TotalNumberOfVentsForNCPatients"],

current_hospitalized=imported_params["CurrentlyHospitalizedCovidPatients"],
census_date = date.fromisoformat(imported_params.get("CurrentlyHospitalizedCovidPatientsDate", date.today().isoformat())),
selected_offset = imported_params.get("SelectedOffsetDays", -1)
)
return constants, imported_params

def param_download_widget(st, parameters, as_date, max_y_axis_set, max_y_axis):
if parameters.author == "Jane Doe" or parameters.scenario == "COVID Model":
st.sidebar.markdown("""
**Enter a unique author name and scenario name to enable parameter download.**""")
else:
filename = "ModelParameters" + "_" + parameters.author + "_" + parameters.scenario + "_" + datetime.now().isoformat() + ".json"
out_obj = {
"Author": parameters.author,
"Scenario": parameters.scenario,
"NumberOfDaysToProject": parameters.n_days,
"DoublingTimeBeforeSocialDistancing": parameters.doubling_time,
"SocialDistancingPercentReduction": parameters.relative_contact_rate,
"HospitalizationPercentage": parameters.hospitalized.rate,
"ICUPercentage": parameters.icu.rate,
"VentilatorsPercentage": parameters.ventilators.rate,
"HospitalLengthOfStay": parameters.hospitalized.length_of_stay,
"ICULengthOfStay": parameters.icu.length_of_stay,
"VentLengthOfStay": parameters.ventilators.length_of_stay,
"HospitalMarketShare": parameters.market_share,
"RegionalPopulation": parameters.susceptible,
"PresentResultAsDates": as_date,
"MaxYAxisSet":max_y_axis_set,
"MaxYAxis":max_y_axis,

"TotalNumberOfBedsForNCPatients": parameters.total_non_covid_beds,
"TotalNumberOfICUBedsForNCPatients": parameters.total_non_covid_icu_beds,
"TotalNumberOfVentsForNCPatients": parameters.total_non_covid_vents,

"CurrentlyHospitalizedCovidPatients": parameters.current_hospitalized,
"CurrentlyHospitalizedCovidPatientsDate": parameters.census_date.isoformat(),
"SelectedOffsetDays": parameters.selected_offset,
}
out_json = json.dumps(out_obj)
b64_json = base64.b64encode(out_json.encode()).decode()
st.sidebar.markdown(
"""<a download="{filename}" href="data:text/plain;base64,{b64_json}" style="padding:.75em;border-radius:10px;background-color:#00aeff;color:white;font-family:sans-serif;text-decoration:none;">Save Scenario</a>"""
.format(b64_json=b64_json,filename=filename),
unsafe_allow_html=True,
)
10 changes: 5 additions & 5 deletions src/penn_chime/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def __init__(self, p: Parameters):
self.i_day = 0 # seed to the full length
self.beta_t = self.beta
self.run_projection(p)
self.i_day = i_day = int(get_argmin_ds(self.census_df, p.current_hospitalized))
self.i_day = i_day = int(get_argmin_ds(self.census_df, p.covid_census_value))

self.beta_t = get_beta(intrinsic_growth_rate, self.gamma, self.susceptible, p.relative_contact_rate)
self.run_projection(p)
Expand All @@ -114,7 +114,7 @@ def __init__(self, p: Parameters):
min_loss = 2.0**99
dts = np.linspace(1, 15, 29)
losses = np.zeros(dts.shape[0])
self.current_hospitalized = p.current_hospitalized
self.covid_census_value = p.covid_census_value
for i, i_dt in enumerate(dts):
intrinsic_growth_rate = get_growth_rate(i_dt)
self.beta = get_beta(intrinsic_growth_rate, self.gamma, self.susceptible, 0.0)
Expand Down Expand Up @@ -184,14 +184,14 @@ def run_projection(self, p):
def get_loss(self) -> float:
"""Squared error: predicted vs. actual current hospitalized."""
predicted = self.census_df.hospitalized.loc[self.i_day]
return (self.current_hospitalized - predicted) ** 2.0
return (self.covid_census_value - predicted) ** 2.0


def get_argmin_ds(census_df: pd.DataFrame, current_hospitalized: float) -> float:
def get_argmin_ds(census_df: pd.DataFrame, covid_census_value: float) -> float:
# By design, this forbids choosing a day after the peak
# If that's a problem, see #381
peak_day = census_df.hospitalized.argmax()
losses_df = (census_df.hospitalized[:peak_day] - current_hospitalized) ** 2.0
losses_df = (census_df.hospitalized[:peak_day] - covid_census_value) ** 2.0
return losses_df.argmin()


Expand Down
39 changes: 26 additions & 13 deletions src/penn_chime/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

from collections import namedtuple
from datetime import date
import datetime
from typing import Optional

from .validators import (
Expand Down Expand Up @@ -51,13 +51,18 @@ class Parameters:
def __init__(
self,
*,
current_hospitalized: int,
covid_census_value: int, # used to be current_hospitalized
covid_census_date: datetime.date, # added by Health Catalyst team
total_covid_beds: int,
icu_covid_beds: int,
covid_ventilators: int,
hospitalized: Disposition,
icu: Disposition,
relative_contact_rate: float,
ventilated: Disposition,
current_date: date = date.today(),
date_first_hospitalized: Optional[date] = None,
ventilators: Disposition, # used to be ventilated
current_date: datetime.date = datetime.date.today() - datetime.timedelta(hours=6),
social_distancing_date: datetime.date = datetime.date.today() - datetime.timedelta(hours=6),
date_first_hospitalized: Optional[datetime.date] = None,
doubling_time: Optional[float] = None,
infectious_days: int = 14,
market_share: float = 1.0,
Expand All @@ -66,17 +71,25 @@ def __init__(
population: Optional[int] = None,
recovered: int = 0,
region: Optional[Regions] = None,
# Added by the Health Catalyst Team
):
self.current_hospitalized = StrictlyPositive(value=current_hospitalized)
self.covid_census_value = StrictlyPositive(value=covid_census_value)
self.covid_census_date = Date(value=covid_census_date)
self.current_date = Date(value=current_date)
self.relative_contact_rate = Rate(value=relative_contact_rate)

Rate(value=hospitalized.rate), Rate(value=icu.rate), Rate(value=ventilated.rate)
StrictlyPositive(value=hospitalized.days), StrictlyPositive(value=icu.days),
StrictlyPositive(value=ventilated.days)
self.total_covid_beds = StrictlyPositive(value=total_covid_beds)
self.icu_covid_beds = StrictlyPositive(value=icu_covid_beds)
self.covid_ventilators = StrictlyPositive(value=covid_ventilators)
Rate(value=hospitalized.rate)
Rate(value=icu.rate)
StrictlyPositive(value=hospitalized.days)
StrictlyPositive(value=icu.days),

self.hospitalized = hospitalized
self.icu = icu
self.ventilated = ventilated

self.ventilators = ventilators

if region is not None and population is None:
self.region = region
Expand All @@ -87,7 +100,7 @@ def __init__(
else:
raise AssertionError('population or regions must be provided.')

self.current_date = Date(value=current_date)
self.social_distancing_date = Date(value=social_distancing_date)

self.date_first_hospitalized = OptionalDate(value=date_first_hospitalized)
self.doubling_time = OptionalStrictlyPositive(value=doubling_time)
Expand All @@ -101,7 +114,7 @@ def __init__(
self.labels = {
"hospitalized": "Hospitalized",
"icu": "ICU",
"ventilated": "Ventilated",
"ventilators": "Ventilators",
"day": "Day",
"date": "Date",
"susceptible": "Susceptible",
Expand All @@ -112,5 +125,5 @@ def __init__(
self.dispositions = {
"hospitalized": hospitalized,
"icu": icu,
"ventilated": ventilated,
"ventilators": ventilators,
}
Loading

0 comments on commit ef6eb35

Please sign in to comment.