Real-time bar display using pyqtgraph


I used pyqtgraph to create real-time bar displays which show positive and negative accelerometer data real-time:

accelerometer data

I'm displaying x,y,z accelerometer data from a 3 axis accelerometer. he bottom bar shows the overall amplitude, which is (x2+y2+z2). The circuit  I am using to collect the sensor data is shown below - an MPU6050 3-axis accelerometer/gyrsocope board connected to a pyboard v1.0 using the I2C interface.
pyboard v1.0 and an MPU6050 3-axis accelerometer/gyroscope board
Now pyqtgraph does have a bar chart class, BarGraphItem. I would like to link to the documentation for this class, but there is not any pyqtgraph documentation here at the time of writing! There is an example program bundled with the pyqtgraph library though, which is how I learned about the class. Search on 'pyqtgraph bargraphitem' and you will find the listing. However I could not see how to animate it. I tried. I failed. So I did it a different way. I used the pyside QProgressBar class to create my own display widget, which I named Gui_Pbar and call pbars. Please find the listing for Gui_Pbar below.

  1. import pyqtgraph as pg
  2. from PySide import QtGui
  3.  
  4. class Gui_Pbar():
  5.     def __init__(self, title='', color=''max=2):
  6.         ''' max value = max '''
  7.         self.layout_pbar = pg.LayoutWidget()
  8.         self.pos_pbar = QtGui.QProgressBar()
  9.         self.neg_pbar = QtGui.QProgressBar()
  10.         self.neg_pbar.setInvertedAppearance(True)
  11.         self.title = title
  12.         self.max = max
  13.         self.pos_pbar.setFormat('')
  14.         self.neg_pbar.setFormat('')
  15.         self.pos_pbar.setGeometry(304020025)
  16.         self.neg_pbar.setGeometry(304020025)
  17.         if color:
  18.             self.change_color(color)
  19.         self.layout_pbar.addWidget(self.neg_pbar, row=1, col=1)
  20.         self.layout_pbar.addWidget(self.pos_pbar, row=1, col=2)
  21.        
  22.     def change_color(self, color):
  23.         ''' change the progress bar color '''
  24.         template_css = """QProgressBar::chunk { background: %s; }"""
  25.         css = template_css % color
  26.         self.pos_pbar.setStyleSheet(css)
  27.         self.neg_pbar.setStyleSheet(css)
  28.        
  29.     def change_text(self, text):
  30.         ''' display text on progress bar '''
  31.         self.pos_pbar.setFormat(text)
  32.        
  33.     def return_pbar(self):
  34.         return self.layout_pbar
  35.    
  36.     def update_pbar(self, acc_value):
  37.         ''' Set the value of the pbar. '''
  38.         value = acc_value*100/self.max
  39.         if acc_value>0:
  40.             self.neg_pbar.setValue(0)
  41.             self.pos_pbar.setValue(value)
  42.             self.change_text('{} {:0.2f}'.format(self.title, acc_value))
  43.         else:
  44.             self.pos_pbar.setValue(0)
  45.             self.neg_pbar.setValue(-value)
  46.             self.change_text('{} {:0.2f}'.format(self.title, acc_value))

As the acceleration data can be negative as well as positive, each pbar has two QProgressBar widgets, which are created in lines 8 and 9, one each for the negative and positive values. I create a LayoutWidget in line 7 to hold the two progress bar widgets and in lines 19 and 20 these progress bar widgets are added to the LayoutWidget side by side. The bar for negative values is set to fill from the right to get the correct visual appearance, this is set in line 10. There is a little gap in between the negative and positive bars, which I would like to get rid of. I played around for a while to try and figure out how to do this, then put it on my 'to do one day maybe' list as the result I have is 'good enough'. Make it work, make it right, make it fast. It works, it is fast enough - maybe getting rid of the gap constitutes the 'make it right' bit?

The change_color method which starts in line 22 is used to set the colour of the pbar. The pbar value is set in update_bar which starts in line 36. This method tests if the value is positive or negative in line 39, then sets the positive or negative progress bar accordingly. return_pbar returns the layout widget containing the pbar. 

change_text allows text to be superimposed on to the displays. In my application, I set this to show the value of acceleration being displayed by the pbar.

The following code snippet shows how I use the Gui_Pbar class to add pbars to my real-time accelerometer display.

  1. # bar graphs
  2.         self.x_pbar = Gui_Pbar(title='x_acc:', color='yellow')
  3.         self.y_pbar = Gui_Pbar(title='y_acc:', color='green')
  4.         self.z_pbar = Gui_Pbar(title='z_acc:', color='blue')
  5.         self.amp_pbar = Gui_Pbar(title='amp_acc:', color='red')
  6.         layout_bars = pg.LayoutWidget()
  7.         layout_bars.addWidget(self.x_pbar.return_pbar(), row=1, col=1)
  8.         layout_bars.addWidget(self.y_pbar.return_pbar(), row=2, col=1)
  9.         layout_bars.addWidget(self.z_pbar.return_pbar(), row=3, col=1)
  10.         layout_bars.addWidget(self.amp_pbar.return_pbar(), row=4, col=1)
  11.         dock_bar.addWidget(layout_bars)
Lines 1-4 instigate the pbars. Line 6 sets up a LayoutWidget to hold them and each pbar is added to this holder in lines 7-9. Line 11 shows the layout_bars layout being added to the dock in the user interface. Holders within holders within holders! This is how user interfaces can be built up in a modular fashion.

So I created a bar display which shows real-time accelerometer data, positive and negative values with out too much coding trauma.

Comments