35  One variable

You have one column in front of you. What can it tell you? The questions it can answer, and the sentence for each.

35.1 How many of each?

A text column’s first question. Counting rows is a derivation, not a different kind of chart, so it is bar with * count:

data(gapminder_2007) + bar * count + x(continent)
data(gapminder_2007) + bar * count + x(col.continent)
data(gapminder_2007) + bar * count + x(:continent)
plot(data(gapminder_2007), layer(bar, count), x(col.continent))
Asia Europe Africa Americas Oceania 0 20 40 Count Continent

“Bars derived by count: x is continent.” No y() is bound because the count is invented, and the axis labels itself.

One atom away. Long category names? Put the categories on y and the bars lie down, same sentence, positions swapped:

data(gapminder_2007) + bar * count + y(continent)
data(gapminder_2007) + bar * count + y(col.continent)
data(gapminder_2007) + bar * count + y(:continent)
plot(data(gapminder_2007), layer(bar, count), y(col.continent))
0 20 40 Oceania Americas Africa Europe Asia Continent Count

The count still measures along the invented axis, which is now x. Owning chapters: Bar, Transforms.

35.2 What share of the whole is each?

Swap count for proportion and the tallies become fractions that sum to one:

data(iris_flowers) + bar * proportion + x(species)
data(iris_flowers) + bar * proportion + x(col.species)
data(iris_flowers) + bar * proportion + x(:species)
plot(data(iris_flowers), layer(bar, proportion), x(col.species))
setosa versicolor virginica 0.0 0.1 0.2 0.3 Proportion Species

One atom away. Back to raw tallies: * count. Sorted by size: add order().

35.3 How is a measurement distributed?

The continuous column’s first question. bin cuts the axis into intervals and counts rows into each; bar draws the counts touching, because the intervals are adjacent:

data(iris_flowers) + bar * bin + x(petal_length)
data(iris_flowers) + bar * bin + x(col.petal_length)
data(iris_flowers) + bar * bin + x(:petal_length)
plot(data(iris_flowers), layer(bar, bin), x(col.petal_length))
2 4 6 0 10 20 30 40 Count Petal Length

One atom away. bin takes a count or a width when the default guesses wrong. bin(30) for thirty bins, or intervals in the data’s own units:

data(iris_flowers) + bar * bin(width = 0.5) + x(petal_length)
data(iris_flowers) + bar * bin(width = 0.5) + x(col.petal_length)
data(iris_flowers) + bar * bin(width = 0.5) + x(:petal_length)
plot(data(iris_flowers), layer(bar, bin({ width: 0.5 })),
  x(col.petal_length))
2 4 6 0 10 20 Count Petal Length

A line * bin draws the same counts as a frequency polygon. Owning chapters: Bar, Transforms.

35.4 What is its smooth shape?

The binned view depends on where the bin edges fall; the density estimate smooths that decision away:

data(gapminder_2007) + line * density + x(life)
data(gapminder_2007) + line * density + x(col.life)
data(gapminder_2007) + line * density + x(:life)
plot(data(gapminder_2007), layer(line, density), x(col.life))
40 60 80 0.00 0.01 0.02 0.03 0.04 Density Life

“A line derived by density: x is life.” Same question as the histogram, one derivation over. Use both when the bumps matter. One atom tunes the smoothing: density(0.5) sharpens the bumps, density(2) irons them out, and density(bandwidth = 1) fixes the kernel width in years.

35.5 Where does the distribution step?

The third rendering of bin: an unfilled staircase silhouette, tracing bin tops without any fill. It is most useful when several distributions share an axis, see Many groups, but reads cleanly alone too:

data(gapminder_2007) + step * bin + x(life)
data(gapminder_2007) + step * bin + x(col.life)
data(gapminder_2007) + step * bin + x(:life)
plot(data(gapminder_2007), layer(step, bin), x(col.life))
50 60 70 80 0 10 20 30 Count Life

Three marks (bar, line, step), one bin. The transform never changed; only the geometry drawing its output did. That is the No Exceptions law doing its quiet work.

35.6 And when there are only thirty rows?

Every answer above summarizes: bin needs a bin width, density needs a bandwidth, and both choices show more when there are fewer rows to average over. With thirty numbers you can skip the choice and draw all thirty. Add stack and a point piles one dot per observation:

data(gm_europe) + point * bin * stack + x(life) +
  x_label("Life expectancy (years)") + title("Thirty countries, thirty dots")
(data(gm_europe) + point * bin * stack + x(col.life) +
  x_label("Life expectancy (years)") + title("Thirty countries, thirty dots"))
data(gm_europe) + point * bin * stack + x(:life) +
  x_label("Life expectancy (years)") +
  title("Thirty countries, thirty dots")
plot(data(gm_europe), layer(point, bin, stack), x(col.life),
  x_label("Life expectancy (years)"),
  title("Thirty countries, thirty dots"))
74 76 78 80 2 4 6 8 Thirty countries, thirty dots Count Life expectancy (years)

“Points derived by bin and stack: x is life.” The pile’s height is a count, so the tallest column can be read off the axis or simply counted, and no observation has been averaged into anything. Compare the same thirty as bars, where a single bin edge moving would redraw the shape:

data(gm_europe) + bar * bin + x(life) +
  x_label("Life expectancy (years)") + title("The same thirty, summarized")
(data(gm_europe) + bar * bin + x(col.life) +
  x_label("Life expectancy (years)") + title("The same thirty, summarized"))
data(gm_europe) + bar * bin + x(:life) +
  x_label("Life expectancy (years)") +
  title("The same thirty, summarized")
plot(data(gm_europe), layer(bar, bin), x(col.life),
  x_label("Life expectancy (years)"),
  title("The same thirty, summarized"))
74 76 78 80 0 2 4 6 8 The same thirty, summarized Count Life expectancy (years)

One atom away. A categorical column instead: point * count * stack piles one dot per row in each category. Owning chapter: Transforms.

35.7 What this section refuses

A distribution question needs a continuous column. Ask density about a category and the refusal names the type the estimate needs. The categorical version of this question is the share recipe above:

data(gapminder_2007) + line * density + x(continent)
Error:
! gog: `density` estimates a continuous distribution, and `x(continent)` is categorical — there is no number line for the curve to spread along. For the share of rows in each category, that is `bar * proportion`.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.