当前位置:首页>python>Python卡通风格套图(4):堆叠柱状图

Python卡通风格套图(4):堆叠柱状图

  • 2026-10-11 13:58:49
Python卡通风格套图(4):堆叠柱状图

代码绘制成果展示

论文:Optimizing economy-energy-environment (3Es) policy mixes for  decarbonization: Synergies, trade-offs, and regional implementation  in China
论文原图
仿图
多种配色

代码解释

第一部分

库的导入以及字体设置
# =========================================================================================# ====================================== 1. 环境设置 =======================================# =========================================================================================import matplotlib.pyplot as pltimport matplotlib.patches as patchesimport matplotlib.patheffects as peimport matplotlib

第二部分

颜色库设置以及配色方案的选择与提取
# =========================================================================================# ======================================2.颜色库=======================================# =========================================================================================COLOR_SCHEMES = {    1: ['#5ca2fb', '#8ec3a5', '#ff9f9b', '#abe5ea', '#fdf6c2', '#c9cbfd', '#bae8ca', '#02ba6f'],}#要使用的配色方案SCHEME_ID =60#提取配色方案scheme_colors = COLOR_SCHEMES[SCHEME_ID]

第三部分

绘图函数:画布与基础参数初始化,首先创建了一个画布,将内外背景全设为纯白。接着定义了决定柱子外观的三个核心几何参数:块与块的缝隙、柱子宽度以及圆角弧度。最后定义了一套文本特效,包含向右下偏移的灰影、一圈白色的描边,以及最上层的原色文字。
# =========================================================================================# ======================================3.绘图函数======================================# =========================================================================================def draw_cartoon_policy_chart(bars_data, x_positions, labels_x, group_labels_info, legend_items, scheme_id):    BG_COLOR = '#ffffff'#背景色    #创建画布    fig, ax = plt.subplots(figsize=(15, 8.5))    fig.patch.set_facecolor(BG_COLOR)#画布整体背景色    ax.set_facecolor(BG_COLOR)# 坐标轴内部绘图区域的背景色    #最右侧的X坐标    max_x = max(x_positions) if x_positions else 15.0

第四部分

绘图函数:堆叠柱状图与立体阴影绘制。外层循环确定一根根大柱子的横坐标和初始纵坐标。内层循环将这根大柱子内部的小色块一层层叠上去。 绘制时,对于实线色块:直接给这个圆角矩形叠加了三层逐渐增大、透明度逐渐降低的阴影。对于虚线色块先在稍微偏右下的位置画一个半透明的灰色虚线框,然后再把真实的虚线框盖在它上面。
    #开始遍历需要绘制的每一个堆叠柱    for i, stack in enumerate(bars_data):        #底部Y坐标        bottom = 0        # X坐标        x = x_positions[i]        #用于累加当前这一整根柱子的总高度值        total_val = 0                #添加一个作为背景投影的虚线色块                shadow_p = patches.FancyBboxPatch(                    (x - WIDTH / 2 + 0.06, bottom - 1.0), #阴影块起始坐标                    WIDTH,#阴影宽度                    h,#阴影高度                    boxstyle="round,pad=0,rounding_size=0.15",#圆角属性                    mutation_aspect=ASPECT,#变形因子                    facecolor='none',#填充颜色                    edgecolor='#909fa6',# 阴影边框颜色设为灰色                    linestyle='--',#线型                    linewidth=lw,#线宽                    alpha=0.3,#透明度                    zorder=2#层                )                #加入坐标轴                ax.add_patch(shadow_p)                #加入坐标轴,覆盖在阴影上面                ax.add_patch(p)            #更新下一块的底部起始Y坐标            bottom += h + GAP

第五部分

绘图函数:顶部标注
        #整根堆叠柱最顶部的Y坐标        top_y = bottom - GAP        #在柱子顶部标注总分        if top_y > 0:            #添加文本            ax.text(x,#x                    top_y + 4,#y                    str(int(total_val)),#文本                    ha='center',#水平                    va='bottom',#垂直                    fontsize=15,#字体大小                    fontweight='bold',#粗体                    color='#333',#字体颜色                    path_effects=txt_effects)#添加加阴影效果

第六部分

绘图函数:坐标轴设置。
    # 遍历边框    for spine in ax.spines.values():        spine.set_visible(False)#隐藏    ax.xaxis.set_visible(False)#将X轴整条轴线隐藏    ax.tick_params(axis='y', length=0)# 将Y轴上的刻度线长度设置为 0    ax.set_yticks([0, 30, 60, 90, 120, 150])#指定Y轴需要显示的刻度值列表    #获取设置好的Y轴刻度标签,并设定其字体大小和颜色    yticklabels = ax.set_yticklabels([0, 30, 60, 90, 120, 150], fontsize=13, color='#555')    #遍历刚刚生成的 Y 轴各个刻度标签对象    for label in yticklabels:        label.set_path_effects(txt_effects)# 为每个Y轴刻度文本应用阴影效果    #设置Y轴的标题    ylabel = ax.set_ylabel("Effect Score",#文本                           fontsize=15,#字体大小                           color='#444',#颜色                           labelpad=15,#标签与坐标轴之间的内边距                           fontweight='bold')#粗体    ylabel.set_path_effects(txt_effects)#添加阴影效果

第七部分

绘图函数:底部文本标签,两层x轴标注设置(分类名与大组名)。
    #遍历每一个X位置及其对应的分类标签名称    for x, label in zip(x_positions, labels_x):        #添加该柱子对应的具体X分类标签文本        ax.text(x,#x                -6,#y                label,#文本内容                ha='center',#水平                va='top',#垂直                fontsize=13, #字体大小                color='#333', #文本颜色                path_effects=txt_effects) #添加阴影效果

第八部分

绘图函数:标题绘制
    title_y = 168#定义主标题Y坐标所在的高度位置    #绘制主标题文本    ax.text(-0.5,#x            title_y,#y            "Samples",#文本内容            fontweight='bold',#加粗            fontsize=18,#大小            ha='left',#水平            va='center',#垂直            color='#111',#颜色            path_effects=txt_effects)#添加阴影效果

第九部分

绘图函数:绘制图例框与图例项
    #获取需要在图例中展示的图例项的总个数    num_legends = len(legend_items)    #分几行    rows = (num_legends - 1) // 3 + 1    #添加到当前坐标轴    ax.add_patch(legend_frame)    #图例中小颜色块的宽度    L_WIDTH = 0.7    #图例中小颜色块的高度    L_HEIGHT = 5.5    #图例小方块圆角参数    SAFE_ROUNDING = 0.18    # 遍历包含图例样式和文本信息的列表    for idx, item inenumerate(legend_items):        col = idx % 3#当前图例在3列排版中的列索引        row = idx // 3#当前图例在哪一行        x = -0.4 + col * 3# 根据列索引计算图例小方块所在的X坐标位置        y = 154.0 - row * 7.5#根据行索引计算图例小方块所在的Y坐标位置        c = item['c']#当前图例填充颜色        ls = item['ls']#当前图例项边框线条样式        ec = item.get('ec', 'white') if ls == '-' else item.get('ec', 'black')#图例边框颜色        lw = item.get('lw', 2.5 if ls == '-' else 2.0)#图例边框粗细        # 实例化图例区域里的那个展示颜色的小圆角矩形色块        p = patches.FancyBboxPatch(            (x, y),#起始左下角坐标            L_WIDTH,#宽度            L_HEIGHT,#高度            boxstyle=f"round,pad=0,rounding_size={SAFE_ROUNDING}",#圆角样式            mutation_aspect=ASPECT,#形变比例            facecolor=c,#填充色            edgecolor=ec,#边框色            linestyle=ls, #线型            linewidth=lw,#线宽            zorder=5#层级        )        #添加图例文本        ax.text(x + L_WIDTH + 0.25,#x                y + L_HEIGHT / 2,#y                item['label'],#文本                ha='left',#水平                va='center',# 垂直                fontsize=12,#大小                color='#333',#文字颜色                path_effects=txt_effects,#增加特效                zorder=5)#层级

第十部分

执行部分:数据读取与样式/图例映射,通过pandas读取数据框。然后从数据中把所有内部色块的名字提取并去重。 接着,循环这些色块名,依次提取颜色。然后将名字里有 Missing或Trade-offs的把它在绘图样式字典和图例列表中的属性配置为“镂空+粗虚线边框”。反之,配置为“实心填充”。
# =========================================================================================# ======================================4.执行部分======================================# =========================================================================================if __name__ == '__main__':    excel_filename = r'data.xlsx'#原始数据路径    df_data = pd.read_excel(excel_filename)#读取数据    #提取数据框Block_Name列的唯一值    unique_blocks = df_data['Block_Name'].drop_duplicates().tolist()    #用于存储每个数据块对应的绘图样式    style_map = {}    #用于存储图例项的信息    legend_items = []

第十一部分

执行部分:提取数据类别与分组顺序,通过提取大分组和子分类的联合去重,得到了从左到右每一根大柱子的信息。
    #提取Group大组和X_Category子分类两列组合在一起的唯一值,保持数据原有顺序    unique_cols = df_data[['Group', 'X_Category']].drop_duplicates()    #将提取出的唯一组合转换为元组列表    order = list(unique_cols.itertuples(index=False, name=None))    print('order', order)    #提取所有的X_Category,用作X轴的刻度标签    labels_x = [cat for grp, cat in order]    print('labels_x', labels_x)

第十二部分

执行部分:计算X轴坐标,控制组内、组间距。在遍历时进行对比判断:如果当前柱子和上一根是同组,说明内部挨着排,X坐标向右走1.5的距离;如果是新大组,意味着两组之间要有明显的留白间隔,X坐标则向右走3的距离。
    #用于存储每个柱子在 X 轴上的具体坐标位置    x_positions = []    #初始化起点的X坐标值    current_x = 0.0    #用于后续判断是否切换了分组    prev_grp = None            #将X坐标向右步进            current_x += 1.5            #添加到列表中            x_positions.append(current_x)        #如果当前的大组名和前一个大组名不同        else:            #将X坐标向右步进            current_x += 3.0            #将计算好的新坐标添加到列表中            x_positions.append(current_x)        #将当前的大组名赋值给prev_grp,以便在下一次循环中进行比对        prev_grp = grp

第十三部分

执行部分:计算大分组标签的居中坐标,各个大柱子在画面中的具体X坐标算出来后,开始推导大分组名称该放在图表的哪个位置。 它先把刚才算好的柱子坐标,根据归属的 Group全部分别塞进字典里。然后对字典的值取一个平均值。这个均值也就是这一丛柱子正中间的位置。
   # 初始化一个字典,用于收集每个大分组所包含的所有柱子的 X 坐标    group_centers_dict = {}    #遍历大组名, 子分类名    for (grp, _), x in zip(order, x_positions):        #如果还没有记录当前这个大组名        if grp not in group_centers_dict:            #为它初始化一个空的列表            group_centers_dict[grp] = []        #将当前柱子的X坐标追加到对应大组的列表中        group_centers_dict[grp].append(x)    #用于存储每个大分组文本标签应该摆放的中心坐标位置    group_labels_info = []    #遍历大分组坐标    for grp, xs in group_centers_dict.items():        #将该大组内所有柱子的X坐标求和并取平均值,算出该组在X轴上的中心点位置        center_x = sum(xs) / len(xs)        # 将计算出的中心点坐标和该组的名称以元组的形式添加到列表中,供后续绘制大类文本标签使用        group_labels_info.append((center_x, grp))

第十四部分

执行部分:组装最终绘图数据结构“整个大列表 -> 单根柱子列表 -> 内部包含的小色块字典”。开始绘图。
    bars_data = []  #用于存储所有堆叠柱子的最终绘图数据    #遍历大组名和子分类名    for grp, x_cat in order:        #根据当前的大组名和子分类名,从总数据中筛选出属于当前这根堆叠柱的所有行数据        stack_df = df_data[(df_data['Group'] == grp) & (df_data['X_Category'] == x_cat)]        stack = []  #按顺序存放当前这根堆叠柱内部的每一个数据块信息        # 遍历刚刚筛选出的这部分数据框中的每一行数据        for _, row in stack_df.iterrows():            b_name = row['Block_Name']  #从当前行中提取出该数据块的名称            #记录该数据块的绘图高度及其名称            block = {'h': row['Y_Value'], 'name': b_name}            # 从预设的样式字典中查找该数据块的颜色和线条样式            block.update(style_map.get(b_name, {'c': '#000000', 'ls': '-'}))            stack.append(block)  #将装好高度、名称和样式的这个数据块,添加到当前堆叠柱的列表中        bars_data.append(stack)  #当这根柱子的所有色块都处理完后,将这整根堆叠柱的数据追加到最外层的总数据列表中

如何应用到你自己的数据

1.设置配色方案:

SCHEME_ID =60

2.设置绘图结果的保存地址:

png_filename = fr'policy_chart_scheme_{scheme_id}.png'

3.设置原始数据的保存路径:

excel_filename = r'data.xlsx'#原始数据路径

4.提取块数据:

unique_blocks = df_data['Block_Name'].drop_duplicates().tolist()

5.提取分组数据:

unique_cols = df_data[['Group', 'X_Category']].drop_duplicates()

6.提取具体的数值数据:

block = {'h': row['Y_Value'], 'name': b_name}

推荐

期刊图片复现|Python绘制二维偏依赖PDP图
期刊复现|python绘制基于SHAP分析和GAM模型拟合的单特征依赖图
期刊图片复现|python绘制带有渐变颜色shap特征重要性组合图(条形图+蜂巢图)
期刊复现|用Python绘制SHAP特征重要性总览图、依赖图、双特征交互效应SHAP图,解锁XGBoost模型的终极奥秘
期刊图片复现|Python绘制shap重要性蜂巢图+单特征依赖图+交互效应强度气泡图+交互效应依赖图(回归+二分类+分类)

获取方式

公众号中的所有所有的免费代码都已经下架了,都并入到付费部分里了,付费合集代码和数据的购买通道已经开通,全部合集100元,后续将会持续更新,决定购买请后台私信我,注意只会分享练习数据和代码文件,不会提供答疑服务,代码文件中已经包含了每行代码的完整注释,购买前请确保真的需要!!!

最新文章

随机文章