From 3717ffd872810733860881d266e557f94919e603 Mon Sep 17 00:00:00 2001 From: Elliott Rose Date: Mon, 20 Mar 2023 15:25:18 +0100 Subject: [PATCH 1/5] Add syncronization for zoom and pan for all maps in mosaic. Update colors for rc-slider-text on timeseries sliders.' --- assets/style.css | 6 +++++- tabs/forecast_callbacks.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/assets/style.css b/assets/style.css index 6dddcfc..efb192b 100644 --- a/assets/style.css +++ b/assets/style.css @@ -865,7 +865,11 @@ div.dropdown-menu.show { } .rc-slider-mark-text-active { - color:var(--yellow); + color: #999 !important; +} + +.rc-slider-mark-text { + color: var(--yellow); } .rc-slider-handle{ diff --git a/tabs/forecast_callbacks.py b/tabs/forecast_callbacks.py index 41212e1..30b7eda 100644 --- a/tabs/forecast_callbacks.py +++ b/tabs/forecast_callbacks.py @@ -939,6 +939,22 @@ def zoom_country(n_clicks, model, zoom, lat, lon): center = [[float(lat), float(lon)]] return zoom*count, center*count +@dash.callback( + Output('country-focus', 'n_clicks'), + Output('country-zoom', 'value'), + Output('country-lat', 'value'), + Output('country-lon', 'value'), + Input({'tag': 'model-map', 'index': ALL, "n_clicks": ALL}, 'viewport'), + Input({'tag': 'model-map', 'index': ALL, "n_clicks": ALL}, 'id'), + prevent_initial_call=True + ) +def zooms(viewport, models): + """Syncronize all maps to have same center and zoom in mosaic""" + ctx = dash.callback_context + changed = dict(ctx.triggered_id) + index = models.index(changed) + return 1, viewport[index]['zoom'], viewport[index]['center'][0], viewport[index]['center'][1] + # start/stop animation @dash.callback( -- GitLab From cce8e65b184431b15950624f4132a0c5133c9dac Mon Sep 17 00:00:00 2001 From: Elliott Rose Date: Mon, 20 Mar 2023 16:41:52 +0100 Subject: [PATCH 2/5] Update script to check if logos is set to true, so that we can add logos when we want --- conf/coords.json | 12 ++++++++---- js/create_model_loop_zoom_fit.js | 23 ++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/conf/coords.json b/conf/coords.json index 20b98df..82910f3 100644 --- a/conf/coords.json +++ b/conf/coords.json @@ -6,7 +6,8 @@ "width": "1280", "height": "768", "paddingRight": "5px", - "marginTop": "0px" + "marginTop": "0px", + "logos": true }, "spain":{ "zoom":"5", @@ -15,7 +16,8 @@ "width": "1280", "height": "768", "paddingRight": "5px", - "marginTop": "0px" + "marginTop": "0px", + "logos": true }, "fit":{ "zoom":"4", @@ -24,7 +26,8 @@ "width": "1250", "height": "1100", "paddingRight": "5px", - "marginTop": "0px" + "marginTop": "0px", + "logos": true }, "monarch_fit":{ "zoom":"3", @@ -33,7 +36,8 @@ "width": "1180", "height": "720", "paddingRight": "35px", - "marginTop": "20px" + "marginTop": "20px", + "logos": true } } diff --git a/js/create_model_loop_zoom_fit.js b/js/create_model_loop_zoom_fit.js index 3af6a66..77d3b4c 100644 --- a/js/create_model_loop_zoom_fit.js +++ b/js/create_model_loop_zoom_fit.js @@ -7,8 +7,8 @@ const { Cluster } = require('puppeteer-cluster'); const util = require('util'); const path = require('path'); -const url = 'http://127.0.0.1:9000/dashboard/' -// const url = 'http://0.0.0.0:7778/dashboard/' +// const url = 'http://127.0.0.1:9000/dashboard/' +const url = 'http://0.0.0.0:7778/dashboard/' const modelDict = {'od550_dust':'AOD', 'sconc_dust':'Concentration', 'dust_depd':'Dry deposition', @@ -54,7 +54,7 @@ const RunCluster = async (anim, curmodel, seldate, variable, fit) => { waitUntil: 'networkidle0', }); await page.waitForSelector("#graph-collection"); - await page.waitForSelector(".graph-with-slider"); + // await page.waitForSelector(".graph-with-slider"); // select variable try { const sel = await page.$('#variable-dropdown-forecast'); @@ -188,15 +188,16 @@ const RunCluster = async (anim, curmodel, seldate, variable, fit) => { } }, '.leaflet-bar'); - //reveal logos - process.stdout.write("REVEALING LOGOS" + "\n"); - - //style logos - let logos = await page.$('#logos'); - await logos.evaluate((el) => el.style.display = 'inline'); - await logos.evaluate((el, margin) => {el.style.marginTop = margin}, coords[fit].marginTop); - await logos.evaluate((el, padding) => {el.style.paddingRight = padding}, coords[fit].paddingRight); + if (coords[fit].logos == true){ + //reveal logos + process.stdout.write("REVEALING LOGOS" + "\n"); + //style logos + let logos = await page.$('#logos'); + await logos.evaluate((el) => el.style.display = 'inline'); + await logos.evaluate((el, margin) => {el.style.marginTop = margin}, coords[fit].marginTop); + await logos.evaluate((el, padding) => {el.style.paddingRight = padding}, coords[fit].paddingRight); + }; // Handle output and take screenshot const outputFile = './tmp/' + variable.toLowerCase() + '/' + fit + '/' + seldate + '_' + curmodel + '_' + fit + '_' + num + '.png'; process.stdout.write("TAKE SCREENSHOT => " + outputFile + "\n"); -- GitLab From f69d106a134791f48247ea808adafdd4e07e429d Mon Sep 17 00:00:00 2001 From: Elliott Rose Date: Tue, 21 Mar 2023 15:28:51 +0100 Subject: [PATCH 3/5] Alphabetize the stations in the eval/stats aeronet tables. --- assets/custom-functions.js | 292 ++++++++++++++++++++--------------- tabs/evaluation_callbacks.py | 31 +++- 2 files changed, 199 insertions(+), 124 deletions(-) diff --git a/assets/custom-functions.js b/assets/custom-functions.js index 5d5ac6b..6ec8d0b 100644 --- a/assets/custom-functions.js +++ b/assets/custom-functions.js @@ -2,25 +2,25 @@ window.forecastTab = Object.assign({}, window.forecastTab, { forecastMaps: { styleHandle: function(feature, context){ // get props from hideout - const {bounds, colorscale, style, colorProp} = context.props.hideout; + const {bounds, colorscale, style, colorProp} = context.props.hideout; // get value the determines the color const value = feature.properties[colorProp]; - for (let i = 0; i < bounds.length; ++i) { - if (value > bounds[i]) { - // set the fill color according to the class - style.fillColor = colorscale[i]; - } - } + for (let i = 0; i < bounds.length; ++i) { + if (value > bounds[i]) { + // set the fill color according to the class + style.fillColor = colorscale[i]; + } + } return style; }, - pointToLayer: function(feature, latlng, context){ + pointToLayer: function(feature, latlng, context){ const {min, max, colorscale, circleOptions, colorProp} = context.props.hideout; // set color based on color prop. circleOptions.fillColor = feature.properties[colorProp]; // sender a simple circle marker. return L.circleMarker(latlng, circleOptions); }, - bindTooltip: function(feature, layer, context) { + bindTooltip: function(feature, layer, context) { const props = feature.properties; // delete props.cluster; layer.bindTooltip(JSON.stringify(props.value), { opacity: 1.0 }) @@ -29,10 +29,10 @@ window.forecastTab = Object.assign({}, window.forecastTab, { wasMaps: { styleHandle: function(feature, context){ // get props from hideout - const {bounds, colorscale, style, colorProp} = context.props.hideout; + const {bounds, colorscale, style, colorProp} = context.props.hideout; // get value the determines the color const value = feature.properties[colorProp]; - style.fillColor = colorscale[value]; + style.fillColor = colorscale[value]; return style; }, } @@ -40,7 +40,7 @@ window.forecastTab = Object.assign({}, window.forecastTab, { window.evaluationTab = Object.assign({}, window.evaluationTab, { evaluationMaps: { - pointToLayer: function(feature, latlng, context){ + pointToLayer: function(feature, latlng, context){ const {circleOptions} = context.props.hideout; // sender a simple circle marker. return L.circleMarker(latlng, circleOptions); @@ -50,7 +50,7 @@ window.evaluationTab = Object.assign({}, window.evaluationTab, { window.observationsTab = Object.assign({}, window.observationsTab, { observationsMaps: { - pointToLayer: function(feature, latlng, context){ + pointToLayer: function(feature, latlng, context){ const {colorscale, circleOptions, colorProp} = context.props.hideout; const value = feature.properties[colorProp]; circleOptions.fillColor = colorscale[value]; @@ -62,73 +62,62 @@ window.observationsTab = Object.assign({}, window.observationsTab, { $(document).ready(function () { $(document).on('click', ".leaflet-popup-close-button", function () { - elements = document.getElementsByClassName("leaflet-popup-close-button"); - - for (let i = 0; i < elements.length; i++) { - var elem = elements[i]; - // elem.replaceWith(elem.clone()); - alert(elem.innerHTML); - } + elements = document.getElementsByClassName("leaflet-popup-close-button"); + + for (let i = 0; i < elements.length; i++) { + var elem = elements[i]; + // elem.replaceWith(elem.clone()); + alert(elem.innerHTML); + } - alert('Closing!'); + alert('Closing!'); elements[0].close(); }); }); -// Remove yellow from rc-slider-mark-text when moved -$(document).ready(function () { - $(document).on('click','.rc-slider' , function () { - const handle = document.getElementsByClassName('rc-slider-handle')[0]; - const text = document.getElementsByClassName('rc-slider-mark-text')[0]; - if (handle.style.left == '100%') { - text.style.color = '#999'; - } else { - text.style.color = '#F1B545'; - } - }) -}); - +// // Remove yellow from rc-slider-mark-text when moved +// $(document).ready(function () { +// $(document).on('click','.rc-slider' , function () { +// const handle = document.getElementsByClassName('rc-slider-handle')[0]; +// const text = document.getElementsByClassName('rc-slider-mark-text')[0]; +// if (handle.style.left == '100%'){ +// text.style.color = '#999'; +// }else{ +// text.style.color = '#F1B545'; +// } +// }) +// }) +// +// // Add logos for the animated gifs $(document).ready(function () { - $(document).on('click', "#slider-graph", function () { - const logos = document.getElementById('logos'); - if(!logos) { - var img = new Image(); - img.src = './assets/images/logoline.png'; - img.style.position = 'absolute'; - img.style.width = '40rem'; - img.style.height = '5rem'; - img.style.top = '0'; - img.style.left = '23rem'; - img.style.zIndex = '999'; - img.setAttribute('id','logos'); - img.style.display = 'none'; + $(document).on('click', "#slider-graph", function () { + const logos = document.getElementById('logos'); + if(!logos) { + var img = new Image(); + img.src = './assets/images/logoline.png'; + img.style.position = 'absolute'; + img.style.width = '40rem'; + img.style.height = '5rem'; + img.style.top = '0'; + img.style.left = '23rem'; + img.style.zIndex = '999'; + img.setAttribute('id','logos'); + img.style.display = 'none'; - // Get the element to overlay the image on - var div = document.querySelectorAll('.leaflet-map-pane')[0]; + // Get the element to overlay the image on + var div = document.querySelectorAll('.leaflet-map-pane')[0]; - // Append the image to the element - div.appendChild(img); - } - }); + // Append the image to the element + div.appendChild(img); + } + }); }); -// MAKE FULLSCREEN ICON SMALLER WHEN APP IS FULLSCREEN -function changeFullscreenIcon() { - const isFullscreen = window.innerWidth === screen.width && window.innerHeight === screen.height; - const button = document.getElementById('fullscreen-tab'); - if (isFullscreen) { - button.classList.remove('small'); - } else { - button.classList.add('small'); - } -} - // SEND FULLSCREEN REQUEST TO PARENT WINDOW $(document).ready(function () { $(document).on('click', "#fullscreen-tab", function () { parent.postMessage('fullscreen', '*'); - changeFullscreenIcon(); }) }); @@ -136,25 +125,29 @@ $(document).ready(function () { $(window).on('load', function removeFullscreen () { const tab = document.getElementById('fullscreen-tab'); if (tab != null) { - if (window.self === window.top){ - tab.style.visibility = "hidden"; - } + if (window.self === window.top){ + tab.style.visibility = "hidden"; + } } else { - setTimeout(removeFullscreen, 5); + setTimeout(removeFullscreen, 5); } }); // Move datepicker above the time series area $(document).ready(function () { - $(document).on('click', ".SingleDatePickerInput_clearDate, .SingleDatePicker", function moveDatePicker () { - const element = document.getElementsByClassName('DayPicker')[0]; - if (element != null) { - element.style.position = 'absolute'; - element.style.bottom = '78px'; - } else { - setTimeout(moveDatePicker, 20); - }; - }); + $(document).on('click', ".SingleDatePickerInput_clearDate, .SingleDatePicker", function moveDatePicker () { + const element = document.getElementsByClassName('DayPicker')[0]; + //we still want the menu to go below on eval/vis for modis + const evalVis = document.getElementById('eval-date'); + if (evalVis != null) { + return + }else if (element != null) { + element.style.position = 'absolute'; + element.style.bottom = '78px'; + }else { + setTimeout(moveDatePicker, 20); + }; + }); }); // COLLAPSE NAVBAR HAMBURGER RESIZE LARGER @@ -164,49 +157,52 @@ $(window).on('resize', function () { $(document).ready(function () { $(document).on('click', ".SingleDatePickerInput_clearDate", function() { - var date = document.getElementById('date'); - //ADD SPACES AT APPROPRIATE AREAS FOR DATE SELECTOR - date.addEventListener('input', function(e) { - this.type = 'text'; - var input = this.value; + var date = document.getElementById('date'); + //ADD SPACES AT APPROPRIATE AREAS FOR DATE SELECTOR + date.addEventListener('input', function(e) { + this.type = 'text'; + var input = this.value; - //CREATE FUNCTION TO ALLOW DELETION OF SPACES - date.onkeydown = function() { - var key = event.keyCode || event.charCode; - inputText = String(input); - if(key == 8 && (input.length==2 || input.length==6)){ - this.value = inputText.substring(0, inputText.length); - return - } - }; + //CREATE FUNCTION TO ALLOW DELETION OF SPACES + date.onkeydown = function() { + var key = event.keyCode || event.charCode; + inputText = String(input); + if(key == 8 && (input.length==2 || input.length==6)){ + this.value = inputText.substring(0, inputText.length); + return + } + }; - //ESCAPE FUNCTION IF FINAL CHARACTER IS ENTERED - if(input.length == 11) return; - var values = input.split(' '); - // ADD FUNCTION TO ADD SPACES - var output = values.map(function(v, i) { - // ADD SPACE AFTER FIRST TWO CHARACTERS - if (v.length == 2 && i < 1) { - return v = v + ' '; - // ADD SPACE AFTER SECOND THREE CHARACTERS - } else if (v.length == 3 && i < 2) { - return v = v + ' '; - } else { - return v - } - }); - this.value = output.join('').substr(0, 11); - }); + //ESCAPE FUNCTION IF FINAL CHARACTER IS ENTERED + if(input.length == 11) return; + var values = input.split(' '); + // ADD FUNCTION TO ADD SPACES + var output = values.map(function(v, i) { + // ADD SPACE AFTER FIRST TWO CHARACTERS + if (v.length == 2 && i < 1){ + return v = v + ' '; + // ADD SPACE AFTER SECOND THREE CHARACTERS + }else if (v.length == 3 && i < 2){ + return v = v + ' '; + } else { + return v + } + }); + this.value = output.join('').substr(0, 11); + }); }); }); + //================== 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) { +function waitForMutation(selector, func) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); @@ -214,17 +210,8 @@ function waitForMutation(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(); + // console.log(mutations); + func(mutations); } }); observer.observe(document.body, { @@ -236,6 +223,21 @@ function waitForMutation(selector) { }); } +//FIND THE REGIONS TO REMOVE THE CARETS BEFORE FLIPPING THEM +function targetRegions(mutations) { + //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(); +} + //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')"; @@ -267,7 +269,53 @@ function flipCarets() { //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'); + waitForMutation('td.dash-cell.column-0', targetRegions); }) }) //================== Stats table carets END =============================================== + + +//==================Functions to flip adjust colorbar values for only concentration var === +//GET THE VARIABLE VALUE +function getVars() { + const search = window.location.search + const urlParams = new URLSearchParams(search); + const currentVar = urlParams.get('var'); + return currentVar; +} + +function tiltValues() { + if (getVars() == 'concentration') { + const containers = document.querySelectorAll('.leaflet-control-colorbar'); + containers.forEach(container => { + const secondDiv = container.querySelectorAll('div')[1]; + const spans = secondDiv.querySelectorAll('span'); + spans.forEach(span => { + span.style.transform = 'rotate(30deg)'; + span.style.paddingTop = '2px'; + }); + }); + }; +}; + +function setWidthForColorbars(nothing) { + const colorbars = document.querySelectorAll('.leaflet-control-colorbar'); + colorbars.forEach(colorbar => { + const info = document.querySelector('.info').offsetWidth; + colorbar.style.maxWidth = info.toString() + 'px'; + }); +} + +$(document).ready(function () { + $(document).on('click', "#models-apply, .DayPicker, .SingleDatePickerInput_clearDate", function () { + setTimeout(tiltValues, 500); + setTimeout(setWidthForColorbars, 500); + }) +}) + +$(document).ready(function () { + setTimeout(tiltValues, 900); + setTimeout(setWidthForColorbars, 900); +}); +//==================END Funcfions to flip adjust colorbar values for only concentration var ========== + diff --git a/tabs/evaluation_callbacks.py b/tabs/evaluation_callbacks.py index 843c4eb..fcc952b 100644 --- a/tabs/evaluation_callbacks.py +++ b/tabs/evaluation_callbacks.py @@ -253,6 +253,34 @@ def format_floats(df): df.at[i, col] = '{:.2f}'.format(float(val)) return df +@cache.memoize(timeout=cache_timeout) +def alphabetize_stations(df): +# def alphabetize_stations(filepath, tab_name): + """ This will alphabetize the stations for each region in the aeronet stats table""" + # Define a list of regions to sort between (in the desired order) + regions = ['Europe', 'Mediterranean', 'MiddleEast', 'NAfrica', 'Total'] + region_dfs = [] + # Iterate over each pair of consecutive regions and sort the rows between them + for i in range(len(regions)-1): + # Get the indices of the current and next regions + current_region_idx = df[df['station'] == regions[i]].index[0] + next_region_idx = df[df['station'] == regions[i+1]].index[0] + # Slice the dataframe to select the rows between the current and next regions + subset_df = df.loc[current_region_idx+1:next_region_idx-1] + # Sort the rows alphabetically based on the 'station' column + subset_df = subset_df.sort_values(by='station') + # Create a new dataframe containing only the current region row + current_region_row = df.loc[current_region_idx].to_frame().T + # Append the current region row and sorted subset dataframe to the list of region DataFrames + region_dfs.append(current_region_row) + region_dfs.append(subset_df) + # Add the 'Total' row back to the end of the sorted dataframe + total_row_idx = df[df['station'] == 'Total'].index[0] + total_row = df.loc[total_row_idx].to_frame().T + region_dfs.append(total_row) + # Concatenate all of the region DataFrames into a single sorted DataFrame + sorted_df = pd.concat(region_dfs) + return sorted_df @dash.callback( extend_l([ @@ -345,9 +373,8 @@ def aeronet_scores_tables_retrieve(n, *args): # *activel_cells, models, stat, n return no_data df = pd.read_hdf(filepath, tab_name) - # replace "tables" columns - # import pudb; pudb.set_trace() df = format_floats(df) + df = alphabetize_stations(df) ret_tables[ret_idx] = [{'name': i in MODELS and [STATS[SCORES[table_idx]], MODELS[i]['name']] or -- GitLab From fa7dd0e6b269e88b870301a8a4ffb4cc9b4c1e82 Mon Sep 17 00:00:00 2001 From: Elliott Rose Date: Tue, 21 Mar 2023 15:40:49 +0100 Subject: [PATCH 4/5] Fix issue with screenshot cropping right side of png --- assets/download-img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/download-img.js b/assets/download-img.js index b811e09..69a5ec9 100644 --- a/assets/download-img.js +++ b/assets/download-img.js @@ -21,7 +21,7 @@ function getCanvas(element) { allowTaint: true, useCORS: true, async: true, - windowWidth: element.offsetWidth, + windowWidth: element.offsetWidth + 30, windowHeight: element.offsetHeight, logging: true, imageTimeout: 0, -- GitLab From bcb85cbf652ab7901effc2df36c2d31438879aaa Mon Sep 17 00:00:00 2001 From: Elliott Rose Date: Tue, 21 Mar 2023 16:02:38 +0100 Subject: [PATCH 5/5] Remove unnecessary caching in alphabetiztion and update observations tests --- tabs/evaluation_callbacks.py | 1 - tests/test_observations.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tabs/evaluation_callbacks.py b/tabs/evaluation_callbacks.py index fcc952b..249e278 100644 --- a/tabs/evaluation_callbacks.py +++ b/tabs/evaluation_callbacks.py @@ -253,7 +253,6 @@ def format_floats(df): df.at[i, col] = '{:.2f}'.format(float(val)) return df -@cache.memoize(timeout=cache_timeout) def alphabetize_stations(df): # def alphabetize_stations(filepath, tab_name): """ This will alphabetize the stations for each region in the aeronet stats table""" diff --git a/tests/test_observations.py b/tests/test_observations.py index 5f4044f..32103de 100644 --- a/tests/test_observations.py +++ b/tests/test_observations.py @@ -15,7 +15,7 @@ def test_obs_time_slider(): assert "NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-date-picker'), className='timesliderline'), Span(children=[Button(id='btn-obs-play', className='fa fa-play', n_clicks=0, title='Play')], className='timesliderline anim-buttons'), Span(children=Slider(min=0, max=23, step=1, marks={0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 13: '13', 14: '14', 15: '15', 16: '16', 17: '17', 18: '18', 19: '19', 20: '20', 21: '21', 22: '22', 23: '23'}, value=0, id='obs-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)" in str (code.obs_time_slider(div='obs', start=0, end=23, step=1)) #TEST DIV=OBS-VIS - assert "NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-vis-date-picker'), className='timesliderline'), None, Span(children=Slider(min=0, max=23, step=1, marks={0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 13: '13', 14: '14', 15: '15', 16: '16', 17: '17', 18: '18', 19: '19', 20: '20', 21: '21', 22: '22', 23: '23'}, value=0, id='obs-vis-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)" in str (code.obs_time_slider(div='obs-vis', start=0, end=23, step=1)) + assert "NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-vis-date-picker'), className='timesliderline'), None, Span(children=Slider(min=0, max=23, step=1, marks={0: {'label': '00-01'}, 1: {'label': '01-02'}, 2: {'label': '02-03'}, 3: {'label': '03-04'}, 4: {'label': '04-05'}, 5: {'label': '05-06'}, 6: {'label': '06-07'}, 7: {'label': '07-08'}, 8: {'label': '08-09'}, 9: {'label': '09-10'}, 10: {'label': '10-11'}, 11: {'label': '11-12'}, 12: {'label': '12-13'}, 13: {'label': '13-14'}, 14: {'label': '14-15'}, 15: {'label': '15-16'}, 16: {'label': '16-17'}, 17: {'label': '17-18'}, 18: {'label': '18-19'}, 19: {'label': '19-20'}, 20: {'label': '20-21'}, 21: {'label': '21-22'}, 22: {'label': '22-23'}, 23: {'label': '23-24', 'style': {'left': '', 'right': '-32px'}}}, value=6, id='obs-vis-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)" in str (code.obs_time_slider(div='obs-vis', start=0, end=23, step=1)) #TEST DIV = OBS-AOD assert "NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20210318', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2021, 3, 18, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2021, 3, 18, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-aod-date-picker'), className='timesliderline'), Span(children=[Button(id='btn-obs-aod-play', className='fa fa-play', n_clicks=0, title='Play')], className='timesliderline anim-buttons'), Span(children=Slider(min=0, max=23, step=1, marks={0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 13: '13', 14: '14', 15: '15', 16: '16', 17: '17', 18: '18', 19: '19', 20: '20', 21: '21', 22: '22', 23: '23'}, value=0, id='obs-aod-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)" in str (code.obs_time_slider(div='obs-aod', start=0, end=23, step=1)) @@ -34,4 +34,4 @@ def test_tab_obseravtions(): assert "Tab(children=[Span(children=P('EUMETSAT RGB'), className='description-title'), Span(children=P([B('\\n You can explore key observations that can be used to track dust events. \\n '), ' All observations are kindly offered by Partners of the WMO Barcelona Dust Regional Center. RGB is a qualitative satellite product that indicates desert dust in the entire atmospheric column (represented by pink colour).']), className='description-body'), Div(children=[Button(children='HEMISPHERIC', id='btn-fulldisc', active=True), Button(children='MIDDLE EAST', id='btn-middleeast', active=False)], id='rgb-buttons'), Div(children=[Img(id='rgb-image', alt='EUMETSAT RGB - NOT AVAILABLE', src='./assets/eumetsat/FullDiscHD/archive/20220831/FRAME_OIS_RGB-dust-all_202208310000.gif'), Div(children=NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-date-picker'), className='timesliderline'), Span(children=[Button(id='btn-obs-play', className='fa fa-play', n_clicks=0, title='Play')], className='timesliderline anim-buttons'), Span(children=Slider(min=0, max=23, step=1, marks={0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 13: '13', 14: '14', 15: '15', 16: '16', 17: '17', 18: '18', 19: '19', 20: '20', 21: '21', 22: '22', 23: '23'}, value=0, id='obs-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True), className='layout-dropdown')], className='centered-image'), Div(Interval(id='obs-slider-interval', disabled=True, interval=1000, n_intervals=0))], id='observations-tab', className='horizontal-menu', label='Observations', value='observations-tab')" in str(code.tab_observations('rgb')) #TEST VISIBILITY - assert "Tab(children=[Span(children=P('Visibility'), className='description-title'), Span(children=P([B('You can explore key observations that can be used to track dust events. '), 'All observations are kindly offered by Partners of the WMO Barcelona Dust Regional Center. The reduction of VISIBILITY is an indirect measure of the occurrence of sand and dust storms on the surface.']), className='description-body'), Div(children=[], id='obs-vis-graph'), Div(children=[NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-vis-date-picker'), className='timesliderline'), None, Span(children=Slider(min=0, max=18, step=6, marks={0: '0', 6: '6', 12: '12', 18: '18'}, value=0, id='obs-vis-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True), Br(None), Br(None), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer')], className='layout-dropdown rgb-layout-dropdown')], id='observations-tab', className='horizontal-menu', label='Observations', value='observations-tab')" in str(code.tab_observations('visibility')) + assert "Tab(children=[Span(children=P('Visibility'), className='description-title'), Span(children=P([B('You can explore key observations that can be used to track dust events. '), 'All observations are kindly offered by Partners of the WMO Barcelona Dust Regional Center. The reduction of VISIBILITY is an indirect measure of the occurrence of sand and dust storms on the surface.']), className='description-body'), Div(children=[], id='obs-vis-graph', className='graph-with-slider'), Div(children=[NavbarSimple(children=[Div(children=[Span(children=DatePickerSingle(date='20220831', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 31, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 31, 0, 0), clearable=True, reopen_calendar_on_clear=True, display_format='DD MMM YYYY', id='obs-vis-date-picker'), className='timesliderline'), None, Span(children=Slider(min=0, max=18, step=6, marks={0: {'label': '00-06'}, 6: {'label': '06-12'}, 12: {'label': '12-18'}, 18: {'label': '18-24', 'style': {'left': '', 'right': '-32px'}}}, value=6, id='obs-vis-slider-graph'), className='timesliderline')], className='timeslider')], id='rgb-navbar', className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True), Br(None), Br(None), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer')], className='layout-dropdown rgb-layout-dropdown')], id='observations-tab', className='horizontal-menu', label='Observations', value='observations-tab')" in str(code.tab_observations('visibility')) -- GitLab