multiple Map with subplots in R - r

I have a series of rasters plots that I want on a single page. Every raster plot should be together with a subplot of specified region in the raster.
I found some related methods that fail to work with rasters plot
This map is a demo made by Arcgis , I want to implement it with R script.
First of all ,I want to try a single plot with sub plot graph.
Here is my sample code .
require(raster)
require(rgdal)
op <- par(no.readonly = TRUE)
oldwd<-getwd()
setwd(tempdir())
plotr<-raster(nrow=405,ncol=485,
xmn=-2638000,xmx=2212000,ymn=1872000,ymx=5922000,
crs='+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 +x_0=0 +y_0=0 +ellps=krass +units=m +no_defs')
plotr<-setValues(plotr, (coordinates(plotr)[,2]))
chnshp<-getData('GADM', country="China", level=1)
chnshp<-spTransform(chnshp,CRS=CRS(projection(plotr)))
plotr<-mask(plotr,chnshp)
breaks=seq(min(minValue(plotr)),max(maxValue(plotr)),length.out=10)
download.file('https://dl.dropboxusercontent.com/s/vzs6166v46de7v7/subplot_frame.zip?dl=1&token_hash=AAF8H3aS64fwU4T_dVBzhQ_OokjGNanvWFTYBZS3IjY4Vg',
method='auto',mode="wb",'test.zip')
unzip('test.zip',exdir=tempdir())
nnshp<-readShapeSpatial('Nanhaizhudao.shp')
nanhai<-function()
{
before_op <- par(no.readonly = TRUE)
plot(nnshp,add=T)
par(new=TRUE, oma=c(3.5,3.5,3.4,2.2)
,mar=c(2,3,2,1.5)
)
layout(matrix(c(0,0,0,0,0,0,
0,0,0,0,0,0,
0,0,0,0,0,0,
0,0,0,0,1,0,
0,0,0,0,0,0
),nrow=5,byrow=T))
plot(plotr, xlim =c(1e5, 1.2e+6),ylim =c(1.5e5, 2.475e+06),
breaks=breaks,box=F,
legend=F,lwd = 1,axes=FALSE, frame.plot=F,
col = topo.colors(length(breaks)))
par(before_op)
}
if(as.numeric(dev.cur())>1){graphics.off()}
tiff('test.tif',
width=12,height=8,units='cm',
res=600,compression="lzw",pointsize=7)
par(mar = c(3.5, 3.5, 3, 2.5))
plot(plotr,col = topo.colors(length(breaks)),breaks=breaks,horizontal=F,
legend.shrink = 0.8,legend.width = 0.6,legend.mar =7,cex=0.1,
addfun=nanhai,
xlim=c(xmin(plotr), xmax(plotr)), ylim=c(ymin(plotr), ymax(plotr)))
par(op)
dev.off()
if(as.numeric(dev.cur())>1){graphics.off()}
unlink(tempdir())
setwd(oldwd)
Currently ,I have two questions:
How can I modify the display scale of plot area to make sure that nnshp is entirely visible ?(avoid to adjust par parameters manually )
How can I adjust the location of sub plot graph precisely to nnshp ? I spent so many time to modify parameters and failed to get it.
When I want to get multiple plot (stack raster plot) just like the map demo made by ArcGis, I get the wrong result. How to get the multiple plot of it?
plot(stack(plotr,plotr),col = topo.colors(length(breaks)),breaks=breaks,horizontal=F,
legend.shrink = 0.8,legend.width = 0.6,legend.mar =7,cex=0.1,
addfun=nanhai,
xlim=c(xmin(plotr), xmax(plotr)), ylim=c(ymin(plotr), ymax(plotr)))

Related

Adding texture to certain states when plotting maps with R

I'm getting started with maps in R, and I'm facing a problem which I'm not being able to solve.
Suppose the following script:
tmp_dir = tempdir()
url_data = "http://www.sharegeo.ac.uk/download/10672/50/English%20Government%20Office%20Network%20Regions%20(GOR).zip"
zip_file = sprintf("%s/shpfile.zip", tmp_dir)
download.file(url_data, zip_file)
unzip(zip_file, exdir = tmp_dir)
library(maptools)
gor=readShapeSpatial(sprintf('%s/Regions.shp', tmp_dir))
col=gray(gor$NUMBER/sum(gor$NUMBER))
col[5] = NA
plot(gor, col=col)
I would like a way to add a texture to the state with missing data on the "col" vector, instead of just leaving it white.
So in this case for example, I'm looking for something like that:
How can I add textures to specific parts of my plot, specially when working with maps?
I've read about functions like add.texture, but I couldn't use them in such a flexible way.
plot.SpatialPolygons() is capable of using line texture. If the argument density isn't NA, plot.SpatialPolygons() uses line texture.
: # (skip)
library(maptools)
col=gray(gor$NUMBER/sum(gor$NUMBER))
col[5] = NA
plot(gor, col=col) # It's easy to use the argument `add=T`
plot(gor[5,], add=T, density=10, angle=90, col="blue") # Left map
## Of cource, you can draw the map at once without `add=T`
col2 <- col
col2[4:5] <- c("red", "blue")
plot(gor, col=col2, density=c(rep(NA,3), 30, 10, rep(NA,4)),
angle=c(rep(NA,3), 0, 90, rep(NA,4))) # Right map

Plotting multiple charts based on stored functions

In R, I'm trying to plot multiple charts based on stored functions (I'm pretty new to programming with R, so that might not totally make sense). Basically, I've created some charts and stored them in a function that can be easily run with new data. I want to retain that functionality while adding the ability to render multiple charts in one render. I'd like it to end up something like this http://www.statmethods.net/advgraphs/images/layout1.jpg
I've run the code below, but it just produces multiple instances of each graph (or replaces each graph with the new rendering).
So my question is this: what am I doing wrong? Does anyone out there know how I can generate four graphs to be placed in one view (like the link above) using the following code and functions? Any help is greatly appreciated.
Note: the second bit of code has two siblings. I also have a pie chart I haven't included, but it's mentioned in the following code.
Here's the code I've been working with:
attach(ES)
par=(mfrow=c(2,2))
plot=(mapFunctionRead())
plot=(mapFunctionSkim())
plot=(mapFunctionDelete())
plot=(pieChart())
And Here's a sample function:
mapFunctionRead<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Read ####################
# Draw circles
symbols(mtReadLong, mtReadLat, circles=rep(1, length(mtReadLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusRead<-sqrt(mtReadSec/pi)
# draw circles with fill and border
symbols(mtReadLong, mtReadLat, bg="#4173a5", fg="#5589c7", lwd=0.5, circles=radiusRead, inches=0.05, add=TRUE)
}
################# Displays data on world map for SKIM ######################
mapFunctionSkim<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Skim ####################
# Draw circles
symbols(mtSkimLong, mtSkimLat, circles=rep(1, length(mtSkimLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusSkim<-sqrt(mtSkimSec/pi)
# draw circles with fill and border
symbols(mtSkimLong, mtSkimLat, bg="#ead57d", fg="#ead57d", lwd=0.5, circles=radiusSkim, inches=0.05, add=TRUE)
}
################# Displays data on world map for DELETE ######################
mapFunctionDelete<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Delete ####################
# Draw circles
symbols(mtDeleteLong, mtDeleteLat, circles=rep(1, length(mtDeleteLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusDelete<-sqrt(mtDeleteSec/pi)
# draw circles with fill and border
symbols(mtDeleteLong, mtDeleteLat, bg="#77223c", fg="#9c1b3e", lwd=0.5, circles=radiusDelete, inches=0.05, add=TRUE)
}
Well I agree with #MrFlick. You might want to think of providing arguments to your map functions. For example.
library(maps)
mfunc <- function(x,y){
map(database = x, bg = y)
}
mfunc(x = "world", y = "#d4d5d1")
Then once all your map functions are defined you can use par(mfrow = c(a,b)). But just based on the info you have provided I'm not really sure what you want. Best of luck though.

Overlap image plot on a Google Map background in R

I'm trying to add this plot of a function defined on Veneto (italian region)
obtained by an image and contour:
image(X,Y,evalmati,col=heat.colors(100), xlab="", ylab="", asp=1,zlim=zlimits,main=title)
contour(X,Y,evalmati,add=T)
(here you can find objects: https://dl.dropboxusercontent.com/u/47720440/bounty.RData)
on a Google Map background.
I tried two ways:
PACKAGE RGoogleMaps
I downloaded the map mbackground
MapVeneto<-GetMap.bbox(lonR=c(10.53,13.18),latR=c(44.7,46.76),size = c(640,640),MINIMUMSIZE=TRUE)
PlotOnStaticMap(MapVeneto)
but i don't know the commands useful to add the plot defined by image and contour to the map
PACKAGE loa
I tried this way:
lat.loa<-NULL
lon.loa<-NULL
z.loa<-NULL
nx=dim(evalmati)[1]
ny=dim(evalmati)[2]
for (i in 1:nx)
{
for (j in 1:ny)
{
if(!is.na(evalmati[i,j]))
{
lon.loa<-c(lon.loa,X[i])
lat.loa<-c(lat.loa,Y[j])
z.loa<-c(z.loa,evalmati[i,j])
}
}
}
GoogleMap(z.loa ~ lat.loa*lon.loa,col.regions=c("red","yellow"),labels=TRUE,contour=TRUE,alpha.regions=list(alpha=.5, alpha=.5),panel=panel.contourplot)
but the plot wasn't like the first one:
in the legend of this plot I have 7 colors, and the plot use only these values. image plot is more accurate.
How can I add image plot to GoogleMaps background?
If the use of a GoogleMap map is not mandatory (e.g. if you only need to visualize the coastline + some depth/altitude information on the map), you could use the package marmap to do what you want. Please note that you will need to install the latest development version of marmap available on github to use readGEBCO.bathy() since the format of the files generated when downloading GEBCO files has been altered recently. The data from the NOAA servers is fine but not very accurate in your region of interest (only one minute resolution vs half a minute for GEBCO). Here is the data from GEBCO I used to produce the map : GEBCO file
library(marmap)
# Get hypsometric and bathymetric data from either NOAA or GEBCO servers
# bath <- getNOAA.bathy(lon1=10, lon2=14, lat1=44, lat2=47, res=1, keep=TRUE)
bath <- readGEBCO.bathy("GEBCO_2014_2D_10.0_44.0_14.0_47.0.nc")
# Create color palettes for sea and land
blues <- c("lightsteelblue4", "lightsteelblue3", "lightsteelblue2", "lightsteelblue1")
greys <- c(grey(0.6), grey(0.93), grey(0.99))
# Plot the hypsometric/bathymetric map
plot(bath, land=T, im=T, lwd=.03, bpal = list(c(0, max(bath), greys), c(min(bath), 0, blues)))
plot(bath, n=1, add=T, lwd=.5) # Add coastline
# Transform your data into a bathy object
rownames(evalmati) <- X
colnames(evalmati) <- Y
class(evalmati) <- "bathy"
# Overlay evalmati on the map
plot(evalmati, land=T, im=T, lwd=.1, bpal=col2alpha(heat.colors(100),.7), add=T, drawlabels=TRUE) # use deep= shallow= step= to adjust contour lines
plot(outline.buffer(evalmati),add=TRUE, n=1) # Outline of the data
# Add cities locations and names
library(maps)
map.cities(country="Italy", label=T, minpop=50000)
Since your evalmati data is now a bathy object, you can adjust its appearance on the map like you would for the map background (adjust the number and width of contour lines, adjust the color gradient, etc). plot.bath() uses both image() and contour() so you should be able to get the same results as when you plot with image(). Please take a look at the help for plot.bathy() and the package vignettes for more examples.
I am not realy inside the subject, but Lovelace, R. "Introduction to visualising spatial data in R" might help you
https://github.com/Robinlovelace/Creating-maps-in-R/raw/master/intro-spatial-rl.pdf From section "Adding base maps to ggplot2 with ggmap" with small changes and data from https://github.com/Robinlovelace/Creating-maps-in-R/archive/master.zip
library(dplyr)
library(ggmap)
library(rgdal)
lnd_sport_wgs84 <- readOGR(dsn = "./Creating-maps-in-R-master/data",
layer = "london_sport") %>%
spTransform(CRS("+init=epsg:4326"))
lnd_wgs84_f <- lnd_sport_wgs84 %>%
fortify(region = "ons_label") %>%
left_join(lnd_sport_wgs84#data,
by = c("id" = "ons_label"))
ggmap(get_map(location = bbox(lnd_sport_wgs84) )) +
geom_polygon(data = lnd_wgs84_f,
aes(x = long, y = lat, group = group, fill = Partic_Per),
alpha = 0.5)

Shapefile and vector file don't precisely overlap when plotted

I want to plot a shapefile over a raster file in R but I can't make them overlap perfectly: the raster appears to be rotated of few degrees counter-clockwise. Is it a problem with the projection?
Please consider the following MWE
library(raster)
library(rgdal)
# Download from http://biogeo.ucdavis.edu/data/gadm2/shp/ITA_adm.zip
shape_file = "ITA_adm1.shp"
# Download from http://sedac.ciesin.columbia.edu/data/set/gpw-v3-population-density/data-download
# Setting Geography: Country, Italy; Data Attributes: Grid
pop_density_file ="w001001.adf"
italy_map <- readOGR(dsn = shape_file, layer = "ITA_adm1")
italy_map_dens <- raster(pop_density_file)
colPal <- colorRampPalette(c("white", "red"))( 500 )
par(mar=c(0,0,0,0))
plot(italy_map_dens, xlim = c(6.70, 18.32), ylim = c(35.2, 47.6), axes=FALSE, box=FALSE, legend=FALSE, col=colPal)
plot(italy_map, xlim = c(6.70, 18.32), ylim = c(35.2, 47.6), border="grey", add=TRUE)
Apparently there was a bug in the rgdal package. My problem was solved after I updated it to version 0.8-12.
It does appear to be a problem with the projection. You need to find out the exact projection of both datasets, and convert one of the datasets to the projection of the other dataset.

Intersect the contour and polygon in R

I have been trying for a few days to create the contour and then plot the shapefile and contour on the same file. Now, that I am able to create the contour and shapefile on the same plot. I want to clip the contour with the shapefile an only show the shapefile.
The data temp.csv can be found on this link https://www.dropbox.com/s/mg2bo4rcr6n3dks/temp.csv
Shapefile can be found on the following location: https://www.dropbox.com/sh/ztvmibsslr9ocmc/YOtiwB8p9p
The script file image.scale.R can be found on the following location "https://www.dropbox.com/s/2f5s7cc02fpozk7/image.scale.R "
The code that I have used so far is as follows:
## Required packages
library(maptools)
library(rgdal)
library(sp)
library(maptools)
library(sm)
require(akima)
require(spplot)
library(raster)
library(rgeos)
## Set Working Directory
setwd("C:\\Users\\jdbaba\\Documents\\R working folder\\shape")
## Read Data from a file
age2100 <- read.table("temp.csv",header=TRUE,sep=",")
x <- age2100$x
y <- age2100$y
z <- age2100$z
####################################
##Load the shape file
#####################################
shapefile <- readShapePoly("Export_Output_4.shp")
fld <- interp(x,y,z)
par(mar=c(5,5,1,1)) filled.contour(fld)
###Import the image.scale
source source("image.scale.R")
# http://menugget.blogspot.de/2011/08/adding-scale-to-image-plot.html
x11(width=8, height=7)
layout(matrix(c(1,2), nrow=1, ncol=2), widths=c(6,1), height=6, respect=TRUE)
layout.show(2)
par(mar=c(4,4,1,2))
image(fld,axes=T)
contour(fld, add=TRUE)
#points(age2100$x,age2100$y, pch=".", cex=2,legend=F)
plot(shapefile,add=T,lwd=2)
box()
par(mar=c(4,0,1,4))
image.scale(fld, xlab="Eastings", ylab="Northings", xaxt="n", yaxt="n", horiz=FALSE)
axis(4)
mtext("Salinity", side=4, line=2.5)
The output of the above code is as follows:
Now, I want to get rid of the colored gradients and the contours from the polygon shapefile and only leave the intersection part.
Any help is highly appreciated.
Research: I found this link https://gis.stackexchange.com/questions/25112/clip-depth-contour-with-spatial-polygon on Stack exchange Gis and I tried to follow this method I always get error while creating the contour.
I found another similar thread on https://stat.ethz.ch/pipermail/r-sig-geo/2009-May/005793.html . But I couldn't make it work on my dataset.
I would like to acknowledge Marc in the box for helping me in getting to this point.
Thanks.
Indeed, #baptiste gave you a strong hint for the solution, the recent paper by Paul Murrell. Paul was generous to provide us with the code for his entire paper manuscript, which you can get from his personal website. On the side topic, Paul shows beautiful example of reproducible research with this paper. Generally, I took the following approach:
extract latitude and longitude coordinates from the shapefile (a function to do this is here, by Paul Hiemstra),
plot everything with your code,
and use polypath to remove everything outside the boundaries defined by shapefile, using extracted coordinates as a baseline.
#function to extract coordinates from shapefile (by Paul Hiemstra)
allcoordinates_lapply = function(x) {
polys = x#polygons
return(do.call("rbind", lapply(polys, function(pp) {
do.call("rbind", lapply(pp#Polygons, coordinates))
})))
}
q = allcoordinates_lapply(shapefile)
#extract subset of coordinates, otherwise strange line connections occur...
lat = q[110:600,1]
long = q[110:600,2]
#define ranges for polypath
xrange <- range(lat, na.rm=TRUE)
yrange <- range(long, na.rm=TRUE)
xbox <- xrange + c(-20000, 20000)
ybox <- yrange + c(-20000, 20000)
#plot your stuff
plot(shapefile, lwd=2)
image(fld, axes=F, add=T)
contour(fld, add=T)
#and here is the magic
polypath(c(lat, NA, c(xbox, rev(xbox))),
c(long, NA, rep(ybox, each=2)),
col="white", rule="evenodd")

Resources