如何为ggplot2各Utterance分面独立设置颜色刻度范围?
问题描述
我有Utterance中音节的dur(时长)数据,想用ggplot2的geom_tile绘制。当前实现的问题是颜色刻度基于整个数据框的音节时长最大值设定,我想要每个Utterance的颜色刻度范围统一——不管某个Utterance有多少音节,它里面最短和最长的音节,要和其他Utterance里的最短、最长音节对应相同的颜色色调。
当前代码:
library(ggplot2) df %>% ggplot(aes(x = start + dur/2, y = MM, width = dur, height = 0.3, fill = rank)) + geom_tile(size = 0.65, color = "white") + facet_wrap(~ Utterance, scales = "free_x", ncol = 1)+ labs(fill = "SyllDur")
数据结构:
df <- structure(list(Utterance = structure(c(1L, 4L, 4L, 1L, 4L, 1L, 1L, 4L, 1L, 4L, 4L, 1L, 4L, 4L, 4L, 4L, 4L, 4L), levels = c("C: [what's] a !mountain! for you:", "NA: (0.554)", "C: ((v: laughs))=", "A: =I don't know the (Schauinsland) is a small mount[ain]" ), class = "factor"), MM = c("syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll", "syll"), start = c(407, 3967, 4827, 1147, 3682, 577, 847, 4697, 0, 4317, 3807, 1340, 5287, 4457, 3437, 4037, 4917, 5517), dur = c(170L, 70L, 90L, 193L, 125L, 270L, 300L, 130L, 407L, 140L, 160L, 480L, 230L, 240L, 245L, 280L, 370L, 538L), rank = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12)), class = c("tbl_df", "tbl", "data.frame" ), row.names = c(NA, -18L))
解决方案
核心思路是按每个Utterance分组,对dur进行归一化处理,让每个组内的dur都映射到[0,1]区间,这样所有Utterance的颜色刻度就能统一:最短音节对应颜色标尺的最小值,最长对应最大值。
具体实现代码
library(ggplot2) library(dplyr) # 对每个Utterance的时长做组内归一化 df_normalized <- df %>% group_by(Utterance) %>% mutate(norm_dur = (dur - min(dur)) / (max(dur) - min(dur))) %>% ungroup() # 绘制图形 df_normalized %>% ggplot(aes(x = start + dur/2, y = MM, width = dur, height = 0.3, fill = norm_dur)) + geom_tile(size = 0.65, color = "white") + facet_wrap(~ Utterance, scales = "free_x", ncol = 1) + # 自定义颜色渐变,可选将归一化值转回原始时长刻度 scale_fill_gradient( name = "SyllDur", low = "#f7fbff", high = "#08306b", labels = function(x) { # 用全局时长极值生成刻度标签,让图例更直观 global_min <- min(df$dur) global_max <- max(df$dur) round(x * (global_max - global_min) + global_min) } ) + labs(x = "Time", y = "Syllable")
代码说明
norm_dur = (dur - min(dur)) / (max(dur) - min(dur)):把每个Utterance内的时长转换为0到1之间的数值,0对应组内最短时长,1对应组内最长时长,保证所有组的颜色映射基准一致scale_fill_gradient():自定义颜色渐变风格,通过labels参数将归一化数值转回原始时长刻度,避免图例显示0-1的抽象范围- 保留
scales = "free_x",确保每个Utterance的时间轴范围独立显示,不互相干扰
如果不需要原始时长的刻度标签,直接使用norm_dur作为fill的映射变量即可,图例会显示0-1范围,同样能满足颜色统一的需求。
内容的提问来源于stack exchange,提问作者Chris Ruehlemann
相关产品推荐
相关产品推荐

