Engineering

What is a grammar of graphics? A practical guide for product teams

Learn how reusable parts combine into flexible charts, with interactive examples showing what a grammar of graphics means for your product.

14 min read

Featured image

We frequently mention grammar of graphics across Graphy’s website and docs, so it’s worth unpacking what we mean, especially if you’re choosing a charting library for your product.

In short, a grammar of graphics is a system for building charts from independent, composable parts. Instead of choosing a predefined chart type such as “bar chart” or “scatter plot”, you describe how data should map to position, colour and size; which marks should represent it; how those marks should be arranged; and which scales and coordinate system should be used.

That may sound like a distinction for data-visualisation specialists, but it has a very practical consequence for product teams: a new visual does not always need a new component, a new API or another branch in a chart-type switch statement. It can be a new composition of the same building blocks the system already understands.

Key idea: chart types are recipes, not primitives

Build the chart

yx
Same data. Different grammar. A whole new chart.


When choosing a charting library, you’ll often start with the chart types you need:

“I need bar charts, line charts, pie charts and scatter plots.”

A grammar of graphics takes a different approach; you describe how to build a chart from individual parts:

“Put region on the horizontal axis and revenue on the vertical axis. Draw bars, use a different colour for each segment, and stack the segments.”

A grammar like this makes each part of the chart available to combine in other ways. It also gives a granular way for AI agents a structured way to create and revise charts, including combinations you haven’t predefined as chart types.

Named chart types still matter. “Bar chart” is quicker to say than “rectangular marks positioned on a categorical x scale and a continuous y scale”. But in a grammar, the name is shorthand for a composition of several different parts:







Change one part and you change the result. Keep the bars, but change their position from grouped to stacked. Keep the data and marks, but flip the coordinate system for horizontal bars. Map the same values to angle in polar coordinates, and the bars become slices of a pie or donut.

If you want to dig deeper into the topic, look into the work of Leland Wilkinson, who formalised the grammar of graphics concept. Hadley Wickham went on to develop a layered version while building ggplot2.

Why should a product manager or engineer care?

When you add charts to your product, building the first chart is usually pretty easy. Adding a few other chart types is normally manageable. But the difficulty comes when charts become a surface that customers actually use, rather than a basic feature they glance at.

Users often want to see stacked bars, targets, forecasts, direct labels, annotations, custom colours, new number formats, exports, responsive behaviour and a chart that does not yet have a tidy name… you get the idea.

In a fixed catalogue, each user request risks becoming a special case attached to one component. The catalogue grows, its APIs drift apart and cross-cutting features have to be made to work repeatedly.

A grammar changes the unit of work entirely. Instead of implementing “a target line for bar charts” and then “a target line for line charts”, the system can provide a reusable rule layer. Instead of separate vertical and horizontal bar components, it can provide one bar geom and a coordinate flip. Instead of a special implementation for every combination, it can compile the same small vocabulary in different ways.


Chart-type starting point

Grammar-based starting point

Select a chart component

Compose a chart specification

The component API often bundles marks, mappings and scales

Independent parts own marks, mappings, scales and coordinates

Variants often add component-specific options

Variants change one or two spec parts

Shared features depend on the library’s architecture

Layers such as rules or points can be reused

A new visual may require a new component

New or unnamed visuals can emerge from composition

Generated output tends to mirror a component API

Generated output can target a constrained, serialisable vocabulary

This is a spectrum; many excellent charting libraries mix chart templates, low-level primitives and declarative configuration. If your product needs three read-only charts, a small fixed API may be exactly the right approach. A grammar of graphics becomes much more valuable as chart variety, user editing, persistence and programmatic generation become central to your product.

What are the key parts of a grammar of graphics?

Different implementations use slightly different names and boundaries. The following model is enough to understand most layered grammars and Graphy’s SDK.

1. Data

The observations and variables you want to represent. For example, each row might contain a month, region and revenue value.

The chart specification can stay separate from the rows themselves. That means the same specification can be reused with another dataset that has the same shape.

2. Mappings, or aesthetics

A mapping connects a data variable to something visible:


  • month → x-position

  • revenue → y-position

  • region → colour

  • orders → point size

Position, colour, size, opacity and line style are examples of aesthetics: properties a reader can perceive in the graphic.

3. Transforms and statistics

Transforms reshape the table before it is drawn: filter rows, sort categories, aggregate values or convert wide data to long data.

Statistics operate within a layer. They can count records, sum values, calculate a mean or fit a trend. In a general layered grammar, a histogram combines binning with bar marks.

4. ‘Geoms’, or geometric objects

A geom is the visible mark: a point, line, area, bar or rule. The word is short for “geometric object”.

Geoms are deliberately simple. A line does not need to know whether it represents revenue, temperature or a forecast. It only needs mapped positions, a scale and the rules for drawing a line.

5. Position

Position rules resolve marks that would otherwise overlap. Bars can be placed side by side, stacked, normalised to 100%, or left in their original positions.

This is why “grouped bar” and “stacked bar” can be two arrangements of the same mark rather than unrelated components.

6. Scales and guides

A scale converts data values into visual values. It maps revenue to a vertical position, a category to a colour, or order volume to point size.

Guides make those mappings readable. Position scales normally produce axes; colour and size scales normally produce legends.

7. Coordinate system

Coordinates define the space in which marks are drawn. Cartesian coordinates give you the familiar x and y plane. Flipped coordinates swap the orientation. Polar coordinates map values around a circle.

This separation reveals relationships that a chart menu hides. A bar in Cartesian coordinates is rectangular. A 100%-stacked bar drawn in polar coordinates can become a pie.

8. Layers

A layer combines data or mappings with a geom, statistic and position rule. A chart can contain several layers that share scales and coordinates.

A revenue trend might use a line layer for continuity, a point layer for individual observations and a rule layer for the target. The result is one chart, not three charts placed on top of one another by hand.

9. Style and storytelling

The grammar describes what the chart means and how it is structured. A production chart also needs controlled paint and explanation: typography, gridlines, labels, highlights, annotations and other forms of emphasis.

Annotations, highlights and reference lines should be part of the chart’s structure, too. A target line tied to the value 250 stays in the right place when the chart resizes or the data changes.

Grammar of graphics example: build a bar chart from parts

Here is a small Graphy chart. The important part is the specification passed to GraphProvider.


TSX
import {
  GraphProvider,
  GraphRenderer,
  config,
  coord,
  createSpec,
  geom,
  pipe,
  scale,
} from '@graphysdk/react';

const data = {
  columns: [
    { key: 'region', label: 'Region' },
    { key: 'revenue', label: 'Revenue (£k)' },
  ],
  rows: [
    { region: 'North', revenue: 500 },
    { region: 'South', revenue: 260 },
    { region: 'West', revenue: 160 },
    { region: 'East', revenue: 80 },
  ],
};

const spec = pipe(
  createSpec({
    x: 'region',
    y: 'revenue',
    color: 'region',
  }),
  geom.bar({ position: 'identity' }),
  scale.x(),
  scale.y(),
  scale.color.discrete(),
  config({
    legend: { position: 'none' },
    axes: { y: { label: 'Revenue (£k)' } },
    content: {
      graphyBadge: {
        visible: true,
        position: 'footer',
        variant: 'full',
      },
    },
  }),
);

export function RevenueByRegion() {
  return (
    <div style={{ height: 360 }}>
      <GraphProvider data={data} spec={spec}>
        <GraphRenderer />
      </GraphProvider>
    </div>
  );
}

The code does not call a BarChart component. It says:

  1. Map region to x and colour, and revenue to y.

  2. Draw a bar for each observation.

  3. Use identity positioning.

  4. Resolve x, y and colour scales.

  5. Configure the guides and provenance mark.

“Bar chart” is the result of that sentence.

Take the same data, apply a different composition

Suppose the end user’s question changes from “Which region has the most revenue?” to “What share of revenue comes from each region?” The data can stay the same while three structural choices change:


TSX
const donutSpec = pipe(
  createSpec({
    x: '',
    y: 'revenue',
    color: 'region',
  }),
  geom.bar({ position: 'fill' }),
  coord.polar({
    theta: 'y',
    innerRadius: 0.55,
  }),
  scale.x(),
  scale.y(),
  scale.color.discrete(),
  config({
    legend: { position: 'right' },
    content: {
      graphyBadge: {
        visible: true,
        position: 'footer',
        variant: 'full',
      },
    },
  }),
);

The mapping now puts every row in one shared band. position: 'fill' normalises the values to shares of the total. Polar coordinates bend the filled bar around a circle, and innerRadius creates the hole.

Bars make precise comparisons easier because they share a baseline. A donut can work when the question is each region’s share of the total and there are only a few categories. Both use the same data; choosing between them still takes judgement.

Layers turn a chart into an explanation

Composition is not only about changing chart types. It is also how a chart gains context.


TSX
const layeredSpec = pipe(
  createSpec({ x: 'month', y: 'revenue' }),
  geom.line(),
  geom.point({ interactive: false }),
  geom.rule({
    aes: { y: { value: 250 } },
    params: {
      label: 'Target',
      labelPosition: 'start',
    },
  }),
  scale.x(),
  scale.y(),
  config({
    axes: { y: { label: 'Revenue (£k)' } },
    content: {
      graphyBadge: {
        visible: true,
        position: 'footer',
        variant: 'full',
      },
    },
  }),
);

The line shows continuity, the points expose individual observations and the rule provides a benchmark. All three layers share the same scales and coordinate system, so they remain aligned as the data or container changes.

Graphy also treats highlights and annotations as structured, serialisable parts of the specification. That is important in a product where charts are edited, saved and regenerated. The story should remain attached to the data it explains.

What a grammar changes in your product architecture

Having this structured approach also helps when users need to edit, save and reopen a chart.

One model for creating, editing and storing charts

In Graphy, a chart specification describes the chart’s mappings, layers, scales, styling and annotations. It is serialisable, so your application can save and reload it. It is also immutable: edits create a new version of the spec.

The same specification supports several jobs:

  • a developer can build it with typed helpers;

  • an editor can update it and track changes for undo;

  • your application can store and version it;

  • an API can pass it between systems;

  • an AI agent can generate or revise it;

  • the engine can compile it for a renderer to draw.

Plugin code still lives in your application, and reloading a saved spec does not automatically restore its undo history. See the serialisable spec documentation.

A compiler can validate before a renderer paints

Graphy separates the grammar engine from the React renderer. The engine resolves scales, runs statistics, places observations, validates styles and works out guides. It does this without a DOM. The renderer then lays out and paints the compiled result, formats values for the locale and adds interaction.

This boundary makes failures easier to detect and test, and keeps chart meaning separate from the surface that displays it. Graphy’s compile and render pipeline explains the boundary in more detail.

AI gets a constrained visual language

A grammar gives AI agents a defined set of chart-building operations: reshape data, change mappings, add layers or annotations, adjust scales and coordinates, and apply styles.

Requests such as “split this by region”, “show the target” or “use our brand theme” can become changes to a chart specification your application can inspect, save and edit.

The model’s choices can still vary. The chart engine validates and renders the resulting spec deterministically.

How Graphy builds on the grammar

Graphy uses the same chart specification for styling, storytelling and editing. A user might apply a theme, add a target or note, and undo a change without leaving the chart.

  • Themes provide shared styles, palettes and defaults, with per-chart overrides. They can also change how geoms look and are drawn.

  • Storytelling keeps highlights, annotations and reference marks connected to the chart.

  • Editing updates the spec with undo and redo during the session. Your application handles saving the result.

  • Slots let your application replace regions such as tooltips or annotation controls.

  • Custom geoms let you add domain-specific visuals that reuse Graphy’s scales and styling. You implement the rendering and interactions.

For other custom visuals, you can reuse its compiled scales and styling while implementing the rendering and interactions yourself.

Grammar of graphics vs ggplot2, Vega-Lite and Graphy

The grammar of graphics is an idea, not a single library or syntax.

  • The Grammar of Graphics is Leland Wilkinson’s formal framework for describing statistical graphics.

  • ggplot2 implements Hadley Wickham’s layered grammar in R and popularised terms such as geoms, aesthetics and layers. Its grammar chapter explains the model in detail.

  • Vega-Lite is a high-level grammar for interactive graphics expressed as declarative JSON. For a product-focused comparison, see Graphy’s guide to Vega-Lite alternatives.

  • Graphy uses a grammar-of-graphics engine as the structured foundation for a product-facing React renderer, editing, storytelling controls, styling and optional agents.

The shared philosophy is composition. The differences are the host language, level of abstraction, runtime, defaults and product experience built around the grammar.

When is a grammar-based charting platform the right choice?

Consider one when:

  • Users need to create, edit, save and reopen charts.

  • Your chart range will grow, including unusual or custom visuals.

  • Annotations, targets and highlights are part of the experience.

  • Charts need consistent branding, including those generated by users or AI.

  • You want AI agents to work with a structured chart model.

For a small, fixed set of read-only charts, a simpler library may be enough. Building your own rendering may make sense if a highly specialised visualisation is central to your product.

Either way, check framework support and licensing, and test performance with your actual workload.

What to ask when evaluating a charting library

Look beyond the gallery to how charts will work in your product:

  1. Composition: Can you combine marks, layers and coordinates to create the views you need?

  2. Styling and storytelling: Do themes, annotations and reference lines work consistently across chart types and stay linked to the data?

  3. Editing: What can users change, and can they undo those changes?

  4. Persistence: Can your application save, version and reload the chart? What state, such as undo history, must it manage separately?

  5. Custom visuals: If a visual isn’t built in, can you reuse the library’s scales and styling? What rendering and interaction code will you need to write?

Frequently asked questions

What is a grammar of graphics in simple terms?

It is a way to build charts from reusable parts: data, mappings, marks, scales, positions and coordinates. Instead of treating each chart type as a separate component, you describe how those parts should work together.

What is a geom?

A geom is the visual mark used to represent data, such as a bar, point, line, area, rule or tile. Changing the geom can change the chart while leaving much of the rest of the specification intact.

How do Wilkinson’s grammar and ggplot2 relate?

Leland Wilkinson formalised the general framework in The Grammar of Graphics. Hadley Wickham developed a layered version while building ggplot2, an R implementation. Other systems, including Vega-Lite and Graphy, use related grammar-based ideas with different APIs and product goals.

Does a grammar of graphics guarantee a good chart?

No. It gives you a structured way to build and revise charts, but you still need judgement about chart choice, scales, colour, labels and annotations. A grammar makes those decisions easier to express; it does not make them for you.

Why is it useful for AI-generated charts?

A grammar gives an AI system a constrained, inspectable target instead of arbitrary rendering code. The model can propose mappings, layers, scales and annotations, and the engine can validate the spec before the renderer paints it. That makes the result easier to inspect, edit, store and revise.

Sources and further reading

Image

WRITTEN BY

Nick Smith

Graphy team

Nick has 13+ years experience of wrestling with the challenge of how to make data clear and easy to understand. He writes about product, marketing, and all things product marketing.

get started

get started

Install and test it on your own machine.

Install the SDK and follow the docs to render your first chart. Get in touch when you're ready to use Graphy in production.

Install the SDK and follow the docs to render your first chart. Get in touch when you’re ready to use Graphy in production.

01 install

Add Graphy to your app

npm install @graphysdk/react

02 render

Render your first chart

<GraphProvider input={spec} data={data}>
  <GraphRenderer />
</GraphProvider>

03 go live

Use Graphy in production.

Tell us what you are building. We will help with the right licence, integration path and support.