ggplot - panel borders alternating black and white rectangles

后端 未结 1 1018
轻奢々
轻奢々 2021-01-05 02:30

With ggplot, is there a way to set up panel borders with alternation of black and white rectangles, like this :

相关标签:
1条回答
  • 2021-01-05 03:23

    This is lengthy, but here's how to make a border grid. You can reuse this code without major changes among different maps, updating only the values you define for minimum, maximum, and intervals for latitude and longitude.

    require(ggplot2)
    require(maps)
    
    world <- map_data("world2") #get map data
    

    First, define your minimum, maximum, and grid interval for latitude and longitude. These numbers will be used to create a dataframe for border grid rectangles and to create axis breaks and limits in your plot.

    min.lat <- -40
    max.lat <- 40
    interval.lat <- 20
    min.long <- 0
    max.long <- 90
    interval.long <- 30
    

    Next, create two dataframes containing coordinates for the rectangles that will form your grid, one dataframe for black rectangles and one for white rectangles. Separate dataframes for each color of grid rectangle are created so that you will not need to use scale_fill_manual() for border grid fill, and thus will be able to use the fill aesthetic for your data if desired. This code is all written to use the values defined above, rather than actual numbers, so you do not need to change the code below to make a map of a different area, you'll only need to update the values defined above.

    #define a constant (scaled to map size) width for grid rectangles
    #may need to adjust number to get width you prefer
    grid.width <- (max.lat - min.lat)/90
    
    is.even <- function(x) x %% 2 == 0 #function to test if number is even
    
    #dataframe of longitude rectangles
    rects.long <- data.frame(x_start = rep(seq(min.long, max.long - interval.long,
                                      by = interval.long), 2))
    rects.long$x_end <- rects.long$x_start + interval.long
    rects.long$y_start <- c(rep(min.lat, nrow(rects.long)/2),
                            rep(max.lat - grid.width, nrow(rects.long)/2))
    rects.long$y_end <- c(rep(min.lat + grid.width, nrow(rects.long)/2),
                            rep(max.lat, nrow(rects.long)/2))
    
    rects.long$color <- if(is.even(nrow(rects.long)/2)) { #even/odd test
      rep(c("black", "white"), nrow(rects.long)/2) #pattern for even
    } else {
      rep(c(rep(c("black", "white"), (nrow(rects.long) - 2)/4),"black"), 2)} #odd
    
    #dataframe of latitude rectangles
    rects.lat <- data.frame(y_start = rep(seq(min.lat, max.lat - interval.lat,
                                               by = interval.lat), 2))
    rects.lat$y_end <- rects.lat$y_start + interval.lat
    rects.lat$x_start <- c(rep(min.long, nrow(rects.lat)/2),
                            rep(max.long - grid.width, nrow(rects.lat)/2))
    rects.lat$x_end <- c(rep(min.long + grid.width, nrow(rects.lat)/2),
                          rep(max.long, nrow(rects.lat)/2))
    
    rects.lat$color <- if(is.even(nrow(rects.lat)/2)) { #even/odd test
      rep(c("black", "white"), nrow(rects.lat)/2) #pattern for even
    } else {
      rep(c(rep(c("black", "white"), (nrow(rects.lat) - 2)/4),"black"), 2)} #odd
    
    #combine latitude and longitude grid
    rects.grid <- rbind(rects.lat, rects.long)
    
    #split into black dataframe and white dataframe
    rects.black <- rects.grid[rects.grid$color == "black",]
    rects.white <- rects.grid[rects.grid$color == "white",]
    

    Finally, make your plot!

    #define axis breaks to match grid
    axis.breaks.x <- seq(min.long, max.long, interval.long)
    axis.breaks.y <- seq(min.lat, max.lat, interval.lat)
    
    ggplot(data = world) +
      geom_polygon(aes(x = long, y = lat, group = group),
                   color = "black", fill = "gray50") +
      #set limits to your previously defined limits
      coord_fixed(1, xlim = c(min.long, max.long), ylim = c(min.lat, max.lat),
                  expand = FALSE) +
      #define breaks same as grid, duplicate axes for lat/long labels on all sides
      scale_y_continuous(breaks = axis.breaks.y, sec.axis = dup_axis()) +
      scale_x_continuous(breaks = axis.breaks.x, sec.axis = dup_axis()) +
      #use geom_rect() to add border grid
      geom_rect(data = rects.white, inherit.aes = FALSE, #white grid rectangles
            aes(xmin = x_start, xmax = x_end, ymin = y_start, ymax = y_end), 
                color = "black", fill = "white") +
      geom_rect(data = rects.black, inherit.aes = FALSE, #black grid rectangles
            aes(xmin = x_start, xmax = x_end, ymin = y_start, ymax = y_end),
                color = "black", fill = "black") +
      theme_minimal() + #theme edits to make plot look like a map
      theme(axis.title = element_blank(),
            legend.position = "none")
    

    Here is a test to check that this code works with different limits and intervals:

    min.lat <- -10
    max.lat <- 50
    interval.lat <- 10
    min.long <- 60
    max.long <- 150
    interval.long <- 15
    #run same code as above to create grid dataframes and plot
    

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