R ggplot2-线路上方的阴影区域
我有一些数据限制在1:1线以下。我想在一个绘图上演示这一点,通过对线条上方的区域进行轻微着色,将观众的注意力吸引到线条下方的区域 我正在使用R ggplot2-线路上方的阴影区域,r,ggplot2,fill,R,Ggplot2,Fill,我有一些数据限制在1:1线以下。我想在一个绘图上演示这一点,通过对线条上方的区域进行轻微着色,将观众的注意力吸引到线条下方的区域 我正在使用qplot生成图形。很快,我做到了 qplot(x,y)+geom_abline(斜率=1) 但就我个人而言,我不知道如何在不绘制单独对象的情况下轻松地对上述区域进行着色。有没有简单的解决办法 编辑 好的,Joran,下面是一个示例数据集: df=data.frame(x=runif(6,-2,2),y=runif(6,-2,2), var1=re
qplot
生成图形。很快,我做到了
qplot(x,y)+geom_abline(斜率=1)
但就我个人而言,我不知道如何在不绘制单独对象的情况下轻松地对上述区域进行着色。有没有简单的解决办法
编辑 好的,Joran,下面是一个示例数据集:
df=data.frame(x=runif(6,-2,2),y=runif(6,-2,2),
var1=rep(c("A","B"),3),var2=rep(c("C","D"),3))
df_poly=data.frame(x=c(-Inf, Inf, -Inf),y=c(-Inf, Inf, Inf))
这是我用来绘制它的代码(我接受了你的建议,一直在查找ggplot()
):
返回的错误是:“找不到对象‘var1’”有东西告诉我,我没有正确地实现参数…据我所知,除了使用alpha混合填充创建多边形之外,没有其他方法。例如:
df <- data.frame(x=1, y=1)
df_poly <- data.frame(
x=c(-Inf, Inf, -Inf),
y=c(-Inf, Inf, Inf)
)
ggplot(df, aes(x, y)) +
geom_blank() +
geom_abline(slope=1, intercept=0) +
geom_polygon(data=df_poly, aes(x, y), fill="blue", alpha=0.2) +
df基于@Andrie的答案,这里有一个更(但不是完全)通用的解决方案,在大多数情况下,它处理给定线条上方或下方的着色
我没有使用@Andrie引用的方法,因为当在边缘附近添加点时,ggplot
倾向于自动扩展打印范围,这使我遇到了问题。相反,这会根据需要使用Inf
和-Inf
手动构建多边形点。请注意:
- 由于
ggplot
按照点出现的顺序绘制多边形,因此点在数据帧中必须以“正确”的顺序排列。所以仅仅得到多边形的顶点是不够的,它们也必须按顺序排列(顺时针或逆时针)
- 此解决方案假定正在打印的线本身不会导致
ggplot
扩展打印范围。在我的示例中,您将看到我通过随机选择数据中的两个点并绘制穿过它们的线来选择要绘制的线。如果您试图画一条距离其他点太远的线,ggplot
将自动改变绘图范围,并且很难预测它们将是什么
首先,以下是构建多边形数据框的函数:
buildPoly <- function(xr, yr, slope = 1, intercept = 0, above = TRUE){
#Assumes ggplot default of expand = c(0.05,0)
xrTru <- xr + 0.05*diff(xr)*c(-1,1)
yrTru <- yr + 0.05*diff(yr)*c(-1,1)
#Find where the line crosses the plot edges
yCross <- (yrTru - intercept) / slope
xCross <- (slope * xrTru) + intercept
#Build polygon by cases
if (above & (slope >= 0)){
rs <- data.frame(x=-Inf,y=Inf)
if (xCross[1] < yrTru[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(yCross[1],-Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] < yrTru[2]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
}
if (!above & (slope >= 0)){
rs <- data.frame(x= Inf,y= -Inf)
if (xCross[1] > yrTru[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
if (xCross[2] > yrTru[2]){
rs <- rbind(rs,c(yCross[2],Inf),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (above & (slope < 0)){
rs <- data.frame(x=Inf,y=Inf)
if (xCross[1] < yrTru[2]){
rs <- rbind(rs,c(-Inf,Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
if (xCross[2] < yrTru[1]){
rs <- rbind(rs,c(yCross[1],-Inf),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (!above & (slope < 0)){
rs <- data.frame(x= -Inf,y= -Inf)
if (xCross[1] > yrTru[2]){
rs <- rbind(rs,c(-Inf,Inf),c(yCross[2],Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] > yrTru[1]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
}
return(rs)
}
下面是一些结果的例子。如果你发现任何错误,当然,让我知道,这样我可以更新这个答案
编辑
更新以使用OP的示例数据说明解决方案:
set.seed(1)
dat <- data.frame(x=runif(6,-2,2),y=runif(6,-2,2),
var1=rep(c("A","B"),3),var2=rep(c("C","D"),3))
#Create polygon data frame
df_poly <- buildPoly(range(dat$x),range(dat$y))
ggplot(data=dat,aes(x,y)) +
facet_wrap(~var2) +
geom_abline(slope=1,intercept=0,lwd=0.5)+
geom_point(aes(colour=var1),size=3) +
scale_color_manual(values=c("red","blue"))+
geom_polygon(data=df_poly,aes(x,y),fill="blue",alpha=0.2)
set.seed(1)
dat基于以下最小修改版本:
如果线条不是从一个角延伸到另一个角,事情会变得复杂得多,如果线条绘制在另一个数据集的顶部,则很可能会发生这种情况。我做了一点修补,但没有找到一个通用的解决方案。通用的解决方案应该按照感谢您的解决方案中描述的路线进行!我尝试了Andrie的方法,但是我已经指定点由第三个变量qplot(x,y,color=z)
着色,这对geom_polygon()
语句不起作用。这条线的倾斜度也比原点低,这我不知道。有什么想法吗?color
参数通常控制线条颜色。您需要指定fill
来更改多边形的内部。@jslefche我拼凑了一个更一般的答案(至少对于线条而言)…着色点和填充多边形由两种不同的美学(颜色和填充)处理,不应该冲突,因此我怀疑您可能在那里做错了什么。我很乐意提供更多的帮助,但如果没有一个具体的可复制的数据示例,我不能……完成了。我怀疑这是因为我不熟悉ggplot2如何处理这些事情。再次感谢您的帮助,我非常感谢。将color=var1
移动到geom_point
:geom_point(aes(color=var1),…)
。此外,如果您希望在每个面中使用不同的填充多边形,请注意,您必须为每个面创建一个单独的数据框,并将它们组合成一个包含var2
因子的数据框,以便ggplot
知道应用于每个面的是哪一个;希望这会有帮助…@Joran--当然有,谢谢你的帮助!感谢您对一个老问题的精彩回答。:-)
#Generate some data
dat <- data.frame(x=runif(10),y=runif(10))
#Select two of the points to define the line
pts <- dat[sample(1:nrow(dat),size=2,replace=FALSE),]
#Slope and intercept of line through those points
sl <- diff(pts$y) / diff(pts$x)
int <- pts$y[1] - (sl*pts$x[1])
#Build the polygon
datPoly <- buildPoly(range(dat$x),range(dat$y),
slope=sl,intercept=int,above=FALSE)
#Make the plot
p <- ggplot(dat,aes(x=x,y=y)) +
geom_point() +
geom_abline(slope=sl,intercept = int) +
geom_polygon(data=datPoly,aes(x=x,y=y),alpha=0.2,fill="blue")
print(p)
set.seed(1)
dat <- data.frame(x=runif(6,-2,2),y=runif(6,-2,2),
var1=rep(c("A","B"),3),var2=rep(c("C","D"),3))
#Create polygon data frame
df_poly <- buildPoly(range(dat$x),range(dat$y))
ggplot(data=dat,aes(x,y)) +
facet_wrap(~var2) +
geom_abline(slope=1,intercept=0,lwd=0.5)+
geom_point(aes(colour=var1),size=3) +
scale_color_manual(values=c("red","blue"))+
geom_polygon(data=df_poly,aes(x,y),fill="blue",alpha=0.2)
library(ggplot2)
library(tidyr)
library(dplyr)
buildPoly <- function(slope, intercept, above, xr, yr){
# By Joran Elias, @joran https://stackoverflow.com/a/6809174/1870254
#Find where the line crosses the plot edges
yCross <- (yr - intercept) / slope
xCross <- (slope * xr) + intercept
#Build polygon by cases
if (above & (slope >= 0)){
rs <- data.frame(x=-Inf,y=Inf)
if (xCross[1] < yr[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(yCross[1],-Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] < yr[2]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
}
if (!above & (slope >= 0)){
rs <- data.frame(x= Inf,y= -Inf)
if (xCross[1] > yr[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
if (xCross[2] > yr[2]){
rs <- rbind(rs,c(yCross[2],Inf),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (above & (slope < 0)){
rs <- data.frame(x=Inf,y=Inf)
if (xCross[1] < yr[2]){
rs <- rbind(rs,c(-Inf,Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
if (xCross[2] < yr[1]){
rs <- rbind(rs,c(yCross[1],-Inf),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (!above & (slope < 0)){
rs <- data.frame(x= -Inf,y= -Inf)
if (xCross[1] > yr[2]){
rs <- rbind(rs,c(-Inf,Inf),c(yCross[2],Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] > yr[1]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
}
return(rs)
}
GeomSection <- ggproto("GeomSection", GeomPolygon,
default_aes = list(fill="blue", size=0, alpha=0.2, colour=NA, linetype="dashed"),
required_aes = c("slope", "intercept", "above"),
draw_panel = function(data, panel_params, coord) {
ranges <- coord$backtransform_range(panel_params)
data$group <- seq_len(nrow(data))
data <- data %>% group_by_all %>% do(buildPoly(.$slope, .$intercept, .$above, ranges$x, ranges$y)) %>% unnest
GeomPolygon$draw_panel(data, panel_params, coord)
}
)
geom_section <- function (mapping = NULL, data = NULL, ..., slope, intercept, above,
na.rm = FALSE, show.legend = NA) {
if (missing(mapping) && missing(slope) && missing(intercept) && missing(above)) {
slope <- 1
intercept <- 0
above <- TRUE
}
if (!missing(slope) || !missing(intercept)|| !missing(above)) {
if (missing(slope))
slope <- 1
if (missing(intercept))
intercept <- 0
if (missing(above))
above <- TRUE
data <- data.frame(intercept = intercept, slope = slope, above=above)
mapping <- aes(intercept = intercept, slope = slope, above=above)
show.legend <- FALSE
}
layer(data = data, mapping = mapping, stat = StatIdentity,
geom = GeomSection, position = PositionIdentity, show.legend = show.legend,
inherit.aes = FALSE, params = list(na.rm = na.rm, ...))
}
set.seed(1)
dat <- data.frame(x=runif(6,-2,2),y=runif(6,-2,2),
var1=rep(c("A","B"),3),var2=rep(c("C","D"),3))
ggplot(data=dat,aes(x,y)) +
facet_wrap(~var2) +
geom_abline(slope=1,intercept=0,lwd=0.5)+
geom_point(aes(colour=var1),size=3) +
scale_color_manual(values=c("red","blue"))+
geom_section(slope=1, intercept=0, above=TRUE)
ggplot(data=dat,aes(x,y)) +
facet_wrap(~var2) +
geom_abline(slope=1,intercept=0,lwd=0.5)+
geom_point(aes(colour=var1),size=3) +
scale_color_manual(values=c("red","blue"))+
geom_section(data=data.frame(slope=c(-1,1), above=c(FALSE,TRUE), selected=c("selected","selected 2")),
aes(slope=slope, above=above, intercept=0, fill=selected), size=1) +
expand_limits(x=3)