import { BubbleChart } from "semiotic"
BubbleChart visualizes three dimensions of data using x position, y position, and bubble size. It is perfect for showing relationships between continuous variables while encoding magnitude through area. UsecolorBy to add a fourth categorical dimension. For simple two-variable point plots without size encoding, seeScatterplot.
Quick Start
A bubble chart requires data, xAccessor,yAccessor, and sizeBy.
import { BubbleChart } from "semiotic" const frameProps = { /* --- Data --- */ data: [ { gdp: 12000, lifeExpectancy: 72, population: 45, country: "Brazil" }, { gdp: 42000, lifeExpectancy: 79, population: 33, country: "Canada" }, { gdp: 8500, lifeExpectancy: 76, population: 140, country: "China" }, // ...more data points ], /* --- Process --- */ xAccessor: "gdp", yAccessor: "lifeExpectancy", /* --- Customize --- */ xLabel: "GDP per Capita ($)", yLabel: "Life Expectancy (years)", sizeBy: "population" } export default () => { return <BubbleChart {...frameProps} /> }
Examples
Color by Category
Use colorBy to encode a categorical dimension with color. A legend is automatically displayed.
import { BubbleChart } from "semiotic" const frameProps = { /* --- Data --- */ data: [ { gdp: 12000, lifeExpectancy: 72, population: 45, continent: "Americas" }, { gdp: 38000, lifeExpectancy: 82, population: 67, continent: "Europe" }, // ...data with continent field for coloring ], /* --- Process --- */ xAccessor: "gdp", yAccessor: "lifeExpectancy", /* --- Customize --- */ xLabel: "GDP per Capita ($)", yLabel: "Life Expectancy (years)", colorBy: "continent", sizeBy: "population" } export default () => { return <BubbleChart {...frameProps} /> }
Custom Size Range
Adjust sizeRange to control the minimum and maximum bubble radii, and bubbleOpacity for overlapping readability.
import { BubbleChart } from "semiotic" const frameProps = { /* --- Data --- */ data: countryData, /* --- Process --- */ xAccessor: "gdp", yAccessor: "lifeExpectancy", /* --- Customize --- */ xLabel: "GDP per Capita ($)", yLabel: "Life Expectancy (years)", sizeBy: "population", sizeRange: [8, 50], bubbleOpacity: 0.4, bubbleStrokeWidth: 2 } export default () => { return <BubbleChart {...frameProps} /> }
With Grid Lines
Enable showGrid for reference lines that help readers estimate values.
import { BubbleChart } from "semiotic" const frameProps = { /* --- Data --- */ data: countryData, /* --- Process --- */ xAccessor: "gdp", yAccessor: "lifeExpectancy", /* --- Customize --- */ showGrid: true, xLabel: "GDP per Capita ($)", yLabel: "Life Expectancy (years)", sizeBy: "population", bubbleOpacity: 0.7 } export default () => { return <BubbleChart {...frameProps} /> }
Props
| Prop | Type | Required | Default | Description |
|---|
data | array | Yes | — | Array of data points. Each point should have x, y, and size properties. |
xAccessor | string | function | — | "x" | Field name or function to access x values from each data point. |
yAccessor | string | function | — | "y" | Field name or function to access y values from each data point. |
sizeBy | string | function | Yes | — | Field name or function to determine bubble size. This is required for bubble charts. |
sizeRange | [number, number] | — | [5, 40] | Min and max radius for bubbles. |
colorBy | string | function | — | — | Field name or function to determine bubble color. |
colorScheme | string | array | — | "category10" | Color scheme name or custom colors array. |
bubbleOpacity | number | — | 0.6 | Opacity of the bubbles. |
bubbleStrokeWidth | number | — | 1 | Stroke width of bubble borders. |
bubbleStrokeColor | string | — | "white" | Stroke color of bubble borders. |
enableHover | boolean | — | true | Enable hover annotations on data points. |
showGrid | boolean | — | false | Show background grid lines. |
showLegend | boolean | — | true (when colorBy) | Show a legend. Defaults to true when colorBy is specified. |
tooltip | object | function | — | — | Tooltip configuration or render function. |
width | number | — | 600 | Chart width in pixels. |
height | number | — | 400 | Chart height in pixels. |
margin | object | — | { top: 50, bottom: 60, left: 70, right: 40 } | Margin around the chart area. |
xLabel | string | — | — | Label for the x-axis. |
yLabel | string | — | — | Label for the y-axis. |
title | string | — | — | Chart title displayed at the top. |
frameProps | object | — | — | Additional StreamXYFrame props for advanced customization. Escape hatch to the full Frame API. |
Graduating to the Frame
When you need more control — custom marks, complex annotations, force-directed layouts — graduate toStreamXYFrame directly. EveryBubbleChart is just a configured StreamXYFrame under the hood.
Chart (simple)
JSX
import { BubbleChart } from "semiotic" <BubbleChart data={countryData} xAccessor="gdp" yAccessor="lifeExpectancy" sizeBy="population" colorBy="continent" sizeRange={[5, 40]} xLabel="GDP per Capita" yLabel="Life Expectancy" />
Frame (full control)
JSX
import { StreamXYFrame } from "semiotic" <StreamXYFrame points={countryData} xAccessor="gdp" yAccessor="lifeExpectancy" pointStyle={d => ({ fill: colorScale(d.continent), fillOpacity: 0.6, stroke: "white", strokeWidth: 1, r: sizeScale(d.population) })} axes={[ { orient: "left", label: "Life Expectancy" }, { orient: "bottom", label: "GDP per Capita" } ]} hoverAnnotation={true} customPointMark={({ d }) => ( <circle r={d.r} /> )} size={[600, 400]} />
The frameProps prop on BubbleChart lets you pass any StreamXYFrame prop without fully graduating:
JSX
// Use frameProps as an escape hatch <BubbleChart data={countryData} xAccessor="gdp" yAccessor="lifeExpectancy" sizeBy="population" frameProps={{ annotations: [ { type: "enclose", coordinates: largeBubbles, label: "High population" } ], customPointMark: ({ d }) => <circle r={d.r} fill="gold" /> }} />
- Scatterplot — two-variable point plots without size encoding
- Heatmap — aggregate dense point data into color-encoded cells
- StreamXYFrame — the underlying Frame with full control over every rendering detail
- Annotations — adding callouts, highlights, and notes to any visualization
- Tooltips — custom tooltip content and positioning