Isosurface
Overview
An isosurface trace draws the surfaces where a scalar field defined on a 3D grid takes a given value (level surfaces), in a 3D scene. Use it for densities, concentrations, potentials, medical and simulation volumes, and implicit shapes: anything measured or computed at every point of a 3D grid, where the shape of a level matters.
Between isomin and isomax, Holochart draws surface.count isosurfaces, closes them where the grid cuts them (caps), and can add planar slices and a spaceframe of the grid cells. It extracts the triangles exactly as plotly.js does (each grid cell cut into five tetrahedra, then marching tetrahedra), so Plotly figures look the same; hovering shows the nearest grid point's x, y, z and value.
Pick a different chart when:
- you want to see the whole field at once, including its soft gradients: draw a volume (stacked translucent isosurfaces, or GPU ray marching);
- the field is 2D: a contour plot or surface;
- you already have triangles: a mesh3d.
isosurface is part of the full @mk7s/holochart bundle. With a script tag, load the 3D add-on holochart-3d.iife.min.js after holochart.iife.min.js.
Minimal example
import { createChart } from '@mk7s/holochart';
// value = x² + y² + z² on a 4 × 4 × 4 grid, flattened (x changes fastest).
const x: number[] = [];
const y: number[] = [];
const z: number[] = [];
const value: number[] = [];
for (let k = 0; k < 4; k++) {
for (let j = 0; j < 4; j++) {
for (let i = 0; i < 4; i++) {
x.push(i);
y.push(j);
z.push(k);
value.push(i * i + j * j + k * k);
}
}
}
createChart(document.getElementById('chart')!, {
data: [{ type: 'isosurface', x, y, z, value, isomin: 4, isomax: 12 }],
});The two isosurfaces (at isomin and isomax) are colored by value through the colorscale, with a colorbar. The live example is Plotly's documentation example: nested ellipsoids of x²/2 + y² + 2z² on a 30³ grid, the x and y caps hidden so the cut surfaces stay open:
isosurface/basicData format
x,y,z,value: one entry per grid point, flattened columns of a rectilinear grid (NumPy'smgrid(...).flatten(), or nested loops as above). The axes can be nested in any order (x, y or z changing fastest) and run in either direction; the grid spacing can be uneven. Typed arrays (Float32Array,Float64Array) are used as they are, which keeps large grids cheap.- Grid check: as in Plotly, the columns must describe a complete grid, every coordinate increasing along its own axis; otherwise nothing is drawn (Plotly warns about "arbitrary coordinates").
isomin,isomax: the value range drawn (default: the data's extent).isominaboveisomaxdrops both.- Dates and categories work on the axes like any 3D trace; values are numbers.
- Scene.
scene: 'scene2'puts the trace in another scene (default'scene').
Variations
Surface count, fill and pattern
surface.count spreads that many isosurfaces over [isomin, isomax]; surface.fill below 1 draws every triangle as a frame around a hole, so inner surfaces show through; surface.pattern keeps a subset of each grid cell's five tetrahedra ('A'–'E' and their combinations) or a checkerboard of cells ('odd', 'even').
isosurface/surface-optionsCaps
Caps close the solid where the grid's boundary cuts it: on each face of the grid, the part whose values are in range. They are on by default (caps.x.show, .y, .z).
isosurface/capsSlices
slices.z.show draws planes of constant z through the grid, colored by value where it is in range: at locations (between grid planes, interpolated), or at every inner grid plane without them.
isosurface/slicesSpace frame
spaceframe.show draws the central tetrahedron of every grid cell inside the range as thin frames (spaceframe.fill, 0.15 by default): the lattice the field was sampled on.
isosurface/spaceframeStyling
- Colors.
colorscale,reversescale,cauto,cmin,cmax,cmid,showscaleandcolorbar, orcoloraxisto share a scale with other traces. The automatic color domain is[isomin, isomax]. The default look uses its sequential scale (autocolorscale), like Plotly. - Opacity.
opacityfor the whole trace (translucent triangles are sorted back to front when the camera moves). - Lighting. Plotly's model:
lighting.ambient(0.8),diffuse(0.8),specular(0.05),roughness(0.5),fresnel(0.2),facenormalsepsilon(0 for isosurfaces) andlightposition({ x: 1e5, y: 1e5, z: 0 }).flatshadingis on by default, as in Plotly. - Fill.
surface.fill,caps.*.fill,slices.*.fillandspaceframe.fillset the drawn share of every triangle.
import { createChart } from '@mk7s/holochart';
declare const grid: { x: number[]; y: number[]; z: number[]; value: number[] };
createChart(document.getElementById('chart')!, {
data: [
{
type: 'isosurface',
...grid,
colorscale: 'Viridis',
opacity: 0.6,
lighting: { ambient: 0.5, diffuse: 0.9, specular: 0.3 },
caps: { z: { show: false } },
},
],
});Interactivity
- Hover finds the surface under the pointer (GPU picking), snaps to the nearest grid point and shows its
x,yandz, thenvalue: …(always, as in Plotly;valuehoverformat), then itstext(hoverinfo,xhoverformat/yhoverformat/zhoverformat,hovertext).hovertemplatehas%{value}. Spikes run from the point to the walls. - Events:
hover,unhoverandclickreport the grid point'sx,y,zandvalue, withpointNumberits index in the columns. - Camera: drag to turn, scroll to zoom, as in every 3D scene.
import { createChart } from '@mk7s/holochart';
declare const grid: { x: number[]; y: number[]; z: number[]; value: number[] };
const chart = createChart(document.getElementById('chart')!, {
data: [
{
type: 'isosurface',
...grid,
hovertemplate: 'density %{value:.3f} at (%{x}, %{y}, %{z})<extra></extra>',
},
],
});
chart.on('click', (event) => console.log(event.points[0]?.pointNumber));3D-native options
- Materials (
material.type):'flat'draws the colors unlit; three.js materials ('standard','physical','phong', …) light the surfaces with the scene's lights (scene.lighting), shadows and reflections. - For a soft, whole-field view of the same data, draw it as a volume, with GPU ray marching (
render: 'raymarch').
Performance notes
- The triangles are extracted on the CPU, once per data or option change. Every grid cell is visited once per surface: on an Apple M1 Max, a 64³ grid with two surfaces and caps (350,000 triangles) takes about 0.15 s, and the time grows with the grid size and
surface.count. - Like Plotly, the extracted triangles share no vertices (three per triangle), so large surfaces take memory: about 100 bytes per triangle on the CPU. Keep
surface.countand the grid size in proportion; for dense fields, consider a ray-marched volume. - Structured grids (the usual flattened
mgridor loops) are read along their strides, without sorting; typed-array columns are not copied. - The surfaces draw in one call with the mesh primitive, whose code loads the first time a scene draws a mesh. Translucent surfaces re-sort their triangles when the camera moves (up to 500,000 triangles).
- The extraction is a pure function of typed arrays, ready to move to a worker (not done yet).
Accessibility notes
- Screen readers: the chart is a
<canvas>; the hidden description (see the accessibility guide) names the trace. - Keyboard: Shift + arrow keys orbit the camera,
+/-move it in and out and0resets it. There is no keyboard navigation between the trace's own points yet. See the keys by chart family. - Color and depth: inner surfaces can hide behind outer ones. Use
surface.fill,opacityor aslicesplane to open them up, keep the colorbar, prefer lightness-monotonic colorscales and set a useful initialscene.camera.
Attribute reference
See the isosurface attribute reference for every attribute, its type, and its default. Scene attributes (camera, axes, lighting) are under scene in the layout reference.
Related charts
- Volume: the same data drawn as many translucent isosurfaces, or ray-marched
- 3D scenes: the camera, axes, controls, hover and spikes every 3D trace shares
- Surface: a height field over a 2D grid
- Mesh3D: arbitrary triangle meshes
Plotly migration notes
- Attribute names and defaults match Plotly's
isosurface:x,y,z,value,isomin,isomax,surface.{show, count, fill, pattern},caps.{x, y, z}.{show, fill},slices.{x, y, z}.{show, locations, fill},spaceframe.{show, fill}, the colorscale attributes,opacity,flatshading,lighting,lightposition,text,hovertext, the hover formats,hoverinfo,hovertemplateandscene. Isosurfaces are hidden from the legend unlessshowlegend: true. - The triangles are Plotly's: the same five-tetrahedra cells, levels, caps, slices, fills and patterns, including its quirks (slices between grid planes are drawn once per internal pass). Differences: spaceframe corners and slices on descending axes are placed correctly for every grid order (Plotly assumes one), and interpolated points stay on their cell edge for value steps near 1e-9.
- Hover snaps to the nearest grid point; Plotly takes, per axis, the grid value at or above the picked vertex.
materialis a Holochart extension.- Not supported yet:
contour(Plotly's hover iso-line),xcalendar/ycalendar/zcalendar,hovertemplatefallback.