Skip to content

Commit

Permalink
feat: remove printer and add drawer. edit reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
senavs committed Oct 2, 2021
1 parent 8383df1 commit 2bcc8de
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 104 deletions.
12 changes: 6 additions & 6 deletions simulation.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ MAX_AGE=90


# PATHOLOGY
PROB_INFECTION=0.15
PROB_INFECTION=0.20
PROB_DEATH=0.03
EXPOSED_MAX_DAY=7
INFECTIOUS_MAX_DAY=14


# PREVENTION MASK
MASK_PROB_INFECTION=0.2
MASK_PROB_DEATH=1
MASK_PERC_ACTIVATION=0.4

# PREVENTION ISOLATION
ISOLATION_PROB_INFECTION=0.5
ISOLATION_PROB_DEATH=1
ISOLATION_PERC_ACTIVATION=0.2

# PREVENTION MASK
MASK_PROB_INFECTION=0.4
MASK_PROB_DEATH=1
MASK_PERC_ACTIVATION=0.4

# PREVENTION VACCINE
VACCINE_PROB_INFECTION=1
VACCINE_PROB_DEATH=0.05
Expand Down
8 changes: 4 additions & 4 deletions simulation/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
selected_preventions.append(PREVENTIONS[flag])

preventions = ", ".join(preventions_names if preventions_names else ["null"])
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - start. preventions: {preventions}')
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - {preventions}')

p = Progress(*selected_preventions)
p.progress()
progress = Progress(*selected_preventions)
progress.run()

print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - done. {p.current_time} days')
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - {progress.current_time} days')
51 changes: 24 additions & 27 deletions simulation/automatos/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from simulation.automatos.board import Board
from simulation.core.subject import Subject
from simulation.report.printer import Printer
from simulation.report.drawer import BoardImageDrawer, BoardGifDrawer, GraphDrawer
from simulation.core.prevention import SocialIsolation, Mask, Vaccine, PreventionEnum
from simulation.report.reporter import Reporter
from simulation.report.reporter import SheetReporter
from simulation.settings import prevention_settings, SIMULATION_UUID

PREVS = {
Expand All @@ -23,38 +23,35 @@ def __init__(self, *preventions: PreventionEnum):
self.current_time = 0
self.board = Board()

self.printer = Printer()
self.reporter = Reporter(self.board)
def run(self):
with BoardImageDrawer() as board_drawer, SheetReporter(self.board) as sheet_reporter:
sheet_reporter.report_steps()

def progress(self):
self.reporter.report_cells()
while self.board.sick_cells():
self.current_time += 1

while self.board.sick_cells():
self.record()
board_drawer.draw(self.board, f'{self.current_time:0>5}')
sheet_reporter.report_steps()

for sick_cell in self.board.filter_sick():
neighbours = self.board.get_closest_neighbours(sick_cell)
sick_cell.subject.agglomerate([cell.subject for cell in neighbours])
for sick_cell in self.board.filter_sick():
neighbours = self.board.get_closest_neighbours(sick_cell)
sick_cell.subject.agglomerate([cell.subject for cell in neighbours])
sick_cell.subject.pathology.evolve()

sick_cell.subject.pathology.evolve()
self._activate_preventions(sheet_reporter)
else:
self.current_time += 1

self.activate_preventions()
board_drawer.draw(self.board, f'{self.current_time:0>5}')
sheet_reporter.report_steps()

self.record()
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - images saved')
with BoardGifDrawer() as gif_drawer:
gif_drawer.draw()

self.reporter.save()
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - sheets saved')
with GraphDrawer() as graph_drawer:
graph_drawer.draw()

self.printer.make_gif()
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - gif saved')

def record(self):
self.current_time += 1
self.printer.draw(self.board, f'{self.current_time:0>5}')
self.reporter.report_steps()

def activate_preventions(self):
def _activate_preventions(self, sheet_reporter: SheetReporter):
n_cells_have_been_sick = self.board.filter_have_been_sick().size

for name, (prev, prec_setting) in PREVS.items():
Expand All @@ -65,5 +62,5 @@ def activate_preventions(self):
if not prev.activate():
continue

self.reporter.report_prevt(name, self.current_time)
sheet_reporter.report_prevt(name, self.current_time)
print(f'{datetime.now().isoformat()} {SIMULATION_UUID} - {name} activated. {self.current_time} days')
192 changes: 192 additions & 0 deletions simulation/report/drawer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import os
from abc import ABC, abstractmethod
from collections import namedtuple

import imageio
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from matplotlib.axes import Axes
from matplotlib.figure import Figure

from simulation.automatos.board import Board
from simulation.settings import report_settings

FilteredDataframes = namedtuple('FilteredDataframes', ['infected', 'dead', 'infected_per_day', 'dead_per_day', 'dead_by_age'])


class Drawer(ABC):

def __init_subclass__(cls, width: int = 100, height: int = 100, dpi: int = 96, *args, **kwargs):
cls.width = width
cls.height = height
cls.dpi = dpi
return cls

def __init__(self):
self.figure: Figure = plt.figure(figsize=(self.width / self.dpi, self.height / self.dpi), dpi=self.dpi)
self.axis: Axes = plt.subplot(1, 1, 1)

@abstractmethod
def draw(self, *args, **kwargs):
raise NotImplemented

def __enter__(self) -> 'Drawer':
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.axis.cla()


class BoardImageDrawer(Drawer, width=800, height=800, dpi=96):

def draw(self, board: Board, file_name: str):
func = np.frompyfunc(lambda cell: cell.draw(), 1, 1)

drawable_board = np.array(func(board.board).tolist(), dtype=np.uint8)

self.axis.cla()
self.axis.axis('off')
self.axis.imshow(drawable_board)
self._create_grid(drawable_board)

self.figure.savefig(f'{report_settings.OUTPUT_BOARD_DIR}/{file_name}.png', bbox_inches='tight')

@staticmethod
def _create_grid(arr: np.ndarray):
""""Add grid border in each pixel"""

pixel, *_ = arr.shape
plt.hlines(y=np.arange(0, pixel) + 0.5, xmin=np.full(pixel, 0) - 0.5, xmax=np.full(pixel, pixel) - 0.5, color="black", linewidth=0.2)
plt.vlines(x=np.arange(0, pixel) + 0.5, ymin=np.full(pixel, 0) - 0.5, ymax=np.full(pixel, pixel) - 0.5, color="black", linewidth=0.2)


class GraphDrawer(Drawer, width=800, height=200, dpi=96):

def draw(self):
cells, steps, prevt = self._load_dataframes(report_settings.OUTPUT_SHEET_DIR)
filtered_dataframes = self._create_filtered_dataframes(cells, steps)

self._draw_infected(filtered_dataframes.infected, prevt)
self._draw_infected_per_day(filtered_dataframes.infected_per_day, prevt)
self._draw_dead(filtered_dataframes.dead, prevt)
self._draw_dead_per_day(filtered_dataframes.dead_per_day, prevt)
self._draw_dead_by_age(filtered_dataframes.dead_by_age)

def _draw_infected(self, infected: pd.DataFrame, prevt: pd.DataFrame):
data = infected.sum(axis=1)

self.axis.set_title('Infected')
self.axis.plot(data.values, color='r', label='infected')
self._create_prevt_lines(prevt)
self.axis.legend()

self.figure.savefig(f'{report_settings.OUTPUT_GRAPH_DIR}/infected.png', bbox_inches='tight')

self.axis.cla()

def _draw_infected_per_day(self, infected_per_day: pd.DataFrame, prevt: pd.DataFrame):
data = infected_per_day.sum(axis=1)
rolling = data.rolling(7).mean()

self.axis.set_title('Infected per day')
self.axis.bar(data.index, data.values, color='r', label='infected')
self.axis.plot(rolling, color='black', label='7 days average long-term', linewidth=2)
self._create_prevt_lines(prevt)
self.axis.legend()

self.figure.savefig(f'{report_settings.OUTPUT_GRAPH_DIR}/infected_per_day.png', bbox_inches='tight')

self.axis.cla()

def _draw_dead(self, dead: pd.DataFrame, prevt: pd.DataFrame):
data = dead.sum(axis=1)

self.axis.set_title('Dead')
self.axis.plot(data.values, color='r', label='dead')
self._create_prevt_lines(prevt)
self.axis.legend()

self.figure.savefig(f'{report_settings.OUTPUT_GRAPH_DIR}/dead.png', bbox_inches='tight')

self.axis.cla()

def _draw_dead_per_day(self, dead_per_day: pd.DataFrame, prevt: pd.DataFrame):
data = dead_per_day.sum(axis=1)
rolling = data.rolling(7).mean()

self.axis.set_title('Dead per day')
self.axis.bar(data.index, data.values, color='r', label='dead')
self.axis.plot(rolling, color='black', label='7 days average long-term', linewidth=2)
self._create_prevt_lines(prevt)
self.axis.legend()

self.figure.savefig(f'{report_settings.OUTPUT_GRAPH_DIR}/dead_per_day.png', bbox_inches='tight')

self.axis.cla()

def _draw_dead_by_age(self, dead_by_age: pd.DataFrame):
self.axis.set_title('Dead by age')
self.axis.bar(dead_by_age.index, dead_by_age.values, color='black', label='dead')
self.axis.legend()

self.figure.savefig(f'{report_settings.OUTPUT_GRAPH_DIR}/dead_by_age.png', bbox_inches='tight')

self.axis.cla()

@staticmethod
def _load_dataframes(reports_path: str) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
cells = pd.read_csv(os.path.join(reports_path, 'cells.csv'))
steps = pd.read_csv(os.path.join(reports_path, 'steps.csv'))
prevt = pd.read_csv(os.path.join(reports_path, 'prevt.csv'))

return cells, steps, prevt

@staticmethod
def _create_filtered_dataframes(cells: pd.DataFrame, steps: pd.DataFrame) -> FilteredDataframes:
def apply_first_time(col: pd.Series, condition: str):
col_copy = col.copy()
col_copy.values[:] = 0

if condition in col.unique():
col_copy[np.argmax((col == condition))] = 1
return col_copy

infected = steps.applymap(lambda x: x in ('EXPOSED', 'INFECTOUS'))

dead = steps.applymap(lambda x: x in ('DEAD',))

infected_per_day = steps.apply(lambda x: apply_first_time(x, 'EXPOSED'))

dead_per_day = steps.apply(lambda x: apply_first_time(x, 'DEAD'))

dead_by_age = dead.copy()
dead_by_age.columns = cells.age.astype(int)
dead_by_age = dead_by_age.sum(axis=0).groupby('age').sum().sort_index()

return FilteredDataframes(infected, dead, infected_per_day, dead_per_day, dead_by_age)

@staticmethod
def _create_prevt_lines(prevt: pd.DataFrame):
for column, color in zip(prevt.columns, ['y', 'b', 'g']):
value = prevt.loc[0, column]
if not value:
continue
plt.axvline(x=prevt.loc[0, column], color=color, label=column, linewidth=3)


class BoardGifDrawer(Drawer):

def __init__(self):
# it's not necessary figure or axis
object.__init__(self)

def draw(self):
images = []
for filename in sorted(os.listdir(report_settings.OUTPUT_BOARD_DIR)):
images.append(imageio.imread(os.path.join(report_settings.OUTPUT_BOARD_DIR, filename)))
imageio.mimsave(f'{report_settings.OUTPUT_GIF_DIR}/movie.gif', images)

def __exit__(self, exc_type, exc_val, exc_tb):
# it's not necessary to clear figure or axis, but it's not have
pass
55 changes: 0 additions & 55 deletions simulation/report/printer.py

This file was deleted.

8 changes: 6 additions & 2 deletions simulation/report/reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from simulation.settings import report_settings


class Reporter:
class SheetReporter:

def __init__(self, board: Board):
self.flatten_board: np.ndarray = board.board.reshape(mul(*board.board.shape))
Expand Down Expand Up @@ -35,7 +35,11 @@ def report_prevt(self, prevt_type: str, started_day: int):

self.prevt_data[prevt_type] = started_day

def save(self):
def __enter__(self) -> 'SheetReporter':
self.report_cells()
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.cells_data.to_csv(f'{report_settings.OUTPUT_SHEET_DIR}/cells.csv', index=False) # noqa
self.steps_data.to_csv(f'{report_settings.OUTPUT_SHEET_DIR}/steps.csv', index=False) # noqa
self.prevt_data.to_csv(f'{report_settings.OUTPUT_SHEET_DIR}/prevt.csv', index=False) # noqa
Loading

0 comments on commit 2bcc8de

Please sign in to comment.