Zmiana klasy wody

Warstwa przejściowa 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 zmian w zasobach wodnych;
  2. utwórz zgrupowany reduktor, który sumuje obszar każdej klasy przejścia w określonym regionie zainteresowania,
  3. utworzyć wykres podsumowujący obszar według klasy przejścia.

Podstawowa wizualizacja

W sekcji listy komponentów skryptu dodaj to stwierdzenie, które tworzy obiekt obrazu z 1 zakresem o nazwie transition:

Edytor kodu (JavaScript)

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

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

U dołu sekcji Warstwy mapy w skrypcie dodaj to polecenie, które dodaje nową warstwę mapy wyświetlającą klasy przejść:

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ę Mekongu, na którym widać duże zróżnicowanie przejść między klasami wód powierzchniowych.

Klucz mapy dla klas przejść to:

Wartość Symbol Etykieta
0 Nie woda
1 Trwałe
2 Nowe stałe
3 Utracono na stałe
4 Sezonowe
5 Nowe sezonowe
6 Utracone treści sezonowe
7 Przejście z umowy sezonowej na umowę na czas nieokreślony
8 Stałe na sezonowe
9 Efemeryczny stały
10 Efemeryczne sezonowe

Podsumowanie obszaru według klasy przejścia

W tej sekcji ponownie użyjemy narzędzia do tworzenia wielokątów, aby zdefiniować obszar zainteresowania. Jeśli chcesz przeanalizować nową lokalizację, najpierw wybierz i usuń pierwotny 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 Mekongu.

Klasy przejścia z ROI
Rysunek 11. Delta Mekongu 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 dodatkowe pasmo, które 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);

Obiekt obrazu wynikowego (area_image_with_transition_class) to obraz dwupasmowy, w którym pierwsze pasmo zawiera informacje o obszarze w metrach kwadratowych (uzyskane za pomocą metody ee.Image.pixelAreacode> ), a drugie pasmo zawiera informacje o klasie przejścia.

Następnie podsumowujemy przejścia między klasami w wybranym regionie (roi) za pomocą metody ee.Image.reduceRegion reduktora grupującego, który sumuje obszar w każdej klasie przejścia:

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);

Dane wyjściowe na karcie konsoli będą teraz zawierać znak reduction_results. Pamiętaj, że aby zobaczyć dane podsumowujące obszar, musisz rozwinąć drzewo o kilka poziomów.

Wyniki zgrupowanej redukcji
Rysunek 12. Dane wyjściowe karty Konsola pokazujące wyniki zgrupowanej redukcji.

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

Tworzenie wykresu podsumowującego

W tej sekcji utworzymy wykres, aby lepiej podsumować wyniki. Na początek 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 zgrupowanego reduktora (reduction_results) jest słownik zawierający listę słowników. Na liście znajduje się jeden słownik dla każdej klasy przejścia. Te instrukcje używają metody ee.Dictionary.get , aby wyodrębnić z tego słownika zgrupowane wyniki reduktora, i rzutują wyniki na typ danych ee.List , abyśmy mogli uzyskać dostęp do poszczególnych słowników.

Aby korzystać z  funkcji tworzenia wykresów w edytorze kodu, utworzymy obiekt FeatureCollection zawierający niezbędne informacje. W tym celu najpierw tworzymy 2 słowniki wyszukiwania i 2 funkcje pomocnicze. Kod tworzący 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 przypisuje wartości klasy przejścia do ich nazw, a słownik lookup_palette przypisuje wartości klasy przejścia do definicji kolorów.

Te 2 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 Feature odpowiedni do tworzenia wykresów. Funkcja createPieChartSliceDictionary tworzy listę kolorów, które odpowiadają klasom przejść, w formacie oczekiwanym przez wykres kołowy.

Następnie zastosujemy funkcję createFeature do każdego słownika na liście roi_stats, używając funkcji 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);

Mamy już obiekt FeatureCollection zawierający atrybuty, które chcemy wyświetlić na wykresie. Możemy teraz 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 powoduje pokolorowanie wycinków wykresu kołowego za pomocą domyślnej palety zdefiniowanej dla klas przejść (pokazanej wcześniej w tabeli legendy mapy). Opcja sliceVisibilityThreshold zapobiega grupowaniu małych wycinków w kategorii „Inne”. Wynikowy wykres powinien być podobny do tego na rysunku 13.

Wykres podsumowania zajęć z przejścia na pływanie
Rysunek 13. Wykres podsumowujący względne rozmiary klas przejść wody.

Skrypt końcowy

Cały skrypt tej sekcji to:

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ć tylko z 3 warstwami danych (występowanie, intensywność zmian i przejście) dostępnymi w zbiorze danych Global Surface Water. Więcej informacji o innych warstwach danych dostępnych w  Przewodniku dla użytkowników danych (wersja 2) znajdziesz w tym dokumencie.

Życzymy owocnych analiz.