Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make bars in ggplot2 barplot interactive in shiny?

Tags:

r

ggplot2

shiny

I'm plotting a barplot in ggplot2 in a shiny application.

enter image description here

What I would like is that when the mouse hovers over one of the bars, the bar becomes highlighted (maybe by a stronger outline) and when I click (or doubleclick) the bar, the corresponding x-value becomes available to be used as input for a textOutput.

I tried to find examples on the shiny documentation, but there it's mostly about returning x-, y-values from the pointer location. Is there an example I could use as a starting point?

like image 281
TMOTTM Avatar asked Oct 20 '22 05:10

TMOTTM


1 Answers

I had the same question and found this post. I realised the question is quite old, but maybe someone is still interested in a solution.

Challenge:

The problem you are facing is that the ggplot will be rendered as an image: enter image description here

So you dont have seperate html elements you could listen on.

Solution:

But there is one interesting feature in ggplots in shiny. If you add a click listener to the plot, the $x variable of the click event is scaled to the amount of elements in the picture. So if you add an onlick listener the round($click$x) will equal the element being clicked.

See an example here: https://shiny.rstudio.com/articles/plot-interaction-advanced.html

Reproducible example:

I implemented a solution with textbox and highlighting, with the highlighting part coming from Highlight a single "bar" in ggplot.

Solution looks as follows:

enter image description here

Sample data:

letters <- data.frame(
  word = c("First", "Second", "Third"),
  num = c(2, 3, 4),
  stringsAsFactors = FALSE
)

The app:

library(shiny)
library(ggplot2)

ui <- fluidPage(
  fluidRow(
    column(6,
           plotOutput("plot1", click = "plot1_click")
    ),
    column(5,
           uiOutput("text")
    )
  )
)

server <- function(input, output) {
  global <- reactiveValues(toHighlight = rep(FALSE, length(letters$word)), 
    selectedBar = NULL)

  observeEvent(eventExpr = input$plot1_click, {
    global$selectedBar <- letters$word[round(input$plot1_click$x)]
    global$toHighlight <- letters$word %in% global$selectedBar
  })

  output$plot1 <- renderPlot({
    ggplot(data = letters, aes(x = word, y = num, fill = ifelse(global$toHighlight, 
      yes = "yes", no = "no"))) +
      geom_bar(stat="identity") +
      scale_fill_manual(values = c("yes" = "blue", "no" = "grey" ), guide = FALSE )
  })

  output$text <- renderUI({
    req(global$selectedBar)
    textInput(inputId = "label", label = "selected text:", value = global$selectedBar)
  })
}
shinyApp(ui, server)
like image 197
Tonio Liebrand Avatar answered Nov 01 '22 13:11

Tonio Liebrand