34 thoughts on “Circular Migration Flow Plots in R”

  1. 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?


    1. 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. 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

      1. 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?


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

  4. 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.

  5. 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).

  6. 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.



    #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")

    1. Hi Anthony. Do you want to post your question/code on stackoverflow, send us the link and I will answer there. I have managed to a plot with your data, but it won’t display very well in the wordpress comments section. Guy

      1. Posted the code with plot as an answer. Let me know via stackoverflow if things don’t make any sense. Guy

  7. Hi gjabel! I love this graph. I am trying to replicating this with my data which is a country level trade data. To get an idea of how your code works, I tried your code posted at http://stackoverflow.com/questions/23916451/r-circlize-detect-some-gaps-are-too-large . But this seems to cause an error which I am unable to resolve.
    Error in match.arg(facing) :
    ‘arg’ should be one of “inside”, “outside”, “reverse.clockwise”, “clockwise”, “downward”, “bending”

    I get this after I run the ‘plot sectors’ snippet. Googling on this didn’t help. Any idea why this is happening?

    1. Hi Vanathi. They makers of the circlize package updated some of their functions, so for the moment the demo won’t work…. i have updated the files in a new version (1.6) of the migest package which should be on CRAN in the next few days. If you can’t wait, the discussions in the comments section my answer on the stackoverflow question that you point to explain the same (two) changes I just made to get the demo scripts working error free. You can copy and paste the code in the R scripts of the demo file directory of the current migest (1.5) version you have installed, add in the edits, and then run the script as you would any normal R code. Hope this helps. Guy

  8. Hey Guy, this is probably the best example i’ve come across that allows someone to simply replicate a customised chord chart using circlize. I am wondering whether you’ve had any experience with a rectangular matrix (e.g 8×10) instead of square matrix. Further to this is it possible to put the ‘circos’ in some kind of object/variable that can be printed later similar to a ggplot?

    1. Thanks Dan. I imagine a rectangular matrix should be pretty straight forward, if your row and columns are part of the same set of regions (its just a square matrix with a couple of rows containing zeros). I am not sure about the ggplot style object. I guess not, but probably best to contact the circlize developers. I have found they are really helpful with their responses.

  9. Hi Guy,
    thank you very much for your evaluable effort to share your work.
    I’m trying to replicate your plots using the script available at https://github.com/null2/globalmigration, but unfortunately there is something going wrong.
    First of all I got a warning for all plotting regions (i.e. ” Note: 1 point is out of plotting region in sector ‘Mexico’, track ‘1’ “). I thought the problem was that in circos.text and circos.axis I was using “direction”, which is a deprecated function. But also using “facing” instead of “direction”, the problem persists. So I guess I didn’t understand the meaning of this warning.
    Moreover, in my plot, links were very far from segments. Thus I tried to reduce the track.margin, which solve the problem, but now the names of the segments are outside the margins, and I cannot visualize them.
    Would you be so kind to give me some hints? I posted the same question in stackoverflow (http://stackoverflow.com/questions/27871768/r-circlize-plot-margins-and-plotting-regions). so that it may be easier to communicate.
    Again thank you very much

  10. Hi gjabel
    Thanks for such a wonderful visualistion. I am also trying to perform similar kind of study although its on SNPs sharing .. I have 14 samples and i know the shared section among all the possible combination with in them. Can you library be used to visualise this kind of study as Venn Diagram are not feasible to understand this situation.Please reply ASAP

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 )

Connecting to %s

%d bloggers like this: