The water transition layer captures changes between three classes of water occurrence (not water, seasonal water, and permanent water) along with two additional classes for ephemeral water (ephemeral permanent and ephemeral seasonal).
This section of the tutorial will:
- add a map layer for visualizing water transition,
- create a grouped reducer for summing the area of each transition class within a specified region-of-interest, and
- create a chart that summarizes the area by transition class.
Basic Visualization
In the Asset List section of the script, add the following statement which creates
a single band image object called transition
:
Code Editor (JavaScript)
var transition = gsw.select('transition');
The GSW images contain metadata on the transition class numbers and names, and a default palette for styling the transition classes. When the transition layer is added to the map, these visualization parameters will be used automatically.
At the bottom of the Map Layers section of your script, add the following statement which adds a new map layer that displays the transition classes:
Code Editor (JavaScript)
Map.setCenter(105.26, 11.2134, 9); // Mekong River Basin, SouthEast Asia Map.addLayer({ eeObject: transition, name: 'Transition classes (1984-2015)', });
When you run the script, the transition layer will be displayed.
The map key for the transition classes is:
Value | Symbol | Label |
---|---|---|
0 | Not water | |
1 | Permanent | |
2 | New permanent | |
3 | Lost permanent | |
4 | Seasonal | |
5 | New seasonal | |
6 | Lost seasonal | |
7 | Seasonal to permanent | |
8 | Permanent to seasonal | |
9 | Ephemeral permanent | |
10 | Ephemeral seasonal |
Summarizing Area by Transition Class
In this section we will once again use the geometry polygon tool to define a region-of-interest. If you want to analyze a new location, you will want to first select and delete the original polygon that you drew so that you don't get results from the combined areas. See the Geometry tools section of the Code Editor docs from information on how to modify geometries.
For this example we will draw a new polygon within the Mekong River delta.
In order to calculate the area covered by parts of an image, we will add an additional band to the transition image object that identifies the size of each pixel in square meters using the ee.Image.pixelArea method.
Code Editor (JavaScript)
var area_image_with_transition_class = ee.Image.pixelArea().addBands(transition);
The resulting image object (area_image_with_transition_class
) is a two band
image where the first band contains the area information in units of square meters
(produced by the
ee.Image.pixelArea
code>
method), and the second band contains the transition class information.
We then summarize the class transitions within a region of interest (roi
) using the
ee.Image.reduceRegion
method and a
grouped reducer
which acts to sum up the area within each transition class:
Code Editor (JavaScript)
var reduction_results = area_image_with_transition_class.reduceRegion({ reducer: ee.Reducer.sum().group({ groupField: 1, groupName: 'transition_class_value', }), geometry: roi, scale: 30, bestEffort: true, }); print('reduction_results', reduction_results);
The console tab output now displays the reduction_results
. Note that you will
need to expand the tree a few levels to see the area summary data.
While the reduction_results
object does contain information on the area
covered by each transition class, it is not particularly easy to read. In the next section
we will make it easier to view the results.
Creating a Summary Chart
In this section we will make a chart to better summarize the results. To get started, we first extract out the list of transition classes with areas as follows:
Code Editor (JavaScript)
var roi_stats = ee.List(reduction_results.get('groups'));
The result of the grouped reducer (reduction_results
) is a dictionary containing
a list of dictionaries.
There is one dictionary in the list for each transition class.
These statements use the
ee.Dictionary.get
method to extract the grouped reducer results from that dictionary and casts
the results to an
ee.List
data type, so we can access the individual dictionaries.
In order to make use of the charting functions of the Code Editor, we will build a FeatureCollection that contains the necessary information. To do this we first create two lookup dictionaries and two helper functions. The code that creates the lookup dictionaries can be placed at the top of the "Calculations" section as follows:
Code Editor (JavaScript)
////////////////////////////////////////////////////////////// // Calculations ////////////////////////////////////////////////////////////// // Create a dictionary for looking up names of transition classes. var lookup_names = ee.Dictionary.fromLists( ee.List(gsw.get('transition_class_values')).map(numToString), gsw.get('transition_class_names') ); // Create a dictionary for looking up colors of transition classes. var lookup_palette = ee.Dictionary.fromLists( ee.List(gsw.get('transition_class_values')).map(numToString), gsw.get('transition_class_palette') );
The lookup_names
dictionary associates transition class values with their
names, while the lookup_palette
dictionary associates the transition class
values with color definitions.
The two helper functions can be placed in a new code section called "Helper functions".
Code Editor (JavaScript)
//////////////////////////////////////////////////////////////
// Helper functions
//////////////////////////////////////////////////////////////
// Create a feature for a transition class that includes the area covered.
function createFeature(transition_class_stats) {
transition_class_stats = ee.Dictionary(transition_class_stats);
var class_number = transition_class_stats.get('transition_class_value');
var result = {
transition_class_number: class_number,
transition_class_name: lookup_names.get(class_number),
transition_class_palette: lookup_palette.get(class_number),
area_m2: transition_class_stats.get('sum')
};
return ee.Feature(null, result); // Creates a feature without a geometry.
}
// Create a JSON dictionary that defines piechart colors based on the
// transition class palette.
// https://developers.google.com/chart/interactive/docs/gallery/piechart
function createPieChartSliceDictionary(fc) {
return ee.List(fc.aggregate_array("transition_class_palette"))
.map(function(p) { return {'color': p}; }).getInfo();
}
// Convert a number to a string. Used for constructing dictionary key lists
// from computed number objects.
function numToString(num) {
return ee.Number(num).format();
}
The function createFeature
takes a dictionary (containing the area and the
water transition class) and returns a Feature suitable for charting.
The function createPieChartSliceDictionary
creates a list of colors that
correspond to the transition classes, using the format expected by the pie chart.
Next, we will apply the createFeature
function over each dictionary in the
list (roi_stats
), using
ee.List.map
to apply the helper function to each element of the list.
Code Editor (JavaScript)
var transition_fc = ee.FeatureCollection(roi_stats.map(createFeature)); print('transition_fc', transition_fc);
Now that we have a FeatureCollection containing the attributes we want to display on the chart, we can create a chart object and print it to the console.
Code Editor (JavaScript)
// Add a summary chart. var transition_summary_chart = ui.Chart.feature.byFeature({ features: transition_fc, xProperty: 'transition_class_name', yProperties: ['area_m2', 'transition_class_number'] }) .setChartType('PieChart') .setOptions({ title: 'Summary of transition class areas', slices: createPieChartSliceDictionary(transition_fc), sliceVisibilityThreshold: 0 // Don't group small slices. }); print(transition_summary_chart);
The slices
option colors the pie chart slices so that they use the
default palette defined for the transition classes (shown earlier in the map key table).
The sliceVisibilityThreshold
option prevents small slices from being grouped
together into an "other" category.
The resulting chart should be something similar to the one shown in Figure 13.
Final Script
The entire script for this section is:
Code Editor (JavaScript)
////////////////////////////////////////////////////////////// // Asset List ////////////////////////////////////////////////////////////// var gsw = ee.Image('JRC/GSW1_0/GlobalSurfaceWater'); var occurrence = gsw.select('occurrence'); var change = gsw.select("change_abs"); var transition = gsw.select('transition'); var roi = ee.Geometry.Polygon( [[[105.531921, 10.412183], [105.652770, 10.285193], [105.949401, 10.520218], [105.809326, 10.666006]]]); ////////////////////////////////////////////////////////////// // Constants ////////////////////////////////////////////////////////////// var VIS_OCCURRENCE = { min: 0, max: 100, palette: ['red', 'blue'] }; var VIS_CHANGE = { min: -50, max: 50, palette: ['red', 'black', 'limegreen'] }; var VIS_WATER_MASK = { palette: ['white', 'black'] }; ////////////////////////////////////////////////////////////// // Helper functions ////////////////////////////////////////////////////////////// // Create a feature for a transition class that includes the area covered. function createFeature(transition_class_stats) { transition_class_stats = ee.Dictionary(transition_class_stats); var class_number = transition_class_stats.get('transition_class_value'); var result = { transition_class_number: class_number, transition_class_name: lookup_names.get(class_number), transition_class_palette: lookup_palette.get(class_number), area_m2: transition_class_stats.get('sum') }; return ee.Feature(null, result); // Creates a feature without a geometry. } // Create a JSON dictionary that defines piechart colors based on the // transition class palette. // https://developers.google.com/chart/interactive/docs/gallery/piechart function createPieChartSliceDictionary(fc) { return ee.List(fc.aggregate_array("transition_class_palette")) .map(function(p) { return {'color': p}; }).getInfo(); } // Convert a number to a string. Used for constructing dictionary key lists // from computed number objects. function numToString(num) { return ee.Number(num).format(); } ////////////////////////////////////////////////////////////// // Calculations ////////////////////////////////////////////////////////////// // Create a dictionary for looking up names of transition classes. var lookup_names = ee.Dictionary.fromLists( ee.List(gsw.get('transition_class_values')).map(numToString), gsw.get('transition_class_names') ); // Create a dictionary for looking up colors of transition classes. var lookup_palette = ee.Dictionary.fromLists( ee.List(gsw.get('transition_class_values')).map(numToString), gsw.get('transition_class_palette') ); // Create a water mask layer, and set the image mask so that non-water areas // are transparent. var water_mask = occurrence.gt(90).mask(1); // Generate a histogram object and print it to the console tab. var histogram = ui.Chart.image.histogram({ image: change, region: roi, scale: 30, minBucketWidth: 10 }); histogram.setOptions({ title: 'Histogram of surface water change intensity.' }); print(histogram); // Summarize transition classes in a region of interest. var area_image_with_transition_class = ee.Image.pixelArea().addBands(transition); var reduction_results = area_image_with_transition_class.reduceRegion({ reducer: ee.Reducer.sum().group({ groupField: 1, groupName: 'transition_class_value', }), geometry: roi, scale: 30, bestEffort: true, }); print('reduction_results', reduction_results); var roi_stats = ee.List(reduction_results.get('groups')); var transition_fc = ee.FeatureCollection(roi_stats.map(createFeature)); print('transition_fc', transition_fc); // Add a summary chart. var transition_summary_chart = ui.Chart.feature.byFeature({ features: transition_fc, xProperty: 'transition_class_name', yProperties: ['area_m2', 'transition_class_number'] }) .setChartType('PieChart') .setOptions({ title: 'Summary of transition class areas', slices: createPieChartSliceDictionary(transition_fc), sliceVisibilityThreshold: 0 // Don't group small slices. }); print(transition_summary_chart); ////////////////////////////////////////////////////////////// // Initialize Map Location ////////////////////////////////////////////////////////////// // Uncomment one of the following statements to center the map on // a particular location. // Map.setCenter(-90.162, 29.8597, 10); // New Orleans, USA // Map.setCenter(-114.9774, 31.9254, 10); // Mouth of the Colorado River, Mexico // Map.setCenter(-111.1871, 37.0963, 11); // Lake Powell, USA // Map.setCenter(149.412, -35.0789, 11); // Lake George, Australia Map.setCenter(105.26, 11.2134, 9); // Mekong River Basin, SouthEast Asia // Map.setCenter(90.6743, 22.7382, 10); // Meghna River, Bangladesh // Map.setCenter(81.2714, 16.5079, 11); // Godavari River Basin Irrigation Project, India // Map.setCenter(14.7035, 52.0985, 12); // River Oder, Germany & Poland // Map.setCenter(-59.1696, -33.8111, 9); // Buenos Aires, Argentina // Map.setCenter(-74.4557, -8.4289, 11); // Ucayali River, Peru ////////////////////////////////////////////////////////////// // Map Layers ////////////////////////////////////////////////////////////// Map.addLayer({ eeObject: water_mask, visParams: VIS_WATER_MASK, name: '90% occurrence water mask', shown: false }); Map.addLayer({ eeObject: occurrence.updateMask(occurrence.divide(100)), name: "Water Occurrence (1984-2015)", visParams: VIS_OCCURRENCE, shown: false }); Map.addLayer({ eeObject: change, visParams: VIS_CHANGE, name: 'occurrence change intensity', shown: false }); Map.addLayer({ eeObject: transition, name: 'Transition classes (1984-2015)', });
This concludes the tutorial on the Global Surface Water dataset. Note that this tutorial has shown how to work with just three of the data layers (occurrence, change intensity, and transition) that are available in the Global Surface Water dataset. You can read about the other data layers that are available in the Data Users Guide (v2).
Happy analyzing!