With ggplot, is there a way to set up panel borders with alternation of black and white rectangles, like this :
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