April 24: ggplot2 pt2

Запись занятий


Все записи организованы в плейлист


пакеты и данные

# imdb_link <- 'https://gitlab.com/upravitelev/r_course/raw/master/data/IMDb%20movies.csv'
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_woody <- 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())

Статистические геомы

geom_bar()

Геом используется для отрисовки столбиковых диаграмм (барчартов). При использовании геома по оси ОХ указывают переменную категорий (даты, строковые значения и проч). У геома есть, среди прочих, есть важный параметр stat.

Когда stat = 'count' (это значение по умолчанию), то ось OY указывать не надо. Так как при отрисовке графика происходит вычисление количества наблюдений (строк) на каждое значение по оси OX и именно по этому вычисленному значению отрисовываются столбики (предупреждение Removed 108 rows containing non-finite values (stat_count). означает, что есть пропуски в колонке title_year)

ggplot(imdb[genre == 'Horror'], aes(x = year)) +
  geom_bar(stat = 'count')

Когда stat = 'identity' (это значение надо пропиcывать), то необходимо указать и по значениям какой колонки строится ось OY. Этот вариант предпочтительнее в работе — лучше сначала явно создать отдельный объект, а потом его отрисовать, чем делать неявные вычисления при отрисовке графика. Здесь у нас не таблица с сырыми данными по фильмам, а агрегат по жанрам, который мы подготовили ранее (imdb_genres_scores).

# указываем год как x, а количество строк как y
ggplot(imdb_genres_scores[genre == 'Horror'], aes(x = year, y = n_titles)) +
  geom_bar(stat = 'identity')


0.0.0.3 geom_bar() aesthetics

Основные параметры:

  • colour: цвет края столбика (названием или rgb-кодом)
  • fill: цвет заливки столбика (названием или rgb-кодом)
  • alpha: прозрачность заливки столбика
  • position: если групп несколько, то как должны быть организованы столбики по группам - “стопкой” или “рядом”


0.0.0.4 Настройка визуальных параметров

Как и во всех геомах можно использовать колонки датасета для того, чтобы задать цвет контура или заливки столбика. Обычно делается только в том случае, когда есть разные группы в датасете и их надо выделить цветом. Во всех остальных случаях цвета контура и заливки, как правило, задаются фиксированными значениями:

ggplot(imdb_genres_scores[genre == 'Horror'], aes(x = year, y = n_titles)) +
  geom_bar(stat = 'identity',
           color = 'darkblue',
           fill = 'steelblue',
           alpha = 0.1)

Группировка может быть двух видов — “стопкой”, когда в столбике на одном значении OX выделены цветом группы. Это значение по умолчанию и задается с помощью параметра position = 'stack'. Отрисуем, сколько фильмов разных жанров снимали каждый год. Цвета заливки и контура столбика задаем по значениям колонки genre (каждая страна выделяется одним цветом):

ggplot(imdb_genres_scores, aes(x = year, y = n_titles)) +
  geom_bar(
    mapping = aes(color = genre, fill = genre),
    stat = 'identity',
    position = 'stack'
  )

Тот же самый график, но с группировкой “рядом”:

ggplot(imdb_genres_scores, aes(x = year, y = n_titles)) +
  geom_bar(
    mapping = aes(color = genre, fill = genre),
    stat = 'identity',
    position = 'dodge'
  )


geom_histogram()

Гистограммы во многом похожи на барчарты c stat = 'count', с единственным отличием. Барчарты строятся на дискретных значения оси OX (имя режиссера, дата и проч). А гистограммы строятся на интервальной шкале, то есть, позволяют самим выбирать, сколько значений по оси OX будет в одном столбике. Это задается параметром binwidth:

Построим гистограмму по количеству фильмов с шагом пять лет:

ggplot(imdb, aes(x = year)) +
  geom_histogram(binwidth = 5)

Построим гистограмму по количеству фильмов с шагом в 1 год, это должно быть идентично geom_bar():

ggplot(imdb, aes(x = year)) +
  geom_histogram(binwidth = 1)


geom_boxplot()

Геом для отрисовки боксплотов, по конструкции похож на geom_bar(). Отрисуем боксплоты распределений оценок фильмов трех разных жанров:

ggplot(imdb_genres_scores, aes(x = genre, y = votes)) +
  geom_boxplot()

Укажем, чтобы цвет заливки и контура боксплота были свои для каждого режиссера. Так как заливка в чистом виде непрозрачная, необходимо отдельно указать параметр alpha, который задаст степень прозрачности заливки:

ggplot(imdb_genres_scores, aes(x = genre, y = votes)) +
  geom_boxplot(aes(colour = genre,
                   fill = genre),
               alpha = 0.1)


geom_smooth()

Геом задает линии тренда. Как правило, линии задаются формулой y ~ x, где значения по y — зависимая, а x — независимая, предиктор. Методов построения линии может быть несколько, не только lm и loess (линейная регрессия и локальная полиномиальная регрессия соответственно), подробнее в справке по геому в аргументе method.

Построим по облаку точек фильмов из жанра Drama тренд imdb-оценок. Нарисуем сначала собственно облако точек, а потом зададим линию тренда с помощью loess и линейной регрессии.

ggplot(imdb_genres_scores[genre == 'Drama'], aes(x = year, y = votes)) +
  geom_point() + 
  geom_smooth(method = 'glm') + 
  geom_smooth(method = 'loess')


0.0.0.5 geom_smooth() aesthetics

Визуальные параметры геома в первую очередь включают в себя параметры линии, а также параметры доверительного интервала:

  • colour: цвет линии
  • fill: цвет заливки области доверительного интервала
  • alpha: прозрачность заливки области доверительного интервала
  • se: если se = FALSE, то доверительный интервал скрывается
ggplot(imdb_genres_scores[genre == 'Drama'], aes(x = year, y = votes)) +
  geom_point() + 
  geom_smooth(method = 'glm', color = 'blue', se = FALSE, size = 1.5) + 
  geom_smooth(method = 'loess', color = 'red', fill = 'red', alpha = 0.1)


Кастомизация графиков

Параметры осей

Оси относятся к одному из тех компонентов графиков, которые едины для всех заданных слоев. Как правило, при создании графиков в параметрах осей задают названия осей, метки, градиенты цветов (если цвет в слое указан как зависящий от какой-то третьей переменной, в aes()), трансформации осей (логарифмические, квадратным корнем, инверсией) и прочее.

0.0.0.6 scale_(x|y)_* {-}

Три группы функций, которые задают параметры осей OX или OY. Функции зависят от типа данных по оси:

  • scale_(x|y)_continuous: когда данные оси интервальные
  • scale_(x|y)_discrete: когда данные оси дискретные
  • scale_(x|y)_date: даты

Аргументы (и параметры) осей, которые можно задать:

  • breaks: шаги деления оси
  • labels: подписи для шагов
  • name: название оси (аналогично слою labs())
  • limits: границы оси (аналогично слою lims())
  • trans: когда нужно трансформировать значения по оси. Варианты трансформаций: “asn”, “atanh”, “boxcox”, “exp”, “identity”, “log”, “log10”, “log1p”, “log2”, “logit”, “probability”, “probit”, “reciprocal”, “reverse”, “sqrt”.
ggplot(imdb_woody, aes(x = year, y = avg_vote)) +
  geom_point() + 
  scale_x_continuous(breaks = c(1970, 2000, 2010)) + 
  scale_y_continuous(breaks = c(0, 7, 7.25, 7.5, 7.75, 8, 10))

В том случае, если в слое задано изменение цвета элементов графика в зависимости от вариативности какой-то переменной в датасете (это указывается в аргументах функции aes(), которая задает значения аргумента mapping функции геома), то по умолчанию используются оттенки синего, в диапазоне от черного к белому. Есть необходимость изменить цвета шкалы, то следует воспользоваться одной из соответствующих функций семейства scale_*: scale_(colour|fill)_gradient(), scale_(colour|fill)_brewer() и проч. С помощью разных функций можно либо задать свою палитру, либо выбрать из уже сконструированных (BrBG, Accent т.д.), в том числе указать цвет средней точки градиента.

Основные термины функций:

  • colour|fill: colour применяется для графиков рассеяния, линий и прочих простых геометрических объектов. Функции с fill в названии применяются для барчартов и прочих объектов, для которых может быть вычислена площадь
  • gradient: функции с gradient (scale_colour_gradient(), scale_fill_gradient2()) применяются для интервальных значений
  • brewer: brewer-функции применяются для дискретных значений, в ggplot2 есть целый ряд уже созданных палитр, как дискретизированных градиентов (Blues, Greens), так и контрастных (BrBG, Set1)
  • distiller: промежуточный вариант между brewer и gradient, который на основе данных интерполирует заданную дискретную палитру к интервальному виду.

scale_color_gradient()

ggplot(imdb_woody, aes(x = year, y = avg_vote)) +
  geom_point(aes(color = avg_vote), shape = 'circle', size = 4) + 
  scale_color_gradient(low = 'steelblue4', high = 'steelblue1')

scale_color_distiller()

ggplot(imdb_woody, aes(x = year, y = avg_vote)) +
  geom_point(aes(color = avg_vote), shape = 'circle', size = 4) + 
  scale_color_distiller(palette = 'Set1')

scale_color_brewer()

ggplot(imdb_woody, aes(x = year, y = avg_vote)) +
  geom_point(aes(color = genre), shape = 'circle', size = 4) + 
  scale_color_brewer(palette = 'Set1')

lims()

Слой, который задается функцией lims() и позволяет явно ограничить график по осям. Для того, чтобы задать границы оси, надо в соответствующий аргумент передать вектор из двух значений, которые будут интерпретированы как максимальное и минимальное значения оси.

ggplot(imdb_lynch, aes(x = year, y = avg_vote)) +
  geom_point() + 
  lims(x = c(2000, 2010))

labs()

Помимо границ оси можно задать и названия осей, также как и название графика. Функция labs() (от labels) имеет несколько аргументов, которые и отвечают за тексты на соответствующих элементах графика. Так, title задает заголовок всего графика, аргументы x и y — названия осей. Прочие аргументы могут соответствовать параметрам геомов. Например, мы задаем цвет и размер точек в геоме geom_point(). Соответственно, названия легенд для этих параметров могут быть заданы в labs() в аргументах color и shape:

ggplot(imdb_lynch, aes(x = year, y = avg_vote)) +
  geom_point(aes(colour = avg_vote, shape = country), size = 3) + 
  scale_color_gradient(low = 'steelblue4', high = 'steelblue1') +
  labs(title = 'Рейтинги фильмов Дэвида Линча',
       x = '',
       y = 'avg_vote',
       colour = 'imdb score',
       shape = 'country')

Координатная плоскость

Любой график немыслим без какой-то определенной системы координат. Стандартно и по умолчанию в ggplot2 используется декартова система координат. Тем не менее, доступна также и полярная система координат. Декартова система координат используется по умолчанию, однако её можно и явно задать:

ggplot(imdb_genres, aes(x = genre, y = avg_vote)) +
  geom_boxplot(aes(color = genre)) + 
  coord_cartesian()

Несмотря на то, что, на первый взгляд, оси ОХ и ОY идентичны и взаимозаменяемы, это не так. Для достаточно большого количества типов графиков важна ориентация. Например, столбиковые диаграммы (барчарты) и боксплоты ориентированы вертикально и просто сменой осей переориентировать их горизонтально не получится. Для таких целей как раз используют отдельную функцию поворота координатной плоскости, coord_flip():

ggplot(imdb_genres, aes(x = genre, y = avg_vote)) +
  geom_boxplot(aes(color = genre)) + 
  coord_flip()

Фасеты

Комбинация на одном графике данных по двум или нескольким градациям группирующей переменной позволяет сравнить несколько значений. Однако бывают ситуации, когда необходимо каким-то образом разделить и отдельно визуализировать данные по этим градациям: например, сравнить пробы по отдельным испытуемым или показать графики значений и линии тренда в разные годы и тому подобное. Простое совмещение на одном графике всех данных может привести к потере читабельности, когда данных много и используются сложные комбинации слоев. Чтобы все нарисовать на одном графике, но раздельно, в своих блоках, используется функция facet_grid() или facet_wrap(). Функция facet_wrap() аналогична facet_grid(), только организует панели подграфиков в виде плитки, а facet_grid() — либо вертикально, либо горизонтально, либо плиткой (в случае, когда по оси OX задана одна группировка, а по оси OY — вторая).

Основные аргументы функций фасет:

  • facets — выражение вида x ~ y, когда x ~ . задает расположение панелей фасет горизонтально, по факторам переменной x, формула вида . ~ yзадает вертикальное положение фасет. Формула x ~ y используется в том случае, если данные группируются и отрисовываются по комбинациям значений факторов переменных и x, и y - в таком случае в результате получится график, с сеткой панелей-фасет субграфиков;
  • margins — используется в тех случаях, когда надо дополнительно отрисовать панель с общим графиком по всем значениям группирующей переменной (т. е., без группировки), в качестве значения принимает название группирующей переменной;
  • scales — для ситуаций, когда необходимо закрепить (fixed) или, наоборот, задать собственный (free) масштаб шкалы для каждой панели.

Визуальные параметры всего графика

После того как основные содержательные и структурные элемента графика заданы, можно перейти к доводке визуального оформления. Совокупность визуальных параметров названий, линий, текстов и прочих элементов графиков, не относящихся собственно к данным, называется темой, theme. В ggplot2 есть ряд уже скомплектованных тем и одна из них, оттенки серого, используется по умолчанию.

Список готовых тем пакета ggplot2:

  • theme_grey()
  • theme_gray()
  • theme_bw()
  • theme_linedraw()
  • theme_light()
  • theme_dark()
  • theme_minimal()
  • theme_classic()
  • theme_void()

theme()

Помимо использования уже готовых тем как из ggplot2, так и из пакетов расширений (например, ggthemes), можно самостоятельно менять оформление тех или иных элементов. Делается это с помощью функции theme(), которая вызывается после применения к объекту графика уже существующей темы.

Функция theme() имеет огромное количество аргументов, все их названия построены по схеме родитель.ребенок, например, аргумент plot.background, который определяет параметры бэкграунда графика. Значения аргументов функции theme() задаются одной из четырех нижеследующих функций, в зависимости от формы объекта графика, которому надо придать какое-то оформление:

  • element_blank() используется в том случае, если объект не надо отрисовывать, например, надо убрать метки с оси;
  • element_rect() задает параметры для границ и бэкграунда, как правило, цвет;
  • element_line() задает параметры объектов-линий на графике (например, линия оси);
  • element_text() задает параметры объектов-текстов (например, тип или размер подписей к меткам оси);
  • unit() задает параметры для тех элементов, которым передаются какие-то размеры - размеры меток осей, расстояний между фасетами и проч. Можно задать различные измерения для этого параметра: дюймы, сантиметры и т.д. Так же можно указать относительные размеры, в долях от размера всего графика (npc = Normalised Parent Coordinates, где точка (.5, .5) обозначает центр графика).

Примеры аргументов и соответствующих элементов графика:

plot.*

  • plot.background: бэкграунд всего графика (element_rect)
  • plot.title: название графика (element_text)
  • plot.subtitle: подзаголовок графика (text appearance) (element_text)
  • plot.caption: примечение под графиком (text appearance) (element_text)
  • plot.margin: отступы вокруг графика

legend.*

  • legend.background: фон легенды (element_rect)
  • legend.text: текст легенды (element_text)
  • legend.title: заголовок легенды (element_text)
  • legend.position: расположение легенды (“none”, “left”, “right”, “bottom”, “top”, or two-element numeric vector)

strip.*

  • strip.background: фон фасет (element_rect)
  • strip.text: текст фасет (element_text)

Пример кастомизации темы графика:

ggplot(imdb_genres[country %in% c('USA', 'France', 'Italy', 'India', 'UK')], 
       aes(x = genre, y = avg_vote)) +
  geom_boxplot(aes(color = genre)) + 
  scale_x_discrete(labels = NULL, breaks = NULL) +
  facet_grid(. ~ country)+ 
  labs(title = 'Пример theme()',
       caption = 'на основе theme_minimal()',
       x = NULL,
       y = 'imdb score') +
  theme_minimal() + 
  # theme(legend.background = element_rect(color = 'grey80', fill = 'grey95'),
  theme(legend.background = element_blank(),        
        legend.position = 'top',
        legend.title = element_blank(),
        plot.title = element_text(face = 'bold', size = 18),        
        plot.caption = element_text(colour = 'grey50', face = 'italic'),
        panel.grid.major = element_line(colour = 'grey95'),
        panel.grid.minor = element_line(colour = 'grey97'),
        axis.title = element_text(face = 'italic'))