Skip to content

Bubble

Scatter with a third dimension: sizeField controls the marker diameter within the size…maxSize range.

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'GDP vs Happiness Index' },
    subtitle: { text: 'bubble size — population, millions' },
    series: [
      {
        type: 'bubble',
        xField: 'gdp',
        xName: 'GDP per capita',
        yField: 'happiness',
        name: 'Happiness Index',
        sizeField: 'population',
        sizeName: 'Population, M',
        maxSize: 36,
      },
    ],
    axes: [
      { type: 'number', position: 'bottom', title: { text: 'GDP per capita, $K' } },
      { type: 'number', position: 'left', title: { text: 'Happiness Index' }, nice: false },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { gdp: 4.2, happiness: 5.9, population: 144 },
    { gdp: 12.6, happiness: 6.1, population: 1412 },
    { gdp: 2.4, happiness: 4.3, population: 1408 },
    { gdp: 76.3, happiness: 6.9, population: 332 },
    { gdp: 48.7, happiness: 7.0, population: 84 },
    { gdp: 34.0, happiness: 6.5, population: 125 },
    { gdp: 51.0, happiness: 6.4, population: 52 },
    { gdp: 9.7, happiness: 6.3, population: 215 },
  ];
}

Labels inside bubbles

In addition to the line placements there is placement: 'inside' — text at the center of the bubble with an auto-contrast color and a halo in the marker's color:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Bubble with Inside Labels' },
    subtitle: { text: "placement: 'inside' — auto contrast and bubble-colored halo" },
    series: [
      {
        type: 'bubble',
        xField: 'reach',
        yField: 'engagement',
        sizeField: 'budget',
        sizeName: 'Budget',
        name: 'Channels',
        size: 22,
        maxSize: 58,
        fillOpacity: 0.8,
        label: {
          enabled: true,
          placement: 'inside',
          formatter: ({ datum }) => String(datum.channel),
        },
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { reach: 20, engagement: 65, budget: 45, channel: 'TV' },
    { reach: 45, engagement: 40, budget: 28, channel: 'Radio' },
    { reach: 60, engagement: 72, budget: 64, channel: 'Social' },
    { reach: 75, engagement: 30, budget: 18, channel: 'Print' },
    { reach: 85, engagement: 58, budget: 38, channel: 'Search' },
  ];
}

Size range

size/maxSize set the diameters for the minimum and maximum sizeField values:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Bubble Size Range' },
    subtitle: { text: 'size 8 → maxSize 46, translucent fill' },
    series: [
      {
        type: 'bubble',
        xField: 'effort',
        yField: 'impact',
        sizeField: 'team',
        sizeName: 'Team',
        name: 'Initiatives',
        size: 8,
        maxSize: 46,
        fillOpacity: 0.55,
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { effort: 2, impact: 8, team: 6 },
    { effort: 4, impact: 6, team: 14 },
    { effort: 5, impact: 9, team: 22 },
    { effort: 7, impact: 4, team: 9 },
    { effort: 8, impact: 7, team: 30 },
    { effort: 3, impact: 3, team: 4 },
    { effort: 6, impact: 8, team: 18 },
    { effort: 9, impact: 9, team: 12 },
  ];
}

Options

Options common to all series (name, showInLegend, tooltip.renderer, …) are covered in Common series options.

All scatter options, plus:

OptionTypeDefaultDescription
sizeFieldstringsize value key (required)
sizeNamestringsizeFieldname in the tooltip
sizePixels8diameter for the minimum value
maxSizePixels28diameter for the maximum value
shapeMarkerShapecirclemarker shape
fillstylespalettefill
fillOpacitystyles0.85fill
strokestylesbackgroundmarker stroke
strokeWidthstyles1marker stroke
itemStyler(params) => MarkerItemStyleper-point styles
label.enabledbooleanfalseshow value labels
label.placement'top' | 'bottom' | 'left' | 'right' | 'inside''top'label position
label.formatter({ value, datum }) => stringthe valuelabel content
label.fontSizePixels11label font size
label.fontWeightstring | numbernormalfont weight
label.fontFamilystringtheme fontfont family
label.colorColorValueforeground; auto-contrast when insidetext color