I am attempting to calculate tree canopy coverage statistics (count, min, max, mean, median) on a census block level using the GLCF: Landsat Tree Cover Continuous Fields data set. I ran the script and discovered for some census blocks it will return all statistics, for others it will return only the mean and median, while yet other census blocks it won't return any of them. The code below references three census blocks that illustrate this behavior.
- What causes this behavior?
- Are there any changes I can make to guarantee all statistics are calculated?
_
var censusBlockIds = ['050534701002010', // Returns all statistics
'051250105031020', // Returns only mean and median statistics
'051250106006047']; // Returns no statistics
// Get census blocks for analysis
var censusBlocks = ee.FeatureCollection("TIGER/2010/Blocks")
.filter(ee.Filter.inList('blockid10', censusBlockIds));
// Get 2010 Landsat Tree Cover Continuous Fields
var treeCanopyCover = ee.ImageCollection('GLCF/GLS_TCC')
.filter(ee.Filter.date('2010-01-01', '2010-12-31'))
.filterBounds(censusBlocks)
.select('tree_canopy_cover')
.max();
// Function to calculates statistics and add block id
function censusBlockTreeCoverage(censusBlock) {
return calcTreeCoverage(censusBlock.geometry())
.set('blockid10', censusBlock.get('blockid10'));
}
// Function to calculate tree canopy coverage statistics for census block
function calcTreeCoverage(censusBlockGeometry) {
// Count pixels census block intersects
var countDict = treeCanopyCover.reduceRegion({
reducer: ee.Reducer.count(),
geometry: censusBlockGeometry,
scale: 30,
maxPixels: 1e9,
bestEffort: true
});
// Calculate minimum tree canopy cover for census block
var minDict = treeCanopyCover.reduceRegion({
reducer: ee.Reducer.min(),
geometry: censusBlockGeometry,
scale: 30,
maxPixels: 1e9,
bestEffort: true
});
// Calculate maximum tree canopy cover for census block
var maxDict = treeCanopyCover.reduceRegion({
reducer: ee.Reducer.max(),
geometry: censusBlockGeometry,
scale: 30,
maxPixels: 1e9,
bestEffort: true
});
// Calculate mean tree canopy cover for census block
var meanDict = treeCanopyCover.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: censusBlockGeometry,
scale: 30,
maxPixels: 1e9,
bestEffort: true
});
// Calculate median tree canopy cover for census block
var medianDict = treeCanopyCover.reduceRegion({
reducer: ee.Reducer.median(),
geometry: censusBlockGeometry,
scale: 30,
maxPixels: 1e9,
bestEffort: true
});
// Return new geometry-less feature with calculations
return ee.Feature(null)
.set('treeCoverageCount', countDict.get('tree_canopy_cover'))
.set('treeCoverageMin', minDict.get('tree_canopy_cover'))
.set('treeCoverageMax', maxDict.get('tree_canopy_cover'))
.set('treeCoverageMean', meanDict.get('tree_canopy_cover'))
.set('treeCoverageMedian', medianDict.get('tree_canopy_cover'));
}
// Define visualization parameters
var treeCanopyCoverVis = {
min: 0.0,
max: 100.0,
palette: ['ffffff', 'afce56', '5f9c00', '0e6a00', '003800'],
};
// Calculate statistics for each census block
var censusBlockStatistics = censusBlocks.map(censusBlockTreeCoverage);
print(censusBlockStatistics);
// Add layers to map for visual confirmation
Map.addLayer(treeCanopyCover, treeCanopyCoverVis, 'Tree Canopy Cover');
Map.addLayer(censusBlocks, {}, 'Census Blocks');
Map.centerObject(censusBlocks);