使用ggvis显示信息

时间:2015-01-16 20:14:12

标签: r ggvis

我正在使用ggvis图创建一个闪亮的应用程序。我试图在鼠标移动到图表上的某个点后显示信息。如果我使用layer_points,则会正确显示有关特定点的数据。但是,如果我使用layer_bars,则即使数据集尚未更改,它也会显示值NULL

dfL %>% ggvis(x = ~time, y = ~amount) %>% layer_points() 
%>% add_tooltip(all_values, "hover") %>% bind_shiny("AnPlot", "AnPlot_ui")

^信息显示正确。

dfL %>% ggvis(x = ~time, y = ~amount) %>% layer_bars(width=1, fill:= "white") 
%>% add_tooltip(all_values, "hover") %>% bind_shiny("AnPlot", "AnPlot_ui")

^接收值为NULL。

以下是all_values的代码。

all_values <- function(x) {
  if(is.null(x)) return(NULL)
  paste0("Amount: ", format(x$amount, digits=4), 
  " Present Value: ", format(x$pv, digits=4), collapse = "<br />")
}

数据框dfL有三列:时间,pv和金额。我试图在这里只提供相关代码,但如果需要其他部分,我会编辑帖子并将其包含在内。

我无法弄清楚为什么当图表是散点图时它会返回正确的值,但是当它是条形图时无法返回值。

感谢您提供的任何见解!

2 个答案:

答案 0 :(得分:2)

这是一个棘手的问题,因为很遗憾,并非所有类型的layeradd_tooltip的{​​{1}}一样好。我不是100%清楚许多layer_points函数的所有实现细节,但我至少会引导您理解它,以便您了解我是如何达到我的解决方案的。我将使用ggvis数据集(默认情况下应在会话中提供)来演示,但您只需进行一些小的调整即可将方法应用于您自己的数据。

cars

我还将使用这个分组数据定义几个可视化 - library(dplyr) library(ggvis) ## my_data <- cars %>% group_by(speed) %>% summarize(avg_dist = mean(dist)) ## R> my_data Source: local data frame [19 x 2] speed avg_dist 1 4 6.00000 2 7 13.00000 3 8 16.00000 4 9 10.00000 5 10 26.00000 6 11 22.50000 7 12 21.50000 8 13 35.00000 9 14 50.50000 10 15 33.33333 11 16 36.00000 12 17 40.66667 13 18 64.50000 14 19 50.00000 15 20 50.40000 16 22 66.00000 17 23 54.00000 18 24 93.75000 19 25 85.00000 (条形图)和bar_obj(散点图);和一个函数point_obj,它将打印出传递给vis_names的数据对象的名称。

add_tooltip

bar_obj <- my_data %>% ggvis(x = ~speed, y = ~avg_dist) %>% layer_bars() ## point_obj <- my_data %>% ggvis(x = ~speed, y = ~avg_dist) %>% layer_points() ## vis_names <- function(x) { if(is.null(x)) return(NULL) paste0(names(x),collapse="<br />") } 内部打印出来的名称是一种很好的方法,可以准确找出传递的数据。对于add_tooltip,我们有:

point_obj

enter image description here

这是我输入数据的列名。另一方面,为point_obj %>% add_tooltip(vis_names,"hover") 执行此操作会给我们:

bar_obj

enter image description here

绝对不是bar_obj %>% add_tooltip(vis_names,"hover") 中的列名。如果我们定义另一个函数,

my_data

我们可以获得更多细节:

bar_info <- function(x) {
  if(is.null(x)) return(NULL) 

  paste(
    names(x)[1],
    x[1,1],
    names(x)[2],
    x[1,2],
    names(x)[3],
    x[1,3],
    names(x)[4],
    x[1,4],
    sep=" : ",
    collapse="<br />")
}

enter image description here

因此,bar_obj %>% add_tooltip(bar_info,"hover") xmin_显然是我们正在悬停的给定栏的x坐标,而xmax_stack_upr_是相应的y坐标。从这里开始,我们只需要一种方法将条形坐标转换回原始输入数据stack_lwr_

my_data中,我经常使用一个称为ggplot2的简洁函数。当您在ggplot_build对象上调用此函数时,它会创建绘图(就像打印通常那样),但也会返回有关构建绘图的所有内容的非常详细的信息 - 长轴范围,短轴范围等...当您需要找到有关图表的非常精确的信息时,这非常有用。我怀疑ggplot会有类似ggvis的内容,并通过小插图发现函数ggplot_build。在get_data对象上调用此方法会返回ggvis个列表,其中第一个元素是原始data.framedata.frame),第四个元素是{{1其中包含上面条形图中显示的四列 - my_datadata.framexmin_xmax_

从这里开始,我将定义一个最终函数,该函数将传递给stack_upr_以与stack_lwr_一起使用:

add_tooltip

这里有很多事情 - 它肯定不像bar_obj工具提示功能那样简洁,但它完成了工作。这一行

tooltip_bars <- function(x) {
  if(is.null(x)) return(NULL)

  bar_obj <- get("bar_obj",.GlobalEnv)

  input_data <- get_data(bar_obj)[[1]]
  bar_data <- get_data(bar_obj)[[4]]
  xmin_col <- bar_data[,3]

  row_idx <- which.min(abs(x[1,1]-xmin_col))

  paste0(
    paste0(names(input_data)[1],
           ": ",
           format(input_data[row_idx,1],4)), 
    paste0(names(input_data)[2],
           ": ",
           format(input_data[row_idx,2],4)), 
    collapse = "<br />")
}

从全局环境中抓取我们实际绘制的all_values对象的副本,并将其拉入我们的工具提示子功能的范围。接下来的两行,

bar_obj <- get("bar_obj",.GlobalEnv)

存储我们的输入数据集(相当于ggvis)和图中使用的条形坐标,即我们可以通过变量input_data <- get_data(bar_obj)[[1]] bar_data <- get_data(bar_obj)[[4]] 访问的内容。 my_data是定义条的左侧x坐标的值列。通过将此值与x中包含的xmin_col值进行比较,我们可以确定正在绘制哪一行数据,即

xmin_

对于此示例,可能有一种更简单的方法可将我们的值x与列row_idx <- which.min(abs(x[1,1]-xmin_col)) 进行比较,以确定当前正在悬停的数据行。我使用上面的x[1,1]方法,因为我认为在例如xmin_值不完全是某个整数+ 0.5的情况下它会更强大,因为它们处于这种情况。试图测试浮点数之间的精确相等有时会有问题。

无论如何,我们可以使用我们创建的which.min(...)来提取我们正在悬停的栏所代表的原始数据行(即xmin_包含的内容),这是在{{{ 1}}部分。结果如下:

row_idx

enter image description here

由于某种原因,标签格式不正确;虽然这与我使用的一般方法没有任何关系。

回到原始问题,关于为什么显示x值,简短的回答是传递给paste0(...)可视化中的bar_obj %>% add_tooltip(tooltip_bars,"hover") 的数据对象不一样正如在NULL可视化中传递给它的内容一样,因此调用add_tooltiplayer_points将返回layer_bars,因为x$amount中没有这些列。

为了澄清一下,要将此代码应用于您自己的数据,请确保您创建一个基本x$pv对象,就像我使用NULL一样,并将其名称替换为我使用的{{1} } x函数的ggvis行。

答案 1 :(得分:0)

我遇到了类似的问题。我通过显式过滤数据集到悬停所属的行来解决它,如:

  my_tooltip <- function(x) {
    # do some checks   
    if (is.null(x)) return(NULL)
    if (is.null(x$bin)) return(NULL)
    # select the data for the bar you're hovered over
    all_data <- my.data()
    this_data <- all_data[all_data$bin == x$bin, ]
    paste0("<b>", this_data$bin, ": ", "</b><br>", format(this_data$value))
  }

其中输入数据已在反应函数中定义,例如

my_data <- reactive({
  df <- df.all  # simplest example
  df <- df.all[df.all$group==input$selected_group,]  # example using user input
})

给定names(df.all)"group" "bin" "value"

然后我在反应vis函数中调用了工具提示函数:

  vis <- reactive({ 
    plot.data %>%
      ggvis(x=~bin, y=~value, key := ~bin) %>%  # key on `bin` here
      layer_bars(width=1, fill=~group) %>% 
      add_tooltip(my_tooltip, "hover")
  })
  vis %>% bind_shiny("my_plot")  # bind with UI name

documentation中,您需要在我的示例中键入bin,因为它是图中的一条数据,因此不清楚。但是,我发现如果没有明确设置该参数,工具提示就不会出现。