Axes

Cars scatterplot of horsepower and fuel economy
Quantitative positions with nominal color.

At a glance

Action Shortest call Inference/defaults Result
createAxes createAxes() Stored coordinate family, position scales, titles Complete x/y, theta/radius, or Parallel dimension axes
editXAxis editXAxis({ line: { lineWidth: 2 } }) Existing x-axis components Selected x-axis components rematerialized
editYAxis editYAxis({ position: "right" }) Existing y-axis components Existing y-axis components moved together
removeXAxis / removeYAxis removeXAxis() Existing complete axis Semantic, graphic, and stored axis state removed

createAxes(options?)

Creates complete axes for encoded Cartesian x/y, Polar theta/radius, or Parallel dimension channels. This is the recommended axis action for ordinary chart authoring.

program.createAxes({
  y: { ticksAndLabels: { count: 6 } }
});
Option Type Default
coordinate { id?, type? } unique coordinate used by x/y layers
x axis options or false create when x is encoded
y axis options or false create when y is encoded
theta Polar axis options or false create when theta is encoded
radius Polar axis options or false create when radius is encoded

coordinate.type accepts "auto", "cartesian", "polar", or "parallel" as a stored type assertion.

Each x/y axis option supports:

Option Value
scale scale ID; inferred when one scale is used on the channel
position x: "bottom" or "top"; y: "left" or "right"
line { color?, lineWidth? }
ticksAndLabels { count?, values?, ticks?, labels? }
title title options including text, at, offset, and font styling

Use either count or exact data-space values for ticks. Ambiguous coordinates or scales must be selected explicitly. createAxes reads stored coordinates; it never creates or repairs them.

Linear scales create numeric nice ticks. Time scales choose a UTC calendar interval near the requested count and format labels automatically. Automatic formatting starts from the domain span, then raises precision only when two distinct resolved ticks would otherwise share a label. For example, a 1970–1982 domain produces 1970, 1972, …, 1982, while sub-month ticks include the day needed to distinguish them. Explicit time values are finite timestamps.

A band or point x scale uses its complete domain as the default tick and label values. Each value is placed at the shared band or point center and formatted with String(value). Explicit ticksAndLabels.values may select a domain subset in the requested order. Discrete axes reject count so categories are not silently omitted. Reversed ranges and Canvas rematerialization preserve the stored category values.

For a binned histogram x encoding, omitted tick options use the inferred bin boundaries. This keeps the axis aligned with every rect edge. Explicit ticksAndLabels.count or ticksAndLabels.values takes precedence. Count y axes use numeric nice ticks and infer titles such as count(Displacement).

Titles are inferred from the unique encoding consuming each scale. Aggregate encodings include their operation, so mean on Acceleration becomes mean(Acceleration). Pass title.text when inference is ambiguous or a custom label is desired.

The default edges remain bottom for x and left for y. A complete axis forwards an explicit edge to its line, ticks, labels, and title:

program.createAxes({
  x: {
    position: "top",
    ticksAndLabels: { labels: { format: ".1f" } }
  },
  y: { position: "right" }
});

Top ticks point upward and right ticks point right. Labels and titles are placed outward from the selected edge. The Canvas margin must already be large enough; guide creation does not resize it.

Numeric label formats are .0f, .1f, .2f, .0%, .1%, and .2e. UTC time formats are %Y, %Y-%m, and %Y-%m-%d. Numeric formats require a linear scale, time formats require a time scale, and ordinal labels use "auto". The existing { decimals: nonNegativeInteger } form remains available for linear labels. Explicit formats remain exact and may intentionally produce repeated display strings.

The selected coordinate ID is stored on each semantic axis. Canvas size and margin edits explicitly rematerialize positional scales and every connected axis component.

The trace preserves its decomposition:

createAxes
├─ createXAxis (when selected)
└─ createYAxis (when selected)

For a Polar coordinate, the same aggregate becomes:

createAxes
├─ createThetaAxis
└─ createRadialAxis

createThetaAxis() creates the outer circular baseline, outward ticks, perimeter labels, and an inferred title. createRadialAxis() creates one center-to-edge baseline; its angle defaults to 90 degrees (right). Both support ticksAndLabels: { count?, values?, ticks?, labels? } and title style. Set title: false on either Polar axis to omit that title at creation. The radial title defaults to position: "inside" at the baseline midpoint. Use title: { position: "outside" } to place it beyond the radial endpoint; offset is measured from the midpoint normal when inside and from the endpoint when outside.

For a Parallel coordinate, createAxes() delegates to an internal wrapped dimension-axis action. It creates one ordinary baseline, tick/label set, and title for each stored dimension. Channel-specific x/y/theta/radius options do not apply; revise dimension mapping with encodeParallelCoordinates and individual mappings with editScale.

For individual lines, ticks, labels, and titles, see Advanced axis components.

Editing a complete axis

Use editXAxis() or editYAxis() when several components of one existing axis should change together:

program
  .editXAxis({
    line: { color: "#334155", lineWidth: 2 },
    ticksAndLabels: {
      count: 6,
      ticks: { length: 7 },
      labels: { color: "#475569", fontSize: 11 }
    },
    title: { text: "Engine displacement" }
  })
  .editYAxis({ position: "right" });

The complete edit facade does not create an axis or change its scale and coordinate binding. It delegates to the existing line, tick, label, grouped tick/label, and title edit actions. Omitted component objects remain unchanged. Changing position updates every existing component on that axis, including components omitted from the call.

Use editThetaAxis() for grouped theta component edits. Use editRadialAxis({ angle: 180 }) to move the radial line, ticks, labels, and title together. Focused editThetaAxisLine/Ticks/Labels/Title and matching editRadialAxis* actions change one visible component without raw graphic IDs. editRadialAxisTitle({ position: "inside" | "outside" }) switches only the radial title placement while preserving its text and style.

Removing an axis

removeXAxis(), removeYAxis(), removeThetaAxis(), and removeRadialAxis() remove the complete axis: line, ticks, labels, title, semantic guide state, and stored materialization settings. Marks, scales, coordinates, and the opposite axis remain.

const withoutXAxis = program.removeXAxis();
const selected = program.removeYAxis({ scale: "y", coordinate: "main" });

Optional selectors must match the existing resource. A missing or mismatched axis throws before anything changes.

Option Meaning
position x: "bottom"/"top"; y: "left"/"right"
line { color?, lineWidth? }
ticks { count?, values?, length?, color?, lineWidth? }
labels { count?, values?, offset?, format?, color?, fontSize?, fontFamily?, fontWeight? }
ticksAndLabels { count?, values?, ticks?, labels? }
title { text?, at?, offset?, rotation?, color?, fontSize?, fontFamily?, fontWeight? }

Axis label and title weights follow the shared Canvas font-weight policy.

Use either ticksAndLabels or the independent ticks/labels options in one call. The action validates the entire request before editing any component, so an invalid later component cannot leave a partial result.

Errors and limitations

Ambiguous scale or coordinate candidates require explicit IDs. Each channel has one semantic axis, so parallel duplicate axes cannot be created.

Guides · Grids · Advanced axis components