【问题标题】:Flask stuck loading after opening a certain route with a function使用功能打开某个路线后烧瓶卡住加载
【发布时间】:2018-07-02 06:42:36
【问题描述】:

我对 Python 和 Flask 比较陌生。我一直在尝试创建一个 Web 应用程序,它从 .txt 文件读取数据并将它们绘制到 matplotlib 图上。在这个网络应用程序中,我有一个带有 3 个按钮的首页。这些按钮使用读取数据并将它们绘制到 matplotlib 图上的功能重定向到不同的路线。该网络应用程序仅在我第一次去这些路线中的任何一条时才能完美运行。之后什么都没有加载了。我想我有某种无限循环,但我无法弄清楚。此外,在网站卡住后,Python 进程开始消耗更多资源。

只有当我在 web-app 上打开这条路线时问题仍然存在:

@app.route("/temperature/")

这在网页上加载没有问题,但只有一次,整个网络应用程序卡住了,我也无法访问任何其他路线。

提前致谢!

EDIT 1 - 下面的完整代码

cloudapp.py(运行 Flask 和函数的 Python 源代码)

from flask import Flask
from flask import render_template
from flask import request
import numpy as np
import matplotlib.pyplot as plt, mpld3
from datetime import datetime

app = Flask(__name__, template_folder='C:\Users\Valtteri\Desktop\cloudapp\Templates\HTML')
global all_lines

@app.route("/")
def frontpage():

    return render_template('frontpage.html')


@app.route("/temperature/")
def temperature():


    f = open('C:/Email/file.txt', 'r') 
    cpt = 0 # Line amount value
    all_lines = [] # List that has every Nth value 
    for line in f:
        cpt += 1 # Goes through every line and adds 1 to the counter
        # How often values are plotted (every Nth value)
        if cpt%100 == 0: 
            all_lines.append(line) # When 30th line is counted, add that line to all_lines[] list
        if cpt == 500: # How many values are plotted (counts from first)
            break

    dates = [str(line.split(';')[0]) for line in all_lines]
    date = [datetime.strptime(x,'%Y.%m.%d_%H:%M') for x in dates]
    y = [float(line.split(';')[1]) for line in all_lines]
    z = [float(line.split()[2]) for line in all_lines]

    fig, ax = plt.subplots()
    ax.plot_date(date, y, 'r-')

    f.close()
    return mpld3.fig_to_html(fig)
if __name__ == "__main__":
    app.run()

frontpage.html(文件夹 ..\templates\html 中的 HTML 模板)

<!DOCTYPE html>
<html>
  <head>
<meta charset="UTF-8">
    <title>Envic Oy Cloud</title>
  </head>
  <body>
  <div class="headers">
  <h1>Web-Application</h1>
  <h2> Version 0.0.1 </h2>
  </div>
  <div class="buttons">
  <h3 class="buttonheader">Logger 1</h3>

  <a class="templink" href="http://127.0.0.1:5000/temperature/" target="_blank"> Check temperature </a>
  </body>
</html>

我在 Windows 上使用 Bash 来运行代码

export FLASK_APP=myCloud.py

flask run

编辑 2

我试图解决这个问题很长时间,但找不到解决方案。对我来说,这与 Flask/mpld3 的兼容性有关。我制作了同样的网络应用程序,但这次使用了一个简单的金字塔 WSGI。我现在可以多次刷新绘图并将自己重定向到任何视图而服务器不会挂起。我仍然会留下未解决的帖子,因为我仍然想使用 Flask。我也会继续我的研究。这是适合我的金字塔版本:

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
import numpy as np
import matplotlib.pyplot as plt, mpld3
from datetime import datetime

def hello_world(request):
    return Response('<h1>Testing the Pyramid version!</h1><a href="http://localhost:8888/second_view">Check temperature</a>')

def second_view(request):
    with open('C:/Email/file.txt') as f:   

        cpt = 0 # Line amount value
        all_lines = [] # List that has every Nth value 
        for line in f:
            cpt += 1 # Goes through every line and adds 1 to the counter
            # How often values are plotted (every Nth value)
            if cpt%100 == 0: 
                all_lines.append(line) # When 30th line is counted, add that line to all_lines[] list
            if cpt == 500: # How many values are plotted (counts from first)
                break

        dates = [str(line.split(';')[0]) for line in all_lines]
        date = [datetime.strptime(x,'%Y.%m.%d_%H:%M') for x in dates]
        y = [float(line.split(';')[1]) for line in all_lines]
        z = [float(line.split()[2]) for line in all_lines]

        plt.figure(figsize=(10,5))
        plt.title('Humidity', fontsize=15)
        plt.ylabel('Humidity RH', fontsize=15)


        fig = plt.figure()
        plot = plt.plot_date(date, z, 'b-')


        myfig = mpld3.fig_to_html(fig, template_type='simple')
    return Response(myfig)

if __name__ == '__main__':
    config = Configurator()
    config.add_route('hello_world', '/hello_world')
    config.add_route('second_view', '/second_view')
    config.add_view(hello_world, route_name='hello_world')
    config.add_view(second_view, route_name='second_view')
    app = config.make_wsgi_app()
    server = make_server('', 8888, app)
    server.serve_forever()

【问题讨论】:

  • 尝试取消缩进您的return 语句。我的预感是文件处理程序永远不会关闭文件,因此您可能在后续读取中对文件进行了文件锁定。
  • 感谢您的回复。试过了,但不幸的是没有解决问题。我也尝试在 return 语句之前执行 f.close() ,但它仍然保持不变。我和你的猜测一样,是文件处理程序没有关闭,代码无法处理其他任何内容。
  • 问题似乎与情节本身(matplotlib 或 mpld3)有关,请参阅我原帖中的编辑。
  • 嗯...我似乎无法复制您的问题。但是,在使用您的代码时,我注意到您有 2 个plt.figures。我相信您想删除第二个并将fig 设置为第一个语句。我还尝试在 return 语句之前使用 plt.clf()plt.cla() 来查看 pyplot 是否可以刷新其缓存。
  • 有趣。我现在只有一条路线,只有一个简单的代码,它使用 matplotlib 创建一个绘图并使用 mpld3 将其打印在网页上,但我仍然遇到问题。它加载一次,但之后它变得无响应并且页面甚至无法刷新。加载图标出现在 chrome 上,但它一直在旋转。

标签: python matplotlib flask web-applications mpld3


【解决方案1】:

这是我尝试的。刷新或打开链接的新选项卡后,我没有遇到服务器挂起的任何问题。但是,在我关闭服务器 (Ctrl + C) 后,控制台抛出了一些异常,表明 mpld3 或 matplotlib 打开了一些新线程。具体来说,例外是RuntimeError: main thread is not in main loop

我做了一些谷歌搜索,发现了这个link。这家伙建议使用fig_to_dictjson。我尝试了他的解决方案,但仍然出现异常。

现在,我将写下这两种方法,让您决定使用哪种方法。我不知道他们中的任何一个是否对你有用。对于我的设置,尽管关闭服务器后出现异常,但应用程序运行良好。

我还将使用您未读取 txt 文件的示例。我已将调试设置为 True,因此当我刷新图表或打开链接的新实例时,我可以确保正在处理 GET 请求。

方法 1 (fig_to_html)

app.py

from flask import Flask
from flask import render_template
import matplotlib.pyplot as plt
import mpld3


app = Flask(__name__, template_folder='/path/to/templates')


@app.route("/")
@app.route("/index")
def index():
    return render_template('frontpage.html')


@app.route('/temperature')
def temperature():
    date = ([1, 2, 3, 4])
    y = ([1, 2, 3, 4])

    fig = plt.figure(figsize=(10, 5))
    plt.title('Temperature', fontsize=15)
    plt.ylabel('Temperature' + u'\u2103', fontsize=15)

    plt.plot(date, y, 'b-')
    plt.ylim([0, 40])

    myfig = mpld3.fig_to_html(fig, template_type='simple')

    plt.clf()  # clear figure
    plt.cla()  # clear axes
    plt.close('all')  # close all figures

    # Print as HTML
    return myfig


if __name__ == "__main__":
    app.run(debug=True)  # run on debug mode

方法 2 (fig_to_dict)

app.py

from flask import Flask
from flask import render_template
import matplotlib.pyplot as plt
import mpld3
import json


app = Flask(__name__, template_folder='/path/to/templates')


@app.route("/")
@app.route("/index")
def index():
    return render_template('frontpage.html')


@app.route('/temperature')
def temperature():
    date = ([1, 2, 3, 4])
    y = ([1, 2, 3, 4])

    fig = plt.figure(figsize=(10, 5))
    plt.title('Temperature', fontsize=15)
    plt.ylabel('Temperature' + u'\u2103', fontsize=15)

    plt.plot(date, y, 'b-')
    plt.ylim([0, 40])

    single_chart = dict()
    single_chart['id'] = "temp_figure"
    single_chart['json'] = json.dumps(mpld3.fig_to_dict(fig))

    plt.clf()  # clear figure
    plt.cla()  # clear axes
    plt.close('all')  # close figure

    # Print as HTML
    return render_template('temperature.html', single_chart=single_chart)


if __name__ == "__main__":
    app.run(debug=True)  # run on debug mode

这里是模板文件。我注意到您在 frontpage.html 中使用了静态链接,因此我将其替换为允许 Flask 自动填充 URL 的占位符。你还有一个 div 没有关闭的标签。

frontpage.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Envic Oy Cloud</title>
  </head>
  <body>
    <div class="headers">
      <h1>Web-Application</h1>
      <h2> Version 0.0.1 </h2>
    </div>
    <div class="buttons"></div>
    <h3 class="buttonheader">Logger 1</h3>
    <a class="templink" href="{{ url_for('temperature') }}" target="_blank"> Check temperature </a>
  </body>
</html>

temperature.html(仅适用于第二种方法)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Sample Page</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
    <script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.2.js"></script>
  </head>
  <body>
    <div id="{{single_chart.id}}">
  </div>
  <script type="text/javascript">
    var figureId = "{{single_chart.id}}";
    var json01 = {{single_chart.json|safe}};
    mpld3.draw_figure(figureId, json01);
  </script>
  </body>
</html>

顺便说一句,我使用的是 Python 3.5.4、Flask==0.12.2、matplotlib==2.1.2 和 mpld3==0.3。我使用 Chrome 版本 67.0.3396.87 进行了测试。

【讨论】:

  • 感谢您的帮助。我试过你的版本,但不幸的是我仍然有这个问题。我单击链接,它会打开并加载绘图。在我关闭绘图并尝试再次打开它后,它不再处理“GET”请求。我用的是python 2.7,会是这样吗?
  • 从 fig 到 dict 的版本根本不起作用。它加载了一个空白页面。之后,GET 请求不再起作用。这个问题太令人沮丧了。我可能会在另一台使用 python 3.5 的 PC 上尝试代码。哦,顺便说一句,我的程序无法导航到路由地址为@app.route('/temperature') 的 URL,对我来说,我需要在其上加上另一个斜杠才能工作('/temperature/')。否则它会给我一个找不到 URL 的错误。
  • 我试过 2.7 也没有问题。我做了一些谷歌搜索,发现这个repo 可能值得一看。这家伙在创建他的情节之前创建了一把锁。如果这不起作用,那么我真的无法为您提供任何进一步的帮助,因为我没有想法。
  • 好的。似乎是一个非常奇怪的问题。我非常感谢你的帮助,你真的很好。我会花很多时间来解决这个问题,并认为我的代码有问题。我会尝试那个,如果它不起作用,我会切换我的电脑并重新开始。希望我能正常工作:)
  • 没问题!希望你让它工作!如果你弄清楚了,我很想看看解决方案。 :)
猜你喜欢
  • 2021-08-19
  • 2015-02-27
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多