Skip to content
Back to skills

Study Area Map

ASecurity

Use when building a study-area location or setting map for a paper in R with ggplot2 + sf + terra — nested locator panels (country → province → site), shaded-relief DEM basemaps, land-use and other categorical rasters, classed continuous rasters, sampling sites with graduated symbols, one locator with several thematic panels, zoom leader lines, in-panel or strip legends, north arrows and scale bars. Also covers sourcing boundary and elevation data, including reading ArcGIS and MapGIS files.

  • 13 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 22, 2026
ai-agentsgo

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned September 25, 2026

npx -y skills add keros68/xiaoyu-skill --skill study-area-map --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Study Area Map?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Study Area Map
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/keros68-study-area-map/badge)](https://www.skillsdirectory.com/skills/keros68-study-area-map)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: study-area-map
description: Use when building a study-area location or setting map for a paper in R with ggplot2 + sf + terra — nested locator panels (country → province → site), shaded-relief DEM basemaps, land-use and other categorical rasters, classed continuous rasters, sampling sites with graduated symbols, one locator with several thematic panels, zoom leader lines, in-panel or strip legends, north arrows and scale bars. Also covers sourcing boundary and elevation data, including reading ArcGIS and MapGIS files.
---

# study-area-map

Builds the frame of a study-area map: projection, window, basemap, thematic layers, panel composition and map furniture. The details that are easy to get wrong carry assertions, so a wrong window, a blank raster edge, a legend on the frame or an inset on land stops the script instead of reaching the journal.

## Modules

Source in this order; later files use earlier ones.

| File | Contents |
|---|---|
| `reference/relief_basemap.R` | constants `LW`, `LW_DAT`, `TXT_PT`, `TXT_GG` (set only if undefined, so a house-style preamble wins), `ensure_font()`, `theme_map_pub()`; windows `inscribed_window()`, `bbox_union()`, `fit_aspect()`, `win_aspect()`, `pad_win()`, `pad_until_clear()`; DEM `load_dem()`, `vsizip_tiles()`, `locate_na()`; relief `shade_factor()`, `relief_rgb()`; furniture `north_needle()`, `elev_legend_block()`, `legend_backing()`, `frac_fun()`, `assert_inside()`, `FRAME_PAD`; insets `inset_aspect()`, `corner_inset()`, `inset_is_clear()`, `assert_inset_clear()`, `widen_for_inset()`; composition `pin_panel()`, `panel_margins()`, `with_font_device()`, `box_in()`, `add_leaders()`, `credit_footer()`; checks `assert_window()`, `check_cn_content()` |
| `reference/palettes.R` | `pal_hypso()`, `elev_breaks()`, `elev_labels()`, `preview_hypso()`, `check_ramp()`, `simulate_cvd()`, `to_gray()`, `assert_accent_unique()`, `PAL_SURROUND`, `BRK_SURROUND` |
| `reference/thematic.R` | `class_rgb()`, `graduated_sizes()`, `legend_rows_block()`, `assert_within_reserved()`, `mm_win()`, `legend_panel()` |

Set region constants (paths, CRS, windows, accent colour) in the figure script, not in the modules, so several figures in one paper can share them.

## Start from the closest example

Copy the matching script from `example/`, change the data block at the top, then adapt. Each writes a 300 dpi PNG and a 150 dpi preview.

| Figure | Start from |
|---|---|
| Locator + one main map, relief basemap | `taiyuan_locator.R` (two levels) |
| Country → province → site with zoom leaders; South China Sea in frame or as corner inset | `taiyuan_three_level.R` (`SCS_INSET`) |
| Locator + several thematic maps of one area (terrain, land use, sites, a continuous variable) | `taiyuan_thematic.R` |

The thematic example uses synthetic land use, sites and SOC generated from a fixed seed; see `guides/data-sources.md` before replacing them with real data.

## Decide before drawing

A location map answers *where is this, and why does the location matter?* Settle these first; each one constrains the layout.

1. **Zoom levels.** Two (country → site) is usually enough. Three only when the province is itself the reason — an administrative dataset, a provincial policy, a regional geological unit. Each extra level costs a panel and buys less than the previous one.
2. **What the main panel shows.** Terrain when relief explains the study (a basin against its rim, a fault-bounded graben); land use, a continuous variable or sampling sites when that is the evidence; a quiet vector map when location is all that matters. A relief basemap that explains nothing is decoration.
3. **How quiet the basemap is.** Locator panels and any panel carrying many symbols get a pale, neutral base (vector fills, a grey relief surround, or `wash`). Full colour is reserved for the panel whose colour is the message.
4. **One accent colour means "study area", everywhere.** Locator highlight, province outline, main-panel boundary — the same hex, used by nothing else, including point fills. `assert_accent_unique()` enforces it.
5. **Where legends go.** Inside the panel needs an empty corner (`pad_until_clear()`); small panels in a set take legend strips below (`legend_panel()`).
6. **Which furniture.** Coordinates when position matters, scale bar when distance matters, north arrow only when orientation is not already clear — once per panel set.

## Workflow

| Step | Do | Details |
|---|---|---|
| 1 Data | Name every path in a data block; one projected CRS for all layers | `guides/data-sources.md` |
| 2 Window | Inscribed rectangle for raster panels; data bbox of every layer for country panels; fix the slot size, then `fit_aspect()`; `coord_sf()` last | `guides/window-and-projection.md` |
| 3 Basemap | `load_dem()` (asserts no-data), `elev_breaks()` from this DEM, preview and check ramps, `relief_rgb()`; mask or veil locators | `guides/relief.md` |
| 4 Thematic layers | `class_rgb()` for classes, classed `relief_rgb(strength = 0)` for continuous values, `graduated_sizes()` for points; mask to the study area over a neutral surround | `guides/thematic-layers.md` |
| 5 Compose | `pin_panel()` sizes, `arrangeGrob()` in mm, margins from `panel_margins()` inside `with_font_device()`; leaders via `box_in()` + `add_leaders()` | `guides/composition.md` |
| 6 Furniture | Hand-drawn legends laid out in mm, needle arrow, clearance from the frame, corner budget | `guides/furniture.md` |
| 7 Check | `assert_window()` on every panel, `check_cn_content()` for national maps, then look at the preview at final size | checklist below |

This skill overlaps with rfigure.skill's *China Maps And Site Distributions* section and corrects one measured error in it: inset sizing from transformed corner points (see `guides/composition.md`).

## Checklist

- [ ] One projected CRS for every layer
- [ ] Raster fills the frame — no blank corners, no-data fraction asserted and printed
- [ ] Country panel window derived from the data bbox of every layer, not a lon/lat rectangle
- [ ] `assert_window()` passes for every panel; every panel frame the intended width, no letterboxing
- [ ] Relief multiplied in, not alpha-blended; elevation classes discrete, edges derived from this DEM, alternate boundaries labelled
- [ ] One accent colour for the study area, used nowhere else; `assert_accent_unique()` passed
- [ ] Every class and symbol on the map appears in the legend, and vice versa; no class too small to see
- [ ] Legends and furniture clear of the frame and of the study area; nothing collides with panel tags
- [ ] Leader lines, if present, collide with nothing; target-side axis labels moved away
- [ ] Boundary source, DEM source, generalised relief and any synthetic data named in the caption or source line
- [ ] Companion figures share the basemap module, window and graticule spacing

## Common mistakes

- Alpha-blending the hillshade, then compensating with a more saturated palette
- `st_bbox()` of a transformed lon/lat rectangle for a country panel — silently amputates the south
- Taking the window from one layer's bbox when several layers must fit — partial line layers cut whole regions off
- A `geom_sf()` added after `coord_sf(xlim =, ylim =)` — the limits are silently discarded
- Sizing an inset from a corner-bbox aspect ratio instead of the rendered panel ratio
- A corner inset dropped into a window fitted to the land — it covers part of the map and nothing looks wrong
- Calling `ggplotGrob()` with no font-aware device open
- A white casing under the accent-coloured boundary: at figure scale it reads pink and no longer matches its legend swatch
- Built-up land or site symbols in a red close to the accent
- Forcing a class legend into a 60 mm panel instead of a legend strip
- Four separate furniture boxes in four corners of a panel that only has two free ones
- Letting a 5 km DEM be described as the study-area DEM

Files in this skill

  • .gitignore41 B
  • LICENSE1 KB
  • README.md8.7 KB
  • SKILL.md30.9 KB
  • example/taiyuan_locator.R7.7 KB
  • example/taiyuan_three_level.R14.9 KB
  • reference/palettes.R8.8 KB
  • reference/relief_basemap.R27.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.