I am working with the following dataframe about floods in Filipines:
head(mi_dato)
lat lon flood_heig elevation precipitat
1 14.64039 121.0557 0 54.55330 9
2 14.69830 121.0021 0 21.85627 10
3 14.69886 121.1003 0 69.32281 16
4 14.57131 120.9833 0 10.98724 8
5 14.76223 121.0757 0 87.88985 18
6 14.60118 121.0886 0 14.46373 11
I made an IDW interpolation, seeking the sectors most affected by precipitations. However, trying to project the raster image of the IDW in a Leaflet code, I got the following image on the viewer:
The script is:
remove(list = ls())
library(data.table)
library(dplyr)
library(gstat)
library(sp)
library(raster)
library(readxl)
library(leaflet)
library(RColorBrewer)
#DATASET
inundacion <- as.data.frame(fread(file="Muestras inundaciones.csv",
header = TRUE, encoding = "UTF-8"))
# IDW -----------------------------------------------------------------
hist(inundacion$precipitat)
coordinates(inundacion) <- ~ lat + lon
plot(inundacion)
# CREATE GRID ------------------------------------------------------------
# Create grid automatically
x.range <- as.double(range(inundacion#coords[,1]))
y.range <- as.double(range(inundacion#coords[,2]))
grd <- expand.grid(x=seq(from=x.range[1], to=x.range[2], by=0.01),
y=seq(from=y.range[1], to=y.range[2], by=0.01))
## convert grid to SpatialPixel class
coordinates(grd) <- ~ x + y
gridded(grd) <- TRUE
## test it out - this is a good way of checking that your sample points are all well within your grid.
## If they are not, try some different values in you r x and y ranges:
plot(grd, cex = 1.5)
points(inundacion, pch = 1, col = 'red', cex = 1)
title("Interpolation Grid and Sample Points")
# INTERPOLATION -----------------------------------------------------------
idw_01 <- idw(precipitat ~ 1, inundacion, grd, idp = 3)
plot(idw_01)
idw.output <- as.data.frame(idw_01)
names(idw.output)[1:3] <- c("lon","lat","var1.pred")
# Raster layer ------------------------------------------------------------
r <- raster(idw_01) # Convert tu raster
r
proj4string(r) <- CRS("+init=epsg:3857")
crs(r)
# LEAFLET -----------------------------------------------------------------
pal <- colorNumeric(palette = "Spectral", domain = values(r), reverse = T)
leaflet() %>%
addProviderTiles(provider = providers$CartoDB) %>%
addRasterImage(x = r, colors = pal, opacity = 0.8) %>%
addLegend(pal = pal, values = values(r), title = "IDW - Inundaciones")
I would be thankful with your help!
As I understand it R lacks a methods to buffer polygons in a spatially exclusive way that preserves the topology of adjacent polygons. So I'm experimenting with an approach that generates voronoi polygons of the original polygon vertices. Results seem quite promising except for apparent errors in the voronoi generation.
Fairly old school R, so it's possible a tidier alternative may work better. This reproducible example uses US/Canada, but note the problem is one of mathematical geometry so marine boundaries are not relevant:
require(rworldmap)
require(rgeos)
require(dismo)
require(purrr)
require(dplyr)
par(mai = rep(0,4))
p = rworldmap::countriesCoarse[,'ADMIN']
p = p[p$ADMIN %in% c('United States of America', 'Canada'),]
p$ADMIN = as.character(p$ADMIN)
p = rgeos::gBuffer(p, byid=T, width = 0) # precaution to ensure no badly-formed polygon nonsense
# Not critical to the problem, but consider we have points we want to assign to enclosing or nearest polygon
set.seed(42)
pts = data.frame(x = runif(1000, min = p#bbox[1,1], max = p#bbox[1,2]),
y = runif(1000, min = p#bbox[2,1], max = p#bbox[2,2]))
coordinates(pts) = pts
pts#proj4string = p#proj4string
# point in polygon classification.
pts$admin = sp::over(pts, p)$ADMIN
pts$admin = replace(pts$admin, is.na(pts$admin), 'unclass')
plot(p)
plot(pts, pch=16, cex=.4, col = c('red','grey','blue')[factor(pts$admin)], add=T)
Let's say we want to bin the grey points to nearest polygon. I think the most elegant approach would be to create a new expanded set of polygons. This avoids lots of n-squared nearest neighbour calculations. Next we try a voronoi tesselation of the original polygon vertices:
vertices1 = map_df(p#polygons, ~ map2_df(.x#Polygons, rep(.x#ID, length(.x#Polygons)),
~ as.data.frame(..1#coords) %>% `names<-`(c('x','y')) %>% mutate(id = ..2)))
print(head(vertices1))
#> x y id
#> 1 -56.13404 50.68701 Canada
#> 2 -56.79588 49.81231 Canada
#> 3 -56.14311 50.15012 Canada
#> 4 -55.47149 49.93582 Canada
#> 5 -55.82240 49.58713 Canada
#> 6 -54.93514 49.31301 Canada
coordinates(vertices1) = vertices1[,1:2]
# voronois
vor1 = dismo::voronoi(vertices1)
# visualise
plot(p)
plot(vertices1, add=T, pch=16, cex=.5, col = c('red','blue')[factor(vertices1$id)])
plot(vor1, add=T, border='#00000010', col = c('#FF000040','#0000FF40')[factor(vor1$id)])
Lots of errors in here. Maybe due to different polygons sharing some vertices. Let's try small negative buffer to help the algorithm:
p_buff2 = rgeos::gBuffer(p, byid=T, width = -.00002) # order of 1 metre
vertices2 = map_df(p_buff2#polygons, ~ map2_df(.x#Polygons, rep(.x#ID, length(.x#Polygons)),
~ as.data.frame(..1#coords) %>% `names<-`(c('x','y')) %>% mutate(id = ..2)))
coordinates(vertices2) = vertices2[,1:2]
vor2 = dismo::voronoi(vertices2)
plot(p_buff2)
plot(vertices2, add=T, pch=16, cex=.4, col = c('red','blue')[factor(vertices2$id)])
plot(vor2, add=T, border='#00000010', col = c('#FF000040','#0000FF40')[factor(vor2$id)])
Some improvements - almost validating the approach I think. But again we still have some errors, e.g. blue chunk of British Colombia and a thin pink strip of easter border area in Alaska. Lastly I plot with a bigger buffer to help show what is happening with individual vertices (click for bigger resolution):
p_buff3 = rgeos::gBuffer(p, byid=T, width = -.5, ) # order of 30kms I think
vertices3 = map_df(p_buff3#polygons, ~ map2_df(.x#Polygons, rep(.x#ID, length(.x#Polygons)),
~ as.data.frame(..1#coords) %>% `names<-`(c('x','y')) %>% mutate(id = ..2)))
coordinates(vertices3) = vertices3[,1:2]
vor3 = dismo::voronoi(vertices3)
plot(p_buff3)
plot(vertices3, add=T, pch=16, cex=.4, col = c('red','blue')[factor(vertices3$id)])
plot(vor3, add=T, border='#00000010', col = c('#FF000040','#0000FF40')[factor(vor3$id)])
Is anyone able to shed light on the problem, or possible suggest an alternative voronoi method that works? I've tried ggvoronoi but struggled to get that working. Any assistance appreciated.
That is an interesting, and important, problem; and I think it is a good idea to use voronoi. The apparent errors arise from the distribution of the vertices. For example, the border between Canada and the USA hardly has vertices in the west. This leads to undesired results, but they are not wrong. A step in the right direction might be to add vertices, using geosphere::makePoly
library(dismo)
library(geosphere)
library(rworldmap)
library(rgeos)
w <- rworldmap::countriesCoarse[,'ADMIN']
w <- w[w$ADMIN %in% c('United States of America', 'Canada'),]
p <- geosphere::makePoly(w, 25000)
p$ADMIN = as.character(p$ADMIN)
p <- buffer(p, width = 0, dissolve=FALSE)
p_buff <- buffer(p, width = -.00002, dissolve=FALSE) # order of 1 metre
g <- geom(p_buff)
g <- unique(g)
vor <- dismo::voronoi(g[,c("x", "y")])
plot(p_buff)
points(g[,c("x", "y")], pch=16, cex=.4, col= c('red','blue')[g[,"object"]])
plot(vor, add=T, border='#00000010', col = c('#FF000040','#0000FF40')[g[,"object"]])
Dissolve the polygons by country and remove holes
v <- aggregate(vor, list(g[,"object"]), FUN=length)
gg <- data.frame(geom(v))
v <- as(gg[gg$hole==0, ], "SpatialPolygons")
lines(v, col="yellow", lwd=4)
Now use this to cut the buffer by country
pp <- buffer(p, width = 10)
buf <- v * (pp - p) # intersect(v, erase(pp, p))
buf <- SpatialPolygonsDataFrame(buf, data=data.frame(p), match.ID = FALSE)
x <- bind(p, buf)
z <- aggregate(x, "ADMIN")
lines(z, lwd=2, col="dark green")
And now for something more focused. The below does essentially the same as the above, but focuses just on the regions that matter (coastal borders) making it computationally less intensive --- although not so much for this example with a rather large buffer.
library(dismo)
library(rworldmap)
library(rgeos)
w <- rworldmap::countriesCoarse[,'ADMIN']
w <- w[w$ADMIN %in% c('United States of America', 'Canada', 'Mexico'),]
p <- geosphere::makePoly(w, 25000)
p$ADMIN = as.character(p$ADMIN)
p <- buffer(p, width = 0, dissolve=FALSE)
#p <- buffer(p, width = -.00002, dissolve=FALSE) # order of 1 metre
bsz <- 10
mbuf <- buffer(p, width = bsz, dissolve=FALSE)
# e <- mbuf[1,] * mbuf[2,]
# -----------
# general solution for e?
poly_combs = expand.grid(p1 = seq_along(mbuf), p2 = seq_along(mbuf))
poly_combs = poly_combs[poly_combs$p1 < poly_combs$p2,]
# pairwise overlaps
e_pw = plyr::compact(lapply(1:nrow(poly_combs), FUN = function(i){
pair = poly_combs[i,]
pairing = suppressWarnings(mbuf[pair$p1,] * mbuf[pair$p2,])
return(pairing)
}))
e = e_pw[[1]]
for(i in 2:length(e_pw)) e = e + e_pw[[i]]
# -----------
f <- e - p
b <- buffer(f, bsz)
# bp is the area that matters
bp <- b * p
g <- data.frame(geom(bp))
# getting rid of duplicated and shared vertices
g <- aggregate(g[,1,drop=FALSE], g[,5:6], min)
v <- dismo::voronoi(g[,c("x", "y")], extent(p)+ 2 * bsz)
v <- aggregate(v, list(g[,"object"]), FUN=length)
v <- v- p
buf1 <- buffer(p, width = bsz, dissolve=TRUE)
v <- v * buf1
v#data <- p#data
plot(v, col=c("red", "blue", "green"))
Slight adaptation from Robert's, for discussion.
library(dismo)
library(rworldmap)
library(rgeos)
w <- rworldmap::countriesCoarse[,'ADMIN']
# w <- w[w$ADMIN %in% c('United States of America', 'Canada'),]
w <- w[w$ADMIN %in% c('Guyana', 'Suriname','French Guiana'),]
p <- geosphere::makePoly(w, 25000)
p$ADMIN = as.character(p$ADMIN)
p <- buffer(p, width = 0, dissolve=FALSE)
#p <- buffer(p, width = -.00002, dissolve=FALSE) # order of 1 metre
bsz <- .5
# outward buffer
mbuf = buffer(p, width = bsz, dissolve=F)
# overlay between two country buffers
# e <- mbuf[1,] * mbuf[2,]
poly_combs = expand.grid(p1 = seq_along(mbuf), p2 = seq_along(mbuf))
poly_combs = poly_combs[poly_combs$p1 < poly_combs$p2,]
# pairwise overlaps
e_pw = plyr::compact(lapply(1:nrow(poly_combs), FUN = function(i){
pair = poly_combs[i,]
pairing = suppressWarnings(mbuf[pair$p1,] * mbuf[pair$p2,])
return(pairing)
}))
e = e_pw[[1]]
for(i in 2:length(e_pw)) e = e + e_pw[[i]]
# contested buffer zones - overlap minus original polys
f <- e - p
f#data = data.frame(id = seq_along(f))
# buffer the contested zones
b <- buffer(f, bsz)
# bp is the area that matters
bp <- b * p
# vertices
bp = buffer(bp, width = -0.00002, dissolve=F)
g0 <- data.frame(data.frame(geom(bp)))
# getting rid of duplicated and shared vertices
# g <- aggregate(g0[,'object', drop=FALSE], g0[,c('x','y')], min)
g = unique(g0)
v0 <- dismo::voronoi(g[,c("x", "y")], extend(extent(p), 2 * bsz))
v0$id = g$object
v <- raster::aggregate(v0, list(g[,"object"]), FUN=length)
v#proj4string = p#proj4string
v = v * f
v#data = data.frame(ADMIN = p$ADMIN[v$Group.1])
# full buffer
fb = raster::bind(mbuf - p - f, v, p)
fb = raster::aggregate(fb, list(fb$ADMIN), FUN = function(x)x[1])[,'ADMIN']
fb#proj4string = p#proj4string
#----------------------------------
par(mai=c(0,0,0,0))
plot(p, border='grey')
plot(mbuf, add=T, border='pink')
plot(e, add=T, col='#00000010', border=NA)
plot(f, add=T, border='purple', lwd=1.5)
plot(b, add=T, border='red')
plot(bp, add=T, col='#ffff0040', border=NA)
# plot(v, add=T, col=c("#ff770020", "#0077ff20"), border=c("#ff7700", "#0077ff"))
plot(fb, add=T, col=c("#ff000020", "#00ff0020", "#0000ff20"), border=NA)
I have overlayed two contour plots:
library(plotly)
cluster_count <- 5
volcan <- plot_ly(z = ~volcano,
type = "contour",
contours = list(
coloring= "fill",
showlines = F
))
cluster_matrix <- volcano
cluster_matrix[cluster_matrix < 100] <- 1
cluster_matrix[cluster_matrix <= 120 & cluster_matrix >= 100] <- 2
cluster_matrix[cluster_matrix < 140 & cluster_matrix >= 120] <- 3
cluster_matrix[cluster_matrix <= 160 & cluster_matrix >= 140] <- 4
cluster_matrix[cluster_matrix > 160] <- 5
cluster_name_matrix <- cluster_matrix
cluster_name_matrix[cluster_matrix ==1] <- "Eins"
cluster_name_matrix[cluster_matrix ==2] <- "Zwei"
cluster_name_matrix[cluster_matrix ==3] <- "Drei"
cluster_name_matrix[cluster_matrix ==4] <- "Vier"
cluster_name_matrix[cluster_matrix ==5] <- "Funf"
volcan %>% add_contour(cluster_matrix,
type = "contour",
opacity =1,
text=cluster_name_matrix,
hovertemplate = 'Cluster: %{text}<extra></extra>',
autocontour = F,
line=list(color="orange"),
contours = list(
start = 1,
showlabels = T,
coloring= "lines",
end = cluster_count,
size = 1,
showlines = T
))
Is it possible to have a plot like this:
Like I did for the hovering text? Thanks for tips and suggestions in advance!
What you've been looking for is the add_annotations() function. In the code below, I write a function that retrieves a random coordinate pair for each level and then passes the corresponding coordinates to the add_annotations() function. Note that I stored your contour plot in the variable p:
library(purrr)
# Custom function
find_rand_annotation_index <- function(name_matrix, string){
d <- which(name_matrix == string, arr.ind = TRUE)
d2 <- as.data.frame(d[sample(nrow(d), size = 1), , drop = FALSE])
cbind(d2, string)
}
# Get 5 random coordinates to plot the labels
text_coords <- purrr::map_dfr(c("Eins", "Zwei", "Drei", "Vier", "Funf"), ~ find_rand_annotation_index(cluster_name_matrix, .x))
# Plot the annotations on the contour plot
p %>%
add_annotations(
x = text_coords$col,
y = text_coords$row,
text = text_coords$string,
font = list(color = "IndianRed"),
showarrow = F
)
The positioning of the labels may not be to your liking (because the coordinates are chosen randomly), but you may want to do something about it in your code.
A sample data first:
library(raster)
# download a sample shape file
shape.file <- getData('GADM', country='FRA', level=2)
ID_2 <- rep(shape.file#data$ID_2,times=2)
group.id <- rep(c(100,200),each=96)
set.seed(1)
cat1<- runif(192,min=0,max=100)
set.seed(2)
cat2<- runif(192,min=0,max=100)
set.seed(3)
cat3<- runif(192,min=0,max=100)
dat <- as.data.frame(cbind(ID_2,group.id,cat1,cat2,cat3))
# extract the data for group.id = 100 and group.id = 200 in two seprate df
group.id.100 <- dat[dat$group.id==100,]
group.id.200 <- dat[dat$group.id==200,]
# merge with shape file
merge.shp.100 <- merge(shape.file,group.id.100, by="ID_2")
merge.shp.200 <- merge(shape.file,group.id.200, by="ID_2")
# plot them together
par(mfrow=c(3,2))
plot(merge.shp.100,col=merge.shp$cat1,main="Group.id.100,cat1")
plot(merge.shp.100,col=merge.shp$cat2,main="Group.id.100,cat2")
plot(merge.shp.100,col=merge.shp$cat3,main="Group.id.100,cat3")
plot(merge.shp.200,col=merge.shp$cat1,main="Group.id.200,cat1")
plot(merge.shp.200,col=merge.shp$cat2,main="Group.id.200,cat2")
plot(merge.shp.200,col=merge.shp$cat3,main="Group.id.200,cat3")
I want to insert a common legend and colour scheme for all the 6 figures.
For example, the legend should go from minimum = min(c(cat1,cat2,cat3)) to max(c(cat1,cat2,cat3))
for all the six figures. Similarly, a value of 50 should have the same colour in all the 6 figures.
Thank you
You can use spplot
Example data:
library(raster)
s <- getData('GADM', country='FRA', level=2)[, c('GID_1', 'NAME_1', 'GID_2', 'NAME_2')]
set.seed(1)
m <- matrix(runif(96*6, 0, 100), nrow=96, ncol=6)
vars <- paste0("cat", 1:6)
colnames(m) <- vars
d <- data.frame(GID_2 = s$GID_2, m)
sd <- merge(s, d)
Use spplot:
spplot(sd, vars)
With base plot, you could do something like
brks <- seq(0,100,20)
par(mfrow=c(2,3), mai=c(0,0,0.5,0))
cols = rainbow(length(brks))
for (v in vars) {
cuts <- cut(data.frame(sd)[, v], brks)
plot(s, col=cols[cuts], main=v)
}
How do I plot a network of type bipartite in R? Similar to this:
I have similar data but with weights for both genes and diseases and SARS. This network is an example. I have different kind of attributes. I followed a link here. But due to my little knowledge in this topic, I could not get much out of it. Thanks in advance for any help.
From the ?bipartite_graph help:
Bipartite graphs have a type vertex attribute in igraph, this is boolean and FALSE for the vertices of the first kind and TRUE for vertices of the second kind.
So you could do something like this (igraph 1.0.1):
library(igraph)
set.seed(123)
# generate random bipartite graph.
g <- sample_bipartite(10, 5, p=.4)
# check the type attribute:
V(g)$type
# define color and shape mappings.
col <- c("steelblue", "orange")
shape <- c("circle", "square")
plot(g,
vertex.color = col[as.numeric(V(g)$type)+1],
vertex.shape = shape[as.numeric(V(g)$type)+1]
)
Check also ?bipartite.
Using the example provided by the OP in the comments. Since the graph is multipartite and given the provided data format, I would first create a bipartite graph, then add the additional edges. Note that although the resulting graph returns TRUE for is_bipartite() the type argument is specified as numeric instead of logical and may not work properly with other bipartite functions.
set.seed(123)
V1 <- sample(LETTERS[1:10], size = 10, replace = TRUE)
V2 <- sample(1:10, size = 10, replace = TRUE)
d <- data.frame(V1 = V1, V2 = V2, weights = runif(10))
d
> d
V1 V2 weights
1 C 10 0.8895393
2 H 5 0.6928034
3 E 7 0.6405068
4 I 6 0.9942698
5 J 2 0.6557058
6 A 9 0.7085305
7 F 3 0.5440660
8 I 1 0.5941420
9 F 4 0.2891597
10 E 10 0.1471136
g <- graph_from_data_frame(d, directed = FALSE)
V(g)$label <- V(g)$name # set labels.
# create a graph connecting central node FOO to each V2.
e <- expand.grid(V2 = unique(d$V2), V2 = "FOO")
> e
V2 V2
1 10 FOO
2 5 FOO
3 7 FOO
4 6 FOO
5 2 FOO
6 9 FOO
7 3 FOO
8 1 FOO
9 4 FOO
g2 <- graph.data.frame(e, directed = FALSE)
# join the two graphs.
g <- g + g2
# set type.
V(g)$type <- 1
V(g)[name %in% 1:10]$type <- 2
V(g)[name %in% "FOO"]$type <- 3
V(g)$type
> V(g)$type
[1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3
col <- c("steelblue", "orange", "green")
shape <- c("circle", "square", "circle")
library(rTRM) # Bioconductor package containing layout.concentric()
# the fist element in the list for concentric is the central node.
l <- layout.concentric(g, concentric = list("FOO", 1:10, LETTERS[1:10]))
plot(g,
layout = l,
vertex.color = col[V(g)$type],
vertex.shape = shape[V(g)$type],
edge.width = E(g)$weights * 5 # optional, plot edges width proportional to weights.
)
The function layout.concentric() is in (my) package rTRM, available from Bioconductor. It is really a simple implementation I wrote to do exactly what you want. I am not completely sure whether the latest igraph version has the same functionality though (it may be).
For the example you provided, I would recommend using the x and y attributes for visualizing a bipartite graph. E.g.:
V(g)$x <- c(1, 1, 1, 2, 2, 2, 2)
V(g)$y <- c(3, 2, 1, 3.5, 2.5, 1.5, 0.5)
V(g)$shape <- shape[as.numeric(V(g)$type) + 1]
V(g)$color <- c('red', 'blue', 'green', 'steelblue', 'steelblue', 'steelblue', 'steelblue')
E(g)$color <- 'gray'
E(g)$color[E(g)['A' %--% V(g)]] <- 'red'
E(g)$color[E(g)['B' %--% V(g)]] <- 'blue'
E(g)$color[E(g)['C' %--% V(g)]] <- 'green'
plot(g)
EDIT: added code to give the vertices and edges different colors for clarity.
Or you can use the multigraph package.
swomen <- read.dl(file = "http://moreno.ss.uci.edu/davis.dat")
bmgraph(swomen, layout = "force", seed = 1, cex = 3, tcex = .8, pch = c(19, 15), lwd = 2,
+ vcol = 2:3, ecol = 8, rot = 65)
that can produce the binomial projection of the two-mode data set