优化Matplotlib中的自定义绘图

48 阅读2分钟

在使用matplotlib进行数据可视化时,用户经常需要对绘图进行自定义,以满足特定的视觉要求或突出关键信息。然而,对于某些常见的自定义需求,实现起来可能会有难度。例如,用户可能需要将绘图中的坐标轴居中显示,添加网格线,并在坐标轴末端添加箭头,但同时又希望坐标轴原点只显示一个零值,且不与其他坐标轴重叠。

2、解决方案

  1. 坐标轴居中
def center_spines(ax=None, centerx=0, centery=0):
    # 设置坐标轴 spines 的中心位置
    ax.spines['left'].set_position(('data', centerx))
    ax.spines['bottom'].set_position(('data', centery))
    ax.spines['right'].set_position(('data', centerx - 1))
    ax.spines['top'].set_position(('data', centery - 1))

    # 在 spines 末端添加箭头
    ax.spines['left'].set_path_effects([EndArrow()])
    ax.spines['bottom'].set_path_effects([EndArrow()])

    # 隐藏多余 spines 的线,保留刻度记号
    for side in ['right', 'top']:
        ax.spines[side].set_color('none')

    # 设置坐标轴的刻度和网格
    for axis, center in zip([ax.xaxis, ax.yaxis], [centerx, centery]):
        axis.set_ticks_position('both')
        axis.grid(True, 'major', ls='solid', lw=0.5, color='gray')
        axis.grid(True, 'minor', ls='solid', lw=0.1, color='gray')
        axis.set_minor_locator(mpl.ticker.AutoMinorLocator())

        formatter = CenteredFormatter()
        formatter.center = center
        axis.set_major_formatter(formatter)

        xlabel, ylabel = map(formatter.format_data, [centerx, centery])
        ax.annotate('(%s, %s)' % (xlabel, ylabel), (centerx, centery),
                xytext=(-4, -4), textcoords='offset points',
                ha='right', va='top')
  1. 网格线
# 添加网格线
ax.grid(True)
  1. 隐藏多余的零值
# 隐藏坐标轴原点的零值
ax.xaxis.set_ticks([tick for tick in ax.xaxis.get_ticks() if tick != 0])
ax.yaxis.set_ticks([tick for tick in ax.yaxis.get_ticks() if tick != 0])
  1. 自定义坐标轴箭头的样式
class EndArrow(mpl.patheffects._Base):
    def __init__(self, headwidth=5, headheight=5, facecolor=(0,0,0), **kwargs):
        # ... 省略代码 ...

    def draw_path(self, renderer, gc, tpath, affine, rgbFace):
        # ... 省略代码 ...
  1. 自定义坐标轴刻度的格式
class CenteredFormatter(mpl.ticker.ScalarFormatter):
    def __call__(self, value, pos=None):
        if value == self.center:
            return ''
        else:
            return mpl.ticker.ScalarFormatter.__call__(self, value, pos)

代码例子

import matplotlib.pyplot as plt
import numpy as np

# 创建一个matplotlib绘图对象
fig, ax = plt.subplots()

# 设置坐标轴范围
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])

# 绘制数据
x = np.arange(-5, 5)
y = x

line, = plt.plot(x, y)

# 调用自定义函数对绘图进行美化
center_spines()
plt.axis('equal')

# 显示绘图
plt.show()

这个代码示例演示了如何将坐标轴居中显示,添加网格线,并在坐标轴末端添加箭头,同时隐藏了坐标轴原点的多余零值。