4

For reproduction purposes, consider the following data:

library(rgdal)
library(ggplot2)
library(rgeos)

download.file("http://spatialanalysis.co.uk/wp-content/uploads/2010/09/London_Sport.zip", 

destfile = "London_Sport.zip")
unzip("London_Sport.zip")

projection="+proj=merc"

london_shape = readOGR("./", layer="london_sport")

# Create random points
set.seed(1)
points = data.frame(long=rnorm(10000, mean=-0.1, sd=0.1), lat=rnorm(10000, mean=51.5, sd=0.1))
points = SpatialPoints(points, proj4string=CRS("+proj=latlon"))

# Transform data to our projection
london = spTransform(london_shape, CRS(projection))
points = spTransform(points, CRS(projection))

# Keeps only points inside London
intersection = gIntersects(points, london, byid = T)
outside = apply(intersection == FALSE, MARGIN = 2, all)
points = points[which(!outside), ]

# Blank theme
new_theme_empty <- theme_bw()
new_theme_empty$line <- element_blank()
new_theme_empty$rect <- element_blank()
new_theme_empty$strip.text <- element_blank()
new_theme_empty$axis.text <- element_blank()
new_theme_empty$plot.title <- element_blank()
new_theme_empty$axis.title <- element_blank()
new_theme_empty$plot.margin <- structure(c(0, 0, -1, -1), unit = "lines", valid.unit = 3L, class = "unit")

# Prepare data to ggplot
london = fortify(london)
points = as.data.frame(points)

I want to plot a density map of the points. I can do so by using stat_bin2d:

ggplot() + 
  geom_polygon(data=london, aes(x=long,y=lat,group=group), fill="black") +
  stat_bin2d(data=points, aes(x=long,y=lat), bins=40) +
  geom_path(data=london, aes(x=long,y=lat,group=id), colour='white') +
  coord_equal() +
  new_theme_empty

But that results in some parts of the density squares to be be plotted outside of London:

Density

How can I plot the density map only inside London?

João Pesce
  • 2,424
  • 1
  • 24
  • 26
  • 1
    If all the stuff you want to plot is already inside the polygon, you can just set the *colour* of the lines for the polygon to white and plot as is. If that isn't the case, see the `gDifference` function in the [rgeos package](http://cran.r-project.org/web/packages/rgeos/index.html). As always, if you provide a small reproducible example of where you are at so far it helps others. – Andy W Jan 22 '14 at 16:02
  • Just put a small reproducible example :) – João Pesce Jan 23 '14 at 05:47
  • 1
    This link may be helpful: http://spatial.ly/2013/12/introduction-spatial-data-ggplot2/ – tonytonov Jan 24 '14 at 06:30
  • Thanks, it was helpful :) Now I removed points outside of London. Helped a lot, but the problem persists since part of the squares (from stat_bin2d) go outside of the polygon. I don't want to lose precision and aggregate them by boroughs. – João Pesce Jan 24 '14 at 18:17

1 Answers1

4

I found the answer by getting the polygon that is the difference between London's bounding box and London itself (using gDifference) and plotting it in white above everything. The downsides I can think for this approach are: 1) you have to manually increase the size of the polygon if some squares still appear behind it. 2) you can't use a plotting theme with complex background. So I'll leave the question open for a while if anyone has a better answer.

Here's the code:

library(rgdal)
library(ggplot2)
library(rgeos)

projection="+proj=merc"

#London boroughs polygons
download.file("http://spatialanalysis.co.uk/wp-content/uploads/2010/09/London_Sport.zip", destfile = "London_Sport.zip")
unzip("London_Sport.zip")
london = readOGR("./", layer="london_sport")
london = spTransform(london, CRS(projection))

# Generate random points
set.seed(1)
points = data.frame(long=rnorm(10000, mean=-0.1, sd=0.1), lat=rnorm(10000, mean=51.5, sd=0.1))
points = SpatialPoints(points, proj4string=CRS("+proj=latlon"))
points = spTransform(points, CRS(projection))

# Keep only points inside London
intersection = gIntersects(points, london, byid = TRUE)
inside = apply(intersection == TRUE, MARGIN = 2, any)
points = points[which(inside), ]

# Create a bounding box 10% bigger than the bounding box of London
x_excess = (london@bbox['x','max'] - london@bbox['x','min'])*0.1
y_excess = (london@bbox['y','max'] - london@bbox['y','min'])*0.1
x_min = london@bbox['x','min'] - x_excess
x_max = london@bbox['x','max'] + x_excess
y_min = london@bbox['y','min'] - y_excess
y_max = london@bbox['y','max'] + y_excess
bbox = matrix(c(x_min,x_max,x_max,x_min,x_min,
                y_min,y_min,y_max,y_max,y_min),
              nrow = 5, ncol =2)
bbox = Polygon(bbox, hole=FALSE)
bbox = Polygons(list(bbox), "bbox")
bbox = SpatialPolygons(Srl=list(bbox), pO=1:1, proj4string=london@proj4string)

# Get the Polygon that is the difference between the bounding box and London
outside = gDifference(bbox,london)

# Blank theme
new_theme_empty <- theme_bw()
new_theme_empty$line <- element_blank()
new_theme_empty$rect <- element_blank()
new_theme_empty$strip.text <- element_blank()
new_theme_empty$axis.text <- element_blank()
new_theme_empty$plot.title <- element_blank()
new_theme_empty$axis.title <- element_blank()
new_theme_empty$plot.margin <- structure(c(0, 0, -1, -1), unit = "lines", valid.unit = 3L, class = "unit")

# Prepare data for ggplot
london = fortify(london)
points = as.data.frame(points)
outside = fortify(outside)

# Plot!
ggplot() + 
  geom_polygon(data=london, aes(x=long,y=lat,group=group), fill="black") +
  stat_bin2d(data=points, aes(x=long,y=lat), bins=40) +
  geom_path(data=london, aes(x=long,y=lat,group=id), colour='white') +
  geom_polygon(data=outside, aes(x=long,y=lat), fill='white') +
  coord_equal() +
  new_theme_empty

Plot

João Pesce
  • 2,424
  • 1
  • 24
  • 26