What is Observable Plot?
Observable Plot is a free, open-source JavaScript library for exploratory data visualization. Created by Mike Bostock—the same developer who created D3.js—Observable Plot is designed to make it fast and easy to create common chart types while maintaining the flexibility to build custom visualizations when needed.
Unlike D3, which requires you to build everything from primitives, Observable Plot provides a concise, declarative API built on a grammar of graphics. You describe what you want to see, and Plot handles the how.
Why Use Observable Plot?
Observable Plot vs D3.js
D3 is incredibly powerful but verbose. A simple bar chart might require 50+ lines of code. Observable Plot achieves the same result in 5-10 lines. Plot is built on top of D3, so you get D3’s rendering quality without the boilerplate.
Choose D3 when: You need pixel-perfect custom visualizations, complex animations, or highly interactive dashboards.
Choose Plot when: You’re doing exploratory analysis, need quick iterations, or want readable, maintainable code.
Observable Plot vs Vega-Lite
Both Plot and Vega-Lite use declarative grammars, but they differ in philosophy:
- Vega-Lite uses JSON specifications—great for tooling but awkward in JavaScript
- Observable Plot uses native JavaScript—easier to integrate with data transformations and application logic
Plot also renders to SVG by default, making it easy to style with CSS and export for print.
Getting Started with Observable Plot
Installation
Install via npm:
npm install @observablehq/plot
Or use from a CDN:
<script type="module">
import * as Plot from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";
</script>
Your First Plot
Here’s a minimal example creating a scatter plot:
import * as Plot from "@observablehq/plot";
const data = [
{x: 1, y: 2},
{x: 2, y: 4},
{x: 3, y: 3},
{x: 4, y: 7}
];
const chart = Plot.dot(data, {x: "x", y: "y"}).plot();
document.body.appendChild(chart);
That’s it—four lines of code (excluding data) to render a scatter plot with axes, grid lines, and proper scaling.
Examples with Code
Bar Chart
Plot.barY(sales, {
x: "month",
y: "revenue",
fill: "category"
}).plot({
marginLeft: 60,
color: {legend: true}
})
Line Chart with Multiple Series
Plot.plot({
marks: [
Plot.lineY(stocks, {
x: "date",
y: "price",
stroke: "symbol"
}),
Plot.ruleY([0])
],
y: {grid: true},
color: {legend: true}
})
Faceted Small Multiples
Plot.plot({
marks: [
Plot.dot(penguins, {
x: "bill_length",
y: "bill_depth",
fill: "species",
fx: "island" // facet by island
})
],
facet: {marginRight: 80}
})
Heatmap
Plot.cell(data, {
x: "hour",
y: "day",
fill: "value"
}).plot({
color: {scheme: "YlOrRd"}
})
Animation Capabilities
Observable Plot focuses on static, publication-quality graphics rather than animation. However, you can achieve animated effects through several approaches:
Transition with Re-rendering
Plot charts are SVG elements. You can animate between states by re-rendering and using CSS transitions or FLIP animations:
// Re-render with new data
const newChart = Plot.barY(newData, {x: "category", y: "value"}).plot();
// Replace old chart
container.replaceChild(newChart, oldChart);
Integration with D3 Transitions
Since Plot outputs SVG, you can select elements with D3 and apply transitions:
import * as d3 from "d3";
d3.select(chart)
.selectAll("rect")
.transition()
.duration(750)
.attr("height", d => newScale(d.value));
Observable Framework Reactivity
In Observable notebooks or the Observable Framework, charts automatically re-render when input data changes, creating smooth reactive updates.
Pros and Cons
Pros
- Concise API: 10x less code than D3 for common charts
- Grammar of Graphics: Composable marks and scales follow a consistent logic
- Smart Defaults: Axes, legends, and grids are automatic but customizable
- TypeScript Support: Full type definitions included
- Free and Open Source: ISC license, no vendor lock-in
- Active Development: Regular updates from Observable team
- SVG Output: Easy to style, export, and embed
Cons
- Limited Animation: Not designed for animated or interactive dashboards
- Learning Curve: Grammar of graphics concepts take time to internalize
- Large Datasets: SVG rendering can slow down with 10,000+ points (use Canvas marks for better performance)
- Less Ecosystem: Fewer tutorials and Stack Overflow answers than D3 or Chart.js
- Breaking Changes: API still evolving (though stabilizing)
Conclusion
Observable Plot fills a crucial gap in the JavaScript visualization ecosystem. It’s more powerful than Chart.js, more concise than D3, and more JavaScript-native than Vega-Lite. For data analysts, journalists, and developers who need to quickly explore and communicate data, Plot is an excellent choice.
The library excels at exploratory data visualization—the kind of quick, iterative charting you do when trying to understand a dataset. It’s less suited for highly animated dashboards or games, where D3 or Canvas-based libraries remain the better choice.
If you’re already comfortable with D3, Plot will feel familiar but liberating. If you’re new to data visualization, Plot’s declarative approach teaches good habits while remaining approachable.
Get started: Visit the Observable Plot documentation for interactive examples and the full API reference.