Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controlling plot order for visual objects with multiple geometries in ggplot2

Tags:

r

ggplot2

I want ggplot to plot in a specific order to control what is visible when objects overlap. Each data row maps to a composite of 2 geometry layers - the particulars of the plot require this. I've been using a loop to do this, but it's very slow. I wonder if there's a better way? e.g.

d = data.frame(x=c(1,5,2,2,4,2), y=c(1,1,4,3,3,5), grp=c(1,1,1,2,2,2))

ggplot(d, aes(x, y, group=grp)) + 
  geom_polygon(aes(fill = factor(grp))) +
  geom_line(size=1)

enter image description here

Each polygon line should plot with its polygon - so e.g. the red polygon's line should be obscured by blue's polygon. Is there any way to achieve this without looping when both geom_polygon and geom_line use the same dataset?


Edit: looping methods..

Here are loop methods I've used. Added a better dataset for comparing performance. Both take about 5.6s to run on my machine. By comparison the typical approach (ggplot(d, aes(x, y, fill=factor(grp))) + geom_polygon() + geom_line(size=1)) takes 0.45s.

d = data.frame(x = sample(-30:30,99,rep=T) + rep(sample(1:100,33),each=3),
               y = sample(-30:30,99,rep=T) + rep(sample(1:100,33),each=3),
               grp = rep(1:33,each=3))

# Method 1 - for loop
p = ggplot()
for(g in unique(d$grp)){
  dat = subset(d, grp == g)
  p = p + geom_polygon(data=dat, aes(x, y, fill = factor(grp))) + 
    geom_line(data=dat, aes(x, y), size=1)
}
print(p)

# Method 2 - apply
ggplot() + lapply(unique(d$grp), FUN=function(g){
  dat = subset(d, grp == g)
  list(geom_polygon(data=dat, aes(x, y, fill = factor(grp))),
       geom_line(data=dat, aes(x, y), size=1))
})

enter image description here

like image 424
geotheory Avatar asked Nov 09 '22 00:11

geotheory


1 Answers

I just used your code and changed the order of the layers in ggplot2 It looks like this

d = data.frame(x=c(1,5,2,2,4,2), y=c(1,1,4,3,3,5), grp=c(1,1,1,2,2,2))

ggplot(d, aes(x, y, group=grp)) +
   geom_line(size=1)+
   geom_polygon(aes(fill = factor(grp)))

And the result is this one

enter image description here

Also notice that if you remove the geom_line call you produce the same result but without the border.

like image 171
Matias Andina Avatar answered Nov 15 '22 05:11

Matias Andina