在 matplotlib 中,我可以使用多个 CPU 来加速许多子图和数据点的绘制吗?

joe*_*lom 4 python matplotlib multiprocessing joblib python-multiprocessing

我正在创建一个包含大约一百个子图/轴的图形,每个子图/轴都有几千个数据点。目前,我正在循环遍历每个子图并用于plt.scatter放置点。然而,这是相当慢的。是否可以使用多个 CPU 来加速绘图,通过将工作分配给每个子图一个核心或在单个子图中绘制数据点?

到目前为止,我尝试使用joblib并行进程来创建子图,但它不是在同一图中创建新的子图,而是为每个子图生成一个新图。我尝试过后端PDF、、Qt5AggAgg。这是我的代码的简化示例。

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')
Run Code Online (Sandbox Code Playgroud)

设置n_jobs=1有效后,所有点都将绘制在同一个图中。然而,将其增加到一以上会创建四个数字:我启动时使用一个数字plt.subplots,然后每次ax.scatter调用一个数字。

由于我将轴从第一个图形传递到plotter,所以我不确定如何/为什么创建附加图形。matplotlib 中是否有一些后备措施,如果指定的图形被另一个绘图过程“锁定”,则会导致自动创建新图形?

任何关于如何改进我当前的方法或通过替代方法实现加速的建议都将受到赞赏。

J. *_*sen 5

Joblibparallel使用该multiprocessing模块来生成进程,因此每个作业将在不同的进程中运行。这就是为什么你会为每项工作获得一个新的数字。这些进程不像线程那样共享任何内存,因此它们无法访问原始数据。

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

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

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

  • 创建单独的图形,暂时保存并最终将它们加载到组合图形中可能是最可行的?对于速度增益,“plt.ioff()”也有帮助,因为可以避免自动重画。 (2认同)
  • 1. 创建每个子图并将它们保存为 png(这可以并行化)。2a. 使用您最初想要的布局创建一个空图形。3a. 使用“plt.imread()”和“plt.imshow()”2/3b 填充该数字。或者,将图片放入 LaTeX 表格中并从那里创建 PDF。4. 重做步骤 1,直到您对它的外观感到满意为止(这很可能很痛苦) (2认同)