Skip to content

Instantly share code, notes, and snippets.

@jdbcode
Last active May 27, 2023 13:18
Show Gist options
  • Save jdbcode/8410646ff2af593b2d0ae980113aee4a to your computer and use it in GitHub Desktop.
Save jdbcode/8410646ff2af593b2d0ae980113aee4a to your computer and use it in GitHub Desktop.
An Earth Engine App script that displays a global PDSI map and time series chart

Earth Engine App
Earth Engine Code Editor script

/**
 * @license
 * Copyright 2021 The Google Earth Engine Community Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @description
 * This app shows a global map of the most recent calculation of Palmer Drought
 * Severity Index and a monthly mean time series chart for a selected county
 * going back to the year 2000. Click on a county polygon and wait a minute to
 * view the time series. The app uses URL parameters to save its state for
 * sharing with with colleagues. PDSI are represented by the TerraClimate
 * dataset.
 */

/*******************************************************************************
 * Model *
 ******************************************************************************/

var m = {};

m.palette = {
  minRgb: [255, 0, 0],
  midRgb: [255, 255, 255],
  maxRgb: [0, 0, 255],
  minVal: -5,
  midVal: 0,
  maxVal: 5
};

m.chartBounds = {
  min: -7,
  max: 7
};

m.fvVis = {
  polygonStrokeColor: '484848',
  polygonStrokeOpacity: 0.9,
  polygonStrokeWidth: 1,
  polygonFillOpacity: 0,
  pointSize: 0
};

m.counties = ee.FeatureCollection('FAO/GAUL_SIMPLIFIED_500m/2015/level2');
m.countiesFv = ui.Map.FeatureViewLayer('FAO/GAUL_SIMPLIFIED_500m/2015/level2_FeatureView');
m.drought = ee.ImageCollection("IDAHO_EPSCOR/TERRACLIMATE");
m.droughtBand = 'pdsi';
m.dateRange = ['2000-01-01', Date.now()];
m.pdsiScale = 0.01;


/*******************************************************************************
 * Components *
 ******************************************************************************/

var c = {};

// Panel to hold the chart.
c.chartPanel = ui.Panel();

// Map widget.
c.map = ui.Map();
c.map.setLocked(false, 4, 16);
c.map.setCenter(30, 40, 4);

// Map/chart panel
c.mapChartSplitPanel = ui.SplitPanel({
  firstPanel: c.map, //
  secondPanel: c.chartPanel,
  orientation: 'vertical',
  wipe: false,
});

// Messages.
var spinnerUri = 'data:image/gif;base64,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';
var clickUrl = 'https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/left_click/default/24px.svg';
var warningUrl = 'https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/warning/grad200/24px.svg';
var iconsStyle = {fontWeight: 'bold', fontSize: '16px', margin: '14px 5px'};

c.clickMessage = ui.Panel([
  ui.Label({imageUrl: clickUrl}),
  ui.Label('Click a county to view its PDSI time series.', iconsStyle)
  ], ui.Panel.Layout.flow('horizontal'));
c.waitMessage = ui.Panel([
  ui.Label({imageUrl: spinnerUri}),
  ui.Label('Processing, please wait', iconsStyle)
  ], ui.Panel.Layout.flow('horizontal'));
c.noFeaturesMessage = ui.Panel([
  ui.Label({imageUrl: warningUrl}),
  ui.Label('There are no features intersecting the ' +
  'point you clicked, try again', iconsStyle)
  ], ui.Panel.Layout.flow('horizontal'));

// Element panel.
c.aboutPanel = ui.Panel(
  {style: {margin: '0px -8px 0px -8px'}});

// Show/hide info panel button.
c.aboutButton = ui.Button(
  {label: 'About ❯', style: {margin: '0px 4px 0px 0px'}});

// Information text. 
c.descrLabel = ui.Label(
  'This app shows a map of the most recent calculation of Palmer ' +
  'Drought Severity Index and a monthly mean time series chart ' +
  'for a selected county going back to the year 2000. Click on a ' +
  'county polygon and wait a minute to view the time series. ' +
  'The app uses URL parameters to save its state for sharing what ' +
  'you discover with colleagues.');

c.datasetLabel = ui.Label('Learn more about the TerraClimate dataset.', null,
  'https://developers.google.com/earth-engine/datasets/catalog/IDAHO_EPSCOR_TERRACLIMATE');
c.descrHolder = ui.Panel([c.descrLabel, c.datasetLabel]);

// Define a legend widget group.
c.legend = {};
c.legend.title = ui.Label();
c.legend.colorbar = ui.Thumbnail(ee.Image.pixelLonLat().select(0));
c.legend.leftLabel = ui.Label('[min]');
c.legend.centerLabel = ui.Label();
c.legend.rightLabel = ui.Label('[max]');
c.legend.labelPanel = ui.Panel({
  widgets: [
    c.legend.leftLabel,
    c.legend.centerLabel,
    c.legend.rightLabel,
  ],
  layout: ui.Panel.Layout.flow('horizontal')
});
c.legend.panel = ui.Panel([
  c.legend.title,
  c.legend.colorbar,
  c.legend.labelPanel
]);



/*******************************************************************************
 * Composition *
 ******************************************************************************/

ui.root.clear();
ui.root.add(c.mapChartSplitPanel);
c.map.add(c.legend.panel);
c.map.add(c.aboutPanel);
c.chartPanel.add(c.clickMessage);
c.aboutPanel.add(c.aboutButton);
c.aboutPanel.add(c.descrHolder);



/*******************************************************************************
 * Styling *
 ******************************************************************************/

var s = {};

s.opacityWhiteMed = {
  backgroundColor: 'rgba(255, 255, 255, 0.5)'
};
s.opacityWhiteNone = {
  backgroundColor: 'rgba(255, 255, 255, 0)'
};
s.chartStyle = {
  height: '325px',
  margin: '0px',
  padding: '0px'
};

c.map.style().set('cursor', 'crosshair');
c.map.setOptions('Grey', {Grey: mapStyle()});

c.chartPanel.style().set({
  height: s.chartStyle.height,
  minHeight: s.chartStyle.height,
  maxHeight: s.chartStyle.height
});

c.aboutPanel.style().set({
  position: 'bottom-right',
  backgroundColor: 'rgba(255, 255, 255, 0.5)'
});

c.descrLabel.style().set({
  margin: '0px',
  backgroundColor: 'rgba(255, 255, 255, 0)',
  fontSize: '13px',
  color: '505050'
});

c.datasetLabel.style().set({
  margin: '4px 0px 0px 0px',
  backgroundColor: 'rgba(255, 255, 255, 0)',
  fontSize: '13px',
  color: '505050'
});

c.descrHolder.style().set({
  shown: false,
  width: '250px',
  margin: '4px 0px 0px 0px',
  padding: '8px 8px 8px 8px',
  backgroundColor: 'rgba(255, 255, 255, 0.8)',
});

c.aboutButton.style().set({
  margin: '0px 0px 0px 0px'
});

c.legend.title.style().set({
  fontWeight: 'bold',
  fontSize: '12px',
  color: '383838'
});
c.legend.title.style().set(s.opacityWhiteNone);
c.legend.colorbar.style().set({
  stretch: 'horizontal',
  margin: '0px 8px',
  maxHeight: '20px'
});
c.legend.leftLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px'
});
c.legend.leftLabel.style().set(s.opacityWhiteNone);
c.legend.centerLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px',
  textAlign: 'center',
  stretch: 'horizontal'
});
c.legend.centerLabel.style().set(s.opacityWhiteNone);
c.legend.rightLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px'
});
c.legend.rightLabel.style().set(s.opacityWhiteNone);
c.legend.panel.style().set({
  position: 'bottom-left',
  width: '200px',
  padding: '0px'});
c.legend.panel.style().set(s.opacityWhiteMed);
c.legend.labelPanel.style().set(s.opacityWhiteNone);



/*******************************************************************************
 * Behaviors *
 ******************************************************************************/

// Converts RGB integer component to hex string. 
function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? '0' + hex : hex;
}

// Converts RGB color list to hex color string.
function rgbToHex(rgb) {
  return "#" +
  componentToHex(rgb[0]) +
  componentToHex(rgb[1]) +
  componentToHex(rgb[2]);
}

// Identifies the RGB color for a value in a divergent palette.
function getRgbDivergent(cMin, cMid, cMax, min, mid, max, val) {
  var dif, frac, c1, c2, r, g, b;
  
  if (val <= mid) {
    val = val < min ? min : val;
    dif = mid - min;
    frac = Math.abs(val/dif);
    c1 = cMin;
    c2 = cMid;
    r = (c1[0] - c2[0]) * frac + c2[0];
    g = (c1[1] - c2[1]) * frac + c2[1];
    b = (c1[2] - c2[2]) * frac + c2[2];
  } else {
    val = val > max ? max : val;
    dif = max - mid;
    frac = Math.abs(val/dif);
    c1 = cMid;
    c2 = cMax;
    r = (c2[0] - c1[0]) * frac + c1[0];
    g = (c2[1] - c1[1]) * frac + c1[1];
    b = (c2[2] - c1[2]) * frac + c1[2];
  }
  
  var rgb = [];
  [r, g, b].forEach(function(c) {
    rgb.push(Math.round(c));
  });
  
  return rgb;
}

// Adds date information to images.
function scalePdsi(img) {
  return img.select(m.droughtBand).multiply(m.pdsiScale)
    .set('system:time_start', img.get('system:time_start'));
}

// Calculates mean monthly PDSI image collection.
function getPdsiSummary() {
  return m.drought
          .filterDate(m.dateRange[0], m.dateRange[1])
          .map(scalePdsi);
}

// Generates a PDSI time series chart and adds it to chart panel.
function drawChart(coords) {
  var point = ee.Geometry.Point(coords.lon, coords.lat);
  var aoi = m.counties.filterBounds(point).first();
  var aoiId = aoi.get('system:index');

  m.fvVis['rules'] = [{
    filter: ee.Filter.eq('system:index', aoiId),
    polygonStrokeWidth: 3,
    polygonStrokeOpacity: 1,
    polygonStrokeColor: 'black',
    polygonFillOpacity: 0
  }];
  m.countiesFv.setVisParams(m.fvVis);

  var pdsiSummary = getPdsiSummary();
  var pdsiDf = pdsiSummary.map(function(img) {
    var stat = img.reduceRegion({
      'geometry': aoi.geometry(),
      'reducer': ee.Reducer.mean(),
      'scale': 4500,
      'crs': 'EPSG:4326',
      'bestEffort': true 
    });
    return ee.Feature(null, stat)
            .set({'millis': img.date().millis()});  
  }).sort('millis');
  
  var pdsiVal = pdsiDf.aggregate_array(m.droughtBand);
  var evalInfo = ee.Dictionary({
    pdsiVal: pdsiVal,
    ADM2_NAME: aoi.getString('ADM2_NAME'),
    ADM1_NAME: aoi.getString('ADM1_NAME'),
    ADM0_NAME: aoi.getString('ADM0_NAME')
  });
  
  evalInfo.evaluate(function(evalInfo) {
    var colors = [];
    for (var i in evalInfo.pdsiVal) {
      var rgb = getRgbDivergent(
        m.palette.minRgb, m.palette.midRgb, m.palette.maxRgb,
        m.palette.minVal, m.palette.midVal, m.palette.maxVal,
        evalInfo.pdsiVal[i]);
      colors.push(rgbToHex(rgb));
    }
  
    var chart = ui.Chart.feature.groups(pdsiDf, 'millis', 'pdsi', 'millis')
      .setChartType('ColumnChart')
      .setOptions({
        title: evalInfo.ADM2_NAME+', '+evalInfo.ADM1_NAME+', '+evalInfo.ADM0_NAME,
        bar: {groupWidth: '100%'},
        colors: colors,
        legend: {position: 'none'},
        vAxis: {
          title: 'PDSI',
          viewWindow: {min: m.chartBounds.min, max: m.chartBounds.max}, 
          titleTextStyle: {italic: false, bold: true}
        },
        hAxis: {
          minorGridlines: {count: 0}
        },
        isStacked: true,
        explorer: {axis: 'horizontal'}
      });
    chart.style().set(s.chartStyle);
    c.chartPanel.widgets().reset([chart]);
  });
}

// Updates the URL parameters for the location clicked.
function updatePtUrl(coords) {
  ui.url.set('ptlon', coords.lon);
  ui.url.set('ptlat', coords.lat);
}

// Checks to see of clicked point intersects data, calls drawChart if so.
function checkPoint(coords) {
  c.chartPanel.widgets().reset([c.waitMessage]);
  var geom = ee.Geometry.Point(coords.lon, coords.lat);
  var aoi = m.counties.filterBounds(geom)
    .filterBounds(m.drought.first().geometry());
  aoi.size().evaluate(function(nFeatures) {
    if (nFeatures === 0) {
      c.chartPanel.widgets().reset([c.noFeaturesMessage]);
      return null;
    } else {
      drawChart(coords);
      updatePtUrl(coords);
    }
  });
}
c.map.onClick(checkPoint);

// Updates URL parameters that control map bounds on load.
function updateUrlParamMap(newMapParams) {
  ui.url.set('lat', newMapParams.lat);
  ui.url.set('lon', newMapParams.lon);
  ui.url.set('zoom', newMapParams.zoom);
}
c.map.onChangeBounds(ui.util.debounce(updateUrlParamMap, 100));

var infoShow = false;
function infoButtonHandler() {
  if(infoShow) {
    infoShow = false;
    c.descrHolder.style().set('shown', false);
    c.aboutButton.setLabel('About ❯');
  } else {
    infoShow = true;
    c.descrHolder.style().set('shown', true);
    c.aboutButton.setLabel('About ❮');
  }
}
c.aboutButton.onClick(infoButtonHandler);



/*******************************************************************************
 * Initialize *
 ******************************************************************************/

// Adds the most recent PDSI image to the map.
function drawRecentPdsi() {
  var recent = m.drought.sort('system:time_start', false).first();
  recent = scalePdsi(recent);
  var date = recent.date().format('YYYY-MM-dd').getInfo();
  var recentRelLayer = ui.Map.Layer(
    recent, {min: m.palette.minVal, max: m.palette.maxVal,
      palette: ['red', 'white', 'blue']},
      'PDSI for ' + date, true, 0.7);  
  
  c.map.layers().set(0, recentRelLayer);
  drawLegend(date);
}

// Overlays counties on the map.
function drawCounties() {
  m.countiesFv.setVisParams(m.fvVis);
  m.countiesFv.setName('Counties');
  c.map.layers().set(1, m.countiesFv);
}

// Adds PDSI legend to the map.
function drawLegend(imgDate) {
  c.legend.title.setValue('PDSI for ' + imgDate);
  c.legend.colorbar.setParams({
    bbox: [0, 0, 1, 0.1],
    dimensions: '100x10',
    format: 'png',
    min: 0,
    max: 1,
    palette: ['red', 'white', 'blue']
  });
  c.legend.leftLabel.setValue(m.palette.minVal);
  c.legend.centerLabel.setValue(m.palette.midVal);
  c.legend.rightLabel.setValue(m.palette.maxVal);
}

// Set map bounds based on URL params.
c.map.setCenter({
  lon: ui.url.get('lon', 0),
  lat: ui.url.get('lat', 20),
  zoom: ui.url.get('zoom', 3)
});

// Initialize map.
drawRecentPdsi();
drawCounties();


// Draw chart if a point was clicked according to URL params.
if (ui.url.get('ptlon')) {
  var coords = {
    lon: ui.url.get('ptlon'),
    lat: ui.url.get('ptlat')
  };
  drawChart(coords);
}



/*******************************************************************************
 * Map style *
 ******************************************************************************/

function mapStyle() {
  return [
    {
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#f5f5f5"
        }
      ]
    },
    {
      "elementType": "labels.icon",
      "stylers": [
        {
          "visibility": "off"
        }
      ]
    },
    {
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#616161"
        }
      ]
    },
    {
      "elementType": "labels.text.stroke",
      "stylers": [
        {
          "color": "#f5f5f5"
        }
      ]
    },
    {
      "featureType": "administrative.land_parcel",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#bdbdbd"
        }
      ]
    },
    {
      "featureType": "poi",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#eeeeee"
        }
      ]
    },
    {
      "featureType": "poi",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#757575"
        }
      ]
    },
    {
      "featureType": "poi.park",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#e5e5e5"
        }
      ]
    },
    {
      "featureType": "poi.park",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#9e9e9e"
        }
      ]
    },
    {
      "featureType": "road",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#ffffff"
        }
      ]
    },
    {
      "featureType": "road.arterial",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#757575"
        }
      ]
    },
    {
      "featureType": "road.highway",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#dadada"
        }
      ]
    },
    {
      "featureType": "road.highway",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#616161"
        }
      ]
    },
    {
      "featureType": "road.local",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#9e9e9e"
        }
      ]
    },
    {
      "featureType": "transit.line",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#e5e5e5"
        }
      ]
    },
    {
      "featureType": "transit.station",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#eeeeee"
        }
      ]
    },
    {
      "featureType": "water",
      "elementType": "geometry",
      "stylers": [
        {
          "color": "#c9c9c9"
        }
      ]
    },
    {
      "featureType": "water",
      "elementType": "labels.text.fill",
      "stylers": [
        {
          "color": "#9e9e9e"
        }
      ]
    }
  ];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment