Moving parts of a country over a map

January 28, 2018
By

(This article was first published on Category R on Roel's R-tefacts, and kindly contributed to R-bloggers)

I love making maps, I also love making gifs.
In this short post I make an animated gif of parts of a map moving. In this case the parts of the map only move in the xy direction, but you can also turn them, and make them bigger or smaller.
Today I show you how I made a part of the Netherlands ‘float away’. It is part of a larger nonsense project (I have many silly projects), and mostly just to document my path to learning about spatial analytics.

End result :

General principles

  • make small functions that do one thing well (not that small in this case)
  • combine those
  • make imagemagick canvas
  • write to the canvas
  • animate the canvas

loading libraries and data

suppressMessages(library(tidyverse)) # ggplot2, dplyr, purrr, etc.
library(magick)
library(sf)
library(paletti) # thanks @edwinthoen

# colorscheme
dutchmasters_fill <- get_scale_fill(get_pal(dutchmasters))
# the data
NLD <- read_sf("data/NLD_adm1.shp") # I cannot redistribute the data from GADM, but you can download and use it for your projects

basic functions

I created a function that takes a name, uses that to filter the data and apply a transformation on that part only. (a mutate_if() could also work, but I didn’t know how). And also one that uses that function to plot. The final function takes a matrix of xy values and sequentially applies every row to the plotting function.

  • modify data
  • plot a single ggplot version
  • loop or apply over range
# basic function that moves an a province
move_province <- function(provincename, movement){
    mov <- quo(movement)
    rest <- NLD %>%
        filter(NAME_1 != !!provincename) %>%
        filter(TYPE_1 != "Water body")
    #rest %>% st_centroid() %>% st_as_text()
    province <- NLD %>%
        filter(NAME_1 == !!provincename) %>%
        mutate(geometry = geometry + !!mov) %>%
        st_set_crs("+proj=longlat +datum=WGS84 +no_defs")

    data1 <-
        rbind(province, rest)
    centroids <-
        data1 %>% st_centroid()  %>% st_coordinates()
    cbind(data1, centroids)
}
# make function to create plot
# using the previous function to move the province
plot_netherlands <- function(province, movement){
    plotunit <- move_province(provincename = province, movement = movement) %>%
            ggplot()+
            geom_sf(aes(fill = NAME_1),color = "grey50", alpha = 3/4)+
            geom_text(aes(X,Y, label = NAME_1), size = 6)+
            lims(x = c(3.2,7.1), y = c(50.8,55))+
            labs(x="", y = "", caption = "shapefiles from www.gadm.org", title = "Floating Friesland")+
            dutchmasters_fill("little_street")+
            theme( legend.position = "empty", # we already labeled the provinces
                   panel.grid.major = element_line(colour = "grey80"))
    print(plotunit) # you have to explicitly tell it to print so the image is captured
}
# go over every frame and print
plot_province_over_range <-
     function(offset_matrix, province = "Friesland", debug = FALSE){

    if(any(is.na(offset_matrix))){stop("I cannot handle empty movements, there are NA's in movement_matrix")}
    if(NCOL(offset_matrix) != 2) stop("movement_matrix needs to have exactly 2 columns")
    actionsframe <- data_frame(x = offset_matrix[,1], y = offset_matrix[,2]) %>%
        mutate(rownumber = row_number())
    actionsframe$name <- paste0(formatC(actionsframe$rownumber, flag = 0,width = 4))

    pb <- progress_estimated(NROW(actionsframe))

    walk(actionsframe$name, ~{

        pb$tick()$print()
        vars <- filter(actionsframe, name == .x)
        if(debug){
            message("using values from: ",vars)
        }

        plot_netherlands(province = province,movement = c(vars$x[[1]], vars$y[[1]]))

        }) # ends the walk action
}

The plotting and saving

Nothing happened before the next step (except loading data). All the action and calculation happens here.

## then the creation starts with the movement
Friesland_moves <- rbind(
    matrix(c(c(0,-.1,-.2,-.2,-.3), c(0,.03,.05,.1,.15)) ,ncol = 2),
    matrix(c(seq(from = -.3, by = -.1, length.out = 14),seq(from = .2, by = .1, length.out = 14)), ncol = 2)
)
# set up print location
frames <- image_graph(width = 1500, height = 2500, res = 300, pointsize = 5)


plot_province_over_range(offset_matrix = Friesland_moves, province = "Friesland")

# animate
image_animate(frames, 1) %>%
    image_write(path = "friesland.gif")

Notes

I tried to edit this post on github on my mobile phone, boy, that does not work at all!

To leave a comment for the author, please follow the link and comment on their blog: Category R on Roel's R-tefacts.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

Search R-bloggers

Sponsors

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)