1

I'm trying to create a stacked bar chart where the important sub categories are represented by a label, but the smaller sub categories don't appear (as this would really clutter the chart). I've now made a subset to only display labels where the value is over 20 for that sub category, but some of the labels are not centered correctly even though I've used position = position_stack(vjust = 0.5)

EDIT: for example of labels which are centered correctly, see the 'housing' column, where property rates doesn't sit within its stack - its actually on a line between 2 stacks. Another example is in the 'Miscellaneous' column, where insurance is correct, but 'personal care' should be higher up, in the larger stack.

If anyone has a better way of displaying these labels that would also be appreciated as I'm not really happy with how this chart is going to look even if the labels do center properly, but i just cant think of a better way to do it.

here is my code for the graph;

##stacked column chart for expenditure breakdowns
ggplot(expenditureDS, aes(fill = Category, y=AvgExpenditurePerWeek, x=Category)) + 
    geom_bar(stat="identity",
             width = 0.6,
             color = "black",
             size = 0.5,
             alpha = 0.7) + 
    theme_minimal() +
    theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 0.8)) +
    labs(x= "Categories", y = "Expenditure Per Week", title = "All Households in NZ - Expenditure Breakdowns",
        caption = "2008-2020 data") +
    theme(
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank()) +
    theme(plot.title = element_text(hjust = 0.5)) +
    geom_text(data=subset(expenditureDS, AvgExpenditurePerWeek > 20), aes(label = SubCategory), position = position_stack(vjust = 0.5), size = 2.5) +
    scale_y_continuous(labels= dollar_format(prefix="$"))

here is my graph output; enter image description here

Nad
  • 31
  • 5
  • 1
    Can you point out which labels are not correctly centered? (They all look centered to me). It's easier to help you if you include a simple [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input that can be used to test and verify possible solutions. – MrFlick Jun 08 '21 at 17:10
  • updated to point out the bad labels. Not sure what you mean by a reproducible example? but if you are looking for all of the code to run it, im not sure how i can do that as it runs off .csv files etc? – Nad Jun 08 '21 at 17:16
  • the `hjust = 0.8` bit in one of your theme calls is the problem. Try `hjust = 0.5`. If you want it outright centered, try `axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5)`. – PavoDive Jun 08 '21 at 17:18
  • 2
    Your text is stacking just the subset of data with values over 20, which will stack to lower heights than the full data does. I think you should use the full data for that layer, but change the label to blank if value under 20. – Jon Spring Jun 08 '21 at 17:52
  • You might also consider using `label = str_wrap(Subcategory, 12)` or similar to wrap the lines, and `lineheight = 0.7` or similar to squeeze them together to taste. – Jon Spring Jun 08 '21 at 18:00

1 Answers1

3

Change

geom_text(data=subset(expenditureDS, AvgExpenditurePerWeek > 20), 
          aes(label = SubCategory), 
          position = position_stack(vjust = 0.5), size = 2.5) +

to

geom_text(aes(label = if_else(AvgExpenditurePerWeek > 20, SubCategory, "")), 
          position = position_stack(vjust = 0.5), size = 2.5) +

Otherwise your text layer is only stacking a subset of values, which have lower totals than the full data.

Compare these:

ggplot(mtcars, aes(cyl, wt)) +
  geom_col(color = "white", fill = "gray80") +
  geom_text(data = mtcars %>% filter(wt > 4), aes(label = wt), 
            position = position_stack(vjust = 0.5))

enter image description here

ggplot(mtcars, aes(cyl, wt)) +
  geom_col(color = "white", fill = "gray80") +
  geom_text(aes(label = if_else(wt > 4, as.character(wt), "")), 
            position = position_stack(vjust = 0.5))

enter image description here

Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • I changed as suggested, but got a new error; ERROR while rich displaying an object: `false` must be a `factor` object, not a character vector – Nad Jun 08 '21 at 21:48
  • Sounds like you could use `as.character(SubCategory)` for the first `if_else` option so that both can be character. `if_else` is pickier that `base::ifelse` in requiring both to be the same type. – Jon Spring Jun 08 '21 at 21:51