Some ways to add labels on contour plots
# load packages
library('mgcv')
library('gratia') # draw(); smooth_estimates()
library('metR') # geom_contour2(); geom_text_contour()
library('ggplot2')
Simulate data using the example from Gavin Simpson's website: https://fromthebottomoftheheap.net/2018/10/23/introducing-gratia/
set.seed(1)
dat <- gamSim(2, n = 4000, dist = "normal", scale = 1, verbose = FALSE)
mod <- gam(y ~ s(x, z, k = 30), data = dat$data, method = "REML")
sm <- smooth_estimates(mod); sm
Plot using gratia with the number of contour lines automatically adjusted:
draw(mod) +
geom_text_contour(
aes(z = est), # 'est' from smooth_estimates(mod)
colour = "black", size = 4.5, fontface = "bold",
stroke = 0.3, stroke.colour = "white", # 'stroke' controls the width of stroke relative to the size of the text
skip = 0, # number of contours to skip
rotate = FALSE, # horizontal labeling; if TRUE, rotate text following the contour
label.placer = label_placer_fraction(frac = 0.5)) # 'frac = 0.5' places the label at equal distance from extremities. Try 'label.placer = label_placer_n(2)' to display two labels per contour line
However, contour lines and labeling do no longer match if we use e.g. 'n_contour = 10' within draw(). To allow this matching, use 'n_contour = 0' within draw(), define 'binwidth' within geom_contour2() and 'breaks' within geom_text_contour(), as follows.
Plot using gratia::draw with 'binwidth'-adjusted contour lines:
min(sm$est); max(sm$est) # find min() and max() for adjusting the 'est' z-scale
draw(mod, n_contour = 0) +
geom_contour2(aes(z = est), binwidth = 0.2) +
geom_text_contour(
aes(z = est), # 'est' from smooth_estimates(mod)
breaks = seq(-0.4, 0.4, by = 0.2), # 'breaks' must match with 'binwidth' above
colour = "black", size = 4.5, fontface = "bold",
stroke = 0.3, stroke.colour = "white", # 'stroke' controls the width of stroke relative to the size of the text
skip = 0, # number of contours to skip
rotate = FALSE, # horizontal labelling; if TRUE, rotate text following the contour
label.placer = label_placer_fraction(frac = 0.5)) # 'frac = 0.5' places the label at equal distance from contour lines' extremities. Try 'label.placer = label_placer_n(2)' to display two labels per contour line
Also possible to customize the graph directly with ggplot2:
ggplot(data = sm, aes(x = x, y = z, z = est)) +
geom_contour2(aes(z = est), binwidth = 0.1) +
geom_text_contour(
aes(z = est), # 'est' from smooth_estimates(mod)
breaks = seq(-0.4, 0.4, by = 0.1), # 'breaks' instead of 'bins' to not have too many decimals
colour = "black", size = 4.5, fontface = "bold",
stroke = 0.3, stroke.colour = "white", # 'stroke' controls the width of stroke relative to the size of the text
skip = 0, # number of contours to skip
rotate = FALSE, # horizontal labelling; if TRUE, rotate text following the contour
label.placer = label_placer_fraction(frac = 0.5)) # 'frac = 0.5' places the label at equal distance from contour lines' extremities. Try 'label.placer = label_placer_n(2)' to display two labels per contour line
You can use geom_textcontour
from geomtextpath
to obtain nicely placed labels without having to tweak lots of different parameters:
library(geomtextpath)
ggplot(sm, aes(x, z, z = est)) + geom_textcontour()
To use it within the gratia::draw
framework, you can remove the existing contour from the plot first:
p <- draw(mod)
p$layers[[2]] <- NULL
p + geom_textcontour(aes(z = est), fontface = 'bold')
EDIT
To get a similar effect to the stroke
parameter we can do:
library(ggfx)
p + with_outer_glow(geom_textcontour(aes(z = est), fontface = 'bold',
linetype = NA),
colour = 'white', expand = 3, sigma = 1) +
geom_textcontour(aes(z = est), fontface = 'bold', textcolour = NA)