Big number
AtomA featured statistic with its label, change and the context that gives it meaning.
Get started
InsightCharts is a React library of charts, figures, page layouts and infographic posters built on Apache ECharts 6. Every component can be written as JSX or as a JSON spec.
Every chart takes a title that states one fact with its number, an entity to highlight, and annotations that mark a date, a threshold or a single value. The defaults follow common practice in news graphics. Lines and bars are labelled directly where possible. Bars start at zero. The highlighted series is drawn in colour and the other series in grey.
Global electricity generation from solar and wind, TWh
import { LineChart } from "insightcharts";
const data = [
{ year: "2019", Solar: 705, Wind: 1420 },
{ year: "2020", Solar: 855, Wind: 1590 },
{ year: "2021", Solar: 1050, Wind: 1860 },
{ year: "2022", Solar: 1320, Wind: 2110 },
{ year: "2023", Solar: 1640, Wind: 2310 },
{ year: "2024", Solar: 2130, Wind: 2500 },
];
export function Example() {
return (
<LineChart
data={data}
x="year"
y={["Solar", "Wind"]}
highlight="Solar"
title="Solar generation rose from 705 TWh in 2019 to 2,130 TWh in 2024"
subtitle="Global electricity generation from solar and wind, TWh"
note="Illustrative figures"
annotations={[
{ type: "point", x: "2024", y: 2130, label: "+30% from 2023", position: "left" },
]}
height={300}
/>
);
}{
"type": "line-chart",
"data": [
{ "year": "2019", "Solar": 705, "Wind": 1420 },
{ "year": "2020", "Solar": 855, "Wind": 1590 },
{ "year": "2021", "Solar": 1050, "Wind": 1860 },
{ "year": "2022", "Solar": 1320, "Wind": 2110 },
{ "year": "2023", "Solar": 1640, "Wind": 2310 },
{ "year": "2024", "Solar": 2130, "Wind": 2500 }
],
"x": "year",
"y": ["Solar", "Wind"],
"highlight": "Solar",
"title": "Solar generation rose from 705 TWh in 2019 to 2,130 TWh in 2024",
"subtitle": "Global electricity generation from solar and wind, TWh",
"note": "Illustrative figures",
"annotations": [
{
"type": "point",
"x": "2024",
"y": 2130,
"label": "+30% from 2023",
"position": "left"
}
],
"height": 300
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Open the Code and JSON tabs above. They show the same chart as JSX and as a plain JSON spec. Every component in this library can be written both ways.
Components are grouped into three levels by size.
| Level | What it is | Examples |
|---|---|---|
| Atoms | One chart form or one figure primitive. | Bar chart, line chart, big number |
| Molecules | A combination of atoms that is used often. | A row of statistics, a chart with a callout beside it |
| Templates | A complete page built from molecules and atoms. | A one-page executive brief, a scroll-driven essay |
Every component page lists what the component is built from and where it is used. For example, a big number is an atom. A stat row is a molecule that repeats the big number. The executive brief is a template that starts with a stat row.
A featured statistic with its label, change and the context that gives it meaning.
Two to five key figures in one row separated by hairlines, collapsing to two columns and then one as the container narrows.
A one-page summary. It has a headline that states the main finding with its number, a deck, a row of three or four key figures, one hero chart with a takeaway callout, two smaller supporting exhibits, a short list of actions and a source note.
10 of the templates are infographics. An infographic draws one poster: a painted background, a large title and one large graphic or several graphics laid out together. Infographics are built on the poster frame from 19 poster primitives, in eight poster themes, with 69 built-in icons. See the infographics guide.
import { FlowPoster } from "insightcharts";
export function Example() {
return (
<FlowPoster
theme="magenta"
kicker="Fishing"
title="Six ports on the Verran Coast landed 412,000 tonnes of fish in 2025"
subtitle="Landings by port, the buyers of Port Alda's catch, and how much each buyer relies on Port Alda. Thousand tonnes (kt)."
format={"{value} kt"}
producers={{
data: [
{ port: "Port Alda", kt: 148 },
{ port: "Skerry", kt: 96 },
{ port: "Marrow Bay", kt: 71 },
{ port: "Tolven", kt: 52 },
{ port: "Hask", kt: 28 },
{ port: "Lund", kt: 17 },
],
name: "port",
value: "kt",
title: "Port Alda landed 148,000 of the 412,000 tonnes",
}}
flow={{
data: [
{ buyer: "Canneries", kt: 46 },
{ buyer: "Fresh markets", kt: 34 },
{ buyer: "Frozen export", kt: 29 },
{ buyer: "Fishmeal plants", kt: 21 },
{ buyer: "Restaurants", kt: 11 },
{ buyer: "Smokehouses", kt: 7 },
],
name: "buyer",
value: "kt",
trunk: "Port Alda",
title: "Canneries bought 46,000 tonnes of Port Alda's catch",
}}
scale={{
data: [
{ buyer: "Canneries", fromAlda: 56, kt: 82 },
{ buyer: "Fresh markets", fromAlda: 35, kt: 96 },
{ buyer: "Frozen export", fromAlda: 23, kt: 124 },
{ buyer: "Fishmeal plants", fromAlda: 34, kt: 61 },
{ buyer: "Restaurants", fromAlda: 29, kt: 38 },
{ buyer: "Smokehouses", fromAlda: 64, kt: 11 },
],
name: "buyer",
value: "fromAlda",
size: "kt",
sizeFormat: "{value} kt",
scaleLabel: "From Port Alda",
title: "Smokehouses bought 64% of their fish from Port Alda",
subtitle: "Share of each buyer's fish landed at Port Alda (position) and all the fish it bought (area)",
}}
sources="Verran Coast Fisheries Board landing returns"
note="The Verran Coast is an invented place. All figures are illustrative."
credit="InsightCharts"
/>
);
}{
"type": "flow-poster",
"theme": "magenta",
"kicker": "Fishing",
"title": "Six ports on the Verran Coast landed 412,000 tonnes of fish in 2025",
"subtitle": "Landings by port, the buyers of Port Alda's catch, and how much each buyer relies on Port Alda. Thousand tonnes (kt).",
"format": "{value} kt",
"producers": {
"data": [
{ "port": "Port Alda", "kt": 148 },
{ "port": "Skerry", "kt": 96 },
{ "port": "Marrow Bay", "kt": 71 },
{ "port": "Tolven", "kt": 52 },
{ "port": "Hask", "kt": 28 },
{ "port": "Lund", "kt": 17 }
],
"name": "port",
"value": "kt",
"title": "Port Alda landed 148,000 of the 412,000 tonnes"
},
"flow": {
"data": [
{ "buyer": "Canneries", "kt": 46 },
{ "buyer": "Fresh markets", "kt": 34 },
{ "buyer": "Frozen export", "kt": 29 },
{ "buyer": "Fishmeal plants", "kt": 21 },
{ "buyer": "Restaurants", "kt": 11 },
{ "buyer": "Smokehouses", "kt": 7 }
],
"name": "buyer",
"value": "kt",
"trunk": "Port Alda",
"title": "Canneries bought 46,000 tonnes of Port Alda's catch"
},
"scale": {
"data": [
{ "buyer": "Canneries", "fromAlda": 56, "kt": 82 },
{ "buyer": "Fresh markets", "fromAlda": 35, "kt": 96 },
{ "buyer": "Frozen export", "fromAlda": 23, "kt": 124 },
{ "buyer": "Fishmeal plants", "fromAlda": 34, "kt": 61 },
{ "buyer": "Restaurants", "fromAlda": 29, "kt": 38 },
{ "buyer": "Smokehouses", "fromAlda": 64, "kt": 11 }
],
"name": "buyer",
"value": "fromAlda",
"size": "kt",
"sizeFormat": "{value} kt",
"scaleLabel": "From Port Alda",
"title": "Smokehouses bought 64% of their fish from Port Alda",
"subtitle": "Share of each buyer's fish landed at Port Alda (position) and all the fish it bought (area)"
},
"sources": "Verran Coast Fisheries Board landing returns",
"note": "The Verran Coast is an invented place. All figures are illustrative.",
"credit": "InsightCharts"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Each chart is defined by one pure function that turns props and rows into an ECharts option. A shared factory supplies the features below, so they work the same way on every chart.
option prop for any ECharts setting that no prop covers: see custom ECharts options.InsightCharts pages are expected to be written mostly by AI agents and read by people. Each component carries machine-readable metadata: what it shows, when to use it, when to pick something else, its props and a working example. That metadata generates this site, llms.txt, a JSON Schema, a shadcn registry and an installable agent skill. See for AI agents.