R 繪圖時的柱狀圖如何加上誤差線?如何使用線條填色?如何把圖示放在外部?本文提供一個例子。
以下是產生上圖的原始碼。
# dat 為輸入的二因子資料 | |
set.seed(1234) | |
dat <- data.frame( | |
y = rnorm(80, 5, 2), | |
x1 = gl(2, 40, labels = c("A","B")), | |
x2 = gl(4, 10, labels = c("1","2","3","4")) | |
) | |
# 利用 tapply 求出各組之 mean 和 sd | |
y.mean <- with(dat, tapply(y, paste(x1, x2, sep="."), mean)) | |
y.sd <- with(dat, tapply(y, paste(x1, x2, sep="."), sd)) | |
# 為了方便之後畫圖,把 y.mean 和 y.sd 轉成矩陣 | |
# 矩陣各列表示 X2,各欄表示 X1 | |
Y <- matrix(y.mean, 4) | |
E <- matrix(y.sd, 4) | |
colnames(Y) <- colnames(E) <- c("A", "B") | |
rownames(Y) <- rownames(E) <- c("1", "2", "3", "4") | |
# 接下來就開始畫圖 | |
# 過程小小複雜,若有不了解可以逐步進行並觀看圖怎麼變化 | |
# 先開一個畫布 | |
# 因為我想把圖示畫在右側外部,所以 mar 和 xpd 要自行設定 | |
dev.new(width = 5, height = 5) | |
par(mar=c(4, 4, 1, 10) + 0.1, xpd = T) | |
# 接下來是畫上柱狀圖主體 | |
# 因為 X2 == "4" 柱體要畫成同時有「斜線填色」和「顏色填色」 | |
# 所以 barplot 要畫二次 | |
# 以下是第一次,只畫主要文字、框線和顏色填色 | |
# 我習慣先自行算好 ylim | |
# 注意 barplot 的回傳值被我定義為變數 bp(之後有用) | |
bp <- barplot( | |
Y, beside = T, | |
xaxt = "n", ylim = c(0,10), | |
ylab = "Title for y-axis (dat$y)", xlab = "Title for x-axis (dat$x1)", | |
col = c(0,3,0,"yellow") | |
) | |
# 接下來是疊上 X2 == "4" 柱體的「斜線填色」 | |
# 上一步已經畫過的就不要再畫一次 | |
# 只要畫上 X2 == "4" 柱體的「斜線填色」即可 | |
# 注意到 add = T 就是疊圖的作用 | |
barplot( | |
Y, beside = T, | |
xaxt = "n", ylim = c(0,10), yaxt = "n", | |
ylab = "", xlab = "", | |
col = c(0,1,1,1), density = c(0,0,25,15), angle = c(NULL,NULL,45,135), | |
border = c(0,0,0,0), | |
add = T | |
) | |
# 這裡只是示範怎麼用 axis() | |
axis(1, colMeans(bp), c("A", "B"), tick = F) | |
# 這裡是畫「只向上方延伸的 error bar」 | |
# 這時候 bp 的值(也就是每個柱的橫軸位置)就很有用了 | |
arrows(bp, Y, bp, Y+E, length = 0.1, angle = 90) | |
# 當然也可以再補畫上「向下方延伸的 error bar」 | |
# 但這個例子不太適當就不做了 | |
# 有需要的話請再加入 | |
# arrows(bp, Y, bp, Y-E, length = 0.1, angle = 90) | |
# 接下來是畫圖示 | |
# 這裡示範如何把圖示畫在右側外部 | |
# 需要與前面 par() 配合才行 | |
# 也因為 X2 == "4" 柱體的同時有「斜線填色」和「顏色填色」 | |
# 所以 legend() 一樣要畫兩次 | |
# 第一次負責文字、線框、顏色填色 | |
legend( | |
"right", | |
legend = c("1", "2", "3", "4"), | |
fill = c(0,3,0,"yellow"), | |
title = "Row name (dat$x2)", | |
text.width = 5.5, | |
box.lwd = 1, col = c(1,1,1,1), | |
inset=c(-0.9,0) | |
) | |
# 第二次負責 X2 == "4" 的斜線填色就好 | |
# 重覆的東西都不要再畫 | |
# 注意兩次畫 legend 要完全重疊才會成功 | |
# 因此我定了 text.width 之類看似多餘的參數 | |
legend( | |
"right", | |
legend = c("", "", "", ""), | |
fill = c(0,0,1,1), | |
border = c(0,0,0,0), | |
density = c(0,0,25,15), angle = c(NULL,NULL,45,135), | |
title = "", | |
text.width = 5.5, | |
box.lwd = 0, col = c(0,0,0,0), | |
inset=c(-0.9,0) | |
) | |
# 畫個框框 | |
box() |