Great circles on a recentered worldmap, in ggplot

Even though several examples of great circle visualizations exist by now, I had not seen the code of one made with ggplot2. Both solutions offered, here using plot and here using lattice, basically loop through the great circle lines ordered from low to high number of flights and overplot the lines with fewer counts, which are plotted in a light color with those with higher counts, which are plotted in a dark color.

In ggplot we can simply use the alpha parameter for transparency in combination with scale_colour_gradient to obtain a similar effect.

I am also addressing another issue here, namely the ability to flexibly recenter the world map to any longitude (not just 0 and 180) and to avoid the problem of split polygons.

Example data are all flights out of Beijing, China, downloaded from openflights.org.

Beijing - outgoing flights

[Update 5/5/2012: Note that I wrote this code with the earlier version of ggplot (0.89). Apparently there is an issue with ggplot 0.9 and the fortify.SpatialLinesDataFrame function - please see the comments below and suggestion for a workaround. Thank you Einar!]

No TweetBacks yet. (Be the first to Tweet this post)

10 thoughts on “Great circles on a recentered worldmap, in ggplot

  1. Thanks so much for posting this--that split polygon thing was driving me nuts, and this is a great patch. That 300 degree thing works brilliantly.

    I pulled your code into a function with options to apply to either a polygon or string of segments for my own use (I may have introduced a couple mistakes along the way--it seems to have trouble with the Caspian sea and Antarctica in the shapefile I'm using, not from the maps package). Here it is, in case anyone else comes looking for something similar:

    Recenter = function(
    data=world,
    center=260,
    # positive values only - US centered view is 260
    shapeType=c("polygon","segment"),
    idfield=NULL
    # shift coordinates to recenter great circles
    ) {

    #use inherited id column, or create a new one from breaks in the data
    if(is.null(idfield)) {
    data$id=factor(cumsum(is.na(data$long)))
    }else{
    data$id = get(idfield,pos=data)
    }

    # shift coordinates to recenter worldmap
    data$long <- ifelse(data$long < center - 180 , data$long + 360, data$long)

    ### Function to regroup split lines and polygons
    # takes dataframe, column with long and unique group variable,
    #returns df with added column named group.regroup
    RegroupElements <- function(df, longcol, idcol){
    g 300) {
    # check if longitude within group differs more than 300 deg, ie if element was split
    d mean(range(df[,longcol]))
    # we use the mean to help us separate the extreme values
    g[!d] <- 1
    # some marker for parts that stay in place (we cheat here a little, as we do not take into account concave polygons)
    g[d] <- 2
    # parts that are moved
    }
    g <- paste(df[, idcol], g, sep=".") # attach to id to create unique group variable for the dataset
    df$group.regroup <- g
    df
    }

    ### Function to close regrouped polygons
    # takes dataframe, checks if 1st and last longitude value are the same, if not, inserts first as last and reassigns order variable
    ClosePolygons <- function(df, longcol, ordercol){
    if (df[1,longcol] != df[nrow(df),longcol]) {
    tmp <- df[1,]
    df <- rbind(df,tmp)
    }
    df
    }

    # now regroup

    returnframe <- ddply(data, .(id), RegroupElements, "long", "id")

    # close polys
    if(shapeType[1]=="polygon") {
    returnframe <- ddply(returnframe, .(group.regroup), ClosePolygons, "long", "order") # use the new grouping var
    }
    ggplot(returnframe,aes(x=long,y=lat))+geom_polygon(aes(group=group.regroup))
    returnframe
    }

  2. Thanks a lot for this. I am replicating the steps.

    I get this error Error: could not find function "fortify.SpatialLinesDataFrame"
    while executing step
    rts.ff <- fortify.SpatialLinesDataFrame(rts)

    Would you know whats causing this.

    1. I'm a bit of novice. Would someone be so kind as to post complete working code for ggplot2 0.9? I'm not quite sure how to integrate fortify-spatial.r. Thank you, thank you. I was almost about to give up on great circles over the Pacific.

    2. KP,

      Download the entire code for fortify-spatial.r to your working directory.

      In R:
      source ("fortify-spatial.r") # if necessary adjust path

      Then run the fortify.SpatialLinesDataFrame command from the code above.

  3. if you have a problem like :
    Error: could not find function "fortify.SpatialLinesDataFrame"

    change this step.
    rts.ff <- fortify.SpatialLinesDataFrame(rts)

    to.
    rts <- as(rts, "SpatialLinesDataFrame")
    rts.ff <- fortify(rts)

    it will be okay.

  4. Thanks for sharing!

    I was getting the error message "Error: Use 'theme' instead. (Defunct; last used in version 0.9.1)" and replaced the last few lines of code with the following and it workded:

    ggplot() +
    geom_polygon(aes(long.recenter,lat,group=group.regroup), size = 0.2, fill="#f9f9f9", colour = "grey65", data=worldmap.cp) +
    geom_line(aes(long.recenter,lat,group=group.regroup, color=freq, alpha=freq), size=0.4, data= gcircles.rg) + # set transparency here
    scale_colour_gradient(low="#fafafa", high="#EE0000") + # set color gradient here
    theme(panel.background = element_blank(), panel.grid.minor = element_blank(), panel.grid.major = element_blank(), axis.ticks = element_blank(), axis.title.x = element_blank(), axis.title.y = element_blank(), axis.text.x = element_blank(), axis.text.y = element_blank(), legend.position = "none") +
    ylim(-60, 90) +
    coord_equal()

Comments are closed.