Diverging Stacked Bars

Visualising simulated results from an UX User Testing, using Diverging Stacked Bars.

R code

# Libraries --------------------------------------------------------------------

library(tidyverse)
library(RColorBrewer)
library(grid)
library(stringr)
# Data --------------------------------------------------------------------

tasks <- 15

results <- c("Direct Success", "Indirect Success", "Direct Failure", "Indirect Failure")
summary <- c("Success", "Failure")

users <- 8
score <- c(50, 0, 25, 12.5, 12.5, 0, 0, 0)

data <- tibble(
task = factor( paste("", rep(1:tasks, each= users), sep = ""), levels = paste("", 1:tasks, sep = "") ),
result = factor(replicate(tasks*users,sample(results, 1, replace = TRUE)), levels = results)
)

data <- data %>%
mutate(summary = factor(word(result, - 1), levels = summary) ) %>%
add_column(limit = 100) %>%
group_by(task, result) %>%
mutate(counts = n()) %>%
mutate(metrics = counts/users*100) %>%
distinct(result, .keep_all = TRUE)
#ungroup()

# sucess vs failure for each task
data <- data %>% group_by(task, summary) %>% mutate(total = sum(metrics))
# Theme --------------------------------------------------------------------

# Titles
plotTitle <- "UX User Testing Results"
plotSubtitle <- paste(tasks, "tasks performed by", users, " users", sep = " ")
plotCaption <- "client: UDSA, date: 2017 November 17"

# Colors
backgroundColor <- "#ffffff"
primaryColor <- "#2a2a2a"
secondaryColor <- "#7a7a7a"
legendColor <- "#fafafa"

plotColors <- c(brewer.pal(9, "Blues")[7], brewer.pal(9, "Blues")[5], brewer.pal(9, "Reds")[7], brewer.pal(9, "Reds")[5])

# Typography
primaryFontFamily <- "Karla"
secondaryFontFamily <- "Karla"

baseFontSize <- 8
titleFontSize <- baseFontSize*1.75
subtitleFontSize <- baseFontSize*1.25
captionFontSize <- baseFontSize*1
legendFontSize <- baseFontSize*1
axisFontSize <- baseFontSize*1.25

update_geom_defaults("text", list(family = primaryFontFamily)) # update default geom text

theme_spine <- function(){
theme(

# aspect.ratio = 1/1, # fix the aspect ratio
text = element_text(family = primaryFontFamily),

plot.margin = unit( c(40, 40, 40, 40), "pt"),
plot.title = element_text(family = primaryFontFamily, size = titleFontSize, face = "plain", color = primaryColor, hjust=0, margin = unit(c(0, 0, 10, 0), "pt") ),
plot.subtitle = element_text(family = secondaryFontFamily, size = subtitleFontSize, color = primaryColor, face = "italic", hjust=0, margin = unit(c(0, 0, 40, 0), "pt") ),
plot.caption = element_text(family = secondaryFontFamily, size = captionFontSize, color = secondaryColor, face = "italic", hjust = 1, margin = unit(c(40, 0, 0, 0), "pt") ),
plot.background = element_rect(fill = backgroundColor),

panel.background = element_rect(fill = NA, colour = NA),
panel.border = element_blank(),
panel.grid = element_blank(),
panel.grid.major.y = element_line(size = 0.25, color = backgroundColor),
panel.grid.minor.y = element_line(size = 0.25, color = backgroundColor),
panel.ontop = TRUE,

axis.text.x = element_text(family = primaryFontFamily, size = captionFontSize, color = primaryColor, face = "bold", margin = unit(c(0, 0, 1, 0), "pt") ),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),

panel.spacing = unit(0, "lines"),
strip.background = element_blank(),
strip.text = element_blank(),

legend.background = element_rect(fill = legendColor, colour = NA),
legend.position = "bottom",
legend.direction = "horizontal",
legend.title = element_blank(),
legend.text = element_text(family = secondaryFontFamily, size = legendFontSize, color = primaryColor, face = "plain", margin = unit(c(0, 8, 0, 4), "pt") ),
legend.key = element_blank(),
legend.key.size = unit( 10, "pt")
#legend.key.height = unit(1, "pt"),
#legend.key.width = unit(7, "pt"),
#legend.spacing.x = unit(5, "pt"),

)
}
# Plot --------------------------------------------------------------------
labelShift <- 7

plot_spine <- ggplot(data) +

geom_bar(aes(x = task, y = ifelse(result %in% c(results[3], results[4]), -limit, limit ) ), position = "dodge", fill = "transparent", stat = "identity", width = 1) +
geom_bar(aes(x = task, y = ifelse(result %in% c(results[3], results[4]), -metrics, metrics ), fill = result), position = "stack", stat = "identity", width = 0.5) +

geom_label(aes(x = task, label = paste(total, "%", sep =""), y = ifelse(result %in% c(results[3], results[4]), -total - labelShift, total +labelShift ) ), fill = backgroundColor, family = secondaryFontFamily, label.size = FALSE, label.padding = unit(3, "points"), label.r = unit(6, "points"), color = secondaryColor, size = 2.5 ) +

scale_x_discrete() +
scale_fill_manual(values = plotColors, breaks = c("Direct Failure", "Indirect Failure", "Indirect Success", "Direct Success" ) ) +

labs(title = plotTitle, subtitle = plotSubtitle, caption = plotCaption) +

facet_wrap(~summary, ncol = 1, scale = "free", strip.position = "left") +
theme_spine()

#plot_spine

grob_spine <- ggplotGrob(plot_spine) # Get ggplot grob
#g$layout # Print the layuout

# Remove the grobs
pos <- grepl(pattern = "axis-b-1-2", grob_spine$layout$name)
grob_spine$grobs <- grob_spine$grobs[!pos]
grob_spine$layout <- grob_spine$layout[!pos, ]

#grid.newpage()
grid.draw(grob_spine) # Draw the plot
# Export --------------------------------------------------------------------

ggsave(grob_spine, height = 6, width = 9, device = cairo_pdf, filename = paste("export/", plotTitle, ".pdf", sep = "") )
ggsave(grob_spine, height = 6,width = 9, device = "svg", filename = paste("export/", plotTitle, ".svg", sep = "") )
ggsave(grob_spine, height = 6,width = 9, dpi = "retina", filename = paste("export/", plotTitle, ".png", sep = "") )