Matplotlib无法在Django

时间:2015-07-30 08:47:51

标签: python django matplotlib

每当(至少)2个人尝试在我的应用程序中生成轮廓图时,其中至少有一个会收到随机错误,具体取决于第一个人设法绘制的距离..(" unknown element o& #34;," ContourSet必须在当前轴中#34;只是其中两种可能性)

以下是可以产生错误的减少测试,如果您尝试同时在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 个答案:

答案 0 :(得分:1)

首先,让我首先说通过在几个线程中调用_test_chart来更容易重现

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

执行上述操作后,将根据需要工作,而第二个将崩溃。

这个的简单原因是pyplot模块不是为多线程而设计的,因此这两个图表在他们尝试绘制时会混淆数据。

mdboom

可以更好地解释这一点
  

... pyplot用于在命令行方便地绘图并保持全局状态。例如,当你说plt.figure()时,它会将数字添加到全局列表中,然后设置&#34;当前数字&#34;指向最近创建的图形的指针。然后随后的绘图命令自动写入该图。显然,这不是线程安全的......

有两种方法可以解决此问题,

  1. 强制在不同的流程中绘制这些图表。
  2. for i in xrange(2):
        pool = Pool(processes=1)
        pool.apply(_test_chart)   
    

    虽然这会起作用,但你会发现性能明显下降,因为创建流程通常需要与生成图表一样长(我认为这是不可接受的!)

    1. 真正的解决方案是使用Matplotlib的OO接口模块,然后允许您使用正确的对象 - 实际上这可以解决使用子图而不是图。对于问题中的给定示例,这将如下所示
    2. 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