阅读 245

Python量化交易基础讲堂-Matplotlib常见问题解决

欢迎大家订阅《Python实战-构建基于股票的量化交易系统》小册子,小册子会陆续推出与小册内容相关的专栏文章,对涉及到的知识点进行更全面的扩展介绍。

本次专栏主要介绍下小册子中使用Matplotlib库时所涉及到的一些问题。最常见的是“中文显示乱码问题”和“tight_layout()出错问题”。

中文显示乱码问题

由于Matplotlib库缺少中文字体,因此在图表上显示中文时会出现乱码。一种解决方法为在代码中添加以下参数设置,如下所示:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.figure import Figure

# 正常显示画图时出现的中文和负号
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False

# 以下是其他代码
复制代码

另一种方法是更改配置文件。这里我们以mac系统为例来介绍下。在MAC中调试matplotlib时中文显示框框解决方法:

  • 下载simhei.ttf字体库拷贝至matplotlib字体文件夹(Macintosh HD ▸ 用户 ▸ xxxx ▸ anaconda3 ▸ lib ▸ python3.7 ▸ site-packages ▸ matplotlib ▸ mpl-data ▸ fonts▸ ttf)。

  • 同样在matplotlib/mpl-data/fonts目录下面修改配置文件matplotlibrc

font.family : sans-serif
font.sans-serif : SimHei, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif axes.unicode_minus:False 
复制代码
  • 3、在Python中运行如下代码重新加载字体使配置生效:
from matplotlib.font_manager import _rebuild
_rebuild() #reload 
复制代码

tight_layout()出错问题

在matplotlib中,轴Axes的位置以标准化图形坐标指定,可能发生的情况是轴标签、标题、刻度标签等等会超出图形区域,导致显示不全。Matplotlib v1.1 引入了一个新的命令tight_layout(),作用是自动调整子图参数,使之填充整个图像区域。 调用plt.show()函数时会自动运行tight_layout()函数,如下所示:

def show(self):
    self.figure.tight_layout()
    FigureCanvasAgg.draw(self)
    if PORT is None:
        return

    if matplotlib.__version__ < '1.2':
        buffer = self.tostring_rgb(0, 0)
    else:
        buffer = self.tostring_rgb()

    if len(set(buffer)) <= 1:
        # do not plot empty
        return

    render = self.get_renderer()
    width = int(render.width)

    plot_index = index if os.getenv("PYCHARM_MATPLOTLIB_INTERACTIVE", False) else -1
    try:
        sock = socket.socket()
        sock.connect((HOST, PORT))
        sock.send(struct.pack('>i', width))
        sock.send(struct.pack('>i', plot_index))
        sock.send(struct.pack('>i', len(buffer)))
        sock.send(buffer)
    except OSError as _:
        # nothing bad. It just means, that our tool window doesn't run yet
        pass
复制代码

我们通过以下一个例程来介绍,最终的显示效果如下所示:

fig = plt.figure(figsize=(12, 8))
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax1.plot(np.arange(10), np.random.randint(0, 10, 10), ls='-', c='r', lw=1)
ax2.plot(np.arange(10), np.random.randint(10, 20, 10), ls='-', c='y', lw=1)
plt.show()

复制代码

不过很多时候会出现tight_layout()不工作的情况,比如出现以下提示: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect. warnings.warn("This figure includes Axes that are not compatible "

这个警告的原因是tight_layout这个函数出错了,警告语句出现的原因时axes列表为空,tight_layout()中相应的代码,如下所示:

subplotspec_list = get_subplotspec_list(self.axes)
if None in subplotspec_list:
    cbook._warn_external("This figure includes Axes that are not "
                         "compatible with tight_layout, so results "
                         "might be incorrect.")
复制代码

可见这个函数并不太稳定。tight_layout不起作用的时候,绘图效果如下所示,可见子图并没有填充整个图像区域。

网上搜索了下发现也有类似的情况出现,附上部分案例的截图:

接下来我们尝试下解决方法,tight_layout在plt.savefig的调用方式相对比较稳定,我们将plt.show()函数替换为plt.savefig函数,替换后会在本地另外为png图片,该图片中子图填充了整个图像区域。

plt.savefig('fig.png', bbox_inches='tight') # 替换 plt.show()

购买小册子的同学注意了:我们会把这篇专栏的链家附加到《前置基础:Matplotlib函数式绘图的方式》这一节内容中。

更多的量化交易内容欢迎大家订阅小册阅读!!同时也欢迎大家关注我的微信公众号【元宵大师带你用Python量化交易】了解更多Python量化交易相关内容