Search code examples
rplotchord-diagram

R Circular Chord Plots


Im learning how to create circular plots in R, similiar to CIRCOS Im using the package circlize to draw links between origin and destination pairs based on if the flight was OB, Inbound and Return. The logic fo the data doesnt really matter, its just a toy example

I have gotten the plot to work based on the code below which works based on the following logic

  1. Take my data, combine destination column with the flight type
  2. Convert to a matrix and feed the origin and the new column into circlize

Reference

library(dplyr)
library(circlize)

# Create Fake Flight Information in a table
orig = c("IE","GB","US","ES","FI","US","IE","IE","GB")
dest = c("FI","FI","ES","ES","US","US","FI","US","IE")
direc = c("IB","OB","RETURN","DOM","OB","DOM","IB","RETURN","IB")
mydf = data.frame(orig, dest, direc)

# Add a column that combines the dest and direction together
mydf <- mydf %>%
  mutate(key = paste(dest,direc)) %>%
  select (orig, key)

# Create a Binary Matrix Based on mydf
mymat <- data.matrix(as.data.frame.matrix(table(mydf)))

# create the objects you want to link from to in your diagram
from <- rownames(mymat)
to <- colnames(mymat)

# Create Diagram by suppling the matrix 
par(mar = c(1, 1, 1, 1))
chordDiagram(mymat, order = sort(union(from, to)), directional = TRUE)
circos.clear()

I like the plot a lot but would like to change it a little bit. For example FI (which is Finland) has 3 measurements on the diagram FI IB, FI OB and FI. I would like to combine them all under FI if possible and distinguish between the three Types of flights using either a colour scheme, Arrows or even adding an additional track which acts as an umbrella for IB OB and RETURN flights

So for Example,

  • FI OB would be placed in FI but have a one way arrow to GB to signify OB
  • FI IB would be placed in FI but have a one way arrow into FI
  • FI RETURN (if it exists) would have a double headed arrow

Can anyone help, Has anyone seen anything similiar been done before? The end result should just have the countries on the plot once so that someone can see very quickly which countries have the most amount of flights

I have tried following other posts but am afraid im getting lost when they move to the more advanced stuff

Thank you very much for your time


Solution

  • First, I think there is a duplicated record (IE-FI-IB) in your data.

    I will first attach the code and figure and then explain a little bit.

    df = data.frame(orig, dest, direc, stringsAsFactors = FALSE)
    df = unique(df)
    col = c("IB" = "red",
            "OB" = "blue",
            "RETURN" = "orange",
            "DOM" = "green")
    directional = c("IB" = -1,
                    "OB" = 1,
                    "RETURN" = 2,
                    "DOM" = 0)
    diffHeight = c("IB" = -0.04,
                    "OB" = 0.04,
                    "RETURN" = 0,
                    "DOM" = 0)
    chordDiagram(df[1:2], col = col[df[[3]]], directional = directional[df[[3]]], 
        direction.type = c("arrows+diffHeight"),
        diffHeight = diffHeight[df[[3]]])
    
    legend("bottomleft", pch = 15, legend = names(col), col = col)
    

    enter image description here

    First you need to use the development version of circlize for which you can install it by

    devtools::install_github("jokergoo/circlize")
    

    In this new version, chordDiagram() supports input variable as a data frame and drawing two-head arrows for the links (just after reading your post :)).

    In above code, col, directional, direction.type and diffHeight can all be set as a vector which corresponds to rows in df.

    When directional argument in chordDiagram() is set to 2, the corresponding link will have two directions. Then if direction.type contains arrows, there will be a two-head arrow.

    Since diffHeight is a vector which correspond to rows in df, if you want to visualize the direction for a single link both by arrow and offset of the roots, you need to merge these two options as a single string as shown in the example code "arrows+diffHeight".

    By default direction for links are from the first column to the second column. But in your case, IB means the reversed direction, so we need to set diffHeight to a negative value to reverse the default direction.

    Finally, I observe you have links which start and end in a same sector (ES-ES-DOM and US-US-DOM), you can use self.link argument to control how to represent such self-link. self.link is set to 1 in following figure.

    enter image description here