High-resolution PNG map generator for seismicity visualisation, built on the SeisComP framework. Reads SCML (SeisComP Markup Language) event files or queries a live SeisComP database, then renders publication-quality maps with Cartopy and matplotlib.
Design follows established seismological conventions (GMT, USGS, EMSC, GFZ) with perceptually uniform colour scales, colourblind-safe markers, and a clean Tufte-inspired low-data‑ink basemap.
- Three input modes — SCML XML files (
-i), database by event ID (-E), or database by time range (--start-time/--end-time) - Five map modes — event markers (depth‑coloured, magnitude‑scaled), Gutenberg‑Richter b‑value heatmap, magnitude‑of‑completeness (MAXC), annual seismicity rate, and Wadati diagram for Vp/Vs estimation
- Focal mechanisms — beach‑ball rendering for events with moment tensor or nodal‑plane data (requires ObsPy)
- Station locations — derived from arrival azimuth/distance
- Wadati diagram —
--mode wadatiplots S–P vs P travel times with least‑squares Vp/Vs fit; optional--velocity-modeloverlays theoretical curves from SeisComP LOCSAT tables and adds model‑predicted S points for P‑only stations - City labels — loaded from the SeisComP
cities.xml, with density‑aware collision avoidance and population filtering - Professional layout — scale bar, north arrow, graticule, inset overview map, depth colour‑bar, magnitude reference circles, event‑type legend
- OpenStreetMap tiles — optional
--osmflag swaps the vector land/ocean basemap for OSM raster tiles, providing roads, terrain, and built‑up area context beneath event markers - Fully configurable — all colours, sizes, DPI, and dimensions are adjustable via CLI
- Step‑by‑step debug logging —
--debugprints extent, margins, label counts, and analysis grid stats
scmap Pro removes the watermark from generated maps for publication use.
Pro users see a Licensed to badge in the bottom-left corner of every map.
The Pro edition is distributed as a compiled license module (license_check.so) — no Python patching, no environment changes.
| Benefit | Community | Pro |
|---|---|---|
| Watermark | Diagonal "UNLICENSED" | None |
| License badge | — | Licensed to <customer> |
| Future Pro‑only features | — | Access to new modes and tools |
| Support | — | Priority email |
Contact donavinliebgott@gmail.com to purchase an annual license for your institution. Licences are issued per organisation and include updates for the validity period.
See PRO_FEATURES.md for a full roadmap of current and planned Pro capabilities.
You will receive two files:
| File | Place here |
|---|---|
license_check.so |
Same directory as scmap.py |
scmap.crt |
~/.seiscomp/licenses/ or ~/seiscomp/share/licenses/ |
Confirm the installation:
scmap --debug 2>&1 | grep Licensed
# Licensed to SARAOIf the .so or .crt is missing, scmap falls back to the community
edition and applies the watermark automatically — no error, no crash.
| Dependency | Purpose |
|---|---|
| SeisComP ≥ 5.0 | seiscomp.client, seiscomp.datamodel, seiscomp.core, seiscomp.io, seiscomp.logging |
| numpy | numerical arrays |
| matplotlib ≥ 3.3 | plotting |
| Cartopy ≥ 0.18 | map projections, coastlines, borders |
| ObsPy (optional) | focal‑mechanism beach balls |
| MySQL / PostgreSQL / SQLite driver (optional) | database queries |
The SeisComP Python packages are shipped with the SeisComP installation under
$SEISCOMP_ROOT/lib/python. Set PYTHONPATH (or SEISCOMP_ROOT) so that
import seiscomp.client resolves:
export SEISCOMP_ROOT=$HOME/seiscomp
export PYTHONPATH=$SEISCOMP_ROOT/lib/python:$PYTHONPATHpip install numpy matplotlib cartopy obspyscmap [options]
# Render all events from an SCML file
scmap -i events.xml -o map.png
# Fixed geographic region with custom margin
scmap -i events.xml -o map.png --region 10x8+35+20 -m 5
# Query a single event from the database
scmap -E smi:org.gfz-potsdam/event1 -d sysop:sysop@localhost:18002/seiscomp
# All events from the last 24 hours (limit 50)
scmap --start-time "2026-06-15" -d sysop:sysop@localhost:18002/seiscomp \
--limit 50 -o map.png
# b-value heatmap, 0.5° grid, 80 km sample radius
scmap -i events.xml --mode bvalue --grid-size 0.5 --grid-radius 80
# Magnitude-completeness map
scmap -i events.xml --mode mc --grid-size 0.5
# Rate map with log file
scmap --start-time "2026-06-01" -d sysop:sysop@localhost:18002/seiscomp \
--mode rate --grid-size 0.3 --grid-radius 60 --log-file scmap.log
# Thin out city labels in a dense region
scmap -i events.xml --min-city-population 20000 --city-spacing 1.5
# Debug output showing map build steps
scmap -i events.xml --debug
# Use OpenStreetMap raster tiles as the base map
scmap -i events.xml --osm -o map.png
# Wadati diagram for a single event from the database
scmap -E SEC2026mhzy -d localhost --mode wadati -o wadati.png
# Wadati diagram with theoretical overlay from a LOCSAT velocity model
scmap -E SEC2026mhzy -d localhost --mode wadati --velocity-model iasp91_scanloc \
-o wadati.png
# Wadati diagram for a time range with explicit centre and auto-zoom
scmap --start-time "2026-06-22 16:00" --end-time "2026-06-23 09:00" \
-d localhost --lat -26.4 --lon 27.4 --mode wadati -o wadati.png
# Wadati diagram with fixed region, custom margin, and velocity-model overlay
scmap --start-time "2026-06-22" --end-time "2026-06-23" \
-d localhost --lat -26.4 --lon 27.4 --margin 5 \
--mode wadati --velocity-model iasp91 -o wadati.pngGenerates all four map modes (events, b‑value, Mc, rate) in a single invocation. Edit the defaults at the top of the script to set your own region and database, or override them via environment variables.
# Last 7 days (uses $LAT / $LON / $DB defaults)
./scmap-all.sh -d 7
# Last 30 days
./scmap-all.sh -d 30
# Explicit date range
./scmap-all.sh "2026-06-01" "2026-06-18"
# Start date only → end defaults to now
./scmap-all.sh "2026-06-15"Customising the region and database:
# Override via environment variables
LAT=50 LON=8 MARGIN=6 DB="sysop:sysop@10.202.50.1:18002/seiscomp" ./scmap-all.sh -d 30
# Or edit the defaults block at the top of scmap-all.sh:
# LAT="${LAT:--29}" # centre latitude
# LON="${LON:-25}" # centre longitude
# MARGIN="${MARGIN:-8}" # margin in degrees
# DB="${DB:-localhost:18002/seiscomp}"
# GRID_SIZE="${GRID_SIZE:-1.5}"
# GRID_RADIUS="${GRID_RADIUS:-300}"
# MC_HINT="${MC_HINT:-0.5}"
# RATE_PERIOD="${RATE_PERIOD:-0}"
# CITY_POP="${CITY_POP:-50000}"Output files: map_events.png, map_bvalue.png, map_mc.png,
map_rate.png, map_wadati.png.
The four map modes are generated with:
./scmap-all.sh "2026-06-10" "2026-06-18"
The Wadati diagram below uses a 7‑day window with automatic extent and the
iasp91_scanloc velocity model (see Wadati diagram).
Depth‑coloured event markers with magnitude‑proportional sizing, station locations derived from arrivals, and city labels for population ≥ 50 000.
Gutenberg‑Richter b‑value computed via Aki‑Utsu MLE on a 1.5° × 1.5° grid with 300 km sampling radius and Mc = 0.5. Warm (red) = high b‑value, cool (dark) = low b‑value. Cells with fewer than 10 events are blank.
Maximum‑curvature Mc estimate on the same grid. Dark = high Mc (catalogue complete only at larger magnitudes); bright = low Mc (small events detected). Cells with fewer than 15 events are blank.
Weekly event rate (events / km² / week) for M ≥ 0.5, normalised to 7 days. Bright = high activity, dark = low. Cells with fewer than 5 events are blank.
S‑P vs P travel times for stations with both phases, coloured by event.
Linear least‑squares fit gives Vp/Vs = 1.75 (slope = Vp/Vs − 1) with R² =
0.95. The optional --velocity-model flag overlays theoretical travel‑time
curves from SeisComP LOCSAT tables; P‑only stations with model‑predicted S
times appear as orange squares.
| Flag | Description |
|---|---|
-i, --input |
SCML XML file (use "-" for stdin) |
-E, --event |
Event ID(s) from database (comma‑separated) |
--start-time |
Time‑window start ("YYYY-MM-DD [HH:MM[:SS]]") |
--end-time |
Time‑window end (defaults to now) |
--limit |
Max events from a time‑range query (0 = unlimited) |
| Mode | Description |
|---|---|---|
| events (default) | Individual event markers with depth colouring and magnitude‑proportional size |
| bvalue | Gutenberg‑Richter b‑value via Aki‑Utsu maximum‑likelihood estimator: b = log₁₀(e) / (M̄ − Mc), where Mc is set by --mc-hint |
| mc | Magnitude of completeness via maximum curvature (MAXC) |
| rate | Annual seismicity rate (events / km² / year) above Mc set by --mc-hint |
| wadati | Wadati diagram — plots S‑P vs P travel times for stations with both phases. A linear least‑squares fit gives Vp/Vs = slope + 1. When --velocity-model is set, theoretical travel times from the model are overlaid and P‑only stations contribute model‑predicted S‑P points (orange squares) |
All analysis modes use a grid with configurable --grid-size (degrees) and
--grid-radius (km). Each grid node samples events within the radius and
requires a minimum count before computing a value.
| Flag | Default | Description |
|---|---|---|
--grid-size |
0.5 | Grid cell spacing in degrees |
--grid-radius |
50 | Sample radius in kilometres |
--mc-hint |
1.5 | Lower magnitude cutoff for b‑value and rate |
--rate-period |
0 | Rate normalisation in days (0 = auto annual). Set to 7 for weekly, 1 for daily |
--velocity-model |
— | SeisComP LOCSAT travel‑time table profile (e.g. iasp91, iasp91_scanloc, tab). Overlays theoretical travel‑time curves on the Wadati diagram and derives model‑predicted S‑P values for stations with only a P pick. Only used with --mode wadati |
| Flag | Default | Description |
|---|---|---|
-o, --output |
map.png |
Output PNG path |
-r, --region |
— | Map region (lat×lon+lat₀+lon₀ or +lat₀+lon₀+lat₁+lon₁) |
-m, --margin |
3.0 | Margin in degrees around event centre |
--lat |
— | Centre latitude |
--lon |
— | Centre longitude |
--dimension |
1600×1000 |
Output size in pixels (WxH) |
--dpi |
150 | Output resolution |
--title |
— | Override map title |
| Flag | Default | Description |
|---|---|---|
--depth-max |
200 | Maximum depth for colour scale (km) |
--min-mag |
0 | Minimum magnitude for marker scale |
--max-mag |
8 | Maximum magnitude for marker scale |
--min-marker-size |
20 | Minimum marker area |
--max-marker-size |
450 | Maximum marker area |
| Flag | Default | Description |
|---|---|---|
--min-city-population |
100 000 | Minimum population to display a label |
--city-spacing |
1.0 | Spacing multiplier — higher = fewer labels, lower = more |
--no-cities |
— | Disable all city labels |
City label placement uses a density‑aware collision‑avoidance algorithm:
- Text‑size estimate — converts font size, character count, canvas dimensions, and DPI into an approximate degree‑span for each label.
- Density multiplier — when candidate density exceeds 3 cities/deg², margins are scaled up (up to 4×) to thin out labels in crowded regions.
- User factor —
--city-spacingacts as a global multiplier on all margins. Values below 1.0 allow more labels (tighter), values above produce sparser labels.
| Flag | Effect |
|---|---|
--no-legend |
Hide legend / parameter box |
--no-stations |
Hide station triangles |
--no-beachballs |
Hide focal‑mechanism beach balls |
--no-borders |
Hide country borders |
--no-inset |
Hide overview inset map |
--no-labels |
Hide magnitude text labels on event markers |
--no-cities |
Hide city labels |
--show-rivers |
Draw major rivers |
--show-states |
Draw province/state boundaries |
Inherited from seiscomp.client.Application:
| Flag | Description |
|---|---|
-d, --database |
Database URI: [mysql://]user:pass@host[:port]/db |
-H, --host |
Messaging host/queue (default localhost/production) |
--debug |
Debug logging (--verbosity=4 --console=1) |
--log-file |
Write log output to file instead of stderr |
--plugins |
Load SeisComP plugins |
--offline |
Disable messaging connections |
-h, --help |
Show full help |
-V, --version |
Show framework version |
The -d flag accepts SeisComP‑style database URIs:
sysop:sysop@localhost:18002/seiscomp
mysql://sysop:sysop@localhost/seiscomp
Without a scheme prefix, the driver is inferred from core.plugins in
global.cfg (e.g. dbmysql, dbpostgresql, dbsqlite3).
- Default (no
--log-file): messages go to stderr (terminal). - With
--log-file scmap.log: messages go to the file; console is silent. --debug: enables verbose step‑by‑step diagnostic output including map extent, margin, grid dimensions, label counts, collision margins, analysis cell fill‑rates, and render timing.
scmap follows established seismological map conventions:
Uses inferno_r — a perceptually uniform, colourblind‑safe
colormap that progresses warm‑shallow to cool‑deep. This avoids the
traditional red‑green‑blue triad which fails under deuteranopia (~5 % of
males) and produces phantom discontinuities. All Crameri/Brewer scientific
colormaps pass CVD testing; jet and rainbow are explicitly rejected by
Nature, EGU journals, and Crameri et al. (2020).
Markers scale by area ∝ 10^M (moment‑proportional) rather than energy (10^(1.5M)). This keeps the size range manageable — M 8 events remain readable without overwhelming the map — while preserving the relative visual weight between magnitudes. Reference circles at M 2, 4, 6, 8 appear in the legend, drawn to the exact scale used on the map.
Low‑saturation land (#F2EFE9, pale tan) and ocean (#DCE4EC, pale
steel‑blue) maximise contrast with event markers — a Tufte "data‑ink
ratio" approach. Coastlines (0.3 pt), borders (0.2 pt), and grid lines
(0.15 pt) are deliberately thin to let the data dominate.
Clear hierarchy: 14 pt bold title → 8 pt subtitle → 7 pt legend titles → 6 pt legend body → 5 pt magnitude labels. All labels use sans‑serif for readability at small sizes. Ink weight increases with importance.
scmap recognises all SeisComP event types and groups them for the legend:
| Group | Symbol | Example types |
|---|---|---|
| Earthquake | ● | earthquake |
| Induced / Triggered | ◆ | induced earthquake, fluid injection |
| Explosion / Blast | ★ (red) | quarry blast, nuclear explosion |
| Volcanic | ▲ (purple) | volcanic eruption, lahar |
| Landslide / Avalanche | ▼ | landslide, rock avalanche |
| Collapse | ■ | mine collapse, building collapse |
| Rock Burst | ■ (orange) | rock burst |
| Meteor / Impact | ✕ (orange) | meteor impact, meteorite |
| Sonic | ⎯ | sonic boom |
| Anthropogenic | ◆ | anthropogenic event |
| Other / Unknown | · | not reported, other event |
scmap/
├── scmap.py # main application
├── scmap-all.sh # batch script — all four map modes in one run
├── scmap.txt # usage reference (auto‑generated by --help)
├── _license.py # community edition stub (always unlicensed)
├── _license_pro.py # Pro edition wrapper (loads license_check.so)
├── license_check.c # C source for Pro license verification
├── certs/
│ └── scmap-ca-cert.pem # CA public certificate
├── PRO_FEATURES.md # planned Pro feature roadmap
├── tools/
│ └── gen_license.sh # license issuer (requires CA key, kept offline)
├── map.png # sample output
├── README.md # this file
└── .gitignore
The Aki‑Utsu (1965) maximum‑likelihood estimator for magnitudes M ≥ Mc:
where mc_hint, default 0.5 in the batch script, configurable via
--mc-hint). Grid nodes with fewer than 10 events are left blank (NaN).
The maximum curvature method (MAXC; Wiemer & Wyss 2000) bins events by 0.1 magnitude units and finds the bin with the highest frequency. Mc is estimated as the bin centre + 0.2. Nodes with fewer than 15 events are left blank.
Annual event rate per km² for M ≥ Mc, where Mc is set by --mc-hint:
where
For each origin, arrivals are grouped by phase code (via Phase.code() — P‑type
starting with P, S‑type starting with S). A P arrival is paired with the
S arrival from the same station by minimising the distance difference
(tolerance ≤ 0.5°) and checking azimuth consistency (≤ 10°). The P travel time
is derived from the pick time minus origin time (not from arrival.time(),
which is often unset in the database).
For each pair the point
gives the Vp/Vs ratio as
When --velocity-model is given:
- Theoretical curve — the LOCSAT travel‑time table computes P and S travel times at each paired station's distance. These are plotted as a green scatter with a separate Vp/Vs line.
- P‑only stations — stations with only a P pick receive a model‑predicted S travel time, plotted as orange squares. This fills the diagram with additional data without requiring S picks.
- Ensure SeisComP Python bindings are on
PYTHONPATH. - Make changes to
scmap.py. - Run
python3 scmap.py --helpto verify CLI integrity. - Test with both XML file input and database input where possible.
Donavin Liebgott — donavinliebgott@gmail.com
scmap is dual‑release:
- Community edition — free, watermarked, open source.
- Pro edition — paid, watermark‑free, delivered as a compiled license module.
SeisComP is distributed under the GNU AGPL v3 by the GEOFON Program at GFZ Potsdam.
- Aki, K. (1965). Maximum likelihood estimate of b in the formula log N = a − bM and its confidence limits. Bull. Earthq. Res. Inst., 43, 237–239.
- Crameri, F., Shephard, G.E., & Heron, P.J. (2020). The misuse of colour in science communication. Nature Comms., 11, 5444.
- Tufte, E.R. (2001). The Visual Display of Quantitative Information (2nd ed.). Graphics Press.
- Wessel, P., Luis, J.F., Uieda, L., et al. (2019). The Generic Mapping Tools version 6. Geochem. Geophys. Geosyst., 20, 5556–5564.
- Wiemer, S. & Wyss, M. (2000). Minimum magnitude of completeness in earthquake catalogs: Examples from Alaska, the Western United States, and Japan. Bull. Seismol. Soc. Am., 90(4), 859–869.
- SeisComP documentation
- SeisComP on GitHub
- Crameri Scientific Colormaps




