
代码绘制成果展示












代码解释


第一部分

# =========================================================================================# ====================================== 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,#xtop_y + 4,#ystr(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轴上的刻度线长度设置为 0ax.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位置及其对应的分类标签名称for x, label in zip(x_positions, labels_x):#添加该柱子对应的具体X分类标签文本ax.text(x,#x-6,#ylabel,#文本内容ha='center',#水平va='top',#垂直fontsize=13, #字体大小color='#333', #文本颜色path_effects=txt_effects) #添加阴影效果

第八部分

title_y = 168#定义主标题Y坐标所在的高度位置#绘制主标题文本ax.text(-0.5,#xtitle_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,#xy + L_HEIGHT / 2,#yitem['label'],#文本ha='left',#水平va='center',# 垂直fontsize=12,#大小color='#333',#文字颜色path_effects=txt_effects,#增加特效zorder=5)#层级

第十部分

# =========================================================================================# ======================================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_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_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 =602.设置绘图结果的保存地址:
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}
推荐


获取方式
