読者です 読者をやめる 読者になる 読者になる

directlabelsでggplot2のグラフに直接ラベルをつける

R ggplot2

ggplot2で描くグラフの中に直接ラベルを付けたいとき、directlablesパッケージを使うと便利です。

CRANに上がっているのは2年前のバージョン(CRAN - Package directlabels)なんですが、時代はもうちょっと進んでいてGithubで細々と開発が進んでいます。Github版のggplot2といっしょに使おうと思ったらこれをinstall_github()する必要があります。機能としては大して変わってなさそうですけど。

geom_dl()

ggplot2でdirectlabels使うために、geom_dl()という関数が用意されています。?geom_dlに載ってる例はこんな感じ。

library(ggplot2)
library(directlabels)

vad <- as.data.frame.table(VADeaths)
names(vad) <- c("age","demographic","deaths")

ggplot(vad, aes(deaths,age,colour=demographic)) +
  geom_line(aes(group=demographic)) +
  geom_dl(aes(label=demographic), method=list(last.points, rot=30)) +
  xlim(8,80) + theme(legend.position = "none")

f:id:yutannihilation:20151209225838p:plain

geom_dl()はあんまり親切じゃないので、ラベルが切れないようにxlim()で自分で範囲を調節しないといけなかったり、凡例が邪魔なのでtheme()で消したりしないといけなかったりします。このへんはあんまりイケてないです。

geom_dl()が最低限必要とするのは以下の2つです。

method引数はラベルのつけ方を指定するもので、ここに指定したパラメータは、apply.method()という関数に渡されます。

geom_dl()を足し合わせるのではなくて、direct.label()関数にggplotオブジェクトを渡しても大丈夫です。こっちだとlabelマッピングを書かなくてもいいみたいです。

p <- ggplot(vad, aes(deaths,age,colour=demographic)) +
  geom_line(aes(group=demographic)) +
  xlim(8,80) + theme(legend.position = "none")

direct.label(p, method=list(last.points, rot=30))

apply.method()

ここに指定できるmethodは3種類あります。

  • 関数または関数名(例:last.points, "last.points"
  • 関数または関数名とその引数のリスト(例:list(last.points, rot=30), list("last.points", rot=30)

ここで例として出しているlast.points()とかfirst.points()はdirectlabelsパッケージに含まれるPositioning Method関数です。それぞれ、各グループの初めの点と最後の点をラベルとして使います。

この関数は自作することもできるような雰囲気ですが、よく分かりませんでした。

追記:↓この辺に書いてました。

directlabels motivation

ヘルプにはこう書かれています:

a Positioning Function is any function(d,...) which takes a data.frame d with columns x,y,groups and returns another data.frame representing the positions of the desired direct labels.

用意されてる関数はいっぱいあるんですが、あんまりドキュメントにまとまってないです。Use the Source, Lukeです。つらい。

つらいけど試しにいくつか読んでみます。

追記:↓ばっちり書いてました。。

directlabels documentation - home

line plot用に用意されている関数

ここを読みます:directlabels/lineplot.R at master · tdhock/directlabels · GitHub

関数 意味
lasso.labels() Label points at the zero before the first nonzero y value.
first.points() Positioning Method for the first of a group of points.
last.points() Positioning Method for the last of a group of points.
maxvar.points() Do first or last, whichever has points most spread out.
last.bumpup() Label last points, bumping labels up if they collide.
first.bumpup() Label first points, bumping labels up if they collide.
last.qp() Label last points from QP solver that ensures labels do not collide.
first.qp() Label first points from QP solver that ensures labels do not collide.
first.polygons() Draw a speech polygon to the first point.
last.polygons() Draw a speech polygon to the last point.
maxvar.qp() Label first or last points, whichever are more spread out, and use a QP solver to make sure the labels do not collide.
lines2() (長い説明が書いてあるけどよく分からない...)
angled.boxes() Draw a box with the label inside, at the point furthest away from the plot border and any other curve.

たとえば、angled.boxes()とかちょっとおしゃれな感じです。

ggplot(BodyWeight,aes(Time,weight,label=Rat)) +
  geom_line(aes(group=Rat)) +
  geom_dl(method=angled.boxes)

f:id:yutannihilation:20151209234417p:plain

scatter plot用に用意されている関数

ここを読みます:directlabels/scatterplot.R at master · tdhock/directlabels · GitHub

関数 意味
chull.grid() Label the closest point on the convex hull of the data.
ahull.grid() Label the closest point on the alpha hull of the data.
smart.grid() Search the plot region for a label position near the center of each point cloud.
extreme.grid() Label each point cloud near the extremities of the plot region.
その他

あとはよく分かりませんでした。。

関数を組み合わせる

dl.combineを使うと、Positioning Method関数を組み合わせられます。例えば、線分の初めと終わりにラベルを付けるにはfirst.points()last.points()を組み合わせます。

ggplot(vad, aes(deaths,age,colour=demographic, group=demographic, label=demographic)) +
  geom_line() +
  geom_dl(method=dl.combine(list(last.points, rot=30), list(first.points, rot=30))) +
  xlim(0,80) + theme(legend.position = "none")

f:id:yutannihilation:20151210000701p:plain

感想

意外と便利かも。でもところどころ古臭い感じとかドキュメントのなさがつらいです…。