מעבר בין סוגי מים

שכבת המעבר של המים מתעדת שינויים בין שלוש קטגוריות של הימצאות מים (ללא מים, מים עונתיים ומים קבועים) וגם שתי קטגוריות נוספות של מים זמניים (מים קבועים זמניים ומים עונתיים זמניים).

בחלק הזה של המדריך נסביר:

  1. להוסיף שכבה במפה כדי להציג את השינויים במים,
  2. יוצרים רדיוסר מקובץ כדי לסכם את השטח של כל סוג מעבר בתוך אזור עניין מסוים, וגם
  3. ליצור תרשים שמסכם את השטח לפי סוג המעבר.

תרשים בסיסי להמחשה

בקטע Asset List (רשימת נכסים) של הסקריפט, מוסיפים את ההצהרה הבאה שיוצרת אובייקט תמונה עם פס אחד בשם transition:

Code Editor (JavaScript)

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

התמונות של GSW מכילות מטא-נתונים על המספרים והשמות של מחלקות המעבר, ופלטת צבעים שמוגדרת כברירת מחדל לעיצוב של מחלקות המעבר. כששכבת המעבר תתווסף למפה, המערכת תשתמש בפרמטרים האלה של התצוגה החזותית באופן אוטומטי.

בחלק התחתון של הקטע Map Layers בסקריפט, מוסיפים את ההצהרה הבאה שמוסיפה שכבה חדשה במפה שמציגה את מחלקות המעבר:

Code Editor (JavaScript)

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

כשמריצים את הסקריפט, שכבת המעבר מוצגת.

שינויים במים עיליים
איור 10. צילום מסך של הדלתא של נהר המקונג, שבו מוצג מגוון רחב של מעברים בין סוגי מים עיליים.

מקרא המפה של כיתות המעבר:

ערך סמל תווית
0 לא מים
1 קבוע
2 קבוע חדש
3 אובדן קבוע
4 עונתי
5 עונתי חדש
6 עונתיות
7 עונתי עד קבוע
8 ממשרה קבועה למשרה עונתית
9 זמני קבוע
10 עונתיות זמנית

סיכום האזור לפי סיווג המעבר

בקטע הזה נשתמש שוב בכלי הגיאומטריה של הפוליגון כדי להגדיר אזור עניין. אם רוצים לנתח מיקום חדש, קודם צריך לבחור ולמחוק את המצולע המקורי שצויר, כדי לא לקבל תוצאות מהאזורים המשולבים. בקטע כלי גיאומטריה במסמכי התיעוד של עורך הקוד מוסבר איך לשנות גיאומטריות.

בדוגמה הזו נשרטט פוליגון חדש בדלתא של נהר המקונג.

שיעורי מעבר עם החזר ROI
איור 11. הדלתא של נהר המקונג בווייטנאם, עם אזור עניין שנוצר באמצעות כלי השרטוט של פוליגונים ב-Code Editor.

כדי לחשב את השטח שמכוסה על ידי חלקים של תמונה, נוסיף פס נוסף לאובייקט התמונה של המעבר, שמזהה את הגודל של כל פיקסל במטרים רבועים באמצעות השיטה ee.Image.pixelArea.

Code Editor (JavaScript)

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

אובייקט התמונה שנוצר (area_image_with_transition_class) הוא תמונה עם שני פסים, כשהפס הראשון מכיל את פרטי האזור ביחידות של מטרים רבועים (שנוצרו על ידי השיטה ee.Image.pixelArea ), והפס השני מכיל את פרטי סיווג המעבר.

לאחר מכן, אנחנו מסכמים את המעברים בין המחלקות באזור העניין (roi) באמצעות השיטה ee.Image.reduceRegion ו- grouped reducer (מפחית מקובץ) שמסכם את השטח בכל מחלקת מעבר:

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

הפלט בכרטיסיית המסוף מציג עכשיו את reduction_results. שימו לב שצריך להרחיב את העץ בכמה רמות כדי לראות את נתוני הסיכום של האזור.

תוצאות של צמצום מקובץ
איור 12. פלט בכרטיסייה Console, שבו מוצגות התוצאות של ההפחתה המקובצת.

האובייקט reduction_results מכיל מידע על האזור שכל מחלקת מעבר מכסה, אבל לא קל לקרוא אותו. בקטע הבא נסביר איך אפשר לראות את התוצאות בקלות.

יצירת תרשים סיכום

בקטע הזה ניצור תרשים כדי לסכם את התוצאות בצורה טובה יותר. כדי להתחיל, קודם נחלץ את רשימת מחלקות המעבר עם האזורים באופן הבא:

Code Editor (JavaScript)

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

התוצאה של המפחית המקובץ (reduction_results) היא מילון שמכיל רשימה של מילונים. ברשימה יש מילון אחד לכל סוג מעבר. ההצהרות האלה משתמשות בשיטה ee.Dictionary.get כדי לחלץ את תוצאות המפחית המקובצות מהמילון הזה, וממירות את התוצאות לסוג נתונים ee.List כדי שנוכל לגשת למילונים הנפרדים.

כדי להשתמש ב פונקציות התרשימים של עורך הקוד, ניצור FeatureCollection שמכיל את המידע הדרוש. כדי לעשות את זה, קודם יוצרים שני מילוני חיפוש ושתי פונקציות עזר. אפשר להציב את הקוד שיוצר את מילוני החיפוש בחלק העליון של הקטע "חישובים", באופן הבא:

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

המילון lookup_names משייך ערכים של מחלקות מעבר לשמות שלהם, והמילון lookup_palette משייך ערכים של מחלקות מעבר להגדרות של צבעים.

אפשר להציב את שתי פונקציות העזר בקטע קוד חדש שנקרא "פונקציות עזר".

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

הפונקציה createFeature מקבלת מילון (שמכיל את האזור ואת סיווג המעבר של המים) ומחזירה ישות שמתאימה לתרשים. הפונקציה createPieChartSliceDictionary יוצרת רשימה של צבעים שתואמים לסוגי המעברים, בפורמט שנדרש לתרשים העוגה.

בשלב הבא, נפעיל את הפונקציה createFeature על כל מילון ברשימה (roi_stats), באמצעות ee.List.map כדי להפעיל את פונקציית העזר על כל רכיב ברשימה.

Code Editor (JavaScript)

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

עכשיו, כשיש לנו FeatureCollection שמכיל את המאפיינים שאנחנו רוצים להציג בתרשים, אנחנו יכולים ליצור אובייקט של תרשים ולהדפיס אותו במסוף.

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

האפשרות slices צובעת את הפלחים בתרשים העוגה כך שהם משתמשים בלוח הצבעים שמוגדר כברירת מחדל לסיווגי המעבר (הוצג קודם בטבלת מקרא המפה). האפשרות sliceVisibilityThreshold מונעת קיבוץ של פרוסות קטנות יחד לקטגוריה "אחר". התרשים שנוצר אמור להיות דומה לתרשים שמוצג באיור 13.

תרשים סיכום של סיווג המעבר של המים
איור 13. תרשים שמסכם את הגודל היחסי של סוגי המעבר של המים.

התסריט הסופי

התסריט המלא של הקטע הזה הוא:

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

כאן מסתיים המדריך בנושא מערך הנתונים Global Surface Water. שימו לב שבמדריך הזה הראינו איך לעבוד רק עם שלוש משכבות הנתונים (התרחשות, עוצמת השינוי ומעבר) שזמינות במערך הנתונים של Global Surface Water. אפשר לקרוא על שכבות הנתונים האחרות שזמינות ב מדריך למשתמשים בנתונים (גרסה 2).

בהצלחה בהמשך הדרך!