cpt-anywidget
anywidget viewers for cone penetration test (CPT) and geotechnical borehole data, rendered with D3.js. Built for notebook use (marimo, Jupyter). Every viewer shares a zoomable vertical axis in depth below surface or elevation, so soundings, borehole logs, and interpretations line up.
Full documentation on bedrock.engineer/docs/cpt-anywidget
Viewers
CPTViewer— one CPT: measurement channels (qc, fs, Rf, u1/u2, inclination, …) against the vertical axis, plus optional layer columns: a nearby borehole log, read-only interpretation columns (e.g. Robertson, Lengkeek), and an editable layer column synced back to Python.BoreholeViewer— a single borehole log with proportional soil-composition bands and hatch patterns; itslayerstrait takes plain dicts from any source, andlayers_from_bhrgt(brodata BHR-GT) andlayers_from_bore(pygef GEF/BRO XML) convert boreholes already in the Dutch BRO soil vocabulary.ProfileViewer— multiple CPTs side by side along a chainage axis (a cross-section);chainagecomputes along-profile distances from map coordinates.
Install
From PyPI, with uv (recommended):
uv add cpt-anywidget
or with pip: pip install cpt-anywidget.
Usage
import polars as pl
from cpt_anywidget import CPTViewer, Channel
df = pl.DataFrame({
"depth": [0.0, 0.02, 0.04], # or "nap" for elevation
"coneResistance": [0.1, 0.4, 0.9], # MPa
"localFriction": [0.01, 0.02, 0.02],
})
CPTViewer(df, vertical="depth", channels=["coneResistance", "localFriction"])
data is tidy columns — a polars or pandas DataFrame or a dict of
columns (lists, tuples, numpy arrays) — one row per depth sample. The widget never parses file
formats or converts units: loaders (e.g. brodata)
normalize upstream. The Dutch BRO column names get built-in display
defaults; any
other column can be bound with
Channel(key, label=…, unit=…, color=…, side=…).
Custom vertical datums work the same way via
Vertical(key, label=…, up=…).
Annotations, overlays, and axis limits are plain traits and track the zoom. See Interactions for the pointer and keyboard gestures.
Interactions
Zoom and pan — all viewers
- To zoom the vertical axis, hold the Ctrl key (Cmd on macOS) and turn the mouse wheel. Pinching on a trackpad or touch device zooms too, without keys.
- 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.
- Move the pointer across the plot to read the values at that depth.
- The mouse wheel without a modifier key scrolls the notebook, not the chart.
Edit layers — the CPTViewer edit column
- To move a boundary, drag it. A boundary stops at the minimum layer thickness.
- To split a layer, click in the lane beside the column. A dashed line previews where the new boundary goes.
- To merge two layers, move the pointer near their boundary in the lane and click the × it offers. The upper layer keeps its class.
- To set the class of a layer, click the layer. A pie menu opens. Click a wedge, or walk the wedges with the arrow keys and push Enter.
- As a fast path, press the layer, drag toward a wedge, and release.
- To close the pie menu, push the Escape key or click outside the menu.
- Each edit goes back to Python through the
editedLayerstrait.
Select a strip — ProfileViewer
- To select a CPT strip, click it. The name shows in the
selectedtrait in Python. - To deselect the strip, click it again.
Development
Front end (TypeScript, js/) builds into src/cpt_anywidget/static/:
npm install
npm run build # or: npm run dev (watch mode)
Set ANYWIDGET_HMR=1 so JS edits hot-reload in the browser. Sample files
(BRO XML, GEF, AGS) live in examples/.
License
Metadata
Release files for cpt-anywidget 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cpt_anywidget-0.3.0.tar.gz | 2.0 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cpt_anywidget-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.1 MB
Release files / cpt_anywidget-0.3.0.tar.gz
| Download URL | cpt_anywidget-0.3.0.tar.gz |
|---|---|
| Size | 2.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e44c462470949a4cb44d9f0171dd31ae32e092146ecda10a2ba7b70da52d13ba
|
|
BLAKE2b-256 checksum How to use checksums |
57ba29ad663c5f79a6dd650793fa8f3c7cb488c44fe81eb52d36c2679bdbd989
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / cpt_anywidget-0.3.0-py3-none-any.whl
| Download URL | cpt_anywidget-0.3.0-py3-none-any.whl |
|---|---|
| Size | 190.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
04d65d5b0bcefe0ed4a8ae175150a87546a3c7fefff98fbabec5791c3f6420af
|
|
BLAKE2b-256 checksum How to use checksums |
7b9dcbc361d61f4086728545fea5aafae2a1d7475b3d1c4ebf86205eeb633143
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log