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 _0b239ec1c312e88716fa80073df97630.png ## 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');
```

_8e7ee7efe11d80763ed7086757b34621.png
```{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);
```

_b7fc57afd097034b03732421b557206b.png