Combining renderUI, dataTableOutput, renderDataTable, and reactive - r

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()
})
}

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))
}

Toggle between plotly bar chart to plotly column chart by using an actionButton

I have the shiny app below which displays a bar chart with Country in yaxis and Value in xaxis. Im trying to change it to: Country as xaxis and Value as yaxis by clicking on Exchange actionButton(). I should toggle between those two bu clicking on Exchange
library(shiny)
library(DT)
Country<-c("EU","CHE","ITA")
Value<-c(3,2,1)
dat<-data.frame(Country,Value)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton("exc",
"Exchange")
),
mainPanel(
uiOutput(outputId = "plot")
)
)
)
server <- function(input, output) {
excplot <- reactiveVal(TRUE)
observeEvent(input$exc, {
excPlot(!excplot())
})
output[["bar1"]]<-renderPlotly({
fig1 <- plot_ly(dat, x = ~Value, y = ~Country,
type = 'bar', orientation = 'h',
hovertemplate = paste('%{y}', '<br>Value: %{x}<br>'),
marker = list(color = 'green')
)
fig1 <- fig1 %>% layout(
yaxis = list(title="",showgrid = FALSE, showline = FALSE, showticklabels = TRUE, domain= c(0, 0.85)),
xaxis = list(title="",zeroline = FALSE, showline = FALSE, showticklabels = FALSE, showgrid = FALSE))
fig1 <- fig1 %>% add_annotations(xref = 'x1', yref = 'y',
x = dat$Value* 1.1 + 0.5, y = dat$Country,
text = paste(round(dat$Value, 2), '%'),
font = list(family = 'Arial', size = 12, color = 'black'),
showarrow = FALSE)
fig1
})
output$plot <- renderUI({
plotlyOutput("bar1")
})
}
shinyApp(ui = ui, server = server)
Perhaps this will meet your needs.
library(shiny)
library(DT)
Country<-c("EU","CHE","ITA")
Value<-c(3,2,1)
dat<-data.frame(Country,Value)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton("exc", "Exchange")
),
mainPanel(
uiOutput(outputId = "plot")
)
)
)
server <- function(input, output) {
excplot <- reactiveVal(TRUE)
observeEvent(input$exc, {
excplot(!excplot())
})
output[["bar1"]]<-renderPlotly({
if (excplot()) {
dat$xvar <- dat$Value
dat$yvar <- dat$Country
hv <- "h"
myyaxis = list(title="",showgrid = FALSE, showline = FALSE, showticklabels = TRUE, domain= c(0, 0.85) )
myxaxis = list(title="",zeroline = FALSE, showline = FALSE, showticklabels = FALSE, showgrid = FALSE)
xx <- dat$xvar*1.1 + 0.1
yy <- dat$yvar
}else {
dat$yvar <- dat$Value
dat$xvar <- dat$Country
hv <- "v"
myxaxis = list(title="",showgrid = FALSE, showline = FALSE, showticklabels = TRUE, domain= c(0, 0.85) )
myyaxis = list(title="",zeroline = FALSE, showline = FALSE, showticklabels = FALSE, showgrid = FALSE)
xx <- dat$xvar
yy <- dat$yvar*1.1 + 0.1
}
fig1 <- plot_ly(dat, x = ~xvar, y = ~yvar,
type = 'bar', orientation = hv,
hovertemplate = paste('%{y}', '<br>Value: %{x}<br>'),
marker = list(color = 'green')
)
fig1 <- fig1 %>% layout(yaxis = myyaxis, xaxis = myxaxis )
fig1 <- fig1 %>% add_annotations(xref = 'x1', yref = 'y',
x = xx , y = yy,
text = paste(round(dat$Value, 2), '%'),
font = list(family = 'Arial', size = 12, color = 'black'),
showarrow = FALSE)
fig1
})
output$plot <- renderUI({
plotlyOutput("bar1")
})
}
shinyApp(ui = ui, server = server)

Selecting many items from the list in R

I created an application in Shiny where I would like to choose multiple items from the drop-down menu. Unfortunately, I don't know how to make items on the list reduce after a given menu selection. By which all lines merge into a whole. what should I add in the code so that each model is a separate line. Below I put a picture with charts.
My code:
library(shiny)
library(plotly)
library(readxl)
library(shinyWidgets)
library(shinydashboard)
library(shinyjs)
library(DT)
df1 <- data.frame(Month = rep(month.abb[1:12],10,replace = TRUE), Model = paste0('Ferrari ', rep(LETTERS[1:10], each = 12)),
Value = sample(c(0:300),120, replace = T),
Car = rep('Ferrari', 10,each = 12), Year = rep(2019:2020, each = 60),Country = rep(c("USA","DE"), each = 12, times = 5), stringsAsFactors = F)
df2 <- data.frame(Month = rep(month.abb[1:12],10,replace = TRUE), Model = paste0('Porsche ', rep(LETTERS[1:10], each = 12)),
Value = sample(c(0:300),120, replace = T),
Car = rep('Porsche', 10,each = 12), Year = rep(2019:2020, each = 60), Country = rep(c("USA","DE"), each = 12, times = 5),stringsAsFactors = F)
data <-rbind(df1, df2)
ui <- fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel( width = 3,
uiOutput("category1"),
uiOutput("category2"),
uiOutput("category3"),
uiOutput("category4")),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotlyOutput("plot", height = 550,width = 1000))
)
)
)
)
server <- function(input, output,session) {
output$category1 <- renderUI({
selectInput('cat1', 'Choose year:', multiple = T, selected = NULL, choices = sort(as.numeric(unique(data$Year))))
})
df_subset <- eventReactive(input$cat1,{
if(input$cat1=="All") {df_subset <- data}
else{df_subset <- data[data$Year == input$cat1,]}
})
df_subset1 <- reactive({
if(is.null(input$cat2)){df_subset()} else {df_subset()[df_subset()$Country %in% input$cat2,]}
})
output$category2 <- renderUI({
selectInput('cat2', 'Choose country:', choices = sort(as.character(unique(df_subset()$Country))), multiple = T, selected = NULL)
})
df_subset2 <- reactive({
if(is.null(input$cat3)){df_subset1()} else {df_subset1()[df_subset1()$Car %in% input$cat3,]}
})
output$category3 <- renderUI({
selectInput('cat3', 'Choose car:', choices = sort(as.character(unique(df_subset1()$Car))), multiple = F, selected = NULL)
})
df_subset3 <- reactive({
if(is.null(input$cat4)){df_subset2()} else {df_subset2()[df_subset2()$Model %in% input$cat4,]}
})
output$category4 <- renderUI({
pickerInput('cat4', 'Choose model:', choices = sort(as.character(unique(df_subset2()$Model))), multiple = TRUE, selected = NULL)
})
output$plot <- renderPlotly({
xform <- list(categoryorder = "array",
categoryarray = df_subset3()$Month,
title = " ",
nticks=12)
plot_ly(data=df_subset3(), x=~Month, y = ~Value, type = 'scatter', mode = 'lines', name = 'Value') %>%
layout(title = " ",xaxis = xform) %>%
layout(legend = list(orientation = 'h', xanchor = "center", y=1.1, x=0.5))
})
}
shinyApp(ui, server)
To display each model as a separate line on the plot, you can assign the Model column of your dataset to the color parameter of plot_ly this way:
plot_ly( data = df_subset3(), x = ~Month, y = ~Value, color = ~Model, ...)

selectInput only outputs first option

I am writing a shiny app to manipulate daily percentage distributions of call arrivals per interval via drag and drop.
I am trying to display one day only via selectInput.
However, the DataTable Output and Plot Output do not change when I select another day than Monday (first option in selectInput), i.e., the outputs (datatable and plotly) only display Monday regardless of what I am selecting via selectInput.
Appreciate your help! Thank you in advance!
Dummy data:
save_name2 <- paste("Percentage_Forecasts.csv")
df_MON<-data.frame(b=c("MON 07:00","MON 07:30","MON 08:00","MON 08:30","MON 09:00","MON 09:30","MON 10:00"),a=c(15,20,14,6,10,15,20))
df_TUE<-data.frame(b=c("TUE 07:00","TUE 07:30","TUE 08:00","TUE 08:30","TUE 09:00","TUE 09:30","TUE 10:00"),a=c(15,20,14,6,10,15,20))
df_WED<-data.frame(b=c("WED 07:00","WED 07:30","WED 08:00","WED 08:30","WED 09:00","WED 09:30","WED 10:00"),a=c(15,20,14,6,10,15,20))
df_THU<-data.frame(b=c("THU 07:00","THU 07:30","THU 08:00","THU 08:30","THU 09:00","THU 09:30","THU 10:00"),a=c(15,20,14,6,10,15,20))
df_FRI<-data.frame(b=c("FRI 07:00","FRI 07:30","FRI 08:00","FRI 08:30","FRI 09:00","FRI 09:30","FRI 10:00"),a=c(15,20,14,6,10,15,20))
df_SAT<-data.frame(b=c("SAT 07:00","SAT 07:30","SAT 08:00","SAT 08:30","SAT 09:00","SAT 09:30","SAT 10:00"),a=c(15,20,14,6,10,15,20))
Here is my ui.R:
ui <- fluidPage( titlePanel("Prozentuale Verteilung Prognosewoche"),
fluidRow(
column(selectInput(inputId = "dataset",
label = "Choose a weekday",
choices = c("MON", "TUE","WED","THU","FRI","SAT")),
DTOutput("table"),width = 5,downloadButton("downloadData", "Save")),
column(12, plotlyOutput("p"))))
Here is my server.R:
server <- function(input, output, session) {
#i think here is where the problem starts!
datasetInput <- reactive({
switch(input$dataset,
"MON" = df_MON,
"TUE" = df_TUE,
"WED" = df_WED,
"THU" = df_THU,
"FRI" = df_FRI,
"SAT" = df_SAT)
})
rv <- reactiveValues(
x = isolate(datasetInput())$b,
y = isolate(datasetInput())$a)
grid <- reactive({
data.frame(y = rv$y, length=180)})
output$p <- renderPlotly({
circles <- map2(rv$x,
rv$y,
~list(
type = "circle",
xanchor = .x,
yanchor = .y,
x0 = -4, x1 = 4,
y0 = -4, y1 = 4,
xsizemode = "pixel",
ysizemode = "pixel",
# other visual properties
fillcolor = "orange",
line = list(color = "transparent") ) )
plot_ly(grid(), type="scatter", mode='lines+markers', width = 1200, height = 300) %>%
add_trace(y = grid()$y, x = isolate(datasetInput())$b,mode='lines+markers') %>%
layout(shapes = circles) %>%
config(edits = list(shapePosition = TRUE))
})
output$table <-renderDT(rbind({data.frame(rv$x,rv$y)}, c(NULL,sum(rv$y))),colnames=c("Weekday/Time", "Percentage"),width = 800,options = list(
lengthMenu = list(c(15,31), list('15','31')),
pageLength = 15, initComplete = JS(
"function(settings, json) {",
"$(this.api().table().body()).css({'font-size': '70%'});",
"}")
))
observe({
ed <- event_data("plotly_relayout")
shape_anchors <- ed[grepl("^shapes.*anchor$", names(ed))]
if (length(shape_anchors) != 2) return()
row_index <- unique(readr::parse_number(names(shape_anchors)) + 1)
pts <- as.numeric(shape_anchors)
rv$y[row_index] <- pts[2]
})
output$downloadData <- downloadHandler(
filename = function(){save_name2},
content = function(fname){
write.table(data.frame(rv$x,rv$y), row.names=FALSE, sep=";", fname,col.names=c("Weekday/Calendar Week","Percentage"))
})
}
shinyApp(ui, server)
I edited these parts and removed the isolate's:
rv <- reactiveValues()
observe({
rv$x = datasetInput()$b
rv$y = datasetInput()$a
})
and
add_trace(y = grid()$y, x = rv$x,mode='lines+markers')
Full server code:
server <- function(input, output, session) {
#i think here is where the problem starts!
datasetInput <- reactive({
switch(input$dataset,
"MON" = df_MON,
"TUE" = df_TUE,
"WED" = df_WED,
"THU" = df_THU,
"FRI" = df_FRI,
"SAT" = df_SAT)
})
rv <- reactiveValues()
observe({
rv$x = datasetInput()$b
rv$y = datasetInput()$a
})
grid <- reactive({
data.frame(y = rv$y, length=180)})
output$p <- renderPlotly({
circles <- map2(rv$x,
rv$y,
~list(
type = "circle",
xanchor = .x,
yanchor = .y,
x0 = -4, x1 = 4,
y0 = -4, y1 = 4,
xsizemode = "pixel",
ysizemode = "pixel",
# other visual properties
fillcolor = "orange",
line = list(color = "transparent") ) )
plot_ly(grid(), type="scatter", mode='lines+markers', width = 1200, height = 300) %>%
add_trace(y = grid()$y, x = rv$x,mode='lines+markers') %>%
layout(shapes = circles) %>%
config(edits = list(shapePosition = TRUE))
})
output$table <-renderDT(rbind({data.frame(rv$x,rv$y)}, c(NULL,sum(rv$y))),colnames=c("Weekday/Time", "Percentage"),width = 800,options = list(
lengthMenu = list(c(15,31), list('15','31')),
pageLength = 15, initComplete = JS(
"function(settings, json) {",
"$(this.api().table().body()).css({'font-size': '70%'});",
"}")
))
observe({
ed <- event_data("plotly_relayout")
shape_anchors <- ed[grepl("^shapes.*anchor$", names(ed))]
if (length(shape_anchors) != 2) return()
row_index <- unique(readr::parse_number(names(shape_anchors)) + 1)
pts <- as.numeric(shape_anchors)
rv$y[row_index] <- pts[2]
})
output$downloadData <- downloadHandler(
filename = function(){save_name2},
content = function(fname){
write.table(data.frame(rv$x,rv$y), row.names=FALSE, sep=";", fname,col.names=c("Weekday/Calendar Week","Percentage"))
})
}
shinyApp(ui, server)

R shiny plotly width and height don't update

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)

Resources