R - Legend title or units when using Pheatmap - r

I am using pheatmap to create a heatmap of values and would like to label the legend with the units of the z values in the matrix. In this example I would like the top of the legend to say Temperature [°C]. I have read the guidelines here for pheatmap, and it seems the only manipulation of the legend is to add a list of default numbers to be displayed in place of the scale. I cannot see any option to add a legend title per se.
Here is a generic block of code to generate a matrix and plot using pheatmap. I would really appreciate any advice on how to add a title to the legend.
test <- matrix(rexp(200, rate=.1), ncol=20)
colnames(test) = paste("Room", 1:20, sep = "")
rownames(test) = paste("Building", 1:10, sep = "")
pheatmap(test, legend = TRUE, cluster_rows = FALSE, cluster_cols = FALSE)

MikeyMike's answer is incredible; I also learned a lot by reading it.
However, I needed a dumb, ugly, 10 second solution:
test <- matrix(rexp(200, rate=.1), ncol=20)
colnames(test) = paste("Room", 1:20, sep = "")
rownames(test) = paste("Building", 1:10, sep = "")
pheatmap(test, legend_breaks = c(10, 20, 30, 40, max(test)),
main = "", legend_labels = c("10", "20", "30", "40", "title\n"),
legend = TRUE, cluster_rows = FALSE, cluster_cols = FALSE)
Which produces this heatmap:

OK so since someone has yet to answer this, I'll give you one possible option if you absolutely must use the pheatmap function. This is much easier to do using
ggplot, but here it goes:
First we are going to want to generate our plot so we can use all the plot objects to create our own plot, with an edited legend.
#Edited to add in library names
library(gtable)
library(grid)
#Starting with data and generating initial plot
test <- matrix(rexp(200, rate=.1), ncol=20)
colnames(test) = paste("Room", 1:20, sep = "")
rownames(test) = paste("Building", 1:10, sep = "")
p<-pheatmap(test, legend = TRUE, cluster_rows = FALSE, cluster_cols = FALSE)
#Get grobs we want - will use these to create own plot later
plot.grob <- p$gtable$grob[[1]]
xlab.grob <- p$gtable$grob[[2]]
ylab.grob <- p$gtable$grob[[3]]
legend.grob <- p$gtable$grob[[4]]
Now once we have our objects, we actually want to shift the legend down a little to make room for the title.
#Shift both down by 1 inch
legend.grob$children[[1]]$y <- legend.grob$children[[1]]$y - unit(0.85,"inches")
legend.grob$children[[2]]$y <- legend.grob$children[[2]]$y - unit(0.85,"inches")
legend.grob$children[[1]]$x <- legend.grob$children[[1]]$x + unit(0.4,"inches")
legend.grob$children[[2]]$x <- legend.grob$children[[2]]$x + unit(0.4,"inches")
Since we've made room for the legend, now we can create the legend textGrob and add it to the legend grobTree (just set of graphical objects in what we want our legend to be)
#New legend label grob
leg_label <- textGrob("Temperature [°C]",x=0,y=0.9,hjust=0,vjust=0,gp=gpar(fontsize=10,fontface="bold"))
#Add label to legend grob
legend.grob2 <- addGrob(legend.grob,leg_label)
If you want to check out what our legend will look like try:
grid.draw(legend.grob2)
Now we actually need to build our gtable object. To do this we will use a similar layout (with some modifications) as the plot generated by the pheatmap function. Also note that the pheatmap function generates a gtable object which can be accessed by:
p$gtable
In order to see the widths/heights of each of the "sectors" in our gtable object all we need to do is:
p$gtable$heights
p$gtable$widths
These will serve as our reference values. For a more graphical display try:
gtable_show_layout(p$gtable)
Which yields this image:
Ok, so now that we have the grobs we want, all we need to do is build our gtable based on what we saw for the gtable built by pheatmap. Some sample code I've written is:
my_new_gt <- gtable(widths= unit.c(unit(0,"bigpts") + unit(5,"bigpts"),
unit(0,"bigpts"),
unit(1,"npc") - unit(1,"grobwidth",plot.grob) + unit(10,"bigpts") - max(unit(1.1,"grobwidth",plot.grob), (unit(12,"bigpts")+1.2*unit(1.1,"grobwidth",plot.grob))) + unit(5,"bigpts") - unit(3,"inches"),
unit(1,"grobwidth",ylab.grob) + unit(10,"bigpts"),
max(unit(1,"grobwidth",legend.grob2),unit(12,"bigpts")+1.2*unit(1.1,"grobwidth",legend.grob2)) + unit(1,"inches") ,
max(unit(0,"bigpts"),unit(0,"bigpts"))
),
height = unit.c(unit(0,"npc"),
unit(5,"bigpts"),
unit(0,"bigpts"),
unit(1,"npc") - unit(1,"grobheight",xlab.grob) + unit(15,"bigpts") - unit(0.2,"inches"),
unit(1,"grobheight",xlab.grob) + unit(15,"bigpts")
))
Finally, we can add all our objects to our new gtable to get a very similar plot to the one generated by pheatmap with the added legend title.
#Adding each grob to the appropriate spot
gtable <- gtable_add_grob(my_new_gt,plot.grob,4,3)
gtable <- gtable_add_grob(gtable,xlab.grob,5,3)
gtable <- gtable_add_grob(gtable,ylab.grob,4,4)
gtable <- gtable_add_grob(gtable,legend.grob2,4,5)
grid.draw(gtable)
Finally the generated output is:
Hope this helped. You can fiddle around with the different sizing to try to make the layout more dynamic, but I think this is a good setup and gets you what you wanted - the pheatmap with a legend.
EDIT - ggplot option:
Since I recommended ggplot as an alternative here is some code to accomplish it:
library(ggplot2)
library(reshape)
test <- as.data.frame(matrix(rexp(200, rate=.1), ncol=20))
colnames(test) = paste("Room", 1:20, sep = "")
test$building = paste("Building", 1:10, sep = "")
#Get the sorting right
test$sort <- 1:10
#Melting data so we can plot it with GGplot
test.m <- melt(test,id.vars = c("building","sort"))
#Resetting factors
test.m$building <- factor(test.m$building, levels=(test.m$building)[order(test.m$sort)])
#Creating the plot itself
plot <- ggplot(test.m,aes(variable,building)) + geom_tile(aes(fill=value),color = "white") +
#Creating legend
guides(fill=guide_colorbar("Temperature [°C]")) +
#Creating color range
scale_fill_gradientn(colors=c("skyblue","yellow","tomato"),guide="colorbar") +
#Rotating labels
theme(axis.text.x = element_text(angle = 270, hjust = 0,vjust=-0.05))
plot
Which produces this plot:
As you can see the ggplot2 method is much faster. All you have to do is convert your data to a dataframe and then melt it. Once that's done, you can easily change the legend titles.

Related

Reorganize sf multi-plot and add a legend

I'm trying to plot two maps side by side using sf::plot and I can't manage to get it to work. There is two problems, the first one is that the plots are made on top of each other instead of side by side and the second is that I lose the legend.
Here is a example and more explanations.
library(sf)
library(dplyr)
# preparing the shapefile
nc <- st_read(system.file("gpkg/nc.gpkg", package="sf"), quiet = TRUE) %>%
select(AREA, PERIMETER) %>%
mutate(AREA = as.factor(AREA<median(AREA)))
If I plot every field independently:
plot(nc[,1])
plot(nc[,2])
Both images are nice, with a legend and all, but I want both on the same panel. sf::plot offers this feature built in as explained in https://r-spatial.github.io/sf/articles/sf5.html#geometry-with-attributes-sf:
plot(nc)
I lose the legend and they are on top of each other instead of side by side. In ?plot you can read:
For more control over individual maps, set parameter mfrow with par
prior to plotting, and plot single maps one by one.
But when I do, it doesn't work:
par(mfrow=c(1,2))
plot(nc[,1])
plot(nc[,2])
par(mfrow=c(1,1))
Any idea how to plot 2 maps side by side with sf?
Finally, it was a problem in the documentation. To be able to use par with sf::plot you need to do either:
par(mfrow=c(1,2))
plot(st_geometry(nc[,1]))
plot(st_geometry(nc[,2]))
par(mfrow=c(1,1))
or
par(mfrow=c(1,2))
plot(nc[,1], key.pos = NULL, reset = FALSE)
plot(nc[,2], key.pos = NULL, reset = FALSE)
par(mfrow=c(1,1))
However, you lose the colors in the first case and lose the legend in both cases. You have to manage it yourself manually.
see: https://github.com/r-spatial/sf/issues/877
I didn`t found the solution in sf package. I found this that probably works fine for you
library(ggplot2)
area<-ggplot() + geom_sf(data = nc[,1], aes(fill = AREA))
perim<-ggplot() + geom_sf(data = nc[,2], aes(fill = PERIMETER))
gridExtra::grid.arrange(area,perim,nrow=1)
To add to #Bastien's answer, you can add a legend manually. Here's a simple function that will add a continuous legend using the leaflet and plotrix libraries:
addLegendToSFPlot <- function(values = c(0, 1), labels = c("Low", "High"),
palette = c("blue", "red"), ...){
# Get the axis limits and calculate size
axisLimits <- par()$usr
xLength <- axisLimits[2] - axisLimits[1]
yLength <- axisLimits[4] - axisLimits[3]
# Define the colour palette
colourPalette <- leaflet::colorNumeric(palette, range(values))
# Add the legend
plotrix::color.legend(xl=axisLimits[2] - 0.1*xLength, xr=axisLimits[2],
yb=axisLimits[3], yt=axisLimits[3] + 0.1 * yLength,
legend = labels, rect.col = colourPalette(values),
gradient="y", ...)
}
To use the above function with #Bastien's code:
# Load required libraries
library(sf) # Working spatial data
library(dplyr) # Processing data
library(leaflet) # Has neat colour palette function
library(plotrix) # Adding sf like legend to plot
# Get and set plotting window dimensions
mfrowCurrent <- par()$mfrow
par(mfrow=c(1,2))
# Add sf plot with legend
plot(nc[,1], key.pos = NULL, reset = FALSE)
addLegendToSFPlot(values = c(0, 1),
labels = c("False", "True"),
palette = c("lightseagreen", "orange"))
# Add sf plot with legend
plot(nc[,2], key.pos = NULL, reset = FALSE)
valueRange <- range(nc[, 2, drop = TRUE])
addLegendToSFPlot(values = seq(from = valueRange[1], to = valueRange[2], length.out = 5),
labels = c("Low", "", "Medium", "", "High"),
palette = c("blue", "purple", "red", "yellow"))
# Reset plotting window dimensions
par(mfrow=mfrowCurrent)

Customize breaks on a color gradient legend using base R

Here is a sample script using random numbers instead of real elevation data.
library(gridExtra)
library(spatstat) #im function
elevation <- runif(500, 0, 10)
B <- matrix(elevation, nrow = 20, ncol = 25)
Elevation_Map <- im(B)
custom <- colorRampPalette(c("cyan","green", "yellow", "orange", "red"))
plot(Elevation_Map, col = custom(10), main = NULL)
This is the plot and legend that I get:
This is the legend that I am trying to recreate in R (this one made in Word):
I know this is possible and its probably a simple solution but I've tried using some examples I found online to no avail.
This plot (with real elevation data) is an art piece that will be hung in a gallery, with the elevation plot on 1 board and the legend on a separate board. I tried to get R to plot just the plot without the legend using
plot(Elevation_Map, col = custom(10), main = NULL, legend = NULL)
like I have in the past but for some reason it always plots the legend with the plot. As of right now I'm planning on just cropping the .pdf into 2 separate files to achieve this.
Here are two ways of doing it using other packages:
# example data, set seed to reproduce.
set.seed(1); elevation <- runif(500, 0, 10)
B <- matrix(elevation, nrow = 20, ncol = 25)
#Elevation_Map <- im(B)
custom <- colorRampPalette(c("cyan","green", "yellow", "orange", "red"))
1) Using fields package, image.plot(), it is same "base" graphics::image.default() plot but with more arguments for customisation (but couldn't remove the ticks from legend):
library(fields)
image.plot(B, nlevel = 10, col = custom(10),
breaks = 1:11,
lab.breaks = c("Low Elevation", rep("", 9), "High Elevation"),
legend.mar = 10)
2) Using ggplot package, geom_raster function:
library(ggplot2)
library(reshape) # convert matrix to long dataframe: melt
B_melt <- reshape2::melt(B)
head(B_melt)
ggplot(B_melt, aes(X1, X2, fill = value)) +
geom_raster() +
theme_void() +
scale_fill_gradientn(name = element_blank(),
breaks = c(1, 9),
labels = c("Low Elevation", "High Elevation"),
colours = custom(10))
The code in the original post is using the im class from the spatstat package. The plot command is dispatched to plot.im. Simply look at help(plot.im) to figure out how to control the colour ribbon. The relevant argument is ribargs. Here is a solution:
plot(Elevation_Map, col=custom(10), main="",
ribargs=list(at=Elevation_Map$yrange,
labels=c("Low Elevation", "High Elevation"),
las=1))

Too many legend items making it impossible to read

I have a SpatialPolygonsDataFrame with 213 Ecoregions to plot.
My issue is that I'm not able to organize the legend in a way that I could indeed read the legend. I'm new to r and I've been trying this for 2 days now, I feel really stupid... I wonder if anyone could give me some hint on how to achieve this goal.
#### Download and unzip ecoregions ####
#the reference for this ecoregions data: https://doi.org/10.1093/biosci/bix014
#Don't forget to change the path to a path of your own
dir_eco<-"C:/Users/thai/Desktop/Ecologicos/w2"
download.file("https://storage.googleapis.com/teow2016/Ecoregions2017.zip",
file.path(paste0(dir_eco,"/","Ecoregions2017.zip",sep="")))
unzip("Ecoregions2017.zip")
#Read this shapefile
#install.packages("rgdal")
library(rgdal)
ecoreg_shp<- readOGR("Ecoregions2017.shp")
#Crop to a smaller extent
xmin=-120; xmax=-35; ymin=-60; ymin2=-40; ymax=35
limits2 <- c(xmin, xmax, ymin2, ymax) # Just from mexico to Uruguay.
ecoreg_shp<-crop(ecoreg_shp,limits2)
# Color palette - one color for each attribute level
n <- 213
color = grDevices::colors()[grep('gr(a|e)y', grDevices::colors(), invert = T)]
# pie(rep(1,n), col=sample(color, n)) #just to take a look at the colors
col_samp<-sample(color, n)
ecoreg_shp#data$COLOR<-col_samp #put the colors in the polygons data frame
#Plot
png(file="29_ecoreg2.png", width=3000, height=3000, units="px", res=300)
par(mar=c(50,0.3,1.5,0),pty="s")
spplot(ecoreg_shp, zcol = "ECO_NAME", col.regions = ecoreg_shp#data$COLOR,
colorkey = list(space = "bottom", height = 1))
dev.off()
Now, this is how this plot looks like:
I've managed to put this legend at the right of the map, but gets also too overlayed... I've tried to do colorkey = FALSE and set a separate legend...
#Plot the map with no legend
spplot(ecoreg_shp, zcol = "ECO_NAME", col.regions = ecoreg_shp#data$COLOR,
colorkey = FALSE)
#Now, just the legend
legend("bottom",legend=ecoreg_shp#data$ECO_NAME,fill=ecoreg_shp#data$COLOR, ncol=3)
But doesn't work.. I get a message that plot.new has not been called yet
I've managed to do a lot of things with the legend, but I can't make it good... Like the legend item below the map in 2 or 3 columns in a long figure... Actually doesn't matter the format at all, I just wanted to be able to make a good figure. Can anyone point me in some direction? I'm trying to learn ggplot2, but I don't know r enough yet for using such a difficult package.
Thank you in advance, any tip is much appreciated.
As said in the comments, you will not really be able to distinguish between colors. You should define a classification with multiple levels and choose similar colors for similar ecoregions.
Nevertheless, you can create an image only for this long legend as follows. I used a reproducible example as I do not have your dataset but I use the same names as yours so that you can directly use the script:
library(sp)
library(rgdal)
n <- 213
dsn <- system.file("vectors", package = "rgdal")[1]
ecoreg_shp <- readOGR(dsn = dsn, layer = "cities")
ecoreg_shp <- ecoreg_shp[1:n,]
# Color palette - one color for each attribute level
color <- grDevices::colors()[grep('gr(a|e)y', grDevices::colors(), invert = T)]
col_samp <- sample(color, n)
ecoreg_shp#data$COLOR <- col_samp #put the colors in the polygons data frame
ecoreg_shp#data$ECO_NAME <- ecoreg_shp#data$NAME
# Define a grid to plot the legend
grid.dim <- c(45, 5)
ecoreg_shp#data$ROW <- rep(rev(1:grid.dim[1]), by = grid.dim[2], length.out = n)
ecoreg_shp#data$COL <- rep(1:grid.dim[2], each = grid.dim[1], length.out = n)
# Plot the legend
png(file = "legend.png",
width = 21, height = 29.7,
units = "cm", res = 300)
par(mai = c(0, 0, 0, 0))
plot(ecoreg_shp#data$COL,
ecoreg_shp#data$ROW,
pch = 22, cex = 2,
bg = ecoreg_shp#data$COLOR,
xlim = c(0.8, grid.dim[2] + 1),
xaxs = "i")
text(ecoreg_shp#data$COL,
ecoreg_shp#data$ROW,
ecoreg_shp#data$ECO_NAME,
pos = 4, cex = 0.75)
dev.off()
The result:

How to add text to a specific/fixed location in rasterVis levelplot

In fact, this question is consist of two questions targeting the same behaviour.
How can I add text (varies by each panel) to a fixed location in
panel area? I'm aware of panel.text and latticeExtra::layer
solution but it adds text using plotting area coordinates. For
instance, I want to add text to bottom-right corner of each panel
even if their scales are different.
How to add text out of levelplot panel area(s)? Method explained
here requires that levelplot has a plot_01.legend.top.vp area
to add text which I don't have and the trellis object was plotted
before. Besides, I want to add text to left of ylab shown in the
figure below. I used ylab here to state the meaning of rows but I
need a second ylab that represents y-axis values. I found another
question for this problem but It does not work.
The plot above is created by raster::stack object and a rasterVis::levelplot method. I consent to a dirty solution even if I prefer an elegant one. Also despite the question above, I'm open to other approaches that use levelplot.
A very similar issue is currently being discussed on R-sig-Geo, just have a look at the solution I provided there. Here is the corresponding sample code which lets you add custom text annotations inside or outside the panel regions of a trellis graph using trellis.focus(..., clip.off = TRUE) from lattice.
library(rasterVis)
library(grid)
## sample data
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
s <- stack(r, r+500, r-500, r+200)
p <- levelplot(s, layout = c(2, 2), names.att = rep("", 4),
scales = list(y = list(rot = 90)))
## labels
cls <- c("col1", "col2")
rws <- c("row1", "row2")
png("~/rasterVis.png", width = 14, height = 16, units = "cm", res = 300L)
grid.newpage()
print(p, newpage = FALSE)
## loop over panels to be labelled (ie 1:3)
panels = trellis.currentLayout()
for (i in 1:3) {
# focus on current panel of interest and disable clipping
ids <- which(panels == i, arr.ind = TRUE)
trellis.focus("panel", ids[2], ids[1], clip.off = TRUE)
# add labels
if (i %in% c(1, 3)) {
if (i == 1) {
grid.text(cls[1], x = .5, y = 1.1) # add 'col1'
grid.text(rws[1], x = -.35, y = .5, rot = 90) # add 'row1'
} else {
grid.text(rws[2], x = -.35, y = .5, rot = 90) # add 'row2'
}
} else {
grid.text(cls[2], x = .5, y = 1.1) # add 'col2'
}
trellis.unfocus()
}
dev.off()
You may find some further information here:
https://stat.ethz.ch/pipermail/r-help/2005-June/072745.html
http://r.789695.n4.nabble.com/How-to-put-text-outside-an-xyplot-td975850.html

incorporate standalone legend in ggpairs (take 2)

tl;dr can't get a standalone legend (describing common colours across the whole plot) in ggpairs to my satisfaction.
Sorry for length.
I'm trying to draw a (lower-triangular) pairs plot using GGally::ggpairs (an extension package for drawing various kinds of plot matrices with ggplot2). This is essentially the same question as How to add an external legend to ggpairs()? , but I'm not satisfied with the answer to that question aesthetically, so I'm posting this as an extension (if suggested/recommended by commenters, I will delete this question and offer a bounty on that question instead). In particular, I would like the legend to appear outside the sub-plot frame, either putting it within one virtual subplot but allowing additional width to hold it, or (ideally) putting it in a separate (empty) subplot. As I show below, both of my partial solutions have problems.
Fake data:
set.seed(101)
dd <- data.frame(x=rnorm(100),
y=rnorm(100),
z=rnorm(100),
f=sample(c("a","b"),size=100,replace=TRUE))
library(GGally)
Base plot function:
ggfun <- function(...) {
ggpairs(dd,mapping = ggplot2::aes(color = f),
columns=1:3,
lower=list(continuous="points"),
diag=list(continuous="blankDiag"),
upper=list(continuous="blank"),
...)
}
Function to trim top/right column:
trim_gg <- function(gg) {
n <- gg$nrow
gg$nrow <- gg$ncol <- n-1
v <- 1:n^2
gg$plots <- gg$plots[v>n & v%%n!=0]
gg$xAxisLabels <- gg$xAxisLabels[-n]
gg$yAxisLabels <- gg$yAxisLabels[-1]
return(gg)
}
gg0 <- trim_gg(ggfun(legends=TRUE))
Get rid of legends in left column (as in the linked question above):
library(ggplot2) ## for theme()
for (i in 1:2) {
inner <- getPlot(gg0,i,1)
inner <- inner + theme(legend.position="none")
gg0 <- putPlot(gg0,inner,i,1)
}
inner <- getPlot(gg0,2,2)
inner <- inner + theme(legend.position="right")
gg0 <- putPlot(gg0,inner,2,2)
Problems:
the blank panel behind the legend is actually masking some points; I don't know why it's not outside the panel as usual, I assume that's something that ggpairs is doing
if it were outside the panel (on top or to the right), I would want to make sure to leave some extra space so the panels themselves were all the same size. However, ggmatrix/ggpairs looks very inflexible about this.
The only alternative I've been able to try to far is following ggplot separate legend and plot by extracting the legend and using gridExtra::grid.arrange():
g_legend <- function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)
}
library(gridExtra)
grid.arrange(getPlot(gg0,1,1),
g_legend(getPlot(gg0,2,2)),
getPlot(gg0,2,1),
getPlot(gg0,2,2)+theme(legend.position="none"),
nrow=2)
Problems:
the axes and labels suppressed by ggpairs are back ...
I also considered creating a panel with a special plot that contained only the legend (i.e. trying to use theme(SOMETHING=element.blank) to suppress the plot itself, but couldn't figure out how to do it.
As a last resort, I could trim the axes where appropriate myself, but this is practically reinventing what ggpairs is doing in the first place ...
With some slight modification to solution 1: First, draw the matrix of plots without their legends (but still with the colour mapping). Second, use your trim_gg function to remove the diagonal spaces. Third, for the plot in the top left position, draw its legend but position it into the empty space to the right.
data(state)
dd <- data.frame(state.x77,
State = state.name,
Abbrev = state.abb,
Region = state.region,
Division = state.division)
columns <- c(3, 5, 6, 7)
colour <- "Region"
library(GGally)
library(ggplot2) ## for theme()
# Base plot
ggfun <- function(data = NULL, columns = NULL, colour = NULL, legends = FALSE) {
ggpairs(data,
columns = columns,
mapping = ggplot2::aes_string(colour = colour),
lower = list(continuous = "points"),
diag = list(continuous = "blankDiag"),
upper = list(continuous = "blank"),
legends = legends)
}
# Remove the diagonal elements
trim_gg <- function(gg) {
n <- gg$nrow
gg$nrow <- gg$ncol <- n-1
v <- 1:n^2
gg$plots <- gg$plots[v > n & v%%n != 0]
gg$xAxisLabels <- gg$xAxisLabels[-n]
gg$yAxisLabels <- gg$yAxisLabels[-1]
return(gg)
}
# Get the plot
gg0 <- trim_gg(ggfun(dd, columns, colour))
# For plot in position (1,1), draw its legend in the empty panels to the right
inner <- getPlot(gg0, 1, 1)
inner <- inner +
theme(legend.position = c(1.01, 0.5),
legend.direction = "horizontal",
legend.justification = "left") +
guides(colour = guide_legend(title.position = "top"))
gg0 <- putPlot(gg0, inner, 1, 1)
gg0

Resources