RObservations #15: I reverse-engineered Atlas.co (well, some of it)

Introduction

atlas.co
(The Atlas.co logo)

A while back, the famous travel Youtubers Kara and Nate announced that they launched a new company called Atlas.co which prints custom souvenir maps as hangable artwork. After spending some time looking at how the maps looked I thought it would be interesting to see if it is possible to reverse engineer it – and lo and behold- it is (hence the blog) – in R!

In this blog I’m going to share the code that I have put together for this. There is definitely potential to build out this code and make it into a full blown Shiny application with printing capabilities, but for now, I’m sharing the “bare bones” functional code without any of the “bells and whistles” you would find when making a custom map on Atlas.co. Features like making a custom title, being able to edit the map text in a graphical interface, account for multiple stops and having a drop-shipping business infrastructure to print on demand are the big things lacking here. Additionally, I have only figured out how to plot the driving routes- flight paths shouldn’t be to difficult to figure out but I haven’t spent much time working on it.

This was a cool idea to tinker with and I hope you enjoy this code as much as I do! It might be a long shot, but if Kara and Nate are reading this – I’m a big fan of the site and the product, which is why I wanted to try to make it myself! Thank you for the inspiration!

Required packages

The code for this requires installation of the leaflettidygeocoder and osrm packages. I load tidyverse in my code out of habit (might not be a good one) so that I can use the pipe operator but otherwise it is not necessary.

If you are interested in printing your work you are going to want to install the htmlWidgetsmagick and webshot packages.

The Map Code

The code for making the map is actually pretty straight forward as its based on functions available in the leaflet and osrm packages. The real challenge is because we are interested in only certain parameters, choosing which ones to put the user in control of vs which ones not to requires some thinking. The features that we can add are endless, but we don’t want to be overwhelming.

The code for making the visual is here. I could go and explain every part, but if you have a little bit of exposure to the libraries used, its essentially putting pieces together and setting the appropriate arguments.

library(tidyverse)
library(leaflet)
library(tidygeocoder)
library(osrm)



plot_route<-function(to, 
                     from,
                     how="car",
                     colour="black",
                     opacity=1,
                     weight=1,
                     radius=2,
                     label_text=c(to,from),
                     label_position="bottom",
                     provider=providers$CartoDB.PositronNoLabels,
                     font = "Lucida Console",
                     font_weight="bold",
                     font_size= "14px",
                     text_indent="15px"){
  address_single <- tibble(singlelineaddress = c(to,from)) %>% 
    geocode(address=singlelineaddress,method = 'arcgis') %>% 
  transmute(id = singlelineaddress,
         lon=long,
         lat=lat)
  
  trip <- osrmRoute(src=address_single[1,2:3] %>% c,
                     dst=address_single[2,2:3] %>% c,
                     returnclass="sf", 
                    overview="full",
                    osrm.profile = how )

    m<-leaflet(trip,
               options = leafletOptions(zoomControl = FALSE,
                                        attributionControl=FALSE)) %>%
       fitBounds(lng1 = max(address_single$lon)+0.1,
                 lat1 = max(address_single$lat)+0.1,
                 lng2 = min(address_single$lon)-0.1,
                 lat2 = min(address_single$lat)-0.1) %>%  
      addTiles() %>% 
  addProviderTiles(provider = provider) %>% 
  addCircleMarkers(lat = address_single$lat,
                   lng = address_single$lon,
                   color = colour,
                   stroke = FALSE,
                   radius = radius,
                   fillOpacity = opacity) %>%
      addPolylines(color = colour,
                   opacity=opacity,
                   weight=weight) %>% 
       addLabelOnlyMarkers(address_single$lon,
                           address_single$lat, 
                           label =  label_text,
                           labelOptions = labelOptions(noHide = T,
                                                       direction = label_position,
                                                       textOnly = T,
                                                       style=list("font-family" = font,
                                                                  "font-weight"= font_weight,
                                                                  "font-size"=font_size,
                                                                  "text-indent"=text_indent))) 

  m
}

With that done, lets try out function.

viz<- plot_route("New York City",
                 "Los Angeles",
                  how="car",
                  font="Courier",
                  label_position="right",
                  weight=1.5)

viz
(When you run the code this is zoomable)

Now lets compare it to Atlas.co:

(Same visual from Atlas.co)

Atlas.co does look better because of the saturation, but with some theming we could get it to look the same.

Making your map an SVG file (for printing)

Now that we have the map created, we can format the map for printing. Its important to have it exported as an .svg file as this ensures your map will look crisp regardless of the size you want it.

Here is a short function I wrote for exporting your map as a .svg file:

library(webshot)
library(htmlwidgets)
library(magick)

get_route_svg<-function(viz, svg_name="Rplot.svg", zoom=3){
  # Saving the html generated
  saveWidget(viz, "temp.html", selfcontained = FALSE)
  
  webshot("temp.html",
          cliprect = "viewport",
          zoom=zoom,
          file = "Rplot.png") %>% 
    image_read() %>% 
    image_convert(format='svg') %>% 
    image_write('Rplot.svg')
  
  file.remove("temp.html")
  file.remove("Rplot.png")
  print(paste(svg_name,"written in",getwd()))
}

get_route_svg(viz)

After that you are ready to have your map printed locally or online!

You could tweak the map with another platform as well, this is what I made with Canva.com:

Compared to Atlas.co

Conclusion

This was pretty fun to do. I never got a chance to learn how to use leaflet and with less than 100 lines of code its possible to make beautiful visuals. It is possible to make this into a full blown application with an end to end solution for creating custom maps and printing them with Shiny, but for now I’ll leave that for another time.

Thank you for reading my blog! For more intricate and pretty maps, be sure to check out Atlas.co!

4 Comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s