4
votes

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) enter image description here 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. enter image description here

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.Mike Wise
Thank's for the help @MikeWise. It solves the second problem! There only one question left, about putting labels in correct place.AK47
I don't see a way to fix your first problem. I think the code is working the way it is supposed to. Anything else will be a lot more complicated, i.e. you will have to position the text manually. I actually think it looks fine the way it is with hjust=1Mike Wise
The problem is that, that in real case, for example, I have 10 year data. So I add selectInput to change the year. So each time graph ir reploted based on the selections in the menu.AK47
I am not following you. I don't see what that problem makes the positioning of the labels problematic?Mike Wise

1 Answers

3
votes

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