Squeak.ru - шаблоны программирования

Множественное сопоставление маршрутов с разными графами matplotlib в приложении flask

У меня есть это «фласк-приложение» с двумя ссылками, каждая из которых соответствует разным визуализациям matplotlib, например: localhost: 5000/line_chart и localhost: 5000/bar_chart.

Когда я запускаю сервер и нажимаю маршрут (любой из них), я вижу то, что ожидаю.

локальный: 5000/bar_chart

введите здесь описание изображения

Когда я возвращаюсь и просматриваю другую ссылку, оба графика ломаются.

локальный: 5000/line_chart

введите здесь описание изображения

локальный: 5000/bar_chart

введите здесь описание изображения

Я могу воспроизвести это каждый раз, закрыв сервер, а затем снова запустив скрипт «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)

Спасибо за ваше время.

29.05.2016

Ответы:


1

Я думаю, вам нужны две цифры, протестируйте этот код и расскажите, что произошло:

@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)
29.05.2016
  • это сработало. Вау, спасибо большое. это беспокоило меня последние две недели. 29.05.2016

  • 2

    В моем случае это решение не сработало. Кажется, что при попытке доступа к сюжету возникает состояние гонки. Сначала я попытался использовать блокировку из библиотеки, но это не сработало, поэтому вместо этого я как бы разработал блокировку. В моем случае я хотел создать 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')
    

    Наконец, когда я хотел отобразить это в своем приложении для фляг, все, что мне нужно было сделать, это использовать этот <img src="/vis/1"> в моем html-файле.


    Редактировать: я забыл одну из самых важных частей! По какой-то причине это все равно создало бы какую-то несвязанную проблему с потоком. Я посмотрел это, и именно тогда я нашел полное решение. Проблема с потоками была решена добавлением в начало файла:

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

    По какой-то причине использование этого бэкэнда Agg решило проблему второй многопоточности, которая у меня была. На самом деле у меня нет хорошего объяснения этому, но оно работает, так что мне этого достаточно.


    В качестве альтернативы, то, что также работало, запускало приложение, отключая потоки, добавляя:

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

    Однако на данный момент я не знаю, работает ли это в производстве, поэтому я предпочел другое решение. :)

    Я надеюсь, что это поможет, если у вас была такая же проблема!

    29.06.2020
  • Кстати, это, конечно, распространяется на любой случай, когда вы рисуете два или более разных изображения. В таком случае у вас есть не первое условие, а непосредственно соответствующий оператор for или while в зависимости от того, является ли это первым изображением или каким-либо другим соответственно. 29.06.2020
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...