воскресенье, 27 декабря 2015 г.

Plotly: интерактивная графика для R и не только

Plotly: интерактивная графика для R и не только
Plotly (plotly.js) является JavaScript-библиотекой для создания интерактивных графиков, построенной на основе d3.js и stack.gl. Начиная с версии 2.0, ее исходный код стал открытым, а рендеринг графиков происходит на стороне пользователя, т.е. локально. В случае использования совместно с R это осуществляется посредством htmlwidgets. Имеется возможность встраивания графиков в сайты и приложения, также стоит отметить возможность хостинга на сервере разработчиков и наличие интерактивного конструктора графиков.
Помимо программирования непосредственно на языке JavaScript, доступ к возможностям библиотеки можно получить из других языков и приложений путем использования соответствующего API. Реализована поддержка R, Python, Julia, Matlab, Excel (!). Остановимся пока что на первом варианте, остальное - как-нибудь в другой раз.
Для начала нужно установить пакет (с CRAN или с GithHub):
# Установка с CRAN:
install.packages("plotly")
# Установка самой свежей версии с GithHub:
devtools::install_github("ropensci/plotly")
Далее есть три альтернативы:
  1. Независимое использование (функция plot_ly() со своим собственным синтаксисом);
  2. Использование в качестве надстройки на ggplot2 (объект ggplot2 передается конвертирующей функции ggplotly());
  3. Встраивание в приложения Shiny (в этом сообщении не рассматривается, см. примеры).
На сайте разработчиков имеется большое количество справочных и обучающих материалов, но организованы они специфическим образом, поэтому найти ответ на конкретный вопрос не всегда легко. Обязательны для ознакомления следующие страницы:
  • Главная страница справки: содержит ссылки на другие материалы (не пропустите неприметные ссылки внизу страницы), часть из них не работает (например, Layout Options); можно посмотреть примеры различных типов графиков;
  • Plotly for R User Guide: рассмотрено несколько примеров, но на сколько-нибудь полноценное руководство не тянет; показано, как комбинировать в одном конвейере манипуляции с данными и поэтапное построение графика;
  • Chart attributes: дополнение к встроенной справке по функциям plot_ly(), layout(), add_trace() и style(); приведены наиболее ценные примеры, показывающие, как сочетать различные элементы графиков для наиболее полного контроля над их внешним видом;
  • Руководство по использованию с ggplot2: показано, как можно создать объект средствами ggplot2, а затем сконвертировать его в объект plotly;
  • Plotly and ggplot2 UseR Guide: показано, как можно редактировать сконвертированный из ggplot2 объект.
Также имеется виньетка на CRAN.
Пакет plotly предоставляет свой DSL, подобный ggplot2. Базовый график создается при помощи функции plot_ly() (аналог ggplot()), представления данных добавляются при помощи add_trace() (аналог семейства функций geom_()), за все общие атрибуты графика типа подписей к осям отвечает функция layout(). Добавлять элементы к графику можно двумя способами.
Первый способ - сохранение графика и передача переменной, которая на него ссылается, в качестве первого аргумента функций add_trace() и layout():
p <- plot_ly(...)
p <- add_trace(p, ...)
p <- layout(p, ...)
Альтернативный вариант - использование конвейерного оператора %>%, хорошо знакомого по пакету dplyr, который позволяет объединять трансформацию данных и визуализацию в одну цепочку операций:
p <- plot_ly(...) %>%
    add_trace(...) %>%
    layout(...)
Рассмотрим слегка измененный пример из документации.
p <- plot_ly(economics,
    type = "scatter",
    x = date,
    y = uempmed,
    name = "unemployment", 
    mode = "lines+markers",
    line = list(
        color = "pink"
    ),
    marker = list(
        color = "red",
        size = 4
    )
)
На данном этапе создан график, соответствующий временному ряду:
  • используется набор данных economics;
  • тип графика - "scatter" - позволяет рисовать точки и линии;
  • ось x соответствует переменной date, ось y - переменной uempmed;
  • name = "unemployment" задает “имя”, которое будет отображаться в легенде;
  • mode = "lines+markers" - рисуем линию и точки (по умолчанию, если значений больше 20, рисуется только линия);
  • цвет линии - розовый, цвет точек - красный, размер - 4 (по умолчанию - 6).
Таким образом, атрибуты точек, линий и других элементов графика задаются в виде списка.
Добавим сглаживание методом локальной регрессии (loess):
p <- add_trace(p,                       
    y = fitted((loess(uempmed ~ as.numeric(date)))),
    name = "loess",
    mode = "lines",
    line = list(                   
        color = "black",     
        dash = "dashed"              
    )
)
Найдем строку данных, соответствующую максимальному значению переменной uempmed:
maxdf <- economics %>% filter(uempmed == max(uempmed))
Добавим название графика и подписи осей; отметим максимальное значение на графике:
p <- layout(p,  
    title = "График, созданный при помощи <br> 
    <a href='https://plot.ly/'>Plotly</a>",
    xaxis = list( 
        title = "Время",     
        showgrid = FALSE 
    ),
    yaxis = list(          
        title = "Перерыв в работе (медиана), <sub>нед.</sub>"     
    ),
    annotations = list(        
        list(
            x = maxdf$date,     
            y = maxdf$uempmed,  
            text = "Максимум",      
            showarrow = TRUE      
        )
    )
)
p
В этом примере использована имеющаяся поддержка HTML-тегов, в том числе гиперссылок, что может быть весьма полезно.
Теперь о плохом, то есть о замеченном баге:
Не работает заявленная поддержка LaTeX. Artem Klevtsov помог разобраться, был написан багрепорт, ждем исправлений.
Еще из интересных возможностей хочу отметить встраивание одного графика в другой:
p1 <- plot_ly(x = c(1, 2, 3), y = c(4, 3, 2))
p2 <- plot_ly(x = c(20, 30, 40), y = c(30, 40, 50)) %>%
  layout(xaxis = list(domain = c(0.6, 0.95)),
         yaxis = list(domain = c(0.6, 0.95)))
subplot(p1, p2)
Наконец, если не хочется тратить время на изучение нового синтаксиса, можно рисовать графики привычными средствами ggplot2, а затем конвертировать их в интерактивный вариант.
dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
p <- ggplot(data = dsamp, aes(x = carat, y = price)) +
    geom_point(aes(text = paste("Clarity:", clarity))) +
    geom_smooth(aes(colour = cut, fill = cut), size = 0.1) +
    facet_wrap(~cut)
gg <- ggplotly(p)
gg
Был задан параметр size = 0.1, иначе после конвертирования линия будет очень толстой. Это баг, который вроде бы недавно был исправлен, то есть в новых версиях конвертирование должно происходить более правильным образом.

1 комментарий:

  1. Ещё о плохом, сложные графики ggplot поддерживаются далеко не полностью: часть элементов просто не отображаются.

    ОтветитьУдалить