You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用multiprocessing.pool绘图出现空白问题求助

问题原因
  • Matplotlib的Figure和Axes对象不能跨进程共享。多进程模式下,子进程会复制主进程的fig对象,子进程中对ax的绘图操作只作用于副本,主进程的原始fig完全没变化,所以最终保存的只有主进程添加的suptitle,子进程画的内容都丢失了。
  • 你的代码还有几个小问题:
    • do_something里调用plot_data时没传ax参数,会默认用子进程的当前轴,和主进程的fig无关。
    • 代码里display_cols和position变量未定义,会触发报错。
    • actuals和predicted是列表集合,但你在plot_data里直接用了未绑定的actual和predicted,没有对应到每个col的具体数据。
修复方案

方案1:改用单进程批量绘图(最简单可靠)

Matplotlib本身对多进程支持有限,单进程绘图完全能满足大部分场景需求,除非你的distribution_intersection_area计算极慢,否则没必要用多进程。修改后的代码:

import matplotlib.pyplot as plt
import numpy as np

def distribution_intersection_area(actual, predicted):
    # 补全你的实际计算逻辑,这里用示例数据占位
    x = np.linspace(0, 60, 100)
    kde1_x = np.exp(-(x - np.mean(actual))**2 / (2*np.std(actual)**2))
    kde2_x = np.exp(-(x - np.mean(predicted))**2 / (2*np.std(predicted)**2))
    idx = np.argmin(np.abs(kde1_x - kde2_x))
    area = np.trapz(np.minimum(kde1_x, kde2_x), x)
    return area, kde1_x, kde2_x, idx, x

def plot_data(actual, predicted, ax):
    if ax is None:
        ax = plt.gca()
    area, kde1_x, kde2_x, idx, x = distribution_intersection_area(actual, predicted)
    ax.plot(x, kde1_x, color='dodgerblue',label='original', linewidth=2)
    ax.plot(x, kde2_x, color='orangered', label='forecasted', linewidth=2)
    ax.fill_between(x, np.minimum(kde1_x, kde2_x), 0, color='lime', alpha=0.3, label='intersection') 
    ax.plot(x[idx], kde2_x[idx], 'ko')
    handles, labels = ax.get_legend_handles_labels()
    labels[2] += f': {area * 100:.1f}%'
    ax.legend(handles, labels)

def do_something(col, k, rows, cols, fig, actual, predicted):
    ax = fig.add_subplot(rows, cols, k+1)  # 子图位置从1开始计数
    plot_data(actual, predicted, ax)
    annot = f'Plot for {col}'
    ax.set_title(annot)

# 配置参数
rows = 10
cols = 3  # 对应loop_list的长度
fig = plt.figure(figsize=(30, 4 * rows))
fig.subplots_adjust(hspace=0.3, wspace=0.2)

# 替换为你的真实数据,这里示例为每个col生成一组数据
loop_list = ['col1','col2','col3']
actuals = [np.random.randn(100) + i for i in range(3)]
predicted = [np.random.randn(100) + i*2 for i in range(3)]

# 单进程循环绘图
for k, col in enumerate(loop_list):
    do_something(col, k, rows, cols, fig, actuals[k], predicted[k])

# 保存和显示
plt.suptitle('my calculation status', y=0.94, fontsize=18)
plt.savefig('./outputs/test.jpg', dpi=150)
plt.show()

方案2:多进程计算数据,主进程绘图(适合计算密集场景)

如果distribution_intersection_area计算非常耗时,可把计算部分放到子进程,返回绘图所需数据后由主进程统一绘图:

import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool

def distribution_intersection_area(actual, predicted):
    x = np.linspace(0, 60, 100)
    kde1_x = np.exp(-(x - np.mean(actual))**2 / (2*np.std(actual)**2))
    kde2_x = np.exp(-(x - np.mean(predicted))**2 / (2*np.std(predicted)**2))
    idx = np.argmin(np.abs(kde1_x - kde2_x))
    area = np.trapz(np.minimum(kde1_x, kde2_x), x)
    return area, kde1_x, kde2_x, idx, x

# 子进程只做计算,返回绘图所需数据
def calculate_plot_data(actual, predicted):
    return distribution_intersection_area(actual, predicted)

def plot_data_from_result(ax, data, col):
    area, kde1_x, kde2_x, idx, x = data
    ax.plot(x, kde1_x, color='dodgerblue',label='original', linewidth=2)
    ax.plot(x, kde2_x, color='orangered', label='forecasted', linewidth=2)
    ax.fill_between(x, np.minimum(kde1_x, kde2_x), 0, color='lime', alpha=0.3, label='intersection') 
    ax.plot(x[idx], kde2_x[idx], 'ko')
    handles, labels = ax.get_legend_handles_labels()
    labels[2] += f': {area * 100:.1f}%'
    ax.legend(handles, labels)
    ax.set_title(f'Plot for {col}')

# 配置参数
rows = 10
cols = 3
fig = plt.figure(figsize=(30, 4 * rows))
fig.subplots_adjust(hspace=0.3, wspace=0.2)

loop_list = ['col1','col2','col3']
actuals = [np.random.randn(100) + i for i in range(3)]
predicted = [np.random.randn(100) + i*2 for i in range(3)]

# 多进程计算绘图数据
with Pool(processes=None) as pool:
    my_args = [(actuals[k], predicted[k]) for k in range(len(loop_list))]
    plot_results = pool.starmap(calculate_plot_data, my_args)

# 主进程统一绘图
for k, col in enumerate(loop_list):
    ax = fig.add_subplot(rows, cols, k+1)
    plot_data_from_result(ax, plot_results[k], col)

# 保存和显示
plt.suptitle('my calculation status', y=0.94, fontsize=18)
plt.savefig('./outputs/test.jpg', dpi=150)
plt.show()
关键注意点
  • 永远不要在多进程间共享matplotlib的Figure或Axes对象,内存隔离会导致修改无法同步到主进程。
  • 多进程只适合做无状态的计算任务,返回计算结果后由主进程处理绘图逻辑。
  • 若计算耗时不高,单进程绘图是最省心的选择,避免多进程带来的同步问题。

内容的提问来源于stack exchange,提问作者Obiii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:05:14