Short:
I characterized cliffs from localized statistics of slope and slope gradient from 12,000 reported rock climbing locations using ~10m DEM data*.
Combined the information in a simple composite image*.
Displayed the composite image, some other derivative versions, and Google base maps, in an Google Earth Engine app.
*Used cliff domain knowledge and artistic license to weight images and tune filters.
Long:
The best map I could find was the based on the US NED Landforms data provided by the Conservation Science Partners. It specifically classifies cliffs, but the resolution is course at ~30m and the cliffs are often buried in a sea of other landforms.
At minimum I thought I could highlight where the cliffs are with the NED Landforms Data.
I also knew that the highest resolution seamless elevation data in the US was ~10m. I thought a map of the slope at this resolution with colors that highlight steep slopes could be helpful, and I think it is.
I wanted to have some statistical basis to guide my visualization setup beyond my personal familiarity with a few* cliffs, so a scraped 12,000 known rock climbing cliffs from the web. *Actually many.
Often the reported locations of these climbing locations are not exact, so I considered a 100m radius around the points.
It turns out climbing cliffs are often fairly steep.
Fun fact: The single steepest point in the United States according to ~10m DEM data is the Dawn Wall, on El Capitan.
One challenge was that very cliffy, small cliffs often don't show a high slope because of the relatively small change in elevation from one pixel another with 10m elevation data.
To better highlight small cliffs I looked at other information to combine with the slope, slope gradient. It turns out climbing cliffs also change slope rapidly.
Technically the gradient is the direction of steepest accent in the data, not the magnitude of change in that direction. I refer to "gradient" as the magnitude of the gradient vector. "Slope" is just the gradient of the elevation data. "Slope gradient" is the gradient of the gradient of the elevation data, or the gradient of the slope.
Slope gradient below:
I attenuated all the slope gradient values below 55, which seemed like the right cutoff, and then blurred the pixels into small areas so as to represent zones where cliffs are likely to be.
I combined the slope and "smoothed slope gradient" images in a composite. I weighted the "blurred gradient slope" image a little more. Again, this was creative license based on domain knowledge.
The composite image is a simple element wise product of the two images.
Then I attenuated all of the values below a cutoff with the visualization parameters. You might consider the result as a kind of fuzzy classification.
I find that small signatures that barely make it on the map often reveal interesting features that would be missed with a hard classification.
I think the composite is better at highlighting small cliffs than the NED Landforms data.
A simple composite with only DEM data is nice because it is computationally much cheaper than some other methods. Low computation is important for rendering the map quick enough to be useful.
I'm sure it is possible to download the composite data, but that is a lot of computation and data, so the program just computes as it goes. It is lazy.
The program uses functional programming techniques to more easily compute in a parallel fashion on Googles cloud computing resources.
Google Earth Engine makes it really easy to do all of that. Pretty cool.
I also made binary classifications for cliffs at ~10m and ~30 meter.
To seriously compare this map with the NED Landforms map I would need many things:
Somehow define what constitutes a cliff vs not-cliff
Gather confirmed not-cliff location data
Verify the 12,000 cliffs as truly cliffs
Gather more diverse true cliff data
In the absence of rigorous comparison, I did find that this map showed 7.6% true positive increase while also decreasing the total number of pixels classified as cliffs roughly 20% when comparing at similar resolutions.
Less pixels. More often correct when there are pixels.
There are at least a couple problems with this map in terms of cliff classification.
It doesn't classify big cliffs very well. It captures the edges of the big cliffs, where the change in slope is high enough, but not the high slope pixels inside of the boundaries. Perhaps I will get around to that.
It overfits around roads and water. Roads and water are very flat. When there is a decent amount of slope around these features, the slope gradient is high, similar to cliffs. Edges around these features may register as cliffs more than they should.
The satellite imagery often gives away a couple useful clues about cliffs.
One of these is visible breaks. Visible breaks often indicate a discrete and steep cliff line, so as to be distinct from very steep, not-cliffy slopes. Sometimes these come in the form of vegetation change, a shadow, or just a change in rock between the top and bottom.
Another clue can be found at the base. Scree bases often indicate the stability of the cliff. Cliffs that are less stable are more likely to shed rock onto to the base below at a faster rate, hence the scree base.
The Google base maps with the slider in the app make it very easy to quickly consider these clues.
One last thing: To actually be helpful, it is also important that the map doesn't need to be zoomed in extremely close to see the cliffs. That'd be like searching for your car keys with binoculars. With multi-scale images, like the ones provided in Google Earth Engine, as you zoom out information is lost unless you tell it not to be lost. What this means is that you can't see the cliffs when you zoom out, unless the program does something about it.
So I created another layer that computes at the highest reasonable scale before significant information is lost, no matter the zoom. The only catch is that this is computationally very expensive at low zoom levels and may take a moment to load, or even error out. I indicated the appropriate zoom levels in the app.