Short answer

Borehole data only becomes useful in GIS when you stop treating a hole as a single point and start treating it as a 3D object defined by three linked tables: a collar (where the hole starts), a downhole survey (how it bends), and interval logs (what the rock is, from depth to depth). The hard part is not loading points. It is computing the real-world XYZ position of every logged interval from measured depth and survey angles, in a consistent CRS and vertical datum, so that lithology, assays, and structural picks land where the rock actually is.

If you flatten interval data onto the collar coordinate, you discard the depth axis that the entire dataset exists to capture. Almost every "borehole in GIS" failure traces back to that one mistake or to a units and datum mismatch downstream of it.

The minimum data model

A defensible borehole dataset is relational, not a single flat layer. The standard shape used across mining and geotechnical software (Leapfrog, Micromine, Datamine, the QGIS Geoscience plugin) is:

Collar table

One row per hole. Required fields:

  • HoleID (primary key, text, unique)
  • X, Y — collar location in a defined projected CRS
  • Z — collar elevation (ground level or reduced level), in a defined vertical datum
  • TotalDepth — final measured depth (MD) along the hole

Survey table

Many rows per hole, joined on HoleID. This is the deviation record:

  • Depth — measured depth of the survey station, in metres along the hole
  • Azimuth — bearing of the hole at that station, 0–360 degrees (record whether it is grid or magnetic north — this matters)
  • Dip — inclination, typically negative for holes pointing down (a vertical hole is −90)

Even "vertical" holes deviate. A 300 m hole logged as vertical can wander 5–15 m off plumb. If you have no survey, you assume a straight hole at the collar dip and azimuth and you state that assumption.

Interval (downhole) tables

One table per data theme — lithology, alteration, assays, geotechnical (RQD), structure — each with:

  • HoleID
  • From, To — interval start and end as measured depth
  • the attribute(s): Lithology, Au_ppm, RQD, etc.

Validation rule that catches most errors: within a hole, intervals must not overlap, must not have gaps you did not intend, and From < To, with To of the last interval not exceeding TotalDepth. A simple SQL check finds violations:

SELECT a.HoleID, a."From", a."To"
FROM litho a
JOIN litho b ON a.HoleID = b.HoleID
WHERE a."From" < b."To" AND a."To" > b."From" AND a.ctid <> b.ctid;

Why depth is not elevation

The single most common conceptual error is treating measured depth as depth below surface. Measured depth (MD) is distance travelled along the borehole from the collar. True vertical depth (TVD) is the vertical drop. They are equal only in a perfectly vertical hole.

For an inclined hole, an interval at 200 m MD in a hole dipping at −60 degrees sits at a TVD of roughly 200 × sin(60°) = 173 m below the collar, and it has also moved horizontally by 200 × cos(60°) = 100 m from the collar. Place that interval at the collar XY and 200 m down and you have put the rock 27 m too deep and 100 m away from where it is.

So the elevation of any interval point is:

Z_interval = Z_collar − TVD(depth)

computed in the same vertical datum as the collar Z. If collars were levelled to a height above EGM2008 geoid (orthometric) but you mix in a DEM referenced to the WGS84 ellipsoid, you can introduce a 20–40 m vertical offset before any geology is even involved. Decide the vertical datum once and convert everything to it.

Computing downhole XYZ: minimum curvature

To turn the survey table into a 3D trace, you desurvey the hole — interpolate position between survey stations. The industry-standard method is minimum curvature, which fits a circular arc between two stations rather than a straight segment.

Between station 1 (depth, azimuth I₁, dip) and station 2, with measured length ΔMD between them:

  1. Compute the dogleg angle DL (the total angular change between the two orientation vectors).
  2. Compute the ratio factor RF = (2 / DL) × tan(DL / 2) (RF → 1 as DL → 0).
  3. The increments are weighted averages of the direction vectors at both stations, scaled by (ΔMD / 2) × RF.

The tangential method (using only the lower station's angles) is simpler but systematically biases the trace in curved holes; balanced tangential is better; minimum curvature is the accepted default. Most GIS and modelling tools implement it, so you rarely code it by hand — but you must know which method your tool used, because mixing desurvey methods between datasets produces traces that disagree by metres at depth.

In practice you do this in dedicated tooling: the QGIS Geoscience plugin (downhole tools), Leapfrog Geo, Micromine, or a Python desurvey with pandas. The output is either a 3D polyline per hole or a point per interval midpoint with computed X, Y, Z.

Worked workflow in QGIS

  1. Load the three CSVs as tables. Set the collar layer's CRS explicitly — say EPSG:32735 (WGS84 / UTM zone 35S) for a southern-Africa project. Do not let QGIS guess.
  2. Install the Geoscience plugin (Plugins → Manage and Install). Use its "Downhole Data" tool, point it at the collar, survey, and interval tables joined on HoleID.
  3. Generate desurveyed traces and interval points. The plugin applies minimum curvature and writes X/Y/Z attributes you can inspect.
  4. Sanity-check the collars against a DEM. In the Field Calculator, sample the DEM elevation at each collar XY and compare to the surveyed Z. Differences beyond a few metres usually mean a CRS or datum mismatch, not bad surveying.
  5. Style lithology with a categorised renderer on the interval points, and view in the QGIS 3D Map view or export to a 3D format.
  6. Build sections with the qProf or Geoscience sectioning tool: define a section line, set a projection corridor (e.g. 50 m each side), and plot lithology against distance and elevation.

For multi-user projects, store the tables in PostGIS. Create the collar geometry with ST_SetSRID(ST_MakePoint(x, y, z), 32735) and use a 3D geometry type (PointZ) so the elevation rides with the coordinate. A GiST spatial index on the collar geometry keeps map queries fast as the database grows.

Common pitfalls and why they happen

  • Azimuth reference confusion. Surveys recorded in magnetic north plotted as grid north rotate the entire hole trace by the local declination (can exceed 20 degrees in high-latitude or mineralised ground). Always record and convert the reference.
  • Negative vs positive dip convention. Some tools expect −90 for a vertical down-hole, others expect +90. A sign flip sends your trace into the sky. Check one known hole visually before trusting a batch.
  • Overlapping intervals. Re-logging that was never reconciled leaves two lithologies claiming the same depth. The SQL overlap check above catches it; ignoring it double-counts assay length in compositing.
  • Mixing vertical datums. Collar RLs from a total station (orthometric) combined with GNSS ellipsoidal heights without a geoid correction. The geology looks fine in plan and is wrong in section.
  • Desurvey method drift. Importing pre-computed XYZ from one package and re-desurveying in another, then comparing — the two disagree at depth and someone "fixes" real data to match an artefact.

QA and validation

Before borehole data feeds a model, report, or decision:

  • Confirm collar count equals unique HoleID count in every table (orphan survey or assay rows mean a typo in the key).
  • Confirm From/To continuity and no overlaps per hole.
  • Verify the CRS and vertical datum are written into the project metadata, not assumed.
  • Plot all collars over a basemap and over the DEM — outliers usually expose a transposed X/Y or a zone error.
  • Render one fully desurveyed hole in 3D and confirm depth, dip, and azimuth match the driller's record.

Bathyl perspective

Borehole data is the rare geoscience dataset where the third dimension is the whole point, so we treat the collar-survey-interval model and a single declared vertical datum as non-negotiable foundations. The goal of a good borehole GIS is not a tidy point layer but an inspectable 3D object a geologist can section, query, and defend against the original logging sheets.

Related Bathyl reading

Sources