Matplotlib无法在Django上呈现多个等高线图

4
每当至少两个人在我的应用程序中尝试生成等高线图时,其中至少一个人会收到一个随机错误,这取决于第一个人绘制的程度。 (“unknown element o”、“ContourSet必须在当前Axes中”只是可能性之一)
以下是一个简化的测试,如果您尝试同时在2个或更多选项卡中加载此页面,则第一个选项卡将正确呈现,而第二个选项卡将产生错误。(我发现最简单的方法是使用Chrome浏览器的中间鼠标按钮点击刷新页面按钮几次)
views.py
def home(request):
    return render(request, 'home.html', {'chart': _test_chart()})


def _test_chart():
    import base64
    import cStringIO
    import matplotlib
    matplotlib.use('agg')
    from matplotlib.mlab import bivariate_normal
    import matplotlib.pyplot as plt
    import numpy as np
    from numpy.core.multiarray import arange

    delta = 0.5

    x = arange(-3.0, 4.001, delta)
    y = arange(-4.0, 3.001, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
    Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
    Z = (Z1 - Z2) * 10

    fig = plt.figure(figsize=(10, 5))
    plt.contour(X, Y, Z, 10, colors='k')

    jpg_image_buffer = cStringIO.StringIO()
    fig.savefig(jpg_image_buffer)

    array = base64.b64encode(jpg_image_buffer.getvalue())
    jpg_image_buffer.close()
    return array

home.html(只有这一行就足够了)

<img src="data:image/png;base64,{{ chart }}" />

我尝试使用mpld3来处理图像的生成,但仍然出现了不同的错误,所以我知道这绝对不是图像保存的问题,而更多地是它的生成。我还尝试过使用ThreadPoolThreading,但都没有成功,据我所知,在matplotlib中创建等高线图可能不支持多个实例,这在网站上永远不会起作用...
我目前唯一清晰的解决方案是用其他东西替换matplotlib,但我真的不想这样做。
有没有一种方法可以使用matplotlib生成适合我的等高线图呢?
1个回答

2

首先,让我说一句,通过在几个线程中调用_test_chart更容易重现此问题。

from threading import Thread
for i in xrange(2):
    Thread(target=_test_chart).start()

通过上述操作,第一个可以按预期工作,而第二个将会崩溃。
这是因为pyplot模块不适用于多线程,因此两个图表在绘制时会混合数据。
这可以通过mdboom的解释更好地解释:mdboom

...pyplot用于方便命令行绘图,并保留全局状态。例如,当您说plt.figure()时,它会将图形添加到全局列表中,然后将“当前图形”指针设置为最近创建的图形。然后随后的绘图命令会自动写入该图形。显然,这是不安全的...

有两种方法可以解决此问题,
  1. 强制在不同进程中绘制这些图表。
for i in xrange(2):
    pool = Pool(processes=1)
    pool.apply(_test_chart)   

虽然这样可以工作,但你会发现性能明显下降,因为创建进程所需的时间与生成图表的时间一样长(我认为这是不可接受的!)

  1. 真正的解决方案是使用Matplotlib的OO接口模块,这将允许您使用正确的对象进行操作-基本上,这意味着使用子图而不是图。对于问题中给出的示例,代码如下:
def _test_chart2():

    delta = 0.5

    x = arange(-3.0, 4.001, delta)
    y = arange(-4.0, 3.001, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
    Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
    Z = (Z1 - Z2) * 10

    fig = figure(figsize=(10, 5))

    ax1 = fig.add_subplot(111)
    extents = [x.min(), x.max(), y.min(), y.max()]
    im = ax1.imshow(Z,
                    interpolation='spline36',
                    extent=extents,
                    origin='lower',
                    aspect='auto',
                    cmap=cm.jet)
    ax1.contour(X, Y, Z, 10, colors='k')

    jpg_image_buffer = cStringIO.StringIO()
    fig.savefig(jpg_image_buffer)

    array = base64.b64encode(jpg_image_buffer.getvalue())
    jpg_image_buffer.close()

    return array

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