[分享] 柱狀圖的低階繪圖範例

作者: andrew43 (討厭有好心推文後刪文者)   2015-12-16 01:22:28
因為常被問到,也好久沒來「上班」了,發一個教學文。
問題:怎麼畫出像下面這種圖?也就是二因子的柱狀圖。
http://imgur.com/riRkMGA
比較麻煩的部份是:
1. 同時有線條填色與顏色填色
2. 放在外部的圖示
3. 有 error bar
以下請見該圖的原始碼。
# 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()
[關鍵字]: 柱狀圖 線條填色 外部圖示
作者: abcggg (小雞逼逼)   2014-02-16 08:35:00
推 感謝分享!
作者: celestialgod (天)   2015-12-16 02:21:00
作者: ayugioh2003 (小麥)   2015-12-18 23:22:00
作者: cywhale (cywhale)   2015-12-19 23:42:00
push~~ practical issue~~

Links booklink

Contact Us: admin [ a t ] ucptt.com