为什么 geom_histogram 不使用给 ggplot 函数的映射?

Why does geom_histogram not use the mapping given to the ggplot function?

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

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

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

错误在没有闪亮环境的情况下复制,所以我似乎从根本上犯了错误。无论我使用什么 geom,这个错误不仅会复制,而且无论我使用什么输入变量。在这一点上我很困惑,因为 rlang::.data[[]] 策略以前在不同的上下文中对我有用,我认为我已经复制了书中的示例 12.2.2。 查看生成的 gplot,所需的美学呈现在最高级别,但它们未用于图层。所以我以某种方式破坏了数据流?

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

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

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

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

非常感谢!

一个。 S.

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

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

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

使用,例如,

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

生成预期形式的图。

可能有一个更通用的解决方案,涉及使用 enquo!!,但我现在没有时间研究。

编辑

我很接近。您需要使用 get() 而不是 enquo()!!。这是 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)