R Shiny ggplot bar и линейные диаграммы с динамическим выбором переменных и осью y, которые будут процентами

Я изучаю Shiny и хотел помочь в приложении, которое я создаю. Я создаю приложение, которое будет принимать динамические входы от пользователя и должно генерировать штриховые и линейные диаграммы. Мне удалось создать гистограмму, но она порождает неверный результат.

То, что я ищу, - это переменная, выбранная в строке, должна быть моей осью x, а ось y должна быть в процентах. масштаб должен быть 100%. переменная столбца должна быть переменной для сравнения, и для этого я использую position = "dodge". Мои данные большие, и я создал образец данных, чтобы изобразить ситуацию. Поскольку фактические данные находятся в формате data.table, я храню образцы данных в виде data.table. Поскольку я не уверен, как включить эти данные, которые не находятся в формате файла, я сначала создаю его, чтобы он находился в среде R, а затем запустил приложение -

    Location <- sample(1:5,100,replace = T)
    Brand <- sample(1:3,100,replace = T)
    Year <- rep(c("Year 2014","Year 2015"),50)
    Q1 <- sample(1:5,100,replace = T)
    Q2 <- sample(1:5,100,replace = T)

    mydata <- as.data.table(cbind(Location,Brand,Year,Q1,Q2))

Ниже приведен код Shiny, который я использую -

library("shiny")
library("ggplot2")
library("scales")
library("data.table")
library("plotly")

ui <- shinyUI(fluidPage(
  sidebarPanel(
    fluidRow(
      column(10,
             div(style = "font-size: 13px;", selectInput("rowvar", label = "Select Row Variable", ''))
      ),
      tags$br(),
      tags$br(),
      column(10,
             div(style = "font-size: 13px;", selectInput("columnvar", "Select Column Variable", ''))
      ))

  ),
  tabPanel("First Page"),
  mainPanel(tabsetPanel(id='charts',
                        tabPanel("charts",tags$b(tags$br("Graphical Output" )),tags$br(),plotlyOutput("plot1"))
  )
  )
))

server <- shinyServer(function(input, output,session){
  updateTabsetPanel(session = session
                    ,inputId = 'myTabs')


  observe({
    updateSelectInput(session, "rowvar", choices = (as.character(colnames(mydata))),selected = "mpg")
  })

  observe({
    updateSelectInput(session, "columnvar", choices = (as.character(colnames(mydata))),selected = "cyl")
  })

  output$plot1 <- renderPlotly({
    validate(need(input$rowvar,''),
             need(input$columnvar,''))
    ggplot(mydata, aes(x= get(input$rowvar))) + 
      geom_bar(aes(y = ..prop.., fill = get(input$columnvar)), position = "dodge", stat="count") +
      geom_text(aes( label = scales::percent(..prop..),
                     y= ..prop.. ), stat= "count", vjust = -.5) +
      labs(y = "Percent", fill=input$rowvar) +
      scale_y_continuous(labels=percent,limits = c(0,1))

  })

})

shinyApp(ui = ui, server = server)

Если вы видите проблему -

  • Все бары 100%. Пропорции не рассчитываются должным образом. Не знаю, где я ошибаюсь.

  • Если я пытаюсь использовать параметр группы, он дает мне ошибку, говорящую, что переменная "input" не найдена. Я попробовал дать группе как group = get(input$columnvar)

  • Я считаю, что мне нужно реструктурировать свои данные для линейной диаграммы. Можете ли вы помочь с тем, как я могу динамически реструктурировать таблицу data.table, а затем повторно использовать для линейной диаграммы. Как я могу сгенерировать одну и ту же гистограмму в виде линейной диаграммы.

  • Я использую renderplotly, чтобы использовать функции plotly, чтобы отображать проценты с движением/увеличением мыши и т.д. Однако я могу видеть переменную $$ при перемещении мыши. Как я могу избавиться от него и иметь собственные имена.

Попробовали подробно изложить ситуацию. Предлагайте некоторое решение.

Спасибо!

Ответ 1

Чтобы правильно группировать переменные для построения графика, geom_bar требует, чтобы значения x были числовыми, а значения fill были факторами или что аргумент group используется для явного указания группирующих переменных. Однако plotly выдает ошибку, когда используется group. Подход ниже преобразует переменные x в переменные integer и fill в factor, чтобы они были правильно сгруппированы. Это позволяет использовать geom_bar для вычисления процентов.

Во-первых, однако, интересно, правильно ли указан mydata. Учитывая, что данные представляют собой сочетание символа и целого числа, cbind(Location, Brand, Year, Q1, Q2) дает матрицу символов, которая затем преобразуется в data.table, где все переменные являются символьным. В приведенном ниже коде я определил mydata непосредственно как data.table, но преобразовал Q1 в режим символов, так что mydata содержит комбинацию символов и числовых.

Используемый ниже подход заключается в создании нового фрейма данных plotdata, содержащего данные x и fill. Данные x преобразуются в числовые, если необходимо, сначала делая его переменной-фактором, а затем используя unclass для получения кодовых чисел фактора. Данные fill преобразуются в коэффициент. Затем plotdata генерирует график ggplot, который затем отображается с помощью plotly. Код содержит пару других модификаций для улучшения внешнего вида диаграммы.

ИЗМЕНИТЬ

Код ниже обновлен, чтобы отобразить имя переменной строки под ней. Также процент и количество для каждого бара отображаются только тогда, когда указатель мыши нависает над панелью.

 library("shiny")
  library("ggplot2")
  library("scales")
  library(plotly)
  library(data.table)

  Location <- sample(1:5,100,replace = T)
  Brand <- sample(1:3,100,replace = T)
  Year <- rep(c("Year 2014","Year 2015"),50)
  Q1 <- sample(1:5,100,replace = T)
  Q2 <- sample(1:5,100,replace = T)
  Q3 <- sample(seq(1,3,.5), 100, replace=T)
  mydata <- data.table(Location,Brand,Year,Q1,Q2, Q3)
#
# convert Q1 to character for demonstation purposes  
#
    mydata$Q1 <- as.character(mydata$Q1)

  ui <- shinyUI(fluidPage(
    sidebarPanel(
      fluidRow(
        column(10,
               div(style = "font-size: 13px;", selectInput("rowvar", label = "Select Row Variable", 
                                                           choices=colnames(mydata)))),
        tags$br(),
        tags$br(),
        column(10,
               div(style = "font-size: 13px;", selectInput("columnvar", label="Select Column Variable", 
                                                           choices=colnames(mydata))))
        )
    ),
    tabPanel("First Page"),
    mainPanel(tabsetPanel(id='charts',
                          tabPanel("charts",tags$b(tags$br("Graphical Output" )),tags$br(),plotlyOutput("plot1"))
    )
    )
  ))
  server <- shinyServer(function(input, output,session){
    updateTabsetPanel(session = session
                      ,inputId = 'myTabs')
    observe({
      updateSelectInput(session, "rowvar", choices = colnames(mydata), selected=colnames(mydata)[1])
    })
    observe({
      updateSelectInput(session, "columnvar", choices = colnames(mydata), selected=colnames(mydata)[2])
    })
    output$plot1 <- renderPlotly({
#
#   create data frame for plotting containing x variables as integer and fill variables as factors
#   
      if(is.numeric(get(input$rowvar)))  {
        rowvar_brks <- sort(unique(get(input$rowvar)))
        rowvar_lbls <- as.character(rowvar_brks)
        plotdata <- data.frame(get(input$rowvar), factor(get(input$columnvar)) )
      }
      else {
        rowvar_factors <- factor(get(input$rowvar))
        rowvar_brks <- 1:nlevels(rowvar_factors)
        rowvar_lbls <- levels(rowvar_factors)
        plotdata <- data.frame(unclass(rowvar_factors), factor(get(input$columnvar)) )
      }
      colnames(plotdata) <- c(input$rowvar, input$columnvar)
      validate(need(input$rowvar,''),
               need(input$columnvar,''))
      col_width <- .85*mean(diff(rowvar_brks))
      sp <- ggplot(plotdata, aes_(x = as.name(input$rowvar), fill = as.name(input$columnvar))) +
        geom_bar( aes(y= ..prop..), stat="count", position=position_dodge(width=col_width)) +
        geom_text(aes( label = paste(scales::percent(..prop..),"<br>", "count:",..count..,"<br>"),  y= ..prop.. + .01),
                  stat= "count", position=position_dodge(width=col_width), size=3, alpha=0) +
        labs(x= input$rowvar, y = "Percent", fill=input$columnvar) +
        scale_y_continuous(labels=percent) +
        scale_x_continuous(breaks=rowvar_brks, labels=rowvar_lbls)
        ggplotly(sp, tooltip="none")
      })
  })

  shinyApp(ui = ui, server = server)