ggplot2 - 阴影区域在线以上 [英] ggplot2 - Shade area above line

查看:139
本文介绍了ggplot2 - 阴影区域在线以上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些限制在1:1以下的数据。我会在一个情节上通过轻微地遮住线条上方的区域来展示这一点,以便将观众的注意力吸引到线条下方的区域。



我正在使用 qplot 来生成图形。很快,我有;

qplot(x,y)+ geom_abline(斜率= 1)



但在我的生活中,无法弄清楚如何轻松遮蔽上述区域而不用绘制单独的对象。有没有简单的解决这个问题?






编辑



好了,Joran,这里是一个示例数据集:

$ p $ 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()):

  ggplot(df,aes(x,y ,颜色= VAR1))+ 
facet_wrap(〜VAR2)+
geom_abline(斜率= 1,截距= 0,LWD = 0.5)+
geom_point(大小= 3)+
scale_color_manual(values = c(red,blue))+
geom_polygon(data = df_poly,aes(x,y),fill =blue,alpha = 0.2)

返回的错误是:object'var1'not found东西告诉我,我错误地实现了参数.. 。

解决方案

建立在@Andrie这里的答案是在大多数情况下处理大于或小于给定行的阴影的更多(但不是完全)通用解决方案。



我没有使用@Andrie参考这里,因为我遇到了 ggplot 在边缘附近添加点时自动扩展绘图范围的趋势。相反,这会根据需要使用 Inf -Inf 手动构建多边形点。一些注释:


  • 数据框中的点必须处于正确顺序,因为 ggplot 按照点出现的顺序绘制多边形。因此,获取多边形的顶点是不够的,它们必须是顺序的(顺时针或逆时针)。

  • 这个解决方案假设你绘图本身不会导致 ggplot 来扩展绘图范围。在我的示例中,您会看到我通过在数据中随机选择两个点并通过它们绘制线来选取一条线进行绘制。如果你试图画出一条离你剩余点太远的线, ggplot 会自动改变绘图范围,并且很难预测它们会是什么。 / b>


首先,下面是构建多边形数据框的函数:

  buildPoly < -  function(xr,yr,slope = 1,intercept = 0,above = TRUE){
#Assumes ggplot default = c(0.05, 0)
xrTru <-xr + 0.05 * diff(xr)* c(-1,1)
yrTru -yr + 0.05 * diff(yr)* c(-1,1)

#找到线越过绘图边缘的位置
yCross < - (yrTru - 截距)/斜率
xCross < - (slope * xrTru)+截距

#按实例构建多边形
if(above&(slope> = 0)){
rs< - data.frame(x = -Inf,y = Inf)
如果(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]< (rs,c(Inf,xCross [2]),c(Inf,Inf))
}
else {
如果(!above&(slope> = 0)){$ b $(rs,c(yCross [2],Inf))
}
}
如果(xCross [1]> yrTru [1]){
rs <-rbind(rs,c(t)),则b rs < - data.frame(x = Inf,y = -Inf) -Inf,-Inf),c(-Inf,xCross [1]))
}
else {
rs < - rbind(rs,c(yCross [1], - Inf如果(xCross [2]> yrTru [2]){
rs <-rbind(rs,c(yCross [2],Inf),c(Inf) ,Inf))
}
else {
rs< - rbind(rs,c(Inf,xCross [2]))
}
} $ b $ (xCross [1] rs < - data.frame(x = Inf,y = Inf) ){
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 {$ b (b,b,b,b,b,b,b) $ b RS< - data.frame(X = -Inf,Y = -Inf)
如果(XCROSS [1]> yrTru [2]){
RS< - rbind(RS, c(-Inf,Inf),c(yCross [2],Inf))
}
else {
rs < - rbind(rs,c(-Inf,xCross [1]如果(xCross [2]> yrTru [1]){
rs <-rbind(rs,c(Inf,xCross [2]),c(Inf) ,-Inf))
}
else {
rs < - rbind(rs,c(yCross [1], - Inf))
}
}

return(rs)
}

期望x和您的数据的y范围(如 range()),您要绘制的线的斜率和截距,以及是否要遮蔽线的上方或下方。以下是我用来生成以下四个示例的代码:

 #生成一些数据
dat< - data。 frame(x = runif(10),y = runif(10))

#选择两个点来定义行
pts <-dat [sample(1:nrow数据),size = 2,replace = FALSE),]

#通过这些点的线的斜率和截距
sl < - diff(pts $ y)/ diff(pts $ x )
int< - pts $ y [1] - (sl * pts $ x [1])$ ​​b
$ b#构建多边形
datPoly< - buildPoly(range( dat $ x),范围(dat $ y),
slope = sl,intercept = int,above = FALSE)

#绘制图
p < - ggplot(dat ,aes(x = x,y = y))+
geom_point()+
geom_abline(斜率= sl,截距= int)+
geom_polygon(data = datPoly,aes(x = x,y = y),alpha = 0.2,fill =blue)
print(p)

以下是结果的一些例子。如果你发现任何错误,当然,让我知道,以便我可以更新这个答案...







p>




更新以解释使用OP的示例数据的解决方案:

< $ p $ lt; code> 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))
#创建多边形数据帧
df_poly< - buildPoly(范围(dat $ x),范围(dat $ y))

ggplot(data = dat,aes(x,y))+
facet_wrap(〜var2)+
geom_abline(斜率= 1,截距= 0,lwd = 0.5)+
geom_point(aes(color = var1),size = 3)+
scale_color_manual (值= C( 红, 蓝 ))+
geom_polygon(data = df_poly,aes(x,y),fill =blue,alpha = 0.2)

,并产生以下输出:




I have some data that is constrained below a 1:1 line. I would to demonstrate this on a plot by lightly shading the area ABOVE the line, to draw the attention of the viewer to the area beneath the line.

I'm using qplot to generate the graphs. Quickly, I have;

qplot(x,y)+geom_abline(slope=1)

but for the life of me, can't figure out how to easily shade the above area without plotting a separate object. Is there an easy fix for this?


EDIT

Ok, Joran, here is an example data set:

 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))

and here is the code that I'm using to plot it (I took your advice and have been looking up ggplot()):

ggplot(df,aes(x,y,color=var1))+
 facet_wrap(~var2)+
 geom_abline(slope=1,intercept=0,lwd=0.5)+
 geom_point(size=3)+
 scale_color_manual(values=c("red","blue"))+
 geom_polygon(data=df_poly,aes(x,y),fill="blue",alpha=0.2)

The error kicked back is: "object 'var1' not found" Something tells me that I'm implementing the argument incorrectly...

解决方案

Building on @Andrie's answer here is a more (but not completely) general solution that handles shading above or below a given line in most cases.

I did not use the method that @Andrie referenced here since I ran into issues with ggplot's tendency to automatically extend the plot extents when you add points near the edges. Instead, this builds the polygon points manually using Inf and -Inf as needed. A few notes:

  • The points have to be in the 'correct' order in the data frame, since ggplot plots the polygon in the order that the points appear. So it's not enough to get the vertices of the polygon, they must be ordered (either clockwise or counterclockwise) as well.

  • This solution assumes that the line you are plotting does not itself cause ggplot to extend the plot range. You'll see in my example that I pick a line to draw by randomly choosing two points in the data and drawing the line through them. If you try to draw a line too far away from the rest of you points, ggplot will automatically alter the plot ranges, and it becomes hard to predict what they will be.

First, here's the function that builds the polygon data frame:

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)
}

It expects the x and y ranges of your data (as in range()), the slope and intercept of the line you are going to plot, and whether you want to shade above or below the line. Here's the code I used to generate the following four examples:

#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)    

And here are some examples of the results. If you find any bugs, of course, let me know so that I can update this answer...

EDIT

Updated to illustrate solution using OP's example data:

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)

and this produces the following output:

这篇关于ggplot2 - 阴影区域在线以上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆