在Matplotlib中,我可以使用多个CPU加速绘制多个subplot和数据点吗?

4
我正在创建一个包含大约一百个子图/坐标轴的图形,每个子图都有几千个数据点。目前,我正在循环遍历每个子图,并使用plt.scatter放置数据点。然而,这样做速度很慢。是否可以使用多个CPU来加快绘图速度,将工作分成每个子图一个核心或在单个子图中绘制数据点方面进行划分?
到目前为止,我尝试使用joblib来使用并行进程进行子图创建,但它不是在同一图中创建新的子图,而是为每个子图生成一个新的图。我已经尝试过后端PDFQt5AggAgg。以下是我的代码简化示例。
import matplotlib as mpl
mpl.use('PDF')
import seaborn as sns
import matplotlib.pyplot as plt
from joblib import Parallel, delayed

def plotter(name, df, ax):
    ax.scatter(df['petal_length'], df['sepal_length'])

iris = sns.load_dataset('iris')
fig, axes = plt.subplots(3,1)

Parallel(n_jobs=2)(delayed(plotter)
    (species_name, species_df, ax)
    for (species_name, species_df), ax in zip(iris.groupby('species'), axes.ravel()))

fig.savefig('test.pdf')

设置n_jobs=1可以工作,所有点都在同一幅图中绘制。然而,将其增加到1以上会创建四个图:一个由plt.subplots初始化,每次调用ax.scatter时都会创建一个新的图。

由于我将第一个图的轴传递给plotter,所以我不确定为什么会创建额外的图形。是否有一些matplotlib中的回退机制,如果指定的图形由另一个绘图过程“锁定”,则会自动创建新的图形?

欢迎提供任何关于如何改进我的当前方法或通过其他方法获得加速的建议。

1个回答

5

Joblib的parallel使用模块来生成进程,因此每个作业将在不同的进程中运行。这就是为什么您会为每个作业获得一个新的图形。这些进程不像线程那样共享任何内存,因此它们无法访问原始图形。

您可能可以尝试使用线程,但由于全局解释器锁(GIL),您是否能获得任何速度提升是值得怀疑的。

为了加速绘图,您可以尝试避免使用pyplot。它会添加一些开销和一个辅助线程,在每个绘制命令后重新绘制图形。这主要面向使ipython感觉更像Matlab之类的用途,但对于速度来说这很糟糕。如果只使用matplotlib,则可以选择仅在完成绘图时绘制图形,并且这可能会节省相当多的时间。

注意:@Faultier在评论中提到,您可以使用pyplot.ion()pyplot.ioff()启用和禁用交互式绘图。


2
可能最实用的方法是创建单独的图形,将它们暂时保存,最后加载到一个组合图形中。为了提高速度,plt.ioff()也很有帮助,因为可以避免自动重绘。 - Faultier
@Faultier @J.P.Petersen 谢谢!我已经在使用plt.ioff(未包含在问题示例中,抱歉),我从不显示图形,只是创建它并保存为PDF。如果完全避免使用pyplot,直接使用matplotlib,我是否仍然可以获得显著的速度提升? - joelostblom
我认为图形是被创建出来的,因为没有图形轴就无法存在(正如您所说)。每个过程都将复制带有轴的图形,从而为您产生许多图形(这是我想的,不是知道的)。您可以创建单独的图形并将它们保存为png或任何您可以在“imshow()”中重用的格式。在“gridspec()”或“subplots()”上拼接图片应该可以,并将其保存为pdf。虽然不是最漂亮的解决方案,但总之,能实现就好(; - Faultier
1
@cheflo,每个子进程将拥有在生成之前的图形坐标轴和所有其他变量的副本-但如果通常情况下对内存进行了任何修改,则只会发生在子进程中,这通常称为写时复制(Copy On Write)(https://en.wikipedia.org/wiki/Copy-on-write)。您可以尝试将`plotter()`函数中的坐标轴返回给父进程,但我怀疑它是否有效。Matplotlib指出一个坐标轴只能属于一个图形。 - J. P. Petersen
2
  1. 创建每个子图并将其保存为 png(可以并行化)。 2a. 创建一个带有最初所需布局的空白图。 3a. 使用 plt.imread()plt.imshow() 填充该图。 2/3b. 或者,将图片放入 LaTeX 表格中,并从中创建 PDF。
  2. 重复步骤1,直到您对外观感到满意(这很可能很痛苦)。
- Faultier
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接