Search code examples
rshinynetworkd3chord

Chord network in Shiny overlaying itself


I am rendering a chord network in a Shiny app. What I would like to do is provide two different representations of the network. One based on who is influenced by whom, the other based on who influences whom. In a nutshell what I am representing is a dataset in one version, and the transpose of that dataset in another version.

My problem is that when I render the network and toggle the input, the new version of the plot is simply laid over the old version of the plot. I need to somehow erase the previous plot before displaying the next plot.

This minimal example shows the default presentation:

Influenced

This is what happens when I choose to plot the transposed data (i.e. I change the dataset)

Influences

If I switch back to the original choice, it simply overlays again.

I am sure there is a simple answer to this problem, I just haven't been able to google the right words.

Minimal reproducible code below

library(shiny)
library(networkD3)

Data <- matrix(c(NA,  1951,  8010, 1013,
               5871, NA, 16145,  990,
               8916,  2060,  NA,  940,
               2868,  6171,  8045, NA), nrow = 4)

ui <- fluidPage(

    titlePanel("Chord network"),

    mainPanel(   htmlOutput("inputDataChoice"),
                 chordNetworkOutput(outputId = "chord_network", width = "600px", height = "600px")
             )
             
    )


server <- function(input, output) {
    
    #Choose the data type
    output$inputDataChoice <- renderUI({
        selectInput(inputId = "dataChoice", label = "Choose data shape",
                    choices=c("Influenced", "Influences"),
                    width = "450px"
        )})

    #Dataset shape based on choice
    chordData <- reactive({
        switch(input$dataChoice,
               "Influenced" = Data,
               "Influences" = t(Data))
    })

    #Plot
    observe ({
        output$chord_network <- renderchordNetwork({


            chordNetwork(chordData(),
                         padding = 0.1,
                         colourScale = c("#000000",
                                         "#FFDD89",
                                         "#957244",
                                         "#F26223"),
                         labels = c("Bob", "Brenda", "Barry", "Belinda"))

    })})
}

shinyApp(ui = ui, server = server)



Solution

  • Interesting bug! It looks like the issue is actually in the package being used. I'm surprised this bug hasn't been reported, I guess people are not using is much on shiny?!

    I fixed the bug by clearing the canvas before rendering the widget. I'm not a d3 expert but I think this can be fixed in the package chordNetwork.js by using data().enter() instead of datum() but unfortunately I couldn't get this working.

    Instead, it's fixed by inserting the following line of code before we render any plot.

    d3.select(el).select("g").selectAll("g").remove() //Create a blank canvas
    

    You can access this fixed package in my forked repository here,https://github.com/sada1993/networkD3. Use devtools::install_github("sada1993/networkD3") to install the package.

    Perhaps we could add a PR for this fix? But it looks like the package is no longer under development.

    Here is the diff to see the changes: https://github.com/christophergandrud/networkD3/compare/master...sada1993:master