Guides
How to choose a visualization library
Pick a visualization library by language, how much custom control you need, and whether commercial licensing is worth it — not by demo gallery polish.
This category is for developers and analysts embedding charts into code — a notebook, a web app, a paper — not for people who want to drag fields into a finished dashboard. That distinction matters because a visualization library's job is to be a dependency in something else you're building; the wrong choice shows up later as a rewrite, not as a bad first impression. The fourteen libraries here split first by language, and then by how much of the chart's structure you write yourself.
Python: static exploration vs. interactive output
If you're plotting inside a notebook or a script, the first fork is static versus interactive.
- Matplotlib is the foundation nearly everything else in Python visualization is built on. Its object-oriented Figure/Axes API gives fine-grained control over every element — ticks, spines, annotations — which is why it remains the default for publication-quality static figures, at the cost of more verbose code for simple charts.
- seaborn is built directly on Matplotlib and adds high-level statistical functions —
scatterplot,boxplot,heatmap— that take a DataFrame and column names and handle grouping, color mapping, and confidence intervals automatically. It returns Matplotlib Axes objects, so you can drop back to the lower-level API when seaborn's defaults aren't enough. It is not interactive and not built for dashboards. - plotnine reimplements R's ggplot2 grammar of graphics in Python: charts are composed by layering a base aesthetic mapping, geometries, statistical transforms, and scales with the
+operator. It renders through Matplotlib underneath, so it's the right choice specifically for teams that already think in ggplot2's model, not a general Matplotlib replacement. - Bokeh and Plotly both produce interactive, browser-rendered charts — pan, zoom, hover — without writing JavaScript. Bokeh additionally supports a server mode for small interactive apps driven by Python callbacks, putting it between a charting library and an app framework. Plotly's Python, R, and JavaScript packages all render through the same Plotly.js engine, so a chart built in any of the three looks and behaves identically, and it integrates closely with Pandas for quick exploratory plotting.
- Vega-Altair takes a declarative approach: you describe which data fields map to which visual encodings, and it compiles that to a Vega-Lite spec rather than drawing charts imperatively. This keeps code short and consistent as complexity grows, but its capabilities track the underlying Vega-Lite grammar rather than a separately maintained Python engine.
JavaScript: how much do you want to build yourself
- D3.js is the lowest-level option: it doesn't ship pre-built chart types at all, only primitives — scales, axes, shapes, transitions, force layouts — for binding data directly to DOM elements. That makes it the most flexible option for genuinely custom visual designs, and the steepest learning curve. Several other libraries here, including Vega-Lite, Nivo, and Plotly.js, are themselves built on D3.
- Vega-Lite is a JSON-based declarative grammar — a chart is a mapping of data fields to encodings, a few lines long, compiled to a full Vega spec for rendering. It's the engine behind Altair and is designed for concise authoring and reasoning about chart structure rather than pixel-level control.
- Apache ECharts and Chart.js both ship large catalogs of ready-made chart types configured through an options object rather than assembled from primitives. ECharts covers more chart types (including geographic maps and large-dataset WebGL rendering) and is a common choice when you need many chart types with less custom code than D3; Chart.js is deliberately narrower — bar, line, pie, doughnut, radar, scatter — and lighter-weight, a common default when you just need the standard set without adopting a heavier stack.
- Nivo and Recharts are both React-specific, built on D3 internally but exposed as ready-to-use components rather than a general API — Nivo offers SVG, Canvas, and HTML rendering variants per chart type with live-editable documentation; Recharts exposes charts as composable JSX components — a line-chart component wrapping axis, tooltip, and line child components — so building a chart feels like building any other React UI. Neither works outside React, unlike D3 or ECharts.
Free and open source, or commercially licensed
Most of this category is open source with no pricing page: Matplotlib, seaborn, plotnine, Bokeh, Plotly, Altair, D3.js, Vega-Lite, Apache ECharts, Chart.js, Nivo, and Recharts are all free under permissive or Apache-style licenses. Two are not. Highcharts and amCharts are free only for personal, educational, or non-commercial use — any commercial deployment requires a paid per-seat or per-developer license, sold annually or as a perpetual purchase, with add-on modules (financial charts, maps) priced separately. What you get for the license fee is commercial support and a mature, well-documented product maintained by a company whose business model depends on the library working, which matters more to some buyers than the license fee itself. If your project is internal tooling with no redistribution, the open-source options cost nothing; if you're embedding charts in a product you sell, check whether a commercial license and its support obligations are actually cheaper than the engineering time an open-source alternative would cost you.
Static output vs. built-in interactivity
Matplotlib, seaborn, and plotnine produce static images by default — exactly what you want for a paper or a printed report, and the wrong choice if users need to hover, zoom, or filter. Bokeh, Plotly, and every JavaScript library here render interactively in the browser out of the box. If you need interactivity from a Python-first static library, you're generally better served switching to Bokeh, Plotly, or Altair than bolting interactivity onto Matplotlib after the fact.
A shortlist by situation
- Publication-quality static figures in Python, full control over every element: Matplotlib.
- Fast statistical exploration of a DataFrame in a notebook: seaborn.
- You already know ggplot2 and don't want to change your mental model: plotnine.
- Interactive Python charts or a lightweight data app, no JavaScript: Plotly for charts, Bokeh if you also want server-backed widgets.
- Concise declarative charts from Python, layering and faceting included: Vega-Altair.
- Fully custom, bespoke web visualizations and you're prepared to invest in D3's learning curve: D3.js.
- A dashboard needing many chart types fast, with less code than D3: Apache ECharts.
- Standard chart types in a web app, minimal bundle size: Chart.js.
- A React codebase wanting drop-in, D3-quality components: Nivo or Recharts.
- Commercially supported charting for a finance or enterprise product, and you're comfortable paying for it: Highcharts or amCharts.
Questions to ask before you commit
- Does the library need to run server-side (static export), client-side (interactive browser rendering), or both?
- If commercial, is our use case "public site," "SaaS with logins," or "OEM/redistributed" — licensing tiers differ sharply between them?
- How large are our typical datasets, and does the library need WebGL or Canvas rendering to stay responsive at that size?
- Are we locked into a specific frontend framework (React), and does that rule out or favor certain libraries?
- Who maintains this library, and what happens to our charts if the project stalls — is there a large enough community or company behind it?
Common mistakes
- Reaching for D3 by default when a higher-level library like ECharts or Plotly would ship the same chart in a fraction of the code.
- Deploying a commercially licensed library like Highcharts or amCharts in a commercial product without buying a license, discovered later during a compliance review.
- Choosing a React-only library (Nivo, Recharts) for a project that later needs to support another framework.
- Picking a static Python library for a dashboard that actually needs hover, zoom, or filter interactivity, then rebuilding it in Plotly or Bokeh anyway.
See Matplotlib vs seaborn, Apache ECharts vs Highcharts, and D3.js vs Vega-Lite, or browse every tool in this category.