I have converted a raster to a point matrix in R. The file has 3 columns, x (lon), y (lat) and v (pixel value) - I am now looking to delete every second column by x and every second row by y as shown in the upper left corner of the image but am at loss how to do this. The idea is to thin the data without any interpolation or resampling.
Sample data as shown can be accessed here: https://drive.google.com/file/d/1XGEPsPEyrVNLEcZy-C6ES5915kWIaqGz/view?usp=sharing
When asking an R question, please always include a minimal reproducible, self-contained example, that is show some code and do not rely on files that must be downloaded.
As you started out with raster data, it is probably easiest to manipulate the raster data before creating points.
With the raster package:
Example data
library(raster)
r <- raster(nrow=20, ncol=20, xmn=0, xmx=1, ymn=0, ymx=1, crs="+proj=utm +zone=1 +datum=WGS84")
values(r) <- 1:ncell(r)
p <- rasterToPoints(r)
plot(r)
points(p, cex=.5)
Solution
i <- seq(1, nrow(r), 2)
j <- seq(1, ncol(r), 2)
r[i,] <- NA
r[, j] <- NA
pp <- rasterToPoints(r)
points(pp, pch=20, cex=2)
Or with the terra package:
library(terra)
r <- rast(nrow=20, ncol=20, xmin=0, xmax=1, ymin=0, ymax=1, crs="+proj=utm +zone=1 +datum=WGS84")
values(r) <- 1:ncell(r)
p <- as.points(r)
plot(r)
points(p, cex=.5)
i <- seq(1, nrow(r), 2)
j <- seq(1, ncol(r), 2)
r[i,] <- NA
r[, j] <- NA
pp <- as.points(r)
points(pp, pch=20, cex=2)
Does this work? Hard to know what to manipulate without a reproducible example and desired output, but this should remove even rows and columns from your matrix.
library(dplyr)
matrix(1:100, nrow = 10) %>%
as.data.frame() %>%
filter(row_number() %% 2 != 0) %>%
select(seq(1, ncol(.), 2)) %>%
as.matrix()
Related
library(raster)
library(rnaturalearth)
library(terra)
r <- raster::getData('CMIP5', var='tmin', res=10, rcp=45, model='HE', year=70)
r <- r[[1]]
shp <- rnaturalearth::ne_countries()
newcrs <- "+proj=robin +datum=WGS84"
r <- rast(r)
shp <- vect(shp)
r_pr <- terra::project(r, newcrs)
shp_pr <- terra::project(shp, newcrs)
For every country in shp_pr, I want to normalise the underlying raster
on a scale of 0-1. This means dividing a cell by the sum of all the cells within a country boundary and repeating it for all the countries. I am doing this as follows:
country_vec <- shp$sovereignt
temp_ls <- list()
for(c in seq_along(country_vec)){
country_ref <- country_vec[c]
if(country_ref == "Antarctica") { next }
shp_ct <- shp[shp$sovereignt == country_ref]
r_country <- terra::crop(r, shp_ct) # crops to the extent of boundary
r_country <- terra::extract(r_country, shp_ct, xy=T)
r_country$score_norm <- r_country$he45tn701/sum(na.omit(r_country$he45tn701))
r_country_norm_rast <- rasterFromXYZ(r_country[ , c("x","y","score_norm")])
temp_ls[[c]] <- r_country_norm_rast
rm(shp_ct, r_country, r_country_norm_rast)
}
m <- do.call(merge, temp_ls)
I wondered if this is the most efficient/right way to do this i.e. without any for loop and anyone has any suggestions?
Somewhat updated and simplified example data (there is no need for projection the data)
library(terra)
library(geodata)
r <- geodata::cmip6_world("HadGEM3-GC31-LL", "585", "2061-2080", "tmin", 10, ".")[[1]]
v <- world(path=".")
v$ID <- 1:nrow(v)
Solution
z <- rasterize(v, r, "ID", touches=TRUE)
zmin <- zonal(r, z, min, na.rm=TRUE, as.raster=TRUE)
zmax <- zonal(r, z, max, na.rm=TRUE, as.raster=TRUE)
x <- (r - zmin) / (zmax - zmin)
Note that the above normalizes the cell values for each country between 0 and 1.
To transform the data such that the values add up to 1 (by country), you can do:
z <- rasterize(v, r, "ID", touches=TRUE)
zsum <- zonal(r, z, sum, na.rm=TRUE, as.raster=TRUE)
x <- r / zsum
I'd like to create histograms of raster values for polygons based on different combinations of their attributes. Reproducible data below:
library(raster)
library(sp)
poly <- raster(nrow=10, ncol=10)
poly[] <- runif(ncell(poly)) * 10
poly <- rasterToPolygons(poly, fun=function(x){x > 9})
r <- raster(nrow=100, ncol=100)
r[] <- runif(ncell(r))
poly#data$place<-sample(letters[1:3], length(poly), TRUE)
poly#data$rank<-sample.int(3, length(poly), replace = TRUE)
plot(r)
plot(poly, add=TRUE, lwd=4)
v <- raster::extract(r, poly, df=TRUE)
I can plot a histogram for all of the IDs (i.e., polygons) in v with ggplot
ggplot(v, aes(layer)) + geom_histogram(aes(y = stat(count / sum(count))), binwidth = 0.25)
However, I'd like to create a set of three histograms based on the rank attribute (i.e., 1,2,3) and another set of three histograms based on the place attribute (i.e., a,b,c). Perhaps using facet in ggplot but I'm not sure how to link the IDs in v to the attributes in poly.
Your example:
library(raster)
#Loading required package: sp
pr <- raster(nrow=10, ncol=10)
set.seed(1)
values(pr) <- runif(ncell(pr)) * 10
poly <- rasterToPolygons(pr, fun=function(x){x > 9})
poly$place <- sample(letters[1:3], length(poly), TRUE)
poly$rank <- sample.int(3, length(poly), replace = TRUE)
r <- raster(nrow=100, ncol=100)
values(r) <- runif(ncell(r))
v <- raster::extract(r, poly, df=TRUE)
Assign an explicit ID the polygons, only keep variables of interest, and extract the data.frame from the SpatialPolygonsDataFrame.
poly$ID <- 1:length(poly)
poly$layer <- NULL
d <- data.frame(poly)
Merge
vd <- merge(d, v, by="ID")
Select a subset and make a histogram
x <- vd[vd$place == "a",]
hist(x$layer)
I'm looking for some advice on basic geospatial statistics.
I'm using a raster file from Worldpop , indicating the population in Brazil every 100m2. I have another latlong dataset with the coordinates of hospitals in Brazil.
I would like to do the following:
Identify areas (and possibly create polygons) of areas that are within 1km from the hospitals, between 2-10km and above 10km
Calculate the number of people in each of the zones above
I'd like to provide some reproducible example, but the raster file is very large. There are some instructions on how to do this with two separate lists of lat/lon points, but I can't figure out how to do this with a raster file.
Any ideas?
Example data
library(raster)
bra <- getData('GADM', country="BRA", level=1)
r <- raster(bra, res=1)
values(r) <- 1:ncell(r)
r <- mask(r, bra)
pts <- coordinates(bra)
# plot(r)
# points(pts)
Solution
b1 <- extract(r, pts, buffer=100000) # 100 km
b2 <- extract(r, pts, buffer=200000) # 200 km
pop1 <- sapply(b1, sum)
pop2 <- sapply(b2, function(i)sum(i, na.rm=TRUE)) - pop1
To see the areas
spts <- SpatialPoints(pts, proj4string=crs(bra))
buf1 <- buffer(spts, width=100000, dissolve=FALSE)
buf2 <- buffer(spts, width=200000, dissolve=FALSE)
# adding IDs so that they can also be used in "extract"
buf1 <- SpatialPolygonsDataFrame(buf1, data.frame(id1=1:length(buf1)))
buf2 <- SpatialPolygonsDataFrame(buf2, data.frame(id2=1:length(buf2)))
# To combine buf1 and buf2 you could do
# buf <- (buf2-buf1) + buf1
# but in this example there are overlapping buffers, so I do
bb <- list()
for (i in 1:length(buf1)) {
bb[[i]] <- (buf2[i,]-buf1[i,]) + buf1[i,]
}
buf <- do.call(bind, bb)
plot(r)
plot(buf, col=c("red", "blue"), add=TRUE)
And now you could do
z <- extract(r, buf, fun=sum, na.rm=TRUE)
z <- cbind(data.frame(buf), z)
head(z)
To get the same result as above for pop1 and pop2
head(pop1)
head(pop2)
I would like to plot the SpatialPointsDataFrame points over raster by attributes attr1. Specifically, I would like 1's to be red and 0's to be blue circles. Help will be appreciated.
s <- 1 # scale
increment <- seq(-6,6,1) # Create a sequence of x values
y=matrix(0,length(increment))
for (i in 1:length(increment)) {
y[i] <- 1/(1+ exp(-(increment[i])/s))
}
# Create matrix:
rep <- 8
valuematrix <- replicate(rep,y[,1])
library(sp)
library(raster)
raster <- raster(valuematrix)
# Create SpatialPointsDataFrame
x <- c(0.2,0.04,0.7)
y <- c(0.34,0.5,0.9)
attr1 <- c(0,1,0)
attr2 <- c(32,13,30)
data_DF <- data.frame(x,y,attr1,attr2)
colnames(data_DF) <- c("x","y","attr1","attr2")
coords <- data.frame(data_DF$x, data_DF$y)
coords <- SpatialPoints(coords, proj4string=CRS(as.character(NA)), bbox = NULL)
initialdata_DF <- data.frame(coords,data_DF$attr1,data_DF$attr2)
initialdata_SPDF <- SpatialPointsDataFrame(coords,initialdata_DF)
plot(raster)
plot(initialdata_SPDF, add=TRUE)
I need to plot a countrywide raster. I tried cellsize=300 and use 64-bit system. Memory.limit() is 8148. When running the code, it still gives me an "Error: cannot allocate vector of size 3.6 Gb". Sometimes, Windows stops working--even worse...
Is there any other way that I can deal with such large dataset? Btw, I am more familiar with ArcGIS. Thanks!!!
{
x.min <- -6328997.74765339; x.max <- 2182662.25234661 # Extent of easting coordinates
y.min <- 310413.438361092; y.max <- 5448183.43836109 # Extent of northing coordinates
n <- 2351
center <- read.csv ("J:\\...,header=T)
attach(center)
center <- as.matrix (center) # XY corrdinates #
emp <- read.csv ("J:\\...,header=T, sep=",")
attach(emp)
n.rows <- 17126
cellsize <- 300
n.cols <- 28373
x.max <- x.min + n.cols * cellsize # Assures square cells are used#
y.0 <- seq(y.max-cellsize/2, y.min+cellsize/2, length.out=n.rows)
x.0 <- seq(x.min+cellsize/2, x.max-cellsize/2, length.out=n.cols)
system.time(
{
i <- order(emp, decreasing=TRUE)
emp <- emp[i]
center <- center[i, , drop=FALSE]
owner <- matrix(0, n.rows, n.cols)
gravity.max <- matrix(0, n.rows, n.cols)
for (i in 1:n) {
r <- emp[i] / outer((y.0 - center[i,2])^2, (x.0 - center[i,1])^2, "+")
update <- which(r >= gravity.max)
gravity.max[update] <- r[update]
owner[update] <- i
}
})
You might try the raster package.
raster can work with large rasters. It is used by lots of people who do spatial analyses in R.
You will save a lot of time if you first read the vignette Introduction to the raster package to get familiar with the package.