Short answer
A geologic map is not a picture of colored areas; it is a relational dataset. The polygons that fill the map carry only a short key — the MapUnit value — and that key joins to a separate description table that holds the full unit name, age, lithology, and explanatory text. This separation is the core idea behind the USGS GeMS (Geologic Map Schema) standard, and it is what keeps a map internally consistent, queryable, and publishable. Get the key-to-description link right, enforce clean polygon topology, and the map survives editing, scaling, and handoff. Treat color as the data model, and it breaks the first time someone needs to query it.
Why polygons and descriptions must be separate tables
The temptation in any GIS is to type everything into the polygon's attribute row: unit name, age, a paragraph of description, the color. It feels direct, and it is a trap. The same unit appears in dozens or hundreds of disconnected polygons across a sheet. If the description lives in each row, then renaming the unit, correcting its age, or adjusting its lithology means editing every polygon — and the moment two rows disagree, you have two "versions" of one unit and no way to know which is canonical.
The relational fix is normalization. The polygon feature class stores one stable column, MapUnit (for example Qal, Tb, Kgr). A separate DescriptionOfMapUnits (DMU) table stores one row per unit with the long name, age, description, and symbology. A simple join on MapUnit reconstitutes the full record for display, labeling, or analysis. Edit the DMU once and every polygon updates. This is exactly the design GeMS specifies, and it is why GeMS-compliant data can be archived and republished decades later without ambiguity.
The DescriptionOfMapUnits table in practice
In GeMS, DMU is a non-spatial table that also encodes the legend itself. Beyond the join key it carries fields such as:
MapUnit— the short key, unique, the join target (left empty for heading rows).Name— the full unit name ("Alluvium", "Granite of Cedar Pass").FullName/Label— the formatted label, often with subscripts.Age— narrative age ("Holocene", "Late Cretaceous").Description— the lithologic description that appears in the explanation.HierarchyKey— an ordered string (like001-002-003) that controls legend order and indentation, so headings and nested units sort correctly.AreaFillRGB— the symbol color as an RGB triple, e.g.255,255,190.
Because DMU contains both real units and heading rows (which have no MapUnit and no polygons), it doubles as the map explanation. The rule to internalize: every distinct MapUnit value used by any polygon must have exactly one matching row in DMU, and DMU should not contain unit rows that no polygon uses without a deliberate reason. That referential integrity is the most important quality property of the whole dataset.
Enforcing the link so it cannot drift
A join is only as good as the key discipline behind it. Two mechanisms keep the key clean:
In a file geodatabase or ArcGIS Pro project, attach a coded-value or attribute domain to the polygon MapUnit field built from the DMU keys, so editors pick from a list and cannot fat-finger Qa1 instead of Qal. In PostGIS or any SQL-backed store, do it properly with a foreign key:
-- Description table is the authority
CREATE TABLE dmu (
mapunit text PRIMARY KEY,
name text NOT NULL,
age text,
description text,
hierarchykey text,
areafillrgb text
);
-- Polygons reference it; bad keys are rejected at insert time
CREATE TABLE map_unit_polys (
id serial PRIMARY KEY,
geom geometry(MultiPolygon, 26911),
mapunit text NOT NULL REFERENCES dmu(mapunit)
);
Now an attempt to assign a polygon to a unit that does not exist fails immediately rather than silently creating a phantom unit that surfaces months later as an unexplained color. Label the map by joining on mapunit and rendering dmu.label — never by storing the human-readable label per polygon, which reintroduces the duplication you just removed.
Topology: polygons that tile the map cleanly
A geologic map's polygons should form a coverage: they tile the mapped area with no gaps and no overlaps. Two units cannot both occupy the same ground, and there should be no slivers of undefined space between them. Contacts (the boundary lines) should coincide exactly with shared polygon edges.
Validate it explicitly. In QGIS, the Topology Checker plugin with rules "must not overlap", "must not have gaps", and "must not have invalid geometries" flags problems before publication. With GDAL/PostGIS:
-- Find invalid geometries
SELECT id, ST_IsValidReason(geom)
FROM map_unit_polys
WHERE NOT ST_IsValid(geom);
-- Find overlaps between distinct polygons
SELECT a.id, b.id
FROM map_unit_polys a
JOIN map_unit_polys b ON a.id < b.id
WHERE ST_Overlaps(a.geom, b.geom);
ST_MakeValid repairs self-intersections and ring problems, but inspect the result — automated repair can move vertices. In GeMS the contacts and the polygon boundaries are kept in sync because the polygons are typically built from the contact-and-fault linework, which guarantees that every polygon edge is an attributed contact line carrying its own existence confidence and location confidence.
Separating observation, interpretation, and presentation
A robust geologic GIS keeps three things in different places: what was observed (station points, outcrop descriptions, structural measurements), what was interpreted (unit polygons, contacts, faults), and how it is presented (colors, line styles). Mixing them is the source of most downstream confusion. The polygon's MapUnit is an interpretation; its color in AreaFillRGB is presentation; the field stations that justify the boundary are observation. GeMS provides separate feature classes and tables for each, which is why the schema can support both a printed sheet and an interactive query interface from one source.
Common pitfalls and why they happen
- Color as the data model. Symbology is duplicated into rows and treated as the unit identity, so two polygons "the same yellow" but with different keys look identical yet query differently. Drive color from DMU only.
- Free-text labels per polygon. Typing the label into each polygon guarantees eventual inconsistency, because manual entry across hundreds of features always drifts. Render labels from the join.
- Mixing source scales silently. Splicing a 1:24,000 sheet against a 1:250,000 sheet without recording the difference implies a precision that does not exist; boundaries digitized at small scale are not interchangeable with detailed mapping. Carry a
DataSourceIDper feature. - Digitizing a scan without uncertainty. Tracing an old paper map loses the original location confidence; record the source and a location-confidence value so later users know the line is approximate.
- Orphaned keys. A polygon with a
MapUnitabsent from DMU renders as an unexplained area. A foreign key prevents it; a periodic anti-join audit catches legacy cases.
Validation checklist
- Every
MapUnitin the polygons has exactly one DMU row; run an anti-join both directions. - Topology passes: no overlaps, no gaps, valid geometries, contacts coincide with edges.
- Labels and colors derive from DMU, not from per-polygon fields.
- Each feature records its source (
DataSourceID) and, for contacts, existence and location confidence. - The CRS is explicit and appropriate to the mapping scale (a projected CRS such as a UTM zone for detailed work).
Bathyl perspective
We build geologic maps as relational systems first and cartographic outputs second. When the polygon carries only a stable key and the description table is the single authority, the same dataset can drive a printed sheet, a PostGIS query, and an interactive web viewer without anyone retyping a unit name. The geologist's interpretation stays intact; it just becomes something you can query instead of only look at.
Related reading
- Subsurface Data and Surface Maps
- Cross Section Data in GIS Workflows
- Remote Sensing for Geological Mapping
- Geological visualization