I use levelplot in R to plot two raster stacks with values ranging from 0 to 600, by 20. This results to the first color palette below. However, I observed that I have some very sporadic pixels in my domain with values reaching up to 900. I want to include them to mu palette as well with a separate color, but I don't want the color to take so much space in my palette (as the second palette). How can I include an additional class with values ranging from 600-900, without taking so much space in the color ramp (denote it as >600 in the top of the palette)

enter image description here

enter image description here

r1 <- raster(nrow=18, ncol=36)
r1[] <- runif(ncell(r1)) * 10
r2 <- raster(nrow=18, ncol=36)
r2[] <- runif(ncell(r1)) * 2.345
r3 <- raster(nrow=18, ncol=36)
r3[] <- runif(ncell(r1)) * -4

months_obs = stack(r1,r2,r3)
months_cord  = stack(r1*2,r2*4,r3*9)
p1 = levelplot(months_obs, layout=c(4, 2), margin=T, at=at1, xlab=NULL, ylab=NULL, scales=list(draw=FALSE), 
               col.regions=cr2, par.strip.text=p.strip, main=list(label="Precipitation Climatology [mm/month]", cex=0.7),
               colorkey=list(x=c(title=expression(mm/month), row=3, column=1, vjust=2, rot=90))) 
p1 = p1 + layer(sp.polygons(afr))
p1 = p1 + layer(sp.polygons(africa, lwd=2))
p2 = levelplot(months_cord, margin=T, at=at2, xlab=NULL, ylab=NULL, scales=list(draw=FALSE), 
               col.regions=cr3, par.strip.text=p.strip, main=list(label="Precipitation Bias [mm/month]", cex=0.7),
               colorkey=list(x=c(title=expression(mm/month), row=3, column=1, vjust=2, rot=90))) 
p2 = p2 + layer(sp.polygons(afr))
p2 = p2 + layer(sp.polygons(africa, lwd=2))
grid.arrange(p1, p2, ncol=1, nrow=2,
             top = textGrob(paste("Precipitation for January (Climatology for 1990-2008)") ,gp=gpar(fontsize=12,font=1)))
  • How are you using levelplot? If I call levelplot on a raster I get no applicable method for 'levelplot' applied to an object of class "c('RasterStack', 'Raster', 'RasterStackBrick', 'BasicRaster')" – Spacedman Oct 29 '18 at 9:29
  • Please consider adding a minimal reproducible example. – sedot Oct 29 '18 at 9:56
  • You need to include the packages you are using - looks like raster, rasterVis and grid - but maybe more? – Spacedman Oct 29 '18 at 10:11
  • Thank you for the notice! The script is long, so I have included all the packages used. – Maria Karypidou Oct 29 '18 at 10:22
  • I receive an error running your code, when trying to create p1: object 'p.strip' not found. Please try to further reduce your example so it only contains code relevant to your question. – sedot Oct 29 '18 at 10:54

Your script indicates that you're trying to use the at argument, which is the answer here, but its unclear what objects at1 and at2 refer to, so you might have mis-defined them. at works like the breaks in ggplot2::scale_*() functions, if those are familiar to you. So, for your specific case,

rasterVis::levelplot(months_obs, at = c(seq(0, 600, 20), 900))

should do the trick. Note that the following does not work correctly:

rasterVis::levelplot(months_obs, colorkey = list(at = c(seq(0, 600, 20), 900)))

this will manipulate the legend but not the plotted data. Note also that your col.regions argument should be at least length(at) - 1, e.g. compare

levelplot(month_obs, at = c(seq(0, 600, 20), 900),
      col.regions = c(viridisLite::viridis(30), '#ffb6c1'))


levelplot(month_obs, at = c(seq(0, 600, 20), 900),
      col.regions = c(viridisLite::viridis(29), '#ffb6c1'))

Edit: Ah, I see you want to alter the internal colour divisions in the legend. levelplot seems designed to avoid this unless you set colorkey=FALSE and feed in a totally custom key, defined from scratch using the documentation for key in lattice::xyplot which is pretty opaque. I would suggest that this is a) more trouble than its worth and b) perhaps not the best design choice anyway. IMO it should be apparent that the final colour covers a larger range of values than the others do.

The closest I can get easily is a ggplot2() solution, but this would require that you adjust your whole plotting workflow into that paradigm, which may not be desirable. Still,


# just some DEM data I have for an example
data('heronvale_covariates', package = 'dsmartr')
# convert raster to df
hvc <- as.data.frame(heronvale_covariates[[1]], xy = TRUE)
# factorise the actual raster values with e.g.
hvc$plotthis <- cut(hvc[, 3], breaks = c(seq(0, 50, 10), 140))
# format factor labels for maximum fussiness...
levels(hvc$plotthis) <- gsub('^\\(', '', levels(hvc$plotthis))
levels(hvc$plotthis) <- gsub(']$',   '', levels(hvc$plotthis))
levels(hvc$plotthis) <- gsub(',', ' - ', levels(hvc$plotthis))

# assign a colour for each category
pal_custom <- c(viridisLite::viridis(5), '#ffb6c1')

ggplot() +
  geom_raster(data = na.omit(hvc), aes(x = x, y = y, fill = plotthis)) +
  scale_fill_manual(values = pal_custom, drop = FALSE, na.value = NA) +
  theme_minimal() +
  theme(axis.title = element_blank()) +
  labs(fill = 'Elevation') +
  coord_sf(crs = 3577)

enter image description here

  • Thank you for your reply, but still the values from 600 to 900 extent to almost half of the scale. How could I suppress this extent? – Maria Karypidou Oct 29 '18 at 11:29
  • yep, realised as soon as I posted - still trawling through docs, will edit. Although there's a solid argument that you shouldn't do this, for maximum clarity... – obrl_soil Oct 29 '18 at 11:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.