Chapter 21: Data Correlation

This chapter provides a workflow to explore data correlation between vegetation and terrain in the Gabilan Range, California, United States. The full GEE code can be found here.

Functions

/**
 * Calculates and adds the NDVI band for Sentinel-2A
 */
function add_ndvi_s2(image) {
  return image.addBands(image.normalizedDifference(['B8', 'B4']).rename('NDVI'));
}

/**
 * Clips an image to the Gabilan Range, CA study area
 */
function clip_gabilan(image) {
  return image.clip(gabilan_range);
}

Data Acquisition & Preprocessing

// Define geometries
var gabilan_range =
    /* color: #5eff32 */
    /* shown: false */
    ee.Feature(
        ee.Geometry.Polygon(
            [[[-121.39209915128892, 36.41211982460723],
              [-121.40445877042954, 36.4270383353476],
              [-121.42780471769517, 36.43753482852815],
              [-121.43261123624985, 36.445820531007755],
              [-121.44977737394517, 36.45797129413855],
              [-121.48136306730454, 36.47785025501275],
              [-121.48960281339829, 36.4872357700071],
              [-121.51157546964829, 36.50489953730563],
              [-121.52256179777329, 36.52311107716474],
              [-121.53904128996079, 36.534698007435544],
              [-121.54728103605454, 36.55621198679144],
              [-121.57955337492173, 36.5733085705686],
              [-121.60907913175767, 36.59205531122498],
              [-121.6660707089061, 36.620717990097226],
              [-121.6825502010936, 36.62457561415858],
              [-121.69628311124985, 36.60252944801643],
              [-121.71962905851548, 36.58102836805629],
              [-121.75464797941392, 36.56999984966293],
              [-121.75602127042954, 36.554557277884626],
              [-121.75052810636704, 36.53690484497294],
              [-121.75602127042954, 36.526421805784025],
              [-121.75533462492173, 36.500483973199884],
              [-121.7484681698436, 36.49330814444738],
              [-121.71894241300767, 36.475641733322036],
              [-121.71070266691392, 36.46238928152319],
              [-121.68844847586017, 36.449460428394225],
              [-121.6458764543758, 36.44227987424441],
              [-121.61909727957111, 36.425154332654465],
              [-121.56828551199298, 36.39199739069815],
              [-121.57377867605548, 36.382600351332194],
              [-121.5634789934383, 36.37928347804693],
              [-121.53875975515705, 36.3411292687819],
              [-121.52777342703205, 36.337257506937185],
              [-121.5085473528133, 36.34278853636809],
              [-121.49962096121173, 36.3322792446237],
              [-121.48451476003986, 36.31346960497832],
              [-121.44194273855548, 36.26864011750132],
              [-121.42408995535236, 36.257013453780026],
              [-121.40211729910236, 36.270854523880075],
              [-121.36366515066486, 36.26587202121934],
              [-121.34993224050861, 36.27030092817272],
              [-121.33413939382892, 36.27030092817272],
              [-121.32246642019611, 36.28081857542688],
              [-121.30942015554767, 36.31291631156002],
              [-121.33345274832111, 36.39531372165556]]]),
        {
          "system:index": "0"
        }),

var test_region =
    /* color: #ff371b */
    /* shown: false */
    /* displayProperties: [
      {
        "type": "rectangle"
      }
    ] */
    ee.Geometry.Polygon(
        [[[-121.52367515823046, 36.43004814282859],
          [-121.52367515823046, 36.36372428812449],
          [-121.42342491408984, 36.36372428812449],
          [-121.42342491408984, 36.43004814282859]]], null, false);
// Get USGS National Elevation Dataset
var usgs_ned = ee.Image("USGS/NED");

// Clip elevation data to Gabilan Range, CA and create slope and aspect layers
var gabilan_range_elevation = usgs_ned.clip(gabilan_range);
var gabilan_range_slope = ee.Terrain.slope(gabilan_range_elevation);
var gabilan_range_aspect = ee.Terrain.aspect(gabilan_range_elevation);

print('Elevation:', gabilan_range_elevation);
print('Slope:', gabilan_range_slope);
print('Aspect:', gabilan_range_aspect);

// Get Sentinel-2A collection
var sentinel_2a = ee.ImageCollection("COPERNICUS/S2_SR");

// Get monthly median composites
var jun_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-06-01', '2019-06-30'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

var jul_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-07-01', '2019-07-31'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

var aug_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-08-01', '2019-08-31'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

var sep_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-09-01', '2019-09-30'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

var oct_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-10-01', '2019-10-31'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

var nov_2019 = sentinel_2a
  .filterBounds(gabilan_range.geometry())
  .filter(ee.Filter.date('2019-11-01', '2019-11-30'))
  .map(clip_gabilan)
  .map(add_ndvi_s2)
  .median();

Data Processing

// Create image for correlation analysis (single image with necesssary bands)
// Clip to area smaller than full study area so that the elevation and NDVI
//  layers have the same number of pixels (otherwise array shapes won't match,
//  causing the charts to fail)
var correlation_base = ee.Image([
  gabilan_range_aspect.select('aspect'),
  gabilan_range_slope.select('slope'),
  gabilan_range_elevation.select('elevation'),
  jun_2019.select('NDVI').rename('ndvi_jun'),
  jul_2019.select('NDVI').rename('ndvi_jul'),
  aug_2019.select('NDVI').rename('ndvi_aug'),
  sep_2019.select('NDVI').rename('ndvi_sep'),
  oct_2019.select('NDVI').rename('ndvi_oct'),
  nov_2019.select('NDVI').rename('ndvi_nov')
]).clip(test_region);
print('Correlation Image Base:', correlation_base);

// Reduce image to dictionary; band names as keys, pixel values in lists
var pixel_lists = correlation_base.reduceRegion(
  ee.Reducer.toList(),
  test_region,
  30 // Scaled to 30 for computation time       -->  90,000 elements per band
     // Using scale of 10 (Sentinel resolution) --> 820,000 elements per band
);
print('Pixel Lists:', pixel_lists);

Data Postprocessing

// No data postprocessing in this lab.

Data Visualization

// Set map
Map.setCenter(-121.563559, 36.461750, 10);
Map.setOptions('TERRAIN');

// Define Sentinel-2 RGB visualization parameters
var vis_params_s2_rgb = {
  'bands': ['B4', 'B3', 'B2'],
  'min': 0,
  'max': 2500
};

// Define NDVI visualization parameters
var vis_params_ndvi = {
  'min': -1,
  'max': 1,
  palette: ['blue', 'white', 'green']
// 'palette': ['red', 'yellow', 'green']
};

// Add terrain layers to map
Map.addLayer(
  gabilan_range_elevation,
  {
    min: 0.0,
    max: 1250.0,
    palette: [
      'blue',
      'green',
      'yellow',
      'orange',
      'red',
      'brown',
      'white'
    ]
  },
  'Elevation'
);


Map.addLayer(
  gabilan_range_slope,
  {
    min: 0.0,
    max: 60, // 90 is max
    palette: ['green', 'yellow', 'orange', 'red']
  },
  'Slope'
);

Map.addLayer(
  gabilan_range_aspect,
  {
    min: 0.0,
    max: 360,
    palette: [
      '#666666',
      '#bf5b17',
      '#f0027f',
      '#386cb0',
      '#ffff99',
      '#fdc086',
      '#beaed4',
      '#7fc97f'
    ]
  },
  'Aspect'
);

// Add image layers to map
Map.addLayer(jun_2019, vis_params_s2_rgb, 'June 2019 Median RGB');
Map.addLayer(jul_2019, vis_params_s2_rgb, 'July 2019 Median RGB');
Map.addLayer(aug_2019, vis_params_s2_rgb, 'August 2019 Median RGB');
Map.addLayer(sep_2019, vis_params_s2_rgb, 'September 2019 Median RGB');
Map.addLayer(oct_2019, vis_params_s2_rgb, 'October 2019 Median RGB');
Map.addLayer(nov_2019, vis_params_s2_rgb, 'November 2019 Median RGB');

// Add NDVI layers to map
Map.addLayer(jun_2019.select('NDVI'), vis_params_ndvi, 'June 2019 Median NDVI');
Map.addLayer(jul_2019.select('NDVI'), vis_params_ndvi, 'July 2019 Median NDVI');
Map.addLayer(aug_2019.select('NDVI'), vis_params_ndvi, 'August 2019 Median NDVI');
Map.addLayer(sep_2019.select('NDVI'), vis_params_ndvi, 'September 2019 Median NDVI');
Map.addLayer(oct_2019.select('NDVI'), vis_params_ndvi, 'October 2019 Median NDVI');
Map.addLayer(nov_2019.select('NDVI'), vis_params_ndvi, 'November 2019 Median NDVI');

// Select variables for plotting correlation
// Dependent (terrain)
var x_values_elevation = pixel_lists.get('elevation');
var x_values_slope = pixel_lists.get('slope');
var x_values_aspect = pixel_lists.get('aspect');

// Independent (NDVI)
var y_values_jun = ee.Array(pixel_lists.get('ndvi_jun'));
var y_values_jul = ee.Array(pixel_lists.get('ndvi_jul'));
var y_values_aug = ee.Array(pixel_lists.get('ndvi_aug'));
var y_values_sep = ee.Array(pixel_lists.get('ndvi_sep'));
var y_values_oct = ee.Array(pixel_lists.get('ndvi_oct'));
var y_values_nov = ee.Array(pixel_lists.get('ndvi_nov'));

// Create correlation charts (commented out due to display/processing time)
// Elevation
// var chart_ndvi_jun_elevation = ui.Chart.array.values(y_values_jun, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - June 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_jul_elevation = ui.Chart.array.values(y_values_jul, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - July 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_aug_elevation = ui.Chart.array.values(y_values_aug, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - August 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_sep_elevation = ui.Chart.array.values(y_values_sep, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - September 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_oct_elevation = ui.Chart.array.values(y_values_oct, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - October 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_nov_elevation = ui.Chart.array.values(y_values_nov, 0, x_values_elevation)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Elevation - November 2019',
//     hAxis: {'title': 'Elevation (meters)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// Slope
// var chart_ndvi_jun_slope = ui.Chart.array.values(y_values_jun, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - June 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_jul_slope = ui.Chart.array.values(y_values_jul, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - July 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_aug_slope = ui.Chart.array.values(y_values_aug, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - August 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_sep_slope = ui.Chart.array.values(y_values_sep, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - September 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_oct_slope = ui.Chart.array.values(y_values_oct, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - October 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_nov_slope = ui.Chart.array.values(y_values_nov, 0, x_values_slope)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Slope - November 2019',
//     hAxis: {'title': 'Slope (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// Aspect
// var chart_ndvi_jun_aspect = ui.Chart.array.values(y_values_jun, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - June 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_jul_aspect = ui.Chart.array.values(y_values_jul, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - July 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_aug_aspect = ui.Chart.array.values(y_values_aug, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - August 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_sep_aspect = ui.Chart.array.values(y_values_sep, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - September 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_oct_aspect = ui.Chart.array.values(y_values_oct, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - October 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// var chart_ndvi_nov_aspect = ui.Chart.array.values(y_values_nov, 0, x_values_aspect)
//   .setSeriesNames(['NDVI'])
//   .setOptions({
//     title: 'Sentinel-2A Median NDVI vs. NED Aspect - November 2019',
//     hAxis: {'title': 'Aspect (degrees)'},
//     vAxis: {'title': 'NDVI'},
//     pointSize: 3,
// });

// Display correlation charts (commented out due to display/processing time)
// Elevation
// print(chart_ndvi_jun_elevation);
// print(chart_ndvi_jul_elevation);
// print(chart_ndvi_aug_elevation);
// print(chart_ndvi_sep_elevation);
// print(chart_ndvi_oct_elevation);
// print(chart_ndvi_nov_elevation);

// Slope
// print(chart_ndvi_jun_slope);
// print(chart_ndvi_jul_slope);
// print(chart_ndvi_aug_slope);
// print(chart_ndvi_sep_slope);
// print(chart_ndvi_oct_slope);
// print(chart_ndvi_nov_slope);

// Aspect
// print(chart_ndvi_jun_aspect);
// print(chart_ndvi_jul_aspect);
// print(chart_ndvi_aug_aspect);
// print(chart_ndvi_sep_aspect);
// print(chart_ndvi_oct_aspect);
// print(chart_ndvi_nov_aspect);

Data Export

// No data export in this lab.