159 lines
4.3 KiB
Python
Executable File
159 lines
4.3 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import csv
|
|
import datetime
|
|
import requests
|
|
|
|
|
|
def with_snapshot(func):
|
|
def wrapper(self, ts=None):
|
|
if not ts:
|
|
ts = self.Latest()
|
|
return func(self, self.Snapshots[ts])
|
|
return wrapper
|
|
|
|
|
|
def per_million(func):
|
|
def wrapper(self, *args, **kwargs):
|
|
count = func(self, *args, **kwargs)
|
|
return round(count * 1000000 / self.Population)
|
|
return wrapper
|
|
|
|
|
|
class State:
|
|
def __init__(self, population):
|
|
self.Population = population
|
|
self.Snapshots = {}
|
|
|
|
def AddSnapshot(self, ts, positive, negative, pending, hospitalized, dead):
|
|
self.Snapshots[ts] = Snapshot(positive, negative, pending, hospitalized, dead)
|
|
|
|
def Latest(self):
|
|
return max(self.Snapshots)
|
|
|
|
@with_snapshot
|
|
@per_million
|
|
def TestsPerMillion(self, snap):
|
|
return snap.Tests()
|
|
|
|
@with_snapshot
|
|
@per_million
|
|
def PositivePerMillion(self, snap):
|
|
return snap.Positive
|
|
|
|
@with_snapshot
|
|
@per_million
|
|
def HospitalizedPerMillion(self, snap):
|
|
return snap.Hospitalized
|
|
|
|
@with_snapshot
|
|
@per_million
|
|
def DeadPerMillion(self, snap):
|
|
return snap.Dead
|
|
|
|
@with_snapshot
|
|
def PositivePerTestBP(self, snap):
|
|
return round(snap.Positive * 10000 / snap.Tests()) if snap.Tests() else 0
|
|
|
|
def __str__(self):
|
|
return f'{self.Population:>10}=pop {len(self.Snapshots):>4}=snaps {self.TestsPerMillion():>6}=tpm {self.PositivePerMillion():>6}=ppm {self.HospitalizedPerMillion():>6}=hpm {self.DeadPerMillion():>6}=dpm {self.PositivePerTestBP():>4}=p‱'
|
|
|
|
|
|
class Snapshot:
|
|
def __init__(self, positive, negative, pending, hospitalized, dead):
|
|
self.Positive = positive or 0
|
|
self.Negative = negative or 0
|
|
self.Pending = pending or 0
|
|
self.Hospitalized = hospitalized or 0
|
|
self.Dead = dead or 0
|
|
|
|
def Tests(self):
|
|
return self.Positive + self.Negative
|
|
|
|
|
|
states = {}
|
|
latest = datetime.datetime.utcfromtimestamp(0)
|
|
|
|
|
|
def LoadPopulations():
|
|
with open('populations.csv', 'r') as fh:
|
|
reader = csv.DictReader(fh)
|
|
for row in reader:
|
|
states[row['State']] = State(int(row['Population']))
|
|
|
|
def LoadCovidTracking():
|
|
global latest, states
|
|
|
|
resp = requests.get('https://covidtracking.com/api/states/daily')
|
|
for row in resp.json():
|
|
ts = datetime.datetime.fromisoformat(row['dateChecked'][:-1])
|
|
states[row['state']].AddSnapshot(
|
|
ts,
|
|
row['positive'],
|
|
row['negative'],
|
|
row['pending'],
|
|
row['hospitalized'],
|
|
row['death'],
|
|
)
|
|
latest = max(latest, ts)
|
|
|
|
def SumTotal():
|
|
total = State(0)
|
|
positive = 0
|
|
negative = 0
|
|
pending = 0
|
|
hospitalized = 0
|
|
dead = 0
|
|
|
|
for state in states.values():
|
|
total.Population += state.Population
|
|
snap = state.Snapshots[state.Latest()]
|
|
positive += snap.Positive
|
|
negative += snap.Negative
|
|
pending += snap.Pending
|
|
hospitalized += snap.Hospitalized
|
|
dead += snap.Dead
|
|
|
|
total.AddSnapshot(
|
|
latest,
|
|
positive,
|
|
negative,
|
|
pending,
|
|
hospitalized,
|
|
dead,
|
|
)
|
|
states['ΣΣ'] = total
|
|
|
|
def PrintStates():
|
|
for code, state in sorted(states.items(), key=lambda x: x[1].Population):
|
|
print(f'{code} {state}')
|
|
|
|
def ExtrapolateWorstPPM():
|
|
worst = max(states.items(), key=lambda x: x[1].PositivePerMillion())
|
|
ppm = worst[1].PositivePerMillion()
|
|
print(f'Extrapolating worst {ppm}=ppm (from {worst[0]}) gives {round(states["ΣΣ"].Population * ppm / 1000000)} infected')
|
|
|
|
def ExtrapolateWorstHPM():
|
|
worst = max(states.items(), key=lambda x: x[1].HospitalizedPerMillion())
|
|
hpm = worst[1].HospitalizedPerMillion()
|
|
print(f'Extrapolating worst {hpm}=hpm (from {worst[0]}) gives {round(states["ΣΣ"].Population * hpm / 1000000)} hospitalized')
|
|
|
|
def ExtrapolateWorstDPM():
|
|
worst = max(states.items(), key=lambda x: x[1].DeadPerMillion())
|
|
dpm = worst[1].DeadPerMillion()
|
|
print(f'Extrapolating worst {dpm}=dpm (from {worst[0]}) gives {round(states["ΣΣ"].Population * dpm / 1000000)} dead')
|
|
|
|
|
|
LoadPopulations()
|
|
LoadCovidTracking()
|
|
SumTotal()
|
|
PrintStates()
|
|
|
|
print()
|
|
|
|
ExtrapolateWorstPPM()
|
|
ExtrapolateWorstHPM()
|
|
ExtrapolateWorstDPM()
|
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|