What do you have to say about your data before a plot can be drawn? gog’s whole vocabulary is a short list of ordinary English words. Learn them once and you can read, and write, any plot.
binsmoothcountdensityproportionsummeanmedianmaxminrangeconfidenceboundspartition, and the three that resolve collisions, dodgestackjitter
Operators
+ layers, * derives, | and / arrange
Scales
linearlogtimecategoryorder
Spaces
flatspacepolarnestmap
Settings
stylethemepalette
Labels
titlex_labely_labelz_label
Facets
facet
Selections
brush
Every word in it is a common English word: no abbreviations, no acronyms, no silent letters.
Read the kernel as two groups: what a plot needs, and what refines or arranges it. Five kinds build a plot. A table supplies the rows and the columns. A mark is the shape drawn for each row. A channel maps a column to something you can see, such as a position or a color. A transform derives new values from the columns you named. An operator joins the words into one sentence.
The other six refine a plot or arrange it, and none of them is required. A scale decides how a number becomes a position. A space is the surface the plot is drawn on: a flat page, a cube, a circle, a map. A setting changes how the plot looks without saying anything about the data, and a label names it. A facet cuts one plot into panels. A selection picks rows out of a plot that is already drawn.
So the minimum sentence is a table, a mark, and the positions that mark needs:
data(table) + mark + x(column) + y(column)
Two promises hold across the whole kernel. The engine draws every word in it. And gog never accepts a word and then quietly ignores it: a sentence it cannot draw is refused, and the refusal names the rule. See Design laws for the difference between illegal (the grammar forbids it) and unsupported (the grammar allows it; the engine cannot draw it yet).
Each kind has a section below, in the order of the kernel above: the five that build a plot first, then the six that refine or arrange one. Each section gives the words and what they do, and names the chapter that teaches them in full.
2.2 Tables: where the rows come from
Every sentence begins with a table, and there are two ways to name one.
Table
Where the rows come from
data
A table already in memory
query
A table a database returns, named by SQL
query() stands exactly where data() stands, and everything after it is unchanged:
query(connection, "SELECT ...") + mark + x(column) + y(column)
The SQL stays inside query(). The columns after it are still bare names, because a database returns a table, and every sentence begins with a table. See Data.
2.3 Marks: the shape drawn for each row
A mark is the geometric form drawn for each row of data.
Mark
What it draws
point
One glyph per row
line
Rows connected in x order: a function read along a domain
bar
Rectangle from baseline to value, vertical or horizontal
area
Filled region between a line and the baseline
step
A line that holds each value until it changes (CDFs, histogram outlines)
interval
A whisker spanning low→high at each x: error bars, ranges; needs a range transform
box
Distribution per group: box, median, whiskers to 1.5×IQR, outliers as dots; carries its own summary
ribbon
A filled band from a low boundary to a high one across x: confidence / spread bands; needs a range transform
text
A string at each position: its content comes from the label channel
path
Rows connected in the table’s order: a route that may double back; takes style(arrow = )
rule
A line at one position, spanning the other axis: reference lines, and rugs via style(reach = "edge")
zone
A shaded region: bounded where its sides are known, spanning the panel where they are not. Five things know them: a categorical position (a category owns a slot: the tile plot), bounds (names them), bin (cuts them: the heatmap), density (cuts or traces them), and a boundary (the data draws them: the choropleth, in map())
surface
A sheet over a floor whose cells tile: one row per (x, y) crossing with a face between each block of four, or one row per cut cell with a flat plateau on each. The only mark that draws in the cube alone
2.4 Channels: a column made visible
A channel maps a data column to a visual property of the mark. Adding one word to the sentence adds one thing the reader can see:
“Given gapminder 2007: points, x is gdp, y is life, color by continent.” You never asked for the legend. A mapped column earns one.
Channels do not all play the same part, and what tells them apart is what each one earns:
Channel
What it does
Earns
x
Horizontal position, from a numeric or categorical column
an axis
y
Vertical position, from a numeric or categorical column
an axis
z
Depth, the third position: it makes a plot 3-D. Drawn by point, bar, interval, box, path and surface
an axis
color
Fill or stroke color, from a categorical or continuous column
a legend
size
Radius, on point
a legend
shape
Glyph (circle, square, triangle) on point
a legend
pattern
Texture: a fill’s hatch, a stroke’s dash. Every mark but point, text and surface
a legend
opacity
Transparency, on point and bar
a legend
group
Splits a mark into one series per category, without encoding it. On line, area, step, interval, box, ribbon, path, zone and surface
nothing
label
The string a text mark draws, its content
nothing
play
Cuts the plot into frames and plays them in sequence, from a numeric or categorical column
a strip
The Earns column sorts the channels into four kinds, and a Korean syllable is the shape to hold them against. It has three slots: an initial consonant, then a vowel, then an optional final consonant. The mark is the initial consonant, so the channels are the other two.
x, y and z are the vowels: a mark without one of them is silent, so at least one is required, and each earns an axis to be read against.
The five that earn a legend are the final consonants, the optional ㅁ (m) that turns 가 (ga) into 감 (gam). None is ever required, and each changes what the plot says, which is exactly why each needs a key to decode it.
group and label are neither. group splits without encoding: on a line it performs the very same split color does, one polyline per category, and then stops. It is what is left of color once the decoding is taken away, which makes it closer to the space between words than to a letter. label supplies a text mark’s content rather than refining it.
play is the fourth kind, and it stands outside the syllable the way faceting does. It does not refine one picture. It cuts the plot into frames and plays them in order, so what it earns is a strip naming the frame on screen. See Play.
Not every channel applies to every mark: a line is drawn with a single stroke, so it takes no per-row size or opacity. gog states the rule rather than guessing; see Design laws, and Combinations for the whole mark-by-channel grid on one page.
2.5 Transforms: values the data does not hold
A transform derives new values from the columns you named, and attaches to a mark with *. The mark stays what it is: bar * bin is still a bar, drawn over counted bands.
Ten of them replace values with a computed statistic.
Transform
What it computes
bin
Cuts a continuous column into bands and counts the rows in each
count
Tallies the rows in each category
proportion
The same tally, as a share of the whole
density
A smooth curve of where the rows lie
smooth
A trend line fitted through the points
summeanmedianmaxmin
Reduce a column to one value per group
Three produce a low and a high together, which is what a span needs:
Transform
What it computes
range
A low/high pair computed from the data
confidence
The interval around the mean
bounds
A low/high pair the table already holds, in two named columns
Three do not compute anything. They move marks that would otherwise land on top of each other:
Transform
What it does
dodge
Puts them side by side
stack
Piles them on top of one another
jitter
Spreads them sideways along a category
And partition divides a whole among nested parts, which is what a treemap and a mosaic are built from.
# Two layers: bars behind, points on topdata(actuals) +x(year) +y(sales) + bar +style(color ="lightsteelblue") + point +style(color ="steelblue", size =6)
(data(actuals) + x(col.year) + y(col.sales) + bar + style(color ="lightsteelblue") + point + style(color ="steelblue", size =6))
data(actuals) +x(:year) +y(:sales) + bar +style(color ="lightsteelblue") + point +style(color ="steelblue", size =6)
Each mark opens a new layer. Layers are rendered in order: first mark drawn first (at the bottom).
Order comes up more than once in this grammar, and it does not mean the same thing every time. Which orders matter gathers all of it in one place: what you may rearrange freely, what the engine refuses, and the two arrangements that change the picture without saying so.
2.7 The * operator: combining
* binds a mark to a transform, creating a derived mark type. The mark is always on the left; the transform is on the right. Where two transforms follow one mark, write them in the order they happen: bar * bin * mean cuts the axis into bands, then averages inside each one.
bar * bin # histogramline * smooth # smoothed trend linezone * bin # heatmap: the same `bin`, cutting both axes
The last line is the pattern worth noticing: one transform means one thing, and the mark decides how it lands. A bar leaves an axis free to measure the count along, so bin cuts the other one; a zone measures nothing by length and needs an extent on both, so the same word cuts every axis with a width to cut and the count becomes the color. On a zone with one categorical position it cuts the other one only, since a category arrived already cut.
The summaries divide by the same arithmetic, read the other way round. zone * mean + x(a) + y(b) + color(v) averages v within every cell two categories cross, because a summary groups by every position the mark does not measure with and reduces the column named on the one it does, which on a bar is y, on a zone is color, and in space() is z.
See Operators for the full rules, and Transforms for each transform in detail.
2.8 The | and / operators: faceting, or composing
| puts things side by side and / puts one above the other. Whether those are panels or whole plots is decided by what you write on the right.
With facet() on the right they split one plot into panels, one per category of the column it names:
Composed plots share nothing until they name the same column on the same axis, and then they share that axis outright: one scale, one extent, drawn once. That single rule is what makes a marginal plot two operators rather than a chart type. See Composition.
2.9 Scales: how a number becomes a position
A scale is written on the binding, the channel with its column in it. It is not an atom of its own, because it belongs to one channel and nothing else can combine with it:
data(gapminder_2007) + point +x(gdp, scale ="log") +y(life) +x_label("GDP per capita")
(data(gapminder_2007) + point + x(col.gdp, scale ="log") + y(col.life) + x_label("GDP per capita"))
data(gapminder_2007) + point +x(:gdp, scale ="log") +y(:life) +x_label("GDP per capita")
plot(data(gapminder_2007), point,x(col.gdp, { scale:"log" }),y(col.life),x_label("GDP per capita"))
1K10K4050607080LifeGDP per capita
“Given gapminder 2007: points, x is gdp on a log scale, y is life.”
Scale
What it does
linear
Equal steps for equal differences. The default
log
Equal steps for equal ratios, on x, y, color, size and opacity, with any base
time
Positions dates and times, chosen from the column type: Date and POSIXct
category
One slot per distinct value, chosen from the column type: text and factor columns
order
Which way a categorical axis runs, or declare it on the column: a factor in R, ordered() in the other three
A scale is not a transform: it produces no new values, only different positions for the ones you have. Where the two meet, what a log scale means for bar * bin or bar * sum, is set out in Scales.
The same binding takes two more words for the same reason. limits says what range the channel runs over when the data is not the authority on that, and tick_count says how densely an axis should be labeled. Both describe the scale, so both are written where the scale is written. Scales has all three.
2.10 Spaces: the surface a plot is drawn on
A space decides what a position means. Every plot so far has been drawn on the plane, which is flat and needs no saying.
Space
Where the marks stand
flat
The plane: x across, y up. The default
space
The cube: x, y and z, projected onto the page
polar
The plane bent into a circle: one position becomes an angle, the other a radius
nest
Rectangles inside rectangles, each sized by its share of the one holding it
map
The earth flattened: longitude across, latitude up
Every channel above answers a question about the data. color(species) asks “which species?”, and earns a legend so the reader can answer it.
Making every point one color asks nothing. It maps no column, needs no scale, and has nothing to decode, so it is not a channel. That is style:
Setting
What it fixes
style(color = )
One color for the whole layer
style(opacity = )
One opacity, 0–1
style(size = )
Point radius, or line stroke width
style(shape = )
One glyph for every point
style(pattern = )
The texture of a mark’s paint: a stroke’s dash (solid/dashed/dotted), a fill’s hatch (hatch/crosshatch/grid/dots). Every mark but point, text and surface
palette( )
Which colors the color channel hands out
theme( )
The page around the plot: grid, background, fonts, size
An axis carries the name of the column bound to it. A label replaces that name when the column name is not what a reader should see.
Label
What it names
title
The plot
x_labely_labelz_label
One axis each
title() is the one that adds words rather than replacing them, because a plot has no other way to say what it is about.
2.13 Facets: one panel per category
Facet
What it cuts
facet
Splits one plot into panels, one per category of the column it names
A facet is written on the right of | or /, which is why it appeared in the operator section above: … | facet(continent). See Faceting.
2.14 Selections: choosing rows in a drawn plot
Selection
What it does
brush
Dims the rows you did not pick, and removes none of them
A selection is the only kind that acts on a plot after it is drawn. What it does not change is the sentence, so the printed page still shows the bound that sentence named. See Selection.