当前位置:首页>python>Python绘图第2期——分组柱状图

Python绘图第2期——分组柱状图

  • 2026-09-04 22:30:08
Python绘图第2期——分组柱状图
昨天我分享了一个Python的折线图模板:
今天分享一个Python的分组柱状图模板,先看效果:

本文共7个部分(获取方式在 “06 ”部分):

00.数据组织格式

数据一共6个字段。其中行为样本,列为每个样本所对应的5个指标。

01. 设置工作环境

此部分主要是导入必要的库并设置工作空间。
# 1. 设置工作环境# ============================================================# 1.1 导入必要的库import osimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom matplotlib import rcParams# 1.2 设置工作空间os.chdir("D:/Desktop/Py科研绘图/Python论文插图绘制模板第2期-分组柱状图")

02. 数据读取与格式转换

这里直接读取工作空间下的"data.xlsx"文件。
# 2. 数据读取与格式转换# ============================================================# 2.1 读取 Excel 数据data_df = pd.read_excel("data.xlsx")# 2.2 将宽数据转换为长数据   # 第1列为样本名称,第2到第6列为指标组id_vars = data_df.columns[0]            # 第一列作为标识变量(样本名)value_vars = data_df.columns[1:6]       # 第2到第6列为待熔化的列long_data = pd.melt(    data_df,    id_vars=[id_vars],    value_vars=value_vars,    var_name='Index_group',    value_name='Value')
这里的2.2部分我们将原始数据从“宽数据”转换到了“长数据”。有人会有疑问长数据不是R中更常用吗?为什么Python里也要用,这是因为这里长数据更适合我们逐个调整细节,当然这里直接用原始宽数据也可以进行绘制(但我就不用😝)。简单理解长数据就是“每个变量单独成列,每个观测独占一行”。
原始数据转换后的长数据长这样:

03. 绘制图形

这里一定要预设图片大小,这样后面我们调整图形细节(如字体大小)才是有意义的。图片尺寸是多少,应取决于你PPT或word中给这张图预留了多大空间。
其他需要注意的地方我在注释中已经写的很清楚,大家细心读注释即可。
# 3. 绘制图形# ============================================================# 3.1 图片大小(宽×高)fig, ax = plt.subplots(figsize=(9.5, 6.5))# 3.2 准备绘图所需参数categories = long_data[id_vars].unique()                # X轴类别(样本)groups = long_data['Index_group'].unique()              # 分组(Index_group)n_categories = len(categories)n_groups = len(groups)# 3.3 定义颜色colors = ["#105186", "#3D86B6", "#67B3DA", "#9DDAF2", "#CDEEF8"]# 3.4 设置柱子宽度和组内间距bar_width = 0.15                # 单个柱子的宽度group_gap = 0.75                # 组内柱子总宽度total_width = bar_width * n_groupsx = np.arange(n_categories)     # 每个类别的基准位置# 3.5 绘制分组柱状图for i, (group, color) in enumerate(zip(groups, colors)):    # 提取当前分组的数据    subset = long_data[long_data['Index_group'] == group]    # 确保数据顺序与 categories 一致    values = [subset[subset[id_vars] == cat]['Value'].values[0] for cat in categories]    # 计算每个柱子的偏移位置(居中于组内)    offset = (i - (n_groups - 1) / 2) * bar_width    bars = ax.bar(        x + offset,        values,        width=bar_width,        color=color,        edgecolor='none',       # 柱子无边框        linewidth=0.05,        alpha=1.0,        label=group    )# 3.6 添加数值标签for i, (group, color) in enumerate(zip(groups, colors)):    subset = long_data[long_data['Index_group'] == group]    values = [subset[subset[id_vars] == cat]['Value'].values[0] for cat in categories]    offset = (i - (n_groups - 1) / 2) * bar_width    for j, val in enumerate(values):        ax.text(            x[j] + offset,                # 数值标签X坐标            val+0.01,                     # 数值标签Y坐标(柱顶高度+0.01)            f'{val:.2f}',                 # 保留两位小数            ha='center',                  # 水平对齐            va='bottom',                  # 垂直对齐            rotation=90,                  # 旋转角度            fontsize=12,                  # 字体大小            fontweight='bold',            # 字体粗细(可选值:'light'、'normal'、'bold'、'heavy'、'black' 或数值 0-1000)            fontfamily='DejaVu Serif',    # 数值标签字体            color='black'                 # 数值标签颜色        )# 3.7 坐标轴范围、刻度、标题设置# 设置 Y 轴范围、刻度及格式# # 获取数据的最值,便于后续坐标轴设置(本示例中手动指定了范围,可忽略)# y_max = long_data['Value'].max()# y_min = long_data['Value'].min()ax.set_ylim(0, 0.40)                                                     # 纵轴范围ax.set_yticks(np.arange(0, 0.41, 0.05))                                  # 纵轴刻度(起始、停止、步长)ax.set_yticklabels([f'{tick:.2f}' for tick in np.arange(0, 0.41, 0.05)]) # 纵轴刻度小数位数# 设置 X 轴刻度及标签ax.set_xticks(x)ax.set_xticklabels(categories)# 设置坐标轴标题# 横轴标题ax.set_xlabel('X_Title',                   # 横轴标题              fontsize=18,                 # 横轴标题字号              fontstyle='normal',          # 横轴标题字体样式(“normal”、“italic”)               fontfamily='DejaVu Sans',    # 横轴标题字体              labelpad=8)                  # 横轴标题到坐标轴距离# 纵轴标题ax.set_ylabel('Y_Title',                   # 纵轴标题              fontsize=18,                 # 纵轴标题字号              fontstyle='normal',          # 纵轴标题字体样式(“normal”、“italic”)               fontfamily='DejaVu Sans',    # 纵轴标题字体              labelpad=8)                  # 纵轴标题到坐标轴距离

04. 调整细节

画图一定要调整细节,就像你出门会打扮自己一样。我们的原则是让图干干净净。
这里注释我写的很细致清晰,不再赘述。
# 4. 调整细节(边框、网格线、刻度线、标题格式、图例样式等)# ============================================================# 4.1 隐藏上、右边框,并确保左、下边框为默认黑色、默认线宽ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)# 4.2 设置左、下边框颜色为黑色(线宽不显式设置,即为默认值)ax.spines['left'].set_color('black')ax.spines['bottom'].set_color('black')# 4.3 网格线设置:仅保留 Y 轴主网格线,灰色、细线ax.set_axisbelow(True)                   # 将网格线置于柱状图下方ax.yaxis.grid(True, which='major', color='#e5e5e5', linewidth=1.5, linestyle='-')ax.yaxis.grid(False, which='minor')      # 关闭次网格线ax.xaxis.grid(False)                     # 关闭 X 轴网格线# 4.4 刻度线设置ax.tick_params(    axis='both',                          # 设置横纵轴刻度线(“x” 或 “y” 或 “both”)    which='major',                        # 设置主刻度线    length=5,                             # 刻度线长度    direction='out'                       # 刻度线朝向(“in” 或 “out” 或 “inout”))# 单独设置 X 轴刻度标签格式for label in ax.get_xticklabels():    label.set_fontfamily('DejaVu Sefif')  # 字体    label.set_fontsize(14)                # 字号    label.set_fontstyle('italic')         # 字体样式(常规"normal";斜体“italic”)    label.set_fontweight('bold')          # 字体粗细(可选值:'light'、'normal'、'bold'、'heavy'、'black' 或数值 0-1000)    label.set_color('black')              # 字体颜色# 单独设置 Y 轴刻度标签格式for label in ax.get_yticklabels():    label.set_fontfamily('DejaVu Serif')  # 字体    label.set_fontsize(14)                # 字号    label.set_fontstyle('italic')         # 字体样式(常规“normal”;斜体“italic”)    label.set_fontweight('bold')          # 字体粗细(可选值:'light'、'normal'、'bold'、'heavy'、'black' 或数值 0-1000)    label.set_color('black')              # 字体颜色# 图例设置# 创建图例,放置在坐标轴右侧外部居中legend = ax.legend(    frameon=False,    handlelength=2.5,                     # 图例色块长度    handletextpad=0.5,                    # 图例色块到文字距离    loc='center left',                    # 图例的“左侧中心”作为对齐点    bbox_to_anchor=(1.02, 0.5)            # 对齐点位于坐标轴右侧边界外(x=1.02),y=0.5 即垂直居中)# 添加图例标题legend.set_title('Index')                           # 图例标题legend.get_title().set_fontfamily('DejaVu Sans')    # 图例字体legend.get_title().set_fontsize(18)                 # 图例字体大小legend.get_title().set_fontweight('normal')         # 图例字体粗细# 设置图例内部文字字体for text in legend.get_texts():    text.set_family('DejaVu Sans')                  # 图例的字体    text.set_size(18)                               # 图例的字体大小# 图形边距调整(不用动这里的参数)plt.subplots_adjust(left=0.1, right=0.95, top=0.9, bottom=0.1)

05. 图形导出

这里只需要强调一点:在Python里,先保存图片,再显示图片!
不然你就会得到一张空白画布!
# 6. 保存与显示# ============================================================plt.tight_layout()                   # 确保所有标签、标题、图例等不会重叠或被裁剪plt.savefig('分组柱状图-Python.png',  # 可保存为PNG、PDF、SVG、EPS等多格式            dpi=300,                 # 分辨率                         bbox_inches='tight')     # 控制保存时的边界裁剪范围plt.show()
运行上面代码,得出下图:

06. 横向柱状图模板获取方式

公众号后台回复关键词 py横向柱状图
即可获取“代码”+“示例数据”+“效果图”
少一个字都不行哦~(直接复制红色关键词,劝你别自己输入)

往期推荐

联系我们

欢迎大家添加微信以及评论交流~
请转发给你周围需要的人~
将本公众号设为星标,第一时间获取后续推文~

#Python#横向柱状图#科研绘图#Python绘图#柱状图#Python画柱状图#科研#研究生

最新文章

随机文章