Circular Migration Flow Plots in R

A article of mine was published in Science today. It introduces estimates for bilateral global migration flows between all countries. The underlying methodology is based on the conditional maximisation routine in my Demographic Research paper. However, I tweaked the demographic accounting which ensures the net migration in the estimated migration flow tables matches very closely to the net migration figures from the United Nations.

My co-author, Nikola Sander, developed some circular plots for the paper based on circos in perl. A couple of months back, after the paper was already in the submission process, I figured out how to replicate these plots in R using the circlize package. Zuguang Gu, the circlize package developer was very helpful, responding quickly (and with examples) to my emails.

To demonstrate, I have put two demo files in my migest R package. For the estimates of flows by regions, users can hopefully replicate the plots (so long as the circlize and plyr packages are installed) using:

library("migest")
demo(cfplot_reg, package = "migest", ask = FALSE)

It should result in the following plot:
cfplot_reg
The basic idea of the plot is to show simultaneously the relative size of estimated flows between regions. The origins and destinations of migrants are represented by the circle’s segments, where nearby regions are positioned close to each other. The size of the estimated flow is indicated by the width of the link at its bases and can be read using the tick marks (in millions) on the outside of the circle’s segments. The direction of the flow is encoded both by the origin colour and by the gap between link and circle segment at the destination.

You can save the PDF version of the plot (which looks much better than what comes up in my R graphics device) using:

dev.copy2pdf(file = "cfplot_reg.pdf", height=10, width=10)

If you want to view the R script:

file.show(system.file("demo/cfplot_reg.R", package = "migest"))

In Section 5 of our Vienna Institute of Demography Working Paper I provide a more detailed breakdown for the R code in the demo files.

A similar demo with slight alterations to the labelling is also available for a plot of the largest country to country flows:

demo(cfplot_nat, package = "migest", ask = FALSE)

cfplot_nat

If you are interested in the estimates, you can fully explore in the interactive website (made using d3.js) at http://global-migration.info/. There is also a link on the website to download all the data. Ramon Bauer has a nice blog post explaining the d3 version.

Publication Details:

Abel, G.J. and Sander, N. (2014). Quantifying Global International Migration Flows. Science. 343 (6178), 1520–1522.

Widely available data on the number of people living outside of their country of birth do not adequately capture contemporary intensities and patterns of global migration flows. We present data on bilateral flows between 196 countries from 1990 through 2010 that provide a comprehensive view of international migration flows. Our data suggest a stable intensity of global 5-year migration flows at ~0.6% of world population since 1995. In addition, the results aid the interpretation of trends and patterns of migration flows to and from individual countries by placing them in a regional or global context. We estimate the largest movements to occur between South and West Asia, from Latin to North America, and within Africa.

About these ads
This entry was posted in International Migration Estimation, migest, R, Research. Bookmark the permalink.

16 Responses to Circular Migration Flow Plots in R

  1. Dan Holstein says:

    Hello Guy,

    Congratulations on the publication. I really like this visualization. I’ve installed migest and taken a look at the demos; however, I’m unclear how I might create a plot like this from my data. If I have a square connectivity or migration matrix, can I use your migest package to create (and tweak) a plot such as the ones you’ve shown here?

    Cheers,
    Dan

    • gjabel says:

      Hi Dan. Take a look at Section 5 of the Vienna Institute of Demography Working Paper (the link is in the post above, below the first plot). There I explain all the lines of the R code in the demo files, based on the original 10 by 10 origin-destination flow table read from a .txt file. Let me know if there are anything that remains unclear? We are going to submit the paper to journal fairly soon, so any feedback would be great.

  2. beautiful visualization – thanks for the post, and for creating the library!

  3. Emilio says:

    Good job Guy… Cheers from Mexico!

  4. Sabby says:

    Hi Dan,
    a friend of mine posted your fantastic migration globe chart in Facebook and I was wondering if you could send me the file by any chance. I would love to print it out and put it up on my wall (in high quality, like a poster). I know its not what you had in mind but I already have a “future trend map” as wall decoration. It s a powerful visualization. Thanks. Cheers from Germany

    • Sabby says:

      Sorry, I meant Guy, of course. Hi Guy… :-)

      • gjabel says:

        Hi Sabby.

        There is a poster based on my estimates, which includes a larger plot of country to country flows. The plot itself was done in Circos (rather than R) by my colleague. At the bottom of http://www.global-migration.info/ webpage you can find a link to the PDF (we call it a data sheet) and also a details on how anyone can request a hard copy, which I believe will post to you for free!

        If you still want to create a you own print of the R version of the plot, you can do so by running the demo script and printing the graphics device to a PDF as I show in the post above, but use much bigger arguments for the height and width, something like dev.copy2pdf(file = “cfplot_reg.pdf”, height=40, width=40) . This will give you a 40 inch square plot saved in you current R working directory.

        Hope this helps?

        Guy

  5. Mat says:

    Dear Guy,
    Just used your idea, and made a graph on myself! Incredible graph, it has a lot of explanatory power. Simply love it.
    Cheers

  6. anthony says:

    Hi Guy,
    That’s a beautiful graph. I would like make a similar graph using our data, however, I received this error message “Detect some gaps are too large”. You also mentioned this error in one of your reports. Do you recall how you fixed it? Thanks so much.

  7. gjabel says:

    Hi Anthony. I guess have a fiddle with the circos.par, in particular the gap.degree argument? In the plots above I had circos.par(cell.padding=c(0,0,0,0), track.margin=c(0,0.1), start.degree = 90, gap.degree =4).

  8. Anthony says:

    Hi Guy,

    I have tried the parameters as you suggested, but still does not work. Do you think because some values are very small as compare to others (e.g.; 1 versus 1812)?. I made a few changes to my data as in matrix 2 by adding a few zeros after a 1 or 2 and it works. Is there any way to work around with this a large range? I would like to plot this beautiful graph using my real data (matrix 1). Any help is much appreciated.

    Thanks.

    Anthony

    library(circlize)
    #matrix 1
    #level0 <- c(1, 8, 39, 14, 2)
    #level1 <- c(1, 19, 153, 93, 1)
    #level2 <- c(2, 19, 274, 46, 13)
    #level3 <- c(0, 8, 152, 1812, 465)
    #level4 <- c(0, 2, 1, 164, 226)

    #matrix 2
    #level0 <- c(100,8,39,14,200)
    #level1 <- c(100,190, 153,93,100)
    #level2 <- c(200,19,274,646,130)
    #level3 <- c(200,800,152,1812,465)
    #level4 <- c(200,200,100,164,226)

    #build matrix 2
    a <- list(c(100,8,39,14,200),c(100,19, 153,93,100), c(200,19,274,646,13), c(200,8,152,1812,465),c(200,200,100,164,226))
    mat <- do.call(rbind, a)
    mat <- do.call(rbind, a)
    mat <- rbind(level0,rbind(level1,rbind(level2,rbind(level3,level4))))
    #mat = matrix(sample(1:100, 25, replace = TRUE), 5, 5)
    rownames(mat) = c("level 0", "level 1", "level 2", "level 3", "level 4")
    colnames(mat) = c("Level0", "Level1", "Level2", "Level3", "Level4")
    rn = rownames(mat)
    cn = colnames(mat)

    factors = c(rn, rev(cn))
    factors = factor(factors, levels = factors)
    col_sum = apply(mat, 2, sum)
    row_sum = apply(mat, 1, sum)
    xlim = cbind(rep(0, 10), c(row_sum, col_sum))

    par(mar = c(1, 1, 1, 1))
    circos.par(cell.padding = c(0, 0, 0, 0), clock.wise = FALSE, track.margin=c(0,0.1),
    gap.degree = 4, start.degree =90)
    circos.initialize(factors = factors, xlim = xlim
    , sector.width = c(row_sum/sum(row_sum), col_sum/sum(col_sum)))
    circos.trackPlotRegion(factors = factors, ylim = c(0, 1), bg.border = NA,
    # bg.col = c("red", "orange", "yellow", "green", "blue", rep("grey", 5)), track.height = 0.05,
    bg.col = c(c("red", "orange", "yellow", "green", "blue"),
    c("blue", "green", "yellow", "orange", "red")), track.height = 0.05,
    panel.fun = function(x, y) {
    sector.name = get.cell.meta.data("sector.index")
    xlim = get.cell.meta.data("xlim")
    circos.text(mean(xlim), 3, sector.name, adj = c(0.5, 0))
    circos.axis(labels.cex=0.8, direction="outside", labels.away.percentage=0.5)
    if(sector.name %in% rn) {
    for(i in seq_len(ncol(mat))) {
    circos.lines(rep(sum(mat[sector.name, seq_len(i)]), 2), c(0, 1),
    col = "white")
    }
    } else if(sector.name %in% cn) {
    for(i in seq_len(nrow(mat))) {
    circos.lines(rep(sum(mat[ seq_len(i), sector.name]), 2), c(0, 1),
    col = "white")
    }
    }
    })
    col = c("#FF000020", "#FFA50020", "#FFFF0020", "#00FF0020", "#0000FF20")
    for(i in seq_len(nrow(mat))) {
    for(j in seq_len(ncol(mat))) {
    circos.link(rn[i], c(sum(mat[i, seq_len(j-1)]), sum(mat[i, seq_len(j)])),
    cn[j], c(sum(mat[seq_len(i-1), j]), sum(mat[seq_len(i), j])),
    col = col[i], border = "white")
    }
    }

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s