library(tidyverse)
## ─ Attaching packages ───────────────────────────────── tidyverse 1.2.1 ─
## ✔ ggplot2 3.1.0 ✔ purrr 0.2.5
## ✔ tibble 2.0.1 ✔ dplyr 0.7.8
## ✔ tidyr 0.8.2 ✔ stringr 1.3.1
## ✔ readr 1.1.1 ✔ forcats 0.3.0
## Warning: package 'tibble' was built under R version 3.5.2
## ─ Conflicts ─────────────────────────────────── tidyverse_conflicts() ─
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
plot{base}
散布図に慣れる\(xy\)平面上に1対のデータを点として表現するので,\(x\)軸,\(y\)軸に対応するデータが必要になる.plot
関数では,x,y
という引数それぞれに,ベクトルとして値を渡すことで,散布図を描画してくれる.
二つの長さの同じベクトルを用意して,plot
を使ってみよう.
v1 <- c(1,5,3,6,4)
v2 <- c(2,4,7,3,2)
ちなみに,plot(v1,v2)
と引数を省略することもできる.その場合は,順序はx,y
の順番で値を与える必要がある.
plot(x=v1, y=v2)
このベクトルとしてデータを渡すというイメージを定着させることが重要で,DataFrame
やMatrix
を引数に与えてしまって,意図した結果が出ない場合がある. エラーになる場合をできるだけ列挙していこう(基本的にエラー文を読めば分かるはず).
'x' and 'x' lengths differ
このエラーは,x
とy
に与えられたベクトルの長さが異なる場合に返される(そのまま...)
plot(x=v1, y=1)
xy.coords(x, y, xlabel, ylabel, log) でエラー: 'x' and 'y' lengths differ
なぜだ?と思ったら実際にlength()
を使って調べてみると良い.
length(v1)
## [1] 5
length(1)
## [1] 1
実際のデータを可視化したい時,ほとんどの場合はデータフレーム型でデータを扱う.その場合であっても,plot
には2つの同じ長さのベクトルを与えるということは変わらない.データフレームは,ある1列だけを取り出すとベクトルとして扱われる.以下はその確認.
is.vector(iris[,1])
## [1] TRUE
is.vector(iris$Sepal.Length)
## [1] TRUE
丁寧にやるならば,以下のようにすると理解しやすいかもしれない.
v1 <- iris[,1]
v2 <- iris$Sepal.Width
plot(v1, v2)
また,2列のデータフレームを1つ与えるとよしなに読み取ってくれる(1列目をx
,2列目をy
).
plot(iris[,c(1,2)])
x
しか指定しない場合.(y
を与えない場合)引数x
しか与えない場合は,y
に要素番号(index)が与えられる.
plot(x=iris$Sepal.Length)
plot
ある1行を取り出した時,もし列数が3以上の場合は散布図行列が生成される.以下のコードの結果を見ると分かるように,データフレームの列については各列はベクトルであるが,行について,各行はベクトルではない.列ベクトルの集合のようなものだと考えると良いかもしれない.
is.vector(iris[1,])
## [1] FALSE
例えば,次のようにx
にiris
の1行目の1,2,3列目を,y
にiris
の2行目の1,2,3列目を与えると,各列のペアごとの散布図が生成されることがわかる.
iris[1,1:3]
## Sepal.Length Sepal.Width Petal.Length
## 1 5.1 3.5 1.4
iris[2,1:3]
## Sepal.Length Sepal.Width Petal.Length
## 2 4.9 3 1.4
plot(iris[1,1:3], iris[2,1:3])
基本的に扱いたいデータの単位は列になるはずなので,このようなこと気にする事は少ないと思うが,挙動としては知っておいて損はないかと思う.
type
plot
は散布図だけではなく,線グラフなどもサポートしている.点と点を線で繋いでくれるが,その際はベクトルにおける各要素の前後の要素との間を直線で繋いでくれる.
type = l
:グラフの種類を選ぶv1 <- c(1,5,3,6,4)
plot(v1, type = 'l')
線グラフの場合は,以下の引数を利用できる.
blank
solid
dashed
dotted
dotdash
longdash
twodash
df <- data.frame(x = seq(0.1, 10, 0.1))
df$y1 <- df$x
df$y2 <- df$x^2
df$y3 <- sin(df$x)*15
df$y4 <- log(df$x)
df$y5 <- {exp(df$x)}/{1+exp(df$x)}
df$y6 <- cos(df$x)*10
for(i in 1:6){
if(i == 1){
plot(x = df$x, y = df$y1, type='l',ylim = c(min(df), max(df)),
lwd = i)
}else{
# lines()については後述
lines(x = df$x, y = df[,i+1],
lty = i, lwd = i)
}
}
legend("topleft",
legend = c("1:solid, lwd = 1",
"2:dashed, lwd = 2",
"3:dotted, lwd = 3",
"4:dot dash, lwd = 4",
"5:long dash, lwd = 5",
"6:twodash, lwd = 6"),
lty = c(1,2,3,4,5,6),
lwd = c(1,2,3,4,5,6))
type = 'b'
実際のデータ点がどこかわからない,という場合にはtype='b'
を使うと良い.
plot(v1, type='b')
pch
:点の形を変える点の種類は○だけではない.いっぱいある.色々なウェブサイトでも紹介はされているが,ここでも再掲しよう.
v1 <- rep(1:10, 3)
v2 <- rep(1:3, each=10)
pch
に数値を指定すると,対応する種類の点で描画してくれる.
plot(v1, v2, pch = 2)
pch
の値も整数ベクトルで指定することができる.例えば,4つの整数を与えると,要素順に点の形が対応していき,足りない分は繰り返される形で点の種類が変わっていく.
plot(v1, v2, pch=c(1,2,3,4))
何種類あるか見てみる.
plot(v1, v2, pch=1:30)
## Warning in plot.xy(xy, type, ...): pch の値 '26' は未実装です
## Warning in plot.xy(xy, type, ...): pch の値 '27' は未実装です
## Warning in plot.xy(xy, type, ...): pch の値 '28' は未実装です
## Warning in plot.xy(xy, type, ...): pch の値 '29' は未実装です
## Warning in plot.xy(xy, type, ...): pch の値 '30' は未実装です
警告が出てきたが,25の数値まで実装されていることがわかる.
ちなみに,点を文字にすることもできる.
plot(v1, v2, pch = c('a','b','c','d','e','f','g',
'h','i','j','k','m','n','o',
'p','q','r','s','t','u','v'
,'w','x','y','z'))
1文字を越えると,2文字目以降はよしなに消してくれる.
plot(v1, v2, pch = 'abd')
興味のあるイベントがどのタイミングで発生したか,という場合に縦棒「|」を使ったことがあります.
set.seed(100)
v1 <- sample(1:100, 20)
v2 <- rep(1, 20)
plot(v1, v2, pch = '|')
cex
:サイズを変える次は大きさを変えて見る.やはりベクトルで指定する.
v1 <- rep(1:10, 3)
v2 <- rep(1:3, each=10)
plot(v1, v2, pch=19, cex=1:30)
10でも相当でかい.ちなみにこの引数は小数点もカバーしている.
plot(v1, v2, pch=19, cex=c(1:30)/10)
col
:色を変える形を変えたら次は色を変えたいと思うのは当然ですよね.そのためにはcol
という引数にこれまたベクトルとして色を指定できる.色については
のどれかで指定することができる.ちなみに,混在していてもOK.
v1 <- rep(1:10, 3)
v2 <- rep(1:3, each=10)
plot(v1, v2, pch = 19, col=2)
col
の場合,整数の1から8までが対応しているが,pch
の場合と異なり8を超えた場合は繰り返しで対応されることに注意.
plot(v1, v2, pch=19, col=1:30)
red
, blue
などでも指定できる.かなりの種類の単語が実装されているので,是非一度ここのサイトを見てみてほしい.
plot(v1, v2, pch = 19, col = c('lightblue', 'red', 'blue', 'orange', 'darkred'))
Webに少し詳しい人なら分かると思うが,色は#58FAD0
のようなカラーコードで表される.この形式の文字列でも指定は可能だ.
plot(v1, v2, pch = 19, col = '#58FAD0')
カラーコードに透明度を含めても透明度を調整することができるが,tidyverse
パッケージを使っているならalpha()
関数を使うことでスッキリ記述できる. alpha(色, 透明度)
と指定するだけで良い.
plot(c(1,2), c(1,1), cex = 10, pch = 19, col = c(alpha('orange', 0.9) ,alpha('orange', 0.3)))
点の見た目の次は,表示領域の調整について紹介する.一個前のプロットでは,点が大きすぎて少しはみ出してしまっていた.plot
では表示領域を調節する用の引数が用意されている.
xlim, ylim
\(x,y\)軸それぞれの範囲を指定するためには引数xlim, ylim
を使う.この二つの引数にはc(0, 1)
のように長さ2のベクトルを与える.1つ目の要素が範囲の最小値,2つ目の要素が範囲の最大値を表す.次に,\(x\)軸が-1から3,\(y\)軸が-1から10としたプロットのコードを紹介する.
plot(c(1,2), c(1,1), cex = 10, pch = 19,
col = c(alpha('orange', 0.9) ,alpha('orange', 0.3)),
# x軸の範囲の設定
xlim = c(-1, 3),
# y軸の範囲の設定
ylim = c(-1, 10))
さっきははみ出ていた点が領域内に収まるように調整できた.
タイトルを表示したい場合は,main
という引数を利用する.なぜtitle
という名前でないのかは知らない.
plot(v1, v2, main= 'Zelda')
もちろん日本語も表示できる.windowsの場合は何もなくても表示されるが,Macの場合はおまじないが必要となる.今は思考停止でそういうものだと思ってもらって良いかと思う.おまじない付きのコードは下記.
par(family = 'HiraKakuProN-W3')
plot(v1, v2, main = '日本語だコラ')
これまでのプロットでは,x,y
に与えたベクトルの表示がそのまま軸ラベルに反映されていることに注意してほしい.v1
と与えればそのままV1と表示されているし,c(1,2)
と与えるとそのままc(1,2)と表示される.
これらは,xlab, ylab
という引数に文字列を与えることで変更できる.
plot(v1, v2,
main = 'Zelda',
xlab = 'hello',
ylab = 'world')
回帰直線を引いたりするとき,もちろん一気に描いてくれる関数は便利だしどんどん使って行った方が良いが,使わなくてもできるよということで紹介したい.
基本的には以下の2つの関数で事足りるはずである(これ以外思いつかなかった).
points()
:点を追加lines()
:線を追加points()
# orangeで1を描画
plot(x = c(1,10), y = c(1,10), pch = '1', col = 'darkorange', cex = 3)
# skyblueで2を追記
points(x = 5, y = 5, pch = '2', col = 'skyblue', cex =5)
lines()
線上に追記したい場合はlines()
を使う.
plot(c(1,10,4,6,2,3,6), type='l', col = 'darkorange', lwd = 2)
lines(c(10,4,6,2,3,5))
par()
による重ね書きpar()
関数は,プロットする前に設定を渡す関数である.フォントの指定だったり,描画する領域のサイズなど色々な指定ができる.詳しくは?par
でヘルプを参照されたい.
ここではpar(new=TRUE)
を噛ませることで重ね書きできることを紹介する.使い方は以下の通り.
plot(1,1, pch=19, col="darkorange", cex = 2)
par(new=TRUE) # 次に書くプロットは既にあるプロットの上から書くことにする
plot(1.4, 1, pch = 18, col = "skyblue", cex = 5)
この方法は少し問題がある.それは,上記で紹介したpoints(), lines()
とは異なり,プロットの軸やラベルも含めた全体を上から重ね書きしてしまうところだ.軸ラベルも重なってぐちゃぐちゃになっていることがわかる.この場合は次のようにすると良い.
xlim, ylim
の引数で描画領域を合わせるaxis = FALSE
としてどちらかのプロットの軸を表示させないmain, xlab, ylab
には''
を指定して表示させないなどである.上記のプロットを修正してみる.
plot(1,1, pch=19, col="darkorange", cex = 2,
xlim = c(-1, 2), ylim = c(-1, 2))
par(new=TRUE) # 次に書くプロットは既にあるプロットの上から書くことにする
plot(1.4, 1, pch = 18, col = "skyblue", cex = 5,
xlim = c(-1, 2), ylim = c(-1, 2),
axes = FALSE,
xlab = '', ylab = '')
par(new = TRUE)
による重ね書きのメリットは,y軸が2軸のプロットを描けるところかと思う.この方法は少し応用的な部分になるので割愛する.気になる方は是非調べてみてほしい.
matplot, matpoints, matlines
の紹介最後に,複数系列を一度に指定して描画できるmatplot
系関数を紹介する.
ただ,matpoints, matlines
の使い方はmatplot
とほぼ同じでpoints, lines
と挙動は同じなのでmatplot
のみ説明する.
matplot
この関数はx,y
それぞれデータフレームまたは行列を指定する.この時,列番号に対応して点が描画される.実際,点として描画するだけならあまり恩恵は内容に思えるが,列ごとにpch, col
を変えてくれるのが便利である.もちろん指定もできるし,その場合は列に対応させたベクトルを与えれば良い. y
のみ指定する場合は,x
をindex
で補間してくれるが,ここでは解説のため指定する.
Y <- iris[, -5]
head(Y)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 5.1 3.5 1.4 0.2
## 2 4.9 3.0 1.4 0.2
## 3 4.7 3.2 1.3 0.2
## 4 4.6 3.1 1.5 0.2
## 5 5.0 3.6 1.4 0.2
## 6 5.4 3.9 1.7 0.4
X <- matrix(rep(1:nrow(iris), 4), ncol=4, byrow=FALSE)
head(X)
## [,1] [,2] [,3] [,4]
## [1,] 1 1 1 1
## [2,] 2 2 2 2
## [3,] 3 3 3 3
## [4,] 4 4 4 4
## [5,] 5 5 5 5
## [6,] 6 6 6 6
matplot(x=X, y=Y, col = c('gray', 'darkorange', 'skyblue', 'purple'))
せっかくRを使うなら可視化が手軽にできるということを知って欲しいという思いと,plot
でよくつまづくポイントを解決する情報は目的によって散らばっているなぁと感じたため,自分なりに過去つまづいたことを思い出しながらまとめてみました.まだまだ足りないところや,こうやった方が良い!という点はご指摘いただけると嬉しいです. プログラミング経験のない人にとってはplot
一つとっても慣れるまでが少し大変ですが,誰かの参考になれば嬉しいです!