如何在Matplotlib图表轴左侧添加轴截断波浪线?
为Matplotlib哑铃图添加Y轴截断波浪线
问题描述
我想要复刻《经济学人》风格的哑铃图,已通过Matplotlib实现基础效果,但生成的图表缺少Y轴左侧代表轴截断部分的波浪线,需要添加该效果。
解决方案
可以利用Matplotlib的Path和PathPatch类绘制自定义波浪线,将其添加到Y轴对应位置即可。具体步骤如下:
- 导入绘制自定义路径所需的模块
- 定义波浪线的路径坐标,通过轴坐标定位到Y轴左侧
- 创建路径补丁并添加到图表轴上
修改后的完整代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.path import Path from matplotlib.patches import PathPatch # 提高图表分辨率 plt.rcParams['figure.dpi'] = 100 # 导入数据 gdp = pd.read_csv('gdp_1960_2020.csv') # 预先定义要展示的国家列表 countries = ['United States', 'China', 'Japan', 'Germany', 'India', 'United Kingdom', 'France', 'Italy', 'Brazil'] # 处理数据 gdp_dumbbell = (gdp[(gdp['country'].isin(countries)) & ((gdp['year'] == 2000) | (gdp['year'] == 2020))][['year','gdp_trillions','country']] .pivot(index='country',columns='year', values='gdp_trillions') .sort_values(by=2020)) # 设置图表尺寸 fig, ax = plt.subplots(figsize=(7,4)) # 创建网格(置于数据下方) ax.grid(which="major", axis='both', color='#758D99', alpha=0.6, zorder=1) # 隐藏部分边框 ax.spines[['top','right','bottom']].set_visible(False) # 绘制哑铃图的水平线和散点 ax.hlines(y=gdp_dumbbell.index, xmin=gdp_dumbbell[2000], xmax=gdp_dumbbell[2020], color='#758D99', zorder=2, linewidth=2, label='_nolegend_', alpha=.8) ax.scatter(gdp_dumbbell[2000], gdp_dumbbell.index, label='2000', s=60, color='#DB444B', zorder=3) ax.scatter(gdp_dumbbell[2020], gdp_dumbbell.index, label='2020', s=60, color='#006BA2', zorder=3) # 设置X轴范围 ax.set_xlim(0, 25.05) # 格式化X轴刻度 ax.xaxis.set_tick_params(labeltop=True, labelbottom=False, bottom=False, labelsize=11, pad=-1) # 格式化Y轴刻度 ax.set_yticklabels(gdp_dumbbell.index, ha='left') ax.yaxis.set_tick_params(pad=100, labelsize=11, bottom=False) # 添加Y轴底部截断波浪线 # 用轴坐标定义路径:x=-0.03表示Y轴左侧3%的轴宽度位置 wave_x = [-0.03, -0.03, -0.02, -0.04, -0.02, -0.04, -0.03] wave_y = [0.02, 0.08, 0.05, 0.07, 0.03, 0.05, 0.02] path = Path([(x, y) for x, y in zip(wave_x, wave_y)], [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]) patch = PathPatch(path, facecolor='none', edgecolor='#758D99', linewidth=1.5, transform=ax.transAxes) ax.add_patch(patch) # 可选:添加Y轴顶部截断波浪线 # wave_y_top = [0.92, 0.98, 0.95, 0.97, 0.93, 0.95, 0.92] # path_top = Path([(x, y) for x, y in zip(wave_x, wave_y_top)], # [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, # Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]) # patch_top = PathPatch(path_top, facecolor='none', edgecolor='#758D99', linewidth=1.5, transform=ax.transAxes) # ax.add_patch(patch_top) # 设置图例 ax.legend(['2000', '2020'], loc=(-.29,1.09), ncol=2, frameon=False, handletextpad=-.1, handleheight=1) # 添加标题栏装饰 ax.plot([-0.08, .9], [1.17, 1.17], transform=fig.transFigure, clip_on=False, color='#E3120B', linewidth=.6) ax.add_patch(plt.Rectangle((-0.08,1.17), 0.05, -0.025, facecolor='#E3120B', transform=fig.transFigure, clip_on=False, linewidth=0)) # 添加标题和副标题 ax.text(x=-0.08, y=1.09, s="Great expectations", transform=fig.transFigure, ha='left', fontsize=13, weight='bold', alpha=.8) ax.text(x=-0.08, y=1.04, s="Top 9 countries by GDP, in trillions of USD", transform=fig.transFigure, ha='left', fontsize=11, alpha=.8) # 添加来源信息 ax.text(x=-0.08, y=0.04, s="""Source: "GDP of all countries(1960-2020)" via Kaggle.com""", transform=fig.transFigure, ha='left', fontsize=9, alpha=.7) plt.show()
说明
- 波浪线通过轴坐标定位,
ax.transAxes表示坐标范围为0到1,对应轴的宽高比例,方便自适应图表尺寸 - 可调整
wave_x和wave_y的数值改变波浪线的大小、位置和弯曲程度 - 若需要在Y轴顶部添加截断效果,取消注释对应代码块即可
内容的提问来源于stack exchange,提问作者L Robinson
相关产品推荐
相关产品推荐

