I'm having trouble getting an input slider to render in a ggvis plot within a shiny app. The plots render fine without the input slider but after adding it shiny throws this error:
Listening on http://xxxxxxxxxxxxxx
Error in eval(expr, envir, enclos) : could not find function "compdat"
server.R:
library(shiny)
library(ggvis)
data<-data.frame(var1=rnorm(30,5,2.3),var2=rbeta(30,1.5,.8),var3=rnorm(30,10,2.5))
shinyServer(function(input, output,session) {
compdat<-reactive({data[, c(input$xInp,input$yInp)]})
vis1 <-reactive({
compdat %>% ggvis(x= ~compdat()[,1],y= ~compdat()[,2]) %>%
layer_points(fill:="red") %>% layer_smooths(span=input_slider(.1,1,id="scores_ui"))
})
vis1 %>% bind_shiny("scores",controls_id="scores_ui")
vis2<-reactive({
compdat %>% ggvis(x= ~compdat()[,1],y= ~compdat()[,2]) %>%
layer_points(fill:="red") %>% ayer_smooths(span=input_slider(.1,1,id="loadings_ui"))
})
vis2 %>% bind_shiny("loadings",controls_id="loadings_ui")
})
ui.R:
shinyUI(fluidPage(
title="PCA Explorer",
h2("Principal Component Explorer"),
fluidRow(
column(6,ggvisOutput("scores"),
uiOutput("scores_ui")),
column(6,ggvisOutput("loadings"),
uiOutput("loadings_ui"))
),
br(),
fluidRow(
column(6,h3("Component Selection"),selectInput('xInp',"X Variable",names(data)),
selectInput('yInp',"Y Variable",names(data),selected=names(data)[[2]])),
column(6,h3("Summary of Selected Data Points"),verbatimTextOutput("diagn"))
)
))
Any insights on how to get the slider to render would be great. I've spen a fair amount of time digging around to figure this out. Thanks in advance
A nice example demonstrating how you can customize the X/Y-axis variables using a selectizeInput can be found here in this Movie Explorer example.
However, wrapping a ggvis()
function inside a reactive environment has prominent drawback (or a bug), that once you change the input$xInp$
or input$yInp
, the layer_smooths()
stop reacting to your slider input.
Another potential issue with your code is that the data
is not visible to ui.R
.
You probably want to create a global.R
file which contains your data
object.
Below I present two approaches on how you can interact with your ggvis
plot by selecting X/Y variables. You can find both of them in server.R
.
data <- data.frame(var1=rnorm(30,5,2.3),
var2=rbeta(30,1.5,.8),
var3=rnorm(30,10,2.5))
library(shiny)
shinyUI(fluidPage(
title="PCA Explorer",
h2("Principal Component Explorer"),
fluidRow(
column(6,
ggvisOutput("scores"),
uiOutput("scores_ui")),
column(6,
ggvisOutput("loadings"),
uiOutput("loadings_ui"))
),
br(),
fluidRow(
column(6,
h3("Component Selection"),
selectInput('xInp',"X Variable", choices=names(data),
selected=names(data)[[1]]),
selectInput('yInp',"Y Variable", choices=names(data),
selected=names(data)[[2]])
),
column(6,
h3("Summary of Selected Data Points"),
verbatimTextOutput("diagn"))
)
))
library(shiny)
library(ggvis)
shinyServer(function(input, output,session) {
# Approach 1: regenerate a compdat object once the input changes
# rename the X/Y variables to fixed names.
compdat <- reactive({
x <- data[, c(input$xInp, input$yInp)]
names(x) <- c("x", "y")
x
})
# NOTE that you use compdat here instead of compdat()
compdat %>% ggvis(x=~x, y=~y) %>%
layer_points(fill:="red") %>%
layer_smooths(span=input_slider(.1,1)) %>%
bind_shiny("scores", controls_id="scores_ui")
# Approach 2: wrap ggvis in a reactive environment
# This however, would stop to react to slider input
# once input$xInp or input$yInp changes.
vis2 <- reactive({
xvar <- prop("x", as.symbol(input$xInp))
yvar <- prop("y", as.symbol(input$yInp))
data %>% ggvis(x=xvar, y=yvar) %>%
layer_points(fill:="red") %>%
layer_smooths(span=input_slider(.1,1))
})
vis2 %>% bind_shiny("loadings", controls_id="loadings_ui")
})
Both approaches should work (well, almost). But wait, you may see that the smoothing layer stops responding to your slider changes once you change the X/Y variables.
To fix this issue, consider the solution below.
The bug that I mentioned earlier can be fixed by creating a sliderInput
in ui.R
.
library(shiny)
shinyUI(fluidPage(
title="PCA Explorer",
h2("Principal Component Explorer"),
fluidRow(
column(6,
ggvisOutput("scores"),
uiOutput("scores_ui")
),
column(6,
ggvisOutput("loadings"),
uiOutput("loadings_ui"),
# Create a slider by Shiny, instead of by ggvis.
sliderInput('smooth_span',
h5("Smoothing span for plot 2"),
.1, 1, value=0.5)
)
),
br(),
fluidRow(
column(6,
h3("Component Selection"),
selectInput('xInp',"X Variable", choices=names(data),
selected=names(data)[[1]]),
selectInput('yInp',"Y Variable", choices=names(data),
selected=names(data)[[2]])
),
column(6,
h3("Summary of Selected Data Points"),
verbatimTextOutput("diagn"))
)
))
library(shiny)
library(ggvis)
shinyServer(function(input, output,session) {
# Approach 1: regenerate a compdat object once the input changes
# rename the X/Y variables to fixed names.
compdat <- reactive({
x <- data[, c(input$xInp, input$yInp)]
names(x) <- c("x", "y")
x
})
# NOTE that you use compdat here instead of compdat()
compdat %>% ggvis(x=~x, y=~y) %>%
layer_points(fill:="red") %>%
layer_smooths(span=input_slider(.1,1)) %>%
bind_shiny("scores", controls_id="scores_ui")
# Approach 2: wrap ggvis in a reactive environment
# This however, would stop to react to slider input
# once input$xInp or input$yInp changes.
vis2 <- reactive({
xvar <- prop("x", as.symbol(input$xInp))
yvar <- prop("y", as.symbol(input$yInp))
smooth.span <- input$smooth_span
data %>% ggvis(x=xvar, y=yvar) %>%
layer_points(fill:="red") %>%
# FIXED: use the value from the input object, instead of a input_slider
layer_smooths(span=smooth.span)
})
vis2 %>% bind_shiny("loadings", controls_id="loadings_ui")
})
Wrapping ggvis
into a reactive environment has a few drawbacks:
However, it does have a few advantages:
ggvis
in a reactive environment is, AFAIK, currently the ONLY way if you want to change the X-Y axis label dynamically (say, depend on your input$xInp
). Because ggvis
only computes and binds data to the ggvis
object once, changes made to the axis labels won't be reflected in real time. However, because wrapping ggvis
in reactive environment causes the entire graph to redraw, somehow the labels are updated in the redraw as well.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With