更改 ggplot2 中条形图的绘制顺序
Change plotting order of bars in ggplot2
我正在为修订后的手稿准备一个附录图,我需要在其中提供年份和地点之间几个变量的年内范围(变异性)的信息。
我认为最简洁的方法(我有 7 个站点、21 年和 5 个变量...)是使用 coord_polar
使用玫瑰图。然而,我偶然发现了一些让我对 ggplot 感到沮丧的东西——默认排序假设。虽然因子很容易根据某个值重新排序,但这似乎只适用于 fixed 方式:据我所知,该顺序需要应用于整个数据框。
在这个图中,顺序需要取决于一个值,该值在不同年份之间变化,因此 colour
和 fill
值需要在面板内按绘图顺序更改。
为了演示,我创建了一个编码如下的可重现示例(图中显示了它不应该工作的方式)
基本上,我总是需要首先绘制给定年份内具有最小值的站点(在中心),然后向外绘制其他站点的价值增加,按原始值的顺序(见order
和 diff
数据框的列)。换句话说,有些年份A点在中心,有些年份C点在中心,等等
如有任何帮助,我们将不胜感激。
library('ggplot2')
library('reshape2')
library("plyr")
## reproducible example of problem: create dummy data
madeup <- data.frame(Year = rep(2000:2015, each=20), Site=rep(c("a","b","c","d"), each=5, times=16),
var1 = rnorm(n=16*20, mean=20, sd=5), var2= rnorm(n=16*20, mean=50, sd=1))
## create ranges of the data by Year and Site
myRange <- function(dat) {range=max(dat, na.rm=TRUE)-min(dat,na.rm = TRUE)}
vardf <- ddply(madeup, .(Site, Year), summarise, var1=myRange(var1),
var2=myRange(var2))
varmelt <- melt(vardf, id.vars = c("Site","Year"))
varmelt$Site <- as.character(varmelt$Site) # this to preserve the new order when rbind called
varmelt <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {x <- x[order(x$value),]
x$order <- 1:nrow(x)
return(x)})
varmelt <- do.call(rbind, varmelt)
## create difference between these values so that each site gets plotted cumulatively on the rose plot
## (otherwise areas close to the centre become uninterpretable)
vartest <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {
x$diff <- c(x$value[1], diff(x$value))
return(x)
})
vartest <- do.call(rbind,vartest)
## plot rose plot to display how ranges in variables vary by year and between sites
## for this test example we'll just take one variable, but the idea is to facet by variable
max1 <- max(vartest$value[vartest$variable=='var1'])
yearlength <- length(2000:2015)
ggplot(vartest[vartest$variable=="var1",], aes(x=factor(Year), y=diff)) +
theme_bw() +
geom_hline(yintercept = seq(0,max1, by=1), size=0.3, col="grey60",lty=3) +
geom_vline(xintercept=seq(1,yearlength,1), size=0.3, col='grey30', lty=2) +
geom_bar(stat='identity', width=1, size=0.5, aes(col=Site, fill=Site)) +
scale_x_discrete() +
coord_polar() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
您可以从最大站点的单个地块开始,然后像这样在顶部分层较小的站点:
a <- ggplot(vartest[vartest$variable=="var1"& vartest$order==4,], aes(x=factor(Year), y=value,group=order)) +
theme_bw() +
geom_hline(yintercept = seq(0,max1, by=1), size=0.3, col="grey60",lty=3) +
geom_vline(xintercept=seq(1,yearlength,1), size=0.3, col='grey30', lty=2) +
geom_bar(stat='identity', width=1, size=0.5, aes(col=Site, fill=Site)) +
scale_x_discrete() +
coord_polar() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
b <- a + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==3,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
c <- b + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==2,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
c + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==1,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
这会产生以下结果:
这是你想要的吗?
只要您不使用堆叠条形图(position = "stack"
,这是 geom_bar
的默认设置),ggplot2
实际上会 use the order of the rows in your data for the plotting order。因此,您需要做的就是使用 y-axis 的原始值(而不是累积差值)和 position = "identity"
,然后 从最大到最小对数据进行排序 value
绘图前:
ordered_data <- vartest[order(-vartest$value), ]
ggplot(ordered_data, aes(factor(Year), value)) +
geom_col(aes(fill = Site), position = "identity", width = 1) +
coord_polar() +
facet_wrap(~ variable)
由 reprex package (v0.2.0) 创建于 2018-02-17。
PS。为示例生成随机数据时,请考虑使用 set.seed
以便准确重现您的结果。
我正在为修订后的手稿准备一个附录图,我需要在其中提供年份和地点之间几个变量的年内范围(变异性)的信息。
我认为最简洁的方法(我有 7 个站点、21 年和 5 个变量...)是使用 coord_polar
使用玫瑰图。然而,我偶然发现了一些让我对 ggplot 感到沮丧的东西——默认排序假设。虽然因子很容易根据某个值重新排序,但这似乎只适用于 fixed 方式:据我所知,该顺序需要应用于整个数据框。
在这个图中,顺序需要取决于一个值,该值在不同年份之间变化,因此 colour
和 fill
值需要在面板内按绘图顺序更改。
为了演示,我创建了一个编码如下的可重现示例(图中显示了它不应该工作的方式)
基本上,我总是需要首先绘制给定年份内具有最小值的站点(在中心),然后向外绘制其他站点的价值增加,按原始值的顺序(见order
和 diff
数据框的列)。换句话说,有些年份A点在中心,有些年份C点在中心,等等
如有任何帮助,我们将不胜感激。
library('ggplot2')
library('reshape2')
library("plyr")
## reproducible example of problem: create dummy data
madeup <- data.frame(Year = rep(2000:2015, each=20), Site=rep(c("a","b","c","d"), each=5, times=16),
var1 = rnorm(n=16*20, mean=20, sd=5), var2= rnorm(n=16*20, mean=50, sd=1))
## create ranges of the data by Year and Site
myRange <- function(dat) {range=max(dat, na.rm=TRUE)-min(dat,na.rm = TRUE)}
vardf <- ddply(madeup, .(Site, Year), summarise, var1=myRange(var1),
var2=myRange(var2))
varmelt <- melt(vardf, id.vars = c("Site","Year"))
varmelt$Site <- as.character(varmelt$Site) # this to preserve the new order when rbind called
varmelt <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {x <- x[order(x$value),]
x$order <- 1:nrow(x)
return(x)})
varmelt <- do.call(rbind, varmelt)
## create difference between these values so that each site gets plotted cumulatively on the rose plot
## (otherwise areas close to the centre become uninterpretable)
vartest <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {
x$diff <- c(x$value[1], diff(x$value))
return(x)
})
vartest <- do.call(rbind,vartest)
## plot rose plot to display how ranges in variables vary by year and between sites
## for this test example we'll just take one variable, but the idea is to facet by variable
max1 <- max(vartest$value[vartest$variable=='var1'])
yearlength <- length(2000:2015)
ggplot(vartest[vartest$variable=="var1",], aes(x=factor(Year), y=diff)) +
theme_bw() +
geom_hline(yintercept = seq(0,max1, by=1), size=0.3, col="grey60",lty=3) +
geom_vline(xintercept=seq(1,yearlength,1), size=0.3, col='grey30', lty=2) +
geom_bar(stat='identity', width=1, size=0.5, aes(col=Site, fill=Site)) +
scale_x_discrete() +
coord_polar() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
您可以从最大站点的单个地块开始,然后像这样在顶部分层较小的站点:
a <- ggplot(vartest[vartest$variable=="var1"& vartest$order==4,], aes(x=factor(Year), y=value,group=order)) +
theme_bw() +
geom_hline(yintercept = seq(0,max1, by=1), size=0.3, col="grey60",lty=3) +
geom_vline(xintercept=seq(1,yearlength,1), size=0.3, col='grey30', lty=2) +
geom_bar(stat='identity', width=1, size=0.5, aes(col=Site, fill=Site)) +
scale_x_discrete() +
coord_polar() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
b <- a + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==3,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
c <- b + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==2,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
c + geom_bar(data = vartest[vartest$variable=="var1"& vartest$order==1,],
stat='identity', width=1, size=0.5, aes(x=factor(Year), y=value,col=Site, fill=Site))
这会产生以下结果:
这是你想要的吗?
只要您不使用堆叠条形图(position = "stack"
,这是 geom_bar
的默认设置),ggplot2
实际上会 use the order of the rows in your data for the plotting order。因此,您需要做的就是使用 y-axis 的原始值(而不是累积差值)和 position = "identity"
,然后 从最大到最小对数据进行排序 value
绘图前:
ordered_data <- vartest[order(-vartest$value), ]
ggplot(ordered_data, aes(factor(Year), value)) +
geom_col(aes(fill = Site), position = "identity", width = 1) +
coord_polar() +
facet_wrap(~ variable)
由 reprex package (v0.2.0) 创建于 2018-02-17。
PS。为示例生成随机数据时,请考虑使用 set.seed
以便准确重现您的结果。