Zmiana klasy wody

Warstwa przejścia wody rejestruje zmiany między 3 klasami występowania wody (brak wody, woda sezonowa i woda stała) oraz 2 dodatkowymi klasami wody efemerycznej (efemeryczna stała i efemeryczna sezonowa).

W tej części samouczka:

  1. dodać warstwę mapy do wizualizacji przejścia wody,
  2. utworzyć reduktor grupowany, aby zsumować obszar każdej klasy przejścia w określonym regionie zainteresowania, oraz
  3. utworzyć wykres podsumowujący obszar według klasy przejścia.

Podstawowa wizualizacja

W sekcji Asset List (Lista zasobów) skryptu dodaj następującą instrukcję, która tworzy obiekt obrazu z jednym pasmem o nazwie transition:

Edytor kodu (JavaScript)

var transition = gsw.select('transition');

Obrazy GSW zawierają metadane dotyczące numerów i nazw klas przejścia oraz domyślną paletę do stylizowania klas przejścia. Gdy warstwa przejścia zostanie dodana do mapy, te parametry wizualizacji zostaną użyte automatycznie.

Na dole sekcji Map Layers (Warstwy mapy) skryptu dodaj następującą instrukcję, która dodaje nową warstwę mapy wyświetlającą klasy przejścia:

Edytor kodu (JavaScript)

Map.setCenter(105.26, 11.2134, 9);     // Mekong River Basin, SouthEast Asia
Map.addLayer({
  eeObject: transition,
  name: 'Transition classes (1984-2015)',
});

Po uruchomieniu skryptu wyświetli się warstwa przejścia.

Klasy przejścia wód powierzchniowych
Rysunek 10. Zrzut ekranu przedstawiający deltę rzeki Mekong, na którym widać duże zróżnicowanie zmian klas wody powierzchniowej.

Klucz mapy dla klas przejścia to:

Wartość Symbol Etykieta
0 Nie woda
1 Na stałe
2 Nowy stały
3 Utrata stała
4 Sezonowe
5 Nowe sezonowe
6 Utracone sezonowe
7 Sezonowe na stałe
8 Stałe na sezonowe
9 Tymczasowa lub stała
10 Efemeryczna sezonowa

Podsumowanie obszaru według klasy przejścia

W tej sekcji ponownie użyjemy narzędzia do tworzenia wielokątów geometrycznych, aby zdefiniować region zainteresowania. Jeśli chcesz przeanalizować nową lokalizację, najpierw wybierz i usuń pierwotnie narysowany wielokąt, aby nie otrzymywać wyników z połączonych obszarów. Informacje o modyfikowaniu geometrii znajdziesz w sekcji Narzędzia do geometrii w dokumentacji edytora kodu.

W tym przykładzie narysujemy nowy wielokąt w delcie rzeki Mekong.

Zajęcia przejściowe z ROI
Rysunek 11. Delta rzeki Mekong w Wietnamie z obszarem zainteresowania utworzonym za pomocą narzędzia do rysowania wielokątów w edytorze kodu.

Aby obliczyć obszar pokryty przez części obrazu, dodamy do obiektu obrazu przejścia dodatkowy pas, który określa rozmiar każdego piksela w metrach kwadratowych za pomocą metody ee.Image.pixelArea.

Edytor kodu (JavaScript)

var area_image_with_transition_class = ee.Image.pixelArea().addBands(transition);

Wynikowy obiekt obrazu (area_image_with_transition_class) to obraz dwupasmowy, w którym pierwsze pasmo zawiera informacje o obszarze w jednostkach metrów kwadratowych (wygenerowane przez metodę ee.Image.pixelArea ), a drugie pasmo zawiera informacje o klasie przejścia.

Następnie podsumowujemy zmiany klas w interesującym nas regionie (roi) za pomocą metody ee.Image.reduceRegion i  grupowanego reduktora , który sumuje obszar w każdej klasie zmian:

Edytor kodu (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);

Na karcie konsoli wyświetli się teraz reduction_results. Pamiętaj, że aby zobaczyć dane podsumowania obszaru, musisz rozwinąć drzewo o kilka poziomów.

Wyniki redukcji pogrupowanej
Rysunek 12. Dane wyjściowe na karcie konsoli, pokazujące wyniki redukcji pogrupowanej.

Obiekt reduction_results zawiera informacje o obszarze objętym każdą klasą przejścia, ale nie jest on zbyt łatwy do odczytania. W następnej sekcji ułatwimy wyświetlanie wyników.

Tworzenie wykresu podsumowującego

W tej sekcji utworzymy wykres, który pozwoli lepiej podsumować wyniki. Najpierw wyodrębniamy listę klas przejścia z obszarami w ten sposób:

Edytor kodu (JavaScript)

var roi_stats = ee.List(reduction_results.get('groups'));

Wynikiem działania reduktora grupowego (reduction_results) jest słownik zawierający listę słowników. Na liście znajduje się po 1 słowniku dla każdej klasy przejścia. Te instrukcje używają metody ee.Dictionary.get , aby wyodrębnić z tego słownika wyniki zgrupowanego reduktora i rzutować je na typ danych ee.List, dzięki czemu możemy uzyskać dostęp do poszczególnych słowników.

Aby skorzystać z funkcji tworzenia wykresów w edytorze kodu, utworzymy kolekcję obiektów zawierającą niezbędne informacje. W tym celu najpierw tworzymy 2 słowniki wyszukiwania i 2 funkcje pomocnicze. Kod, który tworzy słowniki wyszukiwania, można umieścić u góry sekcji „Obliczenia” w ten sposób:

Edytor kodu (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')
);

Słownik lookup_names wiąże wartości klas przejścia z ich nazwami, a słownik lookup_palette wiąże wartości klas przejścia z definicjami kolorów.

Obie funkcje pomocnicze można umieścić w nowej sekcji kodu o nazwie „Funkcje pomocnicze”.

Edytor kodu (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();
}

Funkcja createFeature przyjmuje słownik (zawierający obszar i klasę przejścia wody) i zwraca obiekt odpowiedni do utworzenia wykresu. Funkcja createPieChartSliceDictionary tworzy listę kolorów odpowiadających klasom przejścia, używając formatu oczekiwanego przez wykres kołowy.

Następnie zastosujemy funkcję createFeature do każdego słownika na liście (roi_stats), używając ee.List.map, aby zastosować funkcję pomocniczą do każdego elementu listy.

Edytor kodu (JavaScript)

var transition_fc = ee.FeatureCollection(roi_stats.map(createFeature));
print('transition_fc', transition_fc);

Teraz, gdy mamy kolekcję FeatureCollection zawierającą atrybuty, które chcemy wyświetlić na wykresie, możemy utworzyć obiekt wykresu i wydrukować go w konsoli.

Edytor kodu (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);

Opcja slices koloruje wycinki wykresu kołowego, tak aby używały domyślnej palety zdefiniowanej dla klas przejścia (pokazanej wcześniej w tabeli kluczy mapy). Opcja sliceVisibilityThreshold zapobiega grupowaniu małych wycinków w kategorii „Inne”. Powstały wykres powinien wyglądać podobnie do tego na rysunku 13.

Wykres podsumowujący klasy przejścia wody
Rysunek 13. Wykres podsumowujący względny rozmiar klas przejścia wody.

Final Script

Cały skrypt dla tej sekcji:

Edytor kodu (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)',
});

To koniec samouczka dotyczącego zbioru danych Global Surface Water. Pamiętaj, że w tym samouczku pokazaliśmy, jak pracować z zaledwie 3 warstwami danych (występowanie, intensywność zmian i przejście), które są dostępne w zbiorze danych Global Surface Water. Informacje o innych dostępnych warstwach danych znajdziesz w  przewodniku użytkownika danych (wersja 2).

Życzymy owocnych analiz.