Contours

map
These circles should not overlap

Examples

Pseudo-3D Terrain Generation

John Nelson’s brilliant ArcGIS Pro tutorial demonstrates how to create a stunning, tactile, “trippy” AI-generated aesthetic using real elevation data. The workflow relies on heavily blurring a Digital Elevation Model (DEM), extracting contour polygons, and using a drop-shadow rendering “hack” to create a pseudo-3D isometric look.

Because the methodology is highly geometric, it’s an instructive exercise in spatial data manipulation to replicate this exact style entirely using open-source R packages.

Background The pseudo-3D map is generated by generalizing high-resolution elevation data so the resulting contours are sweeping and smooth. Then, rather than rendering 3D scenes with heavy ray-tracing, we manually shift the 2D polygon geometries to simulate light and depth.

Our workflow to generate this surface will look like so:

flowchart TD
    %% Node Definitions
    DEM[(Raw DEM Elevation)]
    
    subgraph A[Spatial Processing]
        direction TB
        BLUR[(Focal Blur / Smoothing)]
        CONT[(Extract Contour Polygons)]
        SHIFT[(Geometry Translation)] 
    end

    subgraph B[Aesthetic Rendering]
        direction TB
        SHADOW[Render Base Shadows]
        FILL[Color Thievery / Gradient]
        EDGE[Crisp Edge Highlights]
        TEX[Paper Texture Overlay]
    end

    OUT[Pseudo-3D Map]

    %% Connections
    DEM ==> BLUR
    BLUR ==> CONT
    CONT ==> SHIFT
    
    CONT ==> FILL
    SHIFT ==> SHADOW
    
    SHADOW ==> EDGE
    FILL ==> EDGE
    EDGE ==> TEX
    TEX ==> OUT

    %% Classes
    classDef output fill:#f9f,stroke:#333,stroke-width:2px;
    class OUT output;

To make this problem computationally tractable while keeping the elegant sweeping lines, we apply a focal smoothing window over the DEM. This replicates the “Blur” step in the tutorial, washing out tiny terrain irregularities.

# 1. Blur the DEM for smooth, generalized contours
# Using a 9x9 moving window for an aggressive smoothing effect
w <- matrix(1/81, nc = 9, nr = 9)
r_smoothed <- terra::focal(r_dem, w, fun = mean, na.policy = "omit")

# 2. Creating contour polygons from the DEM
# We extract polygons rather than lines to fill them with color later
contour_polys <- terra::as.polygons(r_smoothed, trunc = FALSE, round = FALSE, breaks = seq(90, 200, by = 5))
contours_sf <- sf::st_as_sf(contour_polys) |> 
  dplyr::rename(elevation = 1) |>
  dplyr::mutate(layer_id = dplyr::row_number())

# 3. Ferris Bueller style summary of the hack: 
# We copy the geometries and physically shift their coordinates down and right
# to create an artificial "drop shadow" layer.
shift_x <- 15
shift_y <- -15

shadows_sf <- contours_sf
sf::st_geometry(shadows_sf) <- sf::st_geometry(shadows_sf) + c(shift_x, shift_y)
sf::st_crs(shadows_sf) <- sf::st_crs(contours_sf) # Re-assign CRS after shift

With the raw geometry prepared, we can execute the rendering. The tutorial emphasizes “Color Thievery” and crisp edge highlights. In {ggplot2}, we stack our geometries: the shifted shadows go down first with a dark, semi-transparent fill, followed by the true contours topped with a crisp, bright stroke.

# Color thievery: Let's use a trippy, vibrant palette 
trippy_pal <- colorRampPalette(c("#0d1b2a", "#1b263b", "#415a77", "#778da9", "#e0e1dd", "#ff9f1c", "#e71d36"))(nrow(contours_sf))

p_map <- ggplot2::ggplot() +
  # The Hack: Isolating the shading into a separate layer
  ggplot2::geom_sf(data = shadows_sf, fill = "#111111", color = NA, alpha = 0.35) +
  
  # The true contours with a crisp edge highlight (color = "#ffffff")
  ggplot2::geom_sf(data = contours_sf, ggplot2::aes(fill = elevation), color = "#ffffff", linewidth = 0.3) +
  
  ggplot2::scale_fill_gradientn(colors = trippy_pal, guide = "none") +
  
  ggplot2::theme_void() +
  ggplot2::theme(
    panel.background = ggplot2::element_rect(fill = "#f4f1de", color = NA),
    plot.background = ggplot2::element_rect(fill = "#f4f1de", color = NA),
    plot.margin = ggplot2::margin(20, 20, 20, 20)
  )

p_map