Как сделать обновляемый график в python

Добавил пользователь Евгений Кузнецов
Обновлено: 04.10.2024

До сих пор я использовал ту, что в Boost , но мне нужно что-то, что от этого не зависит, поэтому я пришел к этому:

Хорошая точка что в separators вы можете передать более одного символа.

Вот рабочая версия рассматриваемого кода (требуется, по крайней мере, версия Matplotlib 1.1.0 с 2011-11-14):

Обратите внимание на некоторые изменения:

  1. Вызовите plt.pause(0.05) для вывода новых данных, и он запускает цикл событий GUI (что позволяет взаимодействовать с мышью).

Если вы заинтересованы в построении в реальном времени, я бы рекомендовал заглянуть в анимационный API matplotlib . В частности, использование blit во избежание перерисовки фона на каждом кадре может дать вам существенную прирост скорости (~ 10x):

show , вероятно, не лучший выбор для этого. Вместо этого я буду использовать pyplot.draw() . Вы также можете включить небольшую задержку (например, time.sleep(0.05) ) в цикле, чтобы вы могли видеть сюжеты. Если я сделаю эти изменения в вашем примере, это сработает для меня, и я вижу, что каждый пункт появляется по одному.

. Все, что вам нужно, это добавить

и чем вы мог видеть новый сюжет.

Итак, ваш код должен выглядеть так, и он будет работать

Верхний (и многие другие) ответы были построены на plt.pause() , но это был старый способ анимации сюжета в matplotlib.

TL; DR: вы можете захотеть использовать matplotlib.animation (, как указано в документации ).

После того, как вы разыграли различные ответы и фрагменты кода, на самом деле это был плавный способ бесконечного рисования входящих данных.

Вот мой код для быстрого запуска. Он отображает текущее время со случайным числом в [0, 100) каждые 200 мс бесконечно, одновременно обрабатывая автоматическое масштабирование вида:

Вы также можете исследовать blit для еще большей производительности , как в документации FuncAnimation .

Я знаю, что немного опоздаю, чтобы ответить на этот вопрос. Тем не менее, я сделал код некоторое время назад для построения живых графиков, которые я хотел бы поделиться:

Просто попробуйте. Скопируйте этот код в новый файл python и запустите его. Вы должны получить красивый, плавно движущийся график:

Создание анимированных диаграмм в Python

В ситуации постоянного и необычайного роста объема данных нам не обойтись без аналитиков, в задачи которых входят их анализ и интерпретация. После обработки данных необходимо эффективно сообщить о полученных результатах.

Однако это может оказаться довольно сложной задачей. Для успешной коммуникации, основанной на данных, используется популярная и мощная техника сторителлинга (рассказывания историй).

“Факт, что в нашем распоряжении находится вся информация в мире, совсем не облегчает процесс коммуникации, а, наоборот, усложняет его”. (Коул Нуссбаумер Кнафлич, автор книги “Storytelling with Data”)

Визуализация данных имеет большое значение для сторителлинга и коммуникации. Анимированная визуализация способствует более выразительному отображению данных и всегда вызывает положительный эмоциональный отклик.

В этой статье вы узнаете о том, как создавать анимированные диаграммы и добавлять новое измерение в гистограммы, линейные и круговые диаграммы. Эта статья — лишь первый шаг в мир безграничных возможностей.

Как работает анимация

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

Этот пакет является методом расширения FuncAnimation и частью класса Animation библиотеки Matplotlib в Python. Мы рассмотрим разнообразные примеры использования упомянутого интерфейса, но пока будем считать эту функцию циклом while, который продолжает перерисовывать нашу фигуру на холсте.

Как использовать библиотеку

Я смог лучше понять процесс создания анимированных диаграмм, начав их изучение с конца. Магия анимации начинается с двух следующих строк:

Посмотрим на эти вводные данные FuncAnimation:

  1. fig обозначает объект рисунка, на котором мы будем “рисовать диаграмму”.
  2. chartfunc — это функция, которая принимает числовой ввод, показывающий время измерения во временном ряду (по мере увеличения числа мы продвигаемся по временной шкале).
  3. interval — это задержка между кадрами в миллисекундах (по умолчанию до 200).

Ознакомьтесь с документацией по дополнительным параметрам входных данных.

В дальнейшем остается только параметризовать диаграммы в функцию, принимающую в виде числового ввода точку во временном ряду, и процесс запущен!

Как начать работу

Проверим на практике, как хорошо мы усвоили основы. Для этого создадим диаграммы, используя статистические данные по пандемии COVID-19 (число смертей в день) и готовый набор данных из приведенного ниже кода.


Анимированная линейная диаграмма

Сначала определим параметры диаграммы, которые останутся постоянными. То есть создадим объект рисунка, координаты x и y, а также установим цвета линий и поля этого объекта.

Затем нужно настроить функцию кривой и анимировать ее:

Анимированная круговая диаграмма

Структуры кода круговой и линейной диаграммы похожи, но есть и некоторые отличия.

Главное отличие состоит в том, что в выше приведенном коде каждый раз возвращается один набор значений. А в линейном графике мы возвращали весь временной ряд к точке, с которого начинали. Для этого использовалась:

df1.head(i) возвращает временной ряд, но .max() гарантирует, что мы получаем только самые последние данные (потому что общее значение смертей либо останется таким же, либо будет расти).

Анимированная гистограмма

Создание гистограммы такой же простой процесс, как и ранее рассмотренные примеры. В данном случае я включил и горизонтальную, и вертикальную гистограммы. В зависимости от того, какую гистограмму вы хотите создать, вам нужно определить переменную bar.

Как сохранить анимированные диаграммы

Создав свои первые анимированные диаграммы, вы, конечно же, захотите ими поделиться. Как же их сохранить?

Бывает, что нужно по-быстрому визуализировать какие-то данные — построить графики для презентации или вроде того. Есть много способов сделать это. Например, можно открыть CSV-файл в LibreOffice или Google Docs и построить графики в нем. Но что, если диаграммы нужно строить регулярно, а значит предпочтительнее делать это автоматически? Вот тут-то на помощь и приходит Python с его потрясающей библиотекой Matplotlib.

Примечание: Для решения той же задачи в свое время мне доводилось использовать Scala Chart. Однако, как вы сами сейчас убедитесь, Matplotlib куда гибче, да и графики у него получаются намного красивее. Если вас интересует тема визуализации данных, вам стоит обратить внимание на мои стары посты, посвященные Graphviz, а также JavaScript-библиотекам Flot и Dracula.

Не будем ходить вокруг да около, лучше сразу перейдем к примерам. Пожалуй, простейший график, который можно построить в Matplotlib, это график синуса и косинуса:

import matplotlib as mpl
import matplotlib . pyplot as plt
import math

dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 512 / dpi , 384 / dpi ) )
mpl. rcParams . update ( < 'font.size' : 10 >)

plt. axis ( [ 0 , 10 , - 1.5 , 1.5 ] )

plt. title ( 'Sine & Cosine' )
plt. xlabel ( 'x' )
plt. ylabel ( 'F(x)' )

xs = [ ]
sin_vals = [ ]
cos_vals = [ ]

x = 0.0
while x 10.0 :
sin_vals + = [ math . sin ( x ) ]
cos_vals + = [ math . cos ( x ) ]
xs + = [ x ]
x + = 0.1

plt. plot ( xs , sin_vals , color = 'blue' , linestyle = 'solid' ,
label = 'sin(x)' )
plt. plot ( xs , cos_vals , color = 'red' , linestyle = 'dashed' ,
label = 'cos(x)' )

plt. legend ( loc = 'upper right' )
fig. savefig ( 'trigan.jpg' )

Я думаю, что код не нуждается в пояснениях. В крайнем случае, вы можете полистать официальную документацию или почитать вывод help() в REPL’е.

График синуса и косинуса в Matplotlib

Однако на практике часто нужно построить график функции не от абстрактного вещественного числа, а от вполне конкретного времени. И в этом случае хочется, чтобы по оси OX были подписаны не абстрактные 1, 2, 3, а вполне конкретные временные метки. Для примера рассмотрим построение графика регистрации новых доменов в зоне RU за разное время с разбивкой по регистраторам:

import matplotlib as mpl
import matplotlib . pyplot as plt
import matplotlib . dates as mdates
import datetime as dt
import csv

with open ( 'ru-newreg.csv' , newline = '' ) as f:
for row in csv . reader ( f , delimiter = ',' , quotechar = '"' ) :
if dates == [ ] :
dates = [
dt. datetime . strptime (
"<>-01" . format ( d ) ,
'%Y-%m-%d'
) . date ( )
for d in row [ 1 : ]
]
continue
values [ row [ 0 ] ] = row [ 1 : ]

dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 512 / dpi , 384 / dpi ) )
mpl. rcParams . update ( < 'font.size' : 10 >)

plt. title ( 'RU New Domain Names Registration' )
plt. xlabel ( 'Year' )
plt. ylabel ( 'Domains' )

ax = plt. axes ( )
ax. yaxis . grid ( True )
ax. xaxis . set_major_formatter ( mdates. DateFormatter ( '%Y' ) )
ax. xaxis . set_major_locator ( mdates. YearLocator ( ) )

for reg in values. keys ( ) :
plt. plot ( dates , values [ reg ] , linestyle = 'solid' , label = reg )

plt. legend ( loc = 'upper left' , frameon = False )
fig. savefig ( 'domains.jpg' )

График регистрации новых доменов, построенный в Matplotlib

Что еще часто строят, это столбчатые диаграммы. В качестве примера возьмем данные из заметки Поиск по географическим данным при помощи PostGIS и построим диаграмму, отображающую сколько точек на карте к какому типу (заправка, кафе и так далее) относятся. Чтобы было чуть интереснее, сделаем вид, что в прошлом году точек каждого вида было на 10% меньше, и попытаемся отразить это изменение:

import matplotlib as mpl
import matplotlib . pyplot as plt
import matplotlib . dates as mdates
import datetime as dt
import csv

data_names = [ 'cafe' , 'pharmacy' , 'fuel' , 'bank' , 'waste_disposal' ,
'atm' , 'bench' , 'parking' , 'restaurant' ,
'place_of_worship' ]
data_values = [ 9124 , 8652 , 7592 , 7515 , 7041 , 6487 , 6374 , 6277 ,
5092 , 3629 ]

dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 512 / dpi , 384 / dpi ) )
mpl. rcParams . update ( < 'font.size' : 10 >)

plt. title ( 'OpenStreetMap Point Types' )

ax = plt. axes ( )
ax. yaxis . grid ( True , zorder = 1 )

xs = range ( len ( data_names ) )

plt. bar ( [ x + 0.05 for x in xs ] , [ d * 0.9 for d in data_values ] ,
width = 0.2 , color = 'red' , alpha = 0.7 , label = '2016' ,
zorder = 2 )
plt. bar ( [ x + 0.3 for x in xs ] , data_values ,
width = 0.2 , color = 'blue' , alpha = 0.7 , label = '2017' ,
zorder = 2 )
plt. xticks ( xs , data_names )

fig. autofmt_xdate ( rotation = 25 )

plt. legend ( loc = 'upper right' )
fig. savefig ( 'bars.jpg' )

Столбчатая диаграмма в Matplotlib

Те же данные можно отобразить, расположив столбики горизонтально:

import matplotlib as mpl
import matplotlib . pyplot as plt
import matplotlib . dates as mdates
import datetime as dt
import csv

data_names = [ 'cafe' , 'pharmacy' , 'fuel' , 'bank' , 'w.d.' , 'atm' ,
'bench' , 'parking' , 'restaurant' , 'p.o.w.' ]
data_values = [ 9124 , 8652 , 7592 , 7515 , 7041 , 6487 , 6374 , 6277 ,
5092 , 3629 ]

dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 512 / dpi , 384 / dpi ) )
mpl. rcParams . update ( < 'font.size' : 9 >)

plt. title ( 'OpenStreetMap Point Types' )

ax = plt. axes ( )
ax. xaxis . grid ( True , zorder = 1 )

xs = range ( len ( data_names ) )

plt. barh ( [ x + 0.3 for x in xs ] , [ d * 0.9 for d in data_values ] ,
height = 0.2 , color = 'red' , alpha = 0.7 , label = '2016' ,
zorder = 2 )
plt. barh ( [ x + 0.05 for x in xs ] , data_values ,
height = 0.2 , color = 'blue' , alpha = 0.7 , label = '2017' ,
zorder = 2 )
plt. yticks ( xs , data_names , rotation = 10 )

plt. legend ( loc = 'upper right' )
fig. savefig ( 'barshoris.jpg' )

Горизонтальная столбчатая диаграмма в Matplotlib

import matplotlib as mpl
import matplotlib . pyplot as plt
import matplotlib . dates as mdates
import datetime as dt
import csv

data_names = [ 'Москва' , 'Санкт-Петербург' , 'Сочи' , 'Архангельск' ,
'Владимир' , 'Краснодар' , 'Курск' , 'Воронеж' ,
'Ставрополь' , 'Мурманск' ]
data_values = [ 1076 , 979 , 222 , 189 , 137 , 134 , 124 , 124 , 91 , 79 ]

dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 512 / dpi , 384 / dpi ) )
mpl. rcParams . update ( < 'font.size' : 9 >)

plt. title ( 'Распределение кафе по городам России (%)' )

xs = range ( len ( data_names ) )

plt. pie (
data_values , autopct = '%.1f' , radius = 1.1 ,
explode = [ 0.15 ] + [ 0 for _ in range ( len ( data_names ) - 1 ) ] )
plt. legend (
bbox_to_anchor = ( - 0.16 , 0.45 , 0.25 , 0.25 ) ,
loc = 'lower left' , labels = data_names )
fig. savefig ( 'pie.jpg' )

Полученная круговая диаграмма:

Круговая диаграмма в Matplotlib

Выше была рассмотрена лишь малая часть возможностей Matplotlib. Чтобы получить более полное представление о всей мощи этой библиотеки, советую заглянуть в галерею построенных с ее помощью графиков на официальном сайте. Что же до исходников к этому посту, как обычно, вы найдете их на GitHub.

Мне нужна ваша помощь для написания script в Python, который будет принимать динамически измененные данные, источник данных здесь не имеет значения и отображает график на экране.

Я знаю, как использовать matplotlib, но проблема с matplotlib, что я могу отображать график только один раз, в конце script. Мне нужно иметь возможность не только отображать график один раз, но и обновлять его "на лету", каждый раз при изменении данных.

Я обнаружил, что для этого можно использовать wxPython с matplotlib, но для этого это немного усложняет, потому что я вообще не знаком с wxPython.

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

Хорошо, так как никто не ответил и посмотрел на помощь matplotlib, замеченную @janislaw, и написал код. Вот какой фиктивный пример:

У этой реализации есть проблемы, например, script останавливается, если вы пытаетесь переместить окно. Но в основном это можно использовать.

Читайте также: