Repository: CodeForPhilly/chime
Pull request #296 (2020-03-28 12:59:32)

Update documentation throughout code base
- Updated docs throughout
- Documentation at the top of modules now include a short summary and / or contents
- Added documentation for various classes and functions
- Flagged / noted classes or functions that are being considered for relocation
- Flagged / noted cases where logic and view still need to be separated


Patch:
diff --git a/Dockerfile b/Dockerfile
index 160917b..e82a514 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,14 @@
 FROM python:3.7.7-slim-buster
-RUN mkdir /app
+
+COPY .streamlit ~/
+
+COPY ./requirements.txt /app/requirements.txt
+
 WORKDIR /app
-COPY README.md .
-COPY setup.py .
-COPY requirements.txt .
-# Creating an empty src dir is a (hopefully) temporary hack to improve layer caching and speed up image builds
-# todo fix once the Pipfile, setup.py, requirements.txt, pyprojec.toml build/dist story is figured out
-RUN mkdir src && pip install -q .
-COPY .streamlit .streamlit
-COPY settings.cfg .
-COPY src src
+
+RUN pip install -q -r requirements.txt
+
+COPY . . 
 
 CMD ["streamlit", "run", "src/app.py"]
 
diff --git a/docs/contributing/app-dev.md b/docs/contributing/app-dev.md
index d6e0633..f94f2e4 100644
--- a/docs/contributing/app-dev.md
+++ b/docs/contributing/app-dev.md
@@ -59,7 +59,6 @@ streamlit run src/app.py
 - `Pipfile.lock`
 - `environment.yml`
 - `requirements.txt`
-- `setup.py`
 
 ### Documentation
 
diff --git a/k8s/app.yaml b/k8s/app.yaml
index fe555c3..08dee57 100644
--- a/k8s/app.yaml
+++ b/k8s/app.yaml
@@ -63,12 +63,12 @@ metadata:
   annotations:
     kubernetes.io/ingress.class: nginx
     certmanager.k8s.io/cluster-issuer: letsencrypt-prod
-    # allow requests larger than 1MiB
     nginx.ingress.kubernetes.io/proxy-body-size: "0"
 spec:
   tls:
   - hosts:
     - penn-chime.phl.io
+    - lke.penn-chime.phl.io
     secretName: tls-secret
   rules:
   - host: penn-chime.phl.io
@@ -78,25 +78,6 @@ spec:
         backend:
           serviceName: chime
           servicePort: 80
-
----
-
-apiVersion: extensions/v1beta1
-kind: Ingress
-metadata:
-  name: chime-alt
-  namespace: chime
-  annotations:
-    kubernetes.io/ingress.class: nginx
-    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
-    # allow requests larger than 1MiB
-    nginx.ingress.kubernetes.io/proxy-body-size: "0"
-spec:
-  tls:
-  - hosts:
-    - lke.penn-chime.phl.io
-    secretName: tls-chime-alt
-  rules:
   - host: lke.penn-chime.phl.io
     http:
       paths:
@@ -106,6 +87,7 @@ spec:
           servicePort: 80
 
 ---
+
 apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
diff --git a/requirements.txt b/requirements.txt
index 95e374a..1968767 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
--e .
 streamlit
 pandas
 numpy
diff --git a/settings.cfg b/settings.cfg
index f8d1a3b..040d6e2 100644
--- a/settings.cfg
+++ b/settings.cfg
@@ -8,6 +8,6 @@
 --icu-rate 0.0075
 --market_share 0.15
 --n-days 60
---population 4119405
+--susceptible 4119405
 --ventilated-los 10
 --ventilated-rate 0.005
diff --git a/setup.py b/setup.py
index b2de718..f89a528 100644
--- a/setup.py
+++ b/setup.py
@@ -1,33 +1,28 @@
+# -*- coding: utf-8 -*-
 """Setup file for chime
 """
 __version__ = "0.1.0"
-__author__ = "Predictive Healthcare @ Penn Medicine"
+__author__ = ""
 
-import io
-from os import path
-from setuptools import setup, find_packages, find_namespace_packages
 
-CWD = path.abspath(path.dirname(__file__))
+from os import path
 
-#with io.open(path.join(CWD, "README.md"), encoding="utf-8") as inp:
-#    LONG_DESCRIPTION = inp.read()
+from setuptools import setup, find_packages
 
-#with io.open(path.join(CWD, "requirements.txt"), encoding="utf-8") as inp:
-#    REQUIREMENTS = [el.strip() for el in inp.read().split(",")]
+CWD = path.abspath(path.dirname(__file__))
 
-with io.open("README.md", "r") as inp:
+with open(path.join(CWD, "README.md"), encoding="utf-8") as inp:
     LONG_DESCRIPTION = inp.read()
 
-with io.open("requirements.txt", "r") as inp:
+with open(path.join(CWD, "requirements.txt"), encoding="utf-8") as inp:
     REQUIREMENTS = [el.strip() for el in inp.read().split(",")]
 
-    
+
 setup(
     name="penn_chime",
+    python_requires=">=3.6",
     version=__version__,
-    author=__author__,
-    author_email="",
-    description="COVID-19 Hospital Impact Model for Epidemics",
+    description=None,
     long_description=LONG_DESCRIPTION,
     long_description_content_type="text/markdown",
     url="https://github.com/CodeForPhilly/chime",
@@ -36,30 +31,11 @@ setup(
         "Source": "https://github.com/CodeForPhilly/chime",
         "Documentation": "https://codeforphilly.github.io/chime/",
     },
-    package_dir={'': 'src'},
-    #packages=find_namespace_packages(where='src', exclude=('tests')),
-    install_requires=[
-        "streamlit",
-        "pandas",
-        "numpy",
-        "altair",
-        "pytest",
-        "dash", 
-        "dash_bootstrap_components", 
-        "pyyaml", 
-        "gunicorn"
-    ],
-    classifiers=[
-        "Programming Language :: Python :: 3",
-        "License :: OSI Approved :: MIT License",
-        "Operating System :: OS Independent",
-    ],
-    python_requires='>=3.6',
-    entry_points = {
-        'console_scripts': ['penn_chime=penn_chime.cli:main'],
-    },
+    author=__author__,
+    author_email="",
     keywords=[],
-    packages=find_packages(".", exclude=["docs", "k82", "script", "tests"]),
-    #install_requires=REQUIREMENTS,
+    packages=find_packages(".", exclude=["docs", "k82", "script"]),
+    install_requires=REQUIREMENTS,
+    classifiers=[],
     include_package_data=True,
 )
diff --git a/src/app.py b/src/app.py
index 056220a..7c47e03 100644
--- a/src/app.py
+++ b/src/app.py
@@ -55,11 +55,8 @@ if st.checkbox("Show Projected Admissions in tabular form"):
         draw_projected_admissions_table(st, m.admits_df, p.labels, 1, as_date=p.as_date)
     else:
         admissions_day_range = st.slider(
-            label="Interval of Days",
-            key="admissions_day_range_slider",
-            min_value=1,
-            max_value=10,
-            value=7 
+            'Interval of Days for Projected Admissions',
+            1, 10, 7
         )
         draw_projected_admissions_table(st, m.admits_df, p.labels, admissions_day_range, as_date=p.as_date)
     build_download_link(st,
@@ -82,11 +79,8 @@ if st.checkbox("Show Projected Census in tabular form"):
         draw_census_table(st, m.census_df, p.labels, 1, as_date=p.as_date)
     else:
         census_day_range = st.slider(
-            label='Interval of Days',
-            key="census_day_range_slider",
-            min_value=1,
-            max_value=10,
-            value=7 
+            'Interval of Days for Projected Census',
+            1, 10, 7
         )
         draw_census_table(st, m.census_df, p.labels, census_day_range, as_date=p.as_date)
     build_download_link(st,
diff --git a/src/chime_dash/app/__init__.py b/src/chime_dash/app/__init__.py
index e69de29..c867cad 100644
--- a/src/chime_dash/app/__init__.py
+++ b/src/chime_dash/app/__init__.py
@@ -0,0 +1,3 @@
+"""app/init
+# consider initializing Dash object here
+"""
\ No newline at end of file
diff --git a/src/chime_dash/app/components/additions.py b/src/chime_dash/app/components/additions.py
index b1a028c..abbfba4 100644
--- a/src/chime_dash/app/components/additions.py
+++ b/src/chime_dash/app/components/additions.py
@@ -1,4 +1,6 @@
-"""Initializes the  dash html
+"""components/additions
+currently handles both view and logic should be separated
+graph activated via "Show additional projections"
 """
 from typing import List, Any
 
diff --git a/src/chime_dash/app/components/base.py b/src/chime_dash/app/components/base.py
index 4b3b534..654300d 100644
--- a/src/chime_dash/app/components/base.py
+++ b/src/chime_dash/app/components/base.py
@@ -1,4 +1,8 @@
-"""Module provides abstract base component needed for rendering
+"""app/components/base
+
+Abstract base class for components
+
+#! candidate for moving into utils/components
 """
 from typing import List, Dict, Any, Union
 
diff --git a/src/chime_dash/app/components/definitions.py b/src/chime_dash/app/components/definitions.py
index 9236ce7..8233d38 100644
--- a/src/chime_dash/app/components/definitions.py
+++ b/src/chime_dash/app/components/definitions.py
@@ -1,4 +1,6 @@
-"""Initializes the  dash html
+"""components/definitions
+
+
 """
 from typing import List
 
diff --git a/src/chime_dash/app/components/footer.py b/src/chime_dash/app/components/footer.py
index cde5d37..dd70d2b 100644
--- a/src/chime_dash/app/components/footer.py
+++ b/src/chime_dash/app/components/footer.py
@@ -1,4 +1,7 @@
-"""Initializes the  dash html
+"""component/footer
+appears at the bottom of the page
+
+source text located in app/templates/en/footer.md
 """
 from typing import List
 
diff --git a/src/chime_dash/app/components/header.py b/src/chime_dash/app/components/header.py
index 8bd2b06..947c1d1 100644
--- a/src/chime_dash/app/components/header.py
+++ b/src/chime_dash/app/components/header.py
@@ -1,4 +1,5 @@
-"""Initializes the header dash html
+"""Initializes the Penn Medicine masthead
+#! consider moving this into navbar or static
 """
 from typing import List
 
diff --git a/src/chime_dash/app/components/intro.py b/src/chime_dash/app/components/intro.py
index b243d8e..ee3814d 100644
--- a/src/chime_dash/app/components/intro.py
+++ b/src/chime_dash/app/components/intro.py
@@ -1,4 +1,8 @@
-"""Initializes the  dash html
+"""components/intro
+initializes the leading text as of right now
+
+currently both classes handle control and view this should be separated
+with the logic for dynamic text moving to services.
 """
 from typing import List, Any
 
diff --git a/src/chime_dash/app/components/menu.py b/src/chime_dash/app/components/menu.py
index 0552372..d6e78c0 100644
--- a/src/chime_dash/app/components/menu.py
+++ b/src/chime_dash/app/components/menu.py
@@ -1,4 +1,7 @@
-"""Initializes dropdown menu
+"""component/menu
+Dropdown menu which appears on the navigation bar at the top of the screen
+
+refactor incoming
 """
 from typing import List
 
diff --git a/src/chime_dash/app/components/navbar.py b/src/chime_dash/app/components/navbar.py
index 13eeebd..7916e1c 100644
--- a/src/chime_dash/app/components/navbar.py
+++ b/src/chime_dash/app/components/navbar.py
@@ -1,4 +1,5 @@
-"""Navigation bar view
+"""components/navbar
+Navigation bar view
 """
 from typing import List
 
@@ -14,11 +15,12 @@ from chime_dash.app.components.menu import Menu
 
 
 class Navbar(Component):
-    """
+    """Navigation bar contains menu and brand
+    TODO refactor / design input on style and layout
     """
 
     def __init__(self, language: str = "en", defaults: Constants = DEFAULTS):
-        """Sets up self, menue and header
+        """Sets up self, menu and header
         """
         super().__init__(language, defaults=defaults)
         self.menu = Menu(language, defaults=defaults)
diff --git a/src/chime_dash/app/components/sidebar.py b/src/chime_dash/app/components/sidebar.py
index afa5451..becb928 100644
--- a/src/chime_dash/app/components/sidebar.py
+++ b/src/chime_dash/app/components/sidebar.py
@@ -1,4 +1,7 @@
-"""Initializes the  dash html
+"""components/sidebar
+Initializes the side bar containing the various inputs for the model
+
+#! _INPUTS should be considered for moving else where
 """
 from typing import List, Dict, Any, Tuple
 from collections import OrderedDict
@@ -54,9 +57,11 @@ _INPUTS = OrderedDict(
 
 
 class Sidebar(Component):
+    """Sidebar to the left of the screen
+    contains the various inputs used to interact
+    with the model.
     """
-    """
-
+    # localization temp. for widget descriptions
     localization_file = "sidebar.yml"
 
     callback_inputs = OrderedDict(
@@ -90,7 +95,7 @@ class Sidebar(Component):
         return pars
 
     def get_html(self) -> List[ComponentMeta]:
-        """Initializes the header dash html
+        """Initializes the view
         """
         elements = []
         for idx, data in _INPUTS.items():
diff --git a/src/chime_dash/app/components/visualizations.py b/src/chime_dash/app/components/visualizations.py
index 040b3cd..7e8e257 100644
--- a/src/chime_dash/app/components/visualizations.py
+++ b/src/chime_dash/app/components/visualizations.py
@@ -1,4 +1,8 @@
-"""Initializes the  dash html
+"""components/visualizations
+
+Initializes the visual components of the interactive model
+
+localization file can be found in app/templates/en
 """
 from typing import List, Any
 
diff --git a/src/chime_dash/app/pages/__init__.py b/src/chime_dash/app/pages/__init__.py
index e69de29..06d9242 100644
--- a/src/chime_dash/app/pages/__init__.py
+++ b/src/chime_dash/app/pages/__init__.py
@@ -0,0 +1,12 @@
+"""app/pages
+
+page layout controlled here - nothing should be defined here only initialized
+
+for component definitions see -> app/components
+for core logic see --> app/services
+for utility classes and functions see --> utils
+
+modules         desc.       route
+----            ----        ----
+index           homepage    /
+"""
\ No newline at end of file
diff --git a/src/chime_dash/app/pages/index.py b/src/chime_dash/app/pages/index.py
index 78a808c..c794ec4 100644
--- a/src/chime_dash/app/pages/index.py
+++ b/src/chime_dash/app/pages/index.py
@@ -1,28 +1,5 @@
 """pages/index
 Homepage
 """
-from typing import List
 
-import dash_html_components as html
-import dash_bootstrap_components as dbc
-from dash.development.base_component import ComponentMeta
-
-from chime_dash.app.components import navbar
-from chime_dash.app.static.homepage import introducing_chime, latest_updates
-
-
-def render (language: str) -> List[ComponentMeta]:
-    """Initializes page
-    """
-    layout = html.Div(
-        [
-            dbc.Row(navbar.setup(language)),
-            dbc.Col(
-                children=introducing_chime('en')
-            ),
-            dbc.Col(
-                children=latest_updates('en')
-            )
-        ]
-    )
-    return layout
+# TODO move layout from components to here
diff --git a/src/chime_dash/app/services/__init__.py b/src/chime_dash/app/services/__init__.py
index 0f673f2..3cf7c3d 100644
--- a/src/chime_dash/app/services/__init__.py
+++ b/src/chime_dash/app/services/__init__.py
@@ -1,4 +1,14 @@
 """
 app/services
 
+classes defined here exist for the duration of the app, or are considered core
+to the solution being delivered.
+
+for more general utility functions see app/utils
+
+modules             desc.
+---                 ---
+plotting            graphs / charts
+#! call back logic should be moved here
+#! logic for updating text should be moved here
 """
\ No newline at end of file
diff --git a/src/chime_dash/app/services/plotting.py b/src/chime_dash/app/services/plotting.py
index 70ef957..db51478 100644
--- a/src/chime_dash/app/services/plotting.py
+++ b/src/chime_dash/app/services/plotting.py
@@ -1,4 +1,6 @@
-"""Functions which set up plotly-dash plots
+"""services/plotting
+
+Logic for data manipulation needed when new call backs are executed
 """
 from typing import Dict, Any
 
diff --git a/src/chime_dash/app/static/homepage.py b/src/chime_dash/app/static/homepage.py
deleted file mode 100644
index dc4d6d4..0000000
--- a/src/chime_dash/app/static/homepage.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import List
-
-from dash.development.base_component import ComponentMeta
-from dash_core_components import Markdown
-
-from chime_dash.app.utils.templates import read_localization_markdown
-
-LOCALIZATION_FILE_1 = "chime-intro.md"
-LOCALIZATION_FILE_2 = "latest-updates.md"
-
-
-def introducing_chime(language: str) -> List[ComponentMeta]:
-    """Initializes the header dash html
-    """
-    content = read_localization_markdown(LOCALIZATION_FILE_1, language)
-
-    return [Markdown(content)]
-
-
-def latest_updates(language: str) -> List[ComponentMeta]:
-    """Initializes the header dash html
-    """
-    content = read_localization_markdown(LOCALIZATION_FILE_2, language)
-
-    return [Markdown(content)]
diff --git a/src/chime_dash/app/utils/__init__.py b/src/chime_dash/app/utils/__init__.py
index e69de29..fcd2fb9 100644
--- a/src/chime_dash/app/utils/__init__.py
+++ b/src/chime_dash/app/utils/__init__.py
@@ -0,0 +1,10 @@
+"""app/utils
+utils
+The helper classes and functions here exist to reduce large repetitive code
+blocks throughout the project. They may contain functions or classes from
+module but do not change the parameters of the class
+Modules
+-------
+templates       utilities for localization templates
+# ? components
+"""
\ No newline at end of file
diff --git a/src/chime_dash/app/utils/templates.py b/src/chime_dash/app/utils/templates.py
index d29f83e..d7e92e3 100644
--- a/src/chime_dash/app/utils/templates.py
+++ b/src/chime_dash/app/utils/templates.py
@@ -1,4 +1,6 @@
-"""Utility functions for dash frontend
+"""utils/templates
+Utility functions for localization templates
+templates themselves can be found in app/templates/en
 """
 from typing import Dict, Any, Optional
 
@@ -14,7 +16,7 @@ from dash_bootstrap_components import FormGroup, Label, Input, Checklist
 
 from penn_chime.defaults import Constants
 
-
+# Consider moving this to a config file eventually
 TEMPLATE_DIR = path.join(
     path.abspath(path.dirname(path.dirname(__file__))), "templates"
 )
diff --git a/src/penn_chime/cli.py b/src/cli.py
similarity index 97%
rename from src/penn_chime/cli.py
rename to src/cli.py
index a4ec533..4fed0f7 100644
--- a/src/penn_chime/cli.py
+++ b/src/cli.py
@@ -91,7 +91,7 @@ def parse_args():
             1.0,
             "Social Distancing Reduction Rate: 0.0 - 1.0",
         ),
-        ("--population", int, 1, None, "Regional Population >= 1"),
+        ("--susceptible", int, 1, None, "Regional Population >= 1"),
         ("--ventilated-los", int, 0, None, "Ventilated Length of Stay (days)"),
         ("--ventilated-rate", float, 0.0, 1.0, "Ventilated Rate: 0.0 - 1.0"),
     ):
@@ -110,7 +110,7 @@ def main():
         market_share=a.market_share,
         n_days=a.n_days,
         relative_contact_rate=a.relative_contact_rate,
-        population=a.population,
+        susceptible=a.susceptible,
 
         hospitalized=RateLos(a.hospitalized_rate, a.hospitalized_los),
         icu=RateLos(a.icu_rate, a.icu_los),
diff --git a/src/penn_chime/charts.py b/src/penn_chime/charts.py
index 790cd53..6054a52 100644
--- a/src/penn_chime/charts.py
+++ b/src/penn_chime/charts.py
@@ -4,7 +4,6 @@ import datetime
 
 from altair import Chart  # type: ignore
 import pandas as pd  # type: ignore
-import numpy as np
 
 from .parameters import Parameters
 from .utils import add_date_column
@@ -32,15 +31,8 @@ def new_admissions_chart(
         x_kwargs = {"shorthand": "day", "title": "Days from today"}
 
     # TODO fix the fold to allow any number of dispositions
-
-    ceiled_admits = projection_admits.copy()
-
-    ceiled_admits.hospitalized = np.ceil(ceiled_admits.hospitalized)
-    ceiled_admits.icu = np.ceil(ceiled_admits.icu)
-    ceiled_admits.ventilated = np.ceil(ceiled_admits.ventilated)
-
     return (
-        alt.Chart(ceiled_admits.head(plot_projection_days))
+        alt.Chart(projection_admits.head(plot_projection_days))
         .transform_fold(fold=["hospitalized", "icu", "ventilated"])
         .mark_line(point=True)
         .encode(
diff --git a/src/penn_chime/defaults.py b/src/penn_chime/defaults.py
index e2b476a..dd28427 100644
--- a/src/penn_chime/defaults.py
+++ b/src/penn_chime/defaults.py
@@ -7,12 +7,15 @@ class Regions:
     """Arbitrary number of counties."""
 
     def __init__(self, **kwargs):
-        population = 0
+        susceptible = 0
         for key, value in kwargs.items():
             setattr(self, key, value)
-            population += value
-        self.population = population
+            susceptible += value
+        self._susceptible = susceptible
 
+    @property
+    def susceptible(self):
+        return self._susceptible
 
 
 class Constants:
@@ -20,9 +23,9 @@ class Constants:
         self,
         *,
         current_hospitalized: int,
-        doubling_time: float,
+        doubling_time: int,
         known_infected: int,
-        relative_contact_rate: float,
+        relative_contact_rate: int,
         region: Regions,
 
         hospitalized: RateLos,
@@ -52,4 +55,4 @@ class Constants:
         self.recovery_days = recovery_days
 
     def __repr__(self) -> str:
-        return f"Constants(population_default: {self.region.population}, known_infected: {self.known_infected})"
+        return f"Constants(susceptible_default: {self.region.susceptible}, known_infected: {self.known_infected})"
diff --git a/src/penn_chime/models.py b/src/penn_chime/models.py
index 97fb33c..97fcba8 100644
--- a/src/penn_chime/models.py
+++ b/src/penn_chime/models.py
@@ -18,7 +18,8 @@ from .parameters import Parameters
 class SimSirModel:
 
     def __init__(self, p: Parameters) -> SimSirModel:
-        # TODO missing initial non-zero 'recovered' value
+        # TODO missing initial recovered value
+        susceptible = p.susceptible
         recovered = 0.0
         recovery_days = p.recovery_days
 
@@ -39,8 +40,6 @@ class SimSirModel:
             p.current_hospitalized / p.market_share / p.hospitalized.rate
         )
 
-        susceptible = p.population - infected
-
         detection_probability = (
             p.known_infected / infected if infected > 1.0e-7 else None
         )
@@ -64,10 +63,10 @@ class SimSirModel:
         # self.r_naught = r_t / (1.0 - relative_contact_rate)
         r_naught = (intrinsic_growth_rate + gamma) / gamma
         doubling_time_t = 1.0 / np.log2(
-            beta * susceptible - gamma + 1)
+            beta * p.susceptible - gamma + 1)
 
         raw_df = sim_sir_df(
-            susceptible,
+            p.susceptible,
             infected,
             recovered,
             beta,
@@ -94,8 +93,6 @@ class SimSirModel:
         self.dispositions_df = dispositions_df
         self.admits_df = admits_df
         self.census_df = census_df
-        self.daily_growth = daily_growth_helper(p.doubling_time)
-        self.daily_growth_t = daily_growth_helper(doubling_time_t)
 
 
 def sir(
@@ -174,11 +171,3 @@ def build_census_df(
             for key, los in lengths_of_stay.items()
         }
     })
-
-
-def daily_growth_helper(doubling_time):
-    """Calculates average daily growth rate from doubling time"""
-    result = 0
-    if doubling_time != 0:
-        result = (np.power(2, 1.0 / doubling_time) - 1) * 100
-    return result
diff --git a/src/penn_chime/parameters.py b/src/penn_chime/parameters.py
index 7ea14da..17b9722 100644
--- a/src/penn_chime/parameters.py
+++ b/src/penn_chime/parameters.py
@@ -17,7 +17,7 @@ class Parameters:
         doubling_time: float,
         known_infected: int,
         relative_contact_rate: float,
-        population: int,
+        susceptible: int,
 
         hospitalized: RateLos,
         icu: RateLos,
@@ -33,7 +33,7 @@ class Parameters:
         self.doubling_time = doubling_time
         self.known_infected = known_infected
         self.relative_contact_rate = relative_contact_rate
-        self.population = population
+        self.susceptible = susceptible
 
         self.hospitalized = hospitalized
         self.icu = icu
diff --git a/src/penn_chime/presentation.py b/src/penn_chime/presentation.py
index 0d80099..aadce0b 100644
--- a/src/penn_chime/presentation.py
+++ b/src/penn_chime/presentation.py
@@ -1,5 +1,8 @@
 """effectful functions for streamlit io"""
 
+from typing import Optional
+
+import altair as alt  # type: ignore
 import numpy as np  # type: ignore
 import pandas as pd  # type: ignore
 
@@ -8,10 +11,7 @@ from .utils import add_date_column, dataframe_to_base64
 from .parameters import Parameters
 
 DATE_FORMAT = "%b, %d"  # see https://strftime.org
-DOCS_URL = "https://code-for-philly.gitbook.io/chime"
 
-FLOAT_INPUT_MIN = 0.001
-FLOAT_INPUT_STEP = FLOAT_INPUT_MIN
 
 hide_menu_style = """
         <style>
@@ -32,43 +32,25 @@ def display_header(st, m, p):
         if m.detection_probability
         else "unknown"
     )
-
-    infection_warning_str = (
-        """(Warning: The number of known infections is greater than the estimate of infected patients based on inputs for current hospitalization, market share, and hospitalization rate. Please verify the market share value in the sidebar, and see if the hospitalization rate needs to be lowered.)"""
-        if p.known_infected > m.infected
-        else ""
-    )
-
-    infected_population_warning_str = (
-        """(Warning: The number of estimated infections is greater than the total regional population. Please verify the values entered in the sidebar.)"""
-        if m.infected > p.population
-        else ""
-    )
-
     st.markdown(
         """
 <link rel="stylesheet" href="https://www1.pennmedicine.org/styles/shared/penn-medicine-header.css">
+
 <div class="penn-medicine-header__content">
     <a href="https://www.pennmedicine.org" class="penn-medicine-header__logo"
         title="Go to the Penn Medicine home page">Penn Medicine</a>
-    <a id="title" class="penn-medicine-header__title">COVID-19 Hospital Impact Model for Epidemics (CHIME)</a>
+    <a id="title" class="penn-medicine-header__title">Penn Medicine - COVID-19 Hospital Impact Model for Epidemics</a>
 </div>
     """,
         unsafe_allow_html=True,
     )
-    st.markdown(
-        """[Documentation](https://code-for-philly.gitbook.io/chime/) | [Github](https://github.com/CodeForPhilly/chime/) | [Slack](https://codeforphilly.org/chat?channel=covid19-chime-penn)"""
-    )
     st.markdown(
         """**IMPORTANT NOTICE**: Admissions and Census calculations were previously **undercounting**. Please update your reports generated before """ + p.change_date() + """. See more about changes [here](https://github.com/CodeForPhilly/chime/labels/models)."""
     )
     st.markdown(
         """*This tool was developed by the [Predictive Healthcare team](http://predictivehealthcare.pennmedicine.org/) at
-    Penn Medicine to assist hospitals and public health officials with hospital capacity planning,
-    but can be used anywhere in the world.
-    Customize it for your region by modifying data inputs in the left panel.
-    For questions on how to use this tool see the [User docs]({docs_url}). Code can be found on [Github](https://github.com/CodeForPhilly/chime)*.
-    """.format(docs_url=DOCS_URL)
+    Penn Medicine. For questions on how to use this tool see the [User docs](https://code-for-philly.gitbook.io/chime/). Code can be found on [Github](https://github.com/CodeForPhilly/chime).
+    Join our [Slack channel](https://codeforphilly.org/chat?channel=covid19-chime-penn) if you would like to get involved!*"""
     )
 
     st.markdown(
@@ -77,22 +59,18 @@ def display_header(st, m, p):
     Hospitalizations (**{current_hosp}**), Hospitalization rate (**{hosp_rate:.0%}**), Region size (**{S}**),
     and Hospital market share (**{market_share:.0%}**).
 
-{infection_warning_str}
-{infected_population_warning_str}
-
 An initial doubling time of **{doubling_time}** days and a recovery time of **{recovery_days}** days imply an $R_0$ of
- **{r_naught:.2f}** and daily growth rate of **{daily_growth:.2f}%**.
+**{r_naught:.2f}**.
 
 **Mitigation**: A **{relative_contact_rate:.0%}** reduction in social contact after the onset of the
-outbreak **{impact_statement:s} {doubling_time_t:.1f}** days, implying an effective $R_t$ of **${r_t:.2f}$**
-and daily growth rate of **{daily_growth_t:.2f}%**.
+outbreak **{impact_statement:s} {doubling_time_t:.1f}** days, implying an effective $R_t$ of **${r_t:.2f}$**.
 """.format(
             total_infections=m.infected,
             initial_infections=p.known_infected,
             detection_prob_str=detection_prob_str,
             current_hosp=p.current_hospitalized,
             hosp_rate=p.hospitalized.rate,
-            S=p.population,
+            S=p.susceptible,
             market_share=p.market_share,
             recovery_days=p.recovery_days,
             r_naught=m.r_naught,
@@ -100,50 +78,13 @@ and daily growth rate of **{daily_growth_t:.2f}%**.
             relative_contact_rate=p.relative_contact_rate,
             r_t=m.r_t,
             doubling_time_t=abs(m.doubling_time_t),
-            impact_statement=("halves the infections every" if m.r_t < 1 else "reduces the doubling time to"),
-            daily_growth=m.daily_growth,
-            daily_growth_t=m.daily_growth_t,
-            docs_url=DOCS_URL,
-            infection_warning_str=infection_warning_str,
-            infected_population_warning_str=infected_population_warning_str
+            impact_statement=("halves the infections every" if m.r_t < 1 else "reduces the doubling time to")
         )
     )
 
     return None
 
 
-class Input:
-    """Helper to separate Streamlit input definition from creation/rendering"""
-    def __init__(self, st_obj, label, value, kwargs):
-        self.st_obj = st_obj
-        self.label = label
-        self.value = value
-        self.kwargs = kwargs
-
-    def __call__(self):
-        return self.st_obj(self.label, value=self.value, **self.kwargs)
-
-
-class NumberInput(Input):
-    def __init__(self, st_obj, label, min_value=None, max_value=None, value=None, step=None, format=None, key=None):
-        kwargs = dict(min_value=min_value, max_value=max_value, step=step, format=format, key=key)
-        super().__init__(st_obj.number_input, label, value, kwargs)
-
-
-class PercentInput(NumberInput):
-    def __init__(self, st_obj, label, min_value=0.0, max_value=100.0, value=None, step=FLOAT_INPUT_STEP, format="%f", key=None):
-        super().__init__(st_obj, label, min_value, max_value, value * 100.0, step, format, key)
-
-    def __call__(self):
-        return super().__call__() / 100.0
-
-
-class CheckboxInput(Input):
-    def __init__(self, st_obj, label, value=None, key=None):
-        kwargs = dict(key=key)
-        super().__init__(st_obj.checkbox, label, value, kwargs)
-
-
 def display_sidebar(st, d: Constants) -> Parameters:
     # Initialize variables
     # these functions create input elements and bind the values they are set to
@@ -152,141 +93,145 @@ def display_sidebar(st, d: Constants) -> Parameters:
 
     if d.known_infected < 1:
         raise ValueError("Known cases must be larger than one to enable predictions.")
-    st_obj = st.sidebar
-    current_hospitalized_input = NumberInput(
-        st_obj,
-        "Currently Hospitalized COVID-19 Patients",
-        min_value=0,
-        value=d.current_hospitalized,
-        step=1,
-        format="%i",
-    )
-    n_days_input = NumberInput(
-        st_obj,
+
+    n_days = st.sidebar.number_input(
         "Number of days to project",
         min_value=30,
         value=d.n_days,
+        step=10,
+        format="%i",
+    )
+
+    current_hospitalized = st.sidebar.number_input(
+        "Currently Hospitalized COVID-19 Patients",
+        min_value=0,
+        value=d.current_hospitalized,
         step=1,
         format="%i",
     )
-    doubling_time_input = NumberInput(
-        st_obj,
+
+    doubling_time = st.sidebar.number_input(
         "Doubling time before social distancing (days)",
-        min_value=FLOAT_INPUT_MIN,
+        min_value=0,
         value=d.doubling_time,
-        step=FLOAT_INPUT_STEP,
-        format="%f",
-    )
-    relative_contact_pct_input = PercentInput(
-        st_obj,
-        "Social distancing (% reduction in social contact)",
-        value=d.relative_contact_rate,
-    )
-    hospitalized_pct_input = PercentInput(
-        st_obj,
-        "Hospitalization %(total infections)",
-        value=d.hospitalized.rate,
+        step=1,
+        format="%i",
     )
-    icu_pct_input = PercentInput(
-        st_obj,
-        "ICU %(total infections)",
-        value=d.icu.rate,
+
+    relative_contact_rate = (
+        st.sidebar.number_input(
+            "Social distancing (% reduction in social contact)",
+            min_value=0,
+            max_value=100,
+            value=int(d.relative_contact_rate * 100),
+            step=5,
+            format="%i",
+        )
+        / 100.0
     )
-    ventilated_pct_input = PercentInput(
-        st_obj,
-        "Ventilated %(total infections)",
-        value=d.ventilated.rate,
+
+    hospitalized_rate = (
+        st.sidebar.number_input(
+            "Hospitalization %(total infections)",
+            min_value=0.001,
+            max_value=100.0,
+            value=d.hospitalized.rate * 100,
+            step=1.0,
+            format="%f",
+        )
+        / 100.0
+    )
+    icu_rate = (
+        st.sidebar.number_input(
+            "ICU %(total infections)",
+            min_value=0.0,
+            max_value=100.0,
+            value=d.icu.rate * 100,
+            step=1.0,
+            format="%f",
+        )
+        / 100.0
+    )
+    ventilated_rate = (
+        st.sidebar.number_input(
+            "Ventilated %(total infections)",
+            min_value=0.0,
+            max_value=100.0,
+            value=d.ventilated.rate * 100,
+            step=1.0,
+            format="%f",
+        )
+        / 100.0
     )
-    hospitalized_los_input = NumberInput(
-        st_obj,
+
+    hospitalized_los = st.sidebar.number_input(
         "Hospital Length of Stay",
         min_value=0,
         value=d.hospitalized.length_of_stay,
         step=1,
         format="%i",
     )
-    icu_los_input = NumberInput(
-        st_obj,
+    icu_los = st.sidebar.number_input(
         "ICU Length of Stay",
         min_value=0,
         value=d.icu.length_of_stay,
         step=1,
         format="%i",
     )
-    ventilated_los_input = NumberInput(
-        st_obj,
+    ventilated_los = st.sidebar.number_input(
         "Vent Length of Stay",
         min_value=0,
         value=d.ventilated.length_of_stay,
         step=1,
         format="%i",
     )
-    market_share_pct_input = PercentInput(
-        st_obj,
-        "Hospital Market Share (%)",
-        min_value=FLOAT_INPUT_MIN,
-        value=d.market_share,
+
+    market_share = (
+        st.sidebar.number_input(
+            "Hospital Market Share (%)",
+            min_value=0.001,
+            max_value=100.0,
+            value=d.market_share * 100,
+            step=1.0,
+            format="%f",
+        )
+        / 100.0
     )
-    population_input = NumberInput(
-        st_obj,
+    susceptible = st.sidebar.number_input(
         "Regional Population",
         min_value=1,
-        value=d.region.population,
-        step=1,
+        value=d.region.susceptible,
+        step=100000,
         format="%i",
     )
-    known_infected_input = NumberInput(
-        st_obj,
+
+    known_infected = st.sidebar.number_input(
         "Currently Known Regional Infections (only used to compute detection rate - does not change projections)",
         min_value=0,
         value=d.known_infected,
-        step=1,
+        step=10,
         format="%i",
     )
-    as_date_input = CheckboxInput(st_obj, "Present result as dates instead of days", value=False)
-    max_y_axis_set_input = CheckboxInput(st_obj, "Set the Y-axis on graphs to a static value")
-    max_y_axis_input = NumberInput(st_obj, "Y-axis static value", value=500, format="%i", step=25)
-
-    # Build in desired order
-    st.sidebar.markdown("### Regional Parameters [ℹ]({docs_url}/what-is-chime/parameters)".format(docs_url=DOCS_URL))
-    population = population_input()
-    market_share = market_share_pct_input()
-    known_infected = known_infected_input()
-    current_hospitalized = current_hospitalized_input()
-
-    st.sidebar.markdown("### Spread and Contact Parameters [ℹ]({docs_url}/what-is-chime/parameters)"
-                        .format(docs_url=DOCS_URL))
-    doubling_time = doubling_time_input()
-    relative_contact_rate = relative_contact_pct_input()
-
-    st.sidebar.markdown("### Severity Parameters [ℹ]({docs_url}/what-is-chime/parameters)".format(docs_url=DOCS_URL))
-    hospitalized_rate = hospitalized_pct_input()
-    icu_rate = icu_pct_input()
-    ventilated_rate = ventilated_pct_input()
-    hospitalized_los = hospitalized_los_input()
-    icu_los = icu_los_input()
-    ventilated_los = ventilated_los_input()
-
-    st.sidebar.markdown("### Display Parameters [ℹ]({docs_url}/what-is-chime/parameters)".format(docs_url=DOCS_URL))
-    n_days = n_days_input()
-    max_y_axis_set = max_y_axis_set_input()
-    as_date = as_date_input()
 
+    as_date = st.sidebar.checkbox(label="Present result as dates instead of days", value=False)
+
+    max_y_axis_set = st.sidebar.checkbox("Set the Y-axis on graphs to a static value")
     max_y_axis = None
     if max_y_axis_set:
-        max_y_axis = max_y_axis_input()
+        max_y_axis = st.sidebar.number_input(
+            "Y-axis static value", value=500, format="%i", step=25,
+        )
 
     return Parameters(
         as_date=as_date,
         current_hospitalized=current_hospitalized,
-        market_share=market_share,
-        known_infected=known_infected,
         doubling_time=doubling_time,
-
+        known_infected=known_infected,
+        market_share=market_share,
         max_y_axis=max_y_axis,
         n_days=n_days,
         relative_contact_rate=relative_contact_rate,
-        population=population,
+        susceptible=susceptible,
 
         hospitalized=RateLos(hospitalized_rate, hospitalized_los),
         icu=RateLos(icu_rate, icu_los),
@@ -398,8 +343,8 @@ $$\\beta = (g + \\gamma)$$.
 def write_definitions(st):
     st.subheader("Guidance on Selecting Inputs")
     st.markdown(
-        """**This information has been moved to the
-[User Documentation]({docs_url}/what-is-chime/parameters#guidance-on-selecting-inputs)**""".format(docs_url=DOCS_URL)
+        """**This information has been moved to the 
+[User Documentation](https://code-for-philly.gitbook.io/chime/what-is-chime/parameters#guidance-on-selecting-inputs)**"""
     )
 
 
diff --git a/src/penn_chime/settings.py b/src/penn_chime/settings.py
index d811c8a..d1831bf 100644
--- a/src/penn_chime/settings.py
+++ b/src/penn_chime/settings.py
@@ -18,7 +18,7 @@ DEFAULTS = Constants(
         philly=philly,
     ),
     current_hospitalized=14,
-    doubling_time=4.0,
+    doubling_time=4,
     known_infected=510,
     n_days=60,
     market_share=0.15,


Test patch:
diff --git a/e2e/cypress/integration/tests/actions.spec.js b/e2e/cypress/integration/tests/actions.spec.js
index f655b37..45474b8 100644
--- a/e2e/cypress/integration/tests/actions.spec.js
+++ b/e2e/cypress/integration/tests/actions.spec.js
@@ -3,14 +3,14 @@
 context('Actions', () => {
   beforeEach(() => {
     cy.visit('http://localhost:8000')
-  });
+  })
 
   it('All + elements are clickable', () => {
-    cy.get('.step-up').click( { multiple: true } );
+    cy.get('.step-up').click( { multiple: true } )
 
     // This gets the "first" input from the sidebar. From clicking step up,
-    // the Regional Population should increase from default 4119405 to 4219405.
+    // the number of days to project should increase from default 60 to 70.
     cy.get('input.st-al')
-      .should('has.value', '4119406')
+      .should('has.value', '70')
   })
-});
+})
diff --git a/tests/test_app.py b/tests/test_app.py
index 696663e..e995c6c 100644
--- a/tests/test_app.py
+++ b/tests/test_app.py
@@ -8,7 +8,7 @@ import numpy as np  # type: ignore
 import altair as alt  # type: ignore
 
 from src.penn_chime.charts import new_admissions_chart, admitted_patients_chart, chart_descriptions
-from src.penn_chime.models import SimSirModel, sir, sim_sir_df, build_admits_df, daily_growth_helper
+from src.penn_chime.models import SimSirModel, sir, sim_sir_df, build_admits_df
 from src.penn_chime.parameters import Parameters
 from src.penn_chime.presentation import display_header
 from src.penn_chime.settings import DEFAULTS
@@ -20,20 +20,7 @@ PARAM = Parameters(
     known_infected=5000,
     market_share=0.05,
     relative_contact_rate=0.15,
-    population=500000,
-    hospitalized=RateLos(0.05, 7),
-    icu=RateLos(0.02, 9),
-    ventilated=RateLos(0.01, 10),
-    n_days=60,
-)
-
-HALVING_PARAM = Parameters(
-    current_hospitalized=100,
-    doubling_time=6.0,
-    known_infected=5000,
-    market_share=0.05,
-    relative_contact_rate=0.7,
-    population=500000,
+    susceptible=500000,
     hospitalized=RateLos(0.05, 7),
     icu=RateLos(0.02, 9),
     ventilated=RateLos(0.01, 10),
@@ -41,7 +28,6 @@ HALVING_PARAM = Parameters(
 )
 
 MODEL = SimSirModel(PARAM)
-HALVING_MODEL = SimSirModel(HALVING_PARAM)
 
 
 # set up
@@ -72,38 +58,46 @@ st = MockStreamlit()
 # test presentation
 
 
-def header_test_helper(expected_str, model, param):
-    st.cleanup()
-    display_header(st, model, param)
-    assert [s for s in st.render_store if expected_str in s],\
-        "Expected the string '{expected}' in the display header".format(expected=expected_str)
-    st.cleanup()
-
-
 def test_penn_logo_in_header():
     penn_css = '<link rel="stylesheet" href="https://www1.pennmedicine.org/styles/shared/penn-medicine-header.css">'
-    header_test_helper(penn_css, MODEL, PARAM)
+    display_header(st, MODEL, PARAM)
+    assert len(
+        list(filter(lambda s: penn_css in s, st.render_store))
+    ), "The Penn Medicine header should be printed"
 
 
 def test_the_rest_of_header_shows_up():
     random_part_of_header = "implying an effective $R_t$ of"
-    header_test_helper(random_part_of_header, MODEL, PARAM)
+    assert len(
+        list(filter(lambda s: random_part_of_header in s, st.render_store))
+    ), "The whole header should render"
 
 
 def test_mitigation_statement():
+    st.cleanup()
     expected_doubling = "outbreak **reduces the doubling time to 7.8** days"
+    display_header(st, MODEL, PARAM)
+    assert [s for s in st.render_store if expected_doubling in s]
+    # assert len((list(filter(lambda s: expected_doubling in s, st.render_store))))
+    st.cleanup()
     expected_halving = "outbreak **halves the infections every 51.9** days"
-    header_test_helper(expected_doubling, MODEL, PARAM)
-    header_test_helper(expected_halving, HALVING_MODEL, HALVING_PARAM)
-
-
-def test_daily_growth_presentation():
-    initial_growth = "and daily growth rate of **12.25%**."
-    mitigated_growth = "and daily growth rate of **9.34%**."
-    mitigated_halving = "and daily growth rate of **-1.33%**."
-    header_test_helper(initial_growth, MODEL, PARAM)
-    header_test_helper(mitigated_growth, MODEL, PARAM)
-    header_test_helper(mitigated_halving, HALVING_MODEL, HALVING_PARAM)
+    halving_params = Parameters(
+        current_hospitalized=100,
+        doubling_time=6.0,
+        known_infected=5000,
+        market_share=0.05,
+        relative_contact_rate=0.7,
+        susceptible=500000,
+        hospitalized=RateLos(0.05, 7),
+        icu=RateLos(0.02, 9),
+        ventilated=RateLos(0.01, 10),
+        n_days=60,
+    )
+    halving_model = SimSirModel(halving_params)
+    display_header(st, halving_model, halving_params)
+    assert [s for s in st.render_store if expected_halving in s]
+    #assert len((list(filter(lambda s: expected_halving in s, st.render_store))))
+    st.cleanup()
 
 
 st.cleanup()
@@ -201,17 +195,15 @@ def test_new_admissions_chart():
     projection_admits = pd.read_csv("tests/projection_admits.csv")
     chart = new_admissions_chart(alt, projection_admits, PARAM)
     assert isinstance(chart, alt.Chart)
-    # COMMENTING OUT because chart tests oughtn't bother with numeric info anyway
-    # assert chart.data.iloc[1].hospitalized < 1 
+    assert chart.data.iloc[1].hospitalized < 1
     assert round(chart.data.iloc[40].icu, 0) == 25
 
     # test fx call with no params
     with pytest.raises(TypeError):
         new_admissions_chart()
-    
-    # unnecessary
-    # empty_chart = new_admissions_chart(alt, pd.DataFrame(), PARAM)
-    # assert empty_chart.data.empty
+
+    empty_chart = new_admissions_chart(alt, pd.DataFrame(), PARAM)
+    assert empty_chart.data.empty
 
 
 def test_admitted_patients_chart():
@@ -238,7 +230,7 @@ def test_model(model=MODEL, param=PARAM):
     # test the class-calculated attributes
     assert model.detection_probability == 0.125
     assert model.intrinsic_growth_rate == 0.12246204830937302
-    assert model.beta == 3.582761451679408e-07
+    assert model.beta == 3.2961405355450555e-07
     assert model.r_t == 2.307298374881539
     assert model.r_naught == 2.7144686763312222
     assert model.doubling_time_t == 7.764405988534983
@@ -251,19 +243,16 @@ def test_model(model=MODEL, param=PARAM):
     second = raw_df.iloc[1, :]
     last = raw_df.iloc[-1, :]
 
-    assert first.susceptible + first.infected + first.recovered == param.population
-    assert last.susceptible + last.infected + last.recovered == param.population
-
-    assert first.susceptible == 460000.0
+    assert first.susceptible == 500000.0
     assert round(second.infected, 0) == 43735
 
-    assert round(last.susceptible, 0) == 59497
-    assert round(raw_df.recovered[30], 0) == 216711
+    assert round(last.susceptible, 0) == 67202
+    assert round(raw_df.recovered[30], 0) == 224048
 
     assert list(model.dispositions_df.iloc[0, :]) == [0, 100.0, 40.0, 20.0]
-    assert [round(i, 0) for i in model.dispositions_df.iloc[60, :]] == [60, 1101.0, 441.0, 220.0]
+    assert [round(i, 0) for i in model.dispositions_df.iloc[60, :]] == [60, 1182.0, 473.0, 236.0]
 
-    # test that admissions are being properly calculated
+    # test that admissions are being properly calculated (thanks @PhilMiller)
     cumulative_admits = model.admits_df.cumsum()
     diff = cumulative_admits.hospitalized[1:-1] - (
         0.05 * 0.05 * (raw_df.infected[1:-1] + raw_df.recovered[1:-1]) - 100
@@ -271,12 +260,6 @@ def test_model(model=MODEL, param=PARAM):
     assert (diff.abs() < 0.1).all()
 
 
-def test_daily_growth_helper():
-    assert np.round(daily_growth_helper(5), decimals=4) == 14.8698
-    assert np.round(daily_growth_helper(0), decimals=4) == 0.0
-    assert np.round(daily_growth_helper(-4), decimals=4) == -15.9104
-
-
 def test_chart_descriptions(p=PARAM):
     # new admissions chart
     projection_admits = pd.read_csv('tests/projection_admits.csv')