Plotlyで軸比を1:1に固定する

カテゴリ: r

今迄Plotly.jsを使いたい時は、元の図を ggplot2 パッケージで作成し、 plotly::ggplotly() で変換していた。しかし、どうもパフォーマンスが悪い気がするので、Plotlyネイティブに書いてみようと思った。

直近ではヒートマップをなんとかしたく、軸比を1:1にする方法を調べたのでメモ。

デフォルト

volcano データセットをヒートマップする例は、 Plotlyでも 紹介されている 。このデータセットは、行列型で、各値が \(10m \times 10m\) 範囲の標高を示す。従って、ヒートマップで標高を表現するならば、軸比を1:1にすべきだが、例では以下の通り、ヒートマップすることに終始し、軸比の面倒までは見ていない。

library(plotly)
p <- plot_ly(z = volcano, type = 'heatmap') 
p

1:1にする

方法は こちら に記載されているのだが、如何せん色々な比率の図を一辺に吐き出すコードなため見通しが悪い。どうやら、以下のようにすれば、y軸の目盛をx軸の目盛に合わせてくれるらしい。

layout(p, yaxis = list(scaleanchor = "x"))

ベンチマーク

ggplotly を使う場合のパフォーマンスの低さがネックだったので、比較してみるとしよう。

まず、行列型のvolcanoをggplotでも使えるdata frameにしておく

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
volcano_df <- volcano %>%
  as.data.frame %>%
  mutate(y = seq(n())) %>%
  gather(x, z, -y) %>%
  group_by(y) %>%
  mutate(x = seq(n()))

ggplotly用のコード

library(ggplot2)
g <- function() {
  ggplotly(
    ggplot(volcano_df, aes(x, y, fill = z)) +
      geom_tile() +
      coord_fixed()
  )
}
g()

plot_ly用のコード

p <- function() {
  plot_ly(x = volcano_df[['x']], y = volcano_df[['y']], z = volcano_df[['z']], type = 'heatmap') %>%
    layout(yaxis = list(scaleanchor = "x"))
}
p()

結果

library(microbenchmark)
bench <- microbenchmark(
  ggplotly = g(), plot_ly = p()
)
bench
## Unit: microseconds
##      expr        min         lq       mean     median         uq
##  ggplotly 122525.869 128253.565 141403.909 132508.503 141137.786
##   plot_ly    914.529    975.272   1337.894   1025.978   1292.698
##         max neval
##  300250.068   100
##    6191.157   100
plot(bench)

圧倒的ですな。