Short answer
QGIS is a fully capable geological mapping environment — for digitising, attributing, symbolising, and publishing maps — provided you treat it as a data system, not a drawing board. The difference between a coloured picture and a geological GIS is structure: units, contacts, faults, and structural measurements modelled as typed, attributed features with controlled vocabularies, stored in a GeoPackage or PostGIS database under one declared CRS. Symbology is then derived from attributes, the legend regenerates from the data, and every polygon can be queried, validated, and reused in cross-sections and 3D models.
A data model before a map
A geologic map encodes interpretation: where a contact is observed versus inferred, which unit is older, how confident a fault location is. The USGS GeMS (Geologic Map Schema) formalises this for digital publication, and even when you are not delivering to GeMS, its structure is a sound template:
- MapUnitPolys — the polygon units, keyed by a
MapUnitcode. - ContactsAndFaults — line features carrying a
type(contact, fault, dike margin) and anexistence/identity confidenceattribute that drives solid vs dashed rendering. - DescriptionOfMapUnits (DMU) — a non-spatial table mapping each
MapUnitcode to its name, lithology, age, and rank. This is the controlled vocabulary your symbology and labels read from. - Stations / OrientationPoints — observation points and structural measurements (strike, dip, plunge).
Model the unit code as a foreign key into the DMU table rather than repeating lithology text on every polygon. That single decision is what makes the map queryable: you can select all Jurassic units, all inferred faults, or all polygons of a lithology in one expression.
Storage: skip shapefiles for production
The shapefile format imposes constraints that actively damage geological data: field names truncate to 10 characters (Lithology becomes Litholog_1), text fields cap at 254 characters, NULLs are unreliable, and each file holds one geometry type. Use instead:
- GeoPackage (.gpkg) — an OGC standard SQLite container holding many layers, long field names, proper NULLs, and attached styles. Ideal for portable, single-analyst projects. Create related tables and even spatial indexes in one file.
- PostGIS — when several people edit concurrently, when you need relational integrity (foreign keys, triggers) and versioning, or when the dataset is large. Load with
ogr2ogr ... PG:"dbname=geo ..."and useST_Transform,ST_SetSRID, and topology functions server-side.
Set one project CRS deliberately — a projected, metric system such as the relevant UTM zone (e.g. EPSG:32633) or national grid (EPSG:27700) so that area, length, and buffer distances are real. Geographic CRS (EPSG:4326) is fine for storage and web export but wrong for measurement.
Worked workflow: from scan to publishable map
- Project and CRS. New project, set CRS to your mapping zone, create a GeoPackage to hold all layers.
- Reference data. Bring in a hillshade (from a DEM via
gdaldem hillshade) and any existing basemap; georeference field-sheet scans first if needed (Raster > Georeferencer). - Create the schema. Add empty layers for map-unit polygons, contacts/faults (line), and orientation points, with the attribute fields above. Set field constraints — e.g. a not-null
MapUnitand a value map forconfidence. - Digitise topologically. Enable Project > Snapping with vertex+segment snapping and Enable Topological Editing and Avoid Overlap, so shared boundaries are coincident and polygons do not gap or overlap. Digitise contacts as lines, then build polygons, or use the Polygonize algorithm from a clean contact network.
- Attribute. Populate
MapUnitfrom your controlled list (a value-relation widget pointing at the DMU table prevents typos). Record dip/strike on orientation points. - Symbolise from attributes. Apply Categorized renderer on
MapUnitfor polygons; style contacts/faults bytypeandconfidence(dashed for inferred). Save the style to the GeoPackage (Save Style > In GeoPackage) so it travels with the data. - Layout. Build the print layout with a data-driven legend, scale bar in the projected units, north arrow, and a credits box citing source and date.
- Validate and export. Run topology checks, then export the layout to PDF/GeoTIFF and the data to GeoPackage with metadata.
Structural symbology that reads correctly
Strike-and-dip symbols are rotation-driven. Use a marker styled with Data-defined rotation set to the strike field, and place the dip value as a label via format_number("dip", 0). This keeps the symbol oriented from data, so re-measuring a station updates the map automatically rather than requiring a hand-rotated symbol. Faults get a line symbol whose dash pattern switches on confidence through a rule-based renderer: solid where mapped, dashed where inferred, dotted where concealed.
Common pitfalls and why they happen
- Treating colour as the data model. Cause: digitising straight into a styled layer with no unit code. Fix: attribute first, colour from the attribute.
- Sliver gaps and overlaps along contacts. Cause: digitising without snapping/topological editing. Fix: enable snapping, Avoid Overlap, and run the Topology Checker before publishing.
- Mixing map scales silently. Cause: combining a 1:25,000 sheet with a 1:250,000 compilation. Fix: carry a
source_scaleattribute and never imply more precision than the coarsest source supports. - Lost interpretation confidence. Cause: not recording observed vs inferred. Fix: a mandatory
confidencefield that drives line style. - Unreusable deliverable. Cause: publishing only a flat image. Fix: ship the GeoPackage plus the PDF so others can inspect and query units and structures.
- Wrong areas in reports. Cause: computing area in EPSG:4326. Fix: use a projected CRS or ellipsoidal
area($geometry).
Validation
Before the map leaves your hands: run Topology Checker for no gaps/overlaps in the unit polygons and dangling/overshoot checks on contacts; confirm every polygon has a valid MapUnit present in the DMU table (a left join finding nulls flags orphans); verify the legend lists exactly the units used; and overlay structural symbols on the hillshade to sanity-check that dips face downslope where expected. Confirm the project CRS and source scale are recorded in the layout credits.
Bathyl perspective
Our geological mapping work turns expert interpretation into an inspectable system: the unit code is a key, not a colour; confidence is data, not a memory; and the deliverable is a queryable GeoPackage as much as a printed sheet. That discipline is exactly what lets a map feed cross-sections, terrain analysis, and 3D models later without being rebuilt.
Related reading
- GIS Data Layers Every Geological Map Needs
- Geological Units, Faults, and Structures in GIS
- QGIS Georeferencing Scanned Maps
- Geological visualization