form modifications - table format

This commit is contained in:
Luis Aleixo 2023-06-29 16:24:00 +01:00
parent 6c86238743
commit be732da4ea
7 changed files with 66 additions and 39 deletions

View file

@ -354,7 +354,6 @@ class CO2Data(BaseRequestHandler):
async def post(self) -> None:
requested_model_config = tornado.escape.json_decode(self.request.body)
try:
form = co2_model_generator.CO2FormData.from_dict(requested_model_config)
except Exception as err:
@ -375,7 +374,7 @@ class CO2Data(BaseRequestHandler):
)
report = await asyncio.wrap_future(report_task)
def generate_image(transition_times: tuple, ventilation_values: tuple):
def generate_ventilation_plot(transition_times: tuple, ventilation_values: tuple):
fig = plt.figure(figsize=(7, 4), dpi=110)
plt.plot(form.CO2_data['times'], form.CO2_data['CO2'])
for index, time in enumerate(transition_times[:-1]):
@ -387,7 +386,8 @@ class CO2Data(BaseRequestHandler):
return fig
result = dict(report.CO2_fit_params())
result['CO2_plot'] = img2base64(_figure2bytes(generate_image(report.ventilation_transition_times, result['ventilation_values'])))
result['transition_times'] = report.ventilation_transition_times
result['CO2_plot'] = img2base64(_figure2bytes(generate_ventilation_plot(report.ventilation_transition_times, result['ventilation_values'])))
self.finish(result)

View file

@ -46,7 +46,7 @@ class CO2FormData:
#: and the defaults in the html form must not be contradictory.
_DEFAULTS: typing.ClassVar[typing.Dict[str, typing.Any]] = {
'CO2_data': '{}',
'specific_breaks': '{}', # CHECK INTEGRATION WITH WHO
'specific_breaks': '{}',
'exposed_coffee_break_option': 'coffee_break_0',
'exposed_coffee_duration': 5,
'exposed_finish': '17:30',
@ -89,8 +89,8 @@ class CO2FormData:
form_data[key] = default_value
for key, value in form_data.items():
if key in model_generator._CAST_RULES_FORM_ARG_TO_NATIVE:
form_data[key] = model_generator._CAST_RULES_FORM_ARG_TO_NATIVE[key](value)
if key in _CAST_RULES_FORM_ARG_TO_NATIVE:
form_data[key] = _CAST_RULES_FORM_ARG_TO_NATIVE[key](value)
if key not in cls._DEFAULTS:
raise ValueError(f'Invalid argument "{html.escape(key)}" given')
@ -318,6 +318,33 @@ class CO2FormData:
if self.ventilation_type == 'from_fitting' and self.window_opening_regime == 'windows_open_periodically':
transition_times = sorted(models.PeriodicInterval(self.windows_frequency,
self.windows_duration, min(self.infected_start, self.exposed_start)/60).transition_times())
return tuple(filter(lambda x: x < last_present_time, transition_times))
return tuple(filter(lambda x: x <= last_present_time, transition_times))
else:
return tuple((min(self.infected_start, self.exposed_start)/60, max(self.infected_finish, self.exposed_finish)/60), ) # all day long
#: Mapping of field name to a callable which can convert values from form
#: input (URL encoded arguments / string) into the correct type.
_CAST_RULES_FORM_ARG_TO_NATIVE: typing.Dict[str, typing.Callable] = {}
#: Mapping of field name to callable which can convert native type to values
#: that can be encoded to URL arguments.
_CAST_RULES_NATIVE_TO_FORM_ARG: typing.Dict[str, typing.Callable] = {}
for _field in dataclasses.fields(CO2FormData):
if _field.type is minutes_since_midnight:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = model_generator.time_string_to_minutes
_CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = model_generator.time_minutes_to_string
elif _field.type is int:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = model_generator._safe_int_cast
elif _field.type is float:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = float
elif _field.type is bool:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = lambda v: v == '1'
_CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = int
elif _field.type is list:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = model_generator.string_to_list
_CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = model_generator.list_to_string
elif _field.type is dict:
_CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = model_generator.string_to_dict
_CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = model_generator.dict_to_string

View file

@ -22,7 +22,6 @@ DEFAULTS = {
'ceiling_height': 0.,
'conditional_probability_plot': False,
'conditional_probability_viral_loads': False,
'CO2_data': '{}',
'CO2_data_option': False,
'CO2_fitting_result': '{}',
'exposed_coffee_break_option': 'coffee_break_0',

View file

@ -37,7 +37,6 @@ class FormData:
ceiling_height: float
conditional_probability_plot: bool
conditional_probability_viral_loads: bool
CO2_data: dict
CO2_data_option: bool
CO2_fitting_result: dict
exposed_coffee_break_option: str

View file

@ -1,5 +1,5 @@
// JS file to handle manipulation on CO2 Fitting Algorithm Dialog.
const CO2_data = [
const CO2_data_form = [
'CO2_data',
'specific_breaks',
'exposed_coffee_break_option',
@ -74,11 +74,11 @@ function displayJsonToHtmlTable(jsonData) {
var row = jsonData[i];
if (i < 5) {
htmlData +=
"<tr><td>" +
row["Times"].toFixed(2) +
"</td><td>" +
row["CO2"].toFixed(2) +
"</td></tr>";
`<tr><td>
${row["Times"].toFixed(2)}
</td><td>
${row["CO2"].toFixed(2)}
</td></tr>`;
}
structure["times"].push(row["Times"]);
structure["CO2"].push(row["CO2"]);
@ -115,8 +115,8 @@ function insertErrorFor(referenceNode, text) {
function validate() {
$('span.' + "error_text").remove();
let submit = true;
for (var i = 0; i < CO2_data.length; i++) {
let element = $(`[name=${CO2_data[i]}]`)[0];
for (var i = 0; i < CO2_data_form.length; i++) {
let element = $(`[name=${CO2_data_form[i]}]`)[0];
if (element.value === '') {
insertErrorFor($('#CO2_input_data_div'), `'${element.name}' must be defined.`); // raise error for total number and room volume.
submit = false;
@ -128,10 +128,17 @@ function validate() {
function display_fitting_data(json_response) {
$("#DIV_CO2_fitting_result").show();
$("#CO2_data_plot").attr("src", json_response['CO2_plot']);
delete json_response['CO2_plot'];
// Not needed for the form submit
delete json_response['CO2_plot'];
$("#CO2_fitting_result").val(JSON.stringify(json_response));
$("#exhalation_rate_fit").html('Exhalation rate: ' + String(json_response['exhalation_rate'].toFixed(2)) + ' m³/h');
// $("#ventilation_rate_fit").html(json_response['ventilation_values']);
let ventilation_table = "<tr><th>Time</th><th>Ventilation value (ACH)</th></tr>";
json_response['ventilation_values'].map((val, index) => {
console.log(json_response['transition_times'])
let transition_times = `${(json_response['transition_times'][index]).toFixed(2)} - ${(json_response['transition_times'][index + 1]).toFixed(2)}`
ventilation_table += `<tr><td>${transition_times}</td><td>${val}</td></tr>`;
});
$("#ventilation_rate_fit").html(ventilation_table);
$("#generate_fitting_data").html('Fit data');
$("#save_and_dismiss_dialog").show();
}
@ -139,7 +146,7 @@ function display_fitting_data(json_response) {
function submit_fitting_algorithm(url) {
if (validate()) {
let CO2_mapping = {};
CO2_data.map(el => {
CO2_data_form.map(el => {
let element = $(`[name=${el}]`);
// Validate radio buttons
if (element.length != 1) CO2_mapping[element[0].name] = $(`[name=${element[0].name}]:checked`)[0].value
@ -147,7 +154,7 @@ function submit_fitting_algorithm(url) {
})
$('#CO2_input_data_div').show();
$("#generate_fitting_data").html(
`<span id="loading_spinner" class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true"></span>Loading...`
`<span id="loading_spinner" class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true" disabled ></span>Loading...`
);
$('#CO2_input_data').html(JSON.stringify(CO2_mapping, null, "\t"))
fetch(url, {
@ -172,7 +179,3 @@ function clear_fitting_algorithm() {
$('#CO2_data_no').click();
ventilation_from_fitting(false);
}
function dismiss_co2_dialog() {
$('#CO2_data_no').click();
}

View file

@ -505,7 +505,12 @@ function ventilation_from_fitting(condition_from_fitting) {
else {
// Select the URL ventilation option, if any (from back-navigation)
var url = new URL(decodeURIComponent(window.location.href));
let ventilation_from_url = url.searchParams.has('ventilation_type') ? url.searchParams.get('ventilation_type') : "no_ventilation";
let ventilation_from_url;
if (url.searchParams.has('ventilation_type')) {
ventilation_from_url = url.searchParams.get('ventilation_type');
if (ventilation_from_url == 'from_fitting') ventilation_from_url = 'no_ventilation';
}
else ventilation_from_url = 'no_ventilation';
$(`input[type=radio][id=${ventilation_from_url}]`).prop('checked',true);
$('#DIVopening_distance').after($('#window_opening_regime'));
}
@ -968,16 +973,8 @@ $(document).ready(function () {
// Handle default URL values if they are not explicitly defined.
// Populate CO2 Fitting Algorithm Dialog
let CO2_data = url.searchParams.has('CO2_data') ? url.searchParams.get('CO2_data') : null;
if (CO2_data) {
let CO2_inputs = JSON.parse(CO2_data);
let input_for_table = [];
for (let i = 0; i < CO2_inputs['times'].length; i++) {
input_for_table.push({'Times': CO2_inputs['times'][i], 'CO2': CO2_inputs['CO2'][i]});
};
displayJsonToHtmlTable(input_for_table);
submit_fitting_algorithm(`${$('#url_prefix').data().calculator_prefix}/co2-fit`);
}
let CO2_data = url.searchParams.has('CO2_fitting_result') ? url.searchParams.get('CO2_fitting_result') : null;
if (CO2_data) display_fitting_data(JSON.parse(CO2_data));
// Populate primary vaccine dropdown
$("#vaccine_type option").remove();

View file

@ -702,7 +702,7 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="CO2_values_title">CO₂ Fitting Algorithm</h5>
<button type="button" class="close close_btn_frm_field" data-dismiss="modal" onclick="dismiss_co2_dialog()">
<button type="button" class="close close_btn_frm_field" data-dismiss="modal" onclick="clear_fitting_algorithm()">
<span aria-hidden="true">&times;</span>
</button>
</div>
@ -719,7 +719,7 @@
<br>
<!-- table to display the excel data -->
<table id="display_excel_data" border="1" style="width: 70%; margin-left: auto; margin-right: auto"></table>
<input id="formatted_data" type="text" name="CO2_data" class="form-control form-control-sm d-none" placeholder='{"times": [...], "concentrations": [...]}' ><br>
<input id="formatted_data" type="text" name="CO2_data" form="not-submitted" class="form-control d-none" placeholder='{"times": [...], "concentrations": [...]}' ><br>
<div id="CO2_input_data_div" style="display: none">
{# <p>The following data will be considered:</p><br>
<p id="CO2_input_data"></p> #}
@ -729,7 +729,9 @@
<h5 style="margin-top: auto; margin-bottom: auto">Fitting result</h5>
<img id="CO2_data_plot" style="margin-top: 2%"/>
<p id="exhalation_rate_fit"></p>
<p id="ventilation_rate_fit">Ventilation values in the plot (ACH)</p>
<p>Ventilation values (ACH):</p><br>
<!-- table to display the ventilation result data -->
<table id="ventilation_rate_fit" border="1" style="width: 70%; margin-left: auto; margin-right: auto"></table>
</div>
</div>
<div class="modal-footer">