iod
iod

Reputation: 7592

Horizontal stacked bar chart with a separate element in ggplot

I'm trying to come up with a way to visualize some likert scale data in a specific way. I'm not even sure how to fake what it would look like, so I hope my explanation would suffice.

I have the following (fake) data:

n questions, each with 5 answers (strongly agree, agree, don't agree, strongly don't agree, and don't know)

I want to visualize the data (ideally using ggplot) along a central axis, so that the two "agree" answers are on the left, and the two "disagree" answers are on the right, and then on a separate block off to the side, a block representing "don't know". It should look roughly like this:

Q1:  *****++++++++|------!!     ?????
Q2:     ****++++++|----!!!!!!   ???????
Q3:       **++++++|---!!!       ??????????
      *: strongly agree, +: agree, -: don't agree, !:strongly disagree, ?: don't know

As you can see, this representation allows to compare the actual numbers of agree and disagree, without hiding how many "don't knows" there are. The place I get stuck on is how to create that second element for the don't knows. Any ideas?

Here's some fake data:

structure(list(Q = structure(1:3, .Label = c("Q1", "Q2", "Q3"
), class = "factor"), SA = c(25, 18, 12), A = c(30, 25, 15), 
    DA = c(25, 20, 25), SDA = c(10, 18, 25), DK = c(10, 19, 23
    )), row.names = c(NA, -3L), class = "data.frame")

Upvotes: 0

Views: 157

Answers (1)

teunbrand
teunbrand

Reputation: 38063

As suggested in the comments, you can just facet out the "DK" category.

library(ggplot2)
library(tidyr)
library(scales)

df <- structure(list(Q = structure(1:3, .Label = c("Q1", "Q2", "Q3"
), class = "factor"), SA = c(25, 18, 12), A = c(30, 25, 15), 
DA = c(25, 20, 25), SDA = c(10, 18, 25), DK = c(10, 19, 23
)), row.names = c(NA, -3L), class = "data.frame")

lvls <- colnames(df)[c(2,3,5,4,6)]

ggplot(
  pivot_longer(df ,-1),
  aes(y = Q, fill = name, group = factor(name, lvls),
      x = ifelse(name %in% c("A", "SA"), -1, 1) * value)
) +
  geom_col() +
  facet_grid(~ name == "DK", scales = "free_x", space = "free_x") +
  scale_fill_manual(
    values = c(viridis_pal()(4), "grey50"),
    limits = colnames(df)[-1]
  )

Created on 2021-11-04 by the reprex package (v2.0.1)

Upvotes: 5

Related Questions