Skip to content

Commit

Permalink
PyPi Release
Browse files Browse the repository at this point in the history
v1.0.0 (First Full Production-Ready Release)
  • Loading branch information
quantum9Innovation committed Aug 22, 2020
1 parent d606ec0 commit 69414f7
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -15,7 +15,7 @@ As a shorthand, use as `import epispot as epi`

## Screenshots

![epidemic-graph](https://i.ibb.co/K9wrhhs/temp.png)
![line-graph](tests/examples/line-graph.png)

## Features

Expand Down
2 changes: 1 addition & 1 deletion build/lib/epispot/__init__.py
Expand Up @@ -17,4 +17,4 @@
from . import plots

# version info
__version__ = 'v0.1.3-beta'
__version__ = 'v1.0.0'
288 changes: 280 additions & 8 deletions build/lib/epispot/comps.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/lib/epispot/plots.py
Expand Up @@ -10,7 +10,7 @@
from . import colors


def plot_comp_nums(Model, timesteps, starting_state=None, seed=1):
def plot_comp_nums(Model, timesteps, starting_state=None, seed=100):
"""
This is meant for plotting the number of people in each compartment over a period of time
Expand Down
Binary file added dist/epispot-1.0.0-py3-none-any.whl
Binary file not shown.
Binary file added dist/epispot-1.0.0.tar.gz
Binary file not shown.
10 changes: 7 additions & 3 deletions epispot.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: epispot
Version: 0.1.3b0
Version: 1.0.0
Summary: A tool for modelling infectious diseases.
Home-page: https://quantum9innovation.github.io/epispot
Author: quantum9innovation
Expand All @@ -11,14 +11,18 @@ Description: # ![epi-spot](https://i.ibb.co/hXMjrCV/epi-spot.png)
A tool for creating and testing epidemiological models faster than ever for the mathematical modelling of infectious
diseases. An idea from https://github.com/henrifroese/infectious_disease_modelling.

<br><br><br>

![epi-spot social image](https://i.ibb.co/0KLfTm5/epi-spot-social.png)

## Installation

Install via `pip install epispot` <br>
As a shorthand, use as `import epispot as epi`

## Screenshots

![epidemic-graph](https://i.ibb.co/K9wrhhs/temp.png)
![line-graph](tests/examples/line-graph.png)

## Features

Expand Down Expand Up @@ -51,5 +55,5 @@ Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3.7
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Operating System :: OS Independent
Requires-Python: >=3
Requires-Python: >=3.7
Description-Content-Type: text/markdown
2 changes: 1 addition & 1 deletion epispot/__init__.py
Expand Up @@ -17,4 +17,4 @@
from . import plots

# version info
__version__ = 'v0.1.3-beta'
__version__ = 'v1.0.0'
177 changes: 161 additions & 16 deletions epispot/comps.py
Expand Up @@ -9,6 +9,7 @@
- Exposed(object)
- Dead(object)
- Hospitalized(object)
- Critical(object)
- Idiom(object)
"""

Expand Down Expand Up @@ -210,7 +211,7 @@ def __init__(self, layer_index, N, R_0=None, gamma=None, delta=None, p_recovery=
- t: time
- return: death probability
:param death_rate: =None, 1 / rate of death (only applicable if next layer is Dead)
implemented as a function death_rate(t)
implemented as a function death_rate(t)--in most cases this should stay constant
- t: time
- return: death rate
"""
Expand Down Expand Up @@ -584,7 +585,7 @@ def __init__(self, layer_index, rho_inf=None, alpha_inf=None, rho_hos=None, alph
:param layer_index: index of layer in `layers`
:param rho_inf: =None, 1 / time until death from Infected (only applicable if previous layer is Infected)
implemented as a function rho_inf(t)
implemented as a function rho_inf(t)--in most cases this should stay constant
- t: time
- return: death rate
:param alpha_inf: =None, probability of death from Infected (only applicable if previous layer is Infected)
Expand All @@ -593,7 +594,7 @@ def __init__(self, layer_index, rho_inf=None, alpha_inf=None, rho_hos=None, alph
- return: probability of death
:param rho_hos: =None, 1 / time until death from Hospitalized (only applicable if previous layer is
Hospitalized)
implemented as a function rho_hos(t)
implemented as a function rho_hos(t)--in most cases this should stay constant
- t: time
- return: death rate
:param alpha_hos: =None, probability of death from Hospitalized (only applicable if previous layer is
Expand All @@ -602,7 +603,7 @@ def __init__(self, layer_index, rho_inf=None, alpha_inf=None, rho_hos=None, alph
- t: time
- return: probability of death
:param rho_cri: =None, 1 / time until death from Critical (only applicable if previous layer is Critical)
implemented as a function rho_cri(t)
implemented as a function rho_cri(t)--in most cases this should stay constant
- t: time
- return: death rate
:param alpha_cri: =None, probability of death from Critical (only applicable if previous layer is Critical)
Expand Down Expand Up @@ -699,7 +700,7 @@ class Hospitalized(object):
"""
The Hospitalized class represents the portion of individuals currently taking up space in the available
hospitals. However, this is a distinct category from the Critical portion of individuals, who require
more resources (ICU beds, etc.). This layer supports triage.
more resources (ICU beds, ventilators, etc.). This layer supports triage.
Infected --> Hospitalized --> Critical, Dead
STRUCTURE:
- __init__
Expand All @@ -722,35 +723,35 @@ def __init__(self, layer_index, hos_rate, p_hos, cri_rate=None, p_cri=None, reco
implemented as a function p_hos(t)
- t: time
- return: probability of hospitalization
:param cri_rate: 1 / time until a patient becomes Critical
:param cri_rate: =None, 1 / time until a patient becomes Critical (only applicable if next layer is Critical)
implemented as a function cri_rate(t)
- t: time
- return: critical rate
:param p_cri: probability of becoming a Critical patient
:param p_cri: =None, probability of becoming a Critical patient (only applicable if next layer is Critical)
implemented as a function p_cri(t)
- t: time
- return: probability of becoming Critical
:param recovery_rate: 1 / time to recover
:param recovery_rate: =None, 1 / time to recover (only applicable if next layer is Recovered)
implemented as a function recovery_rate(t)
- t: time
- return: recovery rate
:param p_recovery: probability of recovery
:param p_recovery: =None, probability of recovery (only applicable if next layer is Recovered)
implemented as a function p_recovery(t)
- t: time
- return: probability of recovery
:param rho: 1 / time in hospital until death
implemented as a function rho(t)
:param rho: =None, 1 / time in hospital until death (only applicable if next layer is Dead)
implemented as a function rho(t)--in most cases this should stay constant
- t: time
- return: death rate
:param alpha: probability of death
:param alpha: =None, probability of death (only applicable if next layer is Dead)
implemented as a function alpha(t)
- t: time
- return: probability of death
:param maxCap: maximum hospital capacity to implement triage
:param maxCap: =None, maximum hospital capacity to implement triage
implemented as a function maxCap(t)
- t: time
- return: maximum capacity
:param dump_to_layer: index of the layer to dump patients which do not make the triage
:param dump_to_layer: =None, index of the layer to dump patients which do not make the triage
should be of type int()
"""

Expand Down Expand Up @@ -794,7 +795,7 @@ def test(self, layer_map, layer_names):

def get_deriv(self, time, system):
"""
Derivative of this compartment
Derivative of the Hospitalized compartment
:param time: time to take derivative at
:param system: system of all states
Expand All @@ -821,13 +822,157 @@ def get_deriv(self, time, system):
return derivative


class Critical(object):
"""
The Critical class represents the portion of individuals currently taking up space in the available
hospitals *and* using limited resources. However, this is a distinct category from the Hospitalized portion of
individuals, who don't require extra resources (ICU beds, ventilators, etc.). This layer supports triage.
Hospitalized, Infected --> Critical --> Dead, Recovered
STRUCTURE:
- __init__
- get_layer_index
- test
- get_deriv
"""

def __init__(self, layer_index, p_from_hos=None, from_hos_rate=None, p_from_inf=None, from_inf_rate=None, rho=None, alpha=None,
p_recovery=None, recovery_rate=None, maxCap=None, dump_to_layer=None):
"""
Initialize the Critical class
:param layer_index: index of layer in `layers`
:param p_from_hos: =None, probability of becoming a Critical patient from Hospitalized
(only applicable if previous layer is Hospitalized)
implemented as a function p_from_hos(t)
- t: time
- return: Critical probability
:param from_hos_rate: =None, 1 / time to Critical condition from Hospitalized
(only applicable if previous layer is Hospitalized)
implemented as a function from_hos_rate(t)
- t: time
- return: Critical rate
:param p_from_inf: =None, probability of becoming a Critical patient from Infected
(only applicable if previous layer is Infected)
implemented as a function p_from_inf(t)
- t: time
- return: Critical probability
:param from_inf_rate: =None, 1 / time to Critical condition from Infected
(only applicable if previous layer is Infected)
implemented as a function from_inf_rate(t)
- t: time
- return: Critical rate
:param alpha: =None, probability of death (only applicable if next layer is Dead)
implemented as a function alpha(t)
- t: time
- return: probability of death
:param rho: =None, 1 / time until death from Critical (only applicable if next layer is Dead)
implemented as a function rho(t)--in most cases this should stay constant
- t: time
- return: death rate
:param p_recovery: =None, probability of recovery (only applicable if next layer is Recovered)
implemented as a function p_recovery(t)
- t: time
- return: probability of recovery
:param recovery_rate: =None, 1 / time to recover (only applicable if next layer is Recovered)
implemented as a function recovery_rate(t)
- t: time
- return: recovery rate
:param maxCap: =None, maximum hospital capacity to implement triage
implemented as a function maxCap(t)
- t: time
- return: maximum capacity
:param dump_to_layer: =None, index of the layer to dump patients which do not make the triage
should be of type int()
"""

self.layer_index = layer_index
self.p_from_hos = p_from_hos
self.from_hos_rate = from_hos_rate
self.p_from_inf = p_from_inf
self.from_inf_rate = from_inf_rate
self.alpha = alpha
self.rho = rho
self.p_recovery = p_recovery
self.recovery_rate = recovery_rate
self.maxCap = maxCap
self.dump_to_layer = dump_to_layer

self.hospitalized_category_indices = []
self.infected_category_indices = []

def get_layer_index(self):
return self.layer_index

def test(self, layer_map, layer_names):
"""
Test of the `get_deriv` method
Used to setup commonly used variables and raise common errors
:param layer_map: next layers (as classes) for every layer in Model
:param layer_names: layer names in system
:return: derivative
"""

# setup
for layer_no in range(len(layer_map)):
for next_layer in layer_map[layer_no]:
if next_layer.get_layer_index() == self.layer_index and layer_names[layer_no] == 'Hospitalized':
self.hospitalized_category_indices.append(layer_no)
elif next_layer.get_layer_index() == self.layer_index and layer_names[layer_no] == 'Infected':
self.infected_category_indices.append(layer_no)
# warnings
elif next_layer.get_layer_index() == self.layer_index:
warnings.warn('You are trying to connect a layer to the Critical layer at %s that is neither \n'
'of the Hospitalized or Infected type. Please remove this connection or use a \n'
'custom layer instead of this one.' % self.layer_index)

# warnings
if not self.p_from_hos and len(self.hospitalized_category_indices) > 0:
warnings.warn("You have connected a Hospitalized layer to the Critical layer at %s but \n"
"haven't specified a Critical probability. Please do this by writing \n"
"`p_from_hos=FLOAT` AND `from_hos_rate=FLOAT` so this can be used.")

if not self.p_from_inf and len(self.infected_category_indices) > 0:
warnings.warn("You have connected a Infected layer to the Critical layer at %s but \n"
"haven't specified a Critical probability. Please do this by writing \n"
"`p_from_inf=FLOAT` AND `from_inf_rate=FLOAT` so this can be used.")

def get_deriv(self, time, system):
"""
Derivative of the Critical compartment
:param time: time to take derivative at
:param system: system of all states
:return: derivative
"""

derivative = 0

for hospitalized_category_index in self.hospitalized_category_indices:
derivative += self.p_from_hos(time) * self.from_hos_rate(time) * system[hospitalized_category_index]

for infected_category_index in self.infected_category_indices:
derivative += self.p_from_inf(time) * self.from_inf_rate(time) * system[infected_category_index]

if self.alpha:
derivative -= self.alpha(time) * self.rho(time) * system[self.layer_index]
if self.p_recovery:
derivative -= self.p_recovery(time) * self.recovery_rate(time) * system[self.layer_index]

# implement triage
if self.maxCap:
if system[self.layer_index] > self.maxCap(time):
derivative -= system[self.layer_index] - self.maxCap(time)

return derivative


class Idiom(object):
"""
An idiom used to create custom classes. Feed this into `Model.add_layer
Can be used with any class. Make sure to change `get_deriv` file.
If you wish, you can change all the other methods as well.
Pass all parameters as an array in `param_list`
STRUCTURE:
- __init__
- get_layer_index
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="epispot",
version="v0.1.3-beta",
version="v1.0.0",
author="quantum9innovation",
description="A tool for modelling infectious diseases.",
long_description=long_description,
Expand All @@ -17,6 +17,6 @@
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
],
python_requires='>=3',
python_requires='>=3.7',
install_requires=['matplotlib', ],
)
Binary file added tests/examples/line-graph.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions tests/tutorials/TODO.md

This file was deleted.

0 comments on commit 69414f7

Please sign in to comment.