Skip to content
A

Getting started

cpt-anywidget is a set of anywidget viewers for cone penetration tests (CPTs) and geotechnical borehole logs. The viewers accept CPT data from any source: if you can load it into Python, you can plot it. The viewers work in marimo and Jupyter notebooks. All viewers share one zoomable vertical axis. The axis shows depth below surface, or elevation in m NAP.

The package contains three viewers:

  • CPTViewer shows one CPT: measurement channels, interpretation columns, a nearby borehole log, and an editable layer column.
  • ProfileViewer shows many CPTs side by side along a profile line (a cross-section).
  • BoreholeViewer shows one geotechnical borehole log with soil-composition bands.
  • Python 3.10 or newer.
  • A notebook environment: marimo, Jupyter, or another anywidget host.

The package is not on PyPI yet. Install it from git:

Terminal window
uv add "cpt-anywidget @ git+https://github.com/bedrock-engineer/cpt-anywidget"

The bro extra installs brodata:

Terminal window
uv add "cpt-anywidget[bro] @ git+https://github.com/bedrock-engineer/cpt-anywidget"

Only layers_from_bhrgt and layers_from_bore need the bro extra. The viewers do not need it.

Put this code in a notebook cell:

import polars as pl
from cpt_anywidget import CPTViewer
df = pl.DataFrame({
"depth": [0.0, 0.02, 0.04], # m below surface
"coneResistance": [0.1, 0.4, 0.9], # MPa
"localFriction": [0.01, 0.02, 0.02],
})
CPTViewer(df, vertical="depth", channels=["coneResistance", "localFriction"])

The notebook shows the widget when the cell returns it. The widget plots each channel against the shared vertical axis.

The data argument takes tidy columns: a polars or pandas DataFrame, or a dict of equal-length lists. Each row is one depth sample. Each column is one measurement.

The widget does not parse file formats. The widget does not convert units. Use a reader to do that upstream — any reader works. Examples: brodata for Dutch BRO data, pygef for GEF files, python-ags4 for AGS files, or plain polars.read_csv for a CSV.

Column names are free. The BRO column names get built-in labels, units, and colors: coneResistance, localFriction, frictionRatio, porePressureU1, porePressureU2, and inclination. For a column with a different name, pass a Channel binding:

from cpt_anywidget import Channel
CPTViewer(df, channels=[Channel("qn", label="qn", unit="MPa", color="tomato")])

Set vertical to the column that holds the vertical coordinate:

  • "depth" is depth below surface, in m, positive down.
  • "nap" is elevation in m NAP, positive up. Compute it as the surface elevation minus the depth.

For a different datum, pass a Vertical binding.

  • To zoom the vertical axis, hold the Ctrl key (Cmd on macOS) and turn the mouse wheel. A trackpad pinch also zooms.
  • To pan a zoomed axis, drag in the plot area.
  • To zoom to a range, hold the Shift key and drag along the axis.
  • To reset the zoom, double-click in the plot area.
  • To read the values at a depth, move the pointer across the plot.

The mouse wheel without a modifier key scrolls the notebook, not the chart.