How to update value of sliderInput with height value from draggable plot? - r

I'm trying to get the value of a resizable plot (using shinyjqui) and use it to update the sliderInput. I am able to get the value however, but I'm unable to update it to the sliderInput. I tried using observe and observeEvent but I'm stuck.
Code
library(shiny)
library(shinyjqui)
library(ggplot2)
ui <- fluidPage(
tags$p("Height value from draggable plot"),
verbatimTextOutput('size_obj'),
# textInput("plotsize", label = "Plot height", value = "300"),
sliderInput("plotsize", label = "Plot height", value = 300, min = 200, max = 500),
tabsetPanel(
id = 'tabs',
tabPanel(
title = 'ggplot',
jqui_resizable(plotOutput('gg'))
)
)
)
server <- function(input, output, session) {
output$gg <- renderPlot({
ggplot(mtcars, aes(x = cyl, y = mpg)) + geom_point()
},
height=exprToFunction(as.numeric(input$plotsize))
)
# observe({
# size_obj()
# updateTextInput(session, "plotsize", value = size_obj())
# })
output$size_obj <- renderPrint({
name <- paste0('gg', '_size')
cat(#sprintf('%s(height: %s',
# input$tabs,
input[[name]]$height)
# input[[name]]$width))
})
}
shinyApp(ui, server)
If you drag the plot from the bottom right, you will notice the verbatimTextOutput change. Once the drag event is over, it goes to the default value. I would like to reverse this and make it so that the slider changes to the value of the verbatimTextOutput so that when I drag to a different height, the sliderInput updates to the new height value.

You want to do this:
library(shiny)
library(shinyjqui)
library(ggplot2)
ui <- fluidPage(
tags$p("Height value from draggable plot"),
verbatimTextOutput('size_obj'),
# textInput("plotsize", label = "Plot height", value = "300"),
sliderInput("plotsize", label = "Plot height", value = 300, min = 200, max = 500),
tabsetPanel(
id = 'tabs',
tabPanel(
title = 'ggplot',
jqui_resizable(plotOutput('gg', height = "300px"))
)
)
)
server <- function(input, output, session) {
name <- paste0('gg', '_size')
height <- reactive({
if(is.null(input[[name]]$height)) 300
else as.numeric( input[[name]]$height)
})
output$gg <- renderPlot({
updateTextInput(session, "plotsize", value = height())
ggplot(mtcars, aes(x = cyl, y = mpg)) + geom_point()
},
height=exprToFunction(height())
)
# observe({
# size_obj()
# updateTextInput(session, "plotsize", value = size_obj())
# })
output$size_obj <- renderPrint({
cat(#sprintf('%s(height: %s',
# input$tabs,
input[[name]]$height)
# input[[name]]$width))
})
}
shinyApp(ui, server)

Related

how to add a logarithmic widget to plotly scatter plot in shiny?

I am struggling with getting the code to work for this log widget I want to add to my interactive plot in shiny. I am able to modify the graphs x and y axis to a log scale by adding log(dat()[[input$yvrbl]]) to the server coder
server <- function(input, output) {
x <- reactive({
log(dat()[[input$yvrbl]])
})
y <- reactive({
log(dat()[[input$yvrbl]])
})
I was able to create the widgets on the ui code as well. I am still unable to transform the data to the log version based on whether or not the widget is checked. I tried making a separate reactive expression to host the changed log version of the x and y axis depending on an if statement. Please let me know what else I can do.
library(shiny)
library(plotly)
library(tibble)
library(tidyverse)
library(tidyr)
library(readr)
library(dplyr)
library(ggplot2)
# set working directory
setwd("~/BDSWD")
#read data
gm <- read_csv("gapminder_clean.csv")
# Define UI ----
ui <- fluidPage(
column(3,offset = 4, titlePanel("Explore Gapminder Data with Shiny")),
headerPanel('Graphs'),
mainPanel(
plotlyOutput('plot')
),
sidebarPanel(
#variable selection for x-axis
selectInput(inputId ='xvrbl', #The input slot that will be used to access the value.
label = 'X-Axis Variable', #Display label for the control, or NULL for no label.
choices = colnames(gm), #List of values to select from
selected = 'CO2 emissions (metric tons per capita)'
),
checkboxInput(inputId = "LogX",
label = "Log Transform",
value = FALSE),
#variable selection for y-axis
selectInput(inputId ='yvrbl', #The input slot that will be used to access the value.
label = 'Y-Axis Variable', #Display label for the control, or NULL for no label.
choices = colnames(gm), #List of values to select from
selected = 'gdpPercap'
),
checkboxInput(inputId = "LogY",
label = "Log Transform",
value = FALSE),
#date range - slider
sliderInput(inputId = "time",
label = "Years",
min = min(gm$Year),
max = max(gm$Year),
step = 5,
value = c(min(gm$Year),max(gm$Year)))
)
)
server <- function(input, output) {
x <- reactive({
dat()[[input$xvrbl]]
})
y <- reactive({
dat()[[input$yvrbl]]
})
dat <- reactive({
subset(gm, Year %in% input$time)
})
lgrthmc <- reactive({
if(isTRUE(input$LogY)) {
y <- reactive({
log(dat()[[input$yvrbl]])
})
} else {}
if(isTRUE(input$LogX)) {
x <- reactive({
log(dat()[[input$xvrbl]])
})
} else {}
})
output$plot <- renderPlotly({
plot_ly(
x = x(),
y = y(),
type = "scatter",
mode = "markers",
color = dat()$continent
) %>%
layout(
title = 'Gapminder Dataset',
plot_bgcolor = "#e5ecf6",
xaxis = list(title = input$xvrbl),
yaxis = list(title = input$yvrbl),
legend = list(title=list(text='<b> Continent </b>'))
)
})
}
# Run the app
shinyApp(ui = ui, server = server)
Instead of wrapping reactives inside a reactive you could achieve your desired result by adding an if inside your reactives, e.g.
Note: I slightly adjusted the subsetting of your data to take the sliderInput into account.
x <- reactive({
x <- dat()[[input$xvrbl]]
if (input$LogX) x <- log(x)
return(x)
})
library(gapminder)
library(shiny)
library(plotly)
library(tidyverse)
gm <- gapminder |> rename(Year = year)
# Define UI ----
ui <- fluidPage(
column(3, offset = 4, titlePanel("Explore Gapminder Data with Shiny")),
headerPanel("Graphs"),
mainPanel(
plotlyOutput("plot")
),
sidebarPanel(
# variable selection for x-axis
selectInput(
inputId = "xvrbl", # The input slot that will be used to access the value.
label = "X-Axis Variable", # Display label for the control, or NULL for no label.
choices = colnames(gm), # List of values to select from
selected = "lifeExp"
),
checkboxInput(inputId = "LogX",
label = "Log Transform",
value = FALSE),
# variable selection for y-axis
selectInput(
inputId = "yvrbl", # The input slot that will be used to access the value.
label = "Y-Axis Variable", # Display label for the control, or NULL for no label.
choices = colnames(gm), # List of values to select from
selected = "gdpPercap"
),
checkboxInput(
inputId = "LogY",
label = "Log Transform",
value = FALSE
),
# date range - slider
sliderInput(
inputId = "time",
label = "Years",
min = min(gm$Year),
max = max(gm$Year),
step = 5,
value = range(gm$Year)
)
)
)
server <- function(input, output) {
x <- reactive({
x <- dat()[[input$xvrbl]]
if (input$LogX) x <- log(x)
return(x)
})
y <- reactive({
y <- dat()[[input$yvrbl]]
if (input$LogY) y <- log(y)
return(y)
})
dat <- reactive({
subset(gm, Year >= input$time[[1]], Year <= input$time[[2]])
})
output$plot <- renderPlotly({
plot_ly(
x = x(),
y = y(),
type = "scatter",
mode = "markers",
color = dat()$continent
)
})
}
# Run the app
shinyApp(ui = ui, server = server)
#>
#> Listening on http://127.0.0.1:6593

Unsupported index type: NULL --> plotly chart in shiny

I am getting an error with the plotting index using plotly in conjunction with reactive values in shiny. The sidebar panel loads with no issues but there is a problem displaying the chart that I cannot determine. Any help solving the index problem would be much appreciated. Thanks!
library(shiny)
library(plotly)
data(economics, package = "ggplot2")
nms <- names(economics)
ui <- fluidPage(
headerPanel("TEST"),
sidebarPanel(
selectInput('x', 'X', choices = nms, selected = nms[[1]]),
selectInput('y', 'Y', choices = nms, selected = nms[[2]]),
sliderInput('plotHeight', 'Height of plot (in pixels)',
min = 100, max = 2000, value = 1000)
),
mainPanel(
plotlyOutput('trendPlot', height = "900px")
)
)
server <- function(input, output) {
#add reactive data information. Dataset = built in diamonds data
dataset <- reactive({economics[, c(input$xcol, input$ycol)]
})
output$trendPlot <- renderPlotly({
# build graph with ggplot syntax
p <- ggplot(dataset(), aes_string(x = input$x, y = input$y)) +
geom_line()
ggplotly(p) %>%
layout(height = input$plotHeight, autosize=TRUE)
})
}
shinyApp(ui, server)
Warning: Error in : Unsupported index type: NULL
You have mistakenly used xcol and ycol not sure why. Without those names the code works fine.
library(shiny)
library(plotly)
library(tidyverse)
data(economics, package = "ggplot2")
nms <- names(economics)
ui <- fluidPage(
headerPanel("TEST"),
sidebarPanel(
selectInput('x', 'X', choices = nms, selected = nms[[1]]),
selectInput('y', 'Y', choices = nms, selected = nms[[2]]),
sliderInput('plotHeight', 'Height of plot (in pixels)',
min = 100, max = 2000, value = 1000)
),
mainPanel(
plotlyOutput('trendPlot', height = "900px")
)
)
server <- function(input, output) {
#add reactive data information. Dataset = built in diamonds data
dataset <- reactive({
economics[, c(input$x, input$y)]
})
output$trendPlot <- renderPlotly({
# build graph with ggplot syntax
p <- ggplot(dataset(), aes_string(input$x, input$y)) +
geom_line()
ggplotly(p, height = input$plotHeight)
})
}
shinyApp(ui, server)

Select which plot to display in a shiny app based on user choice

I have a shiny app which generates 2 plots and one table. As you will see I want to select which one of them will be displayed every time based on the radiobuttons() input. Until now I get an error object of type 'closure' is not subsettable Which object exactly is of type closure? Note that the first is a ggplot object the second is a plotly object and the third a datatable.
# ui.R
library(shiny)
library(plotly)
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
uiOutput("filter_degree")
),
mainPanel(
uiOutput('plot')
)
)
#server.r
function(input, output, session) {
output$filter_degree<-renderUI({
radioButtons("rd","Select Option",choices = c("Mileage","Regression",'Table'),
selected = "Mileage")
})
output$plot <- renderUI({
if(input$rd=="Mileage"){
output$plot1<-renderUI({
# Boxplots of mpg by number of gears
# observations (points) are overlayed and jittered
qplot(gear, mpg, data=mtcars, geom=c("boxplot", "jitter"),
fill=gear, main="Mileage by Gear Number",
xlab="", ylab="Miles per Gallon")
})
}
else if(input$rd=="Regression"){
output$plot2<-renderUI({
x <- c(1:100)
random_y <- rnorm(100, mean = 0)
data <- data.frame(x, random_y)
p <- plot_ly(data, x = ~x, y = ~random_y, type = 'scatter', mode = 'lines')
})
}
else if(input$rd=="Table"){
output$tbl = DT::renderDataTable(datatable(
iris, options = list(lengthChange = FALSE,scrollY = T, scroller = TRUE, scrollX = T),selection = list(target="cell",mode="single"),rownames = F)
)
}
})
}
You need to provide the plot/table output as part of the if/then sequence (plotOutput("plot1"), etc.). Otherwise, it has nothing to render. Also, there appears to be an error in the ploty call, but I haven't fixed it for you.
library(shiny)
library(DT)
library(plotly)
ui <- pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
uiOutput("filter_degree")
),
mainPanel(
uiOutput('plot')
)
)
#server.r
server <- function(input, output, session) {
output$filter_degree<-renderUI({
radioButtons("rd","Select Option",choices = c("Mileage","Regression",'Table'),
selected = "Mileage")
})
output$plot <- renderUI({
if(input$rd=="Mileage"){
output$plot1<-renderPlot({
# Boxplots of mpg by number of gears
# observations (points) are overlayed and jittered
qplot(gear, mpg, data=mtcars, geom=c("boxplot", "jitter"),
fill=gear, main="Mileage by Gear Number",
xlab="", ylab="Miles per Gallon")
})
plotOutput("plot1")
}
else if(input$rd=="Regression"){
output$plot2<-renderUI({
x <- c(1:100)
random_y <- rnorm(100, mean = 0)
data <- data.frame(x, random_y)
p <- plot_ly(data, x = ~x, y = ~random_y, type = 'scatter', mode = 'lines')
})
plotlyOutput("plot2")
}
else if(input$rd=="Table"){
output$tbl = DT::renderDataTable(datatable(
iris, options = list(lengthChange = FALSE,scrollY = T, scroller = TRUE, scrollX = T),selection = list(target="cell",mode="single"),rownames = F)
)
dataTableOutput("tbl")
}
})
}
shinyApp(ui = ui, server = server)

R Shiny Flexdashboard ValueBox in Column layout

I need to align some elements in a column layout in a Shinydashboard which combines some elements from flexdashboard. Here's the code:
library(shiny)
library(shinydashboard)
library(flexdashboard)
ui <- dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(),
dashboardBody(
column(3,flexdashboard::valueBoxOutput("ValueBox")),
#flexdashboard::valueBoxOutput("ValueBox"),
column(3,plotOutput("plot1",height = 150)),
column(6,h3("Gauges"),
fluidRow(
column(3,flexdashboard::gaugeOutput("Gauge1")),
column(3,flexdashboard::gaugeOutput("Gauge2"))
)
)
)
)
server <- function(input, output) {
output$ValueBox <- renderValueBox({
shinydashboard::valueBox(
value = 100,
subtitle = "Value",
icon = icon("area-chart"),
color = "aqua"
)
})
set.seed(122)
histdata <- rnorm(500)
output$plot1 <- renderPlot({
data <- histdata
hist(data)
})
output$Gauge1 <- flexdashboard::renderGauge({
gauge(60, min = 0, max = 100, symbol = "%")
})
output$Gauge2 <- flexdashboard::renderGauge({
gauge(25, min = 0, max = 100, symbol = "%")
})
}
shinyApp(ui, server)
This produces the output where the value box only fills approximately a third of the space designed for it:
When I change the valueBoxOutput to be outside of a column (comment out the first and uncomment the second line in the dashboardBody), the valuebox does fill the full allocated space, but the "Gauge" output is forced on another line rather than to the right:
How do I force the "combination" of the two approaches so that the result looks something like this?
I have tried the following without success:
Use the shinydashboard::valueBoxOutput instead
Utilize the width argument of column as well as valueBoxOutput commands
After experimenting with column widths based on ismirsehregal's answer, I have discovered what the issue was.
The UI part is correct and both ways are capable of producing the result. The issue was that the definition inside renderValueBox did not specify the width argument, which was by default set to 4 and represents the relative width compared to the parental environment. Thus, in the first case, the box takes 4/12 of the column of width 3. In the second case, the output had a width of 4+3+6=13, which is higher than 12 and hence was broken into two lines.
The following definition solves the problem:
output$ValueBox <- renderValueBox({
shinydashboard::valueBox(
value = 100,
subtitle = "Value",
icon = icon("area-chart"),
color = "aqua",
width = 12
)
})
The width = 12 sets the box to fill out the whole width of the parental environment, which in this case is a column of width 3. One can also use width = 3 directly and drop out the column definition, but the first way is preferred as the width of all three elements is specified in the UI rather than the server.
This works for me:
library(shiny)
library(shinydashboard)
library(flexdashboard)
ui <- dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(),
dashboardBody(
flexdashboard::valueBoxOutput("ValueBox", width = "100%"), # Edit %
#flexdashboard::valueBoxOutput("ValueBox"),
column(4,plotOutput("plot1",height = 150)),
column(4,h3("Gauges"),
fluidRow(
column(6,flexdashboard::gaugeOutput("Gauge1")),
column(6,flexdashboard::gaugeOutput("Gauge2"))
)
)
)
)
server <- function(input, output) {
output$ValueBox <- renderValueBox({
shinydashboard::valueBox(
value = 100,
subtitle = "Value",
icon = icon("area-chart"),
color = "aqua"
)
})
set.seed(122)
histdata <- rnorm(500)
output$plot1 <- renderPlot({
data <- histdata
hist(data)
})
output$Gauge1 <- flexdashboard::renderGauge({
gauge(60, min = 0, max = 100, symbol = "%")
})
output$Gauge2 <- flexdashboard::renderGauge({
gauge(25, min = 0, max = 100, symbol = "%")
})
}
shinyApp(ui, server)
So here is the preferred way based on Radek Janhuba's insights - setting the appropriate width while rendering (for everyone going here later):
library(shiny)
library(shinydashboard)
library(flexdashboard)
ui <- dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(),
dashboardBody(
column(4,flexdashboard::valueBoxOutput("ValueBox")),
column(4,plotOutput("plot1",height = 150)),
column(4,h3("Gauges"),
fluidRow(
column(6,flexdashboard::gaugeOutput("Gauge1")),
column(6,flexdashboard::gaugeOutput("Gauge2"))
)
)
)
)
server <- function(input, output) {
output$ValueBox <- renderValueBox({
shinydashboard::valueBox(
value = 100,
subtitle = "Value",
icon = icon("area-chart"),
color = "aqua",
width = 12
)
})
set.seed(122)
histdata <- rnorm(500)
output$plot1 <- renderPlot({
data <- histdata
hist(data)
})
output$Gauge1 <- flexdashboard::renderGauge({
gauge(60, min = 0, max = 100, symbol = "%")
})
output$Gauge2 <- flexdashboard::renderGauge({
gauge(25, min = 0, max = 100, symbol = "%")
})
}
shinyApp(ui, server)

Shiny nearPoints() with slider input

I was wondering if I can get rows data using nearPoints() from an interactive graph with slider input. My app.R file looks like:
library('shiny')
library('ggplot2')
dt <-read.csv('file.csv')
ui <- fluidPage(
plotOutput("plot1", height = 550, click = "plot1_click"),
fluidRow(
column(3,
sliderInput("Obs", "Number of Books", min = 1, max = nrow(up), value = 50)
),
column(3, offset = 3,
h4("Legends"),
verbatimTextOutput("selected")
)
)
)
server <- function(input, output) {
mydata <- reactive({
dt[1:as.numeric(input$Obs),]
})
output$plot1 <- renderPlot({
test <- mydata()
ggplot(data = test, aes(x = test[,2], y = test[,1])) + geom_point()
})
output$selected <- renderPrint({
file <- mydata()
nearPoints(file, input$plot1_click, threshold = 10, maxpoints = 1,
addDist = FALSE)
})
}
shinyApp(ui = ui, server = server)
Shiny nearPoints() is working perfectly without this slider input. When I used slider input, I can't get the row data until max. Is there any approach to work with the slider input? Any help is appreciated.
The following code works for me. It seems nearPoints is not able to tell which columns of your dataset are displayed because of the aes(x = test[,2], y = test[,1]) statement. Another possible fix sould be to set the parameters xvar and yvar in nearPoints.
library('shiny')
library('ggplot2')
dt <-mtcars
ui <- fluidPage(
plotOutput("plot1", height = 550, click = "plot1_click"),
fluidRow(
column(3,
sliderInput("Obs", "Number of Cars", min = 1, max = nrow(dt), value = 50)
),
column(3, offset = 3,
h4("Legends"),
verbatimTextOutput("selected")
)
)
)
server <- function(input, output) {
mydata <- reactive({
dt[1:as.numeric(input$Obs),]
})
output$plot1 <- renderPlot({
test <- mydata()
ggplot(data = test, aes(mpg, wt)) + geom_point()
})
output$selected <- renderPrint({
file <- mydata()
nearPoints(file, input$plot1_click, threshold = 100, maxpoints = 1,
addDist = FALSE)
})
}
shinyApp(ui = ui, server = server)
Quick note: Please try to make the code in your question reproducible by using one of the default datasets in R. You can get a list of all available datasets by calling data().

Resources