3次元のデータをグラフにする

3次元のベクトルで表されるデータをグラフ化する方法について,いくつかまとめてみました.

使用するデータ

volcano

Rに組み込まれているデータセットで,Maunga Whau山の標高データだそうです.10m * 10mのグリッドで,87rowと61columnからなります.rowは東から西へ,columnは南から北へのラインと対応しており,最小値は94,最大値は195です.

まずはデータセットの準備.

# あらわしたいデータのラベルを作成
EastWest <- 1:nrow(volcano) * 10  # rowの数は87
SouthNorth <- 1:ncol(volcano) * 10  # columnの数は61
# 頂上の位置を変数に入れておく
mountaintop <- which(volcano == max(volcano), arr.ind = TRUE) * 10


グラフを描く

image
値に応じた色を格子上に示す関数です.

主要な引数は以下のとおり.
x, y: プロットされるzの位置を表す座標.昇順でなければならない.
z: プロットされる値のmatrix.NA値も許される.
col: プロットされる値につける色.


備考
xはnrow(z)+1かnrow(z)と等しくなる必要がある.前者ならセルの境界に,後者ならセルのmidpointに,値がプロットされる.
NA値は透明になる.
zのmatrixはf(x[i], y[i])のtableとして解釈される.よって,xはrowの数に,yはcolumnの数に,対応している必要がある.つまり,データセットとグラフは90度回転した関係にあるということですね.


実例

image(EastWest, SouthNorth, volcano, col = heat.colors(100))
# col の値には他にこんなのもあります.
# rainbow(7), heat.colors(10), topo.colors(100), terrain.colors(100), gray((0:100)/100), gray((100:0)/100)
# つづけて頂上の位置にプロットを置きます
points(mountaintop[1], mountaintop[2], pch =  20, col = "blue")
# 等高線を描くcontour関数も合成してみましょう.今回は標高175mの位置に.
contour(EastWest, SouthNorth, volcano, levels = 175, add = TRUE)
# levels = seq(90, 200, by = 5) などもできます.

以下のようなグラフが描けます.


persp

x-y平面に遠近図を描く関数です.

主要な引数
x, y: プロットされるzの位置を表す座標.昇順でなければならない.
z: プロットされる値のmatrix.NA値も許される.
col: プロットされる値につける色.
theta, phi: 視座の角度.前者は横向きの回転,後者は縦向きの回転.
r: 視野とプロットの距離.
d: 遠近感の強さ.1以上なら遠近感が弱まり,1以下なら強調される.
scale: FALSEなら,全軸共通のスケーリングがなされる.
border: 表面に描かれる線の色.NAなら線を描かない.
ltheta, lphi: 指定した値の視座から光が投影されたような陰がつく.
shade: 陰がつく.1に近いほど濃い陰になる.
ticktype: "detailed"なら軸にスケールがプロットされる.デフォルトでは"simple".
nticks: スケールの数を指定.


実例
ここでは特に,2次元のグラフに使われる関数を3次元のグラフに描くtrans3d関数を使って,点や線も追加してみます.

mtMaugnaWau <- persp(EastWest, SouthNorth, volcano, theta = 25, phi = 30, scale = FALSE,
  col = "green", border = NA, ltheta = 120, shade = 0.7, ticktype = "detailed", cex.axis = 0.8)
# 頂上の追加
points(trans3d(mountaintop[1], mountaintop[2], max(volcano), pmat = mtMaugnaWau), col = "red", pch = 16)
# 頂上から標高150mラインにある一点に直線を引く
level150 <- which(volcano == 150, arr.ind = TRUE) * 10
x <- 6  # 150mラインのうちのどの点に直線を引くか.適当に決めて6にしました.
lines(trans3d(c(mountaintop[1], level150[x, 1]), c(mountaintop[2], level150[x, 2]),
  c(max(volcano), 150), pmat = mtMaugnaWau), col = "blue")

以下のようなグラフが描けます.


scatterplot3d

値を3次元にプロットする関数です.CRANからパッケージのダウンロードが必要です.
scatterplot3d: 3D Scatter Plot

主要な引数
x, y, x: それぞれの座標.
scale.y: y軸のスケール (奥行き) の調節.
angle: x-y軸の角度
highlight.3d: TRUEなら,y軸の値に応じて色の濃さが変わる.


実例

# データセットの準備.
EastWest3d <- rep(EastWest, length(SouthNorth))
SouthNorth3d <- vector(length = 87 * 61)
for(i in 1:61){
  SouthNorth3d[((i - 1) * 87 + 1):(i * 87)] <- SouthNorth[i]
}
# プロットの実行.
library(scatterplot3d)  # パッケージの呼び出し.
mtMaugnaWau3d <- scatterplot3d(EastWest3d, SouthNorth3d, volcano, scale.y = 0.5, highlight.3d = TRUE)
# plane3dメソッドやpoints3dメソッドで平面や点の追加が可能です.
# 標高150mラインに平面の追加.
mtMaugnaWau3d$plane3d(150, x.coef = 0, y.coef = 0, lty.box = "dashed") 
# 頂上の追加.
mtMaugnaWau3d$points3d(mountaintop[1], mountaintop[2], max(volcano), col = "blue", pch = 19)

以下のようなグラフが描けます.


どんなときに使うか

まず,連続的な値をべたーっと面で描きたいときには,imageやperspが適しているでしょう.imageは直感的にイメージがつかみにくいですが,全体が見渡せるので,ひとつひとつの値をある程度きちんと検証できます.一方,perspは直感的にイメージがつかめますが,山や谷で見えなくなる部分があり,データをすべて見せきれないかもしれません.
次に,線・点など,面に比べるととびとびになる値を3次元にプロットしたいときは,scatterplot3d関数が適しているでしょう.引数も充実しており,ラベルやスケールなどもきちんと描くことができます.

※ 他にもこんな関数がある,などご存じでしたら,ぜひトラックバックなどでお教えいただければ幸いです!