added UI elements for CO2 calculations

This commit is contained in:
Luis Aleixo 2023-06-07 16:55:59 +02:00
parent 827327b70e
commit 8ff01f4137
4 changed files with 218 additions and 23 deletions

View file

@ -18,6 +18,7 @@ import traceback
import typing
import uuid
import zlib
import matplotlib.pyplot as plt
import jinja2
import loky
@ -372,7 +373,15 @@ class CO2Data(BaseRequestHandler):
co2_model_generator.CO2FormData.build_model, form,
)
report = await asyncio.wrap_future(report_task)
self.finish(dict(report.CO2_fit_params()))
def generate_image():
fig = plt.figure(figsize=(4, 4), dpi=110)
plt.plot(form.CO2_data['times'], form.CO2_data['CO2'])
return fig
result = dict(report.CO2_fit_params())
result['CO2_plot'] = img2base64(_figure2bytes(generate_image()))
self.finish(result)
def get_url(app_root: str, relative_path: str = '/'):

View file

@ -0,0 +1,154 @@
const CO2_data = [
'CO2_data',
'specific_breaks',
'exposed_coffee_break_option',
'exposed_coffee_duration',
'exposed_finish',
'exposed_lunch_finish',
'exposed_lunch_option',
'exposed_lunch_start',
'exposed_start',
'infected_coffee_break_option',
'infected_coffee_duration',
'infected_dont_have_breaks_with_exposed',
'infected_finish',
'infected_lunch_finish',
'infected_lunch_option',
'infected_lunch_start',
'infected_people',
'infected_start',
'room_volume',
'total_people',
'windows_duration',
'windows_frequency',
]
// Method to upload a valid excel file
function upload_file() {
var files = document.getElementById("file_upload").files;
if (files.length == 0) {
alert("Please choose any file...");
return;
}
var filename = files[0].name;
var extension = filename.substring(filename.lastIndexOf(".")).toUpperCase();
if (extension == ".XLS" || extension == ".XLSX") {
//Here calling another method to read excel file into json
excelFileToJSON(files[0]);
} else {
alert("Please select a valid excel file.");
}
}
//Method to read excel file and convert it into JSON
function excelFileToJSON(file) {
try {
var reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = function (e) {
var data = e.target.result;
var workbook = XLSX.read(data, { type: "binary" });
var result = {};
var firstSheetName = workbook.SheetNames[0];
//reading only first sheet data
var jsonData = XLSX.utils.sheet_to_json(workbook.Sheets[firstSheetName]);
//displaying the json result into HTML table
displayJsonToHtmlTable(jsonData);
};
} catch (e) {
console.error(e);
}
}
//Method to display the data in HTML Table
function displayJsonToHtmlTable(jsonData) {
var table = document.getElementById("display_excel_data");
var format = document.getElementById("formatted_data");
let structure = { times: [], CO2: [] };
if (jsonData.length > 0) {
var htmlData = "<tr><th>Time</th><th>CO2 Value</th></tr>";
for (var i = 0; i < jsonData.length; i++) {
var row = jsonData[i];
htmlData +=
"<tr><td>" +
Math.round(row["Times"] * 10) / 10 +
"</td><td>" +
Math.round(row["CO2"] * 10) / 10 +
"</td></tr>";
structure["times"].push(row["Times"]);
structure["CO2"].push(row["CO2"]);
}
table.innerHTML = htmlData;
console.log(structure);
format.value = JSON.stringify(structure);
} else {
table.innerHTML = "There is no data in Excel";
}
}
function insertErrorFor(referenceNode, text) {
var element = document.createElement("span");
element.setAttribute("class", "error_text");
element.classList.add("red_text");
element.innerHTML = "&nbsp;&nbsp;" + text;
$(referenceNode).before(element);
}
function validate() {
$('span.' + "error_text").remove();
let submit = true;
for (var i = 0; i < CO2_data.length; i++) {
let element = $(`[name=${CO2_data[i]}]`);
if (element[0].value === '') {
insertErrorFor($('#CO2_input_data_div'), `'${element[0].name}' must be defined.`); // raise error for total number and room volume.
submit = false;
};
}
return submit;
}
function submit_fitting_algorithm(url) {
if (validate()) {
let CO2_mapping = {};
CO2_data.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
else CO2_mapping[element[0].name] = element[0].value;
})
$('#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...`
);
$('#CO2_input_data').html(JSON.stringify(CO2_mapping, null, "\t"))
fetch(url, {
method: "POST",
body: JSON.stringify(CO2_mapping),
})
.then((response) => response.json())
.then((json_response) => {
console.log(json_response)
$("#DIV_CO2_fitting_result").show();
$("#CO2_fitting_result").val(JSON.stringify(json_response));
$("#exhalation_rate_fit").html(String(json_response['exhalation_rate']));
// $("#ventilation_rate_fit").html(json_response['ventilation_values']);
$("#CO2_data_plot").attr("src", json_response['CO2_plot']);
$("#generate_fitting_data").html('Fit data');
$("#save_and_dismiss_dialog").show();
});
}
}
function clear_fitting_algorithm() {
$("#display_excel_data tbody").remove();
$('#CO2_fitting_result').val('');
$('#formatted_data').val('');
$('span.' + "error_text").remove();
$('#DIV_CO2_fitting_result').hide();
$('#CO2_input_data_div').hide();
$('#CO2_data_no').click();
}
function dismiss_co2_dialog() {
$('#CO2_data_no').click();
}

View file

@ -12,6 +12,7 @@
{% block body_scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous"></script>
<script src="{{ get_calculator_url('/static/js') }}/form.js"></script>
<script src="{{ get_calculator_url('/static/js') }}/co2_form.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
{% endblock body_scripts %}
@ -191,23 +192,6 @@
<span class="tooltip_text">?</span>
</div>
<div class="split mt-3">
<div>Use CO₂ concentration values:</div>
<div>
<input class="ml-2" type="radio" id="CO2_data_no" name="CO2_data_option" value=0 checked="checked">
<label for="CO2_data_no">No</label>
<input class="ml-2" type="radio" id="CO2_data_yes" name="CO2_data_option" value=1 data-enables="#DIVCO2_data">
<label for="CO2_data_yes">Yes</label>
</div>
</div>
<div id="DIVCO2_data" class='form-group row' style="display:none">
<div class="col-sm-3"><label class="col-form-label col-form-label-sm">CO2 Data:</label><br></div>
<input type="text" name="CO2_data" class="form-control form-control-sm col-sm-6" placeholder='{"times": [...], "concentrations": [...]}' >
</div>
<hr width="80%">
<div id="ventilation_data">
<div class='sub_title'>Ventilation type:</div>
@ -676,11 +660,62 @@
</div>
<br style="clear:both;">
<i>Coffee breaks are spread evenly throughout the day.</i><br>
<i>Coffee breaks are spread evenly throughout the day.</i>
<br><br>
<div class="split">
<strong>Use CO₂ concentration values:</strong>
<div>
<input class="ml-2" type="radio" id="CO2_data_no" name="CO2_data_option" value=0 checked="checked">
<label for="CO2_data_no">No</label>
<input class="ml-2" type="radio" id="CO2_data_yes" name="CO2_data_option" value=1 data-target="#DIVCO2_data" data-toggle="modal">
<label for="CO2_data_yes">Yes</label>
</div>
</div>
<!-- CO2 Modal -->
<div class="modal fade" id="DIVCO2_data" tabindex="-1" role="dialog" aria-labelledby="CO2_values_title" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document" overflow: visible>
<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()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h5>Upload an excel file to display in HTML Table</h5><br>
<!-- Input element to upload an excel file -->
<input type="file" id="file_upload" />
<button type="button" class="btn btn-primary btn-sm" onclick="upload_file()">Upload</button>
<br>
<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>
<div id="CO2_input_data_div" style="display: none">
<p>The following data will be considered:</p><br>
<p id="CO2_input_data"></p>
</div>
<input type="text" class="form-control d-none" name="CO2_fitting_result" id="CO2_fitting_result">
<div id="DIV_CO2_fitting_result" style="display: none">
<img id="CO2_data_plot"/>
<div>Exhalation rate: <p id="exhalation_rate_fit"></p> </div>
{# <div>Air exchange: <p id="ventilation_rate_fit"></p></div> #}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary dismiss_btn_frm_field" data-dismiss="modal" onclick="clear_fitting_algorithm()">Clear all</button>
<button type="button" id="generate_fitting_data" class="btn btn-primary close_btn_frm_field" onclick="submit_fitting_algorithm('{{ get_calculator_url() }}/co2-fit')">Fit data</button>
<button type="button" style="display: none" id="save_and_dismiss_dialog" class="btn btn-primary close_btn_frm_field" data-dismiss="modal">Save and close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="center">

View file

@ -181,9 +181,6 @@
let short_range_expirations = {{ short_range_expirations | JSONify }};
draw_plot("concentration_plot");
</script>
<img src= "{{ CO2_plot }}" />
<p>Emission rate = {{ ex }}</p>
<p>Ventilation = {{ airs }}</p>
</p>
</div>
</div>