3D bars
Holochart extension
bar3d is not a Plotly trace type: Plotly has no 3D bar chart. Figures that use it only render in Holochart. Its attributes follow Plotly's conventions (marker, colorscales, lighting, hoverinfo, …), so they read like any other trace.
Overview
A 3D bar chart (trace type bar3d) draws one box per value in a 3D scene: each bar stands at its x, y position and rises by its height z. Use it for a matrix of values with two categorical or numeric dimensions, such as sales by product and region, a bivariate histogram, or a value per month and year, and for stacks of such values across traces. Each trace draws all of its bars in one instanced draw call, lit like the other 3D meshes, and every bar can be hovered.
Pick a different chart when:
- values must be compared exactly: a 3D view distorts heights with perspective, and nearer bars hide farther ones. A heatmap of the same matrix, or grouped 2D bars, are easier to read;
- the grid is dense and smooth: a
surfaceshows the shape with less clutter; - the positions are scattered rather than on a grid: a 3D scatter with markers sized or colored by the value.
bar3d is part of the full @mk7s/holochart bundle, like the other 3D traces. 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';
createChart(document.getElementById('chart')!, {
data: [
{
type: 'bar3d',
x: ['a', 'b', 'c', 'a', 'b', 'c'],
y: ['p', 'p', 'p', 'q', 'q', 'q'],
z: [3, 5, 2, 6, 2, 5],
},
],
});Six bars on a 3 × 2 grid of categories, each from 0 up to its z. By default a bar covers 0.8 of its category cell along x and y, takes the colorway's first color, and has thin edges. The live example draws revenue of five products in four regions, one trace per region, so each row gets its own color and legend entry; hover a column for its product, region and value:
Loading source…
bar3d/matrixData format
x,y: the center of each bar: numbers, dates or categories, per scene axis (detected from the data or set withscene.xaxis.typeandscene.yaxis.type). A bar is drawn when itsx,yandzare all valid.z: the bar heights, in z data units. A bar spansbase→base + z: negative heights go down. Zero-height bars and bars with a missing height (null,NaN) draw nothing. All three arrays must be non-empty, else the trace is not drawn; with different lengths, the shortest wins.base: where the bars start on the z axis (default 0), one number or one per bar.width,depth: the bar's footprint along x and along y, in axis units (one category is 1, dates are in milliseconds), one number or one per bar. The default is 0.8 of the smallest distance between the trace's distinct positions on that axis (1 with a single position), so a regular grid leaves a fifth of each cell empty.stackgroup: a name.bar3dtraces of the same scene with the same non-emptystackgroupstack in trace order: at each (x,y) position, a bar starts where the previous trace's bar at that position ended, and the lowest bar of each stack starts at its ownbase. Heights add up as they are, so a negative height goes down from the top of the bar below it. Bars at the same position that are not in one group overlap.- Axis ranges include every bar's whole footprint on x and y, and every bar's bottom and top on z, so the base (0 by default) and the stack totals are in range.
- Log z axes. Bottoms and tops are placed on the log axis; a bottom at or below zero (the default
base: 0) starts at the bottom of the axis range. - Scene.
scene: 'scene2'puts the trace in another scene (default'scene').
Variations
A numeric grid
Bars on numeric axes sit at their x, y values: here a bivariate histogram of 2,000 samples, counted on a 12 × 12 grid of 0.5-wide bins. width and depth are set to 0.45 (in axis units) instead of the default 0.4 (0.8 of the 0.5 spacing); empty bins draw nothing.
Loading source…
bar3d/numeric-gridStacked bars
Three traces (fossil, nuclear and renewable generation) share stackgroup: 'mix', so at every country and year each source starts where the one before it ended. The z axis covers the stack totals, and hovering a block shows its own value and where it starts (base).
Loading source…
bar3d/stackedColored by height
With a marker.colorscale and no marker.color array, the bars are colored by z. Here monthly temperature anomalies over ten years through a diverging scale centered on zero (cmid: 0), with a colorbar; negative anomalies go down from 0.
Loading source…
bar3d/colorscaleMaterials and translucency
The same bars three times: Plotly's lighting model (the default); a three.js standard material (metalness, roughness) lit by the scene's light rig (scene2.lighting); and translucent bars (opacity: 0.55) without edges.
Loading source…
bar3d/materialsStyling
- Colors.
marker.coloris one CSS color, or one per bar: colors, or numbers mapped throughmarker.colorscale,cmin,cmax,cmidandreversescale, withshowscaleandcolorbarfor a colorbar, ormarker.coloraxisto share a scale between traces. When a colorscale is asked for (colorscale,cmin/cmax,showscale,colorbarorcoloraxis) without a color array, the bars are colored by their heightz. Without either, each trace takes the next colorway color. See colors and colorscales. - Opacity.
marker.opacity(times the traceopacity) below 1 draws the bars translucent: front faces only, without depth writes, sorted back to front by box center whenever the view changes. - Edges.
marker.line.colorandmarker.line.width(CSS px, default#444and 1) draw the box edges inside the faces, at the same px width at any depth: half the width on each of the two faces that meet at an edge, so edges never flicker against the faces.width: 0turns them off. - Lighting.
lighting.{ambient, diffuse, specular, roughness, fresnel}(defaults 0.55, 0.6, 0.08, 0.5 and 0.2: more contrast between the top, front and side faces thanmesh3d's defaults) andlightposition.{x, y, z}(default 1e5, 1e5, 0), as in Plotly's meshes. - Default look. The default
holocharttemplate draws 1 px edges in the background color and slims the colorbar.template: 'plotly-classic'(or'none') keeps the#444edges (themes and templates). - Legend. Each trace shows a bar glyph in its color (the middle of its colorscale when colored per bar); clicking an entry toggles the trace.
import { createChart } from '@mk7s/holochart';
createChart(document.getElementById('chart')!, {
data: [
{
type: 'bar3d',
x: [0, 1, 2, 0, 1, 2],
y: [0, 0, 0, 1, 1, 1],
z: [4, 7, 3, 5, 2, 6],
base: 1,
width: 0.6,
depth: 0.6,
marker: {
color: ['#4c78a8', '#4c78a8', '#4c78a8', '#f58518', '#f58518', '#f58518'],
opacity: 0.9,
line: { color: '#ffffff', width: 2 },
},
lighting: { ambient: 0.4, diffuse: 0.8 },
},
],
});Interactivity
Camera. Drag to turn the scene, scroll or pinch to zoom, double-click to go back to the first view; see the scene controls.
Hover. Bars are picked on the GPU, so the bar you hover is the one you see. The label sits at the center of the bar's top (its lower end, for negative heights) and shows, per
hoverinfo(default all ofx+y+z+base+text+name), the position (x: …,y: …, categories by name), the height (z: …: the bar's own value, not the top of its stack),base: …when the bar does not start at 0 (itsbase, or the top of the bar below it in a stack), then itstext. Values are formatted like the scene axes, or byxhoverformat,yhoverformatandzhoverformat; on a log z axis, heights and bases are shown as plain numbers.hovertemplatecan use%{base}and%{top}(the bar's ends on the z axis) besides%{x},%{y},%{z},%{text}and%{customdata}:tsimport { createChart } from '@mk7s/holochart'; createChart(document.getElementById('chart')!, { data: [ { type: 'bar3d', name: 'Q1', stackgroup: 'q', x: ['north', 'south'], y: ['2025', '2025'], z: [12, 9], }, { type: 'bar3d', name: 'Q2', stackgroup: 'q', x: ['north', 'south'], y: ['2025', '2025'], z: [15, 11], hovertemplate: '%{x}: %{z} (%{base} → %{top})<extra></extra>', }, ], });Events.
hoverandclickpoints carryx,y,z(the height),curveNumber,pointNumberandcustomdata, plusbaseandtop:tsimport { createChart } from '@mk7s/holochart'; const chart = createChart(document.getElementById('chart')!, { data: [{ type: 'bar3d', x: ['a', 'b'], y: ['p', 'p'], z: [3, 5] }], }); chart.on('click', (e) => { const p = e.points[0]; if (p) console.log(p.pointNumber, p.x, p.y, p.z); });Spikes and annotations work as for every 3D trace: see spikes and annotations.
3D-native options
- Materials.
material.typeswaps Plotly's lighting model:'plotly'(the default),'flat'(unlit colors), or a three.js material type ('standard','physical','phong','lambert','toon','matcap','basic') with its parameters (metalness,roughness,clearcoat, …). The three.js types are lit by the scene's light rig (scene.lighting) and receive its shadows withmaterial.receiveshadow; bars cast none (castshadowis ignored). See materials and lighting. - Camera tours and auto-rotation.
chart.animateCameraflies the camera to a new view, andscene.autorotateturns the scene like a turntable.
Performance notes
- Every bar of a trace is one instance of a single 24-vertex box (6 faces of 4 vertices with their own normals, 36 indices) in one instanced draw call, with 11 floats per bar (its min corner, its size, its color and its index for picking). No geometry is built on the CPU, and orbiting only moves the camera, so tens of thousands of bars stay interactive.
- Bar corners are stored relative to an origin in 32-bit floats (the origin in 64-bit), so date axes and large coordinates keep their precision.
- Edges cost nothing extra: they are drawn by the faces' fragment shader, not as lines.
- Translucent bars are re-sorted, and their instance data rewritten, whenever the view changes; keep
opacity: 1for the largest traces. - The shaders come from the lazily loaded mesh chunk that
mesh3duses too; the bars appear once it has loaded (chart.readywaits for it).
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: nearer bars hide farther ones, and perspective distorts heights. Set an initial
scene.camerathat shows every row, keep the values in hover labels, and prefer a lightness-monotonic colorscale when coloring by height. For exact comparisons, offer a heatmap of the same matrix as well.
Attribute reference
See the bar3d attribute reference for every attribute, its type, and its default. Scene attributes (camera, axes, lights) are under scene, and shared color axes under coloraxis, in the layout reference.
Related charts
- Bar chart: bars on a flat plot, grouped or stacked with
barmode - Heatmap: the same matrix as colored cells, easier to compare
- 3D mesh: arbitrary triangle meshes in the same scenes and lighting
- 3D scenes: cameras, axes and controls of every 3D trace
Plotly migration notes
bar3dis a Holochart extension: Plotly has no 3D bar trace, and a Plotly figure withtype: 'bar3d'does not render in Plotly. In Plotly, 3D bars are usually built asmesh3dboxes (8 vertices and 12 triangles per bar); such figures still work in Holochart, and abar3dtrace replaces them withx,y,zand one draw call.- Names follow Plotly's conventions:
x,y,base,width,marker.colorand the colorscale attributes,marker.opacity,marker.lineandstackgroupas in 2D bars and scatter;lighting,lightpositionand the hover attributes as inmesh3d.depthis the footprint along y, andzholds the heights (2D bars keep them iny). - Stacking is per trace. Scenes have no
barmode, sostackgroup(like scatter's) chooses which traces stack: it is the equivalent of Plotly'sbarmode: 'stack'for the traces that share a group, and several groups can stack independently in one scene. There is no grouped mode: bars at the same position overlap unless you offset theirxoryand narrow theirwidthordepth. There is nobarnormor'relative'stacking. - Not supported: text drawn on the bars (
texttemplate,textposition),offset, per-barmarker.linestyles, and patterns. Thecastshadowflag ofmaterialis ignored.