求助:ggplot2直方图颜色无法修改(5k完赛时间POSIXct数据)
Hey there! Let's sort out why your fill isn't working and why you're getting errors with POSIXct. The root problem here is a misuse of data types—let's break it down:
The Core Mistake: Using POSIXct for Durations
POSIXct is designed to store specific date-time points (like 2024-05-20 15:34:00), not durations (like a 15 minute 34 second race time). When you convert your finish times to POSIXct, R is implicitly attaching a default date (usually today's date) to each time string, turning your race durations into random "moments in time"—this confuses ggplot and breaks your fill mapping.
The Fix: Use the Right Data Type for Durations
You have two simple, effective options to fix this:
Option 1: Use the hms Package for Proper Duration Types
The hms package lets you store time intervals natively, which ggplot understands perfectly. Here's how to implement it:
# Load required libraries library(hms) library(ggplot2) # Simulate your raw data (replace with your actual data frame) run_data <- data.frame(finish_time = c("15:34", "14:23", "17:34", "16:10", "15:45", "18:02")) # Convert string times to duration objects (add "00:" since your data is min:sec) run_data$duration <- parse_hms(paste0("00:", run_data$finish_time)) # Create your histogram with working fill ggplot(run_data, aes(x = duration, fill = ..count..)) + geom_histogram(binwidth = 60) + # Bin by 60 seconds (1 minute) scale_x_time(labels = function(x) sprintf("%02d:%02d", hour(x), minute(x))) + labs( x = "5k Finish Time", y = "Number of Runners", title = "Distribution of 5k Finish Times" ) + theme_minimal()
Option 2: Convert to Numeric Minutes (Simpler Alternative)
If you don't want to use an extra package, convert your time strings to total minutes as a numeric value. This is super straightforward:
library(ggplot2) # Simulate raw data run_data <- data.frame(finish_time = c("15:34", "14:23", "17:34", "16:10", "15:45", "18:02")) # Convert "mm:ss" strings to total minutes (numeric) run_data$total_minutes <- sapply(strsplit(run_data$finish_time, ":"), function(x) { as.numeric(x[1]) + as.numeric(x[2])/60 }) # Build your histogram with functional fill ggplot(run_data, aes(x = total_minutes, fill = ..count..)) + geom_histogram(binwidth = 1) + # Bin by 1 minute scale_x_continuous( labels = function(x) sprintf("%02d:%02d", floor(x), round((x - floor(x))*60)) ) + labs( x = "5k Finish Time", y = "Number of Runners", title = "Distribution of 5k Finish Times" ) + theme_minimal()
Why This Works
By using either a proper duration type or numeric minutes, you're giving ggplot a continuous, meaningful variable to work with. The fill aesthetic will now map correctly to the histogram bin counts (or any other variable you want to use for coloring).
内容的提问来源于stack exchange,提问作者Matthew Rogers

