In the reproducible code below plot 1 looks fine in terms of its width/height, but I'd like to expand plot 2 in terms of its height so the subplots don't seem so "squished" together. Does anyone have a suggestion on how to do that so it stays nicely within the card but expands responsively with the number of subplots? In this example, there are five subplots, but that could be any number (usually 2 to 7 or so).
library(shiny)
library(bslib)
library(shinyWidgets)
library(plotly)
card <- function(body, title) {
div(class = "card",
div(icon("chart-line", style = "color:white"), class = "card-header bg-success text-white text-center font-weight-bold", title),
div(class = "card-body d-flex justify-content-center", body)
)
}
ui <- fluidPage(
navbarPage(
theme = bs_theme(bootswatch = "flatly", version = 4),
title = 'Methods',
tabPanel('One'),
),
mainPanel(
h1('Hello World'),
uiOutput('p1'),
br(),
uiOutput('p2'),
)
)
server <- function(input, output) {
output$p1 <- renderUI({
fig <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
card(fig, 'Plot 1: Looks Good')
})
### I could do this
output$p2 <- renderUI({
vars <- setdiff(names(economics), "date")
plots <- lapply(vars, function(var) {
plot_ly(economics, x = ~date, y = as.formula(paste0("~", var))) %>%
add_lines(name = var)
})
card(subplot(plots, nrows = length(plots), shareX = TRUE, titleX = FALSE), 'Plot 2: Too Squished')
})
}
shinyApp(ui, server)
We can use plotlyOutput and pass a height parameter corresponding to the number of subplots:
library(shiny)
library(bslib)
library(shinyWidgets)
library(plotly)
card <- function(body, title) {
div(class = "card",
div(icon("chart-line", style = "color:white"), class = "card-header bg-success text-white text-center font-weight-bold", title),
div(class = "card-body d-flex justify-content-center", body)
)
}
ui <- fluidPage(
navbarPage(
theme = bs_theme(bootswatch = "flatly", version = 4),
title = 'Methods',
tabPanel('One'),
),
mainPanel(
h1('Hello World'),
uiOutput('p1'),
br(),
uiOutput('p2'),
)
)
server <- function(input, output) {
output$p1 <- renderUI({
fig <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
card(fig, 'Plot 1: Looks Good')
})
output$plotlyOut <- renderPlotly({
vars <- setdiff(names(economics), "date")
plots <- lapply(vars, function(var) {
plot_ly(economics, x = ~date, y = as.formula(paste0("~", var))) %>%
add_lines(name = var)
})
subplot(plots, nrows = length(plots), shareX = TRUE, titleX = FALSE)
})
output$p2 <- renderUI({
nSubplots <- length(setdiff(names(economics), "date"))
card(plotlyOutput("plotlyOut", height = paste0(nSubplots*200, "px")), 'Plot 2: Looks Good?')
})
}
shinyApp(ui, server)
Related
I'm having a problem with ggplotly objects simply not staying inside boxes with shiny and shinydashboard. Before something is plotted, everything is right. But when a plot is displayed, the box doubles its size and the plot stays on top.
It happens only with ggplotly. A common ggplot works fine.
I've made it reproducible with the iris dataset below.
ui.R
dashboardPage(dashboardHeader(title = "Title"),
dashboardSidebar(
sidebarMenu(
menuItem("Species Overview",
tabName = "species"),
menuItem(
pickerInput(
inputId = "species",
choices = species,
multiple = TRUE)))),
dashboardBody(
tabItems(
tabItem(tabName = "species",
fluidRow(
box(
title = "Plot1",
#width = 6,
id = "plot1",
plotlyOutput(
"plot1", width = "100%") ## box 1 with ggplotly object
),
box(
title = "Plot2",
id = "plot2",
#width = 6,
plotOutput(
"plot2", width = "100%") ## box 2 with ggplot object
))))))
server.R
shinyServer(function(input, output) {
v <- reactiveValues()
observe({
v$species <- input$species
})
species_selected <- reactive({
validate(
need(length(v$species) > 0, "Please select a species")
)
select_species(iris, v$species)})
plot1 = reactive({
plot_1(species_selected())
})
plot2 = reactive({
plot_2(species_selected())
})
output$plot1 = renderPlotly({
plot1() |> ggplotly() ##ggplot object
})
output$plot2 = renderPlot({
plot2() #ggplot object
})})
global.R
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(ggplot2)
library(tidyverse)
#library(bs4Dash)
data(iris)
species = iris$Species |> unique() |> as.character()
select_species = function(df, species) {
df = df |>
filter(Species %in% species)
return(df)
}
plot_1 = function(df) {
df = df
p = df |>
ggplot(aes(x = Petal.Width, y = Petal.Length, color = Species)) +
geom_point()
return(p)
}
plot_2 = function(df) {
p = df |>
ggplot(aes(x = Sepal.Width, y = Sepal.Length, color = Species)) +
geom_point()
return(p)
}
And this is what happens:
I'm open to any suggestions. I've tried bs4dash, shinydashboard, shinydashboardPlus. Packages are all up to date.
You can specify the height of the box and display the plotly object as shown below.
box(
title = "Plot1",
#width = 6,
height = 460,
id = "plot1",
plotlyOutput(
"plot1", width = "100%", height="400px") ## box 1 with ggplotly object
),
I have a Shiny app that builds a scatterplot and highlights the clicked points by restyling the marker outline via plotlyProxy.
The app also subsets the data and moves the entries corresponding to the clicked points from the original "Data table" to an "Outlier table".
This seems to work fine when the markers are all the same color, or when they are colored by a continuous variable. But when I color the points by a categorical variable (like "Species"), it has a weird behavior, restyling a marker from each category instead of the clicked one. The data subsets correctly.
I think the restyle function should update all traces unless specified otherwise, so I am not sure where exactly lies the problem.
Here is my code:
library(plotly)
library(DT)
ui <- fluidPage(
mainPanel(
fluidRow(
div(
column(
width = 2,
uiOutput('chartOptions')),
column(width = 5,
h3("Scatter plot"),
plotlyOutput("scatterplot"),
verbatimTextOutput("click")
)
)
),
hr(),
div(
column(width = 6,
h2("Data Table"),
div(
DT::dataTableOutput(outputId = "table_keep"),
style = "height:auto; overflow-y: scroll;overflow-x: scroll;")),
column(width = 6,
h2("Outlier Data"),
div(
DT::dataTableOutput(outputId = "table_outliers"),
style = "height:auto; overflow-y: scroll;overflow-x: scroll;"))
)
))
server <- function(input, output, session){
datasetInput <- reactive({
df <- iris
return(df)
})
output$chartOptions <- renderUI({#choose variables to plot
if(is.null(datasetInput())){}
else {
list(
selectizeInput("xAxisSelector", "X Axis Variable",
colnames(datasetInput())),
selectizeInput("yAxisSelector", "Y Axis Variable",
colnames(datasetInput())),
selectizeInput("colorBySelector", "Color By:",
c(c("Do not color",colnames(datasetInput()))))
)
}
})
vals <- reactiveValues(#define reactive values for:
data = NULL,
data_keep = NULL,
data_exclude = NULL)
observe({
vals$data <- datasetInput()
vals$data_keep <- datasetInput()
})
## Datatable
output$table_keep <- renderDT({
vals$data_keep
},options = list(pageLength = 5))
output$table_outliers <- renderDT({
vals$data_exclude
},options = list(pageLength = 5))
# mechanism for managing selected points
keys <- reactiveVal()
observeEvent(event_data("plotly_click", source = "outliers", priority = "event"), {
req(vals$data)
is_outlier <- NULL
key_new <- event_data("plotly_click", source = "outliers")$key
key_old <- keys()
if (key_new %in% key_old){
keys(setdiff(key_old, key_new))
} else {
keys(c(key_new, key_old))
}
is_outlier <- rownames(vals$data) %in% keys()
vals$data_keep <- vals$data[!is_outlier, ]
vals$data_exclude <- vals$data[is_outlier, ]
plotlyProxy("scatterplot", session) %>%
plotlyProxyInvoke(
"restyle",
list(marker.line = list(
color = as.vector(ifelse(is_outlier,'black','grey')),
width = 2
))
)
})
observeEvent(event_data("plotly_doubleclick", source = "outliers"), {
req(vals$data)
keys(NULL)
vals$data_keep <- vals$data
vals$data_exclude <- NULL
plotlyProxy("scatterplot", session) %>%
plotlyProxyInvoke(
"restyle",
list(marker.line = list(
color = 'grey',
width = 2
)
))
})
output$scatterplot <- renderPlotly({
req(vals$data,input$xAxisSelector,input$yAxisSelector)
dat <- vals$data
key <- rownames(vals$data)
x <- input$xAxisSelector
y <- input$yAxisSelector
if(input$colorBySelector != "Do not color"){
color <- dat[, input$colorBySelector]
}else{
color <- "orange"
}
scatterplot <- dat %>%
plot_ly(x = dat[,x], y = dat[,y], source = "outliers") %>%
add_markers(key = key,color = color,
marker = list(size = 10, line = list(
color = 'grey',
width = 2
))) %>%
layout(showlegend = FALSE)
return(scatterplot)
})
output$click <- renderPrint({#click event data
d <- event_data("plotly_click", source = "outliers")
if (is.null(d)) "click events appear here (double-click to clear)" else d
})
}
shinyApp(ui, server)
The problem with your above code is that no traceIndices argument is provided for restyle. Please see this.
In your example, once you switch coloring to the factor Species plotly no longer creates one trace, but three. This happens in JS so counting is done from 0 to 2.
To restyle those traces you can address them via curveNumber (in this case 0:2) and pointNumber (50 data points in each trace 0:49)
With a single trace your example works as your key and your trace have the same length (150).
As your provided code is pretty long I just focused on the "Species" problem. It won't work in all other cases, but you should be able to deduce a more general approach from it:
library(shiny)
library(plotly)
library(DT)
ui <- fluidPage(
mainPanel(
fluidRow(
div(
column(
width = 2,
uiOutput('chartOptions')),
column(width = 5,
h3("Scatter plot"),
plotlyOutput("scatterplot"),
verbatimTextOutput("click")
)
)
),
hr(),
div(
column(width = 6,
h2("Data Table"),
div(
DT::dataTableOutput(outputId = "table_keep"),
style = "height:auto; overflow-y: scroll;overflow-x: scroll;")),
column(width = 6,
h2("Outlier Data"),
div(
DT::dataTableOutput(outputId = "table_outliers"),
style = "height:auto; overflow-y: scroll;overflow-x: scroll;"))
)
))
server <- function(input, output, session){
datasetInput <- reactive({
df <- iris
df$is_outlier <- FALSE
return(df)
})
output$chartOptions <- renderUI({#choose variables to plot
if(is.null(datasetInput())){}
else {
list(
selectizeInput("xAxisSelector", "X Axis Variable",
colnames(datasetInput())),
selectizeInput("yAxisSelector", "Y Axis Variable",
colnames(datasetInput())),
selectizeInput("colorBySelector", "Color By:",
c(c("Do not color",colnames(datasetInput()))))
)
}
})
vals <- reactiveValues(#define reactive values for:
data = NULL,
data_keep = NULL,
data_exclude = NULL)
observe({
vals$data <- datasetInput()
vals$data_keep <- datasetInput()
})
## Datatable
output$table_keep <- renderDT({
vals$data_keep
},options = list(pageLength = 5))
output$table_outliers <- renderDT({
vals$data_exclude
},options = list(pageLength = 5))
# mechanism for managing selected points
keys <- reactiveVal()
myPlotlyProxy <- plotlyProxy("scatterplot", session)
observeEvent(event_data("plotly_click", source = "outliers", priority = "event"), {
req(vals$data)
is_outlier <- NULL
plotlyEventData <- event_data("plotly_click", source = "outliers")
key_new <- plotlyEventData$key
key_old <- keys()
if (key_new %in% key_old){
keys(setdiff(key_old, key_new))
} else {
keys(c(key_new, key_old))
}
vals$data[keys(),]$is_outlier <- TRUE
is_outlier <- vals$data$is_outlier
vals$data_keep <- vals$data[!is_outlier, ]
vals$data_exclude <- vals$data[is_outlier, ]
print(paste("pointNumber:", plotlyEventData$pointNumber))
print(paste("curveNumber:", plotlyEventData$curveNumber))
plotlyProxyInvoke(
myPlotlyProxy,
"restyle",
list(marker.line = list(
color = as.vector(ifelse(vals$data[vals$data$Species %in% vals$data[plotlyEventData$key, ]$Species, ]$is_outlier,'black','grey')),
width = 2
)), plotlyEventData$curveNumber
)
})
observeEvent(event_data("plotly_doubleclick", source = "outliers"), {
req(vals$data)
keys(NULL)
vals$data_keep <- vals$data
vals$data_exclude <- NULL
plotlyProxyInvoke(
myPlotlyProxy,
"restyle",
list(marker.line = list(
color = 'grey',
width = 2
)
))
})
output$scatterplot <- renderPlotly({
req(datasetInput(),input$xAxisSelector,input$yAxisSelector)
dat <- datasetInput()
key <- rownames(dat)
x <- input$xAxisSelector
y <- input$yAxisSelector
if(input$colorBySelector != "Do not color"){
color <- dat[, input$colorBySelector]
}else{
color <- "orange"
}
scatterplot <- dat %>%
plot_ly(x = dat[,x], y = dat[,y], source = "outliers") %>%
add_markers(key = key,color = color,
marker = list(size = 10, line = list(
color = 'grey',
width = 2
))) %>%
layout(showlegend = FALSE)
return(scatterplot)
})
output$click <- renderPrint({#click event data
d <- event_data("plotly_click", source = "outliers")
if (is.null(d)) "click events appear here (double-click to clear)" else d
})
}
shinyApp(ui, server)
As a quick workaround, to avoid creating 3 traces, I simply converted the categorical variable assigned to color to numeric, and I hid the colorbar, so the output looks like this:
output$scatterplot <- renderPlotly({
req(vals$data,input$xAxisSelector,input$yAxisSelector)
dat <- vals$data
key <- rownames(vals$data)
x <- input$xAxisSelector
y <- input$yAxisSelector
if(input$colorBySelector != "Do not color"){
color <- as.numeric(dat[, input$colorBySelector])
}else{
color <- "orange"
}
scatterplot <- dat %>%
plot_ly(x = dat[,x], y = dat[,y], source = "outliers") %>%
add_markers(key = key,color = color,
marker = list(size = 10, line = list(
color = 'grey',
width = 2
))) %>%
layout(showlegend = FALSE) %>%
hide_colorbar()%>%
event_register("plotly_click")
return(scatterplot)
})
Update:
Another solution that I found is to make a loop of plotly proxies for each trace / category in the click event.
So the click event looks like this:
observeEvent(event_data("plotly_click", source = "outliers", priority = "event"), {
req(vals$data)
is_outlier <- NULL
key_new <- event_data("plotly_click", source = "outliers")$key
key_old <- keys()
#keys(c(key_new, key_old))
if (key_new %in% key_old){
keys(setdiff(key_old, key_new))
} else {
keys(c(key_new, key_old))
}
is_outlier <- rownames(vals$data) %in% keys()
vals$data_keep <- vals$data[!is_outlier, ]
vals$data_exclude <- vals$data[is_outlier, ]
indices <- list()
p <- plotlyProxy("scatterplot", session)
if(input$colorBySelector != "Do not color"){
if(is.factor(vals$data[,input$colorBySelector])){
for (i in 1:length(levels(vals$data[,input$colorBySelector]))){
indices[[i]] <- rownames(vals$data[which(vals$data[,input$colorBySelector] == levels(vals$data[,input$colorBySelector])[i]), ]) #retrieve indices for each category
plotlyProxyInvoke(p,
"restyle",
list(marker.line = list(
color = as.vector(ifelse(is_outlier[as.numeric(indices[[i]])],'black','grey')),
width = 2
)), c(i-1) #specify the trace (traces are indexed from 0)
)
}
}else{
p %>%
plotlyProxyInvoke(
"restyle",
list(marker.line = list(
color = as.vector(ifelse(is_outlier,'black','grey')),
width = 2
))
)
}
}else{
p %>%
plotlyProxyInvoke(
"restyle",
list(marker.line = list(
color = as.vector(ifelse(is_outlier,'black','grey')),
width = 2
))
)
}
})
I want a plotly plot to change an annotation if the user clicks a button in a shiny app.
I have no idea why this does not work:
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
plot_ly(d)%>%
add_lines(y=d$y, x= d$x)%>%
layout(annotations = list(x = 2, y= 99 , text = "hi"))})
observeEvent(input$button, {
plotlyProxy("plot", session= shiny::getDefaultReactiveDomain()) %>%
plotlyProxyInvoke("relayout", list(annotations= list(x = 2, y= 99 ,
text = "ho")))})}
shinyApp(ui, server)
That is not the way to use relayout in plotly. See below for your example using relayout.
I prefer using native shiny buttons for this purpose because of the greater flexibility it offers. Here is how one might go about achieving the hi-ho toggle.
shiny way
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
p <- plot_ly(d)%>%
add_lines(y=d$y, x= d$x)
if (is.null(input$button) | (input$button%%2 == 0)) {
p <- p %>% layout(annotations = list(x = 2, y= 99 , text = "hi"))
} else {
p <- p %>% layout(annotations = list(x = 2, y= 99 , text = "ho"))
}
p
})
}
shinyApp(ui, server)
In this case though, it is simple enough to make the relayout feature work, although it does require an extra button.
plotly relayout way
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot")
)
server <- function(input, output) {
output$plot <- renderPlotly({
updatemenus <- list(
list(
active = -1,
type = 'buttons',
buttons = list(
list(
label = "hi",
method = "relayout",
args = list(list(annotations = list(list(x = 2, y= 99 , text = "hi"))))),
list(
label = "ho",
method = "relayout",
args = list(list(annotations = list(list(x = 2, y= 99 , text = "ho")))))
)
)
)
p <- plot_ly(d) %>%
add_lines(y=d$y, x= d$x) %>%
layout(updatemenus = updatemenus)
p
})
}
shinyApp(ui, server)
I believe all that needs to change in your code in order to get this to work is wrapping another list around the defined annotation list in your plotly proxy relayout code. I recently discovered that this recursive list structure is all that's needed in order to manipulate annotations using relayout - you can check out my answer to another SO question related to the same issue, but with slightly different context: https://stackoverflow.com/a/70610374/17852464
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
plot_ly(d)%>%
add_lines(y=d$y, x= d$x)%>%
layout(annotations = list(x = 2, y= 99 , text = "hi"))
})
observeEvent(input$button, {
plotlyProxy("plot", session= shiny::getDefaultReactiveDomain()) %>%
plotlyProxyInvoke("relayout", list(annotations= list(list(x = 2, y= 99 ,
text = "ho"))))})}
}
shinyApp(ui, server)
I have a shiny application in which I'd like to capture which bar a user clicks on and store that value in a reactive expression to be referenced elsewhere for filtering. The problem is that the reactive expression reruns when I switch tabs and so the value doesn't sync up between the two tabs.
I have a reproducible example below.
When you load the app and click on the Goats bar, the selection at the bottom changes to 'Goats', but if you then change the tab to Bar2 the reactive expression reruns and therefore returns Giraffes again. So I end up with two separate values for the reactive expression across the different tabs. If I choose Goats on the first tab, I want it to remain when I switch to Bar2 tab and only update when I make another click.
Note that I realize I can resolve this in this example by removing the source argument from the event_data function, but in my application I have other charts which I do not want the user to be able to click on so I need to set the source to only these charts.
library(shiny)
library(plotly)
library(ggplot2)
library(shinydashboard)
df_test <- data.frame(c("Giraffes","Goats"),c(1,4))
df_test <- setNames(df_test,c("species","amount"))
ui <- dashboardPage(
dashboardHeader(title = "Click Example",
titleWidth = 300),
dashboardSidebar(
width = 300,
sidebarMenu(
menuItem("Tab", tabName = "tab")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "tab",
fluidRow(
column(12, tabBox(
title = "",
id = "tabSet",
width = 12,
height = 500,
tabPanel("Bar1", plotlyOutput(outputId="bar_one")),
tabPanel("Bar2", plotlyOutput(outputId="bar_two"))
)
),
column(12,textOutput(outputId = "selection")))
)
)
)
)
server <- function(input, output, session) {
click_reactive = reactive({
d <- event_data("plotly_click",source=input$tabSet)
if (length(d) == 0) {species = as.vector(df_test$species[1])}
else {species = as.character(d[4])}
return(species)
})
output$bar_one <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$bar_two <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar2")
})
output$selection <- renderText({
species <- click_reactive()
return(species)
})
}
shinyApp(ui, server)
You need to change the source to be under one name:
library(shiny)
library(plotly)
library(ggplot2)
library(shinydashboard)
df_test <- data.frame(c("Giraffes","Goats"),c(1,4))
df_test <- setNames(df_test,c("species","amount"))
ui <- dashboardPage(
dashboardHeader(title = "Click Example",
titleWidth = 300),
dashboardSidebar(
width = 300,
sidebarMenu(
menuItem("Tab", tabName = "tab")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "tab",
fluidRow(
column(12, tabBox(
title = "",
id = "tabSet",
width = 12,
height = 500,
tabPanel("Bar1", plotlyOutput(outputId="bar_one")),
tabPanel("Bar2", plotlyOutput(outputId="bar_two"))
)
),
column(12,textOutput(outputId = "selection")))
)
)
)
)
server <- function(input, output, session) {
v <- reactiveValues()
observe({
d <- event_data("plotly_click",source="Bar1")
if (length(d) == 0) {species = as.vector(df_test$species[1])}
else {species = as.character(d[4])}
v$click <- species
})
output$bar_one <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$bar_two <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$selection <- renderText({
v$click
})
}
shinyApp(ui, server)
I am trying out the R Streaming example for extendTraces on Plotly. I am trying to add a functionality to the chart such that it would clear all the data as the browser starts stalling after some time (eg., an actionButton, etc). Is there a way to stop the trace and clear the trace/data on a second click of the actionButton ? Alternatively, is it possible to make the chart incremental, such that the entire data isn't getting stored locally.
https://plot.ly/r/streaming/#streaming-in-r
library(shiny)
library(plotly)
rand <- function() {
runif(1, min=1, max=9)
}
ui <- fluidPage(
includeCSS("styles.css"),
headerPanel(h1("Streaming in Plotly: Multiple Traces", align = "center")),
br(),
div(actionButton("button", "Extend Traces"), align = "center"),
br(),
div(plotlyOutput("plot"), id='graph')
)
server <- function(input, output, session) {
p <- plot_ly(
type = 'scatter',
mode = 'lines'
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#25FEFD',
width = 3
)
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#636EFA',
width = 3
)
) %>%
layout(
yaxis = list(range = c(0,10))
)
output$plot <- renderPlotly(p)
observeEvent(input$button, {
while(TRUE){
Sys.sleep(1)
plotlyProxy("plot", session) %>%
plotlyProxyInvoke("extendTraces", list(y=list(list(rand()), list(rand()))), list(1,2))
}
})
}
shinyApp(ui, server)
Thanks in advance,
Raj.
Hi maybe you could do something like this?
library(shiny)
library(plotly)
library(shinyjs)
rand <- function() {
runif(1, min=1, max=9)
}
ui <- fluidPage(
# includeCSS("styles.css"),
headerPanel(h1("Streaming in Plotly: Multiple Traces", align = "center")),
br(),
div(actionButton("button", "Extend Traces"),actionButton("buttonReset", "Reset Traces"), align = "center"),
br(),
div(plotlyOutput("plot"), id='graph'),
useShinyjs()
)
server <- function(input, output, session) {
values <- reactiveValues()
values$p <- plot_ly(
type = 'scatter',
mode = 'lines'
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#25FEFD',
width = 3
)
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#636EFA',
width = 3
)
) %>%
layout(
yaxis = list(range = c(0,10))
)
output$plot <- renderPlotly({values$p})
observe({
invalidateLater(1000, session)
req(input$button > 0)
plotlyProxy("plot", session) %>%
plotlyProxyInvoke("extendTraces", list(y=list(list(rand()), list(rand()))), list(1,2))
})
observeEvent(input$buttonReset,{
values$p <- plot_ly(
type = 'scatter',
mode = 'lines'
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#25FEFD',
width = 3
)
) %>%
add_trace(
y = c(rand(),rand(),rand()),
line = list(
color = '#636EFA',
width = 3
)
) %>%
layout(
yaxis = list(range = c(0,10))
)
runjs("Shiny.onInputChange('button',0)")
})
}
shinyApp(ui, server)
Hope this helps!!