---
title: "Multi-Question Stacked Bar Charts (Legacy Reference)"
author: "Alexandra Pafford"
date: "14/08/2025"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Multi-Question Stacked Bar Charts (Legacy Reference)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

> **Note:** This functionality is now part of the unified `viz_stackedbar()` function.
> You can use `viz_stackedbar(data, x_vars = ...)` for the same functionality shown here.
> See the [main stackedbar vignette](stackedbar_vignette.html) for comprehensive documentation.
>
> The examples below still work with `viz_stackedbars()` for backward compatibility,
> but we recommend using `viz_stackedbar()` for new code.

This guide covers visualizing responses to multiple Likert-type questions simultaneously.

The multi-variable mode transforms wide survey data (where each question is a separate column) into an elegant stacked bar chart where:
- Each bar represents a different survey question
- Each stack within a bar represents a response category (e.g., "Strongly Agree", "Agree", etc.)
- Colors show the distribution of responses across all questions

This approach is particularly valuable for:
- **Comparing response patterns** across multiple related questions
- **Identifying questions** with similar or different response distributions
- **Visualizing survey batteries** (sets of questions with the same response scale)
- **Showing institutional confidence**, satisfaction measures, or attitude scales

The function handles many data preparation tasks automatically, including pivoting from wide to long format, managing `haven_labelled` variables from SPSS data, and creating publication-ready interactive visualizations.

## Migration to Unified Function

To migrate from `viz_stackedbars()` to `viz_stackedbar()`, simply change the function name:

```r
# Old way (still works)
viz_stackedbars(data, x_vars = c("q1", "q2", "q3"))

# New preferred way
viz_stackedbar(data, x_vars = c("q1", "q2", "q3"))
```

All parameters work the same way. The unified `viz_stackedbar()` also supports crosstab-style charts using `x_var` + `stack_var` parameters.

## ⚙️ Getting Started

Let's load the necessary libraries and examine our dataset. For this demonstration, we will be using the 2020 wave from the GSS dataset.

```{r libraries}
library(gssr)
library(dplyr)
library(highcharter)
library(tidyr)
library(dashboardr)

# Load GSS Panel 2020 data
data(gss_panel20)
```

## 📋 Data Preparation

Let's identify and prepare Likert-type questions from the 2016 wave (`_1a` variables) for ease of use in this practical.

```{r data-prep1}
# Look for confidence-related questions (common Likert-type questions in GSS)
confidence_vars <- names(gss_panel20)[grepl("^con.*_1a$", names(gss_panel20))]
cat("Confidence variables found:\n")
print(confidence_vars)


# Look for other attitude/satisfaction variables
attitude_vars <- names(gss_panel20)[grepl("(trust|fair|helpful|happy).*_1a$", names(gss_panel20))]
cat("\nAttitude variables found:\n")
print(attitude_vars)
```


```{r data-prep2}

# Create a working dataset with key Likert-type variables
gss_likert <- gss_panel20 %>%
  select(
    # Confidence in institutions (if available)
    any_of(confidence_vars),
    # Individual attitudes
    trust_1a, fair_1a, helpful_1a, happy_1a,
    # Additional context variables
    age_1a, sex_1a, degree_1a
  ) %>%
  # Remove completely empty rows
  filter(if_any(everything(), ~ !is.na(.)))

# Examine the response patterns for key variables
cat("Trust responses:\n")
table(gss_likert$trust_1a, useNA = "always")

cat("\nFair responses:\n") 
table(gss_likert$fair_1a, useNA = "always")

cat("\nHelpful responses:\n")
table(gss_likert$helpful_1a, useNA = "always")

cat("\nHappy responses:\n")
table(gss_likert$happy_1a, useNA = "always")
```

# 📊 Basic Multi-Question Charts

## Example 1: Social Trust and Attitudes

Now that we have our simplified data set, let's create our first multi-question chart using social attitude variables.

```{r stackedbars-basic}
# Define our questions and labels
social_questions <- c("trust_1a", "fair_1a", "helpful_1a")
social_labels <- c(
  "Interpersonal Trust",
  "Fairness of Others", 
  "Helpfulness of Others"
)

# Create basic multi-question chart
plot1 <- viz_stackedbars(
  data = gss_likert,
  x_vars = social_questions,
  x_var_labels = social_labels,
  title = "Social Attitudes and Trust",
  subtitle = "GSS Panel 2016 - Distribution of responses across social attitude questions",
  x_label = "Social Attitude Dimension",
  stack_label = "Response Level",
  stacked_type = "normal"
)

plot1
```

## Example 2: Percentage-Based Comparison

Now let's create a percentage-based chart to better compare response patterns across questions.

```{r stackedbars-percentage}
# Create percentage-based chart with custom colors
plot2 <- viz_stackedbars(
  data = gss_likert,
  x_vars = social_questions,
  x_var_labels = social_labels,
  title = "Social Attitudes - Response Distribution",
  subtitle = "Percentage breakdown showing response patterns across questions",
  x_label = "Social Attitude Dimension",
  stack_label = "Response Category",
  stacked_type = "percent",
  tooltip_suffix = "%",
  color_palette = c("#d7191c", "#fdae61", "#ffffbf", "#abdda4", "#2b83ba")
)

plot2
```

# 🎨 Advanced Customization

## Example 3: Custom Response Ordering and Mapping

Let's create a more sophisticated chart with custom response ordering and cleaner labels.

```{r stackedbars-custom}
# First, let's examine what the actual response values are
cat("Unique trust responses:\n")
print(unique(as.character(gss_likert$trust_1a)))

cat("\nUnique fair responses:\n")
print(unique(as.character(gss_likert$fair_1a)))
```


```{r stackedbars-custom2}

#TODO: There is a "Series 4" I think for NA values, that needs to be dealt with, i.e. ideally that has its own value?
# Create response mapping for cleaner labels
response_map <- list(
  "can't trust" = "High Trust/Positive", # I know this doesn't make sense, let's just pretend for the sake of the demo
  "can't be too careful" = "Low Trust/Negative", 
  "depends" = "Situational/Neutral",
  "would try to be fair" = "High Trust/Positive",
  "would take advantage of you" = "Low Trust/Negative",
  "depends" = "Situational/Neutral",
  "try to be helpful" = "High Trust/Positive",
  "looking out for themselves" = "Low Trust/Negative",
  "depends" = "Situational/Neutral"
)

# Define response order (from negative to positive)
response_order <- c("Low Trust/Negative", "Situational/Neutral", "High Trust/Positive")

# Create chart with custom mapping and ordering
plot3 <- viz_stackedbars(
  data = gss_likert,
  x_vars = social_questions,
  x_var_labels = social_labels,
  title = "Social Trust Dimensions with Standardized Responses",
  subtitle = "Responses mapped to consistent positive/negative categories",
  x_label = "Trust Dimension",
  stack_label = "Trust Level",
  stack_map_values = response_map,
  stack_order = response_order,
  stacked_type = "percent",
  tooltip_suffix = "%",
  color_palette = c("#d62728", "#ffbb78", "#2ca02c", "grey")
)

plot3
```

## Example 4: Including Missing Values

Let's create a chart that explicitly shows missing data patterns.

```{r stackedbars-missing}
# Create chart including NA values
plot4 <- viz_stackedbars(
  data = gss_likert,
  x_vars = social_questions,
  x_var_labels = social_labels,
  title = "Social Attitudes Including Non-Responses",
  subtitle = "Showing missing data patterns explicitly",
  x_label = "Social Attitude Question",
  stack_label = "Response",
  stack_map_values = response_map,
  include_na = TRUE,
  na_label_stack = "No Answer/Not Asked",
  stacked_type = "percent",
  tooltip_suffix = "%",
  color_palette = c("forestgreen", "darkred", "grey", "yellow")
)

plot4
```

# 📝 Working with Different Question Types

## Example 5: Happiness and Life Satisfaction

Let's work with happiness as a different type of Likert scale.

```{r stackedbars-happiness}
# Create a happiness-focused analysis
happiness_questions <- c("happy_1a")
happiness_labels <- c("General Happiness")

# Check happiness response values
cat("Happiness responses:\n")
table(gss_likert$happy_1a, useNA = "always")
```


```{r stackedbars-happiness2}
# Create happiness chart
plot5 <- viz_stackedbars(
  data = gss_likert,
  x_vars = "happy_1a",
  title = "General Happiness Distribution",
  x_label = "Well-being Measure",
  stack_label = "Happiness Level",
  stacked_type = "percent",
  tooltip_suffix = "%",
  color_palette = c("#2E8B57", "#FFD700", "#CD5C5C", "grey")
)

plot5
```

## Example 6: Combining Different Question Types

Let's create a comprehensive chart combining different types of attitude questions. In general, we recommend to have one battery per chart. But, if you really want to have different responses in the same chart, then you'll need to standardize the response labels before charting, especially if using SPSS data.


```{r stackedbars-comprehensive}
#TODO: this chart I dont get it has so many different scales, I think ideally should only be used with same scale?
# Standardize responses before charting
gss_standardized <- gss_likert %>%
  mutate(
    # Convert haven_labelled to character with labels first
    trust_1a_char = as.character(haven::as_factor(trust_1a, levels = "labels")),
    fair_1a_char = as.character(haven::as_factor(fair_1a, levels = "labels")),
    helpful_1a_char = as.character(haven::as_factor(helpful_1a, levels = "labels")),
    happy_1a_char = as.character(haven::as_factor(happy_1a, levels = "labels")),
    
    # Now do the case_when with the actual text labels
    trust_1a_std = case_when(
      trust_1a_char == "Can Trust" ~ "Positive",
      trust_1a_char == "Can't Be Too Careful" ~ "Negative", 
      trust_1a_char == "Depends" ~ "Neutral",
      TRUE ~ trust_1a_char
    ),
    fair_1a_std = case_when(
      fair_1a_char == "Most People Try to Be Fair" ~ "Positive",
      fair_1a_char == "Most People Try to Take Advantage" ~ "Negative",
      fair_1a_char == "Depends" ~ "Neutral",  # Fixed: was trust_1a
      TRUE ~ fair_1a_char
    ),
    helpful_1a_std = case_when(
      helpful_1a_char == "Most People Try to Be Helpful" ~ "Positive",
      helpful_1a_char == "Most People Look Out for Themselves" ~ "Negative",
      helpful_1a_char == "Depends" ~ "Neutral",  # Fixed: was trust_1a
      TRUE ~ helpful_1a_char
    ),
    happy_1a_std = case_when(
      happy_1a_char == "Very Happy" ~ "Positive",
      happy_1a_char == "Pretty Happy" ~ "Neutral",
      happy_1a_char == "Not Too Happy" ~ "Negative",
      TRUE ~ happy_1a_char
    )
  )
```


```{r stackedbars-comprehensive2}
# Check what the actual labels are after conversion
cat("Trust labels:\n")
table(gss_standardized$trust_1a_char, useNA = "always")

cat("\nFair labels:\n") 
table(gss_standardized$fair_1a_char, useNA = "always")

cat("\nHelpful labels:\n")
table(gss_standardized$helpful_1a_char, useNA = "always")

cat("\nHappy labels:\n")
table(gss_standardized$happy_1a_char, useNA = "always")
```


```{r stackedbars-comprehensive3}
# Then use the standardized versions
standardized_questions <- c("trust_1a_std", "fair_1a_std", "helpful_1a_std", "happy_1a_std")

# Write the question labels
standardized_labels <- c(
  "Can People Be Trusted?",
  "Are People Generally Fair?", 
  "Are People Generally Helpful?",
  "How Happy Are You?"
)

# Create comprehensive chart
plot6 <- viz_stackedbars(
  data = gss_standardized,
  x_vars = standardized_questions,
  x_var_labels = standardized_labels,
  title = "Social Attitudes and Well-being Battery",
  subtitle = "Multiple dimensions of social trust and personal happiness",
  x_label = "Question Domain",
  stack_label = "Response",
  stacked_type = "percent",
  tooltip_prefix = "Response: ",
  tooltip_suffix = "% of respondents",
  x_tooltip_suffix = " question"
)

plot6
```

# 🔬 Advanced Analysis Techniques

## Example 7: Demographic Subgroup Analysis

Let's create separate charts for different demographic groups.

```{r stackedbars-subgroups} 
## TODO: maybe we dont need the if logic here? I think is confusing for the tutorial.
# You probably noticed one of the response labels is incorrect. Let's fix that first. We can do this easily using mapping in the `viz_barcharts` function.
trust_fix_map <- list(
  "can't trust" = "can trust"
  # Add other mappings if needed
)

# Next, let's examine what degree values actually exist
cat("Degree values in data:\n")
table(gss_likert$degree_1a, useNA = "always")

# Convert degree to factor with labels to see what we're working with
degree_labels <- as.character(haven::as_factor(gss_likert$degree_1a, levels = "labels"))
cat("\nDegree labels:\n")
table(degree_labels, useNA = "always")

# Create education groups based on actual data
gss_education <- gss_likert %>%
  mutate(
    degree_label = as.character(haven::as_factor(degree_1a, levels = "labels")),
    education_group = case_when(
      degree_label %in% c("less than high school", "high school") ~ "High School or Less",
      degree_label %in% c("associate/junior college", "bachelor's", "graduate") ~ "College or More",
      TRUE ~ "Other/Missing"
    )
  ) %>%
  filter(education_group != "Other/Missing")

# Check the groups
cat("\nEducation groups:\n")
table(gss_education$education_group, useNA = "always")

# Filter for college or more
college_data <- gss_education %>%
  filter(education_group == "College or More")

cat("\nCollege data rows:", nrow(college_data), "\n")

# Filter for high school or less  
high_school_data <- gss_education %>%
  filter(education_group == "High School or Less")

cat("High school data rows:", nrow(high_school_data), "\n")

# Only create charts if we have sufficient data
if (nrow(college_data) > 50) {
  plot8a <- viz_stackedbars(
    data = college_data,
    x_vars = social_questions,
    x_var_labels = social_labels,
    stack_map_values = trust_fix_map,
    title = "Social Attitudes Among College-Educated",
    subtitle = paste0("Junior college, bachelor's, and graduate degree holders (n=", nrow(college_data), ")"),
    x_label = "Social Attitude Dimension",
    stack_label = "Response",
    stacked_type = "percent",
    include_na = TRUE,
    na_label_stack = "No Answer",
    tooltip_suffix = "%",
    color_palette = c("#2166ac", "#762a83", "#5aae61", "darkgrey")
  )
  
  print("College-educated chart:")
  print(plot8a)
} else {
  cat("Not enough college-educated respondents for analysis\n")
}

if (nrow(high_school_data) > 50) {
  plot8b <- viz_stackedbars(
    data = high_school_data,
    x_vars = social_questions,
    x_var_labels = social_labels,
    stack_map_values = trust_fix_map,
    title = "Social Attitudes Among High School Educated",
    subtitle = paste0("High school diploma or less (n=", nrow(high_school_data), ")"),
    x_label = "Social Attitude Dimension", 
    stack_label = "Response",
    stacked_type = "percent",
    include_na = TRUE,
    na_label_stack = "No Answer",
    tooltip_suffix = "%",
    color_palette = c("#2166ac", "#762a83", "#5aae61", "darkgrey")
  )
  
  print("High school educated chart:")
  print(plot8b)
} else {
  cat("Not enough high school educated respondents for analysis\n")
}
```

# 📋 Working with Survey Batteries

## Example 9: Creating Question Batteries

Let's demonstrate how to work with related sets of questions (survey batteries).

```{r stackedbars-battery}
# Create a social trust battery
trust_battery <- c("trust_1a", "fair_1a", "helpful_1a")
trust_battery_labels <- c(
  "Interpersonal Trust",
  "Perceived Fairness",
  "Perceived Helpfulness"
)

# Create a comprehensive battery analysis
plot9 <- viz_stackedbars(
  data = gss_likert,
  x_vars = trust_battery,
  x_var_labels = trust_battery_labels,
  title = "Social Trust Battery - Complete Analysis",
  subtitle = "Comprehensive view of social trust dimensions with enhanced tooltips",
  x_label = "Trust Dimension",
  stack_label = "Response Category",
  stacked_type = "percent",
  tooltip_prefix = "Percentage: ",
  tooltip_suffix = "% of respondents",
  show_var_tooltip = TRUE,
  include_na = TRUE,
  na_label_stack= "No answer",
  color_palette = c("#8c510a", "#d8b365", "#f6e8c3", "darkgrey")
)

plot9
```

# 🏷️ Labels and Tooltips Reference

## Summary of Label and Tooltip Options

The `viz_stackedbars()` function offers extensive customization for labels and tooltips:

| Parameter | Description | Example |
|-----------|-------------|---------|
| `x_label` | X-axis title | `"Question"` |
| `y_label` | Y-axis title (auto-set based on stacked_type) | `"Percentage"` |
| `stack_label` | Legend title | `"Response Category"` |
| `x_var_labels` | Custom labels for each question | `c("Trust", "Fairness")` |
| `tooltip_prefix` | Text before value in tooltip | `"Score: "` |
| `tooltip_suffix` | Text after value in tooltip | `"%"`, `" respondents"` |
| `x_tooltip_suffix` | Text after question name in tooltip | `" question"` |
| `show_var_tooltip` | Show question name in tooltip | `TRUE` |

```{r labels-reference}
# Example with all label/tooltip options
viz_stackedbars(
  data = gss_likert,
  x_vars = c("trust_1a", "fair_1a"),
  x_var_labels = c("Trust", "Fairness"),
  title = "Social Attitudes",
  x_label = "Attitude Measure",
  y_label = "Percent of Respondents",
  stack_label = "Response Level",
  stacked_type = "percent",
  tooltip_prefix = "",
  tooltip_suffix = "% responded",
  show_var_tooltip = TRUE
)
```

# 💡 Best Practices and Tips

## Example 10: Publication-Ready Chart

Let's create a fully customized, publication-ready chart.

```{r stackedbars-publication}
# Create the most polished example
plot10 <- viz_stackedbars(
  data = gss_likert,
  x_vars = social_questions,
  x_var_labels = c(
    "Interpersonal Trust\n('Can most people be trusted?')",
    "Perceived Fairness\n('Do people try to be fair?')",
    "Perceived Helpfulness\n('Are people helpful?')"
  ),
  title = "Social Capital Dimensions in American Society",
  subtitle = "General Social Survey Panel 2016 (N = 2,867 respondents)\nPercentage distribution of responses across social trust measures",
  x_label = "Social Trust Dimension",
  stack_label = "Response Category",
  stacked_type = "percent",
  tooltip_prefix = "",
  tooltip_suffix = "% of respondents",
  x_tooltip_suffix = "",
  include_na = TRUE,
  na_label_stack = "No response",
  color_palette = c("#b2182b", "#ef8a62", "#fddbc7", "darkgrey"),
  show_var_tooltip = TRUE
)

plot10
```

# ✅ Summary and Best Practices

## ✅ Key Features Demonstrated

1. **Multi-question visualization** with automatic wide-to-long data transformation
2. **Custom question labeling** for more descriptive axis labels
3. **Response mapping and ordering** for consistent presentation
4. **Missing value handling** with explicit NA categories
5. **Percentage vs. count displays** for different analytical needs
6. **Demographic subgroup analysis** for comparative insights
7. **Survey battery analysis** for related question sets
8. **Publication-ready styling** with comprehensive customization

## 🎯 Best Practices for Multi-Question Charts

1. Choose questions with similar response scales
 - Use questions that have the same or compatible response categories
 - Consider mapping different scales to common categories when appropriate

2. Order questions logically
 - Group related concepts together
 - Consider ordering by typical response patterns (most positive to least positive)
 - Place most important questions first

3. Use appropriate stacking type
 - Use "percent" for comparing response patterns across questions
 - Use "normal" when absolute counts matter more than proportions

4. Handle missing data thoughtfully
 - Decide whether missing patterns are substantively meaningful
 - Use include_na = TRUE when non-response patterns are important
 - Provide clear labels for missing categories

5. Choose colors carefully
 - Use consistent color schemes across related charts
 - Consider the meaning of response categories (positive/negative)
 - Ensure sufficient contrast between adjacent categories
 - Test for colorblind accessibility

6. Customize tooltips for clarity
 - Include question text in tooltips when helpful
 - Use appropriate number formatting (percentages vs. counts)
 - Provide context about sample sizes when relevant


## 📚 Conclusion

The `viz_stackedbars()` function provides a powerful solution for visualizing multiple Likert-type survey questions simultaneously. Its key advantages include:

- **Automatic data transformation** from wide to long format
- **Flexible question labeling** for publication-ready displays
- **Comprehensive customization options** for professional presentations
- **Interactive tooltips** for enhanced data exploration
- **Consistent handling** of survey data complexities

By leveraging the GSS Panel 2020 dataset, we've demonstrated how this function can reveal patterns in social attitudes, trust measures, and other survey constructs. The ability to compare response distributions across multiple related questions makes it an invaluable tool for survey researchers, enabling them to communicate complex patterns in public opinion and social attitudes effectively.

Whether you're analyzing institutional confidence, social trust, life satisfaction, or any other multi-item survey construct, `viz_stackedbars()` provides the flexibility and polish needed for both exploratory analysis and publication-ready visualizations.
