Polar Point Chart Tutorial

Cars Polar scatterplot using acceleration angle and horsepower radius
Quantitative angle and radial position with nominal color.

This tutorial maps car acceleration to angle, horsepower to distance from the center, and origin to color. The public angle unit is degrees: 0 points to 12 o’clock and positive angles move clockwise.

Start with the Vite project from Getting Started, then place the tutorial dataset in Vite’s public directory:

mkdir -p public
curl --fail --location https://raw.githubusercontent.com/ggaction/ggaction/main/data/cars.json --output public/cars.json

Complete program

import { chart, render } from "ggaction";

const response = await fetch("/cars.json");
if (!response.ok) throw new Error(`Failed to load cars: ${response.status}`);
const cars = await response.json();
const rows = cars.filter(row =>
  Number.isFinite(row.Acceleration) &&
  Number.isFinite(row.Horsepower) &&
  typeof row.Origin === "string" &&
  row.Origin.length > 0
);

const program = chart()
  .createCanvas({ width: 520, height: 520, margin: 48 })
  .createData({ values: rows })
  .createPointMark()
  .encodeTheta({ field: "Acceleration" })
  .encodeR({ field: "Horsepower" })
  .encodeColor({ field: "Origin" })
  .encodePointRadius({ value: 3 });

render(program, document.querySelector("canvas").getContext("2d"));

encodeTheta and encodeR infer the current point mark, create the polar coordinate, and create scales named theta and radius. You can call them in either order. Until both channels exist, the semantic assignment is retained but no visible point position is produced.

Scale control

Theta uses [0, 360] by default. An explicit range may be reversed, but its absolute span cannot exceed 360 degrees:

const reversed = program.editScale({ id: "theta", reverse: true });

Radius uses [0, min(plot width, plot height) / 2] by default. Explicit radial ranges are logical Canvas pixels, must be non-negative, and must fit the current plot bounds. Canvas size and margin edits recompute automatic radial ranges.

const zoomed = program.editScale({
  id: "radius",
  domain: [40, 240],
  range: [12, 200]
});

encodePointRadius controls glyph size. It is an alias of encodeRadius and is separate from semantic radial position in encodeR.

Add Polar guides

Cars Polar scatterplot with circular and radial axes and grids
Polar point positions with readable theta and radius guides.

Call createGuides() after both position encodings to infer theta/radius axes and grids:

const guided = chart()
  .createCanvas({ width: 620, height: 620, margin: 78 })
  .createData({ values: rows })
  .createPointMark({ opacity: 0.78 })
  .encodeTheta({ field: "Acceleration" })
  .encodeR({ field: "Horsepower", scale: { zero: true } })
  .encodeColor({ field: "Origin" })
  .encodePointRadius({ value: 3 })
  .createGuides();

The default radial axis points right at 90 degrees. Theta spokes and radial circles draw behind the points; both axes draw above them. Titles are inferred from the encoded fields. Use editRadialAxis({ angle: 180 }) to move the whole radial axis together, or a focused edit such as editThetaAxisLabels({ fontSize: 12 }).

Current boundary

Polar point marks support ordinary color, size, shape, opacity, filtering, selection, highlighting, theta/radius axes, and both Polar grid families. Polar lines and closed radar paths use the same position and guide system; arc marks remain outside this slice.

Position encodings · Polar lines · Coordinates · Scale options