ggplot2:基于多虚拟变量比例的性别分面柱状图,如何重构数据?
Hey there! Let's fix this up for you—your goal is totally achievable with a bit of data reshaping and tweaking the ggplot code. Here's a step-by-step solution:
Step 1: Reshape Your Data from Wide to Long
Your current data is in "wide" format (each transport mode is a separate column), but we need it in "long" format to easily plot all 9 transport modes at once. We'll use tidyr::pivot_longer() for this, and clean up the transport mode names while we're at it.
First, load the tidyverse package (it includes dplyr, tidyr, and ggplot2 which we'll need):
library(tidyverse)
Then reshape the data:
# Reshape wide data to long format dfTrans_long <- dfTrans %>% pivot_longer( cols = starts_with("trans"), # Select all columns starting with "trans" names_to = "transport_mode", # Name of the new column for transport modes values_to = "used" # Name of the new column for 0/1 values ) %>% # Clean up the transport mode names (remove the "trans" prefix) mutate(transport_mode = str_remove(transport_mode, "trans"))
Step 2: Calculate Proportions of Users (Value = 1) by Gender & Transport Mode
Instead of relying on ..prop.. in ggplot (which can be tricky with facets), let's pre-calculate the proportion of people who used each transport mode (the mean of the used column works perfectly here, since averaging 0s and 1s gives the proportion of 1s):
trans_proportions <- dfTrans_long %>% group_by(gender, transport_mode) %>% summarize( usage_proportion = mean(used), # Mean of 0/1 equals the proportion of users .groups = "drop" # Drop grouping after calculation )
Step 3: Build the Visualization
Now we can create the exact plot you described: 3 rows of 3 transport modes, each row showing gender-specific usage proportions as bars. We'll use facet_wrap() to arrange the 9 modes into 3 rows, and customize axes to show percentages clearly.
ggplot(trans_proportions, aes(x = gender, y = usage_proportion, fill = gender)) + geom_col(width = 0.7, show.legend = FALSE) + # Bars, no redundant legend # Format Y-axis as percentages scale_y_continuous( labels = scales::percent_format(accuracy = 1), limits = c(0, 1), # Optional: Fix Y-axis to 0-100% for consistency expand = c(0, 0) # Remove extra space at the bottom of bars ) + # Arrange transport modes into 3 rows (matches your 9-variable layout) facet_wrap(~transport_mode, nrow = 3) + # Add clear labels and clean theme labs( x = "Gender", y = "Percentage of Users", title = "Transport Mode Usage by Gender", subtitle = "Proportion of respondents who used each transport mode (value = 1)" ) + theme_minimal() + theme( axis.text.x = element_text(size = 10), strip.text = element_text(size = 11, face = "bold"), plot.title = element_text(size = 14, face = "bold") )
Why This Works Better Than Your Original Code
- Data Reshaping: Converting to long format lets us plot all transport modes in one go, instead of writing repetitive code for each column.
- Pre-Calculated Proportions: Using
mean(used)gives a clear, easy-to-interpret measure of usage, avoiding confusion with..prop..which depends on strict grouping rules. - Facet Layout:
facet_wrap(nrow=3)neatly organizes your 9 transport modes into 3 rows, exactly matching your desired layout.
If you want to tweak colors, adjust bar widths, or modify the theme further, you can easily add scale_fill_*() or extra theme() elements.
内容的提问来源于stack exchange,提问作者Gabby Hubert

