Rでインタラクティブなプロットを作ろう

前田和寛(kazutan)

はじめに

自己紹介

  • 前田 和寛
  • 比治山大学短期大学部
  • @kazutan
    • twitter
    • GitHub
    • Qiita

今日のお話

  • Rでインタラクティブプロット?
  • htmlwidges系パッケージ
  • plotlyとは
  • plotlyの基本
  • plotlyギャラリー
  • 使いドコロと留意事項

Rでインタラクティブなプロット

Rでプロット、何を使ってますか?

  • baseのplot?
  • ggplot2?
  • lattic?
  • その他パッケージ?

いろんな選択肢があります

できればグリグリ動かしたい

  • baseのplotやggplot2は“静止画”
    • 出力したらそれで固定
    • 軸範囲やデータ系列の変更はコードに戻る必要
  • できれば出力した後で動かしたい
    • しかしplotやggplot2では難しい

HTML + CSS + JSで実現しよう!

htmlwidgets系パッケージ

htmlwidgetsとは

  • jsライブラリをRで使えるようにするパッケージ
    • 主に可視化jsライブラリで効果発揮
    • 要するにjsのwrapper
    • R向けのインターフェースを提供
  • 生成物は(基本)html
    • だってjsだもん
  • このパッケージをフレームワークとして、様々な可視化パッケージが開発されている

leafletパッケージ

# CRANから
install.packages("leaflet")
# GitHubから
devtools::install_github("rstudio/leaflet")
# githubinstallを使うなら
githubinstall::githubinstall("leaflet")

以下のような感じになります:

library(leaflet)
df2 <- data.frame(id=1:100, lng=135+rnorm(100, sd = 0.1), lat=35+rnorm(100, sd = 0.1))
leaflet(df2) %>% addTiles() %>% 
    addMarkers(~lng, ~lat, label=~paste0(id,"番"),
                         clusterOptions = markerClusterOptions())

dygraphsパッケージ

  • 時系列データをプロット
  • dygraphsというjsライブラリのwrapper
  • 詳しくは公式ドキュメントを参照してください
  • インストールは以下の通り:
# CRANから
install.packages("dygraphs")
# GitHubから
devtools::install_github("rstudio/dygraphs")
# githubinstallを使うなら
githubinstall::githubinstall("dygraphs")

以下のような感じになります

library(dygraphs)
lungDeaths <- cbind(mdeaths, fdeaths)
dygraph(lungDeaths, height = 450) %>% dyRangeSelector()

DiagrammeRパッケージ

  • ダイアグラムやネットワークを可視化
  • mermaidGraphvizなどをベース
  • 公式ドキュメントがちょっと古い…
  • かなり巨大なパッケージになってて、細部を追うのは大変
    • でも便利
  • インストールは以下の通り:
# CRANから
install.packages("DiagrammeR")
# GitHubから
devtools::install_github("rich-iannone/DiagrammeR")
# githubinstallを使うなら
githubinstall::githubinstall("DiagrammeR")

例えばこんな感じです:

library(DiagrammeR)
create_graph() %>% add_n_nodes(n = 2) %>% add_edge(from = 1, to = 2) %>%
  render_graph()

visNetworkを利用することも可能:

create_random_graph(n = 30, m = 50) %>% render_graph(output = "visNetwork")

networkD3パッケージ

  • ネットワークを可視化するパッケージ
  • D3.jsを利用
  • 公式サイトはこちら
  • いろいろなgraphがかけます
  • インストールは以下の通り:
# CRANから
install.packages("networkD3")
# GitHubから
devtools::install_github("christophergandrud/networkD3")
# githubinstallを使うなら
githubinstall::githubinstall("networkD3")

公式サイトから:

library(networkD3)
forceNetwork(Links = MisLinks, Nodes = MisNodes, Source = "source",
             Target = "target", Value = "value", NodeID = "name",
             Group = "group", opacity = 0.8)

DTパッケージ

  • 表(data.frame)をインタラクティブに表示
  • jQueryプラグインのDataTables.jsを利用
  • 公式サイトはこちら
  • かなり多機能、でもdata.frameから簡単に作れる
  • インストールは以下の通り:
# CRANから
install.packages("DT")
# GitHubから
devtools::install_github("rstudio/DT")
# githubinstallを使うなら
githubinstall::githubinstall("DT")

こんな感じです:

library(DT)
iris2 = iris[c(1:10, 51:60, 101:110), ]
datatable(iris2, filter = 'top', options = list(
  pageLength = 5, autoWidth = TRUE
))

他にもたくさん

  • 例えば…
  • CRANだけでなくGitHubのみで公開されているものも
  • ギャラリーがあるので,ぜひ一度訪れてみてください

plotly

plotlyパッケージとは

  • plotlyというインタラクティブなchartsを作るパッケージ
    • 元は同社の可視化コンテンツにアクセスするためのパッケージ(要登録)
    • 現在はオープンソース化
  • htmlwigets系で一番GitHubの★を稼いでる
  • 以下の資料がおすすめ
    • R Graphing Library | Plotly
      • 公式サイトによるドキュメント。まずはここから。
    • plotly for R
      • gitbook形式で,より深い使い方が書いてあります。ここ読めばOK

インストール

# CRANから
install.packages("plotly")
# GitHubから
devtools::install_github("ropensci/plotly")
# githubinstallを使うなら
githubinstall::githubinstall("plotly")

Hello, plotly!

library(plotly)
library(magrittr)
plot_ly(iris, x = ~Sepal.Length, y = ~Sepal.Width, color = ~Species)
plot_ly(iris, x = ~Species, y = ~Sepal.Length, type = "box")

特徴

  • 簡単にインタラクティブなplotが作れる
    • デフォルトでいい感じにしてくれる
  • 3Dや地図、ガントチャートも対応
    • D3.jsベースでかなり幅広い
  • プロット記述 %>% レイアウト設定記述
    • pipe演算子で送ると楽
  • type(グラフの種類)が重要
    • これによって指定できるオプションが変わってくる
    • ggplot2みたいに多様なgeomを使い分けるのではない
    • 系統的に分かれていく(後述)
      • 例えばpointとbubbleとlineはすべてtype = scatterから分岐

plotlyの基本(データ・タイプ)

キャンパス

p_empty <- plot_ly()
p_empty
  • 引数を与えないと,キャンパスのみ生成
  • 軸はとりあえず描かれているだけ
  • ここから要素を追加していきます

データ

plot_ly(data = iris)
  • 描写する際に使用するデータセット(data.frame)を指定しています
  • ただデータセットを指定しただけなので,特に何が描かれているわけではないです

x軸の指定

plot_ly(data = iris, 
        x = ~Sepal.Length,
        y = ~Sepal.Width)
  • 軸に割り当てる変数を指定すると描写
  • 変数を指定する場合,変数名の前に~が必要
  • x,yに割り当てられているデータから,自動的にscatterプロットが選択

グラフのタイプを指定

plot_ly(data = iris, 
        x = ~Species,
        y = ~Sepal.Length,
        type = "box")
  • 引数typeでグラフのタイプを指定
    • bar: 棒グラフ
    • box: 箱ひげ図
    • scatter: 散布図
    • pie: 円グラフ
    • sankey: sankey diagram
      etc…

データ系列の指定(split)

plot_ly(data = iris,
        x = ~Sepal.Length,
        y = ~Sepal.Width,
        split = ~Species,
        type = "scatter")
  • いわゆるggplot2のgroupみたいなもの
  • splitで指定した変数で系列を分割
    • 離散変数で使ってください

データ系列の指定(color)

plot_ly(data = iris,
        x = ~Sepal.Length,
        y = ~Sepal.Width,
        color  = ~Petal.Length,
        type = "scatter")
  • いわゆるggplot2のcolorみたいなもの
  • colorで指定した変数で色分け
    • 連続でも離散でもOK

plotlyの基本(軸・凡例・タイトルなど)

軸や凡例

  • こういったプロパティ項目は追加設定
    • plotlyのオブジェクトを作成
    • それにlayout関数をかける
  • 以下に設定を追加していきます:

軸周りの設定

plot_ly(data = iris,
        x = ~Sepal.Length,
        y = ~Sepal.Width,
        split = ~Species,
        type = "scatter") %>% 
  layout(xaxis = list(
    showgrid = F,
    rangemode = "tozero",
    nticks = 6,
    title = "ほげ"
  ))
  • xaxis引数に設定したい内容をlist型で
  • Y軸に設定したい場合はyaxis引数へ
  • たくさんあるので詳しくは公式サイトのreference

凡例(legend)の設定

plot_ly(data = iris,
        x = ~Sepal.Length,
        y = ~Sepal.Width,
        split = ~Species,
        type = "scatter") %>% 
  layout(legend = list(
    orientation = "h",
    yanchor = "bottom"
  ))

タイトルなど

plot_ly(data = iris,
        x = ~Sepal.Length,
        y = ~Sepal.Width,
        color = ~Species,
        type = "scatter") %>% 
  layout(title = "たいとる",
         paper_bgcolor = "#aaf",
         plot_bgcolor = "#66d",
         showlegend = FALSE)

plotlyの基本
(重ね書き・複数プロット)

重ね書き

df <- data.frame(
  x = c(1:50),
  y1 = rnorm(50, mean = 5),
  y2 = rnorm(50, mean = 0)
)
plot_ly(df, x = ~x, y = ~y1,
        name = "kosaki",
        type = "scatter", mode = "lines+marker") %>% 
  add_trace(y = ~y2,
            name = "chitoge",
            mode = "markers")
  • add_trace関数で新たに描写オブジェクトを追加
    • ggplot2でgeom重ね書きに近い
    • dataやaes的なのは継承可

複数プロット(個別で作成)

p1 <- plot_ly(df, x = ~x, y = ~y1,
              type = "scatter",
              mode = "markers")
p2 <- plot_ly(df, x = ~x, y = ~y2,
              type = "scatter",
              mode = "lines")
subplot(p1, p2, nrows = 2)
  • subplotで束ねることが可能
    • nrows引数で行数を指定
    • その後pipeでlayoutを繋げば、全体でのlayout設定が可能

複数プロット(条件別で)

df_tidy <- df %>%  
  tidyr::gather(var, value, -x)
plot_ly(df_tidy,
        x = ~x, y = ~value,
        color = ~var,
        yaxis = ~var) %>% 
  add_lines() %>% 
  subplot(nrows = 2)
  • plot_lyyaxisでY軸のIDを準備
    • あとはggplot2のfacetみたいに自動でやってくれる

ggplot2 to plotly

ggplotlyがある

library(ggplot2)
gg <- ggplot(df_tidy, aes(x, value, group = var)) +
  geom_point(aes(color = var))
ggplotly(gg)
  • なんとggploly関数で一発変換
    • かなりマニアックなものをしてなければすんなりOK
    • どれが効かないかは把握しきれてないです…

facetもOK

gg_facet <- ggplot(df_tidy,
                   aes(x, value, group = var)) +
  geom_point(aes(color = var)) +
  facet_wrap(~var, nrow = 2)
ggplotly(gg_facet)
  • facetされていてもちゃんと出します
    • ただし、plotlyのオブジェクトとしては分かれていない
    • この点には注意

plotlyの出力方法

R Markdown, Shiny

  • そのままでOK
  • この資料でもそのまま出しています
  • CSSで調整も可能
    • classは.plotly
    • idはハッシュ値

htmlファイル

  • htmlファイルとして可能
    • いわゆるウィジットとして使える
    • あとはiframeとかで埋め込めばOK
  • RStudioのViewerから[Export]-[Save As a html…]
  • もしくはhtmlwidgets::saveWidget

静止画像で

  • 静的な出力も可能
    • plotly::exportを使う
    • RStudioのViewerに出して、[Export]のメニューから
  • もちろん「ただの画像」として出す
    • 正直あんまり意味ない…

ギャラリー(短縮版)

bar chart

Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
data <- data.frame(Animals, SF_Zoo, LA_Zoo)

plot_ly(data, x = ~Animals, y = ~SF_Zoo, type = 'bar', name = 'SF Zoo') %>%
  add_trace(y = ~LA_Zoo, name = 'LA Zoo') %>%
  layout(yaxis = list(title = 'Count'), barmode = 'stack')

box plot

plot_ly(y = ~rnorm(50), type = "box") %>%
  add_trace(y = ~rnorm(50, 1))

heatmap

plot_ly(z = volcano, type = "heatmap")

3D surface plot

plot_ly(z = ~volcano) %>% add_surface()

さいごに

使いドコロは?

  • htmlベースなドキュメントに埋め込む
    • インタラクティブなので、インパクトが大きい
  • ダッシュボードに最適
  • Shinyでアプリ
    • htmlwidgetsはShinyでこそ効果を発揮

留意事項

  • データがドキュメントに保持される
    • scriptタグ内に(だいたい)json形式で埋め込まれる
      • 公開する際は注意
  • データ量が多いと重くなる
    • ブラウザ&マシンに依存する
    • クライアント側で処理するため

Enjoy!

参考資料