Неблокирующая отрисовка и обновление графиков с помощью bokeh

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
image

Есть у меня один Python-скрипт с расчётами. Там был цикл примерно на 2000 итераций, каждая из которых считалась несколько минут.

И решил я, чтобы ловчее отлаживать тот скрипт, выводить график кой-каких метрик от номера итерации. И как посчитается очередная итерация, так оный график и обновлять.

Проще всего проделать это с помощью bokeh. Точнее, с помощью bokeh-сервера для отрисовки графиков. Как — сейчас расскажу.

Сначала запускаем сервер: сервачок идёт из коробки вместе с самим bokeh, так что после pip install bokeh достаточно набрать в консоли bokeh serve — и сервер запущен.

Зачем он нужен? А затем, чтобы показ графиков
  • не блокировал исполнение остального кода (ибо происходит в браузере, в отдельном процессе),
  • чтобы график реагировал на изменение размеров окна (или на свёртывание-развёртывание)
  • и чтобы при этом мы в любой момент могли этот график изменить как захотим, прямо из нашего же Python-процесса!


Делается это примерно так:

import time
import sys
from bokeh.plotting import figure
from bokeh.client import pull_session
from bokeh.models import ColumnDataSource

# Перед запуском этого скрипта -- не забудь запустить сервер-отрисовщик, набрав в консоли bokeh serve
# Please run "bokeh serve" in console before start!


if __name__ == "__main__":
    # Создаём браузерную сессию (вкладку в браузере, где мы будем рисовать графики)
    session = pull_session()

    # Создаём т.н. документ, который будем показывать на сессии (фигуру с осями и графиками)
    fig = figure(title=("Total TBS (in bits)"), plot_height=300, plot_width=800)

    # Созадём кривую и пополняемый источник данных к ней
    datasource = ColumnDataSource(data={"x": [], "y": []})
    line = fig.line(x="x", y="y", source=datasource, line_width=2, legend=("Super dooper line from hell"))

    # Браузер откроет новую вкладку с пустыми осями
    session.show(fig)

    # Начинаем изменять состояние графика
    for i in range(10000):

        # Здесь  мы всего лишь добавляем к графику ещё одну точку. При изменении datasource от кривой кривая перерисуется
        # Вы можете изменить график и посильнее = )
        datasource.stream({"x": [i], "y": [i ** 2]})

        # Без вызова этого метода примерно через 30-40 изменений график в табе перестанет обновляться, будьте осторожны
        session.force_roundtrip()


# Удачной отладки!


Раньше мне тоже приходилось делать подобное, но предыдущие решения были, мягко говоря, не столь хороши. Чего я только за свою жизнь не перепробовал…

Осторожно, мозговой балласт!
Можно использовать matplotlib в неблокинующем режиме, вручную дёргая plt.draw() на каждой итерации. Правда, собственной обработки сообщений от GUI в неблокирующем режиме у matplotlib нету, и если окошко свёрнётся или закроется другим окном, то надо ждать следующей итерации, чтобы его перерисовали. Так себе костыль, но для отладки сойдёт.

Можно по-негритянски генерировать картинку с графиком тем же matplotlib и дампить на диск. Тоже лютый костыль, но на безрыбьи и сойдёт. Или на удалённой машине без графики.

Можно сделать и по-крутому: воспользоваться PyQt, завернуть расчётный код в QObject, задвинуть его в отдельный поток, завернуть matplotlib-графики в QWidget (или воспользоваться графиками из Qt Data Visualizaion, или из PyQtGraph), соединить математику с графикой через сигнал со слотом, и будет счастье. Правда, на быстрое решение для отладки это слабо похоже, да и Qt учить надо, но я такое пару раз делал.

Можно поднять в отдельным процессом маааленькое серверное приложение для отрисовки графиков (например, с помощью aiohttp + PyQt + PyQtGraph), к которому стучаться через REST API из главного процесса. Когда-то я делал и такое, но на быстрое-решение-для-отладки это тоже не тянуло.

Можно писать в какую-нибудь БД (что там у нас сейчас в моде?), а потом напускать на это модную же Grafan’у. Правда, нужно ставить и БД, и Grafan’у, настраивать их, и вообще заморачиваться записью в БД. Через файл, наверно, тоже можно, но для двух графиков на тыщу точек каждый — это как из пушки по воробьям…

Или можно разбираться в plotly.dash, выносить математику в отдельный поток, заворачивать в dash-приложение, и делать ещё чёртову уйму всякой фигни. Этого я уже не осилил, хотя и надо бы.


Короче, удачной отладки!
Источник: https://habr.com/ru/post/474378/


Интересные статьи

Интересные статьи

Веб-приложение часто содержит API для взаимодействия с ним. Документирование API позволит клиентам быстрее понять, как использовать ваши сервисы. Если API закрыт от внешнего мира, то все ...
С 2019 года в России работает система быстрых платежей (СБП) — возможность переслать деньги в любой банк — участник системы по номеру телефона и, что не менее важно, новы...
Дисциплина Computational fluid dynamics(CFD) или, на русском языке, Вычислительная гидродинамика изучает поведение различных потоков, в том числе вихревых. Это и моделирование цунами,...
Приветствую, Хабр! Предлагаю вашему вниманию небольшую пятничную статью про Java, Scala, ненормальных программистов и нарушенные обещания. Простые наблюдения иногда приводят к не очень простым...
В далеком 1887 году шотландский физик Уильям Томсон предложил свою геометрическую модель структуры эфира, который якобы являлся всепроникающей средой, колебания которой проявляются для нас ка...