Visualizing Global Land Cover¶
The Global Land Cover 30m product is a powerful dataset for global land cover change monitoring
See https://gee-community-catalog.org/tutorials/examples/glc_fcs30d_lulc for source documentation
Copyright 2025 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
import geeViz.geePalettes as palettes
ee = geeView.ee
Map = geeView.Map
print('done')
Make a basic viewer¶
This is a slight adaptation of the example provided here: https://gee-community-catalog.org/tutorials/examples/glc_fcs30d_lulc/#steps
geeViz will automatically generate legends and query lookups using
"autoViz" : Truein the visualization paramsDouble-clicking on the map will show the values for the pixel you clicked on
Map.clearMap()
Map.port = 1234
# Specify projection to use for zonal summaries and map querying
# Be sure to leave one of scale or transform as None
crs= 'EPSG:4326'
transform = None
scale = 30
Map.setQueryCRS(crs)
if transform == None:
Map.setQueryScale(scale)
else:
Map.setQueryTransform(transform)
Map.clearMapLayers()
####################################################################
# Adapted from: https://gee-community-catalog.org/tutorials/examples/glc_fcs30d_lulc/#steps
annual = ee.ImageCollection('projects/sat-io/open-datasets/GLC-FCS30D/annual')
# Five-Yearly data for 1985-90, 1990-95 and 1995-2000
fiveyear = ee.ImageCollection('projects/sat-io/open-datasets/GLC-FCS30D/five-years-map')
# Classification scheme has 36 classes (35 landcover classes and 1 fill value)
classValues = [10, 11, 12, 20, 51, 52, 61, 62, 71, 72, 81, 82, 91, 92, 120, 121, 122, 130, 140, 150, 152, 153, 181, 182, 183, 184, 185, 186, 187, 190, 200, 201, 202, 210, 220, 0]
classNames = ['Rainfed_cropland', 'Herbaceous_cover_cropland', 'Tree_or_shrub_cover_cropland', 'Irrigated_cropland', 'Open_evergreen_broadleaved_forest', 'Closed_evergreen_broadleaved_forest', 'Open_deciduous_broadleaved_forest', 'Closed_deciduous_broadleaved_forest', 'Open_evergreen_needle_leaved_forest', 'Closed_evergreen_needle_leaved_forest', 'Open_deciduous_needle_leaved_forest', 'Closed_deciduous_needle_leaved_forest', 'Open_mixed_leaf_forest', 'Closed_mixed_leaf_forest', 'Shrubland', 'Evergreen_shrubland', 'Deciduous_shrubland', 'Grassland', 'Lichens_and_mosses', 'Sparse_vegetation', 'Sparse_shrubland', 'Sparse_herbaceous', 'Swamp', 'Marsh', 'Flooded_flat', 'Saline', 'Mangrove', 'Salt_marsh', 'Tidal_flat', 'Impervious_surfaces', 'Bare_areas', 'Consolidated_bare_areas', 'Unconsolidated_bare_areas', 'Water_body', 'Permanent_ice_and_snow', 'Filled_value']
classColors = ['ffff64', 'ffff64', 'ffff00', 'aaf0f0', '4c7300', '006400', 'a8c800', '00a000', '005000', '003c00', '286400', '285000', 'a0b432', '788200', '966400', '964b00', '966400', 'ffb432', 'ffdcd2', 'ffebaf', 'ffd278', 'ffebaf', '00a884', '73ffdf', '9ebb3b', '828282', 'f57ab6', '66cdab', '444f89', 'c31400', 'fff5d7', 'dcdcdc', 'fff5d7', '0046c8', 'ffffff', 'ffffff']
# Mosaic the data into a single image
annualMosaic = annual.mosaic()
fiveYearMosaic = fiveyear.mosaic()
# Rename bands from b1, b2, etc. to 2000, 2001, etc.
fiveYearsList = [str(i) for i in list(range(1985, 1995+1, 5))]
fiveyearMosaicRenamed = fiveYearMosaic.rename(fiveYearsList)
yearsList = [str(i) for i in list(range(2000, 2022+1))]
annualMosaicRenamed = annualMosaic.rename(yearsList)
years = fiveYearsList + yearsList
# Convert the multiband image to an ImageCollection
def getFiveYear(year):
date = ee.Date.fromYMD(ee.Number.parse(year), 1, 1)
return fiveyearMosaicRenamed.select([year]).set({'system:time_start': date.millis(), 'system:index': year, 'year': ee.Number.parse(year)})
fiveYearlyMosaics = ee.List(fiveYearsList).map(getFiveYear)
def getAnnualYear(year):
date = ee.Date.fromYMD(ee.Number.parse(year), 1, 1)
return annualMosaicRenamed.select([year]).set({'system:time_start': date.millis(), 'system:index': year, 'year': ee.Number.parse(year)})
yearlyMosaics = ee.List(yearsList).map(getAnnualYear)
allMosaics = fiveYearlyMosaics.cat(yearlyMosaics)
mosaicsCol = ee.ImageCollection.fromImages(allMosaics)
mosaicsCol = ee.ImageCollection.fromImages(allMosaics)
print(mosaicsCol.size().getInfo())
# Set up viz properties
out_band_name = "lulc"
# Function to convert a given band into a time-enabled image object
def setupLulc(img):
img = img.set(
{
f"{out_band_name}_class_names": classNames,
f"{out_band_name}_class_palette": classColors,
f"{out_band_name}_class_values": classValues,
}
)
return img
# Rename band and set the properties for visualization
landcoverCol = mosaicsCol.select([0],[out_band_name]).map(setupLulc)
print('Pre-processed Collection', landcoverCol.getInfo())
# Visualize the most common class
Map.addLayer(landcoverCol, {'reducer':ee.Reducer.mode(),'autoViz':True}, 'Global Land Cover' )
# Querying the data by double-clicking on the map will show the full time series of values
Map.turnOnInspector()
Map.view()
Calculating and Exporting Landcover Statistics¶¶
geeViz streamlines calculating and exporting statistics
Once the map loads, you can use the
TOOLSunderArea Toolsto generate chartsCharts can be downloaded as a PNG and the underlying data can be downloaded as a CSV
This example shows the imageCollection as a time lapse
Once the map loads, you can annimate the time series using the time lapse controls
Map.clearMap()
Map.turnOffLayersWhenTimeLapseIsOn = False # Set this to False to avoid layers automatically turning off when a time lapse is turned on
Map.addTimeLapse(landcoverCol, {'autoViz':True,'years':years,'canAreaChart':True,'areaChartParams':{'crs':crs,'scale':scale,'transform':transform}}, 'Global Land Cover' )
# Add country boundaries as a layer to select with
countries = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level0")
Map.addSelectLayer(countries, {}, "Global Country Boundaries")
Map.turnOnAutoAreaCharting()
Map.view()
Create Sankey Charts¶
You can also create Sankey charts and download transition matrices with geeViz
Once the map loads, you can use the
TOOLSunderArea Toolsto generate chartsYou can customize the years to include in the sankey charts under the
Area Tools Parameters->Transition Charting PeriodsCharts can be downloaded as a PNG and the underlying data can be downloaded as a CSV
Map.clearMapLayers()
Map.addTimeLapse(landcoverCol, {'autoViz':True,'years':years,'canAreaChart':True,'areaChartParams':{'line':True,'sankey':True,'crs':crs,'transform':transform,'scale':scale}}, 'Global Land Cover' )
countries = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level0")
Map.addSelectLayer(countries, {}, "Global Country Boundaries")
Map.turnOnAutoAreaCharting()
Map.view()
Map.clearMap()
# Adapted from: https://code.earthengine.google.com/f9f56ceb38ed9e911767c4014eeb536d
print("This data is made available by the Global Land Analysis and Discovery (GLAD) lab at the University of Maryland.","P.V. Potapov, M.C. Hansen, A.H. Pickens, A. Hernandez-Serna, A. Tyukavina, S. Turubanova, V. Zalles, X. Li, A. Khan, F. Stolle, N. Harris, X.-P. Song, A. Baggett, I. Kommareddy, A. Komareddy (2022).")
# print("For more information please visit:",ui.Label(" https://glad.umd.edu/dataset/GLCLUC2020",{},"https://glad.umd.edu/dataset/GLCLUC2020"),
# "The legend is available here:",ui.Label(" https://storage.googleapis.com/earthenginepartners-hansen/GLCLU2000-2020/v2/legend.xlsx",{},"https://storage.googleapis.com/earthenginepartners-hansen/GLCLU2000-2020/v2/legend.xlsx"))
landmask = ee.Image("projects/glad/OceanMask").lte(1)
change =ee.Image('projects/glad/GLCLU2020/v2/LCLUC').updateMask(landmask)
m00 = ee.Image('projects/glad/GLCLU2020/v2/LCLUC_2000').updateMask(landmask)
m05 = ee.Image('projects/glad/GLCLU2020/v2/LCLUC_2005').updateMask(landmask)
m10 = ee.Image('projects/glad/GLCLU2020/v2/LCLUC_2010').updateMask(landmask)
m15 = ee.Image('projects/glad/GLCLU2020/v2/LCLUC_2015').updateMask(landmask)
m20 = ee.Image('projects/glad/GLCLU2020/v2/LCLUC_2020').updateMask(landmask)
visParamMap = {"min":0,"max":255,"palette":["FEFECC","FAFAC3","F7F7BB","F4F4B3","F1F1AB","EDEDA2","EAEA9A","E7E792","E4E48A",
"E0E081","DDDD79","DADA71","D7D769","D3D360","D0D058","CDCD50","CACA48","C6C63F","C3C337","C0C02F","BDBD27","B9B91E","B6B616",
"B3B30E","B0B006","609C60","5C985C","589558","549254","508E50","4C8B4C","488848","448544","408140","3C7E3C","387B38","347834",
"317431","2D712D","296E29","256B25","216721","1D641D","196119","155E15","115A11","0D570D","095409","065106","643700","643a00",
"643d00","644000","644300","644600","644900","654c00","654f00","655200","655500","655800","655a00","655d00","656000","656300",
"666600","666900","666c00","666f00","667200","667500","667800","667b00","ff99ff","FC92FC","F98BF9","F685F6","F37EF3","F077F0",
"ED71ED","EA6AEA","E763E7","E45DE4","E156E1","DE4FDE","DB49DB","D842D8","D53BD5","D235D2","CF2ECF","CC27CC","C921C9","C61AC6",
"C313C3","C00DC0","BD06BD","bb00bb","000003","000004","000005","BFC0C0","B7BDC2","AFBBC4","A8B8C6","A0B6C9","99B3CB","91B1CD",
"89AFD0","82ACD2","7AAAD4","73A7D6","6BA5D9","64A3DB","5CA0DD","549EE0","4D9BE2","4599E4","3E96E6","3694E9","2E92EB","278FED",
"1F8DF0","188AF2","1088F4","0986F7","55A5A5","53A1A2","519E9F","4F9B9C","4D989A","4B9597","499294","478F91","458B8F","43888C",
"418589","3F8286","3D7F84","3B7C81","39797E","37767B","357279","336F76","316C73","2F6970","2D666E","2B636B","296068","285D66",
"bb93b0","B78FAC","B48CA9","B189A6","AE85A2","AA829F","A77F9C","A47B99","A17895","9E7592","9A718F","976E8C","946B88","916885",
"8D6482","8A617F","875E7B","845A78","815775","7D5472","7A506E","774D6B","744A68","714765","de7cbb","DA77B7","D772B3","D46EAF",
"D169AB","CE64A8","CB60A4","C85BA0","C4579C","C15298","BE4D95","BB4991","B8448D","B54089","B23B86","AF3682","AB327E","A82D7A",
"A52976","A22473","9F1F6F","9C1B6B","991667","961264","000000","000000","000000",
"1964EB","1555E4","1147DD","0E39D6","0A2ACF","071CC8","030EC1","0000BA",
"0000BA","040464","0000FF","3051cf","000000","000000","000000","000000",
"000000","000000","000000","000000","000000","000000","000000","000000",
"000000","000000","000000","000000","000000","000000","000000","000000",
"547FC4","4D77BA","466FB1","4067A7","395F9E","335895","335896","335897","ff2828","ffffff","d0ffff","ffe0d0","ff7d00","fac800","c86400",
"fff000","afcd96","afcd96","64dcdc","00ffff","00ffff","00ffff","111133","000000"]}
Map.addLayer(m00,visParamMap,'2000 land cover and land use')
Map.addLayer(m05,visParamMap,'2005 land cover and land use')
Map.addLayer(m10,visParamMap,'2010 land cover and land use')
Map.addLayer(m15,visParamMap,'2015 land cover and land use')
Map.addLayer(m20,visParamMap,'2020 land cover and land use')
Map.addLayer(change,visParamMap,'2000-2020 land cover and land use change')
Map.turnOnInspector()
Map.view()