多个路线映射到烧瓶app中的不同matplotlib图

时间:2016-05-29 02:51:17

标签: python matplotlib flask

我有两个链接的“烧瓶应用程序”,每个链接映射到不同的matplotlib可视化,例如:localhost:5000 / line_chart和localhost:5000 / bar_chart。

当我启动服务器,然后单击一条路线(其中任何一条)时,我看到了我的期望。

本地主机:5000 / bar_chart

enter image description here

当我返回查看另一个链接时,两个图都会中断。

本地主机:5000 / line_chart

enter image description here

本地主机:5000 / bar_chart

enter image description here

我每次都可以通过关闭服务器然后再次运行“run.py”脚本来重现这一点。似乎是与内存缓冲区的覆盖冲突。有没有人以前有这个问题?

应用程序/ views.py

import matplotlib
matplotlib.use('Agg') # this allows PNG plotting
import matplotlib.pyplot as plt
import base64

from flask import render_template
from app import app
from io import BytesIO

@app.route('/')
@app.route('/index')
def index():
res = ''
navigation = [['Line Chart','line_chart'],['Bar Chart','bar_chart']]
res = res + '<h1>Matplotlib Chart Examples</h1>'
res = res + '<ul>'

for item in navigation:
    name = item[0]
    link = item[1]
    res = res + '<li><a href="' + link + '">'+ name +'</a></li>'

res = res +'</ul>'
return res


@app.route('/bar_chart')
    def bar_chart():

    movies = ["Annie Hall", "Ben-Hur", "Casablanca", "Gandhi", "West Side Story"]
    num_oscars = [5, 11, 3, 8, 10]

    # bars are by default width 0.8, so we'll add 0.1 to the left coordinates
    # so that each bar is centered

    xs = [i + 0.1 for i, _ in enumerate(movies)]

    # plot bars with left x-coordinates [xs], heights [num_oscars]
    plt.bar(xs, num_oscars)
    plt.ylabel("# of Academy Awards")
    plt.title("My Favorite Movies")

    # label x-axis with movie names at bar centers
    plt.xticks([i + 0.5 for i, _ in enumerate(movies)], movies)

    return compute(plt)


@app.route('/line_chart')
def line_chart():

    years = [1950, 1960, 1970, 1980, 1990, 2000, 2010]
    gdp = [300.2, 543.3, 1075.9, 2862.5, 5979.6, 10289.7, 14958.3]

    # create a line chart, years on x-axis, gdp on y-axis
    plt.plot(years, gdp, color='green', marker='o', linestyle='solid')

    # add a title
    plt.title("Nominal GDP")

    # add a label to the y-axis
    plt.ylabel("Billions of $")

    return compute(plt)


def compute(plt):
    # run plt.plot, plt.title, etc.
    figfile = BytesIO()
    plt.savefig(figfile, format='png')
    figfile.seek(0)  # rewind to beginning of file

    #figfile.getvalue()  extracts string (stream of bytes)
    figdata_png = base64.b64encode(figfile.getvalue())

    return render_template('index.html',
                       title='matplotlib chart',
                       results=figdata_png)

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

我猜你需要两个数字,测试这段代码并告诉发生了什么:

@app.route('/bar_chart')
    def bar_chart():

    movies = ["Annie Hall", "Ben-Hur", "Casablanca", "Gandhi", "West Side Story"]
    num_oscars = [5, 11, 3, 8, 10]

    # bars are by default width 0.8, so we'll add 0.1 to the left coordinates
    # so that each bar is centered

    xs = [i + 0.1 for i, _ in enumerate(movies)]

    # plot bars with left x-coordinates [xs], heights [num_oscars]
    plt.figure(1)
    plt.bar(xs, num_oscars)
    plt.ylabel("# of Academy Awards")
    plt.title("My Favorite Movies")

    # label x-axis with movie names at bar centers
    plt.xticks([i + 0.5 for i, _ in enumerate(movies)], movies)

    return compute(plt, 1)


@app.route('/line_chart')
def line_chart():

    years = [1950, 1960, 1970, 1980, 1990, 2000, 2010]
    gdp = [300.2, 543.3, 1075.9, 2862.5, 5979.6, 10289.7, 14958.3]

    # create a line chart, years on x-axis, gdp on y-axis
    plt.figure(2)
    plt.plot(years, gdp, color='green', marker='o', linestyle='solid')

    # add a title
    plt.title("Nominal GDP")

    # add a label to the y-axis
    plt.ylabel("Billions of $")

    return compute(plt,2)

def compute(plt, fignum):
    # run plt.plot, plt.title, etc.
    plt.figure(fignum)
    figfile = BytesIO()
    plt.savefig(figfile, format='png')
    figfile.seek(0)  # rewind to beginning of file

    #figfile.getvalue()  extracts string (stream of bytes)
    figdata_png = base64.b64encode(figfile.getvalue())

    return render_template('index.html',
                       title='matplotlib chart',
                       results=figdata_png)

答案 1 :(得分:0)

就我而言,该解决方案无效。尝试访问情节时似乎存在竞争条件。我首先尝试使用库中的锁,但是那没有用,所以我设计了一种锁。就我而言,我想在同一视图上使用相同的功能创建n图像,因此我首先以以下方式创建列表:

queue = [False for i in range(n)]

然后,我的烧瓶应用程序看起来像这样:

@app.route('/vis/<j>')
def vis(j):
    global queue
    # We check that it's image's #j turn, as if it was single threaded
    j = int(j)
    if j == 0:
        for i in range(len(queue)):
            queue[i] = False
    else:
        while not queue[j-1]:
            # If it's not, we sleep for a short time (from time import sleep)
            sleep(0.5)
    # This is not important, it's how I was plotting some random figures
    # (from random import seed) (from datetime import datetime)
    seed(datetime.now())
    n = 10
    p1 = [randint(0, 10) for _ in range(n)]
    p2 = [randint(0, 10) for _ in range(n)]
    t = [i for i in range(n)]
    fig = plt.figure(j)
    plt.clf()
    plt.plot(t, p1, color='blue')
    plt.plot(t, p2, color='orange')
    plt.xlabel('Time')
    plt.ylabel('Value')
    # Save the plot
    img = BytesIO()
    fig.savefig(img, dpi=128)
    img.seek(0)
    # We finished using everything related to plot, so we free the "lock"
    queue[j] = True
    # Return the object as a file that can be accessed
    return send_file(img, mimetype='image/png')

最后,当要在我的烧瓶应用程序中显示此内容时,我要做的就是在HTML文件中使用此<img src="/vis/1">


编辑:我忘记了最重要的部分之一!由于某些原因,这仍然会产生一些不相关的线程问题。我抬起头来,那是我提供完整解决方案的时候。通过在文件的开头添加来解决线程问题:

 import matplotlib
 import matplotlib.pyplot as plt
 matplotlib.use('Agg')

由于某种原因,使用那个Agg后端解决了我所拥有的第二个线程。我对此没有很好的解释,但是它确实起作用,所以对我来说足够了。


或者,也可以通过添加以下内容来运行应用程序以禁用线程:

 if __name__ == '__main__':
      app.run(threading=False, debug=True)

但是,我目前不知道这是否可以在生产中使用,因此我更喜欢其他解决方案。 :)

如果您遇到同样的问题,希望对您有所帮助!