Ahh, I see. Unless you can/want to precompute all the data ahead-of-time, this sort of thing is best handled in shiny...plotly provides a plotlyProxy()
function for modifying particular components of graph via plotly.js method. In this case, you'd want to use the extendTraces
method to add data to a line trace.
library(shiny)
library(plotly)
ui <- fluidPage(
plotlyOutput("p")
)
server <- function(input, output, session) {
output$p <- renderPlotly({
plot_ly(x = c(0, 1), y = exp(c(0, -1))) %>%
add_lines()
})
# a reactive value to track the current x value
x <- reactiveVal(1)
# invalidate this R code every 100 milliseconds
observeEvent(invalidateLater(100, session), {
y <- exp(-x())
# update line chart data
plotlyProxy("p", session) %>%
plotlyProxyInvoke(
"extendTraces",
list(
y = list(list(y)),
x = list(list(x()))
),
list(0)
)
# update current x value
x(x() + 1)
}, ignoreNULL = FALSE)
}
shinyApp(ui, server)
You could also do this without shiny if you know a bit of JavaScript and can pre-compute every possible state ahead-of-time:
library(plotly)
library(htmltools)
library(htmlwidgets)
p <- plot_ly() %>%
add_lines(x = c(0, 1), y = exp(-c(0, 1))) %>%
onRender("
function(el) {
Plotly.d3.json('data.json', function(data) {
var i = 0;
setInterval(function() {
var x = data.x[i];
var y = data.y[i];
Plotly.extendTraces(el.id, {x: [[x]], y: [[y]]}, [0])
i = i + 1;
}, 100)
});
}
")
x <- 2:100
y <- exp(-x)
withr::with_path(tempdir(), {
jsonlite::write_json(list(x = x, y = y), "data.json")
saveWidget(p, "index.html")
if (interactive()) servr::httd()
})