A landscape spread of up to eleven small illustrations of one subject, each a different graphic form, in three bands of unequal panels: a statement in large type, spokes round an icon and a network of circles; a smooth trend with its peak labelled, nested squares and a slope chart; a pill ranking, a treemap, a tile map and sized circles; and a closing row of icon statements.
Slope chart
Connects each entity's value at two (or a few) points with a straight line, labelled with name and value at both ends.
- Use when
- Before / after for 3 to about 15 entities when the change in level and in ordering both matter; pair with
highlightto emphasise one line. - Avoid when
- Five or more time points (use line chart); when only the ordering matters (use bump chart); when only the size of each gap matters (use dumbbell chart or arrow chart).
Preview
The UK's coal share of electricity fell from 39% to 1% between 2012 and 2023
Share of electricity generated from coal, 2012 and 2023
import { SlopeChart } from "insightcharts";
const data = [
{ country: "United Kingdom", y2012: 39, y2023: 1 },
{ country: "Germany", y2012: 44, y2023: 26 },
{ country: "United States", y2012: 37, y2023: 16 },
{ country: "Poland", y2012: 84, y2023: 61 },
{ country: "India", y2012: 71, y2023: 75 },
{ country: "Japan", y2012: 29, y2023: 32 },
];
export function Example() {
return (
<SlopeChart
data={data}
series="country"
y={["y2012", "y2023"]}
names={{ y2012: "2012", y2023: "2023" }}
highlight="United Kingdom"
format={"{value}%"}
title="The UK's coal share of electricity fell from 39% to 1% between 2012 and 2023"
subtitle="Share of electricity generated from coal, 2012 and 2023"
source="Ember (rounded)"
note="Figures are approximate, for illustration"
/>
);
}{
"type": "slope-chart",
"data": [
{ "country": "United Kingdom", "y2012": 39, "y2023": 1 },
{ "country": "Germany", "y2012": 44, "y2023": 26 },
{ "country": "United States", "y2012": 37, "y2023": 16 },
{ "country": "Poland", "y2012": 84, "y2023": 61 },
{ "country": "India", "y2012": 71, "y2023": 75 },
{ "country": "Japan", "y2012": 29, "y2023": 32 }
],
"series": "country",
"y": ["y2012", "y2023"],
"names": { "y2012": "2012", "y2023": "2023" },
"highlight": "United Kingdom",
"format": "{value}%",
"title": "The UK's coal share of electricity fell from 39% to 1% between 2012 and 2023",
"subtitle": "Share of electricity generated from coal, 2012 and 2023",
"source": "Ember (rounded)",
"note": "Figures are approximate, for illustration"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Used in
1 infographic uses slope chart.
Infographics
1Installation
$ pnpm dlx shadcn@latest add @insightcharts/slope-chartThe CLI copies the source into your project and needs the @insightcharts registry in components.json; see installation. With the package, import it by name:
import { SlopeChart } from "insightcharts";Examples
Coloured by direction
London's employment rate rose from 68.9% to 75.1% between 2014 and 2024
Employment rate, ages 16 to 64, 2014 and 2024
import { SlopeChart } from "insightcharts";
const data = [
{ region: "North East", before: 71.2, after: 68.4 },
{ region: "London", before: 68.9, after: 75.1 },
{ region: "South West", before: 76, after: 77.8 },
{ region: "Wales", before: 69.5, after: 72.6 },
{ region: "Scotland", before: 73.4, after: 73.1 },
{ region: "West Midlands", before: 70.1, after: 73.9 },
];
export function Example() {
return (
<SlopeChart
data={data}
series="region"
y={["before", "after"]}
names={{ before: "2014", after: "2024" }}
colorBy="direction"
format={"{value}%"}
title="London's employment rate rose from 68.9% to 75.1% between 2014 and 2024"
subtitle="Employment rate, ages 16 to 64, 2014 and 2024"
note="Illustrative figures."
/>
);
}{
"type": "slope-chart",
"data": [
{ "region": "North East", "before": 71.2, "after": 68.4 },
{ "region": "London", "before": 68.9, "after": 75.1 },
{ "region": "South West", "before": 76, "after": 77.8 },
{ "region": "Wales", "before": 69.5, "after": 72.6 },
{ "region": "Scotland", "before": 73.4, "after": 73.1 },
{ "region": "West Midlands", "before": 70.1, "after": 73.9 }
],
"series": "region",
"y": ["before", "after"],
"names": { "before": "2014", "after": "2024" },
"colorBy": "direction",
"format": "{value}%",
"title": "London's employment rate rose from 68.9% to 75.1% between 2014 and 2024",
"subtitle": "Employment rate, ages 16 to 64, 2014 and 2024",
"note": "Illustrative figures."
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Long format, three periods
Streaming's share of recorded music revenue rose from 9% to 67% between 2012 and 2023
Share of recorded music revenue by format, 2012, 2016 and 2023
import { SlopeChart } from "insightcharts";
const data = [
{ format: "Streaming", year: "2012", share: 9 },
{ format: "Streaming", year: "2016", share: 34 },
{ format: "Streaming", year: "2023", share: 67 },
{ format: "Physical", year: "2012", share: 52 },
{ format: "Physical", year: "2016", share: 31 },
{ format: "Physical", year: "2023", share: 11 },
{ format: "Downloads", year: "2012", share: 31 },
{ format: "Downloads", year: "2016", share: 24 },
{ format: "Downloads", year: "2023", share: 4 },
{ format: "Sync and other", year: "2012", share: 8 },
{ format: "Sync and other", year: "2016", share: 11 },
{ format: "Sync and other", year: "2023", share: 18 },
];
export function Example() {
return (
<SlopeChart
data={data}
series="format"
x="year"
y="share"
colorBy="series"
format={"{value}%"}
height={320}
title="Streaming's share of recorded music revenue rose from 9% to 67% between 2012 and 2023"
subtitle="Share of recorded music revenue by format, 2012, 2016 and 2023"
note="Illustrative figures."
/>
);
}{
"type": "slope-chart",
"data": [
{ "format": "Streaming", "year": "2012", "share": 9 },
{ "format": "Streaming", "year": "2016", "share": 34 },
{ "format": "Streaming", "year": "2023", "share": 67 },
{ "format": "Physical", "year": "2012", "share": 52 },
{ "format": "Physical", "year": "2016", "share": 31 },
{ "format": "Physical", "year": "2023", "share": 11 },
{ "format": "Downloads", "year": "2012", "share": 31 },
{ "format": "Downloads", "year": "2016", "share": 24 },
{ "format": "Downloads", "year": "2023", "share": 4 },
{ "format": "Sync and other", "year": "2012", "share": 8 },
{ "format": "Sync and other", "year": "2016", "share": 11 },
{ "format": "Sync and other", "year": "2023", "share": 18 }
],
"series": "format",
"x": "year",
"y": "share",
"colorBy": "series",
"format": "{value}%",
"height": 320,
"title": "Streaming's share of recorded music revenue rose from 9% to 67% between 2012 and 2023",
"subtitle": "Share of recorded music revenue by format, 2012, 2016 and 2023",
"note": "Illustrative figures."
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Stress: 20 entities with close values and long names
Life expectancy in Ethiopia rose from 39 to 65 years between 2000 and 2022
Life expectancy at birth, years, 2000 and 2022. Bangladesh rose from 49 to 73.
import { SlopeChart } from "insightcharts";
const data = [
{ country: "Democratic Republic of the Congo", y2000: 41, y2022: 62 },
{ country: "United Republic of Tanzania", y2000: 44, y2022: 58 },
{ country: "Central African Republic", y2000: 40, y2022: 43 },
{ country: "Papua New Guinea", y2000: 47, y2022: 49 },
{ country: "Bosnia and Herzegovina", y2000: 71, y2022: 70 },
{ country: "Saint Vincent and the Grenadines", y2000: 69, y2022: 71 },
{ country: "Trinidad and Tobago", y2000: 68, y2022: 66 },
{ country: "Lao People's Democratic Republic", y2000: 52, y2022: 66 },
{ country: "Bangladesh", y2000: 49, y2022: 73 },
{ country: "Ethiopia", y2000: 39, y2022: 65 },
{ country: "Rwanda", y2000: 46, y2022: 68 },
{ country: "Cambodia", y2000: 50, y2022: 69 },
{ country: "Nepal", y2000: 53, y2022: 70 },
{ country: "Mozambique", y2000: 42, y2022: 56 },
{ country: "Sierra Leone", y2000: 38, y2022: 55 },
{ country: "South Africa", y2000: 61, y2022: 62 },
{ country: "Russian Federation", y2000: 65, y2022: 72 },
{ country: "United States of America", y2000: 77, y2022: 78 },
{ country: "Brazil", y2000: 70, y2022: 75 },
{ country: "Viet Nam", y2000: 72, y2022: 74 },
];
export function Example() {
return (
<SlopeChart
data={data}
series="country"
y={["y2000", "y2022"]}
names={{ y2000: "2000", y2022: "2022" }}
highlight={["Ethiopia", "Bangladesh"]}
height={520}
title="Life expectancy in Ethiopia rose from 39 to 65 years between 2000 and 2022"
subtitle="Life expectancy at birth, years, 2000 and 2022. Bangladesh rose from 49 to 73."
note="Illustrative figures."
/>
);
}{
"type": "slope-chart",
"data": [
{ "country": "Democratic Republic of the Congo", "y2000": 41, "y2022": 62 },
{ "country": "United Republic of Tanzania", "y2000": 44, "y2022": 58 },
{ "country": "Central African Republic", "y2000": 40, "y2022": 43 },
{ "country": "Papua New Guinea", "y2000": 47, "y2022": 49 },
{ "country": "Bosnia and Herzegovina", "y2000": 71, "y2022": 70 },
{ "country": "Saint Vincent and the Grenadines", "y2000": 69, "y2022": 71 },
{ "country": "Trinidad and Tobago", "y2000": 68, "y2022": 66 },
{ "country": "Lao People's Democratic Republic", "y2000": 52, "y2022": 66 },
{ "country": "Bangladesh", "y2000": 49, "y2022": 73 },
{ "country": "Ethiopia", "y2000": 39, "y2022": 65 },
{ "country": "Rwanda", "y2000": 46, "y2022": 68 },
{ "country": "Cambodia", "y2000": 50, "y2022": 69 },
{ "country": "Nepal", "y2000": 53, "y2022": 70 },
{ "country": "Mozambique", "y2000": 42, "y2022": 56 },
{ "country": "Sierra Leone", "y2000": 38, "y2022": 55 },
{ "country": "South Africa", "y2000": 61, "y2022": 62 },
{ "country": "Russian Federation", "y2000": 65, "y2022": 72 },
{ "country": "United States of America", "y2000": 77, "y2022": 78 },
{ "country": "Brazil", "y2000": 70, "y2022": 75 },
{ "country": "Viet Nam", "y2000": 72, "y2022": 74 }
],
"series": "country",
"y": ["y2000", "y2022"],
"names": { "y2000": "2000", "y2022": "2022" },
"highlight": ["Ethiopia", "Bangladesh"],
"height": 520,
"title": "Life expectancy in Ethiopia rose from 39 to 65 years between 2000 and 2022",
"subtitle": "Life expectancy at birth, years, 2000 and 2022. Bangladesh rose from 49 to 73.",
"note": "Illustrative figures."
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| seriesrequired | string | Entity field: one line each. | |
| x | string | Period field for long data. Omit when each row is an entity with one column per period. | |
| yrequired | string | string[] | Value field (long data), or the period columns in order (one row per entity). | |
| colorBy | "none" | "direction" | "series" | "none" | Accent for all lines, positive / negative by direction, or one hue per entity (up to 8). |
| good | "up" | "down" | "up" | Direction that takes the positive colour when colouring by direction. |
| labels | "both" | "end" | Entity names at both ends or only the end. Default: both; end only on narrow screens. | |
| names | Record<string, string> | Display names for entity keys and period columns. |
Common chart props 29
Every chart built with defineChart accepts these on top of its own props.
| Prop | Type | Description |
|---|---|---|
| data | DataInput | Rows, CSV text, a URL, { url, path }, an async function, or an Arrow-style table. Omit inside <InsightData>. |
| transform | Transform | Transform[] | A pipeline of transforms applied before drawing. |
| title | string | The title. One plain statement of what the data shows, with the number and the period ("Monthly churn fell from 4.2% to 2.1% in 2024"), or a plain label ("Monthly churn, 2024"). One clause, no figures of speech. |
| subtitle | string | Measure, unit, population, period. |
| source | string | Data source, shown as "Source: ...". |
| note | string | Method notes or caveats. |
| height | number | string | CSS height of the plot. Default 360. |
| aspect | number | Width / height. Overrides height. |
| highlight | string | string[] | The entity (or entities) the title is about. Every other series is drawn in grey. |
| annotations | Annotation[] | Reference lines, shaded bands and callouts, in data coordinates. |
| format | FormatSpec | How to print values: "compact", "percent", "currency:USD", "{value} kg", Intl options, or a function. |
| legend | boolean | Show the legend. Default: shown when there are two or more series. |
| select | boolean | string | Make marks clickable to filter. Inside <InsightData> the selection filters every other chart. Pass a field name, or true to use the chart's category field. |
| onSelect | (values: string[], field: string) => void | Called with the selected values whenever the selection changes. |
| option | EChartsOption | ((option: EChartsOption, ctx: BuildContext) => EChartsOption) | Deep-merged over the generated ECharts option, or a function that receives and returns it. Use it for ECharts settings no prop covers. |
| theme | ThemeInput | A theme, or a partial set of tokens merged over the surrounding theme, for this chart only. |
| mode | ModeInput | "auto" (default) follows the page, "system" follows the OS, or force "light" / "dark". |
| renderer | RendererInput | "auto" (default) uses SVG for light charts and canvas for heavy ones. |
| animate | boolean | Set false to disable animation. Reduced-motion preferences are always respected. |
| lazy | boolean | Mount the chart only when it scrolls near the viewport. Default true. |
| group | string | Link tooltips with other charts sharing this group id. |
| exportable | boolean | ExportFormat[] | Show an export menu: true or a list of formats from png, jpeg, svg, pdf, csv, json. |
| table | boolean | Show a collapsible "View data" table under the chart. |
| alt | string | Accessible description: the chart type and measures, then the main pattern and the notable values. |
| id | string | Stable id for this chart's selection in the shared store. |
| onEvents | Record<string, ChartEventHandler> | ECharts event handlers, e.g. { click: (params, chart) => {} }. Prefix a name with zr: to bind to the canvas itself. |
| onReady | (chart: EChartsInstance) => void | Called with the ECharts instance once it is created. |
| className | string | Class name for the outer <figure>. |
| style | CSSProperties | Inline style for the outer <figure>. |