4

I need to add IPCC(-style) stippling to a global map as in this post. However I would like to use one of the functions of ggplot2 for doing so.

Here an example of data and plot:

test.csv

df=read.csv("/home/my_folder/test.csv")

library(ggplot2)
library(metR)

plot_df = ggplot() +
  geom_contour_fill(data=df, aes(x=V1, y=V2, z = value)) +
  scale_fill_steps2(name = "", low = "#0571b0", mid = '#ffffbf', high = '#ca0020')

print(plot_df)

image

How can I add IPCC stippling to this image?

I tried using geom_point() but the stippling are too large and mask the background colors.

Thanks

Edit

Following @Allan answer I am indeed able to add stippling as follows:

library(ggplot2)
library(ggpattern)

df=read.csv("~/...../test.csv")

df_stippl=df[c(10:47, 100:250, 500:510, 707:1000, 1508:1699, 2500:2600, 2680:2690, 3400:4300),]

plot_df = ggplot() +
  
  geom_contour_fill(data=df, aes(x=V1, y=V2, z = value)) +
  
  stat_contour_fill(data=df_stippl, aes(x=V1, y=V2, z = value), geom = "polygon_pattern", 
                    pattern_fill = "black", pattern_size = 0,
                    pattern = "crosshatch", pattern_spacing = 0.02,
                    pattern_angle = 45, pattern_density = 0.1) +
  
  scale_fill_steps2(name = "", low = "#0571b0", mid = '#ffffbf', high = '#ca0020')

print(plot_df)

image_2

However, when I save the figure in pdf:

pdf('~/...../figure.pdf', width = 10, height = 6.6)
print(plot_df)
dev.off()

I get full stippling all over the globe and not only in the areas of df_stippl.

aaaaa
  • 149
  • 2
  • 18
  • 44

1 Answers1

7

You could do this a couple of ways. Perhaps the easiest is to get the centre points of a hexagonal grid covering your data and draw with geom_point

library(ggplot2)
library(metR)
library(hexbin)

df = read.csv("../test.csv")

hb  <- erode(hexbin(df$V1, df$V2, xbins = 55))
df2 <- as.data.frame(hcell2xy(hb))

ggplot() +
  geom_contour_fill(data=df, aes(x=V1, y=V2, z = value)) +
  scale_fill_steps2(name = "", low = "#0571b0",
                    mid = '#ffffbf', high = '#ca0020') +
  geom_point(data = df2, aes(x, y), color = "black", size = 1) +
  theme_bw() 

enter image description here

If you want the dots to have a different density, you can change xbins

hb  <- erode(hexbin(df$V1, df$V2, xbins = 20))
df2 <- as.data.frame(hcell2xy(hb))

ggplot() +
  geom_contour_fill(data=df, aes(x=V1, y=V2, z = value)) +
  scale_fill_steps2(name = "", low = "#0571b0",
                    mid = '#ffffbf', high = '#ca0020') +
  geom_point(data = df2, aes(x, y), color = "black", size = 1) +
  theme_bw() 

enter image description here

An alternative is to filter out some of the rows of your data frame and plot the points there:

ggplot(df, aes(V1, V2)) +
  geom_contour_fill(aes(z = value)) +
  geom_point(data = df[(df$V1 + df$V2) %% 3 == 0,], color = "black", size = 1) +
  scale_fill_steps2(name = "", low = "#0571b0", 
                    mid = '#ffffbf', high = '#ca0020') +
  theme_bw() 

enter image description here

Compare all of these to just plotting the points:

ggplot(df, aes(V1, V2)) +
  geom_contour_fill(aes(z = value)) +
  geom_point(color = "black", size = 1) +
  scale_fill_steps2(name = "", low = "#0571b0", 
                    mid = '#ffffbf', high = '#ca0020') +
  theme_bw() 

enter image description here


Edit

If you want cross-hatching you can do:

library(ggplot2)
library(metR)
library(ggpattern)

df <- read.csv("../test.csv")

ggplot(df, aes(V1, V2)) +
  stat_contour_fill(aes(z = value), geom = "polygon_pattern", 
                      pattern_fill = "black", pattern_size = 0,
                      pattern = "crosshatch", pattern_spacing = 0.02,
                      pattern_angle = 45, pattern_density = 0.1) +
  scale_fill_steps2(name = "", low = "#0571b0", mid = '#ffffbf',
                    high = '#ca0020') +
  theme_bw() 

enter image description here

To save your plot as pdf, you will need to use cairo_pdf:

df_stippl=df[c(10:47, 100:250, 500:510, 707:1000, 1508:1699, 
               2500:2600, 2680:2690, 3400:4300),]

plot_df = ggplot() +
  geom_contour_fill(data=df, aes(x=V1, y=V2, z = value)) +
  stat_contour_fill(data=df_stippl, aes(x=V1, y=V2, z = value), 
                    geom = "polygon_pattern", 
                    pattern_fill = "black", pattern_size = 0,
                    pattern = "crosshatch", pattern_spacing = 0.02,
                    pattern_angle = 45, pattern_density = 0.1) +
  scale_fill_steps2(name = "", low = "#0571b0", mid = '#ffffbf', 
                    high = '#ca0020')

cairo_pdf('../figure.pdf', width = 10, height = 6.6)
print(plot_df)
dev.off()

figure.pdf

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • Thanks. But is this not the same as using data=df in geom_point()? – aaaaa Apr 30 '22 at 16:04
  • 1
    No, that would plot every point. This plots the centre of hexagonal bins. You can try with different values of xbin - see my update @aaaaa – Allan Cameron Apr 30 '22 at 16:09
  • Ok, great. Let’s see if someone will add other solutions. It would be nice for me to have the diagonal lines instead of points. – aaaaa Apr 30 '22 at 16:23
  • ..and of course my real stippling are unevenly distributed across the globe. so I hope that the bin method will hold. – aaaaa Apr 30 '22 at 16:26
  • @aaaaa what diagonal lines do you mean? The image in the linked post has dots - I thought that's what you wanted? The hexbin-dots produces the output you requested. Are you looking for cross - hatching? – Allan Cameron Apr 30 '22 at 16:29
  • yes, see again the link https://stackoverflow.com/questions/11736996/adding-stippling-to-image-contour-plot (1st answer, 1st and 3rd plots). – aaaaa Apr 30 '22 at 16:33
  • 1
    @aaaaa I see - that's actually a bit easier. See my update. – Allan Cameron Apr 30 '22 at 17:02
  • hi @Allan, see my update. I am having issues saving the plot as .pdf. hope you can help if you have time. – aaaaa May 02 '22 at 08:05
  • @aaaaa see my addendum for a solution – Allan Cameron May 05 '22 at 22:12