R shiny plotly width and height don't update - r

I'm writing a shiny app and I try to update the size of the plot depending on some inputs. The problem is that when the plot gets bigger it doesn't come back to the smaller sizes.
This is the code:
library(dplyr)
library(plotly)
library(shiny)
dat <- data.frame(xval = sample(100,1000,replace = TRUE),
group1 = as.factor(sample(c("a","b","c"),1000,replace = TRUE)),
group2 = as.factor(sample(c("a1","a2","a3","a4"),1000, replace = TRUE)),
group3 = as.factor(sample(c("b1","b2","b3","b4"),1000, replace = TRUE)),
group4 = as.factor(sample(c("c1","c2","c3","c4"),1000, replace = TRUE)))
create_plot <- function(dat, group, color, shape) {
p <- dat %>%
plot_ly() %>%
add_trace(x = ~as.numeric(get(group)),
y = ~xval,
color = ~get(group),
type = "box") %>%
add_markers(x = ~jitter(as.numeric(get(group))),
y = ~xval,
color = ~get(color),
symbol = ~get(shape),
marker = list(size = 4)
)
p
}
calc_boxplot_size <- function(facet) {
if (facet) {
width <- 1000
height <- 700
} else {
width <- 500
height <- 400
}
cat(sprintf("WIDTH: %s, HEIGHT: %s", width, height), sep = "\n")
list(width = width, height = height)
}
ui <- fluidPage(
selectizeInput("group", label = "group", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("color", label = "color", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("shape", label = "shape", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("facet", label = "facet", choices = c("none", paste0("group", 1:4)),
multiple = FALSE, selected = "none"),
textOutput("size"),
uiOutput("plotbox")
)
server <- function(input, output, session) {
output$plotbox <- renderUI({
psize <- calc_boxplot_size((input$facet != "none"))
plotlyOutput("plot", height = psize$height, width = psize$width)
})
output$size <- renderText({
psize <- calc_boxplot_size((input$facet != "none"))
sprintf("WIDTH: %s, HEIGHT: %s", psize$width, psize$height)
})
output$plot <- renderPlotly({
if (input$facet == "none") {
p <- create_plot(dat, input$group, input$color, input$shape)
} else {
plots <- dat %>%
group_by_(.dots = input$facet) %>%
do(p = {
create_plot(., input$group, input$color, input$shape)
})
p <- subplot(plots, shareX = TRUE, shareY = TRUE, nrows = 3, margin = 0.02)
}
})
}
shinyApp(ui, server)
If I change the code to have the width and height updated in ... %>% plotly(height = height, width = width) %>% ... it never updates the size of the plot.
The code:
library(dplyr)
library(plotly)
library(shiny)
dat <- data.frame(xval = sample(100,1000,replace = TRUE),
group1 = as.factor(sample(c("a","b","c"),1000,replace = TRUE)),
group2 = as.factor(sample(c("a1","a2","a3","a4"),1000, replace = TRUE)),
group3 = as.factor(sample(c("b1","b2","b3","b4"),1000, replace = TRUE)),
group4 = as.factor(sample(c("c1","c2","c3","c4"),1000, replace = TRUE)))
create_plot <- function(dat, group, color, shape, width, height) {
p <- dat %>%
plot_ly(width = width, height = height) %>%
add_trace(x = ~as.numeric(get(group)),
y = ~xval,
color = ~get(group),
type = "box") %>%
add_markers(x = ~jitter(as.numeric(get(group))),
y = ~xval,
color = ~get(color),
symbol = ~get(shape),
marker = list(size = 4)
)
p
}
calc_boxplot_size <- function(facet) {
if (facet) {
width <- 1000
height <- 700
} else {
width <- 500
height <- 400
}
cat(sprintf("WIDTH: %s, HEIGHT: %s", width, height), sep = "\n")
list(width = width, height = height)
}
ui <- fluidPage(
selectizeInput("group", label = "group", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("color", label = "color", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("shape", label = "shape", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("facet", label = "facet", choices = c("none", paste0("group", 1:4)),
multiple = FALSE, selected = "none"),
textOutput("size"),
uiOutput("plotbox")
)
server <- function(input, output, session) {
output$plotbox <- renderUI({
psize <- calc_boxplot_size((input$facet != "none"))
plotlyOutput("plot")
})
output$size <- renderText({
psize <- calc_boxplot_size((input$facet != "none"))
sprintf("WIDTH: %s, HEIGHT: %s", psize$width, psize$height)
})
output$plot <- renderPlotly({
psize <- calc_boxplot_size((input$facet != "none"))
if (input$facet == "none") {
p <- create_plot(dat, input$group, input$color, input$shape, psize$width, psize$height)
} else {
plots <- dat %>%
group_by_(.dots = input$facet) %>%
do(p = {
create_plot(., input$group, input$color, input$shape, psize$width, psize$height)
})
p <- subplot(plots, shareX = TRUE, shareY = TRUE, nrows = 3, margin = 0.02)
}
})
}
shinyApp(ui, server)
Are there any other ways to update the size of the plot like that? Please help.

I added custom width and height inputs and it works... or maybe I just don't get the problem...
library(dplyr)
library(plotly)
library(shiny)
dat <- data.frame(xval = sample(100,1000,replace = TRUE),
group1 = as.factor(sample(c("a","b","c"),1000,replace = TRUE)),
group2 = as.factor(sample(c("a1","a2","a3","a4"),1000, replace = TRUE)),
group3 = as.factor(sample(c("b1","b2","b3","b4"),1000, replace = TRUE)),
group4 = as.factor(sample(c("c1","c2","c3","c4"),1000, replace = TRUE)))
create_plot <- function(dat, group, color, shape, width, height) {
p <- dat %>%
plot_ly(width = width, height = height) %>%
add_trace(x = ~as.numeric(get(group)),
y = ~xval,
color = ~get(group),
type = "box") %>%
add_markers(x = ~jitter(as.numeric(get(group))),
y = ~xval,
color = ~get(color),
symbol = ~get(shape),
marker = list(size = 4)
)
p
}
calc_boxplot_size <- function(facet) {
if (facet) {
width <- 1000
height <- 700
} else {
width <- 500
height <- 400
}
cat(sprintf("WIDTH: %s, HEIGHT: %s", width, height), sep = "\n")
list(width = width, height = height)
}
ui <- fluidPage(
selectizeInput("group", label = "group", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("color", label = "color", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("shape", label = "shape", choices = paste0("group", 1:4),
multiple = FALSE),
selectizeInput("facet", label = "facet", choices = c("none", paste0("group", 1:4)),
multiple = FALSE, selected = "none"),
textOutput("size"),
tagList(
textInput("plot.width", "width:", 1000),
textInput("plot.height", "height", 700)
),
uiOutput("plotbox")
)
server <- function(input, output, session) {
output$plotbox <- renderUI({
# column(9,
# psize <- calc_boxplot_size((input$facet != "none")),
# plotlyOutput("plot")
# )
psize <- calc_boxplot_size((input$facet != "none"))
plotlyOutput("plot")
})
output$size <- renderText({
psize <- calc_boxplot_size((input$facet != "none"))
sprintf("WIDTH: %s, HEIGHT: %s", psize$width, psize$height)
})
output$plot <- renderPlotly({
psize <- calc_boxplot_size((input$facet != "none"))
if (input$facet == "none") {
p <- create_plot(dat, input$group, input$color, input$shape, input$plot.width, input$plot.height)
} else {
plots <- dat %>%
group_by_(.dots = input$facet) %>%
do(p = {
create_plot(., input$group, input$color, input$shape, input$plot.width, input$plot.height)
})
p <- subplot(plots, shareX = TRUE, shareY = TRUE, nrows = 3, margin = 0.02)
}
})
}
shinyApp(ui, server)

Related

updatePickerInput does not respond to reactive data

I am putting together an Shiny app to allow users to upload an area of interest (AOI), and calculate the amount of overlap with an administrative boundary (WMU). Everything is working as desired, except that my picker input options do not update. The picker input works, but I would like the choices to only include the WMU that overlap the AOI instead of all possible WMU. I can calculate the WMU ID that should populate the list, shown in the "TEST_TEXT"output below the map frame, but cannot successfully update the pickerInput. This kmz will overlap the several WMU that are loaded at the beginning of the script included below:
library(shiny)
library(sf)
library(tidyverse)
library(bcdata)
library(shinyjs)
library(leaflet)
library(mapview)
library(DT)
library(pals)
library(shinyWidgets)
library(shinymanager)
WMU_DATA <-
bcdc_get_data("wildlife-management-units") %>% st_transform(4326) %>% mutate(Total.WMU.HA =
as.numeric(st_area(.)) / 10000)
##### UI #####
ui <- fluidPage(
tags$head(tags$style(
HTML(
".shiny-notification {
height: 100px;
width: 400px;
position:fixed;
top: calc(25% - 50px);;
left: calc(50% - 200px);;
}
"
)
)),
# Application title
titlePanel("Calculate Overlap With WMU"),
# Inputs
sidebarLayout(
sidebarPanel(
width = 3,
textInput(
inputId = "AOI_NAME",
label = "AOI Name",
value = NULL
),
HTML("<br><br>"),
fileInput(
inputId = "KMZ",
label = "Choose KMZ",
multiple = FALSE,
accept = c('.kmz')
),
h3("or"),
HTML("<br><br>"),
fileInput(
inputId = "SHAPEFILE",
label = "Choose shapefile",
multiple = TRUE,
accept = c('.shp', '.dbf', '.sbn', '.sbx', '.shx', '.prj', '.xml')
),
pickerInput(
inputId = "WMU_FILTER",
label = "Filter Overlapping WMU",
choices = unique(WMU_DATA$WILDLIFE_MGMT_UNIT_ID),
selected = unique(WMU_DATA$WILDLIFE_MGMT_UNIT_ID),
multiple = TRUE,
options = list(`actions-box` = TRUE)
),
HTML("<br><br>")
),
# Display OUtputs
mainPanel(
width = 9,
leafletOutput("OVERLAP_MAP", height = 750),
h3(textOutput("TEST_TEXT")),
DTOutput("AOI_OVERLAP_TABLE")
)
)
)
######server#####
server <- function(input, output, session) {
####reactive data
AOI <-
reactive({
if (is.null(input$SHAPEFILE) & !is.null(input$KMZ)) {
st_read(unzip(input$KMZ$datapath)) %>%
st_zm(drop = T) %>%
mutate(AOI_NAME = input$AOI_NAME) %>%
st_transform(4326) %>%
select(-Name)
}
else if (!is.null(input$SHAPEFILE) & is.null(input$KMZ)) {
SHAPEFILE()
}
else{
return(NULL)
}
})
WMU_OVERLAP <- reactive({
st_filter(WMU_DATA, AOI())
})
AOI_WMU_INTERSECT <-
reactive({
st_intersection(AOI(), WMU_OVERLAP()) %>%
mutate(`HA of Overlap` = round(as.numeric(st_area(.)) / 10000, 0)) %>%
mutate(`Percent of WMU` = round(`HA of Overlap` / `Total.WMU.HA` *
100, 2))
})
observeEvent(AOI_WMU_INTERSECT
,
{
updatePickerInput(
session,
"WMU_FILTER",
choices = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID),
selected = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID)
)
},
ignoreInit = TRUE,
ignoreNULL = TRUE)
###outputs
output$OVERLAP_MAP <-
renderLeaflet({
withProgress(message = "Calcualting Overlap", detail = "Should be done soon", {
AOI_SPATIAL <- AOI() %>% mutate(AOI_NAME = input$AOI_NAME)
WMU <-
WMU_OVERLAP() %>% filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
Overlap <-
AOI_WMU_INTERSECT() %>% filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
MAP <-
mapview(
Overlap,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
map.types = c("Esri.WorldTopoMap", "Esri.WorldImagery"),
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
))
) +
mapview(
WMU,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
lwd = 3,
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
)),
hide = TRUE
) +
mapview(AOI_SPATIAL,
label = "AOI_NAME",
col.regions = "red")
MAP#map %>%
setView(st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 1],
st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 2],
zoom = 9)
})
})
output$AOI_OVERLAP_TABLE <-
renderDT({
AOI_OVERLAP_TABLE <- AOI_WMU_INTERSECT() %>%
st_drop_geometry()
AOI_OVERLAP_TABLE
}, filter = "top", extensions = c("FixedHeader", "Buttons"),
options = list(
pageLength = 100,
fixedHeader = TRUE,
dom = "Bfrtip",
buttons = c('colvis', 'copy', 'excel', 'csv')
))
output$TEST_TEXT <-
renderText(unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID))
}
# Run the application
shinyApp(ui = ui, server = server)
Putting some req() and changing observeEvent() to observe() makes it work. Try this
######server#####
server <- function(input, output, session) {
####reactive data
AOI <-
reactive({
if (is.null(input$SHAPEFILE) & !is.null(input$KMZ)) {
st_read(unzip(input$KMZ$datapath)) %>%
st_zm(drop = T) %>%
mutate(AOI_NAME = input$AOI_NAME) %>%
st_transform(4326) %>%
select(-Name)
}
else if (!is.null(input$SHAPEFILE) & is.null(input$KMZ)) {
SHAPEFILE()
}
else{
return(NULL)
}
})
WMU_OVERLAP <- reactive({
req(AOI())
st_filter(WMU_DATA, AOI())
})
AOI_WMU_INTERSECT <-
reactive({
req(AOI(), WMU_OVERLAP())
st_intersection(AOI(), WMU_OVERLAP()) %>%
dplyr::mutate(`HA of Overlap` = round(as.numeric(st_area(.)) / 10000, 0)) %>%
dplyr::mutate(`Percent of WMU` = round(`HA of Overlap` / `Total.WMU.HA` *100, 2))
})
observe({updatePickerInput(
session,
"WMU_FILTER",
choices = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID),
selected = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID)
)
} )#, ignoreInit = TRUE, ignoreNULL = TRUE)
###outputs
output$OVERLAP_MAP <-
renderLeaflet({
req(AOI_WMU_INTERSECT())
withProgress(message = "Calcualting Overlap", detail = "Should be done soon", {
AOI_SPATIAL <- AOI() %>% dplyr::mutate(AOI_NAME = input$AOI_NAME)
WMU <-
WMU_OVERLAP() %>% dplyr::filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
Overlap <-
AOI_WMU_INTERSECT() %>% dplyr::filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
MAP <-
mapview(
Overlap,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
map.types = c("Esri.WorldTopoMap", "Esri.WorldImagery"),
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
))
) +
mapview(
WMU,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
lwd = 3,
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
)),
hide = TRUE
) +
mapview(AOI_SPATIAL,
label = "AOI_NAME",
col.regions = "red")
MAP#map %>%
setView(st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 1],
st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 2],
zoom = 9)
})
})
output$AOI_OVERLAP_TABLE <-
renderDT({
AOI_OVERLAP_TABLE <- AOI_WMU_INTERSECT() %>% st_drop_geometry()
AOI_OVERLAP_TABLE
}, filter = "top", extensions = c("FixedHeader", "Buttons"),
options = list(
pageLength = 100,
fixedHeader = TRUE,
dom = "Bfrtip",
buttons = c('colvis', 'copy', 'excel', 'csv')
))
output$TEST_TEXT <- renderText(unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID))
}

R shiny: How to copy data derived from plotly_selection events into a data frame/table and update each time by pressing an actionButton?

I'm putting together a shiny app to play around with some athlete GPS data. Essentially, I'm looking to structure my script so that each time the user selects an area of interest on the plotly plot and the "Add" actionButton is clicked, the table below will add the calculated Start_time, Time_at_peak, Max_velocity, Time_to_peak, and Distance_to_peak values.
The issue can be seen in the GIF below: - Once the area of interest is selected and the "Add" button clicked, the first values seem correct. However, when the user selects a second area of interest to add to the table, it overwrites the initial entry and will keep overwriting each time a new selection is made. This is seemingly because because the code is inside the observeEvent(event_data("plotly_selected"), which, confusingly, it needs to be in order to calculate the variables of interest.
I'm currently a little stumped and can't seem to find any relevant information. As such, any guidance would be greatly appreciated!
Here is a we transfer link to some test data that can be uploaded to the app: https://wetransfer.com/downloads/5a7c5da5a7647bdbe133eb3fdac79c6b20211119052848/afe3e5
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
x_df <- data.frame(Start_time = character(1), Time_at_peak = character(1), Max_velocity = integer(1),
Time_to_peak = integer(1), Distance_to_peak = integer(1))
x_df$Start_time <- as.character("0:00:00.0")
x_df$Time_at_peak <- as.character("0:00:00.0")
x_df$Max_velocity <- as.integer(0)
x_df$Time_to_peak <- as.integer(0)
x_df$Distance_to_peak <- as.integer(0)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(event_data("plotly_selected"), {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
values <- reactiveValues()
values$df <- x_df
addData <- observe({
if(input$Add > 0) {
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
values$df <- isolate(rbind(values$df, newLine))}
})
output$testing <- renderDataTable({values$df})
})
})
))
I've managed to figure it out and thought I'd post an answer rather than delete the question - just in case someone out there is looking to do a similar thing and they are unsure how to do it.
Firstly, I removed the pre-populated table x_df from the beginning - it was no longer required.
Although I thought the code needed to sit inside the observeEvent(event_data("plotly_selected") to function correctly, it did not - thankfully, because that was at the root of the issue. Instead, I used observeEvent(input$Add, { (which is the correct code to use as opposed to if(input$Add > 0)) to anchor the event to the click of the Add button.
The values <- reactiveValues() was placed outside the observeEvent() and an IF statement was used to either add the data to the values$df data frame on it's own if it was the first selection, or bind it to the existing saved data.
Here's the new code and a GIF demonstrating.
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
values <- reactiveValues(df_data = NULL)
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(input$Add, {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
if (is.null(values$df)){
values$df <- newLine}
else {
values$df <- isolate(rbind(values$df, newLine))}
output$testing <- renderDataTable({values$df})
})
})
))

Shiny R: bad display of plots in plotly

I have some problems displaying plots. They are added dynamically: the more variables selected the more plots are plotted. The problem is there are no space respect.
This is the code:
dades <- iris
binary_variable <- factor(sample(x = c(0, 1), size = nrow(dades), replace = TRUE))
dades <- cbind(iris, binary_variable)
ui <- fluidPage(
column(2, ),
column(8,
fluidRow(
column(4,
selectInput("resposta", "Dependent variable", choices = names(dades))
),
column(4,
textInput("explicatives", "Independent variables")
),
column(4,
actionButton("executar", "Run")
)
),
fluidRow(align = "center",
verbatimTextOutput("resultat"),
uiOutput("grafics")
)
),
column(2, )
)
server <- function(input, output, session) {
model <- reactive({
if(input$executar == 0){
return(invisible(NULL))
}else{
isolate({
resposta2 <- factor(dades[, input$resposta])
etiquetes <- levels(resposta2)
levels(resposta2) <- c(0, 1)
resposta2 <- factor(resposta2, levels = c(0, 1), labels = etiquetes)
f <- as.formula(paste0("resposta2 ~ ", input$explicatives))
glm(formula = f, family = binomial, data = dades)
})
}
})
output$resultat <- renderPrint({
if(input$executar == 0){
return(invisible(NULL))
}else{
isolate({
summary(model())
})
}
})
observe({
if(input$executar == 0) {
return(invisible(NULL))
} else {
lapply(names(model()$model)[-1], function(par){
if (is.factor(model()$model[, par]) || is.character(model()$model[, par]) || is.integer(model()$model[, par])) {
taula <- as.data.frame(table(model()$model$resposta2, model()$model[, par]))
p <- plot_ly(taula, x = ~ Var1, y = ~Freq, color = ~Var2, type = "bar") %>%
layout(title = NULL, xaxis = list(title = ""), yaxis = list(title = ""), height = 500, width = 500, inline = TRUE)
output[[paste("plot", par, sep = "_")]] <- renderPlotly({
p
})
} else if (is.numeric(model()$model[, par])){
p <- plot_ly(model()$model, y = ~model()$model[, par], color = ~resposta2, type = "box") %>%
layout(title = NULL, xaxis = list(title = ""), yaxis = list(title = ""), height = 500, width = 500, inline = TRUE)
output[[paste("plot", par, sep = "_")]] <- renderPlotly({
p
})
}
})
}
})
output$grafics <- renderUI({
if(input$executar == 0) {
return(invisible(NULL))
} else {
plot_output_list <- lapply(names(model()$model)[-1], function(par) {
plotname <- paste("plot", par, sep = "_")
plotlyOutput(plotname)
})
do.call(flowLayout, plot_output_list)
}
})
}
shinyApp(ui, server)
In the "Dependent variable" input you must select "binary_variable" and in the "Independent variables" input something like "Sepal.Length + Sepal.Width + Species". The problem is the plots are like superimposed, it's like there are not enough space between them. How can I fix this?
While you cannot specify the width and height in layout(), you can let it autosize. Also, it is better to put the legend at the bottom, as multiple plots are displayed horizontally. Try this
ui <- fluidPage(
column(2, ),
column(8,
fluidRow(
column(4,
selectInput("resposta", "Dependent variable", choices = names(dades))
),
column(4,
textInput("explicatives", "Independent variables")
),
column(4,
actionButton("executar", "Run")
)
),
fluidRow(# align = "center",
column(12, verbatimTextOutput("resultat")),
column(12, uiOutput("grafics"))
)
),
column(2, )
)
server <- function(input, output, session) {
model <- reactive({
if(input$executar == 0){
return(invisible(NULL))
}else{
isolate({
resposta2 <- factor(dades[, input$resposta])
etiquetes <- levels(resposta2)
levels(resposta2) <- c(0, 1)
resposta2 <- factor(resposta2, levels = c(0, 1), labels = etiquetes)
f <- as.formula(paste0("resposta2 ~ ", input$explicatives))
glm(formula = f, family = binomial, data = dades)
})
}
})
output$resultat <- renderPrint({
if(input$executar == 0){
return(invisible(NULL))
}else{
isolate({
summary(model())
})
}
})
observe({
if(input$executar == 0) {
return(invisible(NULL))
} else {
lapply(names(model()$model)[-1], function(par){
if (is.factor(model()$model[, par]) || is.character(model()$model[, par]) || is.integer(model()$model[, par])) {
taula <- as.data.frame(table(model()$model$resposta2, model()$model[, par]))
p <- plot_ly(taula, x = ~ Var1, y = ~Freq, color = ~Var2, type = "bar") %>%
layout(legend = list(orientation = "h"), title = NULL, xaxis = list(title = ""), yaxis = list(title = ""), autosize=TRUE )
output[[paste("plot", par, sep = "_")]] <- renderPlotly({
p
})
} else if (is.numeric(model()$model[, par])){
p <- plot_ly(model()$model, y = ~model()$model[, par], color = ~resposta2, type = "box") %>%
layout(legend = list(orientation = "h"), title = NULL, xaxis = list(title = ""), yaxis = list(title = ""), autosize=TRUE )
output[[paste("plot", par, sep = "_")]] <- renderPlotly({
p
})
}
})
}
})
output$grafics <- renderUI({
if(input$executar == 0) {
return(invisible(NULL))
} else {
plot_output_list <- lapply(names(model()$model)[-1], function(par) {
plotname <- paste("plot", par, sep = "_")
plotlyOutput(plotname)
})
do.call(flowLayout, plot_output_list)
}
})
}
shinyApp(ui, server)

Combining renderUI, dataTableOutput, renderDataTable, and reactive

This is somewhat of an expansion of this post:
I would like to have the DT::renderDataTable inside the renderUI and then have the output of the renderUI used in the reactive.
This is what I'm doing:
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(plotly))
suppressPackageStartupMessages(library(shiny))
#data.frames to be used in the server
set.seed(1)
coordinate.df <- data.frame(coordinate_id = paste0("c", 1:1000),x = rnorm(1000), y = rnorm(1000), stringsAsFactors = F)
feature.df <- data.frame(coordinate_id = rep(paste0("c", 1:1000), 10), feature_id = rep(paste0("f", 1:10), 1000), value = rnorm(10*1000), stringsAsFactors = F)
feature.rank.df <- feature.df %>% dplyr::select(feature_id) %>% unique() %>% dplyr::mutate(rank=sample(1:10,10,replace = F)) %>% dplyr::arrange(rank)
feature.color.vec <- c("lightgray","darkred")
server <- function(input, output)
{
output$feature.idx <- renderUI({
output$feature.table <- DT::renderDataTable(feature.rank.df, server = FALSE, selection = "single")
DT::dataTableOutput("feature.table")
})
feature.plot <- reactive({
if(!is.null(input$feature.idx)){
feature.id <- feature.rank.df$feature_id[input$feature.idx]
plot.title <- feature.id
plot.df <- suppressWarnings(feature.df %>%
dplyr::filter(feature_id == feature.id) %>%
dplyr::left_join(coordinate.df,by = c("coordinate_id"="coordinate_id")))
feature.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$value,x=plot.df$x,y=plot.df$y,showlegend=F,colors=colorRamp(feature.color.vec)) %>%
plotly::layout(title=plot.title,xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F)) %>%
plotly::colorbar(limits=c(min(plot.df$value,na.rm=T),max(plot.df$value,na.rm=T)),len=0.4,title="Value"))
}
feature.plot
})
output$outPlot <- plotly::renderPlotly({
feature.plot()
})
}
ui <- fluidPage(
titlePanel("Results Explorer"),
sidebarLayout(
sidebarPanel(
uiOutput("feature.idx")
),
mainPanel(
plotly::plotlyOutput("outPlot")
)
)
)
shinyApp(ui = ui, server = server)
It does load the feature.rank.df data.frame but it then prints this error message to the main panel:
Error: no applicable method for 'plotly_build' applied to an object of class "c('reactiveExpr', 'reactive')"
And nothing gets plotted upon row selection in the table in the side panel.
Any idea what the solution is?
You can fix this by replacing your server function by the code below.
refer to the selected feature by input$feature.table_rows_selected
keep the reactive feature.plot code in the renderPlotly function
server <- function(input, output)
{
output$feature.idx <- renderUI({
output$feature.table <-
DT::renderDataTable(feature.rank.df,
server = FALSE,
selection = "single")
DT::dataTableOutput("feature.table")
})
output$outPlot <- plotly::renderPlotly({
if (!is.null(input$feature.table_rows_selected)) {
feature.id <-
feature.rank.df$feature_id[input$feature.table_rows_selected]
plot.title <- feature.id
plot.df <- suppressWarnings(
feature.df %>%
dplyr::filter(feature_id == feature.id) %>%
dplyr::left_join(
coordinate.df,
by = c("coordinate_id" = "coordinate_id")
)
)
feature.plot <-
suppressWarnings(
plotly::plot_ly(
marker = list(size = 3),
type = 'scatter',
mode = "markers",
color = plot.df$value,
x = plot.df$x,
y = plot.df$y,
showlegend = F,
colors = colorRamp(feature.color.vec)
) %>%
plotly::layout(
title = plot.title,
xaxis = list(
zeroline = F,
showticklabels = F,
showgrid = F
),
yaxis = list(
zeroline = F,
showticklabels = F,
showgrid = F
)
) %>%
plotly::colorbar(
limits = c(
min(plot.df$value, na.rm = T),
max(plot.df$value, na.rm = T)
),
len = 0.4,
title = "Value"
)
)
feature.plot
}
})
}
Edit:
Alternatively, you can keep the feature.plot as a reactive, like this:
server <- function(input, output)
{
output$feature.idx <- renderUI({
output$feature.table <- DT::renderDataTable(feature.rank.df, server = FALSE, selection = "single")
DT::dataTableOutput("feature.table")
})
feature.plot <- reactive({
if (!is.null(input$feature.table_rows_selected)) {
feature.id <-
feature.rank.df$feature_id[input$feature.table_rows_selected]
plot.df <- suppressWarnings(
feature.df %>%
dplyr::filter(feature_id == feature.id) %>%
dplyr::left_join(coordinate.df, by = c("coordinate_id" =
"coordinate_id"))
)
feature.plot <-
suppressWarnings(
plotly::plot_ly(
marker = list(size = 3),
type = 'scatter',
mode = "markers",
color = plot.df$value,
x = plot.df$x,
y = plot.df$y,
showlegend = F,
colors = colorRamp(feature.color.vec)
) %>%
plotly::layout(
title = plot.df$feature_id[1],
xaxis = list(
zeroline = F,
showticklabels = F,
showgrid = F
),
yaxis = list(
zeroline = F,
showticklabels = F,
showgrid = F
)
) %>%
plotly::colorbar(
limits = c(
min(plot.df$value, na.rm = T),
max(plot.df$value, na.rm = T)
),
len = 0.4,
title = "Value"
)
)
}
return(feature.plot)
})
output$outPlot <- plotly::renderPlotly({
req(feature.plot(), input$feature.table_rows_selected)
feature.plot()
})
}

the outputs don't update in my shiny app

I have problems in my shiny app. all the inputs show the correct response from the server but, when i select the choice 5 in the checkboxgroup the app return the correct thing. but after, when i try other inputs only show the update of box (dyplot1) and the anothers boxes(dyplot2 and prediction) keep static. this is a sample code:
# funciones ----
addDays <- function(data,date,days) {
for(i in 1:days){
data[length(data)+1] <- NA
date[length(date)+1] <- date[length(date)]+1
}
y <- xts(data,order.by = date)
return(y)
}
addDaysForecast <- function(forecast,date,days) {
data <- rep(NA,length(date))
for(i in 1:days){
data[length(data)+1] <- forecast[i]
date[length(date)+1] <- date[length(date)]+1
}
y <- xts(data,order.by = date)
return(y)
}
plotForecast <- function(table,forecast) {
days <-length(forecast)
date <-as.Date(table[,"ENTRYTIME"])
values <- as.numeric(table[,"CLOSINGPRICE"])
series <- addDays(values,date,days)
serieForecast <- addDaysForecast(forecast,date,days)
day1 <- date[length(date)-days*2]
day2 <- date[length(date)]+7
curvas <- cbind(series,serieForecast)
graf <- dygraph(curvas, main = table[1,1]) %>%
dySeries("..1", label = "datos", color = "black") %>%
dySeries("..2", label = " Forecast", stepPlot = TRUE, color = "green") %>%
dyAxis("y", label = "CLOSINGPRICE") %>%
dyCrosshair(direction = "vertical") %>%
dyRangeSelector(dateWindow = c(day1, day2)) %>%
##dyOptions(maxNumberWidth = 20, stackedGraph = FALSE) %>%
dyLegend(width = 400) %>%
dyHighlight(highlightCircleSize = 3,
highlightSeriesBackgroundAlpha = 0.2,
hideOnMouseOut = FALSE) %>%
dyRangeSelector()
return(graf)
}
plotNormal <- function(table,thing) {
date <-as.Date(table[,"ENTRYTIME"])
values <- as.numeric(table[,thing])
series <- xts(values, order.by = date)
ma1 <- xts(runMean(values, n = 6),order.by = date)
ma2 <- xts(runMean(values, n = 12),order.by = date)
ma3 <- xts(runMean(values, n = 20),order.by = date)
mv1 <- xts(runVar(values, n = 6), order.by = date)
mv2 <- xts(runVar(values, n = 12), order.by = date)
mv3 <- xts(runVar(values, n = 20), order.by = date)
ske1 <- xts(movskew(values,6), order.by = date)
ske2 <- xts(movskew(values,12), order.by = date)
ske3 <- xts(movskew(values,20), order.by = date)
curvas <- cbind(series,ma1,ma2,ma3,mv1,mv2,mv3,ske1,ske2,ske3)
graf <- dygraph(curvas, main = table[1,1], group = "ALL") %>%
dySeries("..1", label = "datos", color = "black") %>%
dySeries("..2", label = "Ma6", color = "red") %>%
dySeries("..3", label = "Ma12", color = "blue") %>%
dySeries("..4", label = "Ma20", color = "green") %>%
dySeries("..5", label = "Mv6",strokePattern = "dashed",axis = 'y2', color = "red") %>%
dySeries("..6", label = "Mv12",strokePattern = "dashed",axis = 'y2', color = "blue") %>%
dySeries("..7", label = "Mv20",strokePattern = "dashed",axis = 'y2',color = "green") %>%
dySeries("..8", label = " as 6", stepPlot = TRUE, color = "red") %>%
dySeries("..9", label = " as 12", stepPlot = TRUE, color = "blue") %>%
dySeries("..10", label = " as 20", stepPlot = TRUE, color = "green") %>%
dyAxis("y", label = thing) %>%
dyCrosshair(direction = "vertical") %>%
##dyOptions(maxNumberWidth = 20, stackedGraph = FALSE) %>%
dyLegend(width = 400) %>%
dyHighlight(highlightCircleSize = 3,
highlightSeriesBackgroundAlpha = 0.2,
hideOnMouseOut = FALSE) %>%
dyRangeSelector()
return(graf)
}
status <- function(table,forecast) {
test <- table[nrow(table)-1:nrow(table),]
last <- test[,"CLOSINGPRICE"]
if(length(forecast)==1|| forecast==-1 ){
return(("No se a realizado predicción para este nemo"))
}else if (last<forecast[1]){
return(paste("A la alza con precio de cierre: ",forecast[1]))
}else if(last>forecast[1]){
return(paste("A la baja con precio de cierre: ",forecast[1]))
}
}
##skewness moving
movskew <- function(values,n) {
values2 <- values
for(i in 1:n){
values2[i] <- NA
}
num <- n
for(i in 1:(length(values)-n)){
num <- num + 1
values2[num] <- as.numeric(skewness(values[i:num]))
}
return(values2)
}
whatshow <- function(array) {
showthis <- vector()
for(i in 1:5){
showthis[i] <- any(array==i)
}
return(showthis)
}
getforecast <- function(path) {
url <- paste0("http://192.168.1.9:3169/api/forecast/", path, "?format=json")
response <- jsonlite::fromJSON(url)
if(length(response)>1){
return(response$forecast)
}else{
return(-1)
}
}
whatPlot <- function(table,name,show,thing) {
if(show[5]==TRUE){
fore <- getforecast(name)
plotForecast(table,fore)
}else{
plotNormal(table,thing) %>%
dyVisibility(visibility=c(show[1],
rep(show[2],3),
rep(show[3],3),
rep(show[4],3)))
}
}
dyVisibility <- function (dygraph, visibility = TRUE){
dygraph$x$attrs$visibility <- visibility
dygraph
}
#creando la tabla de prueba
table <- data.frame(matrix(1, nrow = 100, ncol = 18))
nombres <- c("SYMBOL" ,
"BOOKING_REF_ID",
"BIDQTY",
"BIDPRICE",
"OFFERQTY",
"OFFERPRICE",
"TRADEQTY",
"TRADEPRICE",
"OPENINGPRICE",
"CLOSINGPRICE",
"HIGHPRICE",
"LOWPRICE",
"VWAPPRICE",
"IMBALANCE",
"VOLUME",
"AMOUNT",
"TREND",
"ENTRYTIME")
colnames(table) <- nombres
table$ENTRYTIME <-seq.POSIXt(as.POSIXct("2015-01-01", tz="GMT"),
as.POSIXct("2015-4-10", tz="GMT"), by="1 day")
# estructura pagina ----
header <- dashboardHeader(title = "Basic dashboard")
sidebar <- dashboardSidebar( collapsed = TRUE,
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"))
)
)
body <- dashboardBody(
tabItems(
# First tab content
tabItem(tabName = "dashboard",
fluidRow(
column(width = 9,
box(title = "Grafico 1", status = "primary", width = NULL,
solidHeader = TRUE, collapsible = TRUE,
dygraphOutput("dyPlot1",height = "300px")),
box(title = "Grafico 2", status = "primary", width = NULL,
solidHeader = TRUE, collapsible = TRUE,
dygraphOutput("dyPlot2",height = "300px"))
),
column(width = 3,
box(title = "Inputs", status = "warning", solidHeader = TRUE, width = NULL,
selectInput("var1",
label = "1) variable",
choices = nombres[3:16],
selected = "CLOSINGPRICE"),
selectInput("var2",
label = "2) variable",
choices = nombres[3:16],
selected = "VOLUME"),
checkboxGroupInput("checkGroup", label = h3("Ver:"),
choices = list("Datos" = 1, "Medias" = 2,
"Esperanzas" = 3,"Asimetrias"=4, "Forecast"=5),
selected = 1),
box(title = "Predicción",status = "warning", solidHeader = TRUE, width = NULL,
verbatimTextOutput("prediction"))
)
)
)
),
# Second tab content
tabItem(tabName = "widgets",
h2("Widgets tab content")
)
)
)
# app ----
app <- shinyApp(
#UI
ui <- dashboardPage(header,sidebar,body),
server <- function(input, output) {
observeEvent(input$checkGroup, {
#... # do some work
output$prediction <- renderText({
forecast <- getforecast("CAMANCHACA")
status(table,forecast)
})
#... # do some more work
})
output$dyPlot1 <- renderDygraph({
show <- whatshow(input$checkGroup)
whatPlot(table,"CAMANCHACA",show,input$var1)
})
output$dyPlot2 <- renderDygraph({
show <- whatshow(input$checkGroup)
whatPlot(table,"CAMANCHACA",show,input$var2)
})
}
)
# Run the app ----
runApp(app,host="0.0.0.0",port=3838)

Resources