diff --git a/assets/custom-functions.js b/assets/custom-functions.js index a5b12214d7b8d1e6b25b88cfb56def40859e5cd4..e8ba802e136b3a53396d2b5fbee12a204165928e 100644 --- a/assets/custom-functions.js +++ b/assets/custom-functions.js @@ -189,19 +189,74 @@ $(document).ready(function () { }); }); -// // CREATE WAIT FUNCTION TO WAIT FOR ELEMENT TO BECOME AVAILABLE -// function waitForElement(selector, func, timeout = 1000) { -// //wait for element to be available to change its position -// const start = Date.now(); -// let interval = setInterval(() => { -// var el = document.getElementById(selector); -// if (el) { -// clearInterval(interval); -// return func(el); -// } else if (Date.now() - start > timeout) { -// clearInterval(interval); -// } -// }, 100); -// } -// +//================== Stats table carets =============================================== +// The aeronet stats table changes the position/index of the regions when they +// are clicked, so we cannot easily assign a class to the regions that will maintain on click, +// so we must remove the carets on click, and then add them back after the table has finished +// changing it's state +// ADD FUNCTION TO WAIT FOR TABLE TO FINISH CHANGING +function waitForMutation(selector) { + return new Promise(resolve => { + if (document.querySelector(selector)) { + return resolve(document.querySelector(selector)); + }; + const observer = new MutationObserver(mutations => { + if (document.querySelector(selector)) { + resolve(document.querySelector(selector)); + //Carets will populate in the wrong rows after click, so we must remove them + for (const element of mutations) { + if (['Mediterranean','NAfrica', 'MiddleEast'].includes(element.oldValue)) { + //GET ELEMENTS PARENT NODE 2 ABOVE AS IT CONTAINS THE TARGET CLASS + const target = element.target.parentNode.parentNode; + target.classList.remove('table_caret_up'); + target.classList.remove('table_caret_down'); + }; + } + // Now add the carets back in where appropriate + flipCarets(); + } + }); + observer.observe(document.body, { + childList: true, + subtree: true, + attributeOldValue: true, + characterDataOldValue: true + }); + }); +} +//CREATE FUNCTION TO FIND REGIONS AND FLIP CARETS AS NEEDED +function flipCarets() { + var areas = "td:contains('Europe'), td:contains('Mediterranean'),td:contains('NAfrica'),td:contains('MiddleEast')"; + $(areas).addClass('table_caret_down'); + //Each table has the four regions. Split the returned areas into tables, and then address caret flips + for(var i = 0; i < ($(areas).length/4); i++){ + var medIndex = parseInt($("td:contains('Mediterranean')").eq(i).attr('data-dash-row')); + var nafricaIndex = parseInt($("td:contains('NAfrica')").eq(i).attr('data-dash-row')); + var middleEastIndex = parseInt($("td:contains('MiddleEast')").eq(i).attr('data-dash-row')); + var totalIndex = parseInt($("td:contains('Total')").eq(i).attr('data-dash-row')); + //for each table, check if the caret should be flipped + //if the next region is not at the next index, the dropdown is open + //trigger the caret to be flipped + if (medIndex !== 1) { + $("td:contains('Europe')").eq(i).addClass('table_caret_up'); + }; + if ((medIndex + 1) !== middleEastIndex) { + $("td:contains('Mediterranean')").eq(i).addClass('table_caret_up'); + }; + if ((middleEastIndex + 1) !== nafricaIndex) { + $("td:contains('MiddleEast')").eq(i).addClass('table_caret_up'); + }; + if ((nafricaIndex + 1) !== totalIndex) { + $("td:contains('NAfrica')").eq(i).addClass('table_caret_up'); + }; + }; +}; + +//ADD FUNCTION TO WAIT FOR CLICKS ON AREAS THAT SHOULD TRIGGER CARET FLIPS +$(document).ready(function () { + $(document).on('click', "td:contains('Europe'), td:contains('Mediterranean'),td:contains('NAfrica'),td:contains('MiddleEast'), #scores-apply, #evaluation-tab", function () { + waitForMutation('td.dash-cell.column-0'); + }) +}) +//================== Stats table carets END =============================================== diff --git a/assets/sidebar.css b/assets/sidebar.css index baec1cacb2b19ed7669329e7b2e86fa0aa4ab129..1074f117234a2932724610b015904b42f6a24f6a 100644 --- a/assets/sidebar.css +++ b/assets/sidebar.css @@ -19,7 +19,7 @@ color: var(--blue) !important; background-color: #FAFAFA; overflow: hidden; - z-index: 10000; + z-index: 1049; } .sidebar-first-item { diff --git a/assets/style.css b/assets/style.css index 6be0e97a0a549687b992e73dc9226fef26427e19..7028384d65bd1961c18a72c04309f0f042b988ef 100644 --- a/assets/style.css +++ b/assets/style.css @@ -880,3 +880,30 @@ div.dropdown-menu.show { color: white; font-size: 1.1rem; } + +.table_caret_down { + display: flex; +} + +.table_caret_down:after { + font-family: 'Font Awesome 5 free'; + content: "\f107"; + font-weight: 900; + font-size: 1.3rem; +} + +.table_caret_up { + display: flex; +} + +.table_caret_up:after { + font-family: 'Font Awesome 5 free'; + content: "\f106"; + font-weight: 900; + font-size: 1.3rem; +} + +td.column-0 { + max-width: 100%; + min-width: 10%; +} diff --git a/tabs/evaluation_callbacks.py b/tabs/evaluation_callbacks.py index be28c1023ec374b88b05d6518a0cf2544feb6a68..80cc4705617a646d1d53a0ba00054382e7fc0e6a 100644 --- a/tabs/evaluation_callbacks.py +++ b/tabs/evaluation_callbacks.py @@ -238,6 +238,22 @@ def scores_maps_retrieve(n_clicks, model, score, network, selection, orig_model, return dash.no_update, False, dash.no_update, dash.no_update # PreventUpdate +def format_floats(df): + """This function takes a dataframe and changes all columns except for 'station' + so that floats will be formatted to 2 digits after the decimal place""" + for col in df.columns: + # check if the column is not 'station' + if col != 'station': + # convert the column to a string to allow for string formatting + df[col] = df[col].astype(str) + # iterate over the values in the column + for i, val in enumerate(df[col]): + # check if the value is a float + if '.' in val: + # if so, format it to have 2 decimal places + df.at[i, col] = '{:.2f}'.format(float(val)) + return df + @dash.callback( extend_l([ @@ -331,6 +347,9 @@ def aeronet_scores_tables_retrieve(n, *args): # *activel_cells, models, stat, n df = pd.read_hdf(filepath, tab_name) # replace "tables" columns + # import pudb; pudb.set_trace() + df = format_floats(df) + ret_tables[ret_idx] = [{'name': i in MODELS and [STATS[SCORES[table_idx]], MODELS[i]['name']] or [STATS[SCORES[table_idx]], ''], 'id': i} for