[分享] 柱状图的低阶绘图范例

楼主: 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