11from typing import Dict , Optional
22
3- from altair import Chart
3+ from altair import Chart , Scale
44import pandas as pd
55import i18n
66import numpy as np
99
1010
1111def build_admits_chart (
12- * , alt , admits_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None
12+ * , alt , admits_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None , use_log_scale : bool = False
1313) -> Chart :
14- """Build admits chart."""
15- y_scale = alt .Scale ()
16- if max_y_axis is not None :
17- y_scale .domain = (0 , max_y_axis )
14+ """
15+ This builds the "New Admissions" chart, projecting daily admissions over time.
16+
17+ Args:
18+ alt: Reference to Altair package.
19+ admits_floor_df: Pandas data frame containing three columns: "admits_hospitalized", "admits_icu", and
20+ "admits_ventilated".
21+ max_y_axis: Optional maximum value for the Y axis of the chart.
22+ use_log_scale: Set to true to use a logarithmic scale on the Y axis. Default is linear scale.
23+
24+ Returns: The newly created chart.
25+
26+ """
27+
28+ adjusted_admits_floor_df = __adjust_data_for_log_scale (admits_floor_df ) if use_log_scale else admits_floor_df
29+ y_scale = __build_y_scale (alt , max_y_axis , use_log_scale )
1830
1931 x = dict (shorthand = "date:T" , title = i18n .t ("charts-date" ), axis = alt .Axis (format = (DATE_FORMAT )))
2032 y = dict (shorthand = "value:Q" , title = i18n .t ("charts-daily-admissions" ), scale = y_scale )
@@ -40,7 +52,7 @@ def build_admits_chart(
4052 .transform_filter (alt .datum .day == 0 )
4153 .mark_rule (color = "black" , opacity = 0.35 , size = 2 )
4254 )
43- admits_floor_df_renamed = admits_floor_df .rename ({
55+ admits_floor_df_renamed = adjusted_admits_floor_df .rename ({
4456 "admits_hospitalized" : i18n .t ("admits_hospitalized" ),
4557 "admits_icu" : i18n .t ("admits_icu" ),
4658 "admits_ventilated" : i18n .t ("admits_ventilated" )
@@ -53,12 +65,24 @@ def build_admits_chart(
5365
5466
5567def build_census_chart (
56- * , alt , census_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None
68+ * , alt , census_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None , use_log_scale : bool = False
5769) -> Chart :
58- """Build census chart."""
59- y_scale = alt .Scale ()
60- if max_y_axis :
61- y_scale .domain = (0 , max_y_axis )
70+ """
71+ This builds the "Admitted Patients" census chart, projecting total number of patients in the hospital over time.
72+
73+ Args:
74+ alt: Reference to Altair package.
75+ census_floor_df: Pandas data frame containing three columns: "census_hospitalized", "census_icu", and
76+ "census_ventilated".
77+ max_y_axis: Optional maximum value for the Y axis of the chart.
78+ use_log_scale: Set to true to use a logarithmic scale on the Y axis. Default is linear scale.
79+
80+ Returns: The newly created chart.
81+
82+ """
83+
84+ adjusted_census_floor_df = __adjust_data_for_log_scale (census_floor_df ) if use_log_scale else census_floor_df
85+ y_scale = __build_y_scale (alt , max_y_axis , use_log_scale )
6286
6387 x = dict (shorthand = "date:T" , title = i18n .t ("charts-date" ), axis = alt .Axis (format = (DATE_FORMAT )))
6488 y = dict (shorthand = "value:Q" , title = i18n .t ("charts-census" ), scale = y_scale )
@@ -84,7 +108,7 @@ def build_census_chart(
84108 .transform_filter (alt .datum .day == 0 )
85109 .mark_rule (color = "black" , opacity = 0.35 , size = 2 )
86110 )
87- census_floor_df_renamed = census_floor_df .rename ({
111+ census_floor_df_renamed = adjusted_census_floor_df .rename ({
88112 "census_hospitalized" : i18n .t ("census_hospitalized" ),
89113 "census_icu" : i18n .t ("census_icu" ),
90114 "census_ventilated" : i18n .t ("census_ventilated" )
@@ -97,12 +121,24 @@ def build_census_chart(
97121
98122
99123def build_sim_sir_w_date_chart (
100- * , alt , sim_sir_w_date_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None
124+ * , alt , sim_sir_w_date_floor_df : pd .DataFrame , max_y_axis : Optional [int ] = None , use_log_scale : bool = False
101125) -> Chart :
102- """Build sim sir w date chart."""
103- y_scale = alt .Scale ()
104- if max_y_axis is not None :
105- y_scale .domain = (0 , max_y_axis )
126+ """
127+ This builds the "Susceptible, Infected, and Recovered" chart, projecting the number of those individuals in the
128+ hospital's region over time.
129+
130+ Args:
131+ alt: Reference to the Altair package.
132+ sim_sir_w_date_floor_df: A Pandas data frame with columns named "susceptible", "infected", and "recovered".
133+ max_y_axis: Optional maximum value for the Y axis of the chart.
134+ use_log_scale: Set to true to use a logarithmic scale on the Y axis. Default is linear scale.
135+
136+ Returns: The newly created chart.
137+
138+ """
139+
140+ adjusted_sim_sir_w_date_floor_df = __adjust_data_for_log_scale (sim_sir_w_date_floor_df ) if use_log_scale else sim_sir_w_date_floor_df
141+ y_scale = __build_y_scale (alt , max_y_axis , use_log_scale )
106142
107143 x = dict (shorthand = "date:T" , title = i18n .t ("charts-date" ), axis = alt .Axis (format = (DATE_FORMAT )))
108144 y = dict (shorthand = "value:Q" , title = i18n .t ("charts-count" ), scale = y_scale )
@@ -128,7 +164,7 @@ def build_sim_sir_w_date_chart(
128164 .transform_filter (alt .datum .day == 0 )
129165 .mark_rule (color = "black" , opacity = 0.35 , size = 2 )
130166 )
131- sim_sir_w_date_floor_df_renamed = sim_sir_w_date_floor_df .rename ({
167+ sim_sir_w_date_floor_df_renamed = adjusted_sim_sir_w_date_floor_df .rename ({
132168 "susceptible" : i18n .t ("susceptible" ),
133169 "infected" : i18n .t ("infected" ),
134170 "recovered" : i18n .t ("recovered" )
@@ -146,3 +182,37 @@ def build_table(
146182 table_df .date = table_df .date .dt .strftime (DATE_FORMAT )
147183 table_df_renamed = table_df .rename (labels , axis = 1 )
148184 return table_df_renamed
185+
186+
187+ def __adjust_data_for_log_scale (dataframe : pd .DataFrame ) -> pd .DataFrame :
188+ """
189+ This will clean and adjust some of the data so that Altair can plot it using a logarithmic scale. Altair does not
190+ allow zero values on the Y axis when plotting with a logarithmic scale, as log(0) is undefined.
191+
192+ Args:
193+ dataframe: The data to plot on the chart.
194+
195+ Returns: A new data frame with the appropriate adjustments for plotting on a log scale.
196+
197+ """
198+ return dataframe .replace (0 , float ('nan' )) # We use NaN so that the values will not appear at all on the chart.
199+
200+
201+ def __build_y_scale (alt , max_y_axis : Optional [int ] = None , use_log_scale : bool = False ) -> Scale :
202+ """
203+ Creates the Y axis of the chart, taking into account some of the configuration parameters set by the user.
204+
205+ Args:
206+ alt: Reference to Altair package.
207+ max_y_axis: The maximum value of the Y axis. This is optional.
208+ use_log_scale: Whether to use a logarithmic scale instead of a linear scale.
209+
210+ Returns: A newly created Scale instance.
211+
212+ """
213+ scale_type = 'log' if use_log_scale else 'linear'
214+ y_scale = alt .Scale (type = scale_type )
215+ if max_y_axis is not None :
216+ y_scale .domain = (0 , max_y_axis )
217+
218+ return y_scale
0 commit comments