某所で「ggplot2で文字をど真ん中に入れるようなgeomを作るべし」とのミッションを受けたので、試行錯誤してなんとか走るものができたのでメモ。

なおこれは個人的な勉強とメモのためのもので、実用性は低いです。以下の資料を参考にしました:

ggprotoオブジェクト作成

ようするに、以下のような計算をしてくれるようなものがあればいい:

  1. xとyのそれぞれの範囲(range)を取得
  2. 上限と下限の平均を算出することで真ん中の場所を計算
  3. これをdataframeで返す
StatLabelCenter <- ggproto("StatLabelCenter", Stat,
                           compute_group = function(data, scales) {
                             rngx <- range(data$x, na.rm = TRUE)
                             rngy <- range(data$y, na.rm = TRUE)
                             grid <- data.frame(x = mean(rngx), y = mean(rngy))
                             grid
                           },
                           required_aes = c("x", "y")
                           )

参考資料の内容からちょっと編集して作りました。

geom_label_center()の作成

ラベルをプロットするのはgeom_label()なので、そのソースコードをベースに作りました:

geom_label_center <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity",
                              parse = FALSE, ..., nudge_x = 0, nudge_y = 0, 
                              label.padding = unit(0.25, "lines"), label.r = unit(0.15, "lines"),
                              label.size = 0.25,na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) 
{
  if (!missing(nudge_x) || !missing(nudge_y)) {
    if (!missing(position)) {
      stop("Specify either `position` or `nudge_x`/`nudge_y`", 
           call. = FALSE)
    }
    position <- position_nudge(nudge_x, nudge_y)
  }
  layer(data = data, mapping = mapping, stat = StatLabelCenter, geom = GeomLabel, 
        position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
        params = list(parse = parse, label.padding = label.padding, 
                      label.r = label.r, label.size = label.size, na.rm = na.rm, 
                      ...))
}

修正箇所は、layer()内の引数で、stat = StatLabelCenterと、先ほど作ったggprotoオブジェクトを指定しています。よって、関数の引数にstat = "identity"とありますが思いっきり無視します。

テスト

試してみます:

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  geom_label_center(aes(label="kosaki"))

geom_label()がベースなので、ラベルの書式などはそれと同じように設定できます。

感想

なんとなくggplot2の仕組みに触れられた気がした。でもまだ私には難しすぎる…。あとコードが雑過ぎる。任せたよ未来の自分。

Enjoy!