1. 三元相图基础与数据归一化原理第一次接触三元相图时我被这个三角形图表弄得一头雾水——明明有三个变量却要画在二维平面上。后来在分析药物协同效应实验数据时才发现这种可视化方式能直观展示三种成分的比例关系比三维散点图更利于发现规律。核心约束条件是三个变量的和必须为固定值通常是1或100%。但实际数据往往不符合这个要求比如我最近处理的抗生素浓度实验数据# 原始数据示例单位μg/mL df - data.frame( drug_A c(10, 20, 5, 15), drug_B c(5, 10, 25, 10), drug_C c(15, 10, 5, 5) )归一化操作的本质是将绝对浓度转换为相对比例。用R实现非常简单df_norm - df %% mutate(total drug_A drug_B drug_C, A_norm drug_A / total, B_norm drug_B / total, C_norm drug_C / total)但这里有个关键陷阱直接对原始数据归一化会丢失绝对浓度信息。比如(10,5,15)和(20,10,30)两组数据归一化后完全相同但实际生物效应可能差异显著。我在分析抗菌药物组合时就踩过这个坑——有些高浓度组合虽然比例相同但抑菌效果明显更强。2. ggtern基础绘制与刻度问题安装ggtern包时注意要同时安装依赖的ggplot2最新版install.packages(ggtern) library(ggtern)基础绘图代码看似简单ggtern(df_norm, aes(A_norm, B_norm, C_norm)) geom_point(size3)但默认生成的刻度会有两个典型问题刻度分布不均匀对数间隔而非线性只显示归一化后的比例值0-1范围这在材料组分分析中尤其麻烦。有次我展示合金成分分析时审稿人直接质疑图中显示Ag占30%但实际是30%还是30ppm 这就是没有正确显示绝对数值的后果。3. 均匀刻度与绝对数值显示方案通过scale_*_continuous系列函数可以自定义刻度。以药物浓度分析为例# 定义各药物最大浓度 max_A - max(df$drug_A) max_B - max(df$drug_B) max_C - max(df$drug_C) ggtern(df_norm, aes(A_norm, B_norm, C_norm)) geom_point(aes(colortotal), size4) scale_L_continuous( breaks seq(0, 1, 0.2), labels sprintf(%.1f, seq(0, max_A, length.out6)) ) scale_R_continuous( breaks seq(0, 1, 0.2), labels sprintf(%.1f, seq(0, max_B, length.out6)) ) scale_T_continuous( breaks seq(0, 1, 0.2), labels sprintf(%.1f, seq(0, max_C, length.out6)) ) labs(xDrug A (μg/mL), yDrug B, zDrug C)关键技巧在于breaks参数设置均匀的归一化刻度0-1范围labels参数映射回原始浓度值用颜色映射总浓度通过aes(colortotal)4. 实战案例药物协同效应分析最近分析抗生素组合数据时需要同时展示三种药物的比例关系绝对浓度信息协同效应强度通过颜色梯度完整代码如下# 模拟协同效应数据 set.seed(123) synergy_data - df_norm %% mutate(synergy rnorm(n(), meantotal/50, sd0.1)) # 高级绘图 plot - ggtern(synergy_data, aes(A_norm, B_norm, C_norm)) geom_point(aes(sizetotal, colorsynergy), alpha0.8) scale_size_continuous(range c(3, 10)) scale_color_gradient2( low blue, mid white, high red, midpoint mean(synergy_data$synergy) ) # 自定义刻度标签 scale_L_continuous( breaks seq(0, 1, 0.25), labels function(x) paste0(round(x*max_A,1), μg) ) scale_R_continuous( breaks seq(0, 1, 0.25), labels function(x) paste0(round(x*max_B,1), μg) ) scale_T_continuous( breaks seq(0, 1, 0.25), labels function(x) paste0(round(x*max_C,1), μg) ) theme_rgbw() labs( title Antibiotic Combination Synergy Analysis, color Synergy Score, size Total Concentration (μg/mL) ) # 添加等高线 plot geom_density_tern( aes(zsynergy), colorblack, alpha0.2 )这个方案成功解决了三个需求点位置反映药物比例点大小表示总浓度颜色梯度显示协同效应强度坐标轴标签直接显示绝对浓度5. 特殊场景处理技巧不等比数据的情况需要特别注意。有次分析催化剂组分时三种成分的量级差异很大主成分90%添加剂1%。直接归一化会导致次要成分挤在角落。解决方案是双重坐标轴ggtern(df, aes(xA, yB, zC)) geom_point() # 主坐标轴显示绝对数值 scale_L_continuous(nameMain Component (mg)) scale_R_continuous(nameAdditive1 (μg)) scale_T_continuous(nameAdditive2 (μg)) # 次坐标轴显示百分比 sec_axis_tern( breaks seq(0,1,0.2), labels paste0(seq(0,100,20), %) )大规模数据渲染时会遇到性能问题。测试过5万数据点时建议使用hexbin分箱ggtern(large_df, aes(x,y,z)) stat_hex_tern(bins30)采样显示set.seed(123) large_df %% sample_n(5000) %% ggtern(aes(x,y,z)) geom_point()