Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ggrepel with maps
---
title: "ggrepel to plot on busy maps"
author: "zachcp"
date: "March 1, 2016"
output: html_document
---
```{r, warning=FALSE, message=FALSE}
library(rvest)
library(dplyr)
library(png)
library(sp)
library(maps)
library(rgeos)
library(grid)
library(ggplot2)
library(ggthemes)
```
## Download Flags
Download a bunch of flag files from Wikipedia.
```{r}
#' Download Map files from Wikimedia
process_flagname <- function(fname,outdir="./flags/", prefix="http:"){
flag <- strsplit(fname, ",")[[1]][[1]]
flag <- strsplit(flag, " ")[[1]][[1]]
flagimgname <- strsplit(flag, "/")[[1]][[9]]
countryname <- strsplit(flagimgname, "\\.")[[1]][[1]]
countryname <- strsplit(countryname, "_")[[1]][[3]]
flagurl <- paste0(prefix,flag)
newflag <- paste0(outdir, countryname,".png")
download.file(flagurl, destfile = newflag)
print(paste0("Downloading flag iamge for ", countryname, "."))
}
flags <- read_html("https://en.wikipedia.org/wiki/Gallery_of_sovereign_state_flags")
flagimages <- flags %>%
html_nodes(".thumbborder") %>%
html_attr("srcset")
#get all the images
#lapply(flagimages, process_flagname)
# df of the downloaded flagfiles
flagfiles <- data.frame(flag = list.files("flags",pattern = "*.png"))
countries <- as.character(
lapply(as.character(flagfiles$flag), function(x){strsplit(x,"\\.")[[1]][[1]]}))
flagfiles$country <- countries
```
## Function that calls ggrepel
```{r}
findboxes <- function(df, xcol, ycol,
pad_point_x, pad_point_y,
boxsize,
xlim, ylim,
force = 1e-6, maxiter = 20000) {
#x and y posiitons as a dataframe
posdf <- df[c(xcol,ycol)]
#returnd a df where columns are points
boxdf <- apply(posdf,1,function(row) { xval <- row[xcol]
yval <- row[ycol]
return(c(xval,
yval,
xval + boxsize,
yval + boxsize))})
# columns are x1,y1,x2,y2
boxmatrix = as.matrix(t(boxdf))
moved <- ggrepel:::repel_boxes(data_points=as.matrix(posdf),
pad_point_x=pad_point_x,
pad_point_y=pad_point_y,
boxes = boxmatrix,
xlim=xlim,
ylim=ylim,
force=force,
maxiter=maxiter)
finaldf <- cbind(posdf, moved)
names(finaldf) <- c("x1","y1","x2","y2")
return(finaldf)
}
```
## BaseMap
Process countries and get centroid starting positions.
```{r}
# get centroids of countries
world <- map_data("world")
getLabelPoint <- function(country) {
rgeos::gCentroid(SpatialPoints(country[c('long','lat')]))}
centroids <- by(world, world$region, getLabelPoint)
centnames <- names(centroids)
centroids <- as.data.frame(do.call(rbind, centroids) )
row.names(centroids) <- centnames
names(centroids) <- c('long', 'lat')
gg <- ggplot(world)
gg <- gg + geom_map(
data=world,
map=world,
aes(x=long,y=lat, map_id=region),
fill="grey80")
gg <- gg + theme_map()
gg
```
## Add Flags to Map
Don't use ggrepel, just place them on the map.
```{r}
centroids %>%
add_rownames("country") %>%
inner_join(flagfiles, by=c("country")) %>%
mutate(pngfile = paste0("./flags/",flag)) -> flagfiles
apply(flagfiles,
1,
function(x)
{img <- readPNG(x['pngfile'])
g <- rasterGrob(img, interpolate=TRUE)
lat <- as.numeric(x['lat'])
long <- as.numeric(x['long'])
return(list(grob=g, long=long,lat=lat))
}) -> grobs
addmap <- function(gg,g){
grob <- g$grob
lat <- g$lat
long <- g$long
#print(paste(lat,long))
xdiff = 5
ydiff = 5
gg <- gg + annotation_custom(grob,
xmin = long - xdiff,
xmax = long + xdiff,
ymin = lat - ydiff,
ymax = lat + ydiff)
return(gg)
}
# create Map
Reduce(addmap,grobs,gg)
```
## Use ggrepel with Force=0.2 to plot
```{r}
newcentroids <- findboxes(centroids, xcol = 'long', ycol='lat',
pad_point_x = 10, pad_point_y = 10,
xlim = c(-180,180), ylim=c(-60,60),
force=0.2,
maxiter = 1000)
newcentroids %>%
add_rownames("country") %>%
inner_join(flagfiles, by=c("country")) %>%
mutate(pngfile = paste0("./flags/",flag)) -> newflagfiles
apply(newflagfiles,
1,
function(x)
{img <- readPNG(x['pngfile'])
g <- rasterGrob(img, interpolate=TRUE)
lat <- as.numeric(x['y2'])
long <- as.numeric(x['x2'])
return(list(grob=g, long=long,lat=lat))
}) -> newgrobs
gg2 <- gg + geom_point(data=newflagfiles, aes(x1,y1))
gg2 <- gg2 + geom_segment(data=newflagfiles, aes(x1,y1,xend=x2,yend=y2))
Reduce(addmap,newgrobs,gg2)
```
## Use ggrepel with Force=0.8 to plot
```{r}
newcentroids <- findboxes(centroids, xcol = 'long', ycol='lat',
pad_point_x = 10, pad_point_y = 10,
xlim = c(-180,180), ylim=c(-60,60),
force=0.8,
maxiter = 1000)
newcentroids %>%
add_rownames("country") %>%
inner_join(flagfiles, by=c("country")) %>%
mutate(pngfile = paste0("./flags/",flag)) -> newflagfiles
apply(newflagfiles,
1,
function(x)
{img <- readPNG(x['pngfile'])
g <- rasterGrob(img, interpolate=TRUE)
lat <- as.numeric(x['y2'])
long <- as.numeric(x['x2'])
return(list(grob=g, long=long,lat=lat))
}) -> newgrobs
gg2 <- gg + geom_point(data=newflagfiles, aes(x1,y1))
gg2 <- gg2 + geom_segment(data=newflagfiles, aes(x1,y1,xend=x2,yend=y2))
Reduce(addmap,newgrobs,gg2)
```
## Use ggrepel with Force=1 to plot
```{r}
newcentroids <- findboxes(centroids, xcol = 'long', ycol='lat',
pad_point_x = 0.1, pad_point_y = 0.1,
boxsize = 10,
xlim = c(-180,180), ylim=c(-60,60),
force=1,
maxiter = 1000)
newcentroids %>%
add_rownames("country") %>%
inner_join(flagfiles, by=c("country")) %>%
mutate(pngfile = paste0("./flags/",flag)) -> newflagfiles
apply(newflagfiles,
1,
function(x)
{img <- readPNG(x['pngfile'])
g <- rasterGrob(img, interpolate=TRUE)
lat <- as.numeric(x['y2'])
long <- as.numeric(x['x2'])
return(list(grob=g, long=long,lat=lat))
}) -> newgrobs
gg2 <- gg + geom_point(data=newflagfiles, aes(x1,y1))
gg2 <- gg2 + geom_segment(data=newflagfiles, aes(x1,y1,xend=x2,yend=y2))
Reduce(addmap,newgrobs,gg2)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment