Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot - panel borders alternating black and white rectangles

Tags:

r

ggplot2

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

enter image description here

like image 938
Loulou Avatar asked Feb 25 '19 14:02

Loulou


People also ask

How to add panel border to R plot using ggplot?

Add Panel Border to plot using theme () function and panel.border as its parameter. To add Panel Border to R plot we simply add theme () function to ggplot () function. Inside theme () function, we have to specify panel.border parameter to add panel border around plot and use element_rect () function as value of panel.border parameter.

How do I change the color of a rectangle in ggplot?

Anatomy of Rectangle Elements in ggplot2 Like other theme element functions, to control the color of the rectangle that defines the plot background, we will use “plot.background” element as argument to theme () function and use element_rect () to specify the fill color.

How to control the color of the rectangle that defines plot background?

Like other theme element functions, to control the color of the rectangle that defines the plot background, we will use “plot.background” element as argument to theme () function and use element_rect () to specify the fill color. Here is element_rect () function with the available arguments and their default choices.

How to change a ggplot theme background color and grid lines?

Solution 1: Use the function theme_transparent () [in ggpubr package]. First, install it with install.packages ("ggpubr"), then type this: This article shows how to change a ggplot theme background color and grid lines. The essentials are summarized below:


1 Answers

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

enter image description here

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

enter image description here

like image 58
Jan Boyer Avatar answered Nov 08 '22 21:11

Jan Boyer