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))
Related
I am using the statspat package because I am working on spatial patterns.
I would like to do in ggplot and with colors instead of numbers (because it is not too readable),
the following graph, produced with the plot.quadratest function: Polygone
The numbers that interest me for the intensity of the colors are those at the bottom of each box.
The test object contains the following data:
Test object
I have looked at the help of the function, as well as the code of the function but I still cannot manage it.
Ideally I would like my final figure to look like this (maybe not with the same colors haha):
Final object
Thanks in advance for your help.
Please provide a reproducible example in the future.
The package reprex may be very helpful.
To use ggplot2 for this my best bet would be to convert
spatstat objects to sf and do the plotting that way,
but it may take some time. If you are willing to use base
graphics and spatstat you could do something like:
library(spatstat)
# Data (using a built-in dataset):
X <- unmark(chorley)
plot(X, main = "")
# Test:
test <- quadrat.test(X, nx = 4)
# Default plot:
plot(test, main = "")
# Extract the the `quadratcount` object (regions with observed counts):
counts <- attr(test, "quadratcount")
# Convert to `tess` (raw regions with no numbers)
regions <- as.tess(counts)
# Add residuals as marks to the tessellation:
marks(regions) <- test$residuals
# Plot regions with marks as colors:
plot(regions, do.col = TRUE, main = "")
I have just started to learn R and I have a problem with plotting some values read from a CSV file.
I have managed to load the csv file:
timeseries <- read.csv(file="R/scripts/timeseries.csv",head=FALSE,sep=",")
When checking the content of timeseries, I get the correct results (so far, so good):
1 2016-12-29T19:00:00Z 6
...
17497 2016-12-30T00:00:00Z 3
Now, I am trying to plot the values - the date should be on the x-axis and the values on the y-axis.
I found some SO questions about this topic: How to plot a multicolumn CSV file?. But I am unable to make it work following the instructions.
I tried:
matplot(timeseries[, 1], timeseries[, -1], type="1")
Also, I tried various barplot and matplot modifications but I usuassly get some exception like this one: Error in plot.window(...) : need finite 'xlim' values
Could someone suggest how to tackle this problem? Sorry for elementary question...
You need to make sure your dates have class Date.
dates <- c("2016-12-29T19:00:00Z", "2016-12-30T00:00:00Z")
values <- c(6,3)
df <- data.frame(dates, values)
df$dates <- as.Date(df$dates)
Then you could use ggplot2
library(ggplot2)
qplot(df$dates, df$values) + geom_line()
or even the default
plot(df$dates, df$values, type = "l")
or with lattice as in the question you referred to
library(lattice)
xyplot(df$values ~ df$dates, type = "l")
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.
Update: adding an example. The shapefile destination and read directories just need to be pointed towards a particular user. Thanks for any comments.
a<-rep("Baker",10)
b<-rep("Columbia",10)
m<-factor(data<-c(1,1,1,1,1,2,2,2,2,2))
n<-m
e<-sample(c(runif(10,min=0,max=1)))
f<-sample(c(runif(10,min=0,max=3)))
g<-c(a,b)
h<-c(m,n)
i<-c(e,f)
t5<-data.frame(g,h,i)
colnames(t5)<-c("Regions_RR","Name","Value")
url2<-"http://navigator.state.or.us/sdl/data/shapefile/k24/orcnty24.zip"
work.dir<-"c:/Users/.../Downloads"
file1<-basename(url2)
download.file(url2,file1)
unzip(file1,exdir=work.dir)
require(rgdal)
s<-readOGR("C:/Users/.../Downloads",layer="orcnty24")
summary(s)
s#data$altName
I want to create multi-panel plots, which consist of a column of panels in which are plotted shapefiles and a second column of panels in which are plotted data, corresponding to a single region polygon in the shapefile. Each row represents a different region, so I want to color a single ploygon in each plot.
I can't get the syntax right for the plot statement for the shapefile. My latest attempt is below, using d_ply() in the col= statement. That generates an
"error in evaluating the argument 'x' in selecting a method for function 'plot'
If what I'm asking doesn't come across I can provide some example data, but maybe there is a simple solution. Am I going about this the wrong way? Do I need to convert the shapefile attribute table to some other object? Thanks for any comments.
s= polygon shapefile
s#data = shapefile attribute table
t5= dataframe
plot.new() #open plot
par(mfrow=c(2,3))
par(cex=0.6)
par(mar=c(3,3,0,0),oma=c(1,1,1,1))
par(tcl=-0.25)
d_ply(t5,"Regions_RR",function(y) { #cycle through df by region
for (i in 1:4) { #cycle through panels
if (i %in% c(1,3)) #plot shapefiles in panels 1 & 3
plot(s, col=ifelse(d_ply(as.data.frame(s#data),"altName", function (z)
{
z=y}),1,0))
if (i %in% c(2,4)) #plot data in panels 2 & 4
d_ply(t5,"Name",function(x) {
plot(data=x,(Value~y), xlab="", ylab=unique(x$Name), las =2, par(mar=c(12,5,4,2)+.1))
})
}
})
What I've tried:
On its own this works fine, the plot is one case of what I want:
plot(s, col=ifelse(s#data$Regions_all=="Coastal",1,0))
This statements gets an error:
plot(s, col=ifelse(s#data$Regions_all==y,1,0))
As does this one (because not cycling through s#data, I think):
Error in s#data$Regions_all > y :
comparison of these types is not implemented
In addition: Warning message:
In storage.mode(test) <- "logical" :
Incompatible methods ("Ops.factor", "Ops.data.frame") for ">"
As does this one:
plot(s, col=ifelse(s#data$Regions_all=y,1,0))
Error: unexpected '=' in:
" if (i %in% c(1,3))
plot(s, col=ifelse(s#data$Regions_all="
As does this one:
plot(s, col=ifelse(s#data$Regions_all==t5$Regions_RR[[y]],1,0)
Error in `[[.default`(t5$Regions_RR, y) :
attempt to select more than one element
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: