Python - blit с подзаголовками, отображающими только последние подзаголовки

Я пытаюсь построить несколько подзаголовков в реальном времени в своем приложении Python. В идеале я также должен иметь возможность построить несколько линий на каждом подзаголовке, но для простоты здесь я предполагаю, что на каждый подзаголовок приходится одна строка. Чтобы сделать это эффективно (я ищу быстрые графики), я пытаюсь расширить один пример, который я нашел в Интернете (https://taher-zadeh.com/speeding-matplotlib-plotting-times-real-time-monitoring-plays/) в моем случае. Мой код:

import time    
# for Mac OSX
import matplotlib
matplotlib.use('TkAgg')   
import matplotlib.pylab as plt
import random

def test_fps(use_blit=True):

    ax1.cla()
    ax1.set_title('Sensor Input vs. Time -')
    ax1.set_xlabel('Time (s)')
    ax1.set_ylabel('Sensor Input (mV)')
    ax2.cla()
    ax2.set_title('Sensor Input vs. Time -' )
    ax2.set_xlabel('Time (s)')
    ax2.set_ylabel('Sensor Input (mV)')
    ax3.cla()
    ax3.set_title('Sensor Input vs. Time -')
    ax3.set_xlabel('Time (s)')
    ax3.set_ylabel('Sensor Input (mV)')
    ax4.cla()
    ax4.set_title('Sensor Input vs. Time -')
    ax4.set_xlabel('Time (s)')
    ax4.set_ylabel('Sensor Input (mV)')

    plt.ion()  # Set interactive mode ON, so matplotlib will not be blocking the window
    plt.show(False)  # Set to false so that the code doesn't stop here

    cur_time = time.time()
    ax1.hold(True)
    ax2.hold(True)
    ax3.hold(True)
    ax4.hold(True)

    x, y = [], []
    times = [time.time() - cur_time]  # Create blank array to hold time values
    y.append(0)

    line1, = ax1.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line2, = ax2.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line3, = ax3.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line4, = ax4.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")


    fig.show()
    fig.canvas.draw()

    if use_blit:
        background1 = fig.canvas.copy_from_bbox(ax1.bbox) # cache the background
        background2 = fig.canvas.copy_from_bbox(ax2.bbox) # cache the background
        background3 = fig.canvas.copy_from_bbox(ax3.bbox) # cache the background
        background4 = fig.canvas.copy_from_bbox(ax4.bbox) # cache the background

    tic = time.time()

    niter = 200
    i = 0
    while i < niter:

        fields = random.random() * 100

        times.append(time.time() - cur_time)
        y.append(fields)

        # this removes the tail of the data so you can run for long hours. You can cache this
        # and store it in a pickle variable in parallel.

        if len(times) > 50:
           del y[0]
           del times[0]

        xmin, xmax, ymin, ymax = [min(times) / 1.05, max(times) * 1.1, -5,110]

        # feed the new data to the plot and set the axis limits again
        plt.axis([xmin, xmax, ymin, ymax])

        if use_blit:
            fig.canvas.restore_region(background1)    # restore background
            line1.set_xdata(times)
            line1.set_ydata(y)
            ax1.draw_artist(line1)                   # redraw just the points
            fig.canvas.blit(ax1.bbox)                # fill in the axes rectangle


            fig.canvas.restore_region(background2)    # restore background
            line2.set_xdata(times)
            line2.set_ydata(y)
            ax2.draw_artist(line2)                   # redraw just the points
            fig.canvas.blit(ax2.bbox)

            fig.canvas.restore_region(background3)    # restore background
            line3.set_xdata(times)
            line3.set_ydata(y)
            ax3.draw_artist(line3)                   # redraw just the points
            fig.canvas.blit(ax3.bbox)         

            fig.canvas.restore_region(background4)    # restore background
            line4.set_xdata(times)
            line4.set_ydata(y)
            ax4.draw_artist(line4)                   # redraw just the points
            fig.canvas.blit(ax4.bbox) 

        else:
            fig.canvas.draw()

        fig.canvas.flush_events()

        i += 1

    fps = niter / (time.time() - tic)
    return fps

а также

fig = plt.figure()
ax1 = fig.add_subplot(4, 1, 1)
ax2 = fig.add_subplot(4, 1, 2)
ax3 = fig.add_subplot(4, 1, 3)
ax4 = fig.add_subplot(4, 1, 4)
fps1 = test_fps(use_blit=True)

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

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

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


person jappoz92    schedule 22.05.2017    source источник


Ответы (1)


В текущей реализации вы устанавливаете пределы оси только для последнего графика, т.е. plt.axis([xmin, xmax, ymin, ymax]) работает на последнем активном подзаголовке.

Вместо этого вам нужно будет обновить все оси ax1 на ax4,

ax1.axis([xmin, xmax, ymin, ymax])
ax2.axis([xmin, xmax, ymin, ymax])
ax3.axis([xmin, xmax, ymin, ymax])
ax4.axis([xmin, xmax, ymin, ymax])

чтобы их пределы соответствовали данным.

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

Полный код:

import time    
import matplotlib
matplotlib.use('TkAgg')   
import matplotlib.pylab as plt
import random

def test_fps(use_blit=True):

    ax1.cla()
    ax1.set_title('Sensor Input vs. Time -')
    ax1.set_xlabel('Time (s)')
    ax1.set_ylabel('Sensor Input (mV)')
    ax2.cla()
    ax2.set_title('Sensor Input vs. Time -' )
    ax2.set_xlabel('Time (s)')
    ax2.set_ylabel('Sensor Input (mV)')
    ax3.cla()
    ax3.set_title('Sensor Input vs. Time -')
    ax3.set_xlabel('Time (s)')
    ax3.set_ylabel('Sensor Input (mV)')
    ax4.cla()
    ax4.set_title('Sensor Input vs. Time -')
    ax4.set_xlabel('Time (s)')
    ax4.set_ylabel('Sensor Input (mV)')

    plt.ion()  # Set interactive mode ON, so matplotlib will not be blocking the window
    plt.show(False)  # Set to false so that the code doesn't stop here

    cur_time = time.time()
    #    ax1.hold(True)
    #    ax2.hold(True)
    #    ax3.hold(True)
    #    ax4.hold(True)

    x, y = [], []
    times = [time.time() - cur_time]  # Create blank array to hold time values
    y.append(0)

    line1, = ax1.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line2, = ax2.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line3, = ax3.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
    line4, = ax4.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")


    fig.show()
    fig.canvas.draw()

    if use_blit:
        background1 = fig.canvas.copy_from_bbox(ax1.bbox) # cache the background
        background2 = fig.canvas.copy_from_bbox(ax2.bbox) # cache the background
        background3 = fig.canvas.copy_from_bbox(ax3.bbox) # cache the background
        background4 = fig.canvas.copy_from_bbox(ax4.bbox) # cache the background

    tic = time.time()

    niter = 200
    i = 0
    while i < niter:

        fields = random.random() * 100

        times.append(time.time() - cur_time)
        y.append(fields)

        # this removes the tail of the data so you can run for long hours. You can cache this
        # and store it in a pickle variable in parallel.

        if len(times) > 50:
           del y[0]
           del times[0]

        xmin, xmax, ymin, ymax = [min(times) / 1.05, max(times) * 1.1, -5,110]

        # feed the new data to the plot and set the axis limits again
        ax1.axis([xmin, xmax, ymin, ymax])
        ax2.axis([xmin, xmax, ymin, ymax])
        ax3.axis([xmin, xmax, ymin, ymax])
        ax4.axis([xmin, xmax, ymin, ymax])

        line1.set_data(times, y)
        line2.set_data(times, y)
        line3.set_data(times, y)
        line4.set_data(times, y)

        if use_blit:
            fig.canvas.restore_region(background1)    # restore background
            ax1.draw_artist(line1)                   # redraw just the points
            fig.canvas.blit(ax1.bbox)                # fill in the axes rectangle

            fig.canvas.restore_region(background2)    # restore background
            ax2.draw_artist(line2)                   # redraw just the points
            fig.canvas.blit(ax2.bbox)

            fig.canvas.restore_region(background3)    # restore background
            ax3.draw_artist(line3)                   # redraw just the points
            fig.canvas.blit(ax3.bbox)         

            fig.canvas.restore_region(background4)    # restore background
            ax4.draw_artist(line4)                   # redraw just the points
            fig.canvas.blit(ax4.bbox) 

        else:
            fig.canvas.draw()

        fig.canvas.flush_events()

        i += 1

    fps = niter / (time.time() - tic)
    return fps

fig = plt.figure()
ax1 = fig.add_subplot(4, 1, 1)
ax2 = fig.add_subplot(4, 1, 2)
ax3 = fig.add_subplot(4, 1, 3)
ax4 = fig.add_subplot(4, 1, 4)
fps1 = test_fps(use_blit=True)
print fps1

Просто отметим, что на моем компьютере это работает без бликов со скоростью 10 кадров в секунду и с битами со скоростью 16 кадров в секунду.

person ImportanceOfBeingErnest    schedule 22.05.2017
comment
Это решение работает для меня, большое спасибо. В любом случае, на моем ПК у меня было 20 кадров в секунду без блит и 96 кадров в секунду с блит, я бы сказал, хорошее улучшение. - person jappoz92; 22.05.2017
comment
О, это действительно здорово. Если у вас есть время, мне было бы интересно узнать, какие частоты кадров вы получаете для части matplotlib этого моего ответа, чтобы сравнить это до 18 и 28 кадров в секунду, которые я там получил. - person ImportanceOfBeingErnest; 22.05.2017
comment
Что ж, у меня недостаточно репутации, чтобы добавить комментарий под ваш вопрос. Во всяком случае, я получил ок. 13 кадров в секунду без блита и 16 кадров в секунду с блит-кодом, запустив скопированный код версии matplotlib. - person jappoz92; 22.05.2017
comment
Это кажется разумным, но вызывает вопрос, почему у вас такая высокая частота кадров в этом вашем примере. В любом случае, спасибо, что поделились этим. - person ImportanceOfBeingErnest; 22.05.2017