在Matplotlib中构建双向条形图:变量居中与百分比轴设置
双向条形图实现方案
下面是针对你的需求的完整实现代码,解决level垂直居中显示和X轴百分比格式化的问题,同时修正了DataFrame中variable列大小写不一致的问题(比如Exam和exam会被识别为不同分组,先统一处理):
步骤1:数据预处理
首先统一variable列的大小写,避免分组错误:
import pandas as pd import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter # 构造你的DataFrame data = [ ["volfluid", "1L", 0.718, 0.690], ["volfluid", "2L", 0.501, 0.808], ["volfluid", "5L", 0.181, 0.920], ["MAP", "64", 0.434, 0.647], ["MAP", "58", 0.477, 0.854], ["MAP", "52", 0.489, 0.904], ["Exam", "dry", 0.668, 0.713], ["exam", "euvolemic", 0.475, 0.798], ["exam", "wet", 0.262, 0.893], ["pmh", "COPD", 0.506, 0.804], ["pmh", "Kidney", 0.441, 0.778], ["pmh", "HF", 0.450, 0.832], ["Case", "1 (PIV)", 0.435, 0.802], ["Case", "2 (CVC)", 0.497, 0.809] ] df = pd.DataFrame(data, columns=["variable", "level", "margins_fluid", "margins_vp"]) # 统一variable列的大小写,避免分组错误 df["variable"] = df["variable"].str.lower()
步骤2:绘图实现
# 按variable分组,计算每个组的y轴位置范围 grouped = df.groupby("variable") y_positions = [] current_y = 0 group_spacing = 2 # 组之间的间距 level_spacing = 1 # 同组内level的间距 # 先计算所有y位置 for name, group in grouped: n_levels = len(group) # 分配当前组内每个level的y位置 group_y = list(range(current_y, current_y + n_levels * level_spacing, level_spacing)) y_positions.extend(group_y) current_y += n_levels * level_spacing + group_spacing # 初始化画布 plt.figure(figsize=(12, 10)) # 绘制左向条形(margins_fluid,取负值) plt.barh(y_positions, -df["margins_fluid"], height=0.6, color="#1f77b4", label="Fluid Margin") # 绘制右向条形(margins_vp) plt.barh(y_positions, df["margins_vp"], height=0.6, color="#ff7f0e", label="VP Margin") # 添加level标签(垂直居中显示) for y, level in zip(y_positions, df["level"]): plt.text(0, y, level, ha="center", va="center", fontsize=10, rotation=90) # 设置X轴为百分比格式 def to_percent(x, pos): return f"{abs(x)*100:.0f}%" formatter = FuncFormatter(to_percent) plt.gca().xaxis.set_major_formatter(formatter) # 添加分组标题(显示在每组的上方) current_y = 0 for name, group in grouped: n_levels = len(group) group_center = current_y + (n_levels - 1)*level_spacing / 2 plt.text(-1.2, group_center, name.capitalize(), ha="center", va="center", fontsize=12, fontweight="bold") current_y += n_levels * level_spacing + group_spacing # 设置X轴范围,留出足够空间显示分组标题 plt.xlim(-1.3, 1.3) # 添加图例、网格 plt.legend() plt.grid(axis="x", linestyle="--", alpha=0.7) plt.tick_params(axis="y", left=False, labelleft=False) # 隐藏原y轴刻度 plt.title("Bidirectional Bar Chart with Centered Level Labels", fontsize=14) plt.tight_layout() plt.show()
关键说明
- level居中显示:通过手动计算每个level的y轴位置,在X=0的位置添加垂直旋转的文本,实现居中效果;同时隐藏原y轴刻度,避免干扰。
- X轴百分比转换:使用
FuncFormatter自定义格式化函数,将小数转换为带百分号的字符串,同时处理左向条形的负值(取绝对值显示)。 - 分组间距控制:通过
group_spacing和level_spacing参数调整组间和组内的垂直间距,让图表更清晰。
内容的提问来源于stack exchange,提问作者hulio_entredas
相关产品推荐
相关产品推荐

