Advanced 3-D compositions#

The final step: fine control over how the volume is rendered and viewed. Every 3-D mode accepts the full VolumeMapOptions vocabulary — colour map and range, cell-filtering iso-window, slice and surface density, opacity, station overlays, colour clipping, vertical exaggeration, and camera azimuth. This example composes them into presentation-quality scenes.

Depth is capped to 2 km for visibility

The interpolated pseudo-depth volume reaches roughly 30 km, so the shallow structure that actually matters renders as a vanishingly thin sliver at the top of a tall, empty box. Every scene on this page caps the view to the top 2 km with depth_range=(0, 2000) (set once as DEPTH_CAP below). Change that single value — e.g. (0, 1000) for a 1 km near-surface view, or (0, 5000) to see deeper — to reframe every figure. Pairing a tight depth_range with aspectmode="cube" is the single most effective way to get a legible 3-D resistivity scene.

The scenes are live; use them to find the viewpoint that best tells the story, then export with MapView.export().

Load the survey and set the depth cap#

DEPTH_CAP is threaded through every call below, so the whole page re-frames from one place.

import os

from pycsamt.map import MapView


DEPTH_CAP = (0.0, 2000.0)  # top 2 km — see the admonition above

DATA = os.path.join(
    os.environ.get("PYCSAMT_DOCS_REPO_ROOT", "."), "data", "AMT", "WILLY_DATA"
)
mv = MapView.from_folder(DATA, recursive=True)
print(f"{mv.n_stations} stations across {len(mv.lines)} lines")
print(f"depth cap: {DEPTH_CAP[1]:.0f} m")
53 stations across 2 lines
depth cap: 2000 m

1. A custom-styled block#

Override the colour map, fix the resistivity range for reproducibility, and raise the opacity to firm up the body. log_color=True spreads the scale over resistivity’s many decades. Capped to the top 2 km, the shallow structure fills the frame instead of hiding at the top of a 30 km box.

fig = mv.map3d(
    mode="block",
    depth_range=DEPTH_CAP,
    cmap="Turbo",
    rho_range=(1.0, 5000.0),
    log_color=True,
    opacity=0.55,
    show_stations=True,
    station_size=3,
)
fig.update_layout(height=660, scene_aspectmode="cube")
fig


2. Sharpen contrast with colour clipping#

rho_range chooses which cells render; value_range instead clips the colour scale (cmin/cmax in log10 ρ). Narrowing it saturates the extremes and throws the mid-range resistivity contrast into relief — useful when one very resistive or very conductive cell would otherwise flatten the whole colour bar.

fig = mv.map3d(
    mode="block",
    depth_range=DEPTH_CAP,
    cmap="RdYlBu_r",
    value_range=(1.5, 3.3),
    opacity=0.6,
    show_stations=True,
    station_size=3,
)
fig.update_layout(height=660, scene_aspectmode="cube")
fig


3. A dense depth stack#

More slices give a finer sense of the vertical resistivity gradient — ten constant-depth maps through the top 2 km, each lightly transparent so deeper slices show through.

fig = mv.map3d(
    mode="depth",
    depth_range=DEPTH_CAP,
    n_slices=10,
    opacity=0.8,
    cmap="RdYlBu_r",
)
fig.update_layout(height=660, scene_aspectmode="cube")
fig


4. Focused iso-surfaces#

Narrowing rho_range and raising surface_count isolates a specific resistivity band — here the transition into the conductive zone — and renders it as several nested shells with crisp boundaries.

fig = mv.map3d(
    mode="surface",
    depth_range=DEPTH_CAP,
    surface_count=14,
    rho_range=(1.0, 800.0),
    opacity=0.45,
    show_stations=True,
    station_size=3,
)
fig.update_layout(height=660, scene_aspectmode="cube")
fig


5. A phase volume#

Every mode also renders quantity="phase". Because phase responds to resistivity gradients rather than absolute values, a phase block often outlines boundaries — the top of a conductor, a fault contact — more sharply than the resistivity block does.

fig = mv.map3d(
    mode="block",
    depth_range=DEPTH_CAP,
    quantity="phase",
    cmap="Viridis",
    opacity=0.6,
    show_stations=True,
    station_size=3,
)
fig.update_layout(height=660, scene_aspectmode="cube")
fig


6. Camera and exaggeration#

azimuth rotates the scene and aspectmode="cube" exaggerates the (shallow) depth axis so thin structure stays legible. With station labels this is the fence figure to export for a report.

fig = mv.map3d(
    mode="fence",
    depth_range=DEPTH_CAP,
    azimuth=45.0,
    aspectmode="cube",
    show_stations=True,
    station_labels=True,
)
fig.update_layout(height=680)
fig


7. A presentation composite#

Everything together: the top 2 km, draped on topography, with a firm colour block, station markers, and a chosen camera — the kind of scene you would drop straight into a report or slide.

fig = mv.map3d(
    mode="block",
    depth_range=DEPTH_CAP,
    cmap="Turbo",
    log_color=True,
    opacity=0.65,
    topography=True,
    show_terrain=True,
    terrain_opacity=0.5,
    show_stations=True,
    station_size=3,
    azimuth=25.0,
)
fig.update_layout(height=700, scene_aspectmode="cube")
fig


Exporting#

Any of these figures round-trips to a standalone interactive HTML file (or a static image) with one call — the same object you see above:

mv.export("survey_volume.html", view="map3d", mode="block",
          depth_range=(0, 2000))

That completes the tour — from a flat station map through profiles, fences, volumes, topography, near-surface and body-isolation views, to fully styled 3-D compositions. See the Map tools guide for the complete API and the Dash workbench (pycsamt.map.launch_mapview()) for a live, no-code version.

Total running time of the script: (0 minutes 0.637 seconds)

Gallery generated by Sphinx-Gallery