added UI elements for CO2 calculations
This commit is contained in:
parent
827327b70e
commit
8ff01f4137
4 changed files with 218 additions and 23 deletions
|
|
@ -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 = '/'):
|
||||
|
|
|
|||
154
caimira/apps/calculator/static/js/co2_form.js
Normal file
154
caimira/apps/calculator/static/js/co2_form.js
Normal 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 = " " + 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();
|
||||
}
|
||||
|
|
@ -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">×</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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue