-
-
Save okjodom/38bdc7dfded2a299dda7cbf1a00bd1e3 to your computer and use it in GitHub Desktop.
/* | |
Water Quality Analysis in the Winam Gulf of Lake Victoria | |
Water Quality Parameter: Chlorophyll-a | |
##################### | |
Specific Study Area: Mbita Point | |
Datasets: Landat 5 and Landsat 7 Satellite Imagery | |
Epochs: December 31st of the years [1984, 1988, 1992, 1996, 2000, 2004, 2008, 2016, 2016] | |
Test Epochs: 1984 and 2016 (Sentinel Epochs) | |
Algorithms: Color Index (CI) by Hu et al. 2012 | |
Assets: | |
gulfclip: Extent clipper for the Winam Gulf | |
pointclip: Extent clipper for the Mbita Point | |
gulfpoly: Shoreline of the Winam Gulf | |
pointpoly: Shoreline of the Mbita Point | |
profile(X): waypoints for deriving profiles | |
Published App | |
https://jodom.users.earthengine.app/view/mbita-causeway | |
DISCLAIMER | |
This is not a published, citable, scientific study. Each attriutable input to this script (example; CI algorithm, assets, Earth Engine) may be subject to its own licensing copyrights. | |
The script is free for copy and use, and constitutes zero liability to the author | |
*/ | |
var pointclip = ee.FeatureCollection("users/jodom/causeway/pointclip"), | |
pointpoly = ee.FeatureCollection("users/jodom/causeway/point_polygon"), | |
gulfline = ee.FeatureCollection("users/jodom/causeway/gulf_shoreline"), | |
gulfpoly = ee.FeatureCollection("users/jodom/causeway/gulf_polygon"), | |
profile0 = ee.FeatureCollection("users/jodom/causeway/profile0"), | |
profile1 = ee.FeatureCollection("users/jodom/causeway/profile1"), | |
profile2 = ee.FeatureCollection("users/jodom/causeway/profile2"), | |
profile3 = ee.FeatureCollection("users/jodom/causeway/profile3"), | |
profile4 = ee.FeatureCollection("users/jodom/causeway/profile4"), | |
profile5 = ee.FeatureCollection("users/jodom/causeway/profile5"), | |
profile6 = ee.FeatureCollection("users/jodom/causeway/profile6"), | |
profile7 = ee.FeatureCollection("users/jodom/causeway/profile7"), | |
profiles = ee.FeatureCollection("users/jodom/causeway/1278profiles"); | |
// defaults | |
var extent = gulfpoly; // extent of analysis | |
var profilesOn = false; // status of analysis profiles | |
// constants | |
var waypoints = [profile0, profile1, profile2, profile3, profile4, profile5, profile6, profile7]; | |
var sampledpoints = [profile0, profile1, profile6, profile7]; | |
// ####################### Sourcing Data # | |
function getData(){ | |
/* Import, filter and transforms Satellite Images */ | |
// Filtered Surface Reflectance (SR) Collections | |
var sr5coll = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR").filterBounds(pointclip).filterDate('1982-01-01', '2000-12-31').filter(ee.Filter.lte('CLOUD_COVER', 15)); | |
var sr7coll = ee.ImageCollection("LANDSAT/LE07/C01/T1_SR").filterBounds(pointclip).filterDate('2000-01-01', '2018-12-31').filter(ee.Filter.lte('CLOUD_COVER', 15)); | |
// Compute representative averages for each epoch | |
var epochAvgs = [ | |
ee.Image(sr5coll.filterDate('1984-01-01', '1984-12-31').mean()).set("Year", 1984), | |
ee.Image(sr5coll.filterDate('1994-01-01', '1994-12-31').mean()).set("Year", 1994), | |
ee.Image(sr7coll.filterDate('2004-01-01', '2004-12-31').mean()).set("Year", 2004), | |
ee.Image(sr7coll.filterDate('2014-01-01', '2014-12-31').mean()).set("Year", 2014), | |
ee.Image(sr7coll.filterDate('2017-01-01', '2017-12-31').mean()).set("Year", 2017) | |
]; | |
return epochAvgs; | |
} | |
// filtered dataset | |
var dataset = getData(); | |
// ####################### CHL-a Analysis Algorithms ## | |
// CI Algorithm, (Hu et al. 2012) | |
function CI(image){ | |
/* | |
Calculates the Color Index (CI) by difference in reflectance of bands from input image | |
Formulation: | |
result = Green - [ Blue + (lambdaGreen - lambdaBlue) / (lambdaRed - lambdaBlue) * (Red - Blue) ] | |
Where : | |
Red, Green, Blue are Reflectances in the respective bands of sat image | |
lambdaRed, lambdaGreen, lambdaBlue | |
are instrument-specific wavelengths closest to 670, 555, 443 respectively of bands | |
*/ | |
var result = image.expression( | |
'Green - ( Blue + (lambdaGreen - lambdaBlue) / (lambdaRed - lambdaBlue) * (Red - Blue) )', | |
{ | |
'Red' : image.select('B3'), // *Designations for SR datasets>> | |
'lambdaRed' : 670, | |
'Green' : image.select('B2'), | |
'lambdaGreen' : 555, | |
'Blue' : image.select('B1'), | |
'lambdaBlue' : 443 | |
}); | |
return result; | |
} | |
// ####################### Visualizations #### | |
function computeChlSurfaces(algorithm){ | |
/**/ | |
var result = []; | |
dataset.forEach(function(image){ | |
result.push(CI(image).set('Year', image.get('Year'))); // compute chl-a surfaces | |
}); | |
return ee.ImageCollection(result); | |
// return result; | |
} | |
// color pallete | |
var chlaPallete = ['51f1e3', 'ffd761', 'ff6437', 'ff0414']; | |
function buildChart(collection){ | |
/* | |
Generates a time series chart with specifications provided | |
[ImageCollection]@collection: computed chl-a surfaces | |
*/ | |
// A time series chart from computed surfaces | |
var chart = ui.Chart.image.series({ | |
imageCollection: collection, | |
region: extent, | |
reducer: ee.Reducer.mean(), | |
scale: 30, | |
xProperty: 'Year' | |
}); | |
// Custom chart options | |
chart.setOptions({ | |
title: 'CI Algorithm', | |
legend: {position: 'none'}, | |
vAxis: {title: 'chl-a estimates (avg)'}, | |
hAxis: {title: 'Year', format: '', minValue: 1984}, | |
// backgroundColor: { fill: "#F4F4F4"}, | |
pointSize: 5, | |
pointShape: 'circle' | |
}); | |
// Chart styling | |
chart.style().set({ | |
width: '380px', | |
height: '300px' | |
}); | |
// Update the map and label when the chart is clicked. | |
chart.onClick(function(xValue, yValue, seriesName) { | |
if (!xValue) return; // Selection was cleared. | |
// Show the image for the clicked year. | |
var image = ee.Image(collection.filter(ee.Filter.equals('Year', xValue)).first()).clip(extent); | |
var layer = ui.Map.Layer(image, { | |
min: 0, | |
max: 250, | |
palette: chlaPallete, | |
bands: 'B2' | |
}); | |
profilesOn ? Map.layers().reset([layer, profiles]) : Map.layers().reset([layer]); | |
// Show a label with the date on the map. | |
label.setValue(xValue + ' CHL-A LEVELS FROM CI ALGORITHM'); | |
}); | |
return chart; | |
} | |
function buildProfile(profile, image){ | |
var chart = ui.Chart.image.byRegion({ | |
image: image, | |
regions: profile, | |
scale: 30, | |
xProperty: 'Label' | |
}); | |
// Custom chart options | |
chart.setOptions({ | |
curveType: 'function', | |
title: 'Chlorophyll-a Levels', | |
legend: {position: 'none'}, | |
vAxis: {title: 'average chl-a level', minValue: 0}, | |
hAxis: {title: 'Profile', format: 'short', minValue: 0}, | |
backgroundColor: { fill: "#F4F4F4"}, | |
pointSize: 4, | |
lineWidth: 1 | |
}); | |
// Chart styling | |
chart.style().set({ | |
width: '500px', | |
height: '300px' | |
}); | |
return chart; | |
} | |
// Create the UI | |
// Scale Picker :: different scales of analysis | |
var analysisExtent = { | |
'Choose An Analysis Scale': 'default', | |
'Mbita Point': 'point', | |
'Winam Gulf': 'gulf' | |
}; | |
var selectScale = ui.Select({ | |
items: Object.keys(analysisExtent), | |
onChange: function(value){ | |
// render analysis extent and charts at scale selected | |
if (analysisExtent[value] == 'point'){ | |
extent = pointpoly; | |
Map.setCenter(34.207236, -0.425424, 12); | |
}else if (analysisExtent[value] == 'gulf'){ | |
extent = gulfpoly; | |
Map.setCenter( 34.407875, -0.423000, 10); | |
}else{ | |
return; | |
} | |
rightPanel.widgets().set(1, buildChart(ci_collection)); | |
}, | |
style: { width: '365px', color: 'red'} | |
}); | |
selectScale.setPlaceholder('Choose Scale of Analysis'); | |
var rightPanel = ui.Panel({ | |
layout: ui.Panel.Layout.flow('vertical'), | |
style: { | |
position: 'top-right', | |
width: '400px' | |
} | |
}); | |
var buttonPanel = ui.Panel({ | |
layout: ui.Panel.Layout.flow('horizontal'), | |
style: { | |
width: '365px' | |
} | |
}); | |
buttonPanel.widgets().set(0, | |
ui.Button({ | |
label: 'Show Profiles', | |
style: { width: '45%', color: 'red'}, | |
onClick: function() { | |
if (! profilesOn){ | |
Map.addLayer(profiles, {}, 'Profiles'); | |
} | |
profilesOn = true; | |
} | |
}) | |
); | |
buttonPanel.widgets().set(1, | |
ui.Button({ | |
label: 'Clear', | |
style: { width: '45%', color: 'red'}, | |
onClick: function() { | |
Map.layers().reset(); | |
profilesOn = false; | |
} | |
}) | |
); | |
// CI ## | |
var ci_collection = computeChlSurfaces('CI'); | |
// A time series chart from computed surfaces | |
var ciChart = buildChart(ci_collection); | |
// Add charts to panel | |
rightPanel.widgets().set(0, selectScale); | |
rightPanel.widgets().set(1, ciChart); | |
rightPanel.widgets().set(2, buttonPanel); | |
// Display panel | |
Map.add(rightPanel); | |
// Create a label on the map. | |
var label = ui.Label('Click a point on the chart to show the Chl-a surface'); | |
Map.add(label); | |
Map.setCenter( 34.407875, -0.423000, 10); | |
// profiles | |
// ci_collection.map(function(image){ | |
// print(image) | |
// // print(image.get('Year')); | |
// waypoints.forEach(function(pointgroup){ | |
// pointgroup = pointgroup.sort('Id'); | |
// print(buildProfile(pointgroup, image)); | |
// }); | |
// }); | |
// set position of panel | |
var legend = ui.Panel({ | |
style: { | |
position: 'bottom-center', | |
padding: '8px 15px', | |
margin: '0 0 100px 100px' | |
} | |
}); | |
// Create legend title | |
var legendTitle = ui.Label({ | |
value: 'Chl-a Levels (mg/L)', | |
style: { | |
fontWeight: 'bold', | |
fontSize: '18px', | |
margin: '0 0 4px 0', | |
padding: '0' | |
} | |
}); | |
// Add legend to maps | |
// Add the title to the panel | |
legend.add(legendTitle); | |
// Creates and styles 1 row of the legend. | |
var makeRow = function(color, name) { | |
// Create the label that is actually the colored box. | |
var colorBox = ui.Label({ | |
style: { | |
backgroundColor: '#' + color, | |
// Use padding to give the box height and width. | |
padding: '8px', | |
margin: '0 0 4px 0' | |
} | |
}); | |
// Create the label filled with the description text. | |
var description = ui.Label({ | |
value: name, | |
style: {margin: '0 0 4px 6px'} | |
}); | |
// return the panel | |
return ui.Panel({ | |
widgets: [colorBox, description], | |
layout: ui.Panel.Layout.Flow('horizontal') | |
}); | |
}; | |
// Palette with the colors | |
var pallete = ['51f1e3', 'ffd761', 'ff6437', 'ff0414']; | |
// name of the legend | |
var names = ['Below 50', '50 - 100', '100-200', 'Above 200']; | |
// Add color and and names | |
for (var i = pallete.length; i > 0; i--) { | |
legend.add(makeRow( pallete[i-1], names[i-1])); | |
} | |
// add legend to map (alternatively you can also print the legend to the console) | |
Map.add(legend); |
Please, can you share your assets..
It's helpful, if you can share the asserts (including the pointclip etc) to us that we can run the code
The assets [ gulfclip: Extent clipper for the Winam Gulf
pointclip: Extent clipper for the Mbita Point
gulfpoly: Shoreline of the Winam Gulf
pointpoly: Shoreline of the Mbita Point
profile(X): waypoints for deriving profiles ] were not meant to be public, otherwise they would have been posted in a repo and not gist.
Now you could copy this gist to your earth engine editor, point to your own assets you upload and manage in E.E ( for whatever water body you want to perform an analysis) and run.
Happy to help.
Dear Jodom...
Can you explain your assets as points, polygon, polyline etc. please?
Please, give an explanation...
It's helpful, if you can share the asserts (including the pointclip etc) to us that we can run the code . Thanks very much!