4

I wonder whether I can color countries using ggplot? Using rworldmap this is pretty simple and adding points to lat/long values via ggplot is easy as well.

Is there a way of coloring countries based on a simple table using ggplot (country names in ISO3 and a number for each country?) The coloring should be based on the count.

p <- ggplot(legend=FALSE) +

geom_polygon(fill = "darkseagreen", data=world, aes(x=long, y=lat,group=group)) + 
 geom_path(colour = "grey40") + 
 theme(panel.background = element_rect(fill = "lightsteelblue2", colour = "grey")) +
 theme(panel.grid.major = element_line(colour = "grey90")
) +
 theme(panel.grid.minor = element_blank()) +
 theme(axis.text.x = element_blank(),
 axis.text.y = element_blank()) +
 theme(axis.ticks = element_blank()) +
 xlab("") + ylab("")
Gnark
  • 4,080
  • 7
  • 33
  • 44
  • 2
    Of course you can, you just need a column in your data set to fill by and set `aes(fill = that_column)`. And remember, order matters for geography data plotting, so prefer `plyr::join` or `dplyr::left_join` to `merge` because they preserve order of the first data frame. – Gregor Thomas Dec 07 '14 at 02:39
  • Thanks for the comment. The column 'that_column' could consists of ISO3 country codes and the corresponding countries would get colored? How can a gradient be defined so that the coloring reflects some numbers (basically a count for each country to be colored)? – Gnark Dec 07 '14 at 10:49
  • Everything's probably clear from the answer, but to make this comment chain more complete: no, `that_column` would be actual data, like population, GDP, whatever you're measuring. – Gregor Thomas Dec 08 '14 at 04:22

1 Answers1

10

It's pretty straightforward with ggplot. In the following I use a GeoJSON version of the Natural Earth country boundaries (which stores the ISO3 code in iso_a3) projected to Winkel-Tripel. I stored a CSV of World Bank population data in a gist and read that in for the simple table. I then build two layers, one base layer for the world geometries then the filled-in polygons. Since it's pre-projected, I use coord_equal vs coord_map (which is fine for choropleths but not so much if you intend to draw lines as you'll need to pre-project them, then, too):

library(maptools)
library(mapproj)
library(rgeos)
library(rgdal)
library(ggplot2)
library(jsonlite)
library(RCurl)

# naturalearth world map geojson
URL <- "https://github.com/nvkelso/natural-earth-vector/raw/master/geojson/ne_50m_admin_0_countries.geojson.gz"
fil <- basename(URL)

if (!file.exists(fil)) download.file(URL, fil)
R.utils::gunzip(fil)
world <- readOGR(dsn="ne_50m_admin_0_countries.geojson", layer="OGRGeoJSON")

# remove antarctica
world <- world[!world$iso_a3 %in% c("ATA"),]

world <- spTransform(world, CRS("+proj=wintri"))

dat_url <- getURL("https://gist.githubusercontent.com/hrbrmstr/7a0ddc5c0bb986314af3/raw/6a07913aded24c611a468d951af3ab3488c5b702/pop.csv")
pop <- read.csv(text=dat_url, stringsAsFactors=FALSE, header=TRUE)

map <- fortify(world, region="iso_a3")

# data frame of markers 
labs <- data.frame(lat=c(39.5, 35.50), 
                   lon=c(-98.35, 103.27), 
                   title=c("US", "China"))

# pre-project them to winkel-tripel
coordinates(labs) <-  ~lon+lat
c_labs <- as.data.frame(SpatialPointsDataFrame(spTransform(
  SpatialPoints(labs, CRS("+proj=longlat")), CRS("+proj=wintri")),
  labs@data))

gg <- ggplot()
gg <- gg + geom_map(data=map, map=map,
                    aes(x=long, y=lat, map_id=id, group=group),
                    fill="#ffffff", color=NA)
gg <- gg + geom_map(data=pop, map=map, color="white", size=0.15,
                    aes(fill=log(X2013), group=Country.Code, map_id=Country.Code))
gg <- gg + geom_point(data=c_labs, aes(x=lon, y=lat), size=4)
gg <- gg + scale_fill_gradient(low="#f7fcb9", high="#31a354", name="Population by Country\n(2013, log scale)")
gg <- gg + labs(title="2013 Population")
gg <- gg + coord_equal(ratio=1)
gg <- gg + ggthemes::theme_map()
gg <- gg + theme(legend.position="bottom")
gg <- gg + theme(legend.key = element_blank())
gg <- gg + theme(plot.title=element_text(size=16))
gg

enter image description here

hrbrmstr
  • 77,368
  • 11
  • 139
  • 205
  • Could you please show how to add markers or points based on lat/long? – Gnark Dec 07 '14 at 17:20
  • I get the folowing error: isTRUE(gpclibPermitStatus()) is not TRUE – Gnark Dec 07 '14 at 17:22
  • I've updated the example for the annotations, but you should prbly post another question if you want more added. – hrbrmstr Dec 07 '14 at 17:28
  • This is most awesome! Thanks a bunch! – Gnark Dec 07 '14 at 17:32
  • 2
    Very nice! Here's an alternative url (I had problems with the current url): https://github.com/nvkelso/natural-earth-vector/blob/master/geojson/ne_50m_admin_0_countries.geojson.gz?raw=true. I double-clicked on the ``.gz``, set the directory appropriately, ``setwd("~/R/maps") `` and read it with ``world <- readOGR(dsn = "ne_50m_admin_0_countries.geojson", layer = "OGRGeoJSON")`` – PatrickT Mar 27 '15 at 08:48
  • When I run `devtools::source_gist("33baa3a79c5cfef0f6df")` I get the following error: `Error in r_files[[which]] : invalid subscript type 'closure'`. Since I'm not familiar with source_gist I'm not sure how to address this problem. – JerryN Jan 30 '17 at 21:23
  • 1
    @JerryN just use `ggthemes::theme_map()` – hrbrmstr Jan 31 '17 at 03:19
  • And that map data source seems to have gone away too, ah the perils of time. – hrbrmstr Jan 31 '17 at 03:44
  • Not sure what has gone away. I ran `theme_map2 <- ggthemes::theme_map()` and get a list of 59 elements. When I run the function I found on your website I get the same thing. – JerryN Feb 01 '17 at 16:12
  • After adapting to use ggalt::geom_cartogram `world <- spTransform(world, CRS("+proj=wintri"))` results in _NOTE: rgdal::checkCRSArgs: no proj_defs.dat in PROJ.4 shared files Error in spTransform(xSP, CRSobj, ...) : No transformation possible from NA reference system_ – Lod Mar 06 '17 at 14:26