2017-01-19 5 views
1

Я захватываю данные с устройства и желаю построить его напряжение, при этом график встроен в UI. Я использовал здесь пример: http://matplotlib.org/examples/user_interfaces/embedding_in_qt4.htmlКак я могу изменить этот код, так что я не переустанавливаю свой график каждый раз, matplotlib

Этот пример отлично работает, но когда я добавляю 2 или более графиков, весь пользовательский интерфейс становится очень медленным (с использованием RPi3), а использование ЦП действительно велико. Я понимаю, что это, вероятно, потому, что график постоянно очищается и ретранслируется.

Мой код выглядит следующим образом:

class MyMplCanvas(FigureCanvas): 
    def __init__(self, parent=None, width=5, height=2, dpi=100): 
     fig = Figure(figsize=(width, height), dpi=dpi) 
     self.axes = fig.add_subplot(111) 

     self.compute_initial_figure() 

     FigureCanvas.__init__(self, fig) 
     self.setParent(parent) 

     FigureCanvas.setSizePolicy(self,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding) 
     FigureCanvas.updateGeometry(self) 

    def compute_initial_figure(self): 
     pass 

class MyDynamicMplCanvas(MyMplCanvas): 

    def __init__(self, *args, **kwargs): 
     MyMplCanvas.__init__(self, *args, **kwargs) 

    def compute_initial_figure(self): 
     self.axes.cla() 

    def update_figure(self,voltage): 
     self.axes.cla() 
     self.axes.plot(np.linspace(0,len(voltage)-1,num = len(voltage)), voltage, 'b') 
     self.axes.set_xlabel("Time") 
     self.draw() 


class worker_thread(QThread): 
... #worker thread stuff here 

class Monitor(QtGui.QMainWindow): 

    def __init__(self, parent = None): 
     QtGui.QMainWindow.__init__(self, parent) 
     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     self.ui.exit_button.clicked.connect(exit) 
     self.ui.go_button.clicked.connect(self.start_monitoring) 
     self.ui.print_button.clicked.connect(self.test_print) 

     self.ac_graph = QtGui.QWidget(self) 
     self.ac_1_graph = MyDynamicMplCanvas(self.ac_graph,width = 10, height =3 , dpi = 60) 
     self.ui.mplvl.addWidget(self.ac_1_graph) 
     self.ac_1_graph.axes.set_xlabel("Time") 

     self.dc_graph = QtGui.QWidget(self) 
     self.dc_2_graph = MyDynamicMplCanvas(self.dc_graph,width = 10, height =3 , dpi = 60) 
     self.ui.mplvl_2.addWidget(self.dc_2_graph)  

     self.ac1_voltage_values = [] 
     self.ac1_current_values = [] 
     self.dc2_voltage_values = [] 

    def start_monitoring(self): 

     self.worker_thread = worker_thread() 

     self.connect(self.worker_thread,SIGNAL('grid_done'),  self.update_ac_dc_info) 

    def update_plot_values(self, y_value, y_list): 
     y_list.append(y_value) 
     if (len(y_list) == 61): 
      del y_list[0] 
     return y_list 

    def update_ac_dc_info(self,grid_info): 
     self.ac1_voltage_values = self.update_plot_values((grid_info['ac1_voltage']/10),self.ac1_voltage_values) 
     self.ac_1_graph.update_figure(self.ac1_voltage_values) 

По существу, когда данные поступают обратно из моего устройства, я испускать сигнал от worker_thread, который запускает свой пользовательский интерфейс для обновления в главном потоке, а также сюжет , На данный момент, как мне просто получить matplotlib, чтобы просто принять новый пункт, который пришел в БЕЗ заимствования всего? Многие из примеров, которые я прочитал, используют pyplot, который я не могу использовать, потому что мне нужно внедрить его в существующий пользовательский интерфейс.

ответ

2

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

class MyDynamicMplCanvas(MyMplCanvas): 

    def __init__(self, *args, **kwargs): 
     MyMplCanvas.__init__(self, *args, **kwargs) 

    def compute_initial_figure(self): 
     # empty plot 
     self.line, = self.axes.plot([],[], color="b") 
     self.axes.set_xlabel("Time") # xlabel will not change over time 

    def update_figure(self,voltage): 

     self.line.set_data(np.linspace(0,len(voltage)-1,num = len(voltage)), voltage) 
     # now you need to take care of the axis limits yourself 
     self.axes.set_xlim([0,len(voltage]) 
     self.draw() 

Обновление только последний новый пункт немного сложнее, так как сюжет состоит из одного Line2D объекта. Вы можете выбрать точечный сюжет, где каждый раз, когда появятся новые данные, вы можете построить одну новую точку.

+0

Спасибо за ваш ответ! Я изменил свой код на то, что вы разместили, и он работает нормально. Я могу построить два графика с минимальной загрузкой процессора на моей малиновой пи. До того, как я все время пингал на 100%. Теперь я могу делать другие вещи, пока моя программа работает. Оказывается, моя функция 'update_plot_values' заботится только о построении последней точки, автоматически удаляя последнее значение списка и добавляя одно новое значение, затем весь этот список передается в' set_data'!. Я также решил проблему масштабирования осей (см. Мой ответ, если кто-то хочет знать) – jgv115

0

Метод ImportanceOfBeingErnest работает просто отлично. Чтобы перемасштабировать ось на основе данных:

self.axes.relim() 
self.axes.autoscale_view(True,True,True)