Combining rasters' legends in R language - r

Sorry for the evidently stupid question I haven't be able to solve, even after googleing for a while. Let's suppose the following situation, where I have two rasters with overlapping but different value ranks.
library(raster)
# A couple of rasters from scratch
r2 <- r1 <- raster(nrows=10, ncols=10)
r1[] <- sample(c(0:99), 100, replace = F)
r2[] <- sample(c(50:149), 100, replace = F)
par(mfrow = c(1,2))
plot(r1)
plot(r2)
How may I create the same plot but with only one legend ranging from 0 to 149, that is, the combined rank of both rasters?

Based on the answer I shared in the previous comment, you can manually set the breaks of the legend and the colors. Then you just need to apply that color ramp to both plots. Here's the code and the plot.
# Adjust plot margins
par(mar=c(2,2,2,5))
# Set manually the breaks
breaks = seq(0,150,25)
pal <- colorRampPalette(c("white","orange","yellow","green","forestgreen"))
plot(r1, breaks=breaks, col = pal(length(breaks)-1))
plot(r2, breaks=breaks, col = pal(length(breaks)-1))

Related

Plotting a GeoTIFF raster in R

I am trying to plot a gridded population count GeoTIFF raster downloaded from here.
library(raster)
#----------------------------#
# Set your working directory #
#----------------------------#
setwd(dirname(rstudioapi::getActiveDocumentContext()$path)) # RStudio IDE preferred
getwd() # Path to your working directory
# Import the GeoTIFF file into R workspace
WorldPop <- raster("nga_ppp_2020_1km_Aggregated_UNAdj.tif")
WorldPop
#---------------------------#
# Data plotted in log-scale #
#---------------------------#
tempcol <- colorRampPalette(c("lightblue", "skyblue", "blue", "yellow", "orange", "red", "darkred"))
plot(log(WorldPop), main = "2020 UN-Adjusted Population Count (log-scale) \n (each grid cell is 1 km x 1 km)", col=tempcol(100), legend.width=2, legend.shrink=1, legend.args=list(text='log(Persons)', side=4, font=2, line=2.5, cex=0.8), axes=T)
#--------------------------------#
# Data plotted in absolute-scale #
#--------------------------------#
plot(WorldPop, main = "2020 UN-Adjusted Population Count (absolute-scale) \n (each grid cell is 1 km x 1 km)", col=tempcol(100), legend.width=2, legend.shrink=1, legend.args=list(text='Persons', side=4, font=2, line=2.5, cex=0.8), axes=T)
Plot 1 (log-scale)
Plot 2 (absolute-scale)
I like the Plot 1 (data in log-scale) but Plot 2 (data in absolute-scale) is not showing any variations in color. How can I make the plot of data in absolute-scale look similar to the one in log-scale?
I am open to using other packages (ggplot2 etc.) or other color palates as long as my plot can distinguish densely populated areas from rural areas. When I used a different GIS tool called Panoply my favorite color palate was something called seminf-haxby.cpt (found here). It looks something like this
I am trying to replicate that in R but the plot in absolute-scale isn't looking good. Any tips or advice for plotting tif rasters in R?
You can set breaks, something like this:
Example data
url <- "https://data.worldpop.org/GIS/Population/Global_2000_2020_1km_UNadj/2020/NGA/nga_ppp_2020_1km_Aggregated_UNadj.tif"
fname <- basename(url)
if (!file.exists(fname)) download.file(url, fname, mode="wb")
Solution
library(terra)
r <- rast(fname)
plot(r, col=rev(rainbow(10, end=0.7)), breaks=c(0, 10, 25, 50, 100, 250, 1000, 100000))
Now your second question (it is better to not ask two rather different questions at the same time).
The function below extracts the colors from the palette image in your question, and should also work for other palette images organized like yours.
getPal <- function(f) {
x <- rast(f)
u <- unique(values(x))
hex <- rgb(u[,1], u[,2], u[,3], maxColorValue = 255)
colorRampPalette(hex)
}
pal <- getPal("https://i.stack.imgur.com/E4d85.png")
par(mar=c(0,0,0,0))
barplot(rep(1, 25), col=pal(25), space=0)
An alternative way to apply breaks is to first use classify. I remove the first color (white)
x <- classify(r, c(0, 10, 25, 50, 100, 250, 1000, 100000))
plot(x, col=pal(8)[-1])
You could change the labels, for example like this
levs <- levels(x)[[1]]
levs[7] <- "> 1000"
levels(x) <- levs
To use this palette in your R code you can create it like this (remove '#FFFFFF' if you do not want to start with white)
ramp <- c('#FFFFFF', '#D0D8FB', '#BAC5F7', '#8FA1F1', '#617AEC', '#0027E0', '#1965F0', '#0C81F8', '#18AFFF', '#31BEFF', '#43CAFF', '#60E1F0', '#69EBE1', '#7BEBC8', '#8AECAE', '#ACF5A8', '#CDFFA2', '#DFF58D', '#F0EC78', '#F7D767', '#FFBD56', '#FFA044', '#EE4F4D')
pal <- colorRampPalette(ramp)

classify raster stack with levelplot (RasterVis)

i have a raster stack of 7 rasters with quite varying data ranges and not all of the rasters adhere to quite the same range. (some are low value ranges, some much higher). Using the levelplot function with the stack, it plots nicely enough, eg:
r <- raster(ncol=10,nrow=10)
r[] <- sample(c(1:3),size=100,replace=T)
r1 <- raster(ncol=10,nrow=10)
r1[] <- sample(c(1:9),size=100,replace=T)
r2 <- raster(ncol=10,nrow=10)
r2[] <- sample(c(5:15),size=100,replace=T)
r3 <- raster(ncol=10,nrow=10)
r3[] <- sample(c(3:35),size=100,replace=T)
s <- stack(r,r1,r2,r3)
breaks <- 7
my.at <- round(seq(min(minValue(s)), max(maxValue(s)), length.out = breaks),digits=2)
myColorkey <- list(at=my.at,height=0.95, width=1, labels=list(at=my.at,cex=1.1))
cols <- (brewer.pal(length(my.at)-1, "YlGnBu"))
levelplot(s,at=my.at,col.regions=cols,colorkey = myColorkey)
As you can see, the images with the lower value data are one colour (Actually in my real data most of the plots are one colour as the data range is dominated by two latter rasters). Using the levelplot function, i would like to reclassify the entire raster stack, teasing out some patterns in the lower value rasters with some classes that i define and simply assign anything over value x (perhaps 10 in the sample data above) to be one colour.
the usual method of ratifying and setting levels will not work for a stack and any workaround i have tried (using a matrix and reclassify) will not force more levels than there are classes for a raster
this is my workaround, using the standard legend, but i'd like to use ratify etc if possible;
# using s from above
m <- c(0,1,1, 1,3,2, 3,6,3, 6,10,4, 10,35,5)
mat <- matrix(m, ncol=3, byrow=TRUE)
src <- reclassify(s, mat)
breaks <- nrow(mat)
my.at <- (0:breaks)
myColorkey <- list(at=my.at,height=0.95, width=1, labels=list(at=my.at+0.5,labels=c("0-1","1-3","3-6","6-10","10-35"),cex=1.1))
cols <- (brewer.pal(length(my.at)-1, "YlGnBu"))
levelplot(src,at=my.at,col.regions=cols,colorkey = myColorkey)

Add shading to R base plot

I have a simple plot:
x1<- sort(rnorm(100))
x_max <- x1-0.5
x_min <- x1+0.5
plot(x1,type='l')
points(x_max,type='l',col="red")
points(x_min,type='l',col="red")
I would like to add grey shading between the two red lines.
I am looking for a solution that uses the basic R plotting function of R and not ggplot.
You can try using polygon. If you set the color for the polygon with an alpha channel then things don't overwrite anything. Also adding the suggestion by #rawr to use panel.first.
x1 <- sort(rnorm(100))
x_max <- x1-0.5
x_min <- x1+0.5
plot(x1, type = 'l', panel.first = polygon(c(1:length(x1),length(x1):1), c(x_min, rev(x_max)), col="#eeeeeeaa", border = NA))
points(x_max,type='l',col="red")
points(x_min,type='l',col="red")

ScatterPlot between two rasters, giving color from a third raster

I'm plotting two rasters data, producing the image below.
I'd like to color each point in the graph with a variable taken from a third raster data (with the same bbox, pixel size etc.).
Any ideas from R-Users? This operation is very easy in plotting data from a dataset, but I don’t know about raster…
Here I attach the code (simplified, I think you don't need all the plot parameters e.g. abline, xlab and so on) that produced the image:
plot(mask(raster1, my_mask,maskvalue=0), #first raster, masked by my_mask
mask(raster2, my_mask,maskvalue=0), #second raster, masked by my_mask
col = alpha('black', 0.1), #the current color scheme
)
raster3 #raster with categorical variable,
#that should give the colors to the points in the graph
Thanks a lot!
With the xyplot method defined in
rasterVis
you can use layers of a RasterStack as if they were columns of a
data.frame. Therefore, they can be the components of the formula or
the groups argument.
For example,
library(raster)
library(rasterVis)
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
r2 <- r + 500 * init(r, rnorm)
## categorical variable
r3 <- cut(r, 3)
s <- stack(r, r2, r3)
names(s) <- c('r', 'r2', 'r3')
xyplot(r ~ r2, groups = r3, data = s,
auto.key = list(space = 'right'),
alpha = 1)

Easiest way to plot inequalities with hatched fill?

Refer to the above plot. I have drawn the equations in excel and then shaded by hand. You can see it is not very neat. You can see there are six zones, each bounded by two or more equations. What is the easiest way to draw inequalities and shade the regions using hatched patterns ?
To build up on #agstudy's answer, here's a quick-and-dirty way to represent inequalities in R:
plot(NA,xlim=c(0,1),ylim=c(0,1), xaxs="i",yaxs="i") # Empty plot
a <- curve(x^2, add = TRUE) # First curve
b <- curve(2*x^2-0.2, add = TRUE) # Second curve
names(a) <- c('xA','yA')
names(b) <- c('xB','yB')
with(as.list(c(b,a)),{
id <- yB<=yA
# b<a area
polygon(x = c(xB[id], rev(xA[id])),
y = c(yB[id], rev(yA[id])),
density=10, angle=0, border=NULL)
# a>b area
polygon(x = c(xB[!id], rev(xA[!id])),
y = c(yB[!id], rev(yA[!id])),
density=10, angle=90, border=NULL)
})
If the area in question is surrounded by more than 2 equations, just add more conditions:
plot(NA,xlim=c(0,1),ylim=c(0,1), xaxs="i",yaxs="i") # Empty plot
a <- curve(x^2, add = TRUE) # First curve
b <- curve(2*x^2-0.2, add = TRUE) # Second curve
d <- curve(0.5*x^2+0.2, add = TRUE) # Third curve
names(a) <- c('xA','yA')
names(b) <- c('xB','yB')
names(d) <- c('xD','yD')
with(as.list(c(a,b,d)),{
# Basically you have three conditions:
# curve a is below curve b, curve b is below curve d and curve d is above curve a
# assign to each curve coordinates the two conditions that concerns it.
idA <- yA<=yD & yA<=yB
idB <- yB>=yA & yB<=yD
idD <- yD<=yB & yD>=yA
polygon(x = c(xB[idB], xD[idD], rev(xA[idA])),
y = c(yB[idB], yD[idD], rev(yA[idA])),
density=10, angle=0, border=NULL)
})
In R, there is only limited support for fill patterns and they can only be
applied to rectangles and polygons.This is and only within the traditional graphics, no ggplot2 or lattice.
It is possible to fill a rectangle or polygon with a set of lines drawn
at a certain angle, with a specific separation between the lines. A density
argument controls the separation between the lines (in terms of lines per inch)
and an angle argument controls the angle of the lines.
here an example from the help:
plot(c(1, 9), 1:2, type = "n")
polygon(1:9, c(2,1,2,1,NA,2,1,2,1),
density = c(10, 20), angle = c(-45, 45))
EDIT
Another option is to use alpha blending to differentiate between regions. Here using #plannapus example and gridBase package to superpose polygons, you can do something like this :
library(gridBase)
vps <- baseViewports()
pushViewport(vps$figure,vps$plot)
with(as.list(c(a,b,d)),{
grid.polygon(x = xA, y = yA,gp =gpar(fill='red',lty=1,alpha=0.2))
grid.polygon(x = xB, y = yB,gp =gpar(fill='green',lty=2,alpha=0.2))
grid.polygon(x = xD, y = yD,gp =gpar(fill='blue',lty=3,alpha=0.2))
}
)
upViewport(2)
There are several submissions on the MATLAB Central File Exchange that will produce hatched plots in various ways for you.
I think a tool that will come handy for you here is gnuplot.
Take a look at the following demos:
feelbetween
statistics
some tricks

Resources