3
votes

I have an R shiny page, and am filtering the data based on clicking a pie graph. It would be great if I could trigger the same filtering event from clicking legend entries, but I can't seem to find the event trigger, so it just filters that chart without propagating to the other charts. Is a legend click event accessible?

library(data.table)
library(plotly)
library(shiny)

dt = as.data.table(mtcars)


ui <- fluidPage(
  plotlyOutput("pie1"),
  plotlyOutput("pie2")
)


server <- function(input, output){

  gearDT = reactive({
    return(dt[,.N,by=gear])
  })

  cylDT = reactive({
    return(dt[,.N,by=cyl])
  })

  output$pie1 <- renderPlotly({

    plot_ly(gearDT(), labels = ~gear, values = ~N, type = "pie") %>%
      layout(showlegend = TRUE)


  })

  output$pie2 <- renderPlotly({

    plot_ly(cylDT(), labels = ~cyl, values = ~N, type = "pie")  %>%
      layout(showlegend = TRUE)


  })
}

shinyApp(ui = ui, server = server)
3
Could you please prepare a minimal reproducible example? If you illustrate your problem more completely and demonstrate the steps you've taken so far, then you are likely to receive more productive answersKevin Arseneau
@KevinArseneau Thanks for the advice Kevin, I've attached an example, you may have already answered my question though.Matt

3 Answers

5
votes

For future readers

Plotly now has created an event called plotly_relayout. This event is triggered on layout changes. Clicking on the legend is one of these changes.

One of the variables in this event is called hiddenlabels. This variable contains all the names of the legend traces that are hidden.

observe({
    relayout <- event_data("plotly_relayout")
    hidden_labels <- relayout$hiddenlabels
    print(hidden_labels)
  })

EDIT

Check event when clicking a name in the legend of a plotly's graph in R Shiny if plotly_relayout is not working for you.

2
votes

Short answer is YES, but with caveats and it will take more work to implement than I will fully cover in my answer.

The plotly package includes the event_data function. In the documentation, you will find three events covered:

  1. plotly_hover
  2. plotly_click
  3. plotly_selected

The examples for using these are in the link above. They do not cover interaction with the legend specifically, rather the data in the plot proper.

However, there is the postMessage API provided by plotly, which is what shiny and other frameworks like jupyter use to capture events. I have not gone through the documentation to highlight the events relating to the legend. This would require some javascript, which you could access in R using shinyjs.

The effort may be more than you are willing to put in to achieve this directly. If it is not essential for you to go down this path then I believe you will get a better return on your time using the shiny input and reactive functions to filter and redraw.

edit with your updated example

Your edit to the question reveals a little more to your problem. Although it is not reproducible, manuf is not a colname to mtcars (I'm assuming you assigned that name to the rownames). If your legend is shared between plots, you could use a subplot grouped legend as shown in the documentation.

further revision

Pie charts behave a little strangely in subplots, see this and the docs. The following code gives you a minimal reproducible solution.

dt <- as.data.table(mtcars)

ui <- fluidPage(plotlyOutput("pie"))

server <- function(input, output){

  gearDT <- reactive({return(dt[,.N,by=gear])})  
  cylDT <- reactive({return(dt[,.N,by=cyl])})

  output$pie <- renderPlotly({

    plot_ly() %>%
      add_pie(data = gearDT(), labels = ~gear, values = ~N, name = "gear",
              domain = list(x = c(0, 0.5), y = c(0, 1))) %>%
      add_pie(data = cylDT(), labels = ~cyl, values = ~N, name = "cyl",
              domain = list(x = c(0.5, 1), y = c(0, 1))) %>%
      layout(showlegend = TRUE,
             xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
             yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

  })

}

shinyApp(ui = ui, server = server)

And screenshot showing a common element filtered from both traces (4).

enter image description here

While your original question involved shiny and I incorporated that in my answer. The plotly chart is independent of this and would function perfectly well as an independent widget with the same functionality. Useful perhaps if you intended this in an rmarkdown document and otherwise don't need to depend on shiny.

0
votes
library(dygraphs)
library(datasets)



ui <- shinyUI(fluidPage(

    mainPanel(
      dygraphOutput("dygraph"),dygraphOutput("dygraph1"),dygraphOutput("dygraph2")
    )
  )
)

server <- shinyServer(function(input, output) {


  output$dygraph <- renderDygraph({
    dygraph(ldeaths, main = "All", group = "lung-deaths")
  })
  output$dygraph1 <- renderDygraph({
    dygraph(mdeaths, main = "Male", group = "lung-deaths")
  })
  output$dygraph2 <- renderDygraph({
    dygraph(fdeaths, main = "Female", group = "lung-deaths")
  })
})

shinyApp(ui = ui, server = server)