可以在此电影资源管理器示例中找到一个很好的示例,演示如何使用 selectizeInput 自定义 X/Y 轴变量。
但是,将函数包装ggvis()
在响应式环境中具有明显的缺点(或错误),即一旦更改input$xInp$
or input$yInp
,就会layer_smooths()
停止对滑块输入做出反应。
您的代码的另一个潜在问题data
是ui.R
. 您可能想要创建一个global.R
包含您的data
对象的文件。
下面我将介绍两种方法,说明如何ggvis
通过选择 X/Y 变量与绘图进行交互。您可以在 中找到它们server.R
。
全局.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"))
)
))
服务器.R
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")
})
两种方法都应该有效(好吧,几乎)。但是等等,一旦您更改 X/Y 变量,您可能会看到平滑层停止响应您的滑块更改。
要解决此问题,请考虑以下解决方案。
解决方法2的问题
我之前提到的错误可以通过创建一个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"))
)
))
服务器.R
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")
})
最后的话
包装ggvis
到反应式环境有一些缺点:
- 降低性能:因为一旦因输入变量发生变化,就需要重新绘制整个图形。
- 缺少过渡动画:因为整个图形是重绘的,所以您看不到在方法 1 中看到的漂亮的过渡效果。
但是,它确实有几个优点:
- 更高的灵活性:
ggvis
AFAIK 包装在反应式环境中是目前唯一的方法,如果你想动态地改变 XY 轴标签(比如说,取决于你的input$xInp
)。因为ggvis
只计算数据并将数据绑定到ggvis
对象一次,所以对轴标签所做的更改不会实时反映。但是,由于在响应式环境中包装ggvis
会导致整个图形重绘,因此标签也会在重绘中更新。