r - ggplot2: filling the area between two rays

ggplot2, r

Solution

I thought it would be more simple; but i've arrived at this ugly solution. Here's a helper function which is meant to calculate all the intersection points along the limits defined in `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
}

This will create the data.frame you need for your polygon plotting. For example

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

The idea is that it will go out the limits, and then start wrapping around the edges. So another example is

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

Problem

My plot has two rays coming from the origin. I would like to shade the region going from ray 1 to ray 2 in a counter clockwise direction. I’m thinking that I might have to use geom_polygon. I would like to be able to do this for any two arbitrary rays, but I can’t seem to figure it out. *I’d like to stick to using cartesian coordinates. Here’s an example of what I mean: ``` 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 ``` For this example, I was able to get the vertices of the polygon by inspection, but I'll be generating several random pairs of rays, and I don't want to go through this process manually each time. Any advice?

Original source