You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ggplot中scale_color_gradient2颜色渐变失效问题求助

问题:ggplot颜色渐变失效,点始终显示中间色

尝试制作类似Baseball Savant的百分位排名图表时,颜色渐变功能无法正常工作:ggplot能根据MaxExitVelo正确计算击球手排名,但无论排名位置如何,点的颜色始终固定为mid(白色),无法实现蓝-白-红的渐变效果。

测试数据:

test_df <- data.frame(
  Batter = c("Player 1", "Player 2", "Player 3", "Player 4"),
  MaxExitVelo = c(105, 107, 102, 108),
  rank = c(1, 2, 3, 4)
)

原绘图代码:

test_df %>% 
  filter(Batter == "Player 2") %>% #手动修改Batter名称计算排名
  ggplot(aes(x = rank, y = "")) +
  geom_point(size = 10, aes(color = rank)) +
  geom_text(aes(label = rank)) +
  geom_label(aes(label = round(MaxExitVelo, digits = 1)), nudge_x = 0, nudge_y = 0.15) +
  ggtitle("Max Exit Velocity") +
  scale_x_reverse(expand = c(0,0.5), limits = c(max_rank + 1,  0)) +
  scale_color_gradient2(low = "blue", mid = "white", high = "red") + 
  theme_linedraw(base_line_size = 5) +
  theme(legend.position = "none",
         panel.border = element_rect(color = "white"),
         panel.grid.major.x = element_blank(),
         panel.grid.minor.x = element_blank(),
         axis.ticks.y = element_blank(),
         axis.text.y = element_blank(),
         axis.title.y = element_blank(),
         axis.ticks.x = element_blank(),
         axis.text.x = element_blank(),
         axis.title.x = element_blank(),
        plot.title = element_text(hjust = 0.5, vjust = -15)
  )

问题原因

filter(Batter == "Player 2") 执行后,数据框仅剩余单个行,rank 为唯一值(此处为2)。scale_color_gradient2 需要基于完整的数值范围计算颜色映射,当仅存在单个值时,无法生成渐变区间,因此默认使用中间色(白色)。

解决方案

方法1:手动指定整体排名范围

在scale_color_gradient2中设置limits为整个数据集的rank范围,让ggplot识别完整的数值区间:

# 获取整体rank的范围
rank_range <- range(test_df$rank)

test_df %>% 
  filter(Batter == "Player 2") %>%
  ggplot(aes(x = rank, y = "")) +
  geom_point(size = 10, aes(color = rank)) +
  geom_text(aes(label = rank)) +
  geom_label(aes(label = round(MaxExitVelo, digits = 1)), nudge_x = 0, nudge_y = 0.15) +
  ggtitle("Max Exit Velocity") +
  scale_x_reverse(expand = c(0,0.5), limits = c(max(test_df$rank) + 1,  0)) +
  scale_color_gradient2(low = "blue", mid = "white", high = "red", limits = rank_range) + 
  theme_linedraw(base_line_size = 5) +
  theme(legend.position = "none",
         panel.border = element_rect(color = "white"),
         panel.grid.major.x = element_blank(),
         panel.grid.minor.x = element_blank(),
         axis.ticks.y = element_blank(),
         axis.text.y = element_blank(),
         axis.title.y = element_blank(),
         axis.ticks.x = element_blank(),
         axis.text.x = element_blank(),
         axis.title.x = element_blank(),
        plot.title = element_text(hjust = 0.5, vjust = -15)
  )

方法2:转换为百分位数值

将rank转换为0-100的百分位(排名越靠前,百分位越高),贴合Baseball Savant的逻辑,单个点也能对应正确的渐变位置:

test_df <- test_df %>%
  mutate(rank_pct = (max(rank) - rank + 1)/max(rank)*100) # 计算百分位,100为最高排名

test_df %>% 
  filter(Batter == "Player 2") %>%
  ggplot(aes(x = rank, y = "")) +
  geom_point(size = 10, aes(color = rank_pct)) +
  geom_text(aes(label = rank)) +
  geom_label(aes(label = round(MaxExitVelo, digits = 1)), nudge_x = 0, nudge_y = 0.15) +
  ggtitle("Max Exit Velocity") +
  scale_x_reverse(expand = c(0,0.5), limits = c(max(test_df$rank) + 1,  0)) +
  scale_color_gradient2(low = "blue", mid = "white", high = "red", limits = c(0,100)) + 
  theme_linedraw(base_line_size = 5) +
  theme(legend.position = "none",
         panel.border = element_rect(color = "white"),
         panel.grid.major.x = element_blank(),
         panel.grid.minor.x = element_blank(),
         axis.ticks.y = element_blank(),
         axis.text.y = element_blank(),
         axis.title.y = element_blank(),
         axis.ticks.x = element_blank(),
         axis.text.x = element_blank(),
         axis.title.x = element_blank(),
        plot.title = element_text(hjust = 0.5, vjust = -15)
  )

内容的提问来源于stack exchange,提问作者norcal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 21:47:31