1

I'm building a shiny app that prepares a stacked bar chart with a tooltip showing levels of satisfactions across 3 items and 2 types of respondents. Here's the data that makes up the chart:

mydf <- structure(list(Resp = structure(c(1L, 1L, 2L, 1L, 2L, 1L, 1L, 
2L, 1L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 1L, 2L), .Label = c("Resp_A", 
"Resp_B"), class = "factor"), Rating = structure(c(4L, 4L, 4L, 
4L, 4L, 3L, 3L, 3L, 3L, 3L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 
1L), .Label = c("DK/NA", "Dissatisfied", "Neutral", "Satisfied"
), class = "factor"), Question = structure(c(1L, 2L, 2L, 3L, 
3L, 1L, 2L, 2L, 3L, 3L, 1L, 2L, 2L, 3L, 3L, 1L, 2L, 2L, 3L, 3L
), .Label = c("q14", "q12", "q11"), class = "factor"), count = c(29, 
27, 11, 25, 12, 9, 12, 3, 9, 5, 3, 2, 11, 5, 8, 4, 4, 8, 6, 8
), prop = c(0.644444444444444, 0.6, 0.333333333333333, 0.555555555555556, 
0.363636363636364, 0.2, 0.266666666666667, 0.0909090909090909, 
0.2, 0.151515151515152, 0.0666666666666667, 0.0444444444444444, 
0.333333333333333, 0.111111111111111, 0.242424242424242, 0.0888888888888889, 
0.0888888888888889, 0.242424242424242, 0.133333333333333, 0.242424242424242
), Label = structure(c(1L, 2L, 2L, 3L, 3L, 1L, 2L, 2L, 3L, 3L, 
1L, 2L, 2L, 3L, 3L, 1L, 2L, 2L, 3L, 3L), .Label = c("Label_1", 
"Label_2", "Label_3"), class = "factor"), tooltip = c("<b>Satisfied</b>\n<b>Question:</b> Question_Text_1\n<b>n=</b> 29\n<b>Percentage:</b> 64%", 
"<b>Satisfied</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 27\n<b>Percentage:</b> 60%", 
"<b>Satisfied</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 11\n<b>Percentage:</b> 33%", 
"<b>Satisfied</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 25\n<b>Percentage:</b> 56%", 
"<b>Satisfied</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 12\n<b>Percentage:</b> 36%", 
"<b>Neutral</b>\n<b>Question:</b> Question_Text_1\n<b>n=</b> 9\n<b>Percentage:</b> 20%", 
"<b>Neutral</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 12\n<b>Percentage:</b> 27%", 
"<b>Neutral</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 3\n<b>Percentage:</b> 9%", 
"<b>Neutral</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 9\n<b>Percentage:</b> 20%", 
"<b>Neutral</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 5\n<b>Percentage:</b> 15%", 
"<b>Dissatisfied</b>\n<b>Question:</b> Question_Text_1\n<b>n=</b> 3\n<b>Percentage:</b> 7%", 
"<b>Dissatisfied</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 2\n<b>Percentage:</b> 4%", 
"<b>Dissatisfied</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 11\n<b>Percentage:</b> 33%", 
"<b>Dissatisfied</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 5\n<b>Percentage:</b> 11%", 
"<b>Dissatisfied</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 8\n<b>Percentage:</b> 24%", 
"<b>DK/NA</b>\n<b>Question:</b> Question_Text_1\n<b>n=</b> 4\n<b>Percentage:</b> 9%", 
"<b>DK/NA</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 4\n<b>Percentage:</b> 9%", 
"<b>DK/NA</b>\n<b>Question:</b> Question_Text_2\n<b>n=</b> 8\n<b>Percentage:</b> 24%", 
"<b>DK/NA</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 6\n<b>Percentage:</b> 13%", 
"<b>DK/NA</b>\n<b>Question:</b> Question_Text_3\n<b>n=</b> 8\n<b>Percentage:</b> 24%"
), Ord = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 
4, 4, 4), Question_Text = structure(c(3L, 1L, 1L, 2L, 2L, 3L, 
1L, 1L, 2L, 2L, 3L, 1L, 1L, 2L, 2L, 3L, 1L, 1L, 2L, 2L), .Label = c("Question_Text_2", 
"Question_Text_3", "Question_Text_1"), class = "factor")), row.names = c(NA, 
-20L), .Names = c("Resp", "Rating", "Question", "count", "prop", 
"Label", "tooltip", "Ord", "Question_Text"), class = c("tbl_df", 
"tbl", "data.frame"))

A couple of additional bits:

#Value colours
Labels_Colours <- c("Satisfied" = "#59A14F", "Neutral" = "#76B7B2", "Dissatisfied" = "#F28E2B", "DK/NA" = "#BAB0AC")

#Tooltip feature
tooltip_css <- "background-color:white;font-style:italic;padding:10px;border-radius:10px 20px 10px 20px;"

Here's what the chart in ggplot2 looks like. This chart is exactly what I want my ggiraph chart to look like:

library(ggplot2)
library(dplyr)
mydf %>% filter(prop > 0 | is.na(prop)) %>%
ggplot(aes(x = Label, y = ifelse(is.na(prop), 0, prop), fill = Rating)) +
geom_col() +
geom_text(aes(label = ifelse(is.na(prop), prop, percent(round(prop, 2)))), position = position_stack(vjust = 0.5), size = 3) +
scale_fill_manual(values = Labels_Colours) +
coord_flip() +
facet_grid(~ Resp, drop = FALSE) +
labs(x = "", y = "") +
theme_minimal() +
theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
)

enter image description here

Now, here's my attempt at the final product, using ggiraph. The only difference in the code here is that I'm using geom_bar_interactive instead of geom_col, and of course the last line:

library(ggiraph)
mychart <- mydf %>% filter(prop > 0 | is.na(prop)) %>%
ggplot(aes(x = Label, y = ifelse(is.na(prop), 0, prop), fill = Rating)) +
geom_bar_interactive(aes(tooltip = tooltip, data_id = Rating), stat = "identity") +
geom_text(aes(label = ifelse(is.na(prop), prop, percent(round(prop, 2)))), position = position_stack(vjust = 0.5), size = 3) +
scale_fill_manual(values = Labels_Colours) +
coord_flip() +
facet_grid(~ Resp, drop = FALSE) +
labs(x = "", y = "") +
theme_minimal() +
theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
)
ggiraph(code = print(mychart), width = 1, point = 4, width_svg = 8, height_svg = 2, tooltip_extra_css = tooltip_css, hover_css = "opacity:0.5")

enter image description here

The "DK/NA" bar somehow switched places with the "Dissatisfied" bar, but my percentage labels and the legend remain in the correct places. What's causing this? I assume this has something to do with the order of the levels in the Rating factor, but they appear to be in the correct order. I'm mystified.

Community
  • 1
  • 1
Phil
  • 7,287
  • 3
  • 36
  • 66

2 Answers2

3

It's about grouping. Aesthetics tooltip and data_id in geom_bar_interactive (or in geom_bar, same effect) make grouping different from the grouping of geom_text.

[http://ggplot2.tidyverse.org/reference/aes_group_order.html] By default, the group is set to the interaction of all discrete variables in the plot. This often partitions the data correctly, but when it does not, or when no discrete variable is used in the plot, you will need to explicitly define the grouping structure, by mapping group to a variable that has a different value for each group.

Defining group aesthetic solves the issue (in main aes or in geom_bar):

mychart <- mydf %>% filter(prop > 0 | is.na(prop)) %>%
  ggplot(aes(x = Label, y = ifelse(is.na(prop), 0, prop), fill = Rating, group = Rating)) +
  geom_bar_interactive(mapping = aes(tooltip = tooltip, data_id = Rating), stat = "identity") +
  geom_text(aes(label = ifelse(is.na(prop), prop, percent(round(prop, 2)))), position = position_stack(vjust = 0.5), size = 3) +
  scale_fill_manual(values = Labels_Colours) +
  coord_flip() +
  facet_grid(~ Resp, drop = FALSE) +
  theme_minimal() 
ggiraph(code = print(mychart), width = 1, point = 4, width_svg = 8, height_svg = 2, tooltip_extra_css = tooltip_css, hover_css = "opacity:0.5")

enter image description here

David Gohel
  • 9,180
  • 2
  • 16
  • 34
0

As @DavidGohel points out this is a bug, I've found that the following acts as a workaround:

library(forcats)
mydf <- arrange(mydf, Rating)
mydf$tooltip <- fct_inorder(mydf$tooltip)

Now, running the ggiraph code again:

enter image description here

Phil
  • 7,287
  • 3
  • 36
  • 66