| country | continent | year | life | population | gdp |
|---|---|---|---|---|---|
| Afghanistan | Asia | 2007 | 43.828 | 31889923 | 974.5803 |
| Albania | Europe | 2007 | 76.423 | 3600523 | 5937.0295 |
| Algeria | Africa | 2007 | 72.301 | 33333216 | 6223.3675 |
| Angola | Africa | 2007 | 42.731 | 12420476 | 4797.2313 |
| Argentina | Americas | 2007 | 75.320 | 40301927 | 12779.3796 |
39 Selection
Which of these points are the rich countries, and where do they sit? Finding them among 142 dots takes a long time. Add one word and the reader can draw a box around any group, and the rest are dimmed:
data(gapminder_2007) + point + x(gdp) + y(life) + color(continent) +
theme(width = 620) + brush(data(gapminder_2007) + point + x(col.gdp) + y(col.life) + color(col.continent) +
theme(width = 620) + brush)data(gapminder_2007) + point + x(:gdp) + y(:life) + color(:continent) +
theme(width = 620) + brushplot(data(gapminder_2007), point, x(col.gdp), y(col.life),
color(col.continent), theme({ width: 620 }), brush)“Given gapminder 2007: points, x is gdp, y is life, color by continent, and let the reader select.”
On a page that can run the engine, drag across that plot. On paper it is the scatter itself, because nothing is selected until someone selects it.
Bare brush means the positions this plot binds, so here it is a region over gdp and life together. It says the plot is explorable without deciding in advance what is worth exploring.
Every country is still drawn while you drag. The ones inside your box keep their color and the rest are dimmed, so the group is read against what it was taken from. Remove the other rows and the plot no longer shows that the rich countries sit at the top right of the whole world.
39.1 Saying where the selection starts
On paper the first plot is a plain scatter, and the reader still has to find the rich countries. Name a column and the brush states a bound on it: the two values the selection starts between. That is how you point at something rather than let a reader look for it:
data(gapminder_2007) + point + x(gdp) + y(life) + color(continent) +
theme(width = 620) + brush(gdp, at = c(20000, 60000))(data(gapminder_2007) + point + x(col.gdp) + y(col.life) + color(col.continent) +
theme(width = 620) + brush(col.gdp, at = [20000, 60000]))data(gapminder_2007) + point + x(:gdp) + y(:life) + color(:continent) +
theme(width = 620) + brush(:gdp, at = [20000, 60000])plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
color(col.continent), theme({ width: 620 }),
brush(col.gdp, { at: [20000, 60000] }))“Given gapminder 2007: points, x is gdp, y is life, color by continent, and let the reader select gdp, starting from 20000 to 60000.”
The thirty or so countries above 20,000 dollars keep their color, and you can see at once that they sit almost entirely above 75 years. That is closer to an annotation than to a tool: the sentence has done the selecting, and a reader can still drag to move the bound.
The two forms answer different questions, and the difference is who chooses. brush hands the choice to the reader. brush(gdp, at = ...) makes the choice in the sentence, so the selection appears on paper too.
39.2 Highlighting, never removing rows
This is the one rule to learn, and it separates brush from an atom you already know. limits also takes a range in a column’s own units. It does something different with it.
limits runs before the statistics. It removes rows, and the transform then sees the survivors as if they were the whole data. brush runs after the picture is composed. It removes nothing and recomputes nothing.
One range, one mark, two outcomes:
data(gapminder_2007) + point + x(gdp, limits = c(20000, 60000)) + y(life) +
theme(width = 620, height = 300) + title("limits: 109 countries gone")(data(gapminder_2007) + point + x(col.gdp, limits = [20000, 60000]) + y(col.life) +
theme(width = 620, height = 300) + title("limits: 109 countries gone"))data(gapminder_2007) + point + x(:gdp, limits = [20000, 60000]) +
y(:life) + theme(width = 620, height = 300) +
title("limits: 109 countries gone")plot(data(gapminder_2007), point, x(col.gdp, { limits: [20000, 60000] }),
y(col.life), theme({ width: 620, height: 300 }),
title("limits: 109 countries gone"))“Given gapminder 2007: points, x is gdp from 20000 to 60000, y is life.”
data(gapminder_2007) + point + x(gdp) + y(life) +
theme(width = 620, height = 300) + brush(gdp, at = c(20000, 60000)) +
title("brush: all 142 still here")(data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
theme(width = 620, height = 300) + brush(col.gdp, at = [20000, 60000]) +
title("brush: all 142 still here"))data(gapminder_2007) + point + x(:gdp) + y(:life) +
theme(width = 620, height = 300) + brush(:gdp, at = [20000, 60000]) +
title("brush: all 142 still here")plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
theme({ width: 620, height: 300 }),
brush(col.gdp, { at: [20000, 60000] }),
title("brush: all 142 still here"))The first plot is a different plot. Its axis runs from 20,000 to 60,000, only the countries inside that range are drawn, and both axes were fitted to the ones that survived. Look at its y axis: the lowest number on it is 74, because every country with a low life expectancy was removed. gog prints how many it removed rather than removing them in silence.
The second is the whole world, with one group keeping its color. Its axes are the axes of all 142 countries, so the selection sits where it always sat. Stacked rather than side by side on purpose: the two share no fitted axis, and setting them next to each other invites a reader to compare positions that were fitted to different data.
Which of the two you want is a genuine choice and the grammar keeps both sayable. Ask how does this subgroup look on its own and you want limits. Ask where does this subgroup sit inside the whole and you want brush.
39.3 Two bounds make a rectangle
Which of the rich countries also live longest? That is two conditions on one row. One brush is one column. Write two, and a row has to satisfy both:
data(gapminder_2007) + point + x(gdp) + y(life) + color(continent) +
theme(width = 620) + brush(gdp, at = c(20000, 60000)) + brush(life, at = c(78, 85))(data(gapminder_2007) + point + x(col.gdp) + y(col.life) + color(col.continent) +
theme(width = 620) + brush(col.gdp, at = [20000, 60000]) + brush(col.life, at = [78, 85]))data(gapminder_2007) + point + x(:gdp) + y(:life) + color(:continent) +
theme(width = 620) + brush(:gdp, at = [20000, 60000]) +
brush(:life, at = [78, 85])plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
color(col.continent), theme({ width: 620 }),
brush(col.gdp, { at: [20000, 60000] }),
brush(col.life, { at: [78, 85] }))“Given gapminder 2007: points, x is gdp, y is life, color by continent, and let the reader select gdp, starting from 20000 to 60000, and life, starting from 78 to 85.”
The rich countries that also live longest. Six of the countries that survived the first bound do not survive this one, and you can see exactly which six, because they are still on the page.
Writing it as two atoms rather than one with two arguments follows the rest of the grammar. A position is one column at a time, and so is a bound.
39.4 A categorical column selects slots
at is where the selection starts. The column decides which reading you get, in the same way it decides whether color uses a ramp or a palette. Numbers are a range. Names are a set of slots:
data(gapminder_2007) + point + x(continent) + y(life) + color(continent) +
theme(width = 620) + brush(continent, at = c("Europe", "Oceania"))(data(gapminder_2007) + point + x(col.continent) + y(col.life) + color(col.continent) +
theme(width = 620) + brush(col.continent, at = ["Europe", "Oceania"]))data(gapminder_2007) + point + x(:continent) + y(:life) +
color(:continent) + theme(width = 620) +
brush(:continent, at = ["Europe", "Oceania"])plot(data(gapminder_2007), point, x(col.continent), y(col.life),
color(col.continent), theme({ width: 620 }),
brush(col.continent, { at: ["Europe", "Oceania"] }))“Given gapminder 2007: points, x is continent, y is life, color by continent, and let the reader select continent, starting with Europe and Oceania.”
One word, two readings, decided by the column rather than by a second atom. Drag across the slots and the selection follows them, whole slots at a time, because a category has no half.
The column is on the x axis here and that is not decoration. A drag can only reach a column the panel places. Write it over the scatter this chapter opened with, where continent is only a color. The sentence is still legal and still dims the right countries. But there is nowhere to drag, because no axis is measuring continents. The sentence has chosen the selection, and dragging cannot change it.
Which axis places it does not matter. Here is the same sentence with x and y exchanged, in a shorter panel:
data(gapminder_2007) + point + x(life) + y(continent) + color(continent) +
theme(width = 620, height = 320) + brush(continent, at = c("Europe", "Oceania"))(data(gapminder_2007) + point + x(col.life) + y(col.continent) + color(col.continent) +
theme(width = 620, height = 320) + brush(col.continent, at = ["Europe", "Oceania"]))data(gapminder_2007) + point + x(:life) + y(:continent) +
color(:continent) + theme(width = 620, height = 320) +
brush(:continent, at = ["Europe", "Oceania"])plot(data(gapminder_2007), point, x(col.life), y(col.continent),
color(col.continent), theme({ width: 620, height: 320 }),
brush(col.continent, { at: ["Europe", "Oceania"] }))The slots stack up the side now, and the same two continents keep their color. Drag on it and the band lies across the panel instead of standing in it, whole slots at a time as before. The bound never mentions an axis. It names a column, so turning the plot moves the drag and leaves the sentence alone.
39.5 Two views, one selection
This is what a brush is most useful for, and the sections above prepared for it. Selecting inside one plot shows you what the plot already showed. The question worth asking is where does this group sit in a different picture, and that needs a second picture:
(data(gapminder_2007) + point + x(gdp) + y(life) +
brush(gdp, at = c(20000, 60000)) + theme(height = 230)) /
(data(gapminder_2007) + point + x(gdp) + y(population, scale = "log") +
brush(gdp, at = c(20000, 60000)) + theme(height = 200))((data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
brush(col.gdp, at = [20000, 60000]) + theme(height = 230)) /
(data(gapminder_2007) + point + x(col.gdp) + y(col.population, scale = "log") +
brush(col.gdp, at = [20000, 60000]) + theme(height = 200)))(data(gapminder_2007) + point + x(:gdp) + y(:life) +
brush(:gdp, at = [20000, 60000]) + theme(height = 230)) /
(data(gapminder_2007) + point + x(:gdp) +
y(:population, scale = "log") + brush(:gdp, at = [20000, 60000]) +
theme(height = 200))below(plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
brush(col.gdp, { at: [20000, 60000] }), theme({ height: 230 })),
plot(data(gapminder_2007), point, x(col.gdp),
y(col.population, { scale: "log" }),
brush(col.gdp, { at: [20000, 60000] }), theme({ height: 200 })))“Given gapminder 2007: points, x is gdp, y is life, and let the reader select gdp, starting from 20000 to 60000, above points, x is gdp, y is population on a log scale, and let the reader select gdp, starting from 20000 to 60000.”
Two plots, one page, and one bound keeping the same countries in color in both. Drag in either and the other follows. The rich countries live long, which the top plot says; their populations run from under a million to over three hundred million, which only the bottom one says, and neither plot could have told you both.
Nothing was added to the grammar to link them. Look at what the two sentences share: the column gdp, named on x in each. A bound is a fact about a column’s values rather than about a panel, so two plots that read that column are already answering the same question. There is no name to declare, no identifier to match up, and no third atom joining them.
That is composition’s one rule again, in a new place. Two composed plots naming the same column on the same axis share that axis, which is why these two are the same width and the gdp numbers are written once. The selection is shared for the same reason.
39.6 One bound reaches every panel
Faceting is the other way to get more than one panel, and a brush treats it the same way. The bound is a fact about a column, and every panel reads that column, so every panel answers:
data(gapminder_2007) + point + x(gdp) + y(life) +
brush(gdp, at = c(20000, 60000)) | facet(continent)(data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
brush(col.gdp, at = [20000, 60000]) | facet(col.continent))data(gapminder_2007) + point + x(:gdp) + y(:life) +
brush(:gdp, at = [20000, 60000]) | facet(:continent)plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
brush(col.gdp, { at: [20000, 60000] }), across(col.continent))“Given gapminder 2007: points, x is gdp, y is life, and let the reader select gdp, starting from 20000 to 60000, split into panel columns by continent.”
Five panels, one bound, and the rich countries keeping their color. Europe has many and Africa has none, which is the comparison the split was made for. Again nothing was added: facet divides the rows and brush dims the rest, and neither atom knows about the other.
The panels differ in one way worth knowing. A bound is shared, because it names a column. Pointing is not. In the web edition, resting the pointer on a mark shows that row’s values. They come from the panel you are pointing at, never from a row another panel drew.
39.7 Which one is that?
The other thing people want from a selection is a name. Layer text over the points and the brush decides which labels are legible:
data(gapminder_2007) + point + x(gdp) + y(life) +
text + label(country) + style(size = 7) +
brush(gdp, at = c(30000, 60000)) + theme(width = 620)(data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
text + label(col.country) + style(size = 7) +
brush(col.gdp, at = [30000, 60000]) + theme(width = 620))data(gapminder_2007) + point + x(:gdp) + y(:life) + text +
label(:country) + style(size = 7) + brush(:gdp, at = [30000, 60000]) +
theme(width = 620)plot(data(gapminder_2007), point, x(col.gdp), y(col.life), text,
label(col.country), style({ size: 7 }),
brush(col.gdp, { at: [30000, 60000] }), theme({ width: 620 }))“Given gapminder 2007: points, x is gdp, y is life, and also text, label by country, and let the reader select gdp, starting from 30000 to 60000.”
A hundred and forty-two labels is unreadable, and that is what selection answers: the ones you did not select are dimmed with their points, and about twenty names keep their color. Drag the bound and a different twenty are readable.
This works because text is one of the marks a brush reaches, on the same test as point: one row is one label. No rule joins selection to labels. Each follows its own rule, and this plot is where the two meet.
39.8 What can be brushed
A selection picks out rows, so a mark can be brushed when one row is one shape: point, text, rule and zone.
A plain bar passes that test and still refuses: one row is one bar, but a bar’s thickness is measured from the gap between neighbors, so selected and unselected bars would draw at different widths. The engine refuses it, and the message says so. A jittered point refuses for the same kind of reason, because its offset is seeded from the row’s place in the table, and a repelled text layer is drawn whole instead, with a note that says why.
A line is the other case. It draws one shape through many rows, so a row is a corner of the line rather than a thing of its own. Selecting half of a line would mean cutting it in two, and cutting a line in two already has a word:
| country | continent | year | life | population | gdp |
|---|---|---|---|---|---|
| China | Asia | 1952 | 44.00000 | 556263527 | 400.4486 |
| China | Asia | 1957 | 50.54896 | 637408000 | 575.9870 |
| China | Asia | 1962 | 44.50136 | 665770000 | 487.6740 |
| China | Asia | 1967 | 58.38112 | 754550000 | 612.7057 |
| China | Asia | 1972 | 63.11888 | 862030000 | 676.9001 |
data(gapminder_asia) + line + x(year) + y(life) + group(country) +
brush(life, at = c(60, 80))(data(gapminder_asia) + line + x(col.year) + y(col.life) + group(col.country) +
brush(col.life, at = [60, 80]))data(gapminder_asia) + line + x(:year) + y(:life) + group(:country) +
brush(:life, at = [60, 80])plot(data(gapminder_asia), line, x(col.year), y(col.life),
group(col.country), brush(col.life, { at: [60, 80] }))Error:
! gog: a `line` draws one shape through many rows, so there is no single row to select. Use `group()` to split it, or brush a mark that draws one shape per row: `point`, `text`, `rule` or `zone`.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.
The refusal names two ways out. This sentence has already taken the first: group() splits the line, and each piece still runs through twelve years. So take the second, and brush a mark that draws one shape per row.
A summarized layer refuses for a different reason. A bar of bar * count stands for as many as fifty-two countries at once, so “twelve of these are selected” has no honest picture: dimming the whole bar would be wrong, and dimming part of it would invent a mark nobody asked for. gog says so instead of guessing:
data(gapminder_2007) + bar * count + x(continent) +
brush(gdp, at = c(20000, 60000))(data(gapminder_2007) + bar * count + x(col.continent) +
brush(col.gdp, at = [20000, 60000]))data(gapminder_2007) + bar * count + x(:continent) +
brush(:gdp, at = [20000, 60000])plot(data(gapminder_2007), layer(bar, count), x(col.continent),
brush(col.gdp, { at: [20000, 60000] }))Error:
! gog: `bar * count` cannot be brushed, because `count` summarizes many rows into one and the engine cannot say which of them you selected. Brush the layer that draws the rows themselves, or drop the brush.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.
When a layer that can answer is present, neither of these is a refusal. The plot draws, and gog reports which layer it left whole:
data(gapminder_2007) + point + x(gdp) + y(life) +
line * smooth +
brush(gdp, at = c(20000, 60000))(data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
line * smooth +
brush(col.gdp, at = [20000, 60000]))data(gapminder_2007) + point + x(:gdp) + y(:life) + line * smooth +
brush(:gdp, at = [20000, 60000])plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
layer(line, smooth), brush(col.gdp, { at: [20000, 60000] }))gog: the `line` layer is drawn whole, because it draws one shape through many rows and there is no single row to select. The selection still reads on the rest of the plot.
“Given gapminder 2007: points, x is gdp, y is life, and also a line derived by smooth, and let the reader select gdp, starting from 20000 to 60000.”
The points answer the selection and the trend line does not, so the line is drawn once, undimmed, through all 142 countries. That is the right answer: a trend fitted to the selection alone would be a different statistic, and the sentence did not ask for one.
A range that does not run upward selects nothing, so it is a mistake rather than an empty selection:
data(gapminder_2007) + point + x(gdp) + y(life) +
brush(gdp, at = c(60000, 20000))(data(gapminder_2007) + point + x(col.gdp) + y(col.life) +
brush(col.gdp, at = [60000, 20000]))data(gapminder_2007) + point + x(:gdp) + y(:life) +
brush(:gdp, at = [60000, 20000])plot(data(gapminder_2007), point, x(col.gdp), y(col.life),
brush(col.gdp, { at: [60000, 20000] }))Error:
! gog: `brush(gdp, at = c(60000, 20000))` selects nothing, because the range does not run upward. Write the smaller number first.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.
39.9 Selecting while the plot plays
A frame is a subset of the rows, and a bound is a test on a column’s values, so the two compose and neither needed anything added for the other. The bound is tested again inside every frame:
| country | continent | year | life | population | gdp |
|---|---|---|---|---|---|
| Afghanistan | Asia | 1952 | 28.801 | 8425333 | 779.4453 |
| Afghanistan | Asia | 1957 | 30.332 | 9240934 | 820.8530 |
| Afghanistan | Asia | 1962 | 31.997 | 10267083 | 853.1007 |
| Afghanistan | Asia | 1967 | 34.020 | 11537966 | 836.1971 |
| Afghanistan | Asia | 1972 | 36.088 | 13079460 | 739.9811 |
data(gm_all) + point + x(gdp, scale = "log") + y(life) + color(continent) +
theme(width = 620) + play(year) + brush(gdp, at = c(3000, 20000))(data(gm_all) + point + x(col.gdp, scale = "log") + y(col.life) + color(col.continent) +
theme(width = 620) + play(col.year) + brush(col.gdp, at = [3000, 20000]))data(gm_all) + point + x(:gdp, scale = "log") + y(:life) +
color(:continent) + theme(width = 620) + play(:year) +
brush(:gdp, at = [3000, 20000])plot(data(gm_all), point, x(col.gdp, { scale: "log" }), y(col.life),
color(col.continent), theme({ width: 620 }), play(col.year),
brush(col.gdp, { at: [3000, 20000] }))“Given all the gapminder years: points, x is gdp on a log scale, y is life, color by continent, played by year, and let the reader select gdp, starting from 3000 to 20000.”
Watch countries cross into the selection, frame by frame. The bound stays at 3,000 to 20,000 dollars while the countries move. In 1952 the selected group is that year’s middle-income countries. By 2007 many have grown past 20,000 and poorer ones have grown into the range. Nothing pauses, and no frame is skipped. The same test simply gets a different answer in each one. The bound stays still, and the countries move across it.
39.9.1 What the count includes
Stop the clock, draw a small box, and the count under the plot (the line reading 17 of 1704 selected) looks far too large. The number is right, and the reason is one sentence: a bound is a test on a column’s values, so it holds or fails for every row in the table. It does not stop at the frame you can see. The count and show rows (a button under the plot, listed below) report the whole selection, across every frame. The picture shows you one frame of it.
The plot above makes that concrete. gm_all is 1,704 rows, which is 142 countries in each of twelve years, and one frame draws 142 of them. Stop on 1982 and draw a box around four countries in the low corner, and the count reads far more than four. The same box tests every year’s rows, not only 1982’s, and in earlier years other countries sat in that corner too. The four you can see are 1982’s members of a set that runs through the whole sequence.
show rows is where you check it. The table lists the year of every row it found, beside the columns the sentence maps, so you can see which frame each row belongs to and pick out the four from the one you are looking at.
A faceted plot never raises this question. There every selected row is on the page at once, so a count of the whole selection is a count of what you see. A sequence puts eleven twelfths of it out of sight, in time rather than off the edge of the page. The rule is the same one; only the picture differs.
39.9.2 Choosing a bound the data crosses
The start of a sequence is where an animation misleads. Count what a bound selects in each frame before you write it down. From 3,000 to 20,000 dollars selects between 52 and 74 countries in every frame here. From 20,000 to 60,000 dollars selects none at all in 1952 and 1957, one in 1962, and four by 1972. The second is a true picture and it reads as a broken plot, because a reader cannot tell nothing is selected here from this is not working. Drag the bound upward and you will watch it happen.
One column cannot do both jobs. Brushing the column the frames are cut on would select frames rather than rows inside one, and that is a control for moving through time rather than a selection:
data(gm_all) + point + x(gdp) + y(life) + play(year) + brush(year, at = c(1980, 2007))data(gm_all) + point + x(col.gdp) + y(col.life) + play(col.year) + brush(col.year, at = [1980, 2007])data(gm_all) + point + x(:gdp) + y(:life) + play(:year) +
brush(:year, at = [1980, 2007])plot(data(gm_all), point, x(col.gdp), y(col.life), play(col.year),
brush(col.year, { at: [1980, 2007] }))Error:
! gog: `year` is already the column `play()` cuts the frames on, so `brush(year)` would select frames rather than rows inside one. That is a scrub bar, which belongs to the viewer and not to the sentence. Brush a column the frames are not cut on.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.
Moving the clock belongs to the page a plot is shown on, not to the sentence that describes the plot. That is what the buttons under a played plot do, and Play says why they have no word here.
39.10 All three at once
Play drew the cube of countries through the years, and nothing in it marks the middle-income countries. The third position, the frames and the selection are three separate ideas, and none of them was taught about the others. So they compose:
data(gm_all) + point + x(gdp, scale = "log") + y(life) + z(population) +
color(continent) + play(year) + brush(gdp, at = c(3000, 20000))(data(gm_all) + point + x(col.gdp, scale = "log") + y(col.life) + z(col.population) +
color(col.continent) + play(col.year) + brush(col.gdp, at = [3000, 20000]))data(gm_all) + point + x(:gdp, scale = "log") + y(:life) +
z(:population) + color(:continent) + play(:year) +
brush(:gdp, at = [3000, 20000])plot(data(gm_all), point, x(col.gdp, { scale: "log" }), y(col.life),
z(col.population), color(col.continent), play(col.year),
brush(col.gdp, { at: [3000, 20000] }))“Given all the gapminder years: points, x is gdp on a log scale, y is life, z is population, color by continent, played by year, and let the reader select gdp, starting from 3000 to 20000.”
A cube of 142 countries, twelve frames, and one bound tested inside every one of them. Drag the plot to turn it and the selection turns with the cloud, because the bound picks rows and the angle picks a viewpoint, and neither asks the other anything.
There is one difference here, and it is worth knowing rather than working out. In the cube the drag already turns the plot, so name the bound in the sentence: brush on its own would declare a region with no way to draw one. That is the same rule as everywhere else in this chapter, arriving from the other side. A drag means one thing at a time, and in the cube it means turn.
39.11 Moving the bound yourself
Every brushed plot in this chapter after the first states where its selection starts. On a page that can run the engine, you can drag the panel to move the bound, and the plot redraws under your hand.
This changes nothing about the sentence, and it is the same arrangement the cube uses. space(turn =, tilt =) chooses the angle a plot starts at and the pointer takes you anywhere else; brush(gdp, at = ) chooses the bound a plot starts with and the pointer does the same. Drag to find a selection, then write it into the sentence.
On paper, and in the PDF edition, each plot shows the bound its sentence asked for. That is why naming it is worth doing even though a reader can move it. The printed figure shows the selection you chose, and a reader who can drag starts from it.
Written with no at at all, brush selects nothing. The plot then draws exactly as it would with no brush in the sentence, which is the resting state a page shows before the first drag.
39.12 What the page adds
A brushed plot on a web page carries a line of controls under it. None of them are in the sentence, and that is the rule rather than an omission. They report a selection, or they change how you look at one. Not one of them changes what the plot claims about the data, so none of them needs a word in the grammar. It is the same reason a plot in the cube has a line of controls and space() has no word for the pointer.
They come in two lines, and the first is the one every plot carries:
| Control | What it does |
|---|---|
− + |
Makes the picture smaller or larger |
| the frame (the box that shows the whole plot) | Returns to the whole picture |
| the camera | Saves what you are looking at as a picture file |
It sits first, directly under the picture, on a plain plot and a brushed one alike. This matters. A reader who has found the magnifiers once finds them in the same place under every plot in this book, rather than somewhere that shifts with whatever else the plot needed.
A plot that also plays carries three more buttons at the end of that same line, which stop the clock and step it. Play sets them out.
The second line is what a brush adds:
| Control | What it does |
|---|---|
drag: and its icons |
Says what dragging the plot will do, and switches it: a rectangle, a free shape, or moving the picture |
17 of 142 selected |
How many rows the current bound selects. On a played plot this counts every frame, not the one on screen |
show rows |
Opens a table of those rows; while the table is open the button reads hide rows. A long selection arrives ten at a time, with ‹ and › under the table |
clear |
Puts the selection back to what the sentence asked for |
unstamp |
Takes the stamps off, and counts them once there are several. Absent until you have made one |
A control drawn as an icon names itself when the pointer rests on it. The ones with a word on them need no name.
39.12.1 Selecting
Drag across the panel. A dotted box follows the pointer, and it shows exactly what is bound. On a plot with one brush the box spans the whole panel in the other direction, because that direction was not selected. On a plot with two, it is a rectangle. A box that narrowed an axis nobody bound would be claiming a range you did not choose.
Dragging in either direction gives the same bound, so you can start from any corner. A click on empty space clears the selection. A click that lands on a mark does something else, and the section below is about that.
39.12.2 Drawing around a group
A rectangle is what a sentence can say. Some groups are not rectangles. A cloud of points often has a shape: a narrow tail to one side, a curve, a group sitting apart from the rest. A box drawn around such a group includes points you did not mean.
The second icon beside drag: is the free shape. Choose it, then draw around the group with the pointer held down. The outline closes itself when you let go, and everything inside it is selected. The count and the row table read exactly as they do for a box, because a shape and a bound ask the same question: which rows do you mean.
Nothing about the sentence changes. You do not type a shape, and the printed page still shows the bound the sentence named. Drawing one is a way of looking, like turning a cube, rather than a claim about the data.
That is also why the grammar has no word for it. Other tools call the gesture a lasso, and gog has no such word. A shape can only be written down as a long list of corners, and a specification is something you can write down and print. You can still draw the shape; you cannot write it.
Two restrictions are worth knowing. A free shape needs two axes that measure, so where one axis carries categories the drag stays a rectangle. A category has no half, and whole slots are what you wanted there anyway. And clear removes the shape instead of restoring it, because a shape has no resting form for a sentence to state.
39.12.3 Reading what you selected
The count is always there. show rows opens a table underneath, listing the columns the sentence maps rather than every column in the table, because the columns you did not plot are not what you are looking at.
A long selection arrives ten rows at a time. The line under the table says which rows you are reading, as 11–20 of 40, and the two arrows beside it move you through the rest. Every row you selected is reachable, and none of them pushes the plot off the screen. A selection short enough to fit shows no arrows at all.
The table names every row you selected, in one place, away from the picture. Draw a bound tight around one point and it names that point alone.
For a quick look without selecting anything, move the pointer over a mark and that row’s values appear beside it. Nothing is selected and nothing changes.
39.12.4 Stamping a point
The pointer names one row at a time and forgets it as soon as you move. That is right for a quick look and wrong for a comparison. Three points stand out on a scatter, and reading them one after another means remembering the first two while you look at the third.
Click a mark and its values stay. That is a stamp: a dot on the mark, a short line, and a small card saying what the pointer said. Click as many as you want to compare. The card sits on the picture beside the mark it belongs to, which is the difference between a stamp and the row table. One names rows, the other labels the plot.
A card needs space on the picture. On a crowded scatter it covers the very points you stamped it to read. So drag a card and it goes where you put it. The line stretches to follow, and a long line ends in an arrow head pointing at the row. Move four cards out to the edges and the picture underneath stays whole.
Where you put a card is where it stays. Zoom in, pan across, or drag a new bound: the card holds its place beside its point while the picture moves under it. Zoom far enough that the point leaves the panel and the whole stamp waits out of sight. It has nothing left to point at, and a card left over an unrelated corner would claim a point that is not there. Bring the point back and the card is where you left it.
A played plot works the same way, for the same reason. A row there is one country in one year, so a stamp made in 1972 names something the 1987 frame does not draw. It waits while the other frames run, and comes back on its point when the loop returns. The card names the year it holds. Stamp the same country in three frames and each card appears in its own.
There are three ways to take a stamp off. The × in the corner of a card removes that card. Clicking the card itself does the same, as long as you did not move it. If the pointer traveled, you moved the card. If it did not, the card comes off. unstamp removes every card at once.
clear leaves them alone, because a stamp is not a selection: clear a bound to read your stamped rows against the whole data and they are all still there. clear, unstamp and the frame each undo one thing, which the section below sets out.
The camera saves them. Arrange the cards, press the camera, and the picture file carries the plot with your annotations on it, where they sit and pointing where they point. That is the camera’s rule rather than a rule about stamps: it saves what you are looking at, the same way it saves how far you have zoomed in and the angle a cube is turned to.
You do not type a stamp, and the printed page carries none.
A stamp is for deciding which points are worth naming. A plot with a name on every point is unreadable, and a plot with a name on the few that matter is the one you wanted. Stamping lets you try a few before you commit to them. To put those names in the picture itself, where the page and the PDF will both carry them, write them down: that is text, and it is a layer like any other.
Arranging the cards by hand has a written form too. text * repel does the same job inside the sentence. Every label ends up outside its own dot, and one that moved far keeps a thin line back to the point it names. That is the stamp’s line again, written down rather than dragged. Stamp to decide what is worth naming, then write the labels down and let repel place them.
The stamp is for looking. text is for saying.
Both can go into a presentation, and they are not the same there. A saved picture is one session at one angle and cannot be redrawn. A sentence with text in it draws again for anyone who has the data, in the PDF and on the page and in all four languages. Stamp and save to keep this one picture. Write the labels down to keep the plot itself.
39.12.5 Where pointing cannot answer
The page computes where each row was drawn, from the row’s own value and the two ends of the axis the panel records. That is exact wherever a mark stands at its value, and some plots put a mark somewhere else on purpose.
jitter sets each point beside its value so that a crowded group can be read. dodge moves marks aside to clear their neighbors, and stack sets each on top of the one below. A summary such as bin or mean draws one shape for many rows, so there is no single row under the pointer to name. A polar plot bends both axes around a circle, and a map turns two columns into places on the page before it draws anything.
On any plot like those the pointer stays quiet rather than naming a row that is not there, and a line under the plot says which reason applied. Nothing is stamped either, for the same reason. The page computes a position rather than reading one, so it stays quiet where it cannot compute. That is why some plots name no row.
39.12.6 Looking closer
+ and − magnify the picture and the frame returns to the whole of it. Zooming in switches the drag to panning, because a reader who has just looked closer usually wants to move around inside it; the frame hands the drag back to selecting. You can switch by hand at any time with the button on the left, and the pointer tells you which mode you are in: a crosshair to draw a box, an open hand to move the picture.
This is a view, so it recomputes nothing. The bars are the same bars and the ticks are the same ticks, drawn larger. Zoom far enough into a histogram and you will see the same bins, not finer ones. If you want the statistics re-run over a narrower range, that is limits, the atom this chapter compared with brush.
39.12.7 Three words, three things
clear acts on the selection, unstamp acts on the stamps, and the frame acts on the view. Three controls that undo three different things, so each is named for what it acts on rather than all three being called reset. The frame sits a line above the other two, beside the zoom buttons. It puts back the view they changed.
The × on a card is a fourth undo, and it is not in this line. It belongs to the card rather than to the plot. A control under the picture acts on all of something. A control on a card acts on that card.
None of this exists on paper, and paper loses nothing by it. The PDF shows the bound the sentence named.
39.12.8 Your data on the page
The browser answers a brush, so the table has to be in the page. It is the whole table, including columns the sentence never maps. The table that show rows opens lists only the mapped columns, and the page carries every column.
This matters when a table has a column you would not publish. Bind the columns you plot and drop the rest, as you would check any file before sharing it. What the file carries states the rule for both kinds of plot, with the one line that applies it.