shiny.Rmd
sigmajs
goes hand in hand with Shiny. As stated in the wiki, sigma.js is “interactivity oriented” and therefore plays ideally in apps.
Another good example of the package in the wild is chirp.sh.
simgajs
lets you dynamically interact with the graph, that is, add/remove/customise without redrawing the whole graph: these functions all end in _p
. The package also lets you catch how the user interacts with your graph.
Here I mainly talk you through shiny proxies in general and the add-nodes
demo.
Let’s start by building a simple Shiny app that includes a basic sigmajs
graph.
library(shiny)
library(sigmajs)
nodes <- sg_make_nodes()
edges <- sg_make_edges(nodes)
ui <- fluidPage(sigmajsOutput("sg")) # bare bone UI
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color) %>%
sg_edges(edges, id, source, target)
})
}
shinyApp(ui, server) # run
Now that we have a simple app going we can look at playing with proxies. The layout looks a bit rubbish, we can add a proxy to let the user trigger the forceAtlas2 layout.
nodes <- sg_make_nodes()
edges <- sg_make_edges(nodes)
ui <- fluidPage(
actionButton("start", "Trigger layout"), # add the button
sigmajsOutput("sg")
)
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color) %>%
sg_edges(edges, id, source, target)
})
observeEvent(input$start, {
sigmajsProxy("sg") %>% # use sigmajsProxy!
sg_force_start_p() # app the proxy (_p)
})
}
shinyApp(ui, server) # run
So proxies work on a already existing graphs so you simply have to use the sigmajsProxy
function to catch that graph using its id
; output graph’s id is sg
(sigmajsOutput("sg")
). Then you can pass your proxies _p
.
We could, for instance, now add another button to kill the layout because as it is now the layout is constantly running which is a bit draining for the browser and not very useful.
nodes <- sg_make_nodes()
edges <- sg_make_edges(nodes)
ui <- fluidPage(
actionButton("start", "Start layout"), # start button
actionButton("stop", "Stop layout"), # stop button
sigmajsOutput("sg")
)
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color) %>%
sg_edges(edges, id, source, target)
})
# start layout
observeEvent(input$start, {
sigmajsProxy("sg") %>%
sg_force_start_p()
})
# stop layout
observeEvent(input$stop, {
sigmajsProxy("sg") %>%
sg_force_stop_p()
})
}
shinyApp(ui, server) # run
Now that you are familiar with proxies we can look at the more powerful ones; though you will see, you can use them just as easily! For that we’ll scrap the previous buttons and go back to the basic shiny app we initially set up.
Let’s put a button that lets the user add nodes to the graph. For this example we’ll only plot nodes, no edges.
library(shiny)
library(sigmajs)
# initial nodes
nodes <- sg_make_nodes()
# nodes to add on click
nodes2add <- sg_make_nodes()
nodes2add$id <- 11:20 # ids must be unique
ui <- fluidPage(
actionButton("add", "Add nodes"),
sigmajsOutput("sg")
)
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color)
})
observeEvent(input$add, {
sigmajsProxy("sg") %>%
sg_add_nodes_p(nodes2add, id, size, color)
})
}
shinyApp(ui, server) # run
This is a simplified version of the demo("add-nodes", package = "sigmajs")
It’s fairly simple when you look at it.
id
as the already existing nodes.sg_add_nodes_p
which acutally works just like sg_nodes
.Another great thing the package lets you do is capture how the user interact with your app. Then again there is a demo for the latter: custom-events
.
All the events are integrated in the package. In version 0.1.3
and prior all events are sent to the server by default, from 0.1.4
(currently dev version) onwards users have to specify which event they want to capture with sg_events
.
Let’s take the basic app we built at the begining of the proxies walkthrough and catch which node the user clicks on.
library(shiny)
library(sigmajs)
nodes <- sg_make_nodes()
edges <- sg_make_edges(nodes)
ui <- fluidPage(
sigmajsOutput("sg"),
p("Click on a node"),
verbatimTextOutput("clicked")
)
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color) %>%
sg_edges(edges, id, source, target) %>%
sg_events("clickNode")
})
# capture node clicked
output$clicked <- renderPrint({
input$sg_click_node
})
}
shinyApp(ui, server) # run
Easy! Just use your plot as an input
that points to the graph id (sg
) followed by _
and the name of the event you want to catch; in our case, plot of id (sg
) and capture node clicked = input$sg_click_node
. There are many more events to pick up, see the official documentation for the full list.
Now that you are familiar with proxies, we can add a filter to filter nodes, edges or both.
sg_filter_gt_p
- filter greater than \(x\)
sg_filter_lt_p
- filter less than \(x\)
sg_filter_eq_p
- filter equal to \(x\)
sg_filter_not_eq_p
- filter not equal to \(x\)
sg_filter_undo_p
- undo filtersg_filter_neighbours_p
- to filter neighbours of node \(x\)
Let’s take our basic Shiny app and add our filter. Note that we pass a name to the filter, this allows referencing the filter in sg_filter_undo_p
function. Every time the user moves the slider the filter is actually undone and re-applied.
nodes <- sg_make_nodes()
edges <- sg_make_edges(nodes)
ui <- fluidPage(
sliderInput(
"filter",
"Filter nodes",
value = 0,
min = 0,
max = 5
),
sigmajsOutput("sg")
)
server <- function(input, output){
output$sg <- renderSigmajs({
sigmajs() %>%
sg_nodes(nodes, id, size, color) %>%
sg_edges(edges, id, source, target)
})
observeEvent(input$filter, {
sigmajsProxy("sg") %>%
sg_filter_undo_p("sz") %>% # we undo the filter before applying it
sg_filter_gt_p(input$filter, "size", name = "sz")
})
}
shinyApp(ui, server) # run