Mar 27: ggplot2 pt.1
ggplot2 package
Компоненты графика
Все графики, которые можно создать с помощью пакета, могут быть разделены на несколько компонентов:
- данные
- пространство координат
- визуальные параметры (aesthetics)
- геометрическая форма представления данных (geom)
- статистические вычисления и трансформации (stats)
- параметры смещения графиков на координатной сетке (position adjustment)
- параметры осей (scales)
- фасеты (группировка, facets)
Ниже представлен типовой код создания графика с помощью пакета ggplot2
. На графике отражены все перечисленные структурные элементы: данные (объект mpg
), координатная сетка (coord_cartesian()
), параметры визуализаций (функция aes()
и её аргументы). Основная особенность синтаксиса ggplot2
— его аддитивность, когда объект графика создается путем постепенного добавления к базовому объекту новых элементов и/или параметров визуализаций. Базовый объект создается с помощью функции ggplot()
, а различные слои, геометрические объекты или текстовые метки, параметры визуализаций и т.д. - другими функциями, через внутренний оператор +
:
ggplot() +
geom_smooth(method = 'lm') +
geom_point(data = mpg, mapping = aes(x = hwy, y = cty, color = cyl)) +
coord_cartesian() +
scale_color_gradient() +
theme_classic()
Базовые геомы
geom_point()
Функция geom_point()
позволяет конструировать точечные диаграммы (графики рассеяния). Стандартные аргументы функций: data
(таблица, данные из которой надо отрисовать) и mapping
(с помощью этого аргумента указываются, какие колонки таблица как именно будут использованы при отрисовке — какие будут задавать оси, какие - цвета или форму).
# подключаем библиотеки
library(ggplot2)
library(data.table)
# импорт данных
imdb_link <- 'https://gitlab.com/upravitelev/mar201s/raw/master/data/IMDb movies.csv'
tg_cols <- c("director", "title", "original_title", "year",
"genre", "duration", "country", "avg_vote")
imdb <- fread(imdb_link, select = tg_cols)
imdb[, year := as.numeric(year)]
imdb_lynch <- imdb[director == 'Woody Allen']
imdb_martin <- imdb[director == 'Martin Scorsese']
imdb_lynch <- imdb[director == 'David Lynch']
imdb_genres <- imdb[genre %in% c('Horror', 'Comedy', 'Drama')]
imdb_genres_scores <- imdb_genres[,
list(n_titles = .N, votes = mean(avg_vote)),
by = list(year, genre)]
theme_set(theme_classic())
Рисуем точками фильмы, которые выпустил Дэвид Линч. Задаём базовый объект с помощью ggplot()
и на него наслаиваем геом geom_point()
. Получаем стандартный график, где черным цветом отрисованы точки, а названия осей взяты из названий колонок.
ggplot() +
geom_point(data = imdb_lynch,
mapping = aes(x = year, y = avg_vote))
0.0.0.2.1 geom_point() aesthetics
У geom_point()
есть множество опций, которые позволяют задать визуальные параметры (aesthetics) точки графика. Самые часто используемые:
- colour: цвет края точки (названием или rgb-кодом)
- fill: цвет заливки точки (названием или rgb-кодом)
- shape: форма точки, можно задать номером или по названию.
- size: размер точки
- alpha: прозрачность точки
0.0.0.2.2 Настройка визуальных параметров
Визуальные параметры можно задать двумя методами. Первый – когда форма, цвет или размер точки задаются не пользователем, а берутся из значений колонки в датасете. В таком случае визуальный параметр задается в аргументе mapping
.
Повторим предыдущий график (фильмы Линча), и в mapping
укажем, что цвет и форма точки задаются по значениям из колонки country
, а размер точки берется из значений в колонке duration
.
ggplot() +
geom_point(data = imdb_lynch,
mapping = aes(x = year, y = avg_vote,
color = country, shape = country, size = duration))
Второй метод настройки визуальных параметров — когда значение параметра задается прямо в коде, конкретным значением. И этот параметр будет применен ко всем точкам графика. В таком подходе параметры задаются не в аргументе mapping
, а как отдельные аргументы функции геома (geom_point()
).
На графике ниже все точки, маркирующие фильмы Дэвида Линча, покрашены в красный цвет и сделаны ромбами, независимо от страны или еще каких-то других особенностей фильма. А вот размер точки все так же зависит от значений в колонке duration
:
ggplot() +
geom_point(data = imdb_lynch,
mapping = aes(x = year, y = avg_vote),
color = 'red', shape = 'diamond', size = 4)
geom_line()
Практически идентичный geom_point()
по конструкции геом для отрисовки линий. В отличие от geom_point()
предполагается, что одному значению по x
соответствует одно значение по y
. Либо их может быть несколько, но тогда должна так же быть группирующая переменная, которая позволит различать, что несколько значений по y
для одного x
принадлежат разным линиям.
Покажем динамику оценок фильмов жанра Horror
:
ggplot() +
geom_line(data = imdb_genres_scores[genre == 'Horror'],
mapping = aes(x = year, y = votes))
Воспользуемся механизмом добавления слоев и добавим на график ещё и точки:
ggplot() +
geom_line(
data = imdb_genres_scores[genre == 'Horror'],
mapping = aes(x = year, y = votes)) +
geom_point(
data = imdb_genres_scores[genre == 'Horror'],
mapping = aes(x = year, y = votes))
0.0.0.2.3 geom_line() aesthetics
Основные визуальные параметры схожи с параметрами точек, тип линии задаётся параметром linetype
:
- colour: цвет линии (названием или rgb-кодом)
- linetype: тип линии
- size: толщина линии
- alpha: прозрачность линии
Пунктирные линии также можно задать кодом, код должен состоять из 2, 4, 6 или 8 символов шестнадцатеричной системы счисления, где цифры обозначают количество точек. Например, код 3519
означает ‘три отрисуй, 5 пропусти, 1 отрисуй, 9 пропусти, повторяй в цикле’. В результате получается вот такой пунктир:
ggplot() +
geom_line(data = imdb_genres_scores,
mapping = aes(x = year, y = votes,
group = genre, color = genre, linetype = genre))
0.0.0.2.4 Настройка визуальных параметров
Аналогично geom_point()
можно указать конкретные значения, так же можно указать, что значения должны браться из определенной колонки датасета. Возьмём датасет по жанрам, чтобы можно было в зависимости от жанра указать тип и цвет линии:
ggplot() +
geom_line(data = imdb_genres_scores,
mapping = aes(x = year, y = votes,
group = genre, color = genre, linetype = genre))
Если указать эти параметры не в mapping
, а задать конкретные значения, то изменены будут параметры всех линий, независимо от жанра:
ggplot() +
geom_line(data = imdb_genres_scores,
mapping = aes(x = year, y = votes,
group = genre, color = genre, linetype = genre),
size = 1.5)
геомы визуальных акцентов
geom_vline()
Простейший геом, который позволяет с помощью вертикальной линии акцентировать внимание пользователя на какой-то части кода (vline - vertical line). Точка на оси OX, из которой выводится линия, задается с помощью аргумента xintercept
. Этот геом не требует обязательного указания датасета и осей, так как не особо зависит от них - главное, чтобы ось OX была такого же типа, как задается xintercept
(число, строка, дата).
Укажем на графике границу 2000 года, чтобы понять, какие фильмы Линч снял после 2010 года.
ggplot() +
geom_point(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote,
color = country, shape = country, size = duration)) +
geom_vline(xintercept = 2010)
geom_hline()
Аналогично geom_vline()
позволяет нанести на график горизонтальную линию. Для этого надо указать yintercept
- значение на оси OY, из которого будет выводиться линия, параллельная OX. Графически отметим фильмы, которые имеют avg_vote
больше 0. У Дэвида Линча был один фильм (согласно датасету), у которого оценка была заметно больше 8, и тот был задолго до 2000 года:
ggplot() +
geom_point(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote,
color = country, shape = country, size = duration)) +
geom_vline(xintercept = 2010) +
geom_hline(yintercept = 8)
geom_text()
Еще один инструмент расстановки акцентов на график — нанесение текстовых меток значений. В самом простом виде geom_text()
аналогичен геомам точек и линий, с единственным отличием: метки задаются с помощью аргумента label
в mapping
. В качестве источника значений для меток указывают колонку датасета, в нашем случае это original_title
:
ggplot() +
geom_text(
data = imdb_lynch,
mapping = aes(x = year,
y = avg_vote,
label = original_title)
)
0.0.0.2.5 geom_text() aesthetics
Для текстовых меток на графике есть ряд дополнительных параметров, помимо размера или цвета. Это семейство шрифта (sans, serif, mono) и тип выделения (обычный, жирный, курсив). Так как текстовые метки обычно приводятся для каких-то других элементов графиков (точек или линий), еще есть аргументы hjust и vjust, для сдвига по вертикали или по горизонтали относительно целевой координаты.
- alpha: прозрачность
- angle: угол (если надо разместить метку под углом к точке)
- colour: цвет
- hjust: сдвиг по вертикали
- vjust: сдвиг по погризонтали
- lineheight: межстрочный интервал
- size: размер
- family: семейство шрифта (с засечками, без засечек)
- fontface: тип выделения
- check_overlap: если TRUE, то текстовые метки размещаются без того, чтобы перекрывать друг друга
Значения для family
и fontface
:
df_fontface <- data.frame(x = 1:4, fontface = c("plain", "bold", "italic", "bold.italic"))
df_family <- data.frame(x = 1:3, y = 3:1, family = c("sans", "serif", "mono"))
ggplot() +
geom_text(data = df_fontface,
mapping = aes(x = x, y = 0.1, label = fontface, fontface = fontface),
size = 10) +
geom_text(data = df_family,
mapping = aes(x = x, y = 0.2, label = family, family = family),
size = 10) +
lims(x = c(0.5, 4.5), y = c(0, 0.3)) +
theme_void()
Настройка визуальных параметров
Аналогично прочим геомам можно задать параметры как константу, можно использовать значения определенных колонок для управления цветом, размером и т. д. У geom_text()
так же есть ряд параметров, который не может быть связан со значениями колонок — это запрет на пересечение текстовых меток (check_overlap
) и смещение по вертикали/горизонтали (hjust
, vjust
). Сами по себе текстовые метки не очень интересны, поэтому также накладываем слой точек:
ggplot() +
geom_point(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote, size = duration),
color = 'steelblue') +
geom_text(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote, label = original_title),
check_overlap = TRUE,
hjust = -0.1
)
Композиция слоев
Если внимательно посмотреть на график, на котором были бы точками отмечены фильмы режиссера и текстовые метки названий, то видно много повторяющихся элементов — аргументы data
и частично mapping
в каждом геоме.
ggplot() +
geom_point(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote, size = duration),
color = 'steelblue') +
geom_text(
data = imdb_lynch,
mapping = aes(x = year, y = avg_vote, label = original_title),
check_overlap = TRUE,
hjust = -0.1
)
Можно сократить количество кода, воспользовавшись логикой наследования параметров геомов от основного ggplot()
. Таким образом датасет и параметры осей можно указать в ggplot()
и они будут применяться ко всем наслаиваемым геомам. А в геомах можно оставить только параметры этого конкретного геома.
ggplot(data = imdb_lynch, mapping = aes(x = year, y = avg_vote)) +
geom_point(mapping = aes(size = duration), color = 'steelblue') +
geom_text(mapping = aes(label = original_title), check_overlap = TRUE, hjust = -0.1)
Если сокращать ещё больше, то можно опустить указание аргументов и воспользоваться тем, что в ggplot()
первый аргумент задает датасет, второй — метод использования колонок (mapping
). В геомах наоборот, сначала указывается mapping
:
ggplot(imdb_martin, aes(x = year, y = avg_vote)) +
geom_point(aes(size = duration), color = 'steelblue') +
geom_text(aes(label = original_title), check_overlap = TRUE, hjust = -0.1)
Наследование параметров не отменяет того, что на график можно наложить данные другого датасета (если параметры осей совпадают), для этого надо так же, как и ранее, указать датасет в геоме. Наложим на точечный график фильмов Дэвида Линча фильмы Мартина Скорсезе и покрасим их красным:
ggplot(imdb_lynch, aes(x = year, y = avg_vote)) +
geom_point(aes(size = duration), color = 'steelblue') +
geom_text(aes(label = original_title), check_overlap = TRUE, hjust = -0.1) +
geom_point(
data = imdb_martin,
color = 'red'
)
Дополнительные материалы
Документация по пакету, есть примеры.
Шпаргалки - короткие и наглядные справочные материалы по основам синтаксиса и базовым геомам
R cookbook - сборник примеров и кейсов, как решать наиболее часто встречающиеся задачи при работе с ggplot. Сгруппировано по разделам.
Elegant Graphics for Data Analysis (Use R!) - книга автора ggplot2, с очень внятным описанием базовых идей. При желании, можно найти в сети.
Домашнее задание
Все задания выполняйте с учетом логики композиции слоев (не надо в каждом геоме писать датасет).
Задание 1
С помощью пакета ggplot2
отрисуйте график рассеяния, отражающий связь таких параметров, как carat
и price
. Используйте уже доступный после установки ggplot2
датасет diamonds
, сделайте выборку на 10000 строк (используйте set.seed(1234)
для генерации зерна генератора случайных цифр). Удалите строки, в которых carat > 3
. Сабсет назовите diamonds_sample
. Для конвертации diamonds
в data.table вам поможет as.data.table()
Задание 2
Повторите предыдущий график, добавьте выделение цветом бриллиантов разного качества (cut
).
Задание 3
Добавьте на график из задания 2 вертикальную линию (OX = 2) и горизонтальную линию (OY = 15000).
Задание 4
Выделите цветами из образованных вертикальной и горизонтальной линиями секторов первый и третий секторы (счет против часовой). Используйте зеленый и красный цвета соответственно, с параметром прозрачности opacity = 0.1. Сами линии можно не рисовать. Вам потребуется выбрать необходимый геом для решения этой задачи.