Search code examples
rshinydisplayphylogeny

brushPoints RShiny - dsplay the selected tips from a phylogenetic tree


I would like to upload a phylogentic tree via RShiny and use the brushPoints function to allow a user to select the tips of the phylogenetic tree. Ultimately, the tips selected will be used as information to update the tree via annotation. My thought was to display the tips that are selected to confirm the selection but I am unable to generate the verbatiumTextOutput. Suggestions

Below is my attempt:

library(shiny)
library(ggplot2)
library(treeio)
library(ggtree)
library(tidytree) 

tree <- treeio::read.newick("1509MLJF6-1.dnd")

# Define UI for application that draws a histogram
ui <- fluidPage(

  # Application title
  titlePanel("Select Individuals and Display Data"),

  # Show a plot and output table 
  mainPanel(
    plotOutput("treeDisplay", brush = "plot_brush"),
    verbatimTextOutput("selectedIndivs")

  )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  output$treeDisplay <- renderPlot({
    ggplot(tree) + geom_tree() + geom_tiplab()
  })

  output$selectedIndivs <- renderPrint({
    brushedPoints(tree, input$plot_brush)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Upon running the App, the error is: Warning: Error in [: incorrect number of dimensions

and upon selecting individuals the error is: Error in rep: invalid 'times' argument

If needed, the phylogenetic tree is located here:


Solution

  • ape approach

    To get the tips brushed by the user you need to know the x and y coordinates of the internal and terminal nodes on the plot. You can get these using the ape package. Then, once you have the coordinates of the brushed area, you can subset the phylo coordinate table to only the brushed tips. In the example below we have to explicitly tell brushedPoints where to look for the x and y coordinates (xvar and yvar columns in the data frame). Depending on the number of species on the tree, you might need to expand the plotting area to avoid overlap, so that species can be brushed over easily.


    Code:

    library(shiny)
    library(ape)
    
    Tree <- rtree(n=20)
    Tree <- ladderize(Tree)
    
    ui <- basicPage(
      plotOutput("plot1", brush = "plot_brush"),
      tableOutput("brushed_subtree")
    )
    
    server <- function(input, output) {
    
      output$plot1 <- renderPlot({
        plot(Tree)
      })
    
      getTreeInfo <- reactive({
        plot(Tree)
        plotinfo <- get("last_plot.phylo", envir = .PlotPhyloEnv)
        tips_xy <- data.frame(Tip=Tree$tip.label, 
                              xvar=plotinfo$xx[1:Ntip(Tree)], 
                              yvar=plotinfo$yy[1:Ntip(Tree)])
        return(tips_xy)
      })
    
      # render selected tips table 
      output$brushed_subtree <- renderTable({
        brushedPoints(getTreeInfo(), input$plot_brush, xvar = "xvar", yvar = "yvar")
      })
    
    }
    
    shinyApp(ui, server)
    

    Gif: enter image description here


    ggtree approach

    The ggtree approach is easier. In fact, you were close already, except instead of passing your tree to brushedPoints you need to supply the $data component of the ggtree plot. Note that in this case the brushed area has to include the terminal branch of the wanted tip, because the coordinates of the plot are given by the edge data frame, and the tips are a separate geom plotted relative to the previously plotted (terminal) edges.


    Code

    library(shiny)
    library(ggplot2)
    library(treeio)
    library(ggtree)
    library(tidytree) 
    
    tree <- treeio::read.newick("1509MLJF6-1.dnd")
    treedt <- as.treedata(tree)
    
    # Define UI for application that draws a histogram
    ui <- fluidPage(
    
      # Application title
      titlePanel("Select Individuals and Display Data"),
    
      # Show a plot and output table 
      mainPanel(
        plotOutput("treeDisplay", brush = "plot_brush"),
        verbatimTextOutput("selectedIndivs")
    
      )
    )
    
    # Define server logic required to draw a histogram
    server <- function(input, output) {
    
      make_tree <- reactive({
         ggplot(tree) + geom_tree() + geom_tiplab()
      })
    
      output$treeDisplay <- renderPlot({
        make_tree()
      })
    
      output$selectedIndivs <- renderPrint({
        brushedPoints(make_tree()$data, input$plot_brush)
      })
    }
    
    # Run the application 
    shinyApp(ui = ui, server = server)
    

    Gif:

    enter image description here