LoginSignup
1
1

More than 5 years have passed since last update.

gghighlightを汎用的にしたい(中途半端)

Last updated at Posted at 2018-01-28

gghighlightについて

グラフ作りにおいて、必要な情報だけを色付けてくれるパッケージ(yutannihilation氏作)
http://notchained.hatenablog.com/entry/2017/09/29/212444

gghighlight_point(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species), Species == 'setosa', use_direct_label = FALSE)

image.png

ただし、

- 限られたgeomにしか使えない
- highlightはaesthenticsになっていない

といった課題がある。
前者についてはggplot_add()の登場によって解決できる見通しっぽい。
https://yutani.rbind.io/post/2017-11-07-ggplot-add/

でも実は既にあるggplot2の実装でできるんじゃね?
と思ったので試してみました。

ただ、結局、実用的なのは一部のgeomのみです(boxplotやdensityなどstatで計算を行うものは不可).
geom_point, geom_lineに加え、geom_rect, ribbon, areaなどはいけることを確認しました。

highlightする関数を返す高階関数

.geomにはggplot2::GeomPointなどのGeom*オブジェクトを指定します。

library(ggplot2)
library(purrr)
library(stringr)

gghl <- function(.geom, LL = list(colour = NA)) {
  #.geom Geom objects (e.g., ggplot2::GeomPoint)
  # LL default aethentics for lowlights
  Stats <- substitute(.geom) %>% # Generate Stat for lowlight and highlight
      deparse %>%
      stringr::str_replace('(.*::)?Geom', 'Stat') %>% 
      paste0(c('LL', 'HL')) %>% # _class LL = lowlight HL = highlight
      list(c( # compute_group
        LL = function(data, scales) {
          data[names(LL)] <- LL
          as.data.frame(data)[!as.logical(data$highlight), ]
        },
        HL = function(data, scales)
          data[as.logical(data$highlight), ]
      )) %>%
      setNames(c('_class', 'compute_group')) %>%
      purrr::pmap(
        ggplot2::ggproto,
        `_inherit` = ggplot2::Stat,
        required_aes = c(.geom$required_aes, 'highlight')
      )

  #return stat_ function for highlighjting
  function(
    mapping = NULL, data = NULL, geom = .geom, position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...,
    .Stats = Stats
  ) {
    purrr::map(
      .Stats,
      ggplot2::layer,
      data = data, mapping = mapping, geom = geom,
      position = position, show.legend = show.legend, inherit.aes = inherit.aes,
      params = list(na.rm = na.rm, ...)
    )
  }
}

使用例

デフォルトではhighlightしないデータの色をNAにします。
それらはggplot2::scale_colour_dicreteなどscale_color*系のna.valuesに指定された色でプロットされます(既定値はgray50)

g <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species, highlight = Species == 'setosa'))
g + gghl(ggplot2::GeomPoint)()

image.png

他に

- 引数LL(lowlightの略)にalphaやfillを指定して、highlightしないデータの見た目を変える
- 任意のstat_highlight_*を作成する

といったことが可能です


stat_highlight_boxplot <- gghl(ggplot2::GeomBoxplot, LL = list(alpha = 0.3))
g + stat_highlight_point()

image.png

geom_highlight_rect <- gghl(GeomRect, LL = list(fill = 0))
df <- data.frame(x = sample.int(10), y = sample.int(10), w = 1, z = sample.int(10, 10, replace = TRUE))
ggplot(
  df, 
  aes(xmin = x - w / 2, xmax = x + w / 2, ymin = y, ymax = y + 1, fill = z, highlight = z > 5)
) +
  geom_highlight_rect() +
  geom_text(aes(x = x, y = y, label = z), vjust = 1) +
  scale_fill_gradient2()

image.png

ただし、現状では、geom_boxplotやgeom_densityなど、データに対して演算を行うgeomには対応していません。

ggplot(iris, aes(x = Species, y = Sepal.Length, color = Species, highlight = Species == 'setosa')) +
  gghl(GeomBoxplot)()
# Error: stat_boxplot_ll requires the following missing aesthetics: lower, upper, middle, ymin, ymax
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1