39  Интерактивные графики

Все чаще требуется, чтобы визуализация данных была доступна аудитории. В связи с этим все чаще создаются интерактивные графики. Существует несколько способов их создания, но наиболее распространены два: plotly и shiny.

На этой странице мы рассмотрим преобразование существующего графика ggplot() в интерактивный с помощью plotly. Более подробно о shiny можно прочитать на странице Информационные панели с Shiny. Стоит отметить, что интерактивные графики можно использовать только в HTML-документах формата R markdown, а не в PDF или Word.

Ниже приведена базовая эпидкривая, преобразованная в интерактивную с помощью интеграции ggplot2 и plotly (наведите курсор мыши на график, увеличьте масштаб или щелкните элементы в легенде).

39.1 Подготовка

Загрузка пакетов

В этом фрагменте кода показана загрузка пакетов, необходимых для проведения анализа. В данном руководстве мы делаем акцент на функции p_load() из pacman, которая при необходимости устанавливает пакет и загружает его для использования. Установленные пакеты можно также загрузить с помощью library() из базового R. Более подробную информацию о пакетах R см. на странице [Основы R].

pacman::p_load(
  rio,       # импорт/экспорт
  here,      # пути к файлам
  lubridate, # работа с датами
  plotly,    # интерактивные графики
  scales,    # быстрые проценты
  tidyverse  # управление данными и их визуализация
  ) 

Начните с ggplot()

На этой странице мы предполагаем, что вы начинаете с графика ggplot(), который вы хотите преобразовать в интерактивный. На этой странице мы построим несколько таких графиков, используя случай построчного списка, используемый на многих страницах данного руководства.

Импорт данных

Для начала мы импортируем построчный список случаев из смоделированной эпидемии лихорадки Эбола. Если вы хотите выполнять действия параллельно, нажмите кнопку, чтобы загрузить “чистый” построчный список (в виде файла .rds). Импортируйте данные с помощью функции import() из пакета rio (она работает со многими типами файлов, такими как .xlsx, .csv, .rds - подробности см. на странице [Импорт и экспорт]).

# импорт построчного списка  
linelist <- import("linelist_cleaned.rds")

Ниже отображаются первые 50 строк построчного списка.

39.2 построение графика с ggplotly()

Функция ggplotly() из пакета plotly позволяет легко преобразовать ggplot() в интерактивный формат. Просто сохраните свой ggplot(), а затем передайте его функции ggplotly().

Ниже мы построим простую линию, отражающую долю смертей в течение недели:

Начнем с создания сводного набора данных по каждой эпидемиологической неделе и проценту известных случаев смерти.

weekly_deaths <- linelist %>%
  group_by(epiweek = floor_date(date_onset, "week")) %>%  # создание и группировка данных по столбцу эпинедели
  summarise(                                              # создание новый сводный датафрейм:
    n_known_outcome = sum(!is.na(outcome), na.rm=T),      # количество случаев в группе с известным исходом
    n_death  = sum(outcome == "Death", na.rm=T),          # количество случаев смерти в каждой группе
    pct_death = 100*(n_death / n_known_outcome)           # процент случаев с известным исходом, умерших
  )

Здесь представлены первые 50 строк набора данных weekly_deaths.

Затем строим график с помощью ggplot2, используя geom_line().

deaths_plot <- ggplot(data = weekly_deaths)+            # начать с данных о смертности за неделю
  geom_line(mapping = aes(x = epiweek, y = pct_death))  # построить линию 

deaths_plot   # печать

Мы можем сделать этот график интерактивным, просто передав его в ggplotly(), как показано ниже. При наведении курсора мыши на линию отображаются значения x и y. График можно увеличить и перетащить. Кроме того, в правом верхнем углу графика можно увидеть значки. По порядку они позволяют:

  • Загрузить текущий вид в виде изображения PNG.
  • Увеличить масштаб с помощью окна выбора
  • ” Панорамировать” или перемещаться по графику, щелкая и перетаскивая его.
  • Увеличить, уменьшить масштаб или вернуться к масштабу по умолчанию
  • Сбросить оси к значениям по умолчанию
  • Включить/выключить “линии всплесков”, которые представляют собой пунктирные линии от интерактивной точки, распространяющиеся на оси x и y.
  • Настроить отображение данных при отсутствии наведения курсора на линию
deaths_plot %>% plotly::ggplotly()

Сгруппированные данные можно использовать и с помощью ggplotly(). Ниже построена недельная эпидкривая, сгруппированная по исходам. Сложенные столбики являются интерактивными. Попробуйте щелкнуть на различных элементах в легенде (они будут появляться/исчезать).

# Построить эпидемическую кривую с пакетом incidence2
p <- incidence2::incidence(
  linelist,
  date_index = date_onset,
  interval = "weeks",
  groups = outcome) %>% plot(fill = outcome)
# Построить интерактивные графики  
p %>% plotly::ggplotly()

39.3 Изменения

Размер файла

При экспорте HTML, сгенерированного в R Markdown (как в этом случае!), вы хотите сделать график как можно меньше по размеру данных (в большинстве случаев без негативных побочных эффектов). Для этого достаточно передать интерактивный график в partial_bundle(), также из plotly.

p <- p %>% 
  plotly::ggplotly() %>%
  plotly::partial_bundle()

Кнопки

Некоторые кнопки стандартного plotly являются лишними и могут отвлекать внимание, поэтому их можно удалить. Для этого достаточно передать результат по каналу в config() из plotly и указать, какие кнопки необходимо удалить. В приведенном ниже примере мы заранее задаем названия удаляемых кнопок и указываем их в аргументе modeBarButtonsToRemove =. Мы также задаем displaylogo = FALSE, чтобы удалить логотип plotly.

## Эти кнопки отвлекают внимание, поэтому мы хотим их убрать
plotly_buttons_remove <- list('zoom2d','pan2d','lasso2d', 'select2d','zoomIn2d',
                              'zoomOut2d','autoScale2d','hoverClosestCartesian',
                              'toggleSpikelines','hoverCompareCartesian')

p <- p %>%          # Повторное построение интерактивного графика без этих кнопок
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

39.4 Тепловые плитки

Практически любой график ggplot() можно сделать интерактивным, в том числе и тепловые графики. На странице [Тепловые графики] вы можете прочитать о том, как сделать приведенный ниже график, который отображает долю дней в неделю, когда определенные учреждения предоставляли данные в свою провинцию.

Приведем код, хотя подробно описывать его здесь не будем.

# импорт данных
facility_count_data <- rio::import(here::here("data", "malaria_facility_count_data.rds"))

# агрегирование данных в "Недели" для района Spring
agg_weeks <- facility_count_data %>% 
  filter(District == "Spring",
         data_date < as.Date("2020-08-01")) %>% 
  mutate(week = aweek::date2week(
    data_date,
    start_date = "Monday",
    floor_day = TRUE,
    factor = TRUE)) %>% 
  group_by(location_name, week, .drop = F) %>%
  summarise(
    n_days          = 7,
    n_reports       = n(),
    malaria_tot     = sum(malaria_tot, na.rm = T),
    n_days_reported = length(unique(data_date)),
    p_days_reported = round(100*(n_days_reported / n_days))) %>% 
  ungroup(location_name, week) %>% 
  right_join(tidyr::expand(., week, location_name)) %>% 
  mutate(week = aweek::week2date(week))

# создать график
metrics_plot <- ggplot(agg_weeks,
       aes(x = week,
           y = location_name,
           fill = p_days_reported))+
  geom_tile(colour="white")+
  scale_fill_gradient(low = "orange", high = "darkgreen", na.value = "grey80")+
  scale_x_date(expand = c(0,0),
               date_breaks = "2 weeks",
               date_labels = "%d\n%b")+
  theme_minimal()+ 
  theme(
    legend.title = element_text(size=12, face="bold"),
    legend.text  = element_text(size=10, face="bold"),
    legend.key.height = grid::unit(1,"cm"),
    legend.key.width  = grid::unit(0.6,"cm"),
    axis.text.x = element_text(size=12),
    axis.text.y = element_text(vjust=0.2),
    axis.ticks = element_line(size=0.4),
    axis.title = element_text(size=12, face="bold"),
    plot.title = element_text(hjust=0,size=14,face="bold"),
    plot.caption = element_text(hjust = 0, face = "italic")
    )+
  labs(x = "Week",
       y = "Facility name",
       fill = "Reporting\nperformance (%)",
       title = "Percent of days per week that facility reported data",
       subtitle = "District health facilities, April-May 2019",
       caption = "7-day weeks beginning on Mondays.")

metrics_plot # печать

Ниже мы сделаем его интерактивным и модифицируем для простых кнопок и размера файла.

metrics_plot %>% 
  plotly::ggplotly() %>% 
  plotly::partial_bundle() %>% 
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

.

–>

39.5 Ресурсы

Plotly предназначен не только для R, но также хорошо работает с Python (и вообще с любым языком науки о данных, поскольку построен на JavaScript). Подробнее об этом можно прочитать на сайте plotly