我不确定您是否希望使用滑块来筛选
数据点(即仅显示从滑块选择的年份开始的数据点),还是根据滑块的值以不同颜色显示年份。
情况1(仅显示特定年份的数据点)
data %>%
ggvis(~x, ~y, size=~count) %>%
layer_points(opacity=input_slider(min(data$year), max(data$year), step=1,
map=function(x) ifelse(data$year == x, 1, 0)))
案例2(突出显示所选年份)
data %>%
ggvis(~x, ~y, size=~count) %>%
layer_points(fill=input_slider(min(data$year), max(data$year), step=1,
map=function(x) factor(x == data$year)))
编辑2:如何简单包装left_right()
函数。
在第一次编辑中,我提供了一个解决方案,它不能被正确地认为是“包装”。 我想创建一个反应性对象的包装器,避免完全修改create_keyboard_event
。
在更全面地阅读了ggvis
的源代码和更多关于R中S4对象的内容之后,
我意识到,是的,您可以简单地包装一个反应性对象,只要适当地保留broker
类及其broker
属性。
这使我们能够编写更优雅的代码,例如:
year_lr <- left_right(1997, 2002, value=2000, step=1)
year_wrapper <- reactive({
as.numeric(year_lr() == data$year)
})
class(year_wrapper) <- c("broker", class(year_wrapper))
attr(year_wrapper, "broker") <- attr(year_lr, "broker")
data %>%
ggvis(~x, ~y, size=~count) %>%
layer_points(opacity:=year_wrapper)
编辑:如何创建自己的(修改后的)left_right()
函数
用户3389288问了我一个好问题,就是既然您的left_right()
函数没有map
参数,那么如何绑定键盘事件以生成自定义参数呢?例如,在这个问题的上下文中,我们如何将left_right()
调整为年份过滤器?
如果您深入研究ggvis
的源代码,您会发现left_right()
只是一个简单的包装函数,调用了create_keyboard_event
。
因此,我们可以创建自己版本的left_right()
,甚至是h_j_k_l()
,比如说如果您是Vi的狂热者。但是,有一个大的限制,如果您深入一层来查看create_keyboard_event
的实现,您会发现它并不完全适合我们的任务。
这是因为为了显示部分点,同时隐藏其他点,我们必须让left_right()
返回一个vector
(等于data
行数)。然而,left_right()
和create_keyboard_event()
都假设返回值(也是通过左/右键按下修改的value
的当前状态)是一个标量。
为了将返回值(向量)与缓存的当前状态(标量,即年份)分开,我们必须创建一个稍微修改过的版本的left_right()
和create_keyboard_event()
。
下面是可行的源代码。
data <- data.frame(year=rep(1997:2002, each=12),
x=rnorm(24*3,10), y=rnorm(24*3,10),
count=c(rnorm(24,2), rnorm(24,4), rnorm(24,6)))
create_keyboard_event2 <- function(map, default.x = NULL, default.res = NULL) {
if (!is.function(map)) stop("map must be a function")
vals <- shiny::reactiveValues()
vals$x <- default.x
vals$res <- default.res
res <- reactive({
vals$res
})
connect <- function(session, plot_id) {
key_press_id <- paste0(plot_id, "_key_press")
shiny::observe({
key_press <- session$input[[key_press_id]]
if (!is.null(key_press)) {
current_value <- shiny::isolate(vals$x)
updated <- map(key_press, current_value)
vals$x <- updated$x
vals$res <- updated$res
}
})
}
ggvis:::connector_label(connect) <- "key_press"
spec <- list(type = "keyboard")
ggvis:::create_broker(res, connect = connect, spec = spec)
}
left_right_year <- function(min, max, value = (min + max) / 2,
step = (max - min) / 40, year) {
map <- function(key_press, current_value) {
key <- key_press$value
print(current_value)
if (key == "left") {
new_value <- pmax(min, current_value - step)
} else if (key == "right") {
new_value <- pmin(max, current_value + step)
} else {
new_value = current_value
}
list(x=new_value, res=as.numeric(year == new_value))
}
create_keyboard_event2(map, value, as.numeric(value==year))
}
alpha_by_year <- left_right_year(1997, 2002, value=2000, step=1, data$year)
data %>%
ggvis(~x, ~y, size=~count) %>%
layer_points(opacity:=alpha_by_year)
您可以将left_right_year
和create_keyboard_event2
与它们的原始版本进行比较。
例如,原始的create_keyboard_event
是:
create_keyboard_event <- function(map, default = NULL) {
if (!is.function(map)) stop("map must be a function")
vals <- shiny::reactiveValues()
vals$x <- default
res <- reactive({
vals$x
})
connect <- function(session, plot_id) {
key_press_id <- paste0(plot_id, "_key_press")
shiny::observe({
key_press <- session$input[[key_press_id]]
if (!is.null(key_press)) {
current_value <- shiny::isolate(vals$x)
vals$x <- map(key_press, current_value)
}
})
}
connector_label(connect) <- "key_press"
spec <- list(type = "keyboard")
create_broker(res, connect = connect, spec = spec)
}
您可以看到,我们修改后的版本不仅缓存了当前状态的
vals$x
,还缓存了返回向量
vals$res
。
vals
是一种反应式值。这个概念来源于Shiny。您可以查看这篇文档,了解有关反应式值和整体反应性的高级概述。
有待回答的问题
由于vals$x
本身是一个反应式值。直观地说,如果
x <- left_right(1, 100, value=20, step=10)
那么
y <- reactive(x() * 2)
应该让我们能够实现快速的map
函数。
然而它并没有像预期的那样工作。我还没有弄清楚为什么。如果您知道答案,请友情提供!
更新:请参见EDIT2。
df = data.frame(year=rep(2000:2002, each=23), x=rnorm(23*3,10), y=rnorm(23*3,10), count=c(rnorm(23,2),rnorm(23,4),rnorm(23,6)))
- eipi10