RMD file for explorign ggrepel and maps. Gist available here

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.

#' 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

findboxes <- function(df, xcol, ycol, pad_point_x, pad_point_y, 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 + pad_point_x, 
             yval + pad_point_y))})                                       
    # columns are x1,y1,x2,y2
    boxmatrix = as.matrix(t(boxdf))
    
    moved <- ggrepel:::repel_boxes(data_points=as.matrix(posdf), 
                                   pad_point_x=0.1, 
                                   pad_point_y=0.1, 
                                   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.

# 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.

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

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

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)