ggplot2 aes(fill)填充异常求助:足球赛程可视化颜色不符预期
Let's work through why your tile fill colors aren't behaving as expected and fix it step by step:
First, Diagnose the Core Issue
Looking at your code, you're using fill=Pos where Pos is an integer representing league position. By default, ggplot treats integer values as continuous variables, so it applies a smooth gradient color scale. This likely doesn't match what you want—you probably intended each distinct league position to have a unique, discrete color instead of a blended gradient.
Also, quick check of your sample data: most teams have consistent Pos values across game weeks (GW), but if you meant for every tile of a team to use the same fixed position (like their current season-long rank), we can adjust for that too.
Solution 1: Treat Position as a Discrete Category
Convert Pos to a factor so ggplot recognizes it as distinct ranks, then use a discrete color scale for clear differentiation:
library(tidyverse) df %>% ggplot() + # Convert Pos to factor to get unique colors per rank geom_tile(aes(x = GW, y = team, fill = factor(Pos)), colour = "black") + geom_text(aes(x = GW, y = team, label = oppo), size = 3) + theme_void() + theme( axis.text = element_text(face = "bold"), axis.text.y = element_text(margin = margin(0, -20, 0, 0)) ) + scale_x_continuous(position = "top", breaks = 1:15) + labs( caption = paste("xxx rocks | ", Sys.Date(), sep = ""), fill = "League Position" # Add a clear legend title ) + # Use a colorblind-friendly discrete palette; reverse so top ranks stand out more scale_fill_viridis_d(option = "plasma", reverse = TRUE)
Why this works:
factor(Pos)turns your integer ranks into distinct categories, so each position gets its own unique color instead of a gradient.scale_fill_viridis_d()uses a colorblind-friendly palette that makes ranks easy to tell apart, andreverse=TRUEensures higher positions (smaller numbers) have more prominent colors—intuitive for league rankings.
Solution 2: Fix Positions to a Single Value Per Team (If Needed)
If you want every tile for a team to use the same position color (e.g., their latest league rank), first standardize the position data:
# Get the latest position for each team (using the highest GW in your dataset) team_fixed_pos <- df %>% group_by(team) %>% filter(GW == max(GW)) %>% select(team, fixed_pos = Pos) # Merge this fixed position back to your original data df_updated <- df %>% left_join(team_fixed_pos, by = "team") # Plot using the unified fixed position df_updated %>% ggplot() + geom_tile(aes(x = GW, y = team, fill = factor(fixed_pos)), colour = "black") + geom_text(aes(x = GW, y = team, label = oppo), size = 3) + theme_void() + theme( axis.text = element_text(face = "bold"), axis.text.y = element_text(margin = margin(0, -20, 0, 0)) ) + scale_x_continuous(position = "top", breaks = 1:15) + labs( caption = paste("xxx rocks | ", Sys.Date(), sep = ""), fill = "Latest League Position" ) + scale_fill_viridis_d(option = "plasma", reverse = TRUE)
Why this works:
- We first create a lookup table of each team's most recent position, then merge it with the original data. Now every tile for a team uses the same fixed position color, consistent across all game weeks.
内容的提问来源于stack exchange,提问作者BulletTooth

