Tools of mapping
Following my Bob Ross “Paint the landscape” metaphor, there are a few choice brushes I reach for when you ask me to paint a picture.
DEM
Source Files from data sources
QGIS
wkp/country/wiki-scotland ## tidyterra
Leaflet
TMAP
https://rpubs.com/ials2un/dem_analysis
Earth Engine
```{javascript}
// https://www.youtube.com/watch?v=1ZkXZnw-tsc
// https://helpx.adobe.com/photoshop/using/blending-modes.html
//var elevation_data = ee.Image('CGIAR/SRTM90_V4').select('elevation');
var elevation_data = ee.Image('USGS/3DEP/10m').select('elevation');
function radians(img) {
return img.toFloat().multiply(Math.PI).divide(180);
}
function hillshade(az, ze, slope, aspect) {
var azimuth = radians(ee.Image(az));
var zenith = radians(ee.Image(ze));
return azimuth.subtract(aspect).cos()
.multiply(slope.sin())
.multiply(zenith.sin())
.add(
zenith.cos().multiply(slope.cos()));
}
var elevation_data_blur0 = elevation_data;
var elevation_data_blur7 = elevation_data.focalMean(7, "circle", "pixels", 1, null);
var elevation_data_blur15 = elevation_data.focalMean(15, "circle", "pixels", 1, null);
var elevation_data_blur30 = elevation_data.focalMean(30, "circle", "pixels", 1, null);
var slope_blur0 = ee.Terrain.slope(elevation_data_blur0);
var slope_blur7 = ee.Terrain.slope(elevation_data_blur7);
var slope_blur15 = ee.Terrain.slope(elevation_data_blur15);
var slope_blur30 = ee.Terrain.slope(elevation_data_blur30);
var aspect_blur0 = ee.Terrain.aspect(elevation_data_blur0);
var aspect_blur7 = ee.Terrain.aspect(elevation_data_blur7);
var aspect_blur15 = ee.Terrain.aspect(elevation_data_blur15);
var aspect_blur30 = ee.Terrain.aspect(elevation_data_blur30);
var hillshade_azimuth = 320; //270
var hillshade_elevation = 45;
var max_opacity_percent = 0.40;
var top_brush = 0.8;
var bottom_brush = 6;
var elevation_data_blur0_hs = ee.Terrain.hillshade(elevation_data_blur0,hillshade_azimuth,hillshade_elevation);
elevation_data_blur0_hs = elevation_data_blur0_hs.mask(
(elevation_data_blur0_hs.subtract((1-max_opacity_percent)*255))
.divide(255).clamp(0,1)
);
var elevation_data_blur7_hs = ee.Terrain.hillshade(elevation_data_blur7,hillshade_azimuth,hillshade_elevation);
elevation_data_blur7_hs = elevation_data_blur7_hs.mask(
(elevation_data_blur7_hs.subtract((1-max_opacity_percent)*255))
.divide(255).clamp(0,1)
);
var elevation_data_blur15_hs = ee.Terrain.hillshade(elevation_data_blur15,hillshade_azimuth,hillshade_elevation);
elevation_data_blur15_hs = elevation_data_blur15_hs.mask(
(elevation_data_blur15_hs.subtract((1-max_opacity_percent)*255))
.divide(255).clamp(0,1)
);
var elevation_data_blur30_hs = ee.Terrain.hillshade(elevation_data_blur30,hillshade_azimuth,hillshade_elevation);
elevation_data_blur30_hs = elevation_data_blur30_hs.mask(
(elevation_data_blur30_hs.subtract((1-max_opacity_percent)*255))
.divide(255).clamp(0,1)
);
Map.addLayer(ee.Image(1),{palette:['ffffff']});
Map.addLayer(elevation_data_blur0,{palette:['000000','000000']},'raw dem',false);
Map.addLayer(elevation_data_blur0_hs,{palette:['000000','000000']},'blur0 HS');
Map.addLayer(elevation_data_blur7_hs,{palette:['000000','000000']},'blur7 HS');
Map.addLayer(elevation_data_blur15_hs,{palette:['000000','000000']},'blur15 HS');
Map.addLayer(elevation_data_blur30_hs,{palette:['000000','000000']},'blur30 HS');
slope_blur0 = slope_blur0.mask(slope_blur0.divide(90).clamp(0,1));
Map.addLayer(slope_blur0,{palette:['000000','000000']},'slope0 HS');
var elevation_data_white_highlights_hs = ee.Terrain.hillshade(elevation_data_blur0,hillshade_azimuth,hillshade_elevation);
elevation_data_white_highlights_hs = elevation_data_white_highlights_hs.mask(
elevation_data_white_highlights_hs.divide(255));
Map.addLayer(elevation_data_white_highlights_hs,{min:255*top_brush, max:255, palette:['ffffff','ffffff']},'slope highlights');
slope_blur7 = slope_blur7.mask(
(slope_blur7.subtract((1-max_opacity_percent)*90))
.divide(90).clamp(0,1));
Map.addLayer(slope_blur7,{palette:['000000','000000']},'slope7');
slope_blur15 = slope_blur15.mask(
(slope_blur15.subtract((1-max_opacity_percent)*90))
.divide(90).clamp(0,1));
Map.addLayer(slope_blur0,{palette:['000000','000000']},'slope15');
slope_blur30 = slope_blur30.mask(
(slope_blur30.subtract((1-max_opacity_percent)*90))
.divide(90).clamp(0,1));
Map.addLayer(slope_blur30,{palette:['000000','000000']},'slope30');
var slope_blur0_hs = ee.Terrain.hillshade(ee.Terrain.slope(elevation_data_blur0),hillshade_azimuth,hillshade_elevation);
var slope_blur0_hs_mask = ee.Image(slope_blur0_hs.divide(255)).interpolate(ee.List([0,0.25,0.75,1]),ee.List([1,0,0,1]),'mask');
slope_blur0_hs = slope_blur0_hs.updateMask(slope_blur0_hs_mask);
Map.addLayer(slope_blur0_hs,{palette:['000000','ffffff']},'slope_blur0_hs');
var slope_blur7_hs = ee.Terrain.hillshade(ee.Terrain.slope(elevation_data_blur7),hillshade_azimuth,hillshade_elevation);
var slope_blur7_hs_mask = ee.Image(slope_blur7_hs.divide(255)).interpolate(ee.List([0,0.25,0.75,1]),ee.List([1,0,0,1]),'mask');
slope_blur7_hs = slope_blur7_hs.updateMask(slope_blur7_hs_mask);
Map.addLayer(slope_blur7_hs,{palette:['000000','ffffff']},'slope_blur7_hs');
var low_shadows_mask = elevation_data_blur0.interpolate(ee.List([20,70]),ee.List([0.4,0]),'clamp');
Map.addLayer(elevation_data_blur0.updateMask(low_shadows_mask),{palette:['000000','ffffff']},'low lands');
```
```{javascript}
// Define a function to convert from degrees to radians.
function radians(img) {
return img.toFloat().multiply(Math.PI).divide(180);
}
// Define a function to compute a hillshade from terrain data
// for the given sun azimuth and elevation.
function hillshade(az, ze, slope, aspect) {
// Convert angles to radians.
var azimuth = radians(ee.Image(az));
var zenith = radians(ee.Image(ze));
// Note that methods on images are needed to do the computation.
// i.e. JavaScript operators (e.g. +, -, /, *) do not work on images.
// The following implements:
// Hillshade = cos(Azimuth - Aspect) * sin(Slope) * sin(Zenith) +
// cos(Zenith) * cos(Slope)
return azimuth.subtract(aspect).cos()
.multiply(slope.sin())
.multiply(zenith.sin())
.add(
zenith.cos().multiply(slope.cos()));
}
var elevation = ee.Image("USGS/SRTMGL1_003");
// var slopeDegrees = ee.Algorithms.Terrain(elevation).select('slope').abs();
var slopeDegrees = ee.Terrain.slope(elevation).select('slope');
var slopePercent = ee.Image(slopeDegrees.tan()).multiply(100).abs();
var aspect = ee.Terrain.aspect(elevation).select('aspect');
var slopereclass = ee.Image(slopePercent)
.where(slopePercent.gt(0).and(slopePercent.lte(5)), 10)
.where(slopePercent.gt(5).and(slopePercent.lte(20)), 20)
.where(slopePercent.gt(20).and(slopePercent.lte(40)), 30)
.where(slopePercent.gt(40), 40);
var aspectreclass = ee.Image(aspect)
.where(aspect.gt(0).and(aspect.lte(22.5)), 1)
.where(aspect.gt(22.5).and(aspect.lte(67.5)), 2)
.where(aspect.gt(67.5).and(aspect.lte(112.5)), 3)
.where(aspect.gt(112.5).and(aspect.lte(157.5)), 4)
.where(aspect.gt(157.5).and(aspect.lte(202.5)), 5)
.where(aspect.gt(202.5).and(aspect.lte(247.5)), 6)
.where(aspect.gt(247.5).and(aspect.lte(292.5)), 7)
.where(aspect.gt(292.5).and(aspect.lte(337.5)), 8)
.where(aspect.gt(337.5).and(aspect.lte(360)), 1);
var colorTerrain = aspectreclass.add(slopereclass);
// Map.addLayer(slopeDegrees,{},'slope (degrees)',false);
// Map.addLayer(slopePercent,{},'slope (percent)',false);
// Map.addLayer(slopereclass,{},'slope reclass',false);
// Map.addLayer(aspect,{},'aspect',false);
// Map.addLayer(aspectreclass,{},'aspect reclass',false);
Map.addLayer(colorTerrain,{
min:19,
max:48,
palette:['#a1a1a1','#98b581','#72a890','#7c8ead','#8c75a0','#b47ba1',
'#cb8b8f','#c5a58a','#bdbf89','#8dc458','#3dab71','#5078b6','#77479d',
'#c04d9c','#e76f7a','#e2a66c','#d6db5e','#84d600','#84d600','#0068c0',
'#6c00a3','#ca009c','#ff5568','#ffab47','#f4fa00']});
var x = 0.1;
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 1))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 2))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 3))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 4))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 5))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 6))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 7))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 8))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 9))),{color: "#2f6ecc", width: 0.002});
// Map.addLayer(ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 10))),{color: "#2f6ecc", width: 0.002});
var riv1 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 1))).style({color: "#2f6ecc", width: 1});
var riv2 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 2))).style({color: "#2f6ecc", width: 1.2});
var riv3 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 3))).style({color: "#2f6ecc", width: 1.4});
var riv4 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 4))).style({color: "#2f6ecc", width: 1.6});
var riv5 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 5))).style({color: "#2f6ecc", width: 1.8});
var riv6 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 6))).style({color: "#2f6ecc", width: 2});
var riv7 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 7))).style({color: "#2f6ecc", width: 2.2});
var riv8 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 8))).style({color: "#2f6ecc", width: 2.4});
var riv9 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 9))).style({color: "#2f6ecc", width: 2.6});
var riv10 = ee.FeatureCollection(Rivers.filter(ee.Filter.eq('RIV_ORD', 10))).style({color: "#2f6ecc", width: 2.8});
Map.addLayer(riv1);
Map.addLayer(riv2);
Map.addLayer(riv3);
Map.addLayer(riv4);
Map.addLayer(riv5);
Map.addLayer(riv6);
Map.addLayer(riv7);
Map.addLayer(riv8);
Map.addLayer(riv9);
Map.addLayer(riv10);
Map.addLayer(BIA.union().style({color: '#8a5b19', fillColor: '#8a5b1935',width:2}));
Map.addLayer(Aqu.union().style({color: '#1f4bab', fillColor: '#1f4bab45',width:4}));
Map.addLayer(Cities.style({color: '#ecf230'}));
Map.addLayer(SDWells.style({color: '#22e352'}));
Map.addLayer(Uran.style({color: '#cf3221'}));
var State = ee.FeatureCollection("TIGER/2018/States");
var filter = State.filter(ee.Filter.inList("NAME",['South Dakota']).not());
Map.addLayer(filter.geometry().dissolve(), {opacity:0.3}, 'State');
var legend = ui.Panel({
style: {
position: 'bottom-right',
padding: '8px 15px'
}
});
// Create legend title
var legendTitle = ui.Label({
value: 'Uranium mines, Wells, Waterways, Terrain, and Populations in the Black Hills of South Dakota',
style: {
fontWeight: 'bold',
fontSize: '18px',
margin: '0 0 4px 0',
padding: '0',
maxWidth:'390px'
}
});
// 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 palette =['cf3221', '22e352','ecf230','1f4bab','8a5b19'];
// name of the legend
var names = ['Uranium mines (Surficial)','Water wells','Major cities','Inyan Kara Group aquifers','American Indian Land Area Representation'];
// Add color and and names
for (var i = 0; i < 5; i++) {
legend.add(makeRow(palette[i], names[i]));
}
var legendSources = ui.Label({
value: 'Sources: The BIA, USGS, SRTM, and the South Dakota Department of Agriculture & Natural Resources',
style: {
fontWeight: 'normal',
fontSize: '12px',
margin: '0 0 4px 0',
padding: '0',
maxWidth:'390px'
}
});
// add legend to map (alternatively you can also print the legend to the console)
var logo = ee.Image('users/JamesMColl/LargeSlopeAspect').visualize({
bands: ['b1', 'b2', 'b3'],
min: 0,
max: 255
});
var thumb = ui.Thumbnail({
image: logo,
params: {
dimensions: '398x382',
format: 'png'
},
style: {height: '398px', width: '382px',padding :'0'}
});
legend.add(thumb);
Map.add(legend);
// var toolPanel = ui.Panel(thumb, 'flow', {width: '300px'});
// ui.root.widgets().add(toolPanel);
legend.add(legendSources);
Map.setCenter(-103.061848427201,43.811618572829055, 9);
```