【问题标题】:Displaying information using ggvis使用 ggvis 显示信息
【发布时间】:2015-03-15 12:53:26
【问题描述】:

我正在使用 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 和数量。我试图在这里只提供相关代码,但如果需要其他部分,我会编辑帖子并包含它。

我不知道为什么当图表是散点图时它会返回正确的值,但当它是条形图时却无法返回值。

感谢您提供的任何见解!

【问题讨论】:

    标签: r ggvis


    【解决方案1】:

    这是一个很难处理的问题,因为不幸的是,并非所有类型的layers 都可以像layer_points 那样与add_tooltip 配合得很好。我不是 100% 清楚许多 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,我们有:

    point_obj %>% add_tooltip(vis_names,"hover")
    

    这是我输入数据的列名。另一方面,为bar_obj 这样做会给我们:

    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 />")
    }
    

    我们可以得到更多细节:

    bar_obj %>% add_tooltip(bar_info,"hover")
    

    所以xmin_xmax_ 显然是我们悬停在给定条的x 坐标,而stack_upr_stack_lwr_ 是各自的y 坐标。从这里开始,我们只需要将条形坐标转换回原始输入数据my_data

    ggplot2 中有一个我经常使用的简洁函数ggplot_build。当您在 ggplot 对象上调用此函数时,它会创建绘图(就像打印通常会做的那样),但还会返回有关构建绘图的所有内容的非常详细的信息 - 长轴范围、短轴范围等。 . 当您需要找到有关图表的非常精确的信息时,这非常有用。我怀疑ggvis 会有类似于ggplot_build 的东西,通过小插图我发现了函数get_data。在ggvis 对象上调用此函数会返回data.frames 列表,其中第一个元素是原始data.frame (my_data),第四个元素是data.frame,其中包含上面的条形图中显示了四列 - xmin_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 访问的内容。 xmin_col 是定义条形左侧 x 坐标的值列。通过将其与 x 中包含的 xmin_ 值进行比较,我们可以确定正在绘制哪一行数据,即

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

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

    无论如何,我们可以使用我们创建的row_idx 来提取由我们悬停的条表示的原始数据行(即x 包含的内容),这在paste0(...) 部分中完成。结果如下所示:

    bar_obj %>% add_tooltip(tooltip_bars,"hover") 
    

    由于某种原因,标签的格式不正确;尽管这与我使用的一般方法无关。

    所以回到你最初的问题,为什么要显示 NULL 值,简短的回答是在 layer_points 可视化中传递给 add_tooltip 的数据对象与传递给它的数据对象不同在layer_bars 可视化中,因此调用x$amountx$pv 将返回NULL,因为x 中不存在这些列。

    澄清一下,将此代码应用于您自己的数据,请确保您创建一个基础 ggvis 对象,就像我对 bar_obj 所做的那样,并将其名称替换为我在 get("bar_obj",.GlobalEnv) 中使用 "bar_obj" 的位置tooltip_bars 函数的行。

    【讨论】:

    • 感谢您的详细解答。但是,我在实施它时遇到了一些问题。我创建了一个基础ggvis 对象:layer_bars(x = ~time, y = ~pv, fill := "#B0B0B0")。然后我更新了tooltip_barstooltip_bars &lt;- function(x) { ... bar_obj &lt;- get("levelAn_obj",.GlobalEnv)...。最后,我绘制它:levelAn_obj %&gt;% add_tooltip(tooltip_bars,"hover") %&gt;% bind_shiny("AnPlot", "AnPlot_ui")。当我运行应用程序时,图表会显示,但当我悬停时收到此错误Warning: Unhandled error in observer: object 'levelAn_obj' not found。感谢您的帮助!
    • 更正,我看到我没有完全复制上面评论中的对象。 ggvis 对象是 levelAn_obj &lt;- dfL %&gt;% ggvis(x =~time, y = ~amount) %&gt;% layer_bars() %&gt;% layer_bars(x = ~time, y = ~pv, fill := "#B0B0B0")
    【解决方案2】:

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

      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,因为它是图中的数据之一。但是,我发现如果没有明确设置该参数,工具提示将不会出现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      • 2010-10-16
      • 2023-03-25
      • 2019-03-25
      • 2019-10-09
      相关资源
      最近更新 更多