2016-11-22 3 views
-1

Мне нужна ваша помощь в решении проблемы, с которой я сейчас сталкиваюсь. Я могу распечатать серийные данные, которые были перенесены с моего мобильного телефона Bluetooth и получены COM-портом моего ноутбука. На первый взгляд кажется, что это нормально, но самое большее он может нарисовать каждые 260 мс (~ 3 кадра в секунду). однако мобильный телефон отправляет данные каждые 100 мс. Я уверен, что проблема связана с командой «plot» и «figure», которая меня смущает. Я признателен, если кто-то может исправить мой код:Медленная печать с использованием функции анимации в Matplotlib, Python

from Tkinter import * 
import serial 
import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
fig = plt.figure() 
ax1 = fig.add_subplot(1, 1, 1) 
ser = serial.Serial("COM4", baudrate=115200, timeout=0.1) 
cnt=0 
xComponent=[] 
plt.ylim(0,30) 
while (ser.inWaiting() == 0): # Wait here until there is data 
    pass 
def animate(i): 

    BluetoothString = ser.readline() 
    ser.flush() 
    dataArray = BluetoothString.split(',') 
    x = float(dataArray[2]) # we only need 3rd component 
    xComponent.append(x) 
    print xComponent 
    ax1.clear() 
    ax1.plot(xComponent) 
    plt.ylim(0,25) 
    global cnt 
    if (cnt > 16): 
     xComponent.pop(0) 
    else: 
     cnt = cnt + 1 

ani = animation.FuncAnimation(fig, animate, interval=0) 
plt.show() 
+0

Этот код ничего не делает. Где «FuncAnimation»? – furas

+0

@furas это от [mpl] (http://matplotlib.org/api/animation_api.html#matplotlib.animation.FuncAnimation) – Aaron

+0

Я знаю, что 'FuncAnimation' - это' mpl', но я видел его в вашем коде. Но я вижу, что вы изменили код. – furas

ответ

1

Трудно сказать что-либо о вашем конкретном случае, так как мы не имеем последовательную часть соединения, который вы используете.

Однако график должен быть намного быстрее, чем 3 кадра в секунду в matplotlib, если это всего лишь линейный график с некоторыми точками в нем. Одна вещь, которую вы можете непосредственно попробовать не Replot все на каждом шаге итерации, но сюжет его один раз, а затем обновить только данные, используя .set_data()

Следующий пример тесно связан с вашим кодом и работает с 90 кадров в секунду на моей машине , Так что, возможно, вы попробуете это и посмотрите, помогает ли это ускорить ваш случай.

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import time 

fig = plt.figure() 
ax1 = fig.add_subplot(1, 1, 1) 

cnt=0 
xComponent=[] 

line, = ax1.plot([0], [0]) 
text = ax1.text(0.97,0.97, "", transform=ax1.transAxes, ha="right", va="top") 

plt.ylim(0,25) 
plt.xlim(0,100) 
last_time = {0: time.time()} 
def animate(i): 

    if len(xComponent)>100: 
     xComponent.pop(0) 
    y = i % 25 
    xComponent.append(y) 

    line.set_data(range(len(xComponent)) ,xComponent) 
    new_time = time.time() 
    text.set_text("{0:.2f} fps".format(1./(new_time-last_time[0]))) 
    last_time.update({0:new_time}) 


ani = animation.FuncAnimation(fig, animate, interval=0) 
plt.show() 
+0

Вау. Большое спасибо «ImportanceOfBeingErnest». огромная скорость в моем коде :-) –

0

Я не хочу наступать на любых пальцах здесь, потому что @ImportanceOfBeingErnest прибил его, но добавив blitting его примеру выпрыгнул мой фреймрейт от 50 до 300. Вот как сделать это в своем примере: я оставил комментарии где я внес изменения

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import time 

fig = plt.figure() 
ax1 = fig.add_subplot(1, 1, 1) 

cnt=0 
xComponent=[] 

line, = ax1.plot([0], [0]) 
text = ax1.text(0.97,0.97, "", transform=ax1.transAxes, ha="right", va="top") 

plt.ylim(0,25) 
plt.xlim(0,100) 
last_time = {0: time.time()} 

def animateinit(): #tells our animator what artists will need re-drawing every time 
    return line,text 

def animate(i): 

    if len(xComponent)>100: 
     xComponent.pop(0) 
    y = i % 25 
    xComponent.append(y) 

    line.set_data(range(len(xComponent)) ,xComponent) 
    new_time = time.time() 
    text.set_text("{0:.2f} fps".format(1./(new_time-last_time[0]))) 
    last_time.update({0:new_time}) 
    return line,text #return the updated artists 

#inform the animator what our init_func is and enable blitting 
ani = animation.FuncAnimation(fig, animate, interval=0,init_func=animateinit, blit=True) 
plt.show() 

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

+1

Я не сказал, что блинтство не будет полезно во многих случаях. Кажется, что это немного завышено, когда данные поступают каждые 100 мс (давая максимум 10 кадров в секунду). Так как пример без blitting уже достигает кадров, которые не обнаруживаются человеческим мозгом, в конце концов, это может и не понадобиться. (Лично я бы всегда старался избегать blitting, потому что он также вызывает много служебных кодов, когда вам нужно позаботиться о масштабировании, изменении размера и т. Д. В случаях, когда может понадобиться blitting, я бы сразу изменился с Matplotlib на pyqtgraph, что намного быстрее и делает код простым.) – ImportanceOfBeingErnest

+0

@ImportanceOfBeingErnest Мне не знакомы с такими вещами, как serial over Bluetooth, поэтому я лично предпочел бы ускорение, если данные появятся на нерегулярных временных интервалах, надеясь уменьшить риск переполнения буфер ..просто подумал, что я сделаю дополнение, потому что это было всего около 4 строк, и хорошо, что нужно знать, как это сделать. – Aaron

+0

Аарон, ты прекрасен. Вы решили мою проблему. Большое вам спасибо –

Смежные вопросы