如何使用colorspace包的scale_fill_continuous_divergingx实现一端线性一端对数的不平衡发散色阶?
Absolutely! You can achieve this custom diverging scale with colorspace::scale_fill_continuous_divergingx by building a piecewise transformation—using a log scale for p-values below 0.05 and a linear scale for values above it. This keeps both ranges readable while clearly anchoring the 0.05 midpoint. Here's how to implement it:
Step 1: Define a Custom Piecewise Transformation
We need a transformation that treats values below and above 0.05 differently, while ensuring the 0.05 midpoint aligns perfectly with the diverging color scale's center. We'll use scales::trans_new() to create this:
library(scales) library(dplyr) # Create a custom transformation for p-values p_piecewise_trans <- trans_new( name = "p_piecewise", transform = function(x) { case_when( # Log-transform values below 0.05 (relative to midpoint to center at 0) x < 0.05 ~ log10(x / 0.05), # Linear-transform values above 0.05 (scaled to span [0,1] relative to midpoint) x >= 0.05 ~ (x - 0.05) / (1 - 0.05) ) }, inverse = function(y) { case_when( # Reverse log transform for negative values y < 0 ~ 0.05 * 10^y, # Reverse linear transform for positive values y >= 0 ~ 0.05 + y * (1 - 0.05) ) }, # Generate readable breaks: log breaks for small p-values, linear for large breaks = function(x) { log_breaks <- log_breaks()(x[x < 0.05]) linear_breaks <- seq(0.05, max(x[x >= 0.05]), by = 0.2) unique(c(log_breaks, linear_breaks)) }, # Format labels for readability: scientific notation for small p-values format = function(x) { ifelse(x < 0.05, format(x, scientific = TRUE, digits = 2), format(x, digits = 2)) } )
Step 2: Apply the Transformation to Your Plot
Now plug this custom transformation into scale_fill_continuous_divergingx, setting mid = 0.05 to anchor the color scale's center exactly at your threshold:
library(ggplot2) library(colorspace) ggplot(df, aes(x = factor(group), y = factor(name), fill = p_adjusted)) + geom_tile(color = "white", size = 0.5) + # Add white borders to distinguish tiles scale_fill_continuous_divergingx( name = "Adjusted p-value", mid = 0.05, palette = "RdYlBu", trans = p_piecewise_trans, guide = guide_colorbar(title.position = "top", title.hjust = 0.5) ) + theme_classic() + labs(x = "Group", y = "Feature") + theme( legend.position = "bottom", legend.key.width = unit(3, "cm") # Widen color bar to improve readability of breaks )
Why This Fixes Your Previous Issues
- Default linear scale: Compresses tiny p-values into an indistinguishable range—this log/linear split pulls apart small values while keeping larger ones distinct.
- Tweaking
p1/p2/p3/p4: These parameters adjust global scale steepness, but can't create a true piecewise split between log and linear behavior. - Global log transform: Squashes all values above 0.05 into a tiny sliver of the color bar—our piecewise approach preserves linearity for larger p-values so they remain readable.
内容的提问来源于stack exchange,提问作者Midnighter

