Столбчатые диаграммы сравнивают категории
Столбчатая диаграмма отвечает на вопрос «сколько каждого?» — по столбцу на категорию, где длина столбца показывает значение категории. В R базовая функция называется barplot(), и на вход ей идёт просто вектор высот. Дайте вектору имена — и имена станут подписями под столбцами:
visits <- c(Mon = 42, Tue = 51, Wed = 47, Thu = 60, Fri = 78)
barplot(visits,
main = "Store visits by day",
ylab = "Visits")
Пять серых столбцов, подписанных днями, поднимаются от скромного понедельника к пятничному пику почти вдвое выше. Ничего устанавливать, ничего настраивать: если вы умеете построить именованный вектор, вы умеете его нарисовать.
Запускаемые редакторы на этой странице показывают только текстовый вывод, поэтому вызовы barplot() здесь являются статичными сниппетами для вставки в локальную сессию R, — но шаг подсчёта перед ними выполняется прекрасно, и именно он важнее всего.
Настоящий рабочий процесс: сначала table(), потом barplot()
На практике у вас редко есть аккуратно подсчитанные высоты. У вас есть сырой столбец меток категорий — по строке на ответ анкеты, на заказ, на пользователя, — и подсчёт является настоящей работой. table() делает это одним вызовом, и её вывод — именованный вектор количеств, то есть ровно то, что нужно barplot():
А дальше график — ещё одна строка:
barplot(sort(t, decreasing = TRUE),
main = "Survey responses",
ylab = "Count")
Эти два шага — table(), затем barplot() — самый частый сценарий построения столбчатых диаграмм в R. Предварительная сортировка таблицы — дешёвое улучшение: столбцы, упорядоченные по высоте, читаются быстрее, чем упорядоченные по алфавиту, — если только у категорий нет естественного порядка (дни, месяцы, уровни дозы), и в этом случае фактор с правильно упорядоченными уровнями не даст table() расставить их по алфавиту. Для столбцов, требующих настоящей агрегации — сумм или средних по группам, а не количества строк, — сначала выполните шаг группировки и сводки и передайте результат в barplot().
Подписи и оформление
Подписи обычно берутся из имён вектора, но names.arg их переопределяет — полезно, когда коды из данных не годятся для аудитории:
barplot(visits,
names.arg = c("Monday", "Tuesday", "Wednesday",
"Thursday", "Friday"),
col = "steelblue",
border = NA,
main = "Store visits by day",
las = 2)
colзаливает столбцы; передайте вектор, чтобы раскрасить каждый по-своему, но не поддавайтесь радуге по умолчанию — цвет должен что-то означать, например выделять тот единственный столбец, о котором вы говорите.border = NAубирает контуры столбцов ради более чистого вида.las = 2поворачивает подписи оси перпендикулярно ей — решение для длинных названий категорий, налезающих друг на друга. Сочетайте это с бо́льшим нижним полем (par(mar = c(8, 4, 4, 2))), если названия действительно длинные.
Сгруппированные и накопленные столбцы из матрицы
Чтобы показать сразу два категориальных измерения — скажем, продажи по каналу и кварталу, — передайте barplot() матрицу. Каждый столбец матрицы становится одной позицией на оси категорий, а строки становятся подстолбцами:
sales <- matrix(c(12, 18, 15, 22, 20, 19, 24, 27),
nrow = 2,
dimnames = list(c("Online", "Retail"),
c("Q1", "Q2", "Q3", "Q4")))
# Grouped: rows stand next to each other within each quarter
barplot(sales, beside = TRUE,
col = c("steelblue", "orange"),
legend.text = rownames(sales),
main = "Sales by channel and quarter")
# Stacked: rows pile up into one total bar per quarter (the default)
barplot(sales, beside = FALSE,
col = c("steelblue", "orange"),
legend.text = rownames(sales))
beside = TRUE ставит два канала плечом к плечу внутри каждого квартала — лучший вариант, когда нужно сравнивать каналы напрямую. Накопленный вариант по умолчанию подчёркивает итог за квартал, показывая разбивку внутри каждого столбца; он честен для итогов, но затрудняет сравнение внутренних сегментов между столбцами, поскольку их основания смещаются. legend.text = rownames(sales) добавляет легенду, которая делает читаемым любой из вариантов.
Ещё один переключатель: horiz = TRUE укладывает столбцы вдоль горизонтальной оси. Это самая гуманная раскладка для множества категорий с длинными названиями — каждая подпись сидит на своей строке рядом со своим столбцом, поворачивать ничего не нужно.
Столбчатая диаграмма или гистограмма?
Их постоянно путают, и различие стоит тридцати секунд: столбчатая диаграмма сравнивает различные категории — ось это набор меток, столбцы разделены, и переупорядочивать их допустимо. Гистограмма разбивает на интервалы одну числовую переменную — ось непрерывна, столбцы соприкасаются, потому что интервалы последовательны, и переупорядочивать их было бы бессмыслицей. Если в вашем столбце слова («Yes», «Chrome», «Q3»), вам нужен barplot(table(x)). Если там измерения (рост, цены, время отклика), вам нужна гистограмма и hist(x).
ggplot2: geom_col против geom_bar
Версия на ggplot2 приходит в двух геомах, различающихся тем, выполнен ли подсчёт заранее:
library(ggplot2)
# geom_bar(): raw observations in, counting done for you
ggplot(survey, aes(x = response)) +
geom_bar(fill = "steelblue")
# geom_col(): heights already computed, one row per bar
totals <- data.frame(day = c("Mon", "Tue", "Wed", "Thu", "Fri"),
visits = c(42, 51, 47, 60, 78))
ggplot(totals, aes(x = day, y = visits)) +
geom_col(fill = "steelblue")
geom_bar() — это table(), встроенная в график: он берёт по строке на наблюдение и подсчитывает. geom_col() берёт предварительно агрегированные данные и отображает столбец y на высоту столбика — эквивалент классического barplot(). Передача уже подсчитанных данных в geom_bar() — стандартная ловушка новичка: он считает строки (по одной на каждую), и все столбцы выходят одинаковой высоты.
Что вы уносите с собой
barplot(heights)рисует именованный вектор, аtable(x)производит ровно такую форму из сырых категориальных данных, поэтомуbarplot(table(x))— ключевая идиома.- Сортируйте таблицу (или задавайте уровни фактора) перед построением; порядок столбцов — часть сообщения.
- Матрица даёт сгруппированные (
beside = TRUE) или накопленные (по умолчанию) столбцы; добавляйтеlegend.text = rownames(m). names.arg,col,las = 2иhoriz = TRUEотвечают за подписи; горизонтальные столбцы лучше всего подходят для длинных названий.- Категории → столбчатая диаграмма; числовые интервалы → гистограмма. В ggplot2: сырые строки →
geom_bar(), вычисленные высоты →geom_col().
Дальше: сам ggplot2 — грамматика, которая строит все эти графики и множество других из одних и тех же немногих составных частей.
Часто задаваемые вопросы
Как построить столбчатую диаграмму в R?
Вызовите barplot() на векторе высот. Дайте вектору имена — или постройте его через table(), чей вывод уже именованный, — и каждый элемент станет одним подписанным столбцом: barplot(table(df$category)).
Как сделать сгруппированную или накопленную столбчатую диаграмму в R?
Передайте матрицу. Каждый столбец матрицы становится одной позицией на оси категорий; beside = TRUE рисует строки как столбцы, стоящие рядом (сгруппированные), тогда как умолчание beside = FALSE их накапливает. Добавьте legend.text = rownames(m), чтобы читатели могли различать строки.
В чём разница между barplot() и hist() в R?
barplot() сравнивает различные категории — по столбцу на категорию, столбцы разделены. hist() разбивает одну числовую переменную на последовательные интервалы — столбцы соприкасаются, потому что ось непрерывна. Если ваша переменная состоит из слов, вам нужен barplot(table(x)); если из чисел — hist(x).
Что использовать в ggplot2: geom_bar или geom_col?
geom_bar() считает за вас: дайте ему сырые наблюдения — и он подсчитает каждую категорию. geom_col() рисует уже вычисленные значения: дайте ему по строке на столбец плюс столбец высоты. Передача предварительно подсчитанных данных в geom_bar() — классическая ошибка; там нужен geom_col().