I have a shiny dashboard with multiple tabs that are logically linked, so I've created a DiagrammeR diagram using GraphViz to show how they relate. I want to be able to trigger a change to a new tab when a click event is registered on one of the nodes in the GraphViz Diagram.
The diagram will be at the top of each tab, so there are multiple diagrams that need to be clickable.
I have got most of it working as shown in this reprex:
library(shinydashboard)
library(DiagrammeR)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "DiagrammeR buttons"),
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Tab 1", tabName = "one", icon = icon("dice-one")),
menuItem("Tab 2", tabName = "two", icon = icon("dice-two"))
)
),
dashboardBody(
useShinyjs(),
tabItems(
tabItem(tabName = "one",
fluidRow(box(grVizOutput("diagram_a", width = "100%", height = "100%"), width = 12))
),
tabItem(tabName = "two",
fluidRow(box(grVizOutput("diagram_b", width = "100%", height = "100%"), width = 12))
)
)
)
)
server <- function(input, output, session) {
output$diagram_a <- renderGrViz({grViz("digraph {
graph[rankdir = LR]
node [style = filled]
n1_1 -> n1_2
}")})
output$diagram_b <- renderGrViz({grViz("digraph {
graph[rankdir = LR]
node [style = filled]
n2_1 -> n2_2
}")})
observeEvent(eventExpr = input$clickednode, {
updateTabItems(session, "tabs", input$clickednode)
})
observe({
local({
clicked = "Shiny.onInputChange('clickednode', 'one')"
shinyjs::onclick("node1",runjs(clicked))
})
local({
clicked = "Shiny.onInputChange('clickednode', 'two')"
shinyjs::onclick("node2",runjs(clicked))
})
})
}
shinyApp(ui, server)
The only problem is that only the first graph in the dashboard registers click events. The second tab in this example is just a static diagram that can't be interacted with.
I need some help making sure I refer to the specific node1
and node2
that I am interested in, rather than just the first node1
or node2
that appears in the dashboard. I'm not sure how to do that in JavaScript.
Note: nodeX
where X
is a numeral is the id that shiny automatically gives to the nodes in every graphViz diagram. This can be found by inspecting the dashboard html.
n1_1
and n2_1
for each plot, the default IDs are always node1
, node2
, node3
... You need to manually change it.setInputValue
instead of onInputChange
.Following is how you can set unique IDs for each node in GraphViz. Take a look at GraphViz grammar will be helpful.
library(shinydashboard)
library(DiagrammeR)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "DiagrammeR buttons"),
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Tab 1", tabName = "one", icon = icon("dice-one")),
menuItem("Tab 2", tabName = "two", icon = icon("dice-two"))
)
),
dashboardBody(
useShinyjs(),
tabItems(
tabItem(tabName = "one",
fluidRow(box(grVizOutput("diagram_a", width = "100%", height = "100%"), width = 12))
),
tabItem(tabName = "two",
fluidRow(box(grVizOutput("diagram_b", width = "100%", height = "100%"), width = 12))
)
)
)
)
server <- function(input, output, session) {
output$diagram_a <- renderGrViz({grViz('digraph {
graph[rankdir = LR]
node [style = filled]
n1_1 -> n1_2
n1_1[id="d1_n1"]
n1_2[id="d1_n2"]
}')})
output$diagram_b <- renderGrViz({grViz('digraph {
graph[rankdir = LR]
node [style = filled]
n2_1 -> n2_2
n2_1[id="d2_n1"]
n2_2[id="d2_n2"]
}')})
observeEvent(input$clickednode, {
updateTabItems(session, "tabs", input$clickednode)
})
observe({
local({
clicked = "Shiny.setInputValue('clickednode', 'one')"
shinyjs::onclick("d1_n1",runjs(clicked))
shinyjs::onclick("d2_n1",runjs(clicked))
})
local({
clicked = "Shiny.setInputValue('clickednode', 'two')"
shinyjs::onclick("d1_n2",runjs(clicked))
shinyjs::onclick("d2_n2",runjs(clicked))
})
})
}
shinyApp(ui, server)