Visualizing Dynamic World#
Dynamic World data provide a global near-real time monitoring solution for land cover and land use change
Each Sentinel-2 image tile has a corresponding output
This notebook will run through how to utilize geeViz to visualize and summarize Dynamic World data
Copyright 2024 Ian Housman
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
try:
import geeViz.geeView as geeView
except:
!python -m pip install geeViz
import geeViz.geeView as geeView
ee = geeView.ee
Map = geeView.Map
Map.port = 1234
print('done')
Initializing GEE
Cached project id file path: C:\Users\ihousman\.config\earthengine\credentials.proj_id
Cached project id: lcms-292214
Successfully initialized
geeViz package folder: c:\Users\ihousman\AppData\Local\Programs\Python\Python311\Lib\site-packages\geeViz
done
Make a basic viewer#
First, we’ll adapt the example script to use geeViz
Adapted from: https://code.earthengine.google.com/?scriptPath=Examples%3ADatasets%2FGOOGLE%2FGOOGLE_DYNAMICWORLD_V1
Map.clearMapLayers()
# Construct a collection of corresponding Dynamic World and Sentinel-2 for
# inspection. Filter the DW and S2 collections by region and date.
START = ee.Date('2021-04-02')
END = START.advance(1, 'day')
colFilter = ee.Filter.And(
ee.Filter.bounds(ee.Geometry.Point(20.6729, 52.4305)),
ee.Filter.date(START, END))
dwCol = ee.ImageCollection('GOOGLE/DYNAMICWORLD/V1').filter(colFilter)
s2Col = ee.ImageCollection('COPERNICUS/S2').filter(colFilter)
# Join corresponding DW and S2 images (by system:index).
DwS2Col = ee.Join.saveFirst('s2_img').apply(dwCol, s2Col,
ee.Filter.equals(**{'leftField': 'system:index', 'rightField': 'system:index'}))
# Extract an example DW image and its source S2 image.
dwImage = ee.Image(DwS2Col.first())
s2Image = ee.Image(dwImage.get('s2_img'))
# Create a visualization that blends DW class label with probability.
# Define list pairs of DW LULC label and color.
CLASS_NAMES = [
'water', 'trees', 'grass', 'flooded_vegetation', 'crops',
'shrub_and_scrub', 'built', 'bare', 'snow_and_ice']
VIS_PALETTE = [
'419bdf', '397d49', '88b053', '7a87c6', 'e49635', 'dfc35a', 'c4281b',
'a59b8f', 'b39fe1']
# Create an RGB image of the label (most likely class) on [0, 1].
dwRgb = dwImage.select('label').visualize(**{'min': 0, 'max': 8, 'palette': VIS_PALETTE}).divide(255)
# Get the most likely class probability.
top1Prob = dwImage.select(CLASS_NAMES).reduce(ee.Reducer.max())
# Create a hillshade of the most likely class probability on [0, 1];
top1ProbHillshade =ee.Terrain.hillshade(top1Prob.multiply(100)).divide(255)
# Combine the RGB image with the hillshade.
dwRgbHillshade = dwRgb.multiply(top1ProbHillshade);
# Display the Dynamic World visualization with the source Sentinel-2 image.
Map.setCenter(20.6729, 52.4305, 12)
Map.addLayer(
s2Image, {'min': 0, 'max': 3000, 'bands': ['B4', 'B3', 'B2']}, 'Sentinel-2 L1C');
Map.addLayer(
dwRgbHillshade, {'min': 0, 'max': 0.65}, 'Dynamic World V1 - label hillshade');
Map.turnOnInspector()
Map.view()
c:\Users\ihousman\AppData\Local\Programs\Python\Python311\Lib\site-packages\ee\deprecation.py:207: DeprecationWarning:
Attention required for COPERNICUS/S2! You are using a deprecated asset.
To ensure continued functionality, please update it.
Learn more: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2
warnings.warn(warning, category=DeprecationWarning)
Adding layer: Sentinel-2 L1C
Adding layer: Dynamic World V1 - label hillshade
Starting webmap
Using default refresh token for geeView
Starting local web server at: http://localhost:1234/geeView/
HTTP server command: "c:\Users\ihousman\AppData\Local\Programs\Python\Python311\python.exe" -m http.server 1234
Done
cwd a:\GEE\gee_py_modules_package\geeViz\examples
geeView URL: http://localhost:1234/geeView/?projectID=lcms-292214&accessToken=ya29.a0AcM612yGCqy4-XqRhQqvY_FFaYjrnoQatPaJ93ai0qIqeAtYt_yKOa0_PpRTbgMjzSmUyCEDWYS-gLn4UNL5NmPWwC1KgxJGVhOfj0FTG-s5FEnuukGbvLRYZVH1lMJsFYiIMhaKb9PgfcAwbxVxFjs8l_fuccsBd75lQBepoQMaCgYKAasSARESFQHGX2Mi1F_7ZzfGG7VXwGv70He2qQ0178
Visualizing Dynamic World over time#
Next, we’ll visualize Dynamic World as a seasonal time lapse and summarize zonal stats
geeViz streamlines calculating and exporting statistics
Once the map loads, you can use the
TOOLS
underArea Tools
to generate chartsCharts can be downloaded as a PNG and the underlying data can be downloaded as a CSV
This example can take some time to load
Map.clearMap()
Map.turnOffLayersWhenTimeLapseIsOn = False # Set this to False to avoid layers automatically turning off when a time lapse is turned on
class_band_name = 'label'
# Specify where to visualize
study_area = ee.Geometry.Polygon(
[[[4.9269985485747725, 61.11936200243072],
[4.9269985485747725, 60.187959630772305],
[7.2561001110747725, 60.187959630772305],
[7.2561001110747725, 61.11936200243072]]], None, False)
# Which years to include
startYear = 2018
endYear = 2023
# Number of months to include in each frame of the time lapse
nMonths = 3
# Provide visualization info
viz_dict = {f'{class_band_name}_class_names': [
'water', 'trees', 'grass', 'flooded_vegetation', 'crops',
'shrub_and_scrub', 'built', 'bare', 'snow_and_ice'],
f'{class_band_name}_class_palette': [
'419bdf', '397d49', '88b053', '7a87c6', 'e49635', 'dfc35a', 'c4281b',
'a59b8f', 'b39fe1'],
f'{class_band_name}_class_values':list(range(0,9))
}
# Get DW
dwCol = ee.ImageCollection('GOOGLE/DYNAMICWORLD/V1')\
.filterBounds(study_area)\
.filter(ee.Filter.calendarRange(startYear,endYear,'year'))\
.select([class_band_name])
# Pull projection for area charting
proj = dwCol.first().projection().getInfo()
crs = proj['crs']
transform = proj['transform']
# Create seasonal mode composites
def getMonths(imgs,yr,startMonth):
startMonth = ee.Number(startMonth)
endMonth = startMonth.add(nMonths).subtract(1)
date = ee.Date.fromYMD(yr,startMonth,1)
dateString = date.format('YYYY-MM')
return imgs.filter(ee.Filter.calendarRange(startMonth,endMonth,'month'))\
.mode().set(viz_dict).set({'system:time_start':date.millis(),'dateString':dateString})
def getYr(yr):
yrImgs = dwCol.filter(ee.Filter.calendarRange(yr,yr,'year'))
return ee.FeatureCollection(ee.List.sequence(1,12-nMonths+1,nMonths).map(lambda m:getMonths(yrImgs,yr,m)))
# Apply above functions
dwCompSeasonal = ee.FeatureCollection(ee.List.sequence(startYear,endYear).map(getYr)).flatten()
dwCompSeasonal = ee.ImageCollection(dwCompSeasonal)
dates = dwCompSeasonal.aggregate_histogram('dateString').keys().getInfo()
# Add layer to map as a time lapse
Map.addTimeLapse(dwCompSeasonal,{'autoViz':True,'canAreaChart':True,"dateFormat": "YYYY-MM",'years':dates,
"advanceInterval": "month",'areaChartParams':{'transform':transform,'crs':crs}},'Dynamic World Seasonal Time-Lapse')
# Set up map and view it
Map.centerObject(study_area)
Map.turnOnAutoAreaCharting()
Map.view()
Adding layer: Dynamic World Time-Lapse
Starting webmap
Using default refresh token for geeView
Local web server at: http://localhost:1234/geeView/ already serving.
cwd a:\GEE\gee_py_modules_package\geeViz\examples
geeView URL: http://localhost:1234/geeView/?projectID=lcms-292214&accessToken=ya29.a0AcM612xqiGDcaycnSbAGRNruGn9HQEonDtnU8NC3ZU-4c11MRNqY2FyDVexAiOkUoJQFvOJuby2EDrQ3pYSCW9ABfTJypYe2uqcpNuz2V1zBRQnGPAy1X8gyUlhIOb8lOzeIjAhAV7AL9MHYCQHFCJKJ38TTUd7iOMm3b4YXGjEaCgYKASgSARESFQHGX2MixCTtvcDehFDfDtuskh4RcA0178
Create Sankey Charts#
You can also create Sankey charts and download transition matrices with geeViz
Currently, geeViz only supports annual time series (ImageCollection) for Sankey charts
Once the map loads, you can use the
TOOLS
underArea Tools
to generate chartsYou can customize the years to include in the sankey charts under the
Area Tools Parameters
->Transition Charting Periods
Charts can be downloaded as a PNG and the underlying data can be downloaded as a CSV
Map.clearMap()
# Create annual mode (geeViz only supports annual time series - seasonal time series currently will not work for Sankey charts)
def getYr(yr):
yrImgs = dwCol.filter(ee.Filter.calendarRange(yr,yr,'year'))
return yrImgs.mode().set(viz_dict).set('system:time_start',ee.Date.fromYMD(yr,6,1).millis())
# Apply annual composite function
dwCompAnnual = ee.ImageCollection(ee.List.sequence(startYear,endYear).map(getYr))
# Add layer to map as a time lapse
Map.addTimeLapse(dwCompAnnual,{'autoViz':True,'canAreaChart':True,"dateFormat": "YYYY",'years':list(range(startYear,endYear+1)),'areaChartParams':{'transform':transform,'crs':crs,'line':True,'sankey':True}},'Dynamic World Annual Time-Lapse')
# Set up map and view it
Map.centerObject(study_area)
Map.turnOnAutoAreaCharting()
Map.view()
Adding layer: Dynamic World Annual Time-Lapse
Starting webmap
Using default refresh token for geeView
Local web server at: http://localhost:1234/geeView/ already serving.
cwd a:\GEE\gee_py_modules_package\geeViz\examples
geeView URL: http://localhost:1234/geeView/?projectID=lcms-292214&accessToken=ya29.a0AcM612zGxlR7g2m06p2w_g97qFinVqTn0jWBwkUd7Ajsww2oZAou5J3XU8mLwFQe70M8qw64OeJPA6b5NAoUJxq5Uzxm7IvlyvOwROguzYwXXoIuNhdZswlG7AcNILR05Ut_74LWjabkPQjKkvs1n4D7UKpntSAgsRlCAoVRCWEaCgYKAX0SARESFQHGX2MiA7fum6YIB_wnXdrpRp3weg0178