Replacing the use of hours2timestring by datetimes, in the x-axis of the plots generated in report_generator
This commit is contained in:
parent
99152f7e44
commit
26d7ef9f5d
3 changed files with 27 additions and 26 deletions
|
|
@ -458,14 +458,10 @@ class FormData:
|
|||
|
||||
present_intervals = []
|
||||
|
||||
def hours2time(hours: float):
|
||||
# Convert times like 14.5 to strings, like "14:30"
|
||||
return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}"
|
||||
|
||||
# def add_interval(start, end):
|
||||
|
||||
current_time = start
|
||||
LOG.debug(f"starting time march at {hours2time(current_time/60)} to {hours2time(finish/60)}")
|
||||
LOG.debug(f"starting time march at {_hours2timestring(current_time/60)} to {_hours2timestring(finish/60)}")
|
||||
|
||||
# As we step through the breaks. For each break there are 6 important cases
|
||||
# we must cover. Let S=start; E=end; Bs=Break start; Be=Break end:
|
||||
|
|
@ -480,8 +476,8 @@ class FormData:
|
|||
if current_time >= finish:
|
||||
break
|
||||
|
||||
LOG.debug(f"handling break {hours2time(current_break[0]/60)}-{hours2time(current_break[1]/60)} "
|
||||
f" (current time: {hours2time(current_time/60)})")
|
||||
LOG.debug(f"handling break {_hours2timestring(current_break[0]/60)}-{_hours2timestring(current_break[1]/60)} "
|
||||
f" (current time: {_hours2timestring(current_time/60)})")
|
||||
|
||||
break_s, break_e = current_break
|
||||
case1 = finish <= break_s
|
||||
|
|
@ -494,22 +490,22 @@ class FormData:
|
|||
if case1:
|
||||
LOG.debug(f"case 1: interval entirely before break")
|
||||
present_intervals.append((current_time / 60, finish / 60))
|
||||
LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} "
|
||||
f"- {hours2time(present_intervals[-1][1])}")
|
||||
LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} "
|
||||
f"- {_hours2timestring(present_intervals[-1][1])}")
|
||||
current_time = finish
|
||||
elif case2:
|
||||
LOG.debug(f"case 2: interval straddles start of break")
|
||||
present_intervals.append((current_time / 60, break_s / 60))
|
||||
LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} "
|
||||
f"- {hours2time(present_intervals[-1][1])}")
|
||||
LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} "
|
||||
f"- {_hours2timestring(present_intervals[-1][1])}")
|
||||
current_time = break_e
|
||||
elif case3:
|
||||
LOG.debug(f"case 3: break entirely inside interval")
|
||||
# We add the bit before the break, but not the bit afterwards,
|
||||
# as it may hit another break.
|
||||
present_intervals.append((current_time / 60, break_s / 60))
|
||||
LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} "
|
||||
f"- {hours2time(present_intervals[-1][1])}")
|
||||
LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} "
|
||||
f"- {_hours2timestring(present_intervals[-1][1])}")
|
||||
current_time = break_e
|
||||
elif case4:
|
||||
LOG.debug(f"case 4: interval entirely inside break")
|
||||
|
|
@ -652,6 +648,11 @@ WINDOWS_TYPES = {'window_sliding', 'window_hinged', 'not-applicable'}
|
|||
COFFEE_OPTIONS_INT = {'coffee_break_0': 0, 'coffee_break_1': 1, 'coffee_break_2': 2, 'coffee_break_4': 4}
|
||||
|
||||
|
||||
def _hours2timestring(hours: float):
|
||||
# Convert times like 14.5 to strings, like "14:30"
|
||||
return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}"
|
||||
|
||||
|
||||
def time_string_to_minutes(time: str) -> minutes_since_midnight:
|
||||
"""
|
||||
Converts time from string-format to an integer number of minutes after 00:00
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import base64
|
||||
import dataclasses
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import io
|
||||
import typing
|
||||
import zlib
|
||||
|
|
@ -126,18 +126,20 @@ def img2base64(img_data) -> str:
|
|||
def plot(times, concentrations, model: models.ExposureModel):
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(1, 1, 1)
|
||||
ax.plot(times, concentrations, lw=2, color='#1f77b4', label='Concentration')
|
||||
datetimes = [datetime(1970, 1, 1) + timedelta(hours=time) for time in times]
|
||||
ax.plot(datetimes, concentrations, lw=2, color='#1f77b4', label='Concentration')
|
||||
ax.spines['right'].set_visible(False)
|
||||
ax.spines['top'].set_visible(False)
|
||||
|
||||
ax.set_xlabel('Time (hour of day)')
|
||||
ax.set_xlabel('Time of day')
|
||||
ax.set_ylabel('Concentration ($q/m^3$)')
|
||||
ax.set_title('Concentration of infectious quanta')
|
||||
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%H:%M"))
|
||||
|
||||
# Plot presence of exposed person
|
||||
for i, (presence_start, presence_finish) in enumerate(model.exposed.presence.boundaries()):
|
||||
plt.fill_between(
|
||||
times, concentrations, 0,
|
||||
datetimes, concentrations, 0,
|
||||
where=(np.array(times) > presence_start) & (np.array(times) < presence_finish),
|
||||
color="#1f77b4", alpha=0.1,
|
||||
label="Presence of exposed person(s)" if i == 0 else ""
|
||||
|
|
@ -240,19 +242,21 @@ def comparison_plot(scenarios: typing.Dict[str, models.ExposureModel]):
|
|||
if times is None:
|
||||
t_start, t_end = model_start_end(model)
|
||||
times = np.linspace(t_start, t_end, resolution)
|
||||
datetimes = [datetime(1970, 1, 1) + timedelta(hours=time) for time in times]
|
||||
concentrations = [model.concentration_model.concentration(time) for time in times]
|
||||
|
||||
if name in dash_styled_scenarios:
|
||||
ax.plot(times, concentrations, label=name, linestyle='--')
|
||||
ax.plot(datetimes, concentrations, label=name, linestyle='--')
|
||||
else:
|
||||
ax.plot(times, concentrations, label=name, linestyle='-', alpha=0.5)
|
||||
ax.plot(datetimes, concentrations, label=name, linestyle='-', alpha=0.5)
|
||||
|
||||
# Place a legend outside of the axes itself.
|
||||
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
|
||||
ax.spines['right'].set_visible(False)
|
||||
ax.spines['top'].set_visible(False)
|
||||
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%H:%M"))
|
||||
|
||||
ax.set_xlabel('Time (hour of day)')
|
||||
ax.set_xlabel('Time of day')
|
||||
ax.set_ylabel('Concentration ($q/m^3$)')
|
||||
ax.set_title('Concentration of infectious quanta')
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import dataclasses
|
|||
import pytest
|
||||
|
||||
from cara.apps.calculator import model_generator
|
||||
from cara.apps.calculator.model_generator import _hours2timestring
|
||||
from cara.apps.calculator.model_generator import minutes_since_midnight
|
||||
from cara import models
|
||||
from cara import data
|
||||
|
|
@ -272,13 +273,8 @@ def time2mins(time: str) -> minutes_since_midnight:
|
|||
return minutes_since_midnight(int(time.split(':')[0]) * 60 + int(time.split(':')[1]))
|
||||
|
||||
|
||||
def hours2time(hours: float):
|
||||
# Convert times like 14.5 to strings, like "14:30"
|
||||
return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}"
|
||||
|
||||
|
||||
def assert_boundaries(interval, boundaries_in_time_string_form):
|
||||
boundaries = [(hours2time(start), hours2time(end))
|
||||
boundaries = [(_hours2timestring(start), _hours2timestring(end))
|
||||
for start, end in interval.boundaries()]
|
||||
assert boundaries == boundaries_in_time_string_form
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue