[R] Plotting results from extRemes package - Extreme Value Analysis

If you are familiar with Extreme Value Analysis (EVA) in R you will have likely come across the extRemes package, written by Eric Gilleland. While I am not (yet!) an expert in EVA, I have found this package to be quite accessible.

The package’s main function, ‘fevd()’, fits an extreme value distribution to data. Methods for plotting are available for objects of class ‘fevd’ to produce diagnostics and result plots, such as a return level plot.

My issue is the restricted control you seem to have over the plot’s layout and general look. You can choose which plots to show, or to add a custom title, but not much else. What if you want to customise the plot to your liking, plot the results in another software/package or display two EVAs on the same figure as shown above?

I could not find an easy way to extract the information the package uses to generate the plots, nor could I find any mention of this problem online. In the off-chance someone is in the same situation, you’ll find a solution below. It seems a little awkward to me and if there is a better way that I am missing, please do let me know!

Let’s use the data from the “extRemes” package, with the example for the Peaks Over Threshold approach:

data("damage", package = "extRemes")
fitD <- fevd(Dam, damage, threshold = 6, type = "GP", time.units = "2.06/year")
plot(fitD, type = "rl")

You have to play with the original code for the package’s plot functions. When using the Maximum Likelihood Estimation (MLE) method, the function to change is ‘plot.fevd.mle’. If you are satisfied with the overall default aspect of the plots and just need to tweak it you can customise the code and reload the function. However, I generally use ggplot2 to produce my figures and like to have a consistent template.

Once you have your ‘fevd’ object you will get the information you need to draw a Return Level plot with the following two functions (other types of plots and distributions will use a different section from plot.fevd.mle).

The first returns a dataframe of return level point coordinates:

getrlpoints <- function(fit){

xp2 <- ppoints(fit$n, a = 0)
ytmp <- datagrabber(fit)
y <- c(ytmp[, 1])
sdat <- sort(y)
npy <- fit$npy
u <- fit$threshold
rlpoints.x <- -1/log(xp2)[sdat > u]/npy
rlpoints.y <- sdat[sdat > u]
rlpoints <- data.frame(rlpoints.x, rlpoints.y)


The second returns a dataframe of estimated returned levels with confidence intervals:

getcidf <- function(fit){

rperiods = c(2, 5, 10, 20, 50, 80, 100, 120, 200, 250, 300, 500, 800)
bds <- ci(fit, return.period = rperiods)
c1 <- as.numeric(bds[,1])
c2 <- as.numeric(bds[,2])
c3 <- as.numeric(bds[,3])
ci_df <- data.frame(c1, c2, c3, rperiods) 


That is all you need to produce the plot in ggplot2:

## Registered S3 methods overwritten by 'ggplot2':
##   method         from 
##   [.quosures     rlang
##   c.quosures     rlang
##   print.quosures rlang
rlpoints <- getrlpoints(fitD)
ci_df <- getcidf(fitD)

ggplot() +
  geom_line(data = ci_df, aes(x = rperiods, y = c2), color = "red") +
  geom_line(data = ci_df, aes(x = rperiods, y = c1), color = "grey") +
  geom_line(data = ci_df, aes(x = rperiods, y = c3), color = "grey") +
  geom_point(data = rlpoints, aes(x = rlpoints.x, y = rlpoints.y), size = 1) +
  ylab("Return Level (m)") +
  xlab("Return Period (Years)") +
  scale_x_log10(expand = c(0, 0), breaks = c(2,5,10,20,50,100,200,500)) +
  theme_bw() +
  theme(axis.text = element_text(size=12), axis.title = element_text(size = 14, face = "bold"))

Ulysse Pasquier
Postdoctoral Scholar

Postdoctoral Researcher in Urban Hydro-Climate

comments powered by Disqus