You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用R ggplot2或其他工具绘制按行着色的堆叠直方图式条码图

解决方案:保持条码图布局并按行着色(R + Python)

我来帮你搞定这个需求——既要保留plot(test.matrix)那种“条码图”的布局(柱宽对应行总和,柱高对应行内列差异),又要按指定颜色向量给每行着色。下面分别提供R(用ggplot2)和Python的实现方案:

R 实现(ggplot2)

首先我们需要把表格数据转换成适合ggplot2处理的格式,同时计算出控制柱宽的行总和、控制柱高的列差异,再用矩形来模拟原生plot的布局:

# 测试数据初始化
test.matrix <- matrix(c(70, 120, 65, 140, 13, 68, 46, 294, 52, 410), ncol=2, byrow=TRUE)
rownames(test.matrix) <- c("BC.1", "BC.2", "GC", "MO", "EB")
colnames(test.matrix) <- c("12m","3m")
test.matrix <- as.table(test.matrix)

# 自定义颜色向量
color.ct <- c("gold","yellowgreen","navy","royalblue","orangered")
names(color.ct) <- rownames(test.matrix)

# 转换为数据框并计算关键参数
df <- as.data.frame(test.matrix)
# 计算每行总和(柱宽)
df$row_sum <- ave(df$Freq, df$Var1, FUN = sum)
# 计算行内列差异(柱高,这里用12m - 3m,要绝对值的话改成abs(x[1]-x[2]))
df$diff <- ave(df$Freq, df$Var1, FUN = function(x) x[1] - x[2])
# 保留每个行的唯一记录(因为同一行的sum和diff是重复的)
df_unique <- df[!duplicated(df$Var1), ]

# 计算每个条形的x轴起止位置(累积宽度定位)
df_unique$x_start <- c(0, cumsum(df_unique$row_sum)[-nrow(df_unique)])
df_unique$x_end <- df_unique$x_start + df_unique$row_sum
# 计算y轴起止位置(以0为基准,差异为高度)
df_unique$y_bottom <- pmin(0, df_unique$diff)
df_unique$y_top <- pmax(0, df_unique$diff)

# 用ggplot2绘制
library(ggplot2)

ggplot(df_unique) +
  geom_rect(aes(xmin = x_start, xmax = x_end, 
                ymin = y_bottom, ymax = y_top,
                fill = Var1)) +
  scale_fill_manual(values = color.ct) +
  labs(x = "行总和", y = "12m - 3m 差异", fill = "类别") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

这段代码会生成和原生plot(test.matrix)布局一致的图形,同时每个行的条形会使用你指定的颜色。如果需要柱高是差异的绝对值,只需要修改diff的计算逻辑即可。

Python 实现(matplotlib)

在Python中,我们可以直接用matplotlib绘制矩形来实现相同的效果,步骤和R类似:

import matplotlib.pyplot as plt
import numpy as np

# 测试数据初始化
test_matrix = np.array([[70, 120], [65, 140], [13, 68], [46, 294], [52, 410]])
rownames = ["BC.1", "BC.2", "GC", "MO", "EB"]
colnames = ["12m", "3m"]

# 自定义颜色向量
color_ct = ["gold", "yellowgreen", "navy", "royalblue", "orangered"]
color_dict = dict(zip(rownames, color_ct))

# 计算关键参数:行总和(柱宽)、列差异(柱高)
row_sums = test_matrix.sum(axis=1)
diffs = test_matrix[:, 0] - test_matrix[:, 1]  # 要绝对值的话用np.abs()

# 计算每个矩形的x轴起止位置
x_starts = np.cumsum(row_sums) - row_sums
x_ends = x_starts + row_sums

# 创建绘图对象
fig, ax = plt.subplots(figsize=(10, 6))

# 逐个绘制每个行对应的条形(矩形)
for idx in range(len(rownames)):
    x_start = x_starts[idx]
    x_end = x_ends[idx]
    y_bottom = min(0, diffs[idx])
    y_top = max(0, diffs[idx])
    # 添加矩形到画布
    rect = plt.Rectangle((x_start, y_bottom), 
                         width=x_end - x_start, 
                         height=y_top - y_bottom,
                         color=color_dict[rownames[idx]])
    ax.add_patch(rect)

# 设置坐标轴范围和标签
ax.set_xlim(0, x_ends[-1])
ax.set_ylim(min(diffs) - 10, max(diffs) + 10)  # 留一点边距让图形更美观
ax.set_xlabel("行总和")
ax.set_ylabel("12m - 3m 差异")

# 添加图例
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor=color_ct[i], label=rownames[i]) for i in range(len(rownames))]
ax.legend(handles=legend_elements, loc="upper right")

# 调整布局并显示
plt.tight_layout()
plt.show()

这个Python版本同样完美匹配你的需求,你可以根据实际需要调整柱高的计算逻辑(比如用绝对值)。

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

火山引擎 最新活动