2014-07-06 5 views
3

내 플롯에는 원점에서 오는 두 개의 광선이 있습니다. 광선 1에서 광선 2로가는 영역을 시계 반대 방향으로 음영 처리하고 싶습니다. geom_polygon을 사용해야 할 수도 있습니다. 임의의 두 개의 광선에 대해이 작업을 수행 할 수 있기를 원합니다.하지만이를 파악할 수는 없습니다.r - ggplot2 : 두 광선 사이의 영역 채우기

* 나는 직교 좌표를 사용하고 싶습니다. 여기

가 무슨 뜻인지의 예 :이 예를 들어

d <- data.frame() 

base <- ggplot(d) + xlim(-5, 5) + ylim(-5, 5) + geom_blank() 

ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4)) 
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5)) 

shading <- geom_polygon(data=data.frame(x=c(0,5,5,0), y=c(0,4,5,5)), 
    aes(x,y), fill="blue", alpha=0.2) 

base + ray1 + ray2 + shading 

, 나는 검사에 의해 다각형의 정점을 얻을 수 있었다, 그러나 나는 광선의 여러 무작위 쌍을 생성 할 것이고, I 이 과정을 매번 수동으로 진행하고 싶지는 않습니다.

enter image description here

어떤 조언을 ?

답변

6

나는 그것이 더 간단 할 것이라고 생각했다; 하지만이 추악한 솔루션에 도착했습니다. 여기에 한계를 따라 모든 교차점이 base

findslice<-function(seg1, seg2, base=NULL, lim=getlims(base)) { 
    getlims<-function(x) { 
     list(y=x$scales$get_scales("y")$limits, 
     x=x$scales$get_scales("x")$limits) 
    } 
    gethit<-function(seg, lim) { 
     with(seg$mapping, { 
      x<-eval(x); y<-eval(y); 
      xend<-eval(xend); yend<-eval(yend); 
      dx<-(xend-x); dy<-(yend-y) 
      bx<-ifelse(dx>0,max(lim$x), min(lim$x)) 
      by<-ifelse(dy>0,max(lim$y), min(lim$y)) 
      sx<-ifelse(dx>0,1, 3) 
      sy<-ifelse(dy>0,2, 4) 
      if(identical(dx,0)) { 
       return(list(x=x,y=by, side=sy)) 
      } 
      if (identical(dy,0)) { 
       return(list(x=bx,y=y, side=sx)) 
      } 
      nx<-bx 
      ny<-(y+dy)*(nx-x)/dx 
      side<-sx 
      if (abs(ny)>abs(by)) { 
       ny<-by 
       nx<-(x+dx)*(ny-y)/dy 
       side<-sy 
      } 
      return(list(x=nx, y=ny, side=side)) 
     }) 
    } 
    p1<-gethit(seg1, lim) 
    p2<-gethit(seg2, lim) 
    side<-p1$side 
    corners<-data.frame(x=lim$x[c(2,1,1,2)], y=lim$y[c(2,2,1,1)]) 
    r<-data.frame(x=c(seg1$mapping$x, p1$x), y=c(seg1$mapping$y, p1$y)) 
    while(side != p2$side) { 
     r<-rbind(r, corners[side, ]) 
     side <- (side %% 4) +1 
    } 
    r<-rbind(r, data.frame(x=p2$x, y=p2$y)) 
    r 
} 

이것은 당신이 당신의 다각형 플로팅에 필요한 data.frame을 만듭니다에 정의 된 계산하는 의미 도우미 함수입니다. 예를 들어

base <- ggplot(d) + xlim(-5, 5) + ylim(-5, 5) + geom_blank() 

ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4)) 
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5)) 

shading <- geom_polygon(data=findslice(ray1, ray2, base), 
    aes(x,y), fill="blue", alpha=0.2) 

base + ray1 + ray2 + shading + ggtitle("Take 1") 

한계를 초과 한 다음 가장자리를 감싸는 것이 좋습니다. 따라서 다른 예

ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4)) 
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5)) 

shading <- geom_polygon(data=findslice(ray1, ray2, base), 
    aes(x,y), fill="blue", alpha=0.2) 

base + ray1 + ray2 + shading + ggtitle("Take 2") 

enter image description here

+0

고마워요! 이것은 내가 찾고있는 것입니다! –

6

이것은 아마도 약간 버그와 clunky입니다. 더 똑똑한 사람들로부터 좀 더 우아한 솔루션을보고 싶습니다.

어떻게 가장자리를 처리 할 것인지 명확하지 않습니다. 참조 예

enter image description here

또는 같은

shade_segs <- function(ray1, ray2, xlim = c(-5, 5), ylim = xlim) { 
    ray <- data.frame(x = c(ray1[1], pmin(ray1[3], xlim[2]), 
          pmin(ray1[3], ylim[2]), ray2[3]), 
        y = c(ray2[1], ray1[4], 
          ## how to handle the edges? : 
          pmin(ray2[4], xlim[2]), pmin(ray2[4], ylim[2]))) 
          # pmin(ray1[4], xlim[2]), pmin(ray2[4], ylim[2]))) 
    # print(ray) 
    require(ggplot2) 

    ggplot() + xlim(xlim[1], xlim[2]) + ylim(ylim[1], ylim[2]) + 
    geom_segment(aes_string(x = ray1[1], y = ray1[2], 
        xend = ray1[3], yend = ray1[4])) + 
    geom_segment(aes_string(x = ray2[1], y = ray2[2], 
        xend = ray2[3], yend = ray2[4])) + 
    geom_polygon(data = ray, aes(x = x, y = y), fill = "blue", alpha = 0.2) + 
    theme_bw() 
} 

library(gridExtra) 
## c(x0, y0, x1, y1) 
l <- list(shade_segs(ray1 = c(0, 0, 5, 4), 
        ray2 = c(0, 0, 0, 5)), 
      shade_segs(ray1 = c(0, 0, 2.5, 2.5), 
        ray2 = c(0, 0, 1, 5)), 
      shade_segs(ray1 = c(0, 0, -1, 5), 
        ray2 = c(0, 0, -.5, 5)), 
      shade_segs(ray1 = c(0, 0, -3, 5), 
        ray2 = c(0, 0, -.5, -5))) 
(do.call(arrangeGrob, c(l, list(nrow = 2, ncol = 2)))) 
:

shade_segs <- function(ray1, ray2, xlim = c(-5, 5), ylim = xlim) { 
    ray <- data.frame(x = c(ray1[1], pmin(ray1[3], xlim[2]), 
          pmin(ray1[3], ylim[2]), ray2[3]), 
        y = c(ray2[1], ray1[4], 
          ## how to handle the edges? : 
          # pmin(ray2[4], xlim[2]), pmin(ray2[4], ylim[2]))) 
          pmin(ray1[4], xlim[2]), pmin(ray2[4], ylim[2]))) 
    # print(ray) 
    require(ggplot2) 

    ggplot() + xlim(xlim[1], xlim[2]) + ylim(ylim[1], ylim[2]) + 
    geom_segment(aes_string(x = ray1[1], y = ray1[2], 
        xend = ray1[3], yend = ray1[4])) + 
    geom_segment(aes_string(x = ray2[1], y = ray2[2], 
        xend = ray2[3], yend = ray2[4])) + 
    geom_polygon(data = ray, aes(x = x, y = y), fill = "blue", alpha = 0.2) + 
    theme_bw() 
} 

library(gridExtra) 
## c(x0, y0, x1, y1) 
l <- list(shade_segs(ray1 = c(0, 0, 5, 4), 
        ray2 = c(0, 0, 0, 5)), 
      shade_segs(ray1 = c(0, 0, 2.5, 2.5), 
        ray2 = c(0, 0, 1, 5)), 
      shade_segs(ray1 = c(0, 0, -1, 5), 
        ray2 = c(0, 0, -.5, 5)), 
      shade_segs(ray1 = c(0, 0, -3, 5), 
        ray2 = c(0, 0, -.5, -5))) 
(do.call(arrangeGrob, c(l, list(nrow = 2, ncol = 2)))) 

enter image description here

두 번째는 나에게 더 의미가 있습니다.

+0

Hehe, 그리고 당신은 당신의 생각에 clunky했다. ggplot이 폴리곤의 일부가 플롯 한도를 벗어나면 그 플롯을 포기하지 않았 더라면 좋겠습니다. – MrFlick

+1

이 너와 같이 처음에는 간단하고 시간이 지나면 간단하다고 생각했다 .... 그리고 너는'* lim'을'coord_cartesian()'으로 바꾸어서, 그것을 정확하게 이해할 수있다. – rawr

+0

고마워! 당신이 준 예제는 매우 유용합니다! –

4

광선이 항상 이하 보다 180 도의 각도를 형성하는 일이있는 경우에 부분 용액의 볼록 선체를 형성하는 점을 취할이다 다각형과 그 음모.

enter image description here

이 지역은 당신이 광선은 원점에서 것을 지정된 이후는 간단하다 플롯 영역의 외부를 확장 할 경우

rayX <- c(0,5,0,0) 
rayY <- c(0,4,0,5) 
rays <- data.frame(cbind(rayX,rayY)) 
Mypoly <- rays[chull(rays),] 

shading2 <- geom_polygon(data=Mypoly, aes(rayX,rayY), fill="blue", alpha=0.2) 

base + ray1 + ray2 + shading2 
.볼록 선체에 플롯 제한 범위보다 큰 상수를 곱하면됩니다 (그리고 coord_cartesian을 사용하여 폴리곤이 플롯에서 버려지지 않도록하십시오).

enter image description here

MypolyExt <- Mypoly * 10 

base2 <- ggplot(d) + coord_cartesian(xlim=c(-5, 5),ylim=c(-5, 5)) +geom_blank() 
shading3 <- geom_polygon(data=MypolyExt, aes(rayX,rayY), fill="blue", alpha=0.2) 
base2 + ray1 + ray2 + shading3 

(예를 들어 MrFlick의 대답에 테이크 2) 각도가 180도 이상되는 경우에이 일을 조금 더 작업을 걸릴합니다. 한 가지 방법은 플롯의 바깥 쪽 한도에 정사각형을 형성하는 점 집합을 지정하는 것입니다. 그런 다음 광선 각도가 180도 이상이면 해당 점을 유지 한 다음 볼록 선체를 잡으십시오.

+0

감사! MypolyExt 사용에 대한 귀하의 아이디어를 좋아합니다. –

6

이렇게하려면 두 가지 방법이 있습니다. 첫 번째 방법은 천천히하지만 가장 단순한 무차별 대입 방식을 사용합니다. 두 번째는 맵 구조를 조작하기 위해 sprgeos 패키지의 기능 세트를 사용합니다. 이것은 컨벡스 헐 (convex hull)을 사용하는 솔루션과 개념적으로 유사합니다.

첫 번째 방법 :이 방법은 당신의 광선 원점에서 시작하기 때문에, 우리가 색을 한 후 전체 공간을 커버하는 타일의 그리드를 만들 수 있다는 것을 인식

r1 <- data.frame(x=c(0,5),y=c(0,4)) 
r2 <- data.frame(x=c(0,0),y=c(0,5)) 

th1 <- with(r1,atan2(y[2],x[2])) 
th2 <- with(r2,atan2(y[2],x[2])) 

is.between <- function(x,lo,hi) { 
    if (lo<=hi) return(x>=lo & x<=hi) 
    return(!(x<lo & x>hi)) 
} 

df <- expand.grid(x=seq(-5,5,len=200),y=seq(-5,5,len=200)) 
df$th <- atan2(df$y,df$x) 
library(ggplot2) 
ggplot(mapping=aes(x,y))+ 
    xlim(-5,5) + ylim(-5,5)+ 
    geom_tile(data=df[is.between(df$th,th1,th2),],fill="blue",alpha=.2)+ 
    geom_line(data=r1)+ 
    geom_line(data=r2) 

두 광선에 의해 휩쓸린 각도 사이에 x 축과 각도를 이루는 것들. 아래 코드는 "사이"r1r2 영역을 반 시계 방향으로 음영 처리합니다. 따라서 r2이 먼저 오면 외각을 쉐이드합니다 (r1r2의 정의를 바꿔보십시오). 우리는 음영 처리를 위해 geom_tile(...)을 사용하고 있습니다.

base <- ggplot() + xlim(-5,5) + ylim(-5,5) + geom_blank() 
ray1 <- geom_line(data=r1, aes(x,y)) 
ray2 <- geom_line(data=r2, aes(x,y)) 
shading <- geom_tile(data=df[is.between(df$th,th1,th2),],aes(x,y), 
        fill="blue",alpha=.2) 
base + ray1 + ray2 + shading 

두 번째 방법 :

library(sp)  # for SpatialPolygons(...), etc. 
library(rgeos) # for gIntersection(...) 
th1 <- with(r1,atan2(y[2],x[2])) 
th1 <- ifelse(th1>0, th1, 2*pi+th1) 
th2 <- with(r2,atan2(y[2],x[2])) 
th2 <- ifelse(th2>0, th2, 2*pi+th2) 

th <- if(th1<th2){seq(th1,th2,length=100)} else {c(seq(th1,2*pi,length=100),seq(0,th2,length=100))} 
df <- data.frame(x=c(0,5*sqrt(2)*cos(th),0),y=c(0,5*sqrt(2)*sin(th),0)) 
slice <- SpatialPolygons(list(Polygons(list(Polygon(df)),"1"))) 
box <- readWKT("POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))") 
shade <- gIntersection(box,slice) 
sh.df <- as.data.frame([email protected][[1]]@Polygons[[1]]@coords) 

base <- ggplot() + xlim(-5,5) + ylim(-5,5) + geom_blank() 
ray1 <- geom_line(data=r1, aes(x,y)) 
ray2 <- geom_line(data=r2, aes(x,y)) 
shading <- geom_polygon(data=sh.df,aes(x,y),fill="blue",alpha=.2) 
base + ray1 + ray2 + shading 

이러한 접근 방식이를 계산하는 기능을 설정, rgeos에 특별히 능력을 활용

당신의 형식주의를 사용하여 SpatialPolygons의 교차점. 두 개의 SpatialPolygon을 만듭니다. box은 (-5, -5)에서 (5,5)까지의 영역을 단순히 커버하고 다른 하나는 slice이라는 두 개의 광선 사이의 파이 조각입니다. 파이가 5*sqrt(2) 인 반경을 사용하여 슬라이스가 적어도 box의 모서리까지 이어 지도록해야합니다. 그런 다음 rgeos 패키지에서 gIntersection(...)을 사용하여이 두 폴리곤의 교차점을 계산하고 ggplot을 사용하여 을 다각형으로 그려 봅니다.

다각형을 만드는 구문이 구불 구불 한 반면이 방법은 훨씬 빠릅니다.

+0

sp와 rgeos를 소개해 주셔서 감사합니다! –