dstory docs / chart reference · see it morph live →
Every Vizzu chart type as a copy-paste JSON snippet that drops into a kind: "vizzu" scene's frames[] array. Vizzu has no fixed "chart types" — these are all combinations of 4 geometries × 2 coordinate systems × 7 channels. Memorizing the four moves below unlocks the full range; the rest is recombination.
rectangle — bars, columns, treemaps, marimekkos, heatmaps, pies (with polar)circle — scatter, bubble, dot plotsline — line charts, slope charts, radar (with polar)area — area, stacked area, streamgraphcartesian (default) — flat x/y planepolar — wraps the x-axis into a circle. Bars become wedges, lines become radial.x, y — position axescolor — hue (usually a dimension)size — area / radius (usually a measure)lightness — shade variation within a huelabel — inline text on each elementnoop — included in groupby without encoding"x": "Year" (one field, default)"x": {"set": "Year", "aggregator": "sum"} (with options like aggregator, range, align, split)"y": ["Region", "Pop"] (multi-level grouping or stacking)color alone does NOT stack marks — without the
dimension in the axis channel, all marks start at zero and overdraw each
other (a "pie" becomes overlapping arcs; a "stacked" area shows only the
tallest series). Composition charts need [dimension, measure] on the
stacking axis: "y": ["Region", "Sales"].align and split live on the axis channel, not the config root.
A root-level "align" is rejected with align/...: invalid config
parameter — and in a dstory scene that kills the whole frame sequence.
Write "y": {"set": [...], "align": "center"}.{"channels": {"x": "Year", "y": "Sales"}, "geometry": "rectangle"}
(column chart — vertical bars)
{"channels": {"x": "Sales", "y": "Region"}, "geometry": "rectangle"}
(bar chart — horizontal bars)
{"channels": {"x": "Year", "y": ["Region", "Sales"], "color": "Region"}, "geometry": "rectangle"}
(the dimension must be IN the y set to stack — color alone only tints the overdrawn bars)
{"channels": {"x": ["Year", "Region"], "y": "Sales", "color": "Region"}, "geometry": "rectangle"}
(use array for x to break Region out from the stack into adjacent groups)
{"channels": {"x": "Year", "y": {"set": ["Region", "Sales"], "range": {"max": "100%"}}, "color": "Region"},
"geometry": "rectangle"}
{"channels": {"x": "Day", "y": "Hour", "color": "Visits"}, "geometry": "rectangle"}
(both axes are dimensions; color encodes the measure)
{"channels": {"size": "Pop", "color": "Region", "label": "Region"}, "geometry": "rectangle"}
(no x/y — pure area-packing layout, color groups, label shows region name)
{"channels": {"size": "Pop", "color": ["Region", "Country"], "label": "Country"},
"geometry": "rectangle"}
{"channels": {"x": {"set": "Region", "range": {"max": "100%"}},
"y": {"set": "Sales", "range": {"max": "100%"}},
"color": "Product"},
"geometry": "rectangle"}
(width-weighted columns where each column's height is also a stretched stack)
{"channels": {"x": "Step", "y": ["Step", "Delta"], "color": "Step"},
"geometry": "rectangle"}
(use signed Delta values; stacking y by the step dimension produces the
classic floating-bar lift)
{"channels": {"x": "Region", "y": "Sales", "color": "Region"},
"geometry": "rectangle",
"style": {"plot": {"marker": {"rectangleSpacing": "90%"}}}}
(narrow bars — by squeezing rectangle width to ~10%)
coordSystem: "polar"){"channels": {"x": ["Region", "Sales"], "color": "Region"}, "geometry": "rectangle", "coordSystem": "polar"}
(wedges stack along x and curl into a circle — "x": "Sales" alone overdraws
five arcs all starting at angle zero)
{"channels": {"x": ["Region", "Sales"], "color": "Region"},
"geometry": "rectangle", "coordSystem": "polar",
"style": {"plot": {"marker": {"angularPadding": "1deg"},
"yAxis": {"label": {"position": "axis"}}}}}
(pie with a hole — control via the inner radius style. See Vizzu donut docs.)
{"channels": {"x": "Region", "y": "Sales", "color": "Region"},
"geometry": "rectangle", "coordSystem": "polar"}
(when both x and y are set with polar, you get radial bars where each wedge has a different radius)
{"channels": {"x": "Region", "y": "Sales", "color": "Region"},
"geometry": "rectangle", "coordSystem": "polar"}
{"channels": {"x": "Year", "y": ["Region", "Sales"], "color": "Region"},
"geometry": "rectangle", "coordSystem": "polar"}
{"channels": {"x": "GDP", "y": "Lifespan"}, "geometry": "circle"}
{"channels": {"x": "GDP", "y": "Lifespan", "size": "Population", "color": "Continent"},
"geometry": "circle"}
{"channels": {"size": "Pop", "color": "Region", "label": "City"}, "geometry": "circle"}
{"channels": {"size": "Pop", "color": ["Region", "Country"]}, "geometry": "circle"}
{"channels": {"x": "Region", "y": "Sales"}, "geometry": "circle"}
(one axis as dimension, dots positioned by the measure)
{"channels": {"x": "Variable", "y": "Value", "color": "Series"},
"geometry": "circle", "coordSystem": "polar"}
{"channels": {"x": "Year", "y": "Sales", "color": "Region"}, "geometry": "line"}
{"channels": {"x": "Year", "y": "Sales"}, "geometry": "line"}
{"channels": {"x": "Skill", "y": "Score", "color": "Player"},
"geometry": "line", "coordSystem": "polar"}
(line + polar with categorical x = the classic radar)
{"channels": {"x": "Year", "y": "Rank", "color": "City"},
"geometry": "line"}
(use a dataset with only 2 years; reverse y-scale for rank-1-on-top)
{"channels": {"x": "Year", "y": "Sales"}, "geometry": "area"}
{"channels": {"x": "Year", "y": ["Region", "Sales"], "color": "Region"}, "geometry": "area"}
(without the dimension in y, the areas overlap and only the tallest series is visible)
{"channels": {"x": "Year", "y": {"set": ["Region", "Sales"], "range": {"max": "100%"}}, "color": "Region"},
"geometry": "area"}
{"channels": {"x": "Year", "y": {"set": ["Region", "Sales"], "align": "center"}, "color": "Region"},
"geometry": "area"}
(both gotchas at once: the stack needs the dimension in the y set, and
align belongs on the channel, not the config root)
{"channels": {"x": "Month", "y": "Rainfall", "color": "Month"},
"geometry": "area", "coordSystem": "polar"}
{"channels": {"x": "Value", "y": {"set": "count()"}}, "geometry": "rectangle"}
(use Vizzu's count() aggregator OR pre-bin in your data prep)
{"channels": {"x": "Group", "y": {"set": ["Group", "Value"], "align": "center", "split": true}, "color": "Group"},
"geometry": "area"}
(channel-level split: true separates the groups; align: "center" mirrors
each distribution around the axis — the dimension must be in the y set for
either to apply)
| Want | Use |
|---|---|
| Sankey / alluvial | kind: "sankey" (d3-sankey) |
| Geographic map | kind: "map" (Leaflet) |
| Force-directed network | kind: "network" (d3-force) |
| 3D / WebGL | hand-write with Three.js in a kind: "simple" scene |
| Sunburst | best approximation: nested donut |
| Word cloud | hand-write with d3-cloud |
| Box plot | violin (above) is the closest preset |
Don't pick one chart per scene — pick a sequence that morphs between qualitatively different shapes. The reader stays oriented because the data is constant; only the lens changes.
Make every frame self-contained: list every channel the sequence touches
(with null for detached ones) and set geometry/coordSystem explicitly.
Configs merge differentially, AND the dstory runtime skips stale intermediate
frames during fast scrolling — a frame can never rely on its predecessor to
detach a channel for it. Examples that work:
Bar → polar bar → pie → bubble → treemap (same total per region, 5 different visual logics):
"frames": [
{"config": {"channels": {"x": "Region", "y": "Sales", "color": "Region", "size": null},
"geometry": "rectangle", "coordSystem": "cartesian"}},
{"config": {"channels": {"x": "Region", "y": "Sales", "color": "Region", "size": null},
"geometry": "rectangle", "coordSystem": "polar"}},
{"config": {"channels": {"x": ["Region", "Sales"], "y": null, "color": "Region", "size": null},
"geometry": "rectangle", "coordSystem": "polar"}},
{"config": {"channels": {"x": null, "y": null, "size": "Sales", "color": "Region"},
"geometry": "circle", "coordSystem": "cartesian"}},
{"config": {"channels": {"x": null, "y": null, "size": "Sales", "color": "Region", "label": "Region"},
"geometry": "rectangle", "coordSystem": "cartesian"}}
]
Stacked column → streamgraph → ribbon line (same time series, three temporal logics):
"frames": [
{"config": {"channels": {"x": "Year", "y": {"set": "Sales", "align": "none"}, "color": "Cat"},
"geometry": "rectangle"}},
{"config": {"channels": {"x": "Year", "y": {"set": "Sales", "align": "center"}, "color": "Cat"},
"geometry": "area"}},
{"config": {"channels": {"x": "Year", "y": {"set": "Sales", "align": "none"}, "color": "Cat"},
"geometry": "line"}}
]
(reset align explicitly in the line frame — configs merge differentially, so
the streamgraph's center would otherwise leak into every later frame)
Scatter → dot plot → bubble (same observations, three encoding emphases):
"frames": [
{"config": {"channels": {"x": "GDP", "y": "Lifespan", "color": "Continent", "noop": "Country", "size": null},
"geometry": "circle"}},
{"config": {"channels": {"x": "Continent", "y": "Lifespan", "color": "Continent", "noop": "Country", "size": null},
"geometry": "circle"}},
{"config": {"channels": {"x": null, "y": null, "noop": null, "size": "Pop", "color": "Continent"},
"geometry": "circle"}}
]
(noop keeps individual countries as separate dots in the first two frames
without encoding them anywhere)
vizzu scene for more.circle to rectangle while ALSO changing every channel breaks visual continuity. Hold at least one channel constant between frames.