как заставить matplotlib обновить график

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

Проблема, как кажется сейчас, заключается в том, что холст не обновляется, как только я вызываю canvas.draw(). Когда эта программа запускается, data_collect() и paint() попеременно отправляют сигналы, но рисунок не обновляется до тех пор, пока я не остановлю процесс. Как я могу заставить matplotlib обновлять фигуру всякий раз, когда вызывается paint()?

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

N_length = 150;
count = [0];

def sinval(delay):

    k = 0;
    x = [];

    # set up data vector with sinusoidal data in it.
    while k < N_length:  
        x.append(math.sin(2*math.pi*k/N_length));
        k += 1;

    def next():

        time.sleep(delay);
        outstring = "%0.3e" % (x[count[0]]);

        if (count[0] == (N_length-1)):
            count[0] = 0;
        else:
            count[0] += 1;

        return outstring;

    return next;


class DesignerMainWindow(QtGui.QMainWindow, Ui_mplMainWindow):

    def __init__(self, parent = None):
        super(DesignerMainWindow, self).__init__(parent)
        self.setupUi(self)

        QtCore.QObject.connect(self.mplStartButton, QtCore.SIGNAL("clicked()"), self.start_graph);
        QtCore.QObject.connect(self.mplStopButton, QtCore.SIGNAL("clicked()"), self.stop_graph);
        QtCore.QObject.connect(self.mplQuitButton, QtCore.SIGNAL("clicked()"), QtGui.qApp, QtCore.SLOT("quit()"));
        QtCore.QObject.connect(self, QtCore.SIGNAL("data_collect()"), self.data_collect);
        QtCore.QObject.connect(self, QtCore.SIGNAL("paint()"), self.paint);

    def start_graph(self):

        # generates first "empty" plots
        self.user = [];
        self.l_user, = self.mpl.canvas.ax.plot([], self.user, label='sine wave');

        # set up the axes. 
        self.mpl.canvas.ax.set_xlim(0, 300);
        self.mpl.canvas.ax.set_ylim(-1.1, 1.1);
        self.mpl.canvas.draw();

        # start the data collection process.
        self.delay = 0.05;
        self.next = sinval(self.delay);
        self.emit(QtCore.SIGNAL('data_collect()'));


    def data_collect(self):
        outstring = self.next();
        self.user.append(float(outstring.split()[0]));
        self.l_user.set_data(range(len(self.user)), self.user);
        self.emit(QtCore.SIGNAL('paint()'));


    def paint(self):
        self.mpl.canvas.draw();
        self.emit(QtCore.SIGNAL('data_collect()'));

person user424211    schedule 18.08.2010    source источник
comment
Я что-то упустил, или вы пропустили все сюжетные команды? Ни data_collect, ни paint, кажется, не имеют каких-либо сюжетных команд (например, self.mpl.canvas.ax.plot), которые могли бы изменить сюжет. Так не будет ли вызов self.mpl.canvas.draw() просто перерисовывать тот же старый график?   -  person unutbu    schedule 18.08.2010
comment
@~unutbu - Он настраивает обновление данных графика с помощью self.l_user.set_data(...), а не перерисовывает все. (Это намного эффективнее, чем вызов plot, если вы просто хотите изменить данные графика, а не перерисовывать метки оси и т. д.)   -  person Joe Kington    schedule 18.08.2010
comment
Насколько я понимаю, обновление l_user.set_data и последующий вызов canvas.draw() автоматически обновит фигуру. Я попытался изменить первую команду в paint(self) на self.mpl.canvas.ax.plot(), но, похоже, это не сработало. как мне изменить эту команду? Спасибо -   -  person user424211    schedule 18.08.2010
comment
@Joe и @user424211: Хорошо, спасибо за объяснение.   -  person unutbu    schedule 18.08.2010


Ответы (1)


Я предполагаю, что вызов QCoreApplication::processEvents после paint() поможет. Более элегантным было бы иметь отдельный QThread для чтения. Взгляните на этот поток.

person FFox    schedule 18.08.2010
comment
Спасибо! Мне пришлось вызвать QtGui.QApplication.processEvents() в PyQt4, но это помогло. - person user424211; 18.08.2010