How to display longitude and latitude lines on a map using R? - r

I am trying to view this binary file(unsigned character, pixel =720 and lines=360) as a map ,I tried the piece of code given bellow. First, I downloaded and saved it as landcover.bin.
conne <- file("C:\\landcover.bin", "rb")
sd<- readBin(conne, integer(), size=1, n=360*720, signed=F)
y<-matrix((data=sd), ncol=360, nrow=720)
image(y)
I got a map that looks weird, and then I swap ncol and nrow as
y<-matrix((data=sd), ncol=720, nrow=360)
image(y)
I got a reasonable map but upside down
My question can anyone tell me how can I display my file as (which is not supposed to be the same)and how to display the longitudes and latitudes as are shown on this map:

Use the raster package for geographically based gridded data.
You can probably make it read directly from a binary file with some rgdal trickery, but lets do it via a matrix.
> require(raster)
> conne <- file("landcover.bin","rb")
> sd<- readBin(conne, integer(), size=1, n=360*720, signed=F)
> y<-t(matrix((data=sd), ncol=360, nrow=720))
> r = raster(y)
Now you have a raster object. But if you plot it you will notice three things - lots of green, the scale going up to 250, and the axes being from 0 to 1.
The map seems to use 255 for the sea. If we recode that as NA we'll get a better map:
> r[r==255]=NA
> plot(r)
Looks a lot better. Now let's fix the range:
> extent(r) = extent(c(xmn=-180,xmx=180,ymn=-90,ymx=90))
> plot(r)
Finally we should tell R that this is in the lat-long coordinate system - most likely epsg:4326:
> projection(r)=CRS("+init=epsg:4326")
> plot(r)
Note this is still using a continuous colour scheme, even though you have discrete data (which I guess is a classification scheme). You can map numbers to colours with raster, but that's a whole other problem...

You have to mirror the columns on the matrix to get the right result. Use abline to draw your lats and longs.
conne <- file("Landcover.bin", "rb")
sd<- readBin(conne, integer(), size=1, n=360*720, signed=F)
y<-matrix(sd,ncol=360,nrow=720)
image(y[,360:1])
lats=seq(-90,90,by=30)
longs=seq(-180,180,by=30)
trans.lats=(lats+90) / 180
trans.longs=(longs+180) / 360
abline(h=trans.lats,v=trans.longs)
But, as #January mentioned, there are many packages that handle maps. You should use one of them.

To get a ggplot2 based solution, you can use geom_raster. See my answer to this earlier question of yours for an example. ggplot2 displays lat lon lines, to tweak this see my answer to this other question of yours, specifically the breaks argument for scale_{x,y}_*.
ggplot2 requires a data.frame, not a matrix or array, use melt to do this transformation (example here). To get the correct lat lon values, please take care that the array has the correct dimnames, please see ?dimnames for more information.

Maybe the maps in the R map package would suit you better?
library( maps )
map( "world" )
points( -0.11832, 51.50939, pch= 19, col= "red" )
text( -0.11832, 51.50939, "London", pos=3, col= "red" )
abline( h= 0 )
text( -150, 0, "Equator", pos= 3 )
abline( v= 0 )
Result:

Related

R rasterVis levelplot: a white line erroneously appears

I am plotting maps of atmospheric pollutant fields, or meteorological field, difference between such fields, often overlayed with orography.
My fields are gridded.
A white line misteriously appears, sometimes two.
This seems to happen a bit randomly. I mean: same code and fields, same line; but when I change fields, or color scales, it changes position, or it disappears, or another one appears. Sometimes horizontal, sometimes vertical.
Here is my code
#!/usr/bin/env Rscript
library(rasterVis)
library(RColorBrewer)
NX <- 468
NY <- 421
hgt <- matrix(0.,NX,NY)
# read from file:
ucon <- file("hgt.dat", open="rb")
for (n in seq(1,NX)) {
hgt[n,] <- readBin(ucon, "numeric", n=NY, size=4)
}
close(ucon)
hgtbks <- c(-100,10,500,1000,1500,2000,2500,3000,3500)
hgtcols <- colorRampPalette(c("gray30","white"))(length(hgtbks)-1)
tit <- "Orography"
bkstart=50.0; bkmax=1500.; bkby=100.
bks <- seq(bkstart, bkmax, bkby)
nbks <- length(bks)
cols <- rev(colorRampPalette(brewer.pal(11,"Spectral"))(nbks-2))
cols <- c("white",cols)
legendbreaks <- seq(1,nbks)
legendlabels <- formatC(bks,digits=3)
legendlabpos <- legendbreaks
rpl <-
levelplot(hgt, margin=FALSE , col.regions= hgtcols, at= hgtbks
, main= list(label=tit, cex=1.8)
, colorkey=list(draw= TRUE, col=cols, at=legendbreaks
, labels=list(labels=legendlabels, at=legendlabpos, cex=1.2))
, xlab=NULL, ylab=NULL, scales= list(draw= FALSE))
png("whiteline.png", width=800, height=840)
plot(rpl)
graphics.off()
I would really like to upload a file with my data, but for the moment
I could not find a way to do it (I don't think I can do it, not even an ASCII file). The data matrix (468x421) is too big to be explicitly included in the code, but it really is the orography file
shown in the picture (elevation in meters above mean sea level).
And here is the resulting "white line" map:
Really, I think this might be a levelplot bug. It seems to happen both when hgt is a matrix and when it is a proper raster object: this doesn't seem to make a difference.
Any idea?
I think I found a workaround.
By setting zero padding on the 4 sides, I managed to make the whiteline disappear from a series of maps.
First I defined:
zpadding <- list(layout.heights= list(top.padding=0, bottom.padding=0),
layout.widths= list(left.padding=0, right.padding=0))
then I added, among the parameters of the levelplot call:
par.settings=zpadding
As I said, I don't think this is a proper solution, but a workaround.
The problem seems related to any rescaling of the plot area.
In fact, when a rescaling is forced by, for example, having 4 or 5 digits (instead of 2 or 3) in the colorbar labels, a white line may reappear.
I hope this may point in the right direction other people, either users or developers of levelplot and related software.

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

Plot ggplot polygons with holes with geom_polygon

There are questions out there about the fact that ggplot2 can't plot polygon shapes that have holes.
That is because, if the order of points is not OK, the end graph looks bad, usually with clipping/trimming lines inside the donut shape.
I have read a lot about how order matters, but I am not able to step forward.
I have a SpatialPolygonsDataFrame with 26 features (comes from raster::rasterToPolygons(dissolve=T)) and I want to plot it with ggplot.
Here's what happens -
r3.pol <- rasterToPolygons(r3, dissolve=T)
r3.df <- fortify(r3.pol)
names(r3.df) <- c('x','y','order','hole','piece','ID','group')
p <- ggplot(r3.df)
p <- p + geom_polygon(mapping=aes(x=x,y=y,group=ID), fill='red')
p <- p + coord_equal()
I see this output:
While it should be like so, with plot(r3.pol):
How can I make this work?
I tried for hours but I am not able to reorder r3.df.
Also, can the information in r3.df$hole be helpful? It is returned by the function fortify for points that are holes (I think).
Side question: how can I give you my r3.pol SpatialPolygonsDataFrame, so that you can try yourself? I remember seeing long, reproducible "dumps" of objects here, but I don't know how to do it.
I saved the polygons data frame here. Was not able to save it using dput, sorry. You can fetch it using load.
I suggest to install the package "ggpolypath" and use geom_polypath instead of geom_polygon. Works for me.
My temporary solution is: ##$% polygons, and use the raster package.
Namely:
r <- raster(x=extent(r3.pol), crs=crs(r3.pol)) # empty raster from r3.pol
res(r) <- 250 # set a decent resolution (depends on your extent)
r <- setValues(r, 1) # fill r with ones
r <- mask(r, r3.pol) # clip r with the shape polygons
And now plot it as you would do with any raster with ggplot. The rasterVis package might come helpful here, but I'm not using it, so:
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y), fill='red')
p <- p + coord_equal()
And here it goes.
Alternatively, you can create the raster with rasterize, so the raster will hold the polygons values (in my case, just an integer):
r <- raster(x=extent(r3.pol), crs=crs(r3.pol))
res(r) <- 250
r <- rasterize(r3.pol, r)
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y, fill=factor(layer)))
p <- p + coord_equal()
If someone comes up with a decent solution for geom_polygon, probably involving re-ordering of the polygons data frame, I'll be glad to consider it.

Using a raster attribute from a multi-attribute raster for colour levels in a plot in R

I have a raster object with a large number of attributes, and I would like to plot the spatial data in R and colour code it by a certain attribute. I have not been able to work out how to use the information of a particular attribute to achieve this. So far I have successfully extracted the attribute of choice using factorValues(), but I cannot determine how to now incorporate this information into the plot() function. I tried using the ratify() and level() functions mentioned in the raster package documentation, but I don’t understand how the simplified online examples can be adapted for a raster with multiple attributes.
Any advice on how to achieve this would be greatly appreciated.
# read in shapefile
shp = readOGR(".", "grid")
#convert to raster
r = raster(extent(shp))
res(r) = c(1,0.5)
ra = rasterize(shp, r)
#crop raster to desired extent
rcrop = crop(ra, extent(-12, 2, 29, 51))
# extract attribute value of interest
f = factorValues(rcrop, 1:420, layer=1, att=17, append.names=FALSE)
# here there are 420 cells in the raster and I am interested in plotting values of attribute 17 of the raster (this is currently a numeric attribute, not a factor)
#extra code to set attribute as the level to use for plotting colours???
rcrop = ratify(rcrop)
rat = levels(rcrop)[[1]] #this just extras row IDs..not what I want
#…
### plot: I want to plot the grid using 7 colours (I would ideally like to specify the breaks myself)
require(RColorBrewer)
cols = brewer.pal(7,"YlGnBu")
#set breaks
brks = seq(min(minValue(rcrop)),max(maxValue(rcrop),7))
#plot
plot(rcrop, breaks=brks, col=cols, axis.arg=arg)
The following is pretty hacky (and may perform poorly for large rasters), but I'm not sure if there's a way to link col.regions to a specified attribute.
rasterVis::levelplot does a nice job of labelling colour ramps corresponding to factor rasters, and while it provides an att argument allowing you to specify which attribute you're interested in, this seems to only modify the labelling of the ramp. Raster cell values control how the colour ramp is mapped to the raster, so it seems to me that we need to modify the cell values themselves. Maybe #OscarPerpiñán will chime in here to prove me wrong :)
We can create a simple function to substitute the original cell values with whichever attribute we want:
switch_att <- function(r, att) {
r[] <- levels(r)[[1]][values(r), att]
r
}
Let's download and import a small example polygon dataset from Natural Earth:
library(rasterVis)
library(rgdal)
require(RColorBrewer)
download.file(file.path('http://www.naturalearthdata.com',
'http//www.naturalearthdata.com/download/110m/cultural',
'ne_110m_admin_0_countries.zip'),
f <- tempfile())
unzip(f, exdir=tempdir())
shp <- readOGR(tempdir(), 'ne_110m_admin_0_countries')
rasterize the vector data:
r <- rasterize(shp, raster(raster(extent(shp), res=c(1, 1))))
And create some plots with levelplot:
levelplot(switch_att(r, 'continent'), col.regions=brewer.pal(8, 'Set2')) +
layer(sp.polygons(shp, lwd=0.5))
levelplot(switch_att(r, 'economy'), par.settings=BuRdTheme) +
layer(sp.polygons(shp, lwd=0.5))
EDIT
With Oscar's update to rasterVis, the switch_att hack above is no longer necessary.
devtools::install_github('oscarperpinan/rastervis')
levelplot(r, att='continent', col.regions=brewer.pal(8, 'Set2')) +
layer(sp.polygons(shp, lwd=0.5))
will produce the same figure as the first one above.

How to limit boundaries when plotting a shapefile in R

I hope this isn't a basic question, I've had a hard time finding online resources for using R with shapefiles. I have a shapefile of the 5 digit zip codes in Texas, specifically the one at the bottom of this page.
I'm loading the zip code data and plotting it as such:
> library(maptools)
> zipData <- readShapePoly('~/Documents/Shapefiles/zipCodesTX/tl_2009_48_zcta5.shp')
> plot(zipData)
However, this yields the full map of Texas. I'd like to pare it down to just Dallas.
I thought about using zipData#bbox to find the max values and using xlim and ylim to shrink it down from there, however, this causes the y and x axis to have different amounts.
> zipData#bbox
min max
x -106.64565 -93.50844
y 25.83723 36.99566
> plot(zipData, xlim <- c(-100, -95))
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' and 'y' lengths differ
Does anyone have an idea of an easy way to do this?
Further basic shapeplot question: How does plot() actually plot my shapefile? names(zipData) reveals the names of the data frame columns as:
> names(zipData)
[1] "ZCTA5CE" "CLASSFP" "MTFCC" "FUNCSTAT"
[5] "ALAND" "AWATER" "INTPTLAT" "INTPTLON"
Obviously, INTPTLAT and INTPTLON are lat and long coordinates, but plotting these as:
> plot(zipData$INTPTLAT, zipData$INTPTLON)
yields a big black box. How exactly are maps generated using plot() with shapefiles?
I apologize if these questions are very base, I just could not find a good resource or explanation of this.
You can change the limits of a plot using the xlim and ylim arguments of the plot function:
library("rgdal")
shp <- readOGR("tl_2009_48_zcta5.shp", "tl_2009_48_zcta5")
plot(shp, xlim=c(-97.13, -96.47), ylim=c(32.47, 33.08), col="orange")
or you can subset shp (an object of class SpatialPolygonsDataFrame):
zip_dallas <- c(75019, 75039, 75043, 75048, 75050, 75051, 75060, 75062, 75081,
75089, 75098, 75104, 75125, 75134, 75141, 75146, 75149, 75154,
75159, 75172, 75181, 75182, 75217, 75232, 75241, 75247, 75253,
75001, 75006, 75248, 75254, 75180, 75007, 75234, 75287, 75115,
75137, 75249, 75211, 75063, 75067, 75041, 75052, 75061, 75080,
75088, 75116, 75150, 75201, 75202, 75203, 75204, 75205, 75206,
75207, 75208, 75209, 75210, 75212, 75214, 75215, 75216, 75218,
75219, 75220, 75223, 75224, 75225, 75226, 75227, 75228, 75229,
75230, 75231, 75233, 75235, 75236, 75237, 75238, 75240, 75243,
75244, 75246, 75251, 75252, 75270, 75040, 75042, 75044, 75038,
75082, 76051)
ind <- x[["ZCTA5CE"]] %in% zip_dallas
plot(x[ind, ], col="orange")
Applied Spatial Data Analysis with R is a good reference for basic R usage and advanced spatial statistics.
Too many questions in there really.
First, read the R Spatial Task View for info on spatial data in R.
Then maybe read an introduction to spatial data in R by me: http://www.maths.lancs.ac.uk/~rowlings/Teaching/UseR2012/introductionTalk.html
Then notice that you used <- when you should have used =:
plot(zipData, xlim <- c(-100, -95))

Resources