Stacked ggplot percent barchart in shiny

2019-05-07 02:03发布

问题:

My aim is to create stacked bar chart with percent labels in ggplot. After some research and reading some material I've managed how to plot the chart I want. There a lot of material.

How do I label a stacked bar chart in ggplot2 without creating a summary data frame?

Create stacked barplot where each stack is scaled to sum to 100%

R stacked percentage bar plot with percentage of binary factor and labels (with ggplot)

However, I have 2 problems:

1) I can't find a proper place to put labels. You can see that labes are not centered and are in wrong sections. (plot generated not using shiny) How to solve this issue?

The second problem is when I try to use my plot code in shiny. I create labels using this function: df$label = paste0(sprintf("%.0f", df$percent), "%"), but when it is in reactive I get an error. In real case I have more difficult data generaration and subseting example, so my data must be reactive.

The best result I managed to get in shiny.

Also, I enclose reproducable esample of the app.

My aim is to plot nice labels for stacked percent bar chart in ggplot.

library(shiny)
library(shinydashboard)
library(plyr)
library(ggplot2)



# Header -----------------------------------------------------------

header <- dashboardHeader(title= "DashBoard")


# Sidebar --------------------------------------------------------------

sm <- sidebarMenu(

  menuItem(
    text="stacked bar chart",
    tabName="chart",
    icon=icon("eye")
  )  

)

sidebar <- dashboardSidebar(sm)

# Body --------------------------------------------------

body <- dashboardBody(

  # Layout  --------------------------------------------  

  tabItems(


    tabItem(
      tabName="chart",
      fluidPage(

        fluidRow(

          title = "Inputs", status = "warning", width = 2, solidHeader = TRUE, collapsible = TRUE,


          plotOutput("M1"),
          dataTableOutput(outputId="M3")


        )
      )
    )
  )
)

# Setup Shiny app UI components -------------------------------------------

ui <- dashboardPage(header, sidebar, body)

# Setup Shiny app back-end components -------------------------------------

server <- function(input, output) {






  # ----------------------------------------------------------------------------- 
  #reproducable data generation
  Mdata <- reactive({

    set.seed(1992)
    n=8

    Category <- sample(c("Car", "Bus", "Bike"), n, replace = TRUE, prob = NULL)
    Brand <- sample("Brand", n, replace = TRUE, prob = NULL)
    Brand <- paste0(Brand, sample(1:14, n, replace = TRUE, prob = NULL))
    USD <- abs(rnorm(n))*100

    df <- data.frame(Category, Brand, USD)

    # Calculate the percentages
    df = ddply(df, .(Brand), transform, percent = USD/sum(USD) * 100)


    # Format the labels and calculate their positions
    df = ddply(df, .(Brand), transform, pos = (cumsum(USD) - 0.5 * USD))

    #create nice labes
    #df$label = paste0(sprintf("%.0f", df$percent), "%")  

})



output$M1 <- renderPlot({ 

  ggplot(Mdata(), aes(x=reorder(Brand,USD,
                           function(x)+sum(x)),  y=percent, fill=Category))+
    geom_bar(position = "fill", stat='identity',  width = .7)+
    geom_text(aes(label=percent, ymax=100, ymin=0), vjust=0, hjust=2, color = "white",  position=position_fill())+
    coord_flip()+
    scale_y_continuous(labels = percent_format())+
    ylab("")+
    xlab("")

})  



output$M3 <- renderDataTable({
  Mdata()
})  


  # -----------------------------------------------------------------------------


}

# Render Shiny app --------------------------------------------------------

shinyApp(ui, server)

回答1:

The error from your paste0 command comes because it is the last line in the reactive, and thus becomes the return value. Just add a statement return(df) or something equivalent and that will fix that problem.

As for the label positioning, the code is working as designed, you will have to calculate the desired positions for the geom_text and use those coordinates explicitly.That will require you summing up the coordinates for each individual brand segment so you know its left and right positions and can calculate the center.

Other answers can be found in here:

How to center stacked percent barchart labels