Last active
June 10, 2020 08:43
-
-
Save clubgisdotnet/d0d46ccdc7fc16a36be842d53e99083d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var pt = ee.Geometry.Point(89.07, 22.65); | |
| // Load Sentinel-1 C-band SAR Ground Range collection (log scaling, VV co-polar) | |
| var collection = ee.ImageCollection('COPERNICUS/S1_GRD').filterBounds(pt) | |
| .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) | |
| .select('VV'); | |
| // Add dropdown for year | |
| var thisYear = new Date(); | |
| // Check all images of last 3 year, Sentinel-1 images were scarce before 2017 | |
| var year = []; | |
| for (var i = 0; i < 4; i ++){ | |
| year.push((thisYear.getFullYear() - i).toString()); | |
| } | |
| var selectMonth; | |
| var selectMonthIdx; | |
| var selectMonth2; | |
| var selectMonth2Idx; | |
| var mapLayersList = []; | |
| // Add dropdown for date | |
| var range = { | |
| 'January' : ['01-01', '01-31'], | |
| 'February': ['02-01', '02-28'], | |
| 'March' : ['03-01', '03-31'], | |
| 'April' : ['04-01', '04-30'], | |
| 'May' : ['05-01', '05-31'], | |
| 'June' : ['06-01', '06-30'], | |
| 'July' : ['07-01', '07-31'], | |
| 'August' : ['08-01', '08-31'], | |
| 'September' : ['09-01', '09-30'], | |
| 'October' : ['10-01', '10-31'] | |
| }; | |
| // Select year dropdown | |
| var thisMonth = thisYear.toLocaleString('default', { month: 'long' }); | |
| var thisMonthIdx = Object.keys(range).indexOf(thisMonth); | |
| var selectYear = ui.Select({ | |
| items: year, | |
| // value: year[0], | |
| placeholder: 'Select year', | |
| style:{padding: '0px 0px 0px 10px', stretch: 'horizontal'}, | |
| onChange: function(){ | |
| // Remove future months from selectable month list | |
| if(selectYear.getValue() == thisYear.getFullYear()) { | |
| selectMonths1.items().reset(Object.keys(range).slice(0, thisMonthIdx-1)); | |
| selectMonths2.items().reset(Object.keys(range).slice(1, thisMonthIdx)); | |
| } | |
| else if (selectMonths1.getValue() == selectMonths2.getValue()){ | |
| selectMonths1.items().reset(Object.keys(range).slice(0, -1)); | |
| selectMonths2.items().reset(Object.keys(range).slice(1)); | |
| } | |
| else { | |
| selectMonths1.items().reset(Object.keys(range).slice(0, -1)); | |
| selectMonths2.items().reset(Object.keys(range).slice(1)); | |
| selectMonths1.setValue(Object.keys(range)[0]); | |
| selectMonths2.setValue(Object.keys(range)[selectMonthIdx+1]); | |
| } | |
| // runButton.setDisabled(true); | |
| } | |
| }); | |
| var selectMonths1 = ui.Select({ | |
| items: Object.keys(range), | |
| // value: Object.keys(range)[0], | |
| placeholder: 'Start month', | |
| style: {stretch: 'horizontal'}, | |
| onChange: function(){ | |
| selectMonth = selectMonths1.getValue(); | |
| selectMonthIdx = Object.keys(range).indexOf(selectMonth); | |
| selectMonth2 = selectMonths2.getValue(); | |
| selectMonth2Idx = Object.keys(range).indexOf(selectMonth2); | |
| // Remove future months ensuring month2 comes after month1 | |
| if(selectYear.getValue() == thisYear.getFullYear()){ | |
| selectMonths2.items().reset(Object.keys(range).slice(selectMonthIdx+1, thisMonthIdx)); | |
| if (selectMonthIdx >= selectMonth2Idx){ | |
| selectMonths2.items().reset(Object.keys(range).slice(selectMonthIdx+1, thisMonthIdx)); | |
| selectMonths2.setValue(Object.keys(range)[selectMonthIdx+1]); | |
| selectMonths1.setValue(Object.keys(range)[0]); | |
| } | |
| } | |
| else if (selectMonths1.getValue() == selectMonths2.getValue()){ | |
| selectMonths1.items().reset(Object.keys(range).slice(0, -1)); | |
| selectMonths2.items().reset(Object.keys(range).slice(1)); | |
| } | |
| else if (selectMonthIdx >= selectMonth2Idx){ | |
| selectMonths2.items().reset(Object.keys(range).slice(selectMonthIdx+1)); | |
| selectMonths2.setValue(Object.keys(range)[selectMonthIdx+1]); | |
| } | |
| else { | |
| selectMonths2.items().reset(Object.keys(range).slice(selectMonthIdx+1)); | |
| } | |
| } | |
| }); | |
| var selectMonths2 = ui.Select({ | |
| items: Object.keys(range), | |
| // value: Object.keys(range)[thisMonthIdx-1], | |
| placeholder: 'End month', | |
| onChange: function(){ | |
| if (selectMonths2.getValue() === null){ | |
| runButton.setDisabled(true); | |
| } | |
| else if (selectMonths1.getValue() === null){ | |
| runButton.setDisabled(true); | |
| } | |
| else if (selectYear.getValue() === null){ | |
| runButton.setDisabled(true); | |
| } | |
| else { | |
| runButton.setDisabled(false); | |
| } | |
| }, | |
| style:{padding: '0px 10px 0px 0px', stretch: 'horizontal'} | |
| }); | |
| // Add button to process images | |
| var runButton = ui.Button({ | |
| label: 'Process images', | |
| onClick: function(){ | |
| // Threshold smoothed radar intensities to identify "flooded" areas. | |
| var SMOOTHING_RADIUS = 100; | |
| var DIFF_UPPER_THRESHOLD = -3; | |
| var before = collection.filterDate( | |
| selectYear.getValue() + "-" + range[selectMonths1.getValue()][0], | |
| selectYear.getValue() + "-" + range[selectMonths1.getValue()][1]) | |
| .mosaic(); | |
| var after = collection.filterDate( | |
| selectYear.getValue() + "-" + range[selectMonths2.getValue()][0], | |
| selectYear.getValue() + "-" + range[selectMonths2.getValue()][1]) | |
| .mosaic(); | |
| var diffSmoothed = after.focal_median(SMOOTHING_RADIUS, 'circle', 'meters') | |
| .subtract(before.focal_median(SMOOTHING_RADIUS, 'circle', 'meters')); | |
| var diffThresholded = diffSmoothed.lt(DIFF_UPPER_THRESHOLD); | |
| var layerName = selectMonths1.getValue()+ "-" + selectMonths2.getValue() + ", " + selectYear.getValue() | |
| var layer = diffThresholded.updateMask(diffThresholded) | |
| // Dictionary for splitPanel | |
| mapLayersList.push({ | |
| label: layerName, | |
| value: ee.ImageCollection(layer) | |
| }) | |
| leftSelect.items().reset(mapLayersList) | |
| rightSelect.items().reset(mapLayersList) | |
| }, | |
| disabled: true, | |
| style: {padding: '0px 10px', stretch: 'horizontal', color: 'blue'} | |
| }); | |
| // Variables to set a label for maps | |
| var layerLabelLeft = ui.Label('Select a start and end date'); | |
| var layerLabelRight = ui.Label('Select a start and end date'); | |
| // Set a random color to each map on each onChange | |
| var VizualizeFunc = function(item) { | |
| return item.visualize({palette : Math.floor(Math.random()*65280).toString(16)}) | |
| .copyProperties(item, item.propertyNames()); | |
| }; | |
| // Select map for split panel | |
| var leftSelect = ui.Select({ | |
| items: mapLayersList, | |
| placeholder: 'Left panel', | |
| onChange: function(){ | |
| leftMap.layers().set(0, leftSelect.getValue().map(VizualizeFunc)); | |
| // Take the selected item from the dropdown and show its name on the top | |
| var layerNameLeft = mapLayersList.filter(function (item) {return item.value == leftSelect.getValue()}); | |
| layerLabelLeft.setValue(layerNameLeft[0]['label']); | |
| }, | |
| style:{padding: '0px 0px 0px 10px', stretch: 'horizontal'} | |
| }); | |
| var rightSelect = ui.Select({ | |
| items: mapLayersList, | |
| placeholder: 'Right panel', | |
| onChange: function(){ | |
| rightMap.layers().set(0, rightSelect.getValue().map(VizualizeFunc)); | |
| // Take the selected item from the dropdown and show its name on the top | |
| var layerNameRight = mapLayersList.filter(function (item) {return item.value == rightSelect.getValue()}); | |
| layerLabelRight.setValue(layerNameRight[0]['label']); | |
| }, | |
| style:{padding: '0px 10px 0px 00px', stretch: 'horizontal'} | |
| }); | |
| // Create the left panel | |
| var panel = ui.Panel({ | |
| layout: ui.Panel.Layout.flow('vertical'), | |
| style: {width: '400px'} | |
| }); | |
| // Add the title | |
| var mapTitle = ui.Label('Flood status of Bangladesh'); | |
| mapTitle.style().set('color', 'blue'); | |
| mapTitle.style().set('fontWeight', 'bold'); | |
| mapTitle.style().set({ | |
| fontSize: '20px', | |
| padding: '10px' | |
| }); | |
| // Add description | |
| var mapDesc = ui.Label("The status of flood in Bangladesh as seen in Sentinel-1 satellite image. \ | |
| The SAR images are capable to see through cloud and measure the extent of surface water, \ | |
| where optical satellite (ie Landsat 8) can not."); | |
| mapDesc.style().set({ fontSize: '16px', padding: '0px 10px'}); | |
| // Spilt map | |
| var leftMap = ui.Map().setOptions({mapTypeId: "HYBRID"}); | |
| var rightMap = ui.Map().setOptions({mapTypeId: "HYBRID"}); | |
| var linkedMaps = ui.Map.Linker([leftMap, rightMap]); | |
| leftMap.setControlVisibility({ layerList : false, zoomControl: false, mapTypeControl : true,fullscreenControl : false }); | |
| rightMap.setControlVisibility({ layerList : false, zoomControl: false, mapTypeControl : true, fullscreenControl : false }); | |
| leftMap.setCenter(89.07, 22.65, 10); | |
| leftMap.style().set('cursor', 'hand'); | |
| rightMap.style().set('cursor', 'hand'); | |
| // Add layer name to each maps | |
| leftMap.add(layerLabelLeft); | |
| rightMap.add(layerLabelRight); | |
| // Create a SplitPanel which holds the linked maps side-by-side. | |
| var splitPanel = ui.SplitPanel({ | |
| firstPanel: linkedMaps.get(0), | |
| secondPanel: linkedMaps.get(1), | |
| orientation: 'horizontal', | |
| wipe: true, | |
| style: {stretch: 'both'} | |
| }); | |
| panel.add(mapTitle); | |
| panel.add(mapDesc); | |
| panel.add(ui.Panel([selectYear, selectMonths1, selectMonths2], ui.Panel.Layout.flow('horizontal'))); | |
| panel.add(runButton); | |
| panel.add(ui.Panel([leftSelect, rightSelect], ui.Panel.Layout.flow('horizontal'))); | |
| ui.root.clear(); | |
| ui.root.insert(0, panel); | |
| ui.root.insert(1, splitPanel); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A Google Earth Engine app to visualize the flood status of Bangladesh and India before and after cyclone Amphan.