【问题标题】:How to customise a shiny plotting function to output different plots depending on the parameters received from calling the function如何自定义闪亮的绘图函数以根据从调用函数接收的参数输出不同的绘图
【发布时间】:2019-09-17 08:23:13
【问题描述】:

我试图通过设置一个函数以在每次调用绘图函数时接收一组不同的参数值来从一个 ggplot 饼图代码呈现两个饼图。这让我不必为每个 Pie 编写两组几乎相同的代码。

传递的三个参数是因子、标题和比例。 Pie1 有factor=age_grouptitle="Age_Group Segmentation"scale=c("#ffd700", "#bcbcbc", "#ffa500", "#254290", "#f0e68c", "#808000")。 Pie2 有factor=Outcometitle="Outcome Segmentation"scale=c(#ffd700", "#bcbcbc", "#ffa500", "#254290")

我原则上知道这样做的方法是:

plot_func <- function(factor, title, scale) {ggplot(dfnew, aes("", share, fill = factor)) + geom_bar( +
labs(x = NULL, y = NULL, fill = NULL,title = title) + scale_fill_manual(values = scale)))}

然后在 renderplot 中调用这个 plot_function: plot_func(group, title, scale) 带有参数值。

问题是我不知道所需的语法,尤其是因为反应数据对象也被传递到 ggplot 中,data_mod()。我在stackoverflow中没有找到任何东西来模仿我正在尝试做的事情。包含示例数据框的完整代码。

library(shiny)
library(ggplot2)
library(dplyr)

# use the below if you want to increase the file size being inputed to 9MB
# options(shiny.maxRequestSize = 9.1024^2)

ui <- shinyUI(navbarPage(
  "Example",
  tabPanel("Data",
           sidebarLayout(
             sidebarPanel("Nothing here at the moment"),
             mainPanel(
               "Select Dashboard Panel for results.Click on
    Select/All to make the plots render"
             )
           )),
  tabPanel("Dashboard",
           sidebarLayout(
             sidebarPanel(
               checkboxInput('all', 'Select All/None', value = TRUE),
               uiOutput("year_month"),
               tags$head(
                 tags$style(
                   "#year_month{color:red; font-
   size:12px; font-style:italic;
          overflow-y:scroll; max-height: 100px; background:
    ghostwhite;}"
                 )
               )
             ),
             mainPanel(uiOutput("tb"))
           ))
))

complaint_id <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
age_group <- c(
  "09 Months",
  "03 Months",
  "06 Months",
  "Over A Year",
  "12 Months",
  "01 Months",
  "09 Months",
  "03 Months",
  "06 Months",
  "Over A Year",
  "12 Months",
  "01 Months"
)
closed_date_ym <- c(
  "2019-09",
  "2019-09",
  "2019-09",
  "2019-09",
  "2019-09",
  "2019-09",
  "2019-08",
  "2019-08",
  "2019-08",
  "2018-08",
  "2019-08",
  "2019-08"
)
officer <- c("A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C",
             "D")
Outcome <- c(
  "Excellent",
  "Good",
  "OK",
  "Poor",
  "Excellent",
  "Good",
  "OK",
  "Poor",
  "Excellent",
  "Good",
  "OK",
  "Poor"
)
sample_data <- data.frame(complaint_id, age_group, closed_date_ym,
                          officer, Outcome)

server <- shinyServer(function(session, input, output) {
  # Make it reactive
  data <- reactive({
    sample_data
  })

  # Have to modify the reactive data object to add a column of 1s(Ones) inorder
  # that the Pie chart %s are calculated correctly within the segments. We apply
  # this modification to a new reactive object, data_mod()
  data_mod <- reactive({
    req(data())
    df <- data() %>% select(complaint_id, age_group, closed_date_ym,
                        officer, Outcome)

    df$Ones <- rep(1, nrow(data()))
    df
  })


  # creates a selectInput widget with unique YYYY-MM variables ordered from most
  # recent to oldest time period

  output$year_month <- renderUI({
    req(data_mod())
    data_ordered <- order(data_mod()$closed_date_ym, decreasing = T)
    data_ordered <- data_mod()[data_ordered,]
    checkboxGroupInput("variable_month",
                       "Select Month",
                       choices = unique(data_ordered$closed_date_ym))

  })

  observe({
    req(data_mod())
    data_ordered <- order(data_mod()$closed_date_ym, decreasing = T)
    data_ordered <- data_mod()[data_ordered,]
    updateCheckboxGroupInput(
      session,
      "variable_month",
      choices = unique(data_ordered$closed_date_ym),
      selected = if (input$all)
        unique(data_ordered$closed_date_ym)
    )

  })

  # This subsets the dataset based on what "variable month" above is selected
  # and renders it into a Table
  output$table <- renderTable({
    req(data_mod())
    dftable <- data_mod()
    df_subset <- dftable[, 1:5][dftable$closed_date_ym %in%
                                  input$variable_month, ]
  },
  options = list(scrollX = TRUE))

  # This takes the modified reactive data object data_mod(), assigns it to a
  # dataframe df. The dataset in df is subsetted based on the selected variable
  # month above and assigned into a new data frame, dfnew. The Pie chart is
  # built on the variables within dfnew.
  plot_func <- function(factor, title, scale) {
    group_by(factor) %>%
      summarize(volume = sum(Ones)) %>%
      mutate(share = volume / sum(volume) * 100.0) %>%
      arrange(desc(volume))
    ggplot(dfnew, aes("", share, fill = factor)) +
      geom_bar(
        width = 1,
        size = 1,
        color = "white",
        stat = "identity"
      ) +
      coord_polar("y") +
      geom_text(aes(label = paste0(round(share, digits = 2), "%")),
                position = position_stack(vjust = 0.5)) +
      labs(
        x = NULL,
        y = NULL,
        fill = NULL,
        title = title
      ) +
      guides(fill = guide_legend(reverse = TRUE)) +
      scale_fill_manual(values = scale) +
      theme_classic() +
      theme(
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        plot.title = element_text(hjust = 0.5, color = "#666666")
      )

  }

  output$plot1 <- renderPlot({
    req(data_mod(), input$variable_month)
    df <- data_mod()
    dfnew <- df[, 1:6][df$closed_date_ym %in% input$variable_month, ] %>%
      plot_func(
        factor = age_group,
        title = "Age Group Segmentation",
        scale = c(
          "#ffd700",
          "#bcbcbc",
          "#ffa500",
          "#254290",
          "#f0e68c",
          "#808000"
        )
      )
  })
  output$plot2 <- renderPlot({
    req(data_mod(), input$variable_month)
    df <- data_mod()
    dfnew <- df[, 1:6][df$closed_date_ym %in% input$variable_month, ] %>%
      plot_func(
        factor = Outcome,
        title = "Outcome Segmentation",
        scale =
          c("#ffd700", "#bcbcbc", "#ffa500", "#254290")
      )
  })

  # the following renderUI is used to dynamically gnerate the tabsets when the file is loaded
  output$tb <- renderUI({
    req(data())
    tabsetPanel(tabPanel("Plot",
                         plotOutput("plot1"), plotOutput("plot2")),
                tabPanel("Data", tableOutput("table")))

  })
})

shinyApp(ui = ui, server = server)

预期结果是呈现两个饼图,但我收到错误消息

警告:plot_func 中的错误:未使用的参数 (.)

有人可以帮我解决这个问题吗? 非常感谢。

【问题讨论】:

  • 欢迎来到stackoverflow!请向我们提供reproducible example
  • 谢谢。是的,我是堆栈溢出的新手。我的完整代码 ui 和服务器从目录上传数据集,因此除非我也提供 csv 数据集,否则这是不可能的。是否可以附加我的 csv 数据集并因此使用完整的工作代码?
  • 向我们提供一些虚拟数据(创建data.frame)或使用dput() 将数据粘贴到此处就足够了。此外,请添加使用的库和应用程序结构(服务器,ui)。
  • 我会提供完整的代码
  • 您好,感谢您对我应该如何提交问题的有用建议。我现在提供了一个完整的代码,用户界面,服务器 + 库 + 一个示例 data.frame。我期待着回音。问候

标签: r ggplot2 shiny dplyr


【解决方案1】:

请检查以下内容:

library(shiny)
library(ggplot2)
library(dplyr)


# Global ------------------------------------------------------------------
# use the below if you want to increase the file size being inputed to 9MB
# options(shiny.maxRequestSize = 9.1024^2)

sample_data <- data.frame(
    complaint_id = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
    age_group = c(
      "09 Months",
      "03 Months",
      "06 Months",
      "Over A Year",
      "12 Months",
      "01 Months",
      "09 Months",
      "03 Months",
      "06 Months",
      "Over A Year",
      "12 Months",
      "01 Months"
    ),
    closed_date_ym = c(
      "2019-09",
      "2019-09",
      "2019-09",
      "2019-09",
      "2019-09",
      "2019-09",
      "2019-08",
      "2019-08",
      "2019-08",
      "2018-08",
      "2019-08",
      "2019-08"
    ),
    officer = c("A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D"),
    Outcome = c(
      "Excellent",
      "Good",
      "OK",
      "Poor",
      "Excellent",
      "Good",
      "OK",
      "Poor",
      "Excellent",
      "Good",
      "OK",
      "Poor"
    )
  )


# UI ----------------------------------------------------------------------
ui <- shinyUI(navbarPage(
  "Example",
  tabPanel("Data",
           sidebarLayout(
             sidebarPanel("Nothing here at the moment"),
             mainPanel(
               "Select Dashboard Panel for results.Click on
    Select/All to make the plots render"
             )
           )),
  tabPanel("Dashboard",
           sidebarLayout(
             sidebarPanel(
               checkboxInput('all', 'Select All/None', value = TRUE),
               uiOutput("year_month"),
               tags$head(
                 tags$style(
                   "#year_month{color:red; font-
   size:12px; font-style:italic;
          overflow-y:scroll; max-height: 100px; background:
    ghostwhite;}"
                 )
               )
             ),
             mainPanel(uiOutput("tb"))
           ))
))



# Server ------------------------------------------------------------------
server <- shinyServer(function(session, input, output) {
  # Make it reactive
  data <- reactive({
    sample_data
  })

  # Have to modify the reactive data object to add a column of 1s(Ones) inorder
  # that the Pie chart %s are calculated correctly within the segments. We apply
  # this modification to a new reactive object, data_mod()
  data_mod <- reactive({
    req(data())
    data_mod <-
      data() %>% select(complaint_id, age_group, closed_date_ym, officer, Outcome)
    data_mod$Ones <- rep(1, nrow(data()))
    data_mod
  })


  # creates a selectInput widget with unique YYYY-MM variables ordered from most
  # recent to oldest time period

  output$year_month <- renderUI({
    req(data_mod())
    data_ordered <-
      order(data_mod()$closed_date_ym, decreasing = TRUE)
    data_ordered <- data_mod()[data_ordered,]
    checkboxGroupInput("variable_month",
                       "Select Month",
                       choices = unique(data_ordered$closed_date_ym))

  })

  observe({
    req(data_mod())
    data_ordered <-
      order(data_mod()$closed_date_ym, decreasing = TRUE)
    data_ordered <- data_mod()[data_ordered,]
    updateCheckboxGroupInput(
      session,
      "variable_month",
      choices = unique(data_ordered$closed_date_ym),
      selected = if (input$all)
        unique(data_ordered$closed_date_ym)
    )

  })

  # This subsets the dataset based on what "variable month" above is selected
  # and renders it into a Table
  output$table <- renderTable({
    req(data_mod())
    dftable <- data_mod()
    df_subset <- dftable[, 1:5][dftable$closed_date_ym %in%
                                  input$variable_month, ]
  },
  options = list(scrollX = TRUE))

  # This takes the modified reactive data object data_mod(), assigns it to a
  # dataframe df. The dataset in df is subsetted based on the selected variable
  # month above and assigned into a new data frame, DF. The Pie chart is
  # built on the variables within DF.
  plot_func <- function(DF, grp_vars, title, scale) {
    group_by(DF, DF[[grp_vars]]) %>%
      summarize(volume = sum(Ones)) %>%
      mutate(share = volume / sum(volume) * 100.0) %>%
      arrange(desc(volume)) %>%
      ggplot(aes("", share, fill = unique(DF[[grp_vars]]))) +
      geom_bar(
        width = 1,
        size = 1,
        color = "white",
        stat = "identity"
      ) +
      coord_polar("y") +
      geom_text(aes(label = paste0(round(share, digits = 2), "%")),
                position = position_stack(vjust = 0.5)) +
      labs(
        x = NULL,
        y = NULL,
        fill = NULL,
        title = title
      ) +
      guides(fill = guide_legend(reverse = TRUE)) +
      scale_fill_manual(values = scale) +
      theme_classic() +
      theme(
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        plot.title = element_text(hjust = 0.5, color = "#666666")
      )
  }

  output$plot1 <- renderPlot({
    req(data_mod(), input$variable_month)
    plot_func(
      DF = data_mod()[, 1:6][data_mod()$closed_date_ym %in% input$variable_month, ],
      grp_vars = "age_group",
      title = "Age Group Segmentation",
      scale = c(
        "#ffd700",
        "#bcbcbc",
        "#ffa500",
        "#254290",
        "#f0e68c",
        "#808000"
      )
    )
  })
  output$plot2 <- renderPlot({
    req(data_mod(), input$variable_month)
    plot_func(
      DF = data_mod()[, 1:6][data_mod()$closed_date_ym %in% input$variable_month, ],
      grp_vars = "Outcome",
      title = "Outcome Segmentation",
      scale = c("#ffd700", "#bcbcbc", "#ffa500", "#254290")
    )
  })

  # the following renderUI is used to dynamically gnerate the tabsets when the file is loaded
  output$tb <- renderUI({
    req(data())
    tabsetPanel(tabPanel("Plot",
                         plotOutput("plot1"), plotOutput("plot2")),
                tabPanel("Data", tableOutput("table")))

  })
})



# Compile shiny app -------------------------------------------------------
shinyApp(ui = ui, server = server)

主要问题是将grp_vars(重命名为factor 是R 中的一个函数)正确传递给您的plot_func。此问题与 dplyr 无关,与 shiny 无关。

【讨论】:

  • 非常感谢您给我的帮助。我已将其应用于我的原始应用程序,该应用程序现在从文件夹中检索 csv 文件。有用!它唯一没有做的是将段颜色与正确的图例颜色匹配。段 % 是正确的,但与图例匹配的颜色不正确。例如,段 A 为蓝色,但图例中的 A 具有不同的颜色。是否可以在 ggplot 中添加一些东西来将段颜色与图例颜色联系起来?期待您的建议。非常感谢您的帮助。
  • 这里给出的示例数据似乎没问题,如果没有可重现的示例,很难说您的实际数据出了什么问题。我认为您应该尝试提供显示相同行为的示例数据 - 也许在另一个问题中,因为这个问题是关于在闪亮的上下文中传递参数。看来您的附加问题与ggplot2 相关。
猜你喜欢
  • 2020-08-10
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 2021-06-30
  • 2015-10-19
  • 2018-11-16
相关资源
最近更新 更多