Clip the contour with polygon using ggplot and R - r

I want to create a contour and then clip the contour by the polygon and only show the contour within the polygon.
Shapefile data can be found here
Csv file can be found here
The code I used is as follows:
library("ggplot2")
library("rgdal")
library("gpclib")
library("maptools")
require(sp)
age2100 <- read.csv("temp.csv",header=TRUE, sep=",")
shape.dir <- "C:/Users/jdbaba/Documents/R working folder/shape" # use your directory name here
lon.shape <- readOGR(shape.dir, layer = "Export_Output_4")
str(lon.shape)
lon.df <- fortify(lon.shape, region = "Id")
p <- ggplot(lon.df, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = "black", fill = "grey80", size = 1) +
theme()
p <- p + geom_point(data=age2100,aes(x=age2100$x,y=age2100$y,group="z"),size=0.1)
p <- p + geom_density2d(colour="red")
p
Here, I have created the map, points and the contour. I don't know whether the code I am using created the contour for variable z or not. If it is not correct can anyone suggest me ?
The sample output that I got is as follows:
Now, I want to clip the contour within the polygon and hide the part of contour that is outside the polygon.
I want to know how to add the labels to the contour and control the contour interval.
Please let me know if my question is not clear.
Thanks
Jdbaba

I can't reproduce your map exactly. The code you provided gives me a map with two sets of contours - one that looks like yours and one that overlaps it in the southern part of the region. I suspect this is an artefact of your group setting. Also, I can see there is an island in the southern part of what I assume is the lake.
I like to clean up and partition my ggplot stuff into bits, since I often find something in an early part of a ggplot call confuses something in a later part. Here's how I would map the region, draw points, and then add a density contour:
map <- function(){
geom_polygon(data=lon.df,aes(x=long,y=lat,group=piece),colour="black",fill="grey80",size=1)
}
points <- function(){
geom_point(data=age2100,aes(x=x,y=y),size=0.1)
}
density <- function(){
geom_density2d(data=age2100,aes(x=x,y=y),colour="red")
}
ggplot()+map() +points() +density()
Which gives this:
Now that's much different to what your contour looks like, and I don't know why. Maybe your group parameter is grouping all the points with the same z?
Anyway, it seems you don't want a density plot, you want a map of your Z values over your area. This is going to need kriging or some other interpolation technique. Forget about ggplot for a while, concentrate on the numbers.
For starters, plot the points coloured by the z value. You should see this:
which at least will give you a good idea of what the correct contour will look like.
Anyway, this is getting into a full-on tutorial..

Related

how to change the color scale for each graph with facet_wrap and legend

I have a question about facet_wrap() in ggplot2.
I am trying to make a graph that looks like this. I attach an example image 1.enter image description here
In image 1 it can be seen that there are two maps and each one has its legend and color scale. I would like to be able to do this with ggplot and the facet_wrap() function.
My problem is that because the data in the dataframe is very different, they have a lot of amplitude for each map, when plotting the scale it does not allow me to visualize it the way I want.
enter image description here
ggplot(dataframe,mapping=aes(x=lon,x=lat))+
geom_contour_fill((aes(z=hgt,fill=stat(level)))+
geom_contour(aes(z=hgt),color="black",size=0.2)+
scale_fill_distiller(palette = "YlOrBr",direction = 1,super=ScaleDiscretised)+
mi_mapa+
coord_quickmap(xlim = range(dataframe$lon),ylim=range(dataframe$lat),expand = FALSE)+
facet_wrap(~nombre_nivel,scales="free", ncol =2) +
labs(x="Longitud",y="Latitud",fill="altura",title = "campos")
my dataframe has a shape like this. Where the facets are determined by the level variable. In this case the dataframe has another variable which is temp instead of hgt, but it's just another name.
enter image description here
Thanks
I think I've faced the alike problem building the two parts of the single map with two different scales. I found the package grid useful.
library(grid)
grid.newpage()
print(myggplot, vp = specifiedviewport)
In my case I built the first p <- ggplot() than adjusted p2 <- p + ...
with printing the two ggplots (p and p2) in two viewports. You can newly construct p2 with individual scale and print it in the grid. You can find useful information
here.

Polygon function in R creates a line between first and last point

I have a time series that I'd like to plot using the polygon function as I want to create a shade between different time series. However, when calling polygon (), the function adds a line between the first and last point (in essence it connects the first and last point to finish the plot). I would like to know how to tell R not to join up the two. Slightly related questions have been posted (Line connecting the points in the plot function in R) but the solutions didn't help. Any help would be appreciated.
I have already tried several things, such as reordering the data like in the part below.
% ts_lb_vec is my time-series in vector format;
% x is a vector of time (2000 to 2015);
% I first call plot which plots x (time) with y (the time-series). This works fine;
plot(x, ts_lb_vec,type='n',ylim=c(-300,300), ylab="", xlab="")
But if I want to use the polygon function to use the shading capabilities, it draws the line and I have tried reordering the data (as below) to try to eliminate the problem but this is unsuccessful
polygon(x[order(x),ts_lb_vec[order(x)], xlim=range(x), ylim=range(ts_lb_vec))
I would just like R when calling the polygon function to not connect my first and last point (see image). The figure attached bellow was produced using the following code:
plot(x, ts_lb_vec,type='n', ylab="", xlab="")
polygon(x, ts_lb_vec)
Just to clarify, what I would like is for the space between two time series to be filled, hence why I need the function polygon. See image below
I put together a solution using ggplot2.
The key step is drawing a separate polygon where the order of one of the curves is inverted to avoid the crossing over back to the start.
# simple example data
examp.df <- data.frame(time = seq_len(15), a = c(1,2,3,4,5,5,5,4,3,2,4,5,6,7,8), b = c(2,4,5,6,7,8,7,6,6,5,6,4,3,2,1))
# the polygon is generated by inverting the curve b
polygon <- data.frame(time <- c(examp.df$time, rev(examp.df$time)), y.pos = c(examp.df$a, rev(examp.df$b)))
ggplot(examp.df) +
geom_polygon(data = polygon, aes(x = time, y = y.pos), fill = "blue", alpha = 0.25) +
geom_line(aes(x= time, y = a), size = 1, color = "red") +
geom_line(aes(x = time, y = b), size = 1, color = "green") +
theme_classic()
Which results in:
If you want to know more about ggplot2 this is a good introduction.

line connecting label text and point in tmap plot

i'm doing a tmap plot with a shape file, and i want to be plotting several points for which i have long-lat coordinates onto the shape file. i've got the plot working just fine, however there are too many points on the map, meaning that the label text for different points is overlapping, and is just not particularly legible in general.
here's what the plot currently looks like.
i would really like for the text in the plot to be outside of the actual map, and to be connected to the points in the plot by thin lines which blend into the overall aesthetic of the map.
here's some example data:
name long lat
1 location -71.40909 41.82426
2 location -71.41959 41.82796
3 location -71.41277 41.79667
4 location -71.37327 41.81737
5 location -71.37170 41.89266
6 location -71.33356 41.87736
and here's the code i've got to display the above plot:
let's assume the above dataframe is plot2_points.df, while shapes is the underlying shape file.
library(tmap)
library(sp)
library(rgdal)
coordinates(plot2_points.df) <- c("long", "lat")
proj4string(plot2_points.df) <- CRS("+proj=longlat +datum=WGS84")
plot2_points.df <- spTransform(plot2_points.df, CRS("+proj=utm +zone=19T ellps=WGS84"))
# plot
tm_shape(shapes) + tm_borders() + tm_shape(plot2_points.df) + tm_dots(col = "blue", size = 0.4) + tm_text("name", col = "blue", size = 0.75, just = "top", ymod = 0.75)
i have not been able to find any function that comes anywhere near doing this. tm_lines() doesn't work, but i feel like this is intended for something completely different. also, maybe it would work to do something with the just = option? so far nothing i've tried had any kind of effect, so i figured i'd ask here. any help would be greatly appreciated, thank you very much :)
While the exact solution you are asking for (drawing thin lines from text annotations) is extremely impractical and not (to my knowledge) implemented in tmap you could improve the underlying problem by using tm_symbols() instead of tm_dots() and using the shape property for the spa name (tm_dots() have the shape set to #16 = a dot). The meaning of the symbols would be then explained in a standard legend.
This would be a more "lege artis" way of solving the problem of overlapping text annotations.

How can I recreate this 2d surface + contour + glyph plot in R?

I've run a 2d simulation in some modelling software from which i've got an export of x,y point locations with a set of 6 attributes. I wish to recreate a figure that combines the data, like this:
The ellipses and the background are shaded according to attribute 1 (and the borders of these are of course representing the model geometry, but I don't think I can replicate that), the isolines are contours of attribute 2, and the arrow glyphs are from attributes 3 (x magnitude) and 4 (y magnitude).
The x,y points are centres of the triangulated mesh I think, and look like this:
I want to know how I can recreate a plot like this with R. To start with I have irregularly-spaced data due to it being exported from an irregular mesh. That's immediately where I get stuck with R, having only ever used it for producing box-and-whisper plots and the like.
Here's the data:
https://dl.dropbox.com/u/22417033/Ellipses_noheader.txt
Edit: fields: x, y, heat flux (x), heat flux (y), thermal conductivity, Temperature, gradT (x), gradT (y).
names(Ellipses) <- c('x','y','dfluxx','dfluxy','kxx','Temps','gradTx','gradTy')
It's quite easy to make the lower plot (making the assumption that there is a dataframe named 'edat' read in with:
edat <- read.table(file=file.choose())
with(edat, plot(V1,V2), cex=0.2)
Things get a bit more beautiful with:
with(edat, plot(V1,V2, cex=0.2, col=V5))
So I do not think your original is being faithfully represented by the data. The contour lines are NOT straight across the "conductors". I call them "conductors" because this looks somewhat like iso-potential lines in electrostatics. I'm adding some text here to serve as a search handle for others who might be searching for plotting problems in real world physics: vector-field (the arrows) , heat equations, gradient, potential lines.
You can then overlay the vector field with:
with(edat, arrows(V1,V2, V1-20*V6*V7, V2-20*V6*V8, length=0.04, col="orange") )
You could"zoom in" with xlim and ylim:
with(edat, plot(V1,V2, cex=0.3, col=V5, xlim=c(0, 10000), ylim=c(-8000, -2000) ))
with(edat, arrows(V1,V2, V1-20*V6*V7, V2-20*V6*V8, length=0.04, col="orange") )
Guessing that the contour requested if for the Temps variable. Take your pick of contourplots.
require(akima)
intflow<- with(edat, interp(x=x, y=y, z=Temps, xo=seq(min(x), max(x), length = 410),
yo=seq(min(y), max(y), length = 410), duplicate="mean", linear=FALSE) )
require(lattice)
contourplot(intflow$z)
filled.contour(intflow)
with( intflow, contour(x=x, y=y, z=z) )
The last one will mix with the other plotting examples since those were using base plotting functions. You may need to switch to points instead of plot.
There are several parts to your plot so you will probably need several tools to make the different parts.
The background and ellipses can be created with polygon (once you figure where they should be).
The contourLines function can calculate the contour lines for you which you can add with the lines function (or contour has and add argument and could probably be used to add the lines directly).
The akima package has a function interp which can estimate values on a grid given the values ungridded.
The my.symbols function along with ms.arrows, both from the TeachingDemos package, can be used to draw the vector field.
#DWin is right to say that your graph don't represent faithfully your data, so I would advice to follow his answer. However here is how to reproduce (the closest I could) your graph:
Ellipses <- read.table(file.choose())
names(Ellipses) <- c('x','y','dfluxx','dfluxy','kxx','Temps','gradTx','gradTy')
require(splancs)
require(akima)
First preparing the data:
#First the background layer (the 'kxx' layer):
# Here the regular grid on which we're gonna do the interpolation
E.grid <- with(Ellipses,
expand.grid(seq(min(x),max(x),length=200),
seq(min(y),max(y),length=200)))
names(E.grid) <- c("x","y") # Without this step, function inout throws an error
E.grid$Value <- rep(0,nrow(E.grid))
#Split the dataset according to unique values of kxx
E.k <- split(Ellipses,Ellipses$kxx)
# Find the convex hull delimiting each of those values domain
E.k.ch <- lapply(E.k,function(X){X[chull(X$x,X$y),]})
for(i in unique(Ellipses$kxx)){ # Pick the value for each coordinate in our regular grid
E.grid$Value[inout(E.grid[,1:2],E.k.ch[names(E.k.ch)==i][[1]],bound=TRUE)]<-i
}
# Then the regular grid for the second layer (Temp)
T.grid <- with(Ellipses,
interp(x,y,Temps, xo=seq(min(x),max(x),length=200),
yo=seq(min(y),max(y),length=200),
duplicate="mean", linear=FALSE))
# The regular grids for the arrow layer (gradT)
dx <- with(Ellipses,
interp(x,y,gradTx,xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
dy <- with(Ellipses,
interp(x,y,gradTy,xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
T.grid2 <- with(Ellipses,
interp(x,y,Temps, xo=seq(min(x),max(x),length=15),
yo=seq(min(y),max(y),length=10),
duplicate="mean", linear=FALSE))
gradTgrid<-expand.grid(dx$x,dx$y)
And then the plotting:
palette(grey(seq(0.5,0.9,length=5)))
par(mar=rep(0,4))
plot(E.grid$x, E.grid$y, col=E.grid$Value,
axes=F, xaxs="i", yaxs="i", pch=19)
contour(T.grid, add=TRUE, col=colorRampPalette(c("blue","red"))(15), drawlabels=FALSE)
arrows(gradTgrid[,1], gradTgrid[,2], # Here I multiply the values so you can see them
gradTgrid[,1]-dx$z*40*T.grid2$z, gradTgrid[,2]-dy$z*40*T.grid2$z,
col="yellow", length=0.05)
To understand in details how this code works, I advise you to read the following help pages: ?inout, ?chull, ?interp, ?expand.grid and ?contour.

R Plot Filled Longitude-Latitude Grid Cells on Map

I have a data frame containing a number of (x,y,z) data points, (x,y) is the lower-right coordinate of a longitude-latitude cell of size w (e.g. a 1-degree grid). The z value has been averaged over this cell.
I'd like to plot these points in R so that the entire grid cell is filled with some colour derived from z.
The result would look something like one of these images:
The projection itself (e.g. Lambert conformal conic, equirectangular) isn't important, just the grid cell plotting.
My data is sparse: not every longitude-latitude cell will have data associated with it.
My hope would be a solution similar to
library(maps)
map("state")
grid_points(my_data,c("x","y","z"),0.5)
where 0.5 is the grid resolution above, indicating a 0.5-degree cell.
Any thoughts?
Thanks!
An alternative to using either spplot or image is to use ggplot2. The relevant geometries are geom_raster and geom_tile. The first is supposed to perform better and yield smaller files, and the second is more standard. The following example call:
ggplot(aes(x = x, y = y, fill = value), data = dat_grid) + geom_tile() +
geom_path(data = ant_ggplot)
orginates from this blogpost of mine. In addition, ggplot2 supports a range of projections through the mapproj package, see coord_map for more details.
The following is a working example (provided you've defined YOUR_DATA to have x,y,z columns):
library(ggplot2)
library(maps)
us_states <- map_data("state")
(ggplot(aes(x=x,y=y,fill=z),data=YOUR_DATA) + geom_tile())+geom_polygon(data=us_states,aes(x=long, y=lat, group=group), colour="black", fill="white", alpha=0)
If your data.frame is "x", try this:
library(sp)
coordinates(x) <- c("x", "y", "z")
gridded(x) <- TRUE
image(x, col = terrain.colors(256), useRaster = TRUE)
To get a really exact answer you should provide a sample of your data, hopefully an entire data.frame or the source where you download and the code you used to read it into R.
If the code above fails at the gridded()<- step then it's likely your x and y values don't actually provide a regular grid, which is implied by your plots. If they really are gridded longitude/latitude values and you need to project them to the ones in your image then see the raster package, or more generally the rgdal package.
library(raster)
?projectRaster
library(rgdal)
?project
?spTransform
(The plots look to me like one of the "Albers Equal Area and Lambert Conformal Conic Projections of North America" as shown on this site: http://www.colorado.edu/geography/gcraft/notes/mapproj/mapproj_f.html).
See http://spatialreference.org to get the PROJ.4 string for your projection which you can use in sp or raster.
I tried to do that kind of map recently and ended up using function interp of library akima to intrapolate my z data into a regular grid before plotting (any kind of projections will have to be done prior to the use of interp):
library(akima)
interp(x,y,z,xo=seq(min(x),max(x),by=0.5),yo=seq(min(y),max(y),by=0.5),extrap=FALSE,linear=TRUE) -> xygrid
image(xygrid,breaks=seq(min(z),max(z),length=10), col=1:10)
You can do this:
library(raster)
r <- rasterFromXYZ(xyz)
plot(r)

Resources