Using Proxy Interface in Plotly/Shiny to dynamically change data
Strangely enough addTraces
does not work with only one point but works with two points. To make it work you could add the same point twice. So you could try this:
ui <- fluidPage(
actionButton("update", "Test"),
plotlyOutput("graphe")
)
server <- function(input, output, session) {
output$graphe <- renderPlotly({
p <- plot_ly(type="scatter",mode="markers")
p <- layout(p,title="test")
p <- add_trace(p, x=0,y=0,name="ABC_test",mode="lines+markers")
})
observeEvent(input$update, {
plotlyProxy("graphe", session) %>%
plotlyProxyInvoke("deleteTraces", list(as.integer(1))) %>%
plotlyProxyInvoke("addTraces", list(x=c(0, 0),y=c(1, 1),
type = 'scatter',
mode = 'markers'))
})
}
shinyApp(ui, server)
How to dynamically add AND remove overlay from plotly histogram in shiny
Edit: @FreyGeospatial clarified, that he wants to add/remove traces (I was confused of the wording using overlay
).
The easiest way to dynamically add and remove traces is to create a data.frame in long format providing a category column.
In plot_ly
you can use split
or color
to create traces based on this column.
To remove traces you can filter categories from a reactive dataset and re-render the plot:
library(shiny)
library(plotly)
DF <- data.frame(values = rnorm(2500), category = rep(LETTERS[1:5], each = 500))
ui <- fluidPage(
selectizeInput(inputId = "barmode",
label = "barmode",
choices = c("group", "overlay", "stack"),
selected = "overlay"),
selectizeInput(inputId = "category",
label = "category",
choices = unique(DF$category), selected = LETTERS[1:3], multiple = TRUE),
plotlyOutput("myPlot")
)
server <- function(input, output, session) {
filteredDF <- reactive({
DF[DF$category %in% input$category,]
})
output$myPlot <- renderPlotly({
fig <- plot_ly(data = filteredDF(), x = ~ values, split = ~ category, alpha = 0.6, type = "histogram")
fig <- fig %>% layout(barmode = input$barmode)
fig
})
}
shinyApp(ui, server)
As an alternative to re-rendering the plot you could use plotlyProxy and the addTraces JS function please see my answer here. This is faster than re-rendering but less intutive using plotly's R API.
Please run:
install.packages("listviewer")
schema()
and navigate:
object ► traces ► bar ► layoutAttributes ► barmode
To find the barmode description:
default: group
Determines how bars at the same location coordinate are displayed on
the graph. With stack, the bars are stacked on top of one another
With relative, the bars are stacked on top of one another, with
negative values below the axis, positive values above With group,
the bars are plotted next to one another centered around the shared
location. With overlay, the bars are plotted over one another, you
might need to an opacity to see multiple bars.
Update plotly data (chloropleth) in R shiny without re-rendering entire map
For anyone else who comes across this post later, I found a solution.
It turns out that you can change data using the restyle method in plotlyProxyInvoke, as shown below.
library(shiny)
library(dplyr)
library(plotly)
library(readr)
library(rjson)
zip_geojson <- fromJSON(file="https://raw.githubusercontent.com/hms1/testData/main/zip3_2.json")
plot_data <- read_csv(file="https://raw.githubusercontent.com/hms1/testData/main/plot_data.csv")
mapboxToken <- "pk.eyJ1IjoiaG1vcmdhbnN0ZXdhcnQiLCJhIjoiY2tmaTg5NDljMDBwbDMwcDd2OHV6cnd5dCJ9.8eLR4FtlO079Gq0NeSNoeg"
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("multip",
"n:",
min = 1,
max = 10,
value = 1),
actionButton("Remove", "Remove Trace")
),
mainPanel(
plotlyOutput("cPlot")
)
)
)
server <- function(input, output, session) {
output$cPlot <- renderPlotly({
plot_ly(type = "choroplethmapbox", geojson = zip_geojson) %>%
layout(
mapbox = list(
style = "light",
zoom = 3,
center = list(lon = -95.7129, lat = 37.0902)
)
) %>%
config(mapboxAccessToken = mapboxToken)
})
plotproxy <- plotlyProxy("cPlot", session, deferUntilFlush = FALSE)
observeEvent(input$multip, {
plot_data_i <- plot_data %>%
mutate(log_count = case_when(log_count <= input$multip ~ log_count * input$multip,
TRUE ~ log_count))
plotproxy %>%
plotlyProxyInvoke("restyle", list(z = list(plot_data_i$log_count),
locations = list(plot_data_i$zip)))
})
}
shinyApp(ui = ui, server = server)
How to add a new trace while removing the last one?
Based on what you described, it sounds like you want to add a trace and remove the most recent trace added at the same time when the button is pressed. This would still leave the original plot/trace that you started with.
I tried simplifying a bit. The first plotlyProxyInvoke
will remove the most recently added trace (it is zero-indexed, leaving the first plotly trace in place).
The second plotlyProxyInvoke
will add the new trace. Note that the (x, y) pair is included twice based on this answer.
library(shiny)
library(plotly)
A <- 1:5
B <- c(115, 406, 1320, 179, 440)
data <- data.frame(A, B)
ui <- fluidPage(plotlyOutput("fig1"),
numericInput("A",
label = h5("A"),
value = "",
width = "100px"),
numericInput("B",
label = h5("B"),
value = "",
width = "100px"),
actionButton("action3", label = "Add to plot"),
)
server <- function(input, output, session) {
fig <- plot_ly(data, x = A, y = B, type = 'scatter', mode = 'markers')
output$fig1 <- renderPlotly(fig)
observeEvent(input$action3, {
plotlyProxy("fig1", session) %>%
plotlyProxyInvoke("deleteTraces", list(as.integer(1)))
plotlyProxy("fig1", session) %>%
plotlyProxyInvoke("addTraces",
list(x = c(input$A, input$A),
y = c(input$B, input$B),
type = 'scatter',
mode = 'markers')
)
})
}
shinyApp(ui,server)
Shiny app to show simulation: how to re-write using plotly
For efficient changes to a plotly object you should take a look at plotlyProxy, which avoids re-rendering the entire plot. Here are some streaming examples.
Here is what I think you are after - btw. you sould avoid calling your reactiveValues
"session", because session
is an optional argument to the server
function (which is needed for plotlyProxy
).
library(shiny)
library(plotly)
ui <- fluidPage(titlePanel('1D Brownian Motion'),
sidebarLayout(
# panel with all inputs
sidebarPanel(
# param set-up
numericInput('mean', 'mean', 0, step = 1),
numericInput('sd', 'sd', 1, step = 0.5, min = 0.0001),
# buttons to start, stop, reset
fluidRow(
column(3, actionButton('go', 'Go')),
column(3, actionButton('stop', 'Stop')),
column(3, actionButton('reset', label = 'Reset'))
)
),
# plot panel
mainPanel(
plotlyOutput('bmtrack', height = '250px'),
plotlyOutput('bmmax', height = '250px')
)
))
server <- function(input, output, session) {
# reactive to store all reactive variables
waits <- reactiveValues(x = 0, xmax = 0, tt = 0, timer = reactiveTimer(Inf))
# function to move simulation forward
forward <- function() {
waits$x <- waits$x + rnorm(1, input$mean, input$sd)
waits$xmax <- max(waits$xmax, waits$x)
waits$tt <- waits$tt + 1
}
# when go button is pressed
observeEvent(input$go, {
waits$timer <- reactiveTimer(100)
observeEvent(waits$timer(), {
forward()
})
})
# when stop button is pressed
observeEvent(input$stop, {
waits$timer <- reactiveTimer(Inf)
})
# when reset button is pressed
observeEvent(input$reset,{
waits$x <- 0
waits$xmax <- 0
waits$tt <- 0
})
# generate initial "empty" plot
initial_plot <- plot_ly(
x = 0,
y = 0,
type = 'scatter',
mode = 'lines',
line = list(color = '#000000',
width = 3)
)
# render initial plot and assign to both outputs
output$bmmax <- output$bmtrack <- renderPlotly({
input$reset # rerender when reset is pressed
initial_plot
})
# create plotlyProxy objects for both plotly outputs
bmtrack_proxy <- plotlyProxy("bmtrack", session)
bmmax_proxy <- plotlyProxy("bmmax", session)
# manipulate plots via plotlyProxy objects (without rerendering)
observe({
plotlyProxyInvoke(bmtrack_proxy, "extendTraces", list(x = list(list(waits$tt)), y = list(list(waits$x))), list(0))
})
observe({
plotlyProxyInvoke(bmmax_proxy, "extendTraces", list(x = list(list(waits$tt)), y = list(list(waits$xmax))), list(0))
})
}
shinyApp(ui, server)
Related Topics
Extract Last Non-Missing Value in Row with Data.Table
Repeat the Re-Sampling Function for 1000 Times? Using Lapply
R Ggplot Ordering Bars in "Barplot-Like " Plot
Why Does Mapply Not Return Date-Objects
R Group By, Counting Non-Na Values
In R, How to Plot into a Memory Buffer Instead of a File
Fastest Way to Sort Each Row of a Large Matrix in R
Are Data Tables with More Than 2^31 Rows Supported in R with the Data Table Package Yet
3D Equivalent of the Curve Function in R
Change the Order of Stacked Fill Columns in Ggplot2
Find Most Frequent Combination of Values in a Data.Frame
Combine Multiple PDF Plots into One File
How to Calculate Total Least Squares in R? (Orthogonal Regression)
Warning "The Condition Has Length > 1 and Only the First Element Will Be Used"