1

我目前正在创建一个 Shiny 应用程序,它应该根据用户输入构建图。用户可以在直方图、密度图和散点图、要描绘的变量以及要显示的标题/标签之间进行选择。由于这是 Shiny,我尝试按照https://mastering-shiny.org/action-tidy.html中给出的说明进行操作,该说明解释了如何在这种情况下使用 tidy 评估。

我创建了一个基本的绘图对象,ggplot(..., aes(rlang::.data[[]]))稍后再添加几何图形。不幸的是,我在尝试显示绘图时遇到以下错误消息:

Error: stat_bin() requires an x or y aesthetic.

错误在没有 Shiny 环境的情况下复制,所以我似乎得到了一些根本性的错误。无论我使用什么几何图形,无论我使用什么输入变量,这个错误都会复制。在这一点上我很困惑,因为该rlang::.data[[]]策略以前在不同的情况下对我有用,我认为我复制了书中的示例 12.2.2。查看结果gplot,所需的美学呈现在最高级别,但它们不用于图层。所以我以某种方式破坏了数据流?

因此,我的问题是一个相当基本的问题:

  • 为什么 geom 不访问给 ggplot 函数的映射信息?
  • 我是如何破坏从最高级别到几何的数据流的?

我在网上搜索了答案并阅读了文档,但我不明白。此外,到目前为止,我发现的所有问题都涉及由于未考虑数据屏蔽问题而导致的绘图未打印或错误,但这似乎是我问题的根源。

在创建绘图的同时添加几何图形也不起作用。也不会将映射信息添加到几何本身。该gplot对象仍然不包含在图层中。我还没有尝试使用基本 R 图复制问题,因为我更喜欢在应用程序中使用 ggplot 并且我觉得我无法复制它,因为我以某种方式让整洁的评估错误引入了问题。

我在下面提供了一个没有闪亮上下文的代码示例。

非常感谢!

作为

library(ggplot2)
library(shiny)
input <- list(
  fill = "gear",
  x = "wt",
  y = "mpg",
  geom = "Histogram"
)

# aesthetics: x, y, fill
if (isTruthy(input$fill)) {
  if (isTruthy(input$y) & input$geom == "Scatter plot") {
    gplot <- ggplot2::ggplot(
      mtcars,
      ggplot2::aes(x = rlang::.data[[input$x]], y = rlang::.data[[input$y]],
                   fill = rlang::.data[[input$fill]])
    )
  } else if (input$geom %in% c("Histogram", "Density plot")) {
    gplot <- ggplot2::ggplot(
      mtcars,
      ggplot2::aes(x = rlang::.data[[input$x]],
                   fill = rlang::.data[[input$fill]])
    )
  } else {
    showNotification("Variable on y-axis of scatter plot still missing.",
                     type = "message")
  }
} else {
  if (isTruthy(input$y) & input$geom == "Scatter plot") {
    gplot <- ggplot2::ggplot(
      mtcars,
      ggplot2::aes(x = rlang::.data[[input$x]], y = rlang::.data[[input$y]])
    )
  } else if (input$geom %in% c("Histogram", "Density plot")) {
    gplot <- ggplot2::ggplot(
      mtcars,
      ggplot2::aes(x = rlang::.data[[input$x]])
    )
  } else {
    showNotification("Variable on y-axis of scatter plot still missing.",
                     type = "message")
  }
}

# geom
plot_geom <- switch(input$geom,
                    "Histogram" = ggplot2::geom_histogram(),
                    "Density plot" = ggplot2::geom_density(),
                    "Scatter plot" = ggplot2::geom_point()
)

# build plot
gplot <- gplot +
  plot_geom

gplot
4

1 回答 1

2

您似乎是 tidyverse 非标准评估 ( NSE ) 的受害者。

粗略地说,tidyverse 函数期望 tibble 列作为参数。您正在从input列表中传递字符。

例如,使用

gplot <- ggplot(mtcars, aes_string(x = input$x, y = input$y, fill = input$fill))

生成预期形式的图。

可能有一个更通用的解决方案涉及使用enquoand !!,但我现在没有时间进行调查。

编辑

我很接近。您需要使用get()而不是enquo()and !!。这是一个概念验证 Shiny 应用程序。

library(shiny)
library(tidyverse)

ui <- fluidPage(
  selectInput("x", "X variable:", choices=c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")),
  selectInput("y", "Y variable:", choices=c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")),
  selectInput("type", "Plot type:", choices=c("Histogram", "Scatter", "Density")),
  plotOutput("plot")
)

server <- function(input, output) {
  output$plot <- renderPlot({
    req(input$x, input$y)
    
    if (input$type == "Histogram") {
      mtcars %>% ggplot() + geom_histogram(aes(x=get(input$x)))
    } else if (input$type == "Scatter") {
      mtcars %>% ggplot() + geom_point(aes(x=get(input$x), y=get(input$y)))
    } else if (input$type == "Density"){
      mtcars %>% ggplot() + geom_density(aes(x=get(input$x)))
    }
  })
}

shinyApp(ui = ui, server = server) 
于 2021-03-09T09:04:01.197 回答