independently move 2 legends ggplot2 on a map

后端 未结 4 1424
庸人自扰
庸人自扰 2020-12-17 05:13

I want to independently move two legends on a map to save save and make the presentation nicer.

Here is the data:

##              INST..SUB.TYPE.DESC         


        
相关标签:
4条回答
  • 2020-12-17 05:44

    This works but needs some tweaking. Just plot one legend where you want it and then use annotation_custom to add the second. This is not generalizable to n legends. It'd be nice to have an answer that does. It appears you can only use one annotation_custom at a time.

    plot1 <- e1 + 
        annotation_custom(grob = leg2, xmin = -74, xmax = -72.5, ymin = 41, ymax = 42.5) 
    
    plot2 <- ggplot(mtcars, aes(mpg, hp)) + geom_point()
    grid.arrange(plot1, plot2)
    

    enter image description here

    0 讨论(0)
  • 2020-12-17 05:49

    BTW, it is possible to use more than one annotation_custom:

    library(ggplot2); library(maps); library(grid); library(gridExtra); library(gtable)
        ny <- subset(map_data("county"), region %in% c("new york"))
        ny$region <- ny$subregion
    
        p3 <- ggplot(dat2, aes(x = lng, y = lat)) + 
            geom_polygon(data=ny, aes(x = long, y = lat, group = group)) 
    
        # Get the colour legend
        (e1 <- p3 + geom_point(aes(colour = INST..SUB.TYPE.DESCRIPTION, 
            size = Enrollment), alpha = .3) +
            geom_point() + theme_gray(9) +
            guides(size = FALSE, colour = guide_legend(title = NULL, 
                override.aes = list(alpha = 1, size = 3))) +
            theme(legend.key.size = unit(.35, "cm"),
                legend.key = element_blank(),
                legend.background = element_blank()))
    
        leg1 <- gtable_filter(ggplot_gtable(ggplot_build(e1)), "guide-box") 
    
        # Get the size legend
        (e2 <- p3 + geom_point(aes(colour=INST..SUB.TYPE.DESCRIPTION, 
            size = Enrollment), alpha = .3) +
            geom_point() + theme_gray(9) +
            guides(colour = FALSE) +
            theme(legend.key = element_blank(),
                legend.background = element_blank()))
    
        leg2 <- gtable_filter(ggplot_gtable(ggplot_build(e2)), "guide-box") 
    
        # Get first base plot - the map
        (e3 <- p3 + geom_point(aes(colour = INST..SUB.TYPE.DESCRIPTION, 
            size = Enrollment), alpha = .3) +
            geom_point() + 
            guides(colour = FALSE, size = FALSE))
    
    
    leg2Grob <- grobTree(leg2)
    leg3Grob <- grobTree(leg2)
    leg4Grob <- grobTree(leg2)
    leg5Grob <- grobTree(leg2)
    leg1Grob <- grobTree(leg1)
    
    p = e3 +
      annotation_custom(leg2Grob, xmin=-73.5, xmax=Inf, ymin=41, ymax=43) +
      annotation_custom(leg1Grob, xmin=-Inf, xmax=-76.5, ymin=43.5, ymax=Inf) +
      annotation_custom(leg3Grob, xmin = -Inf, xmax = -79, ymin = -Inf, ymax =  41.5) +
      annotation_custom(leg4Grob, xmin = -78, xmax = -76, ymin = 40.5, ymax = 42) +
      annotation_custom(leg5Grob, xmin=-73.5, xmax=-72, ymin=43.5, ymax=Inf)
    p
    

    enter image description here

    0 讨论(0)
  • 2020-12-17 05:55

    As @Tyler Rinker already said in his own answer, the problem can't be solved with more than one annotation_custom. The following code is quite compact & complete (but needs some tweaking for the right placement of the legends):

    p <- ggplot(dat2, aes(x=lng, y=lat)) + 
      geom_polygon(data=ny, aes(x=long, y=lat, group = group)) +
      geom_point(aes(colour=INST..SUB.TYPE.DESCRIPTION,size = Enrollment), alpha = .3) +
      theme(legend.position = c( .15, .8),legend.key = element_blank(), legend.background = element_blank())
    
    l1 <- p + guides(size=FALSE, colour = guide_legend(title=NULL,override.aes = list(alpha = 1, size=3)))
    l2 <- p + guides(colour=FALSE)
    leg2 <- gtable_filter(ggplot_gtable(ggplot_build(l2)), "guide-box") 
    
    plot1 <- l1 +
      annotation_custom(grob = leg2, xmin = -73, xmax = -71.5, ymin = 41, ymax = 42.5)
    plot2 <- ggplot(mtcars, aes(mpg, hp)) + geom_point()
    grid.arrange(plot1, plot2)
    

    @Tyler: Feel free to include this into you own answer

    0 讨论(0)
  • 2020-12-17 06:02

    Viewports can be positioned with some precision. In the example below, the two legends are extracted then placed within their own viewports. The viewports are contained within coloured rectangles to show their positioning. Also, I placed the map and the scatterplot within viewports. Getting the text size and dot size right so that the upper left legend squeezed into the available space was a bit of a fiddle.

    library(ggplot2); library(maps); library(grid); library(gridExtra); library(gtable)
    ny <- subset(map_data("county"), region %in% c("new york"))
    ny$region <- ny$subregion
    
    p3 <- ggplot(dat2, aes(x = lng, y = lat)) + 
        geom_polygon(data=ny, aes(x = long, y = lat, group = group)) 
    
    # Get the colour legend
    (e1 <- p3 + geom_point(aes(colour = INST..SUB.TYPE.DESCRIPTION, 
        size = Enrollment), alpha = .3) +
        geom_point() + theme_gray(9) +
        guides(size = FALSE, colour = guide_legend(title = NULL, 
            override.aes = list(alpha = 1, size = 3))) +
        theme(legend.key.size = unit(.35, "cm"),
            legend.key = element_blank(),
            legend.background = element_blank()))
    
    leg1 <- gtable_filter(ggplot_gtable(ggplot_build(e1)), "guide-box") 
    
    # Get the size legend
    (e2 <- p3 + geom_point(aes(colour=INST..SUB.TYPE.DESCRIPTION, 
        size = Enrollment), alpha = .3) +
        geom_point() + theme_gray(9) +
        guides(colour = FALSE) +
        theme(legend.key = element_blank(),
            legend.background = element_blank()))
    
    leg2 <- gtable_filter(ggplot_gtable(ggplot_build(e2)), "guide-box") 
    
    # Get first base plot - the map
    (e3 <- p3 + geom_point(aes(colour = INST..SUB.TYPE.DESCRIPTION, 
        size = Enrollment), alpha = .3) +
        geom_point() + 
        guides(colour = FALSE, size = FALSE))
    
    # For getting the size of the y-axis margin
    gt <- ggplot_gtable(ggplot_build(e3))  
    
    # Get second base plot - the scatterplot
    plot2 <- ggplot(mtcars, aes(mpg, hp)) + geom_point()
    
    
    # png("p.png", 600, 700, units = "px")
    grid.newpage()
    # Two viewport: map and scatterplot
    pushViewport(viewport(layout = grid.layout(2, 1))) 
    
    # Map first
    pushViewport(viewport(layout.pos.row = 1))
    grid.draw(ggplotGrob(e3))
    
    # position size legend
    pushViewport(viewport(x = unit(1, "npc") - unit(1, "lines"), 
                          y = unit(.5, "npc"), 
                          w = leg2$widths, h = .4,
                          just = c("right", "centre")))
    grid.draw(leg2)
    grid.rect(gp=gpar(col = "red", fill = "NA"))
    popViewport()
    
    # position colour legend
    pushViewport(viewport(x = sum(gt$widths[1:3]),
                          y = unit(1, "npc") - unit(1, "lines"), 
                          w = leg1$widths, h = .33,
                          just = c("left", "top")))
    grid.draw(leg1)
    grid.rect(gp=gpar(col = "red", fill = "NA"))
    popViewport(2)
    
    # Scatterplot second
    pushViewport(viewport(layout.pos.row = 2))
    grid.draw(ggplotGrob(plot2))
    popViewport()
    # dev.off()
    

    enter image description here

    0 讨论(0)
提交回复
热议问题