├── .gitignore.txt ├── 2016-07-30_qt_matplotlib_sine_scroll ├── LICENSE.md ├── README.md ├── demo.gif ├── go.bat ├── go.py ├── matplotlibwidget.py ├── ui_convert.py ├── ui_main.py └── ui_main.ui ├── 2016-07-31_qt_PyQtGraph_sine_scroll ├── LICENSE.md ├── README.md ├── demo2.gif ├── go.bat ├── go.py ├── ui_convert.py ├── ui_main.py └── ui_main.ui ├── 2016-07-37_qt_audio_monitor ├── LICENSE.rc ├── README.md ├── SWHear.py ├── demo.gif ├── go.py ├── ui_convert.py ├── ui_main.py └── ui_main.ui ├── 2017-06-10_python27_qt4 ├── demo.png ├── readme.md ├── run.cmd ├── run.py ├── ui2py.py ├── ui2py.pyc ├── ui_main.py ├── ui_main.pyc └── ui_main.ui ├── 2019-02-03_pyQtGraph ├── pyQtGraph-example.py ├── readme.md └── screenshot.PNG ├── LICENSE └── README.md /.gitignore.txt: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2016] [Scott W Harden] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/README.md: -------------------------------------------------------------------------------- 1 | # Matplotlib MatplotlibWidget demo 2 | This was tested to be ~40x SLOWER than a similar pyqtgraph graph 3 | 4 | PROJECT PAGE: http://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/ 5 | 6 | This is a minimal-case example how to get a PyQt4 GUI (designed with QT Designer) to display a matploblit widget and update it automatically. This was tested with the WinPython 3.x distribution, but should be cross platform. Read the parent readme for full project details. 7 | 8 | * edit the ui_main.ui with "Qt Designer" 9 | * run ui_convert.py to turn ui_main.ui into ui_main.py 10 | * run go.py to launch the program (pulling UI from ui_main.py) 11 | * if the "keep updating" box is checked and the add buttin is hit, it does more and more! 12 | 13 | ![demo](demo.gif) 14 | 15 | ### Misc notes 16 | If you get `ImportError: No module named 'matplotlibwidget'`, ensure you are in the same folder as `matplotlibwidget.py` which is now provided with this example. -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2016-07-30_qt_matplotlib_sine_scroll/demo.gif -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/go.bat: -------------------------------------------------------------------------------- 1 | python go.py 2 | pause -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/go.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui,QtCore 2 | import sys 3 | import ui_main 4 | import numpy as np 5 | import pylab 6 | import time 7 | 8 | class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow): 9 | def __init__(self, parent=None): 10 | super(ExampleApp, self).__init__(parent) 11 | self.setupUi(self) 12 | self.btnAdd.clicked.connect(self.update) 13 | self.matplotlibwidget.axes.hold(False) #clear on plot() 14 | 15 | def update(self): 16 | t1=time.time() 17 | points=100 #number of data points 18 | X=np.arange(points) 19 | Y=np.sin(np.arange(points)/points*3*np.pi+time.time()) 20 | C=pylab.cm.jet(time.time()%10/10) # random color 21 | self.matplotlibwidget.axes.plot(X,Y,ms=100,color=C,lw=10,alpha=.8) 22 | self.matplotlibwidget.axes.grid() 23 | self.matplotlibwidget.axes.get_figure().tight_layout() # fill space 24 | self.matplotlibwidget.draw() # required to update the window 25 | print("update took %.02f ms"%((time.time()-t1)*1000)) 26 | if self.chkMore.isChecked(): 27 | QtCore.QTimer.singleShot(10, self.update) # QUICKLY repeat 28 | 29 | if __name__=="__main__": 30 | app = QtGui.QApplication(sys.argv) 31 | form = ExampleApp() 32 | form.show() 33 | form.update() #start with something 34 | app.exec_() 35 | print("DONE") -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/matplotlibwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright © 2009 Pierre Raybaut 4 | # Licensed under the terms of the MIT License 5 | 6 | """ 7 | MatplotlibWidget 8 | ================ 9 | 10 | Example of matplotlib widget for PyQt4 11 | 12 | Copyright © 2009 Pierre Raybaut 13 | This software is licensed under the terms of the MIT License 14 | 15 | Derived from 'embedding_in_pyqt4.py': 16 | Copyright © 2005 Florent Rougon, 2006 Darren Dale 17 | """ 18 | 19 | __version__ = "1.0.0" 20 | 21 | from PyQt4.QtGui import QSizePolicy 22 | from PyQt4.QtCore import QSize 23 | 24 | from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as Canvas 25 | from matplotlib.figure import Figure 26 | 27 | from matplotlib import rcParams 28 | rcParams['font.size'] = 9 29 | 30 | 31 | class MatplotlibWidget(Canvas): 32 | """ 33 | MatplotlibWidget inherits PyQt4.QtGui.QWidget 34 | and matplotlib.backend_bases.FigureCanvasBase 35 | 36 | Options: option_name (default_value) 37 | ------- 38 | parent (None): parent widget 39 | title (''): figure title 40 | xlabel (''): X-axis label 41 | ylabel (''): Y-axis label 42 | xlim (None): X-axis limits ([min, max]) 43 | ylim (None): Y-axis limits ([min, max]) 44 | xscale ('linear'): X-axis scale 45 | yscale ('linear'): Y-axis scale 46 | width (4): width in inches 47 | height (3): height in inches 48 | dpi (100): resolution in dpi 49 | hold (False): if False, figure will be cleared each time plot is called 50 | 51 | Widget attributes: 52 | ----------------- 53 | figure: instance of matplotlib.figure.Figure 54 | axes: figure axes 55 | 56 | Example: 57 | ------- 58 | self.widget = MatplotlibWidget(self, yscale='log', hold=True) 59 | from numpy import linspace 60 | x = linspace(-10, 10) 61 | self.widget.axes.plot(x, x**2) 62 | self.wdiget.axes.plot(x, x**3) 63 | """ 64 | def __init__(self, parent=None, title='', xlabel='', ylabel='', 65 | xlim=None, ylim=None, xscale='linear', yscale='linear', 66 | width=4, height=3, dpi=100, hold=False): 67 | self.figure = Figure(figsize=(width, height), dpi=dpi) 68 | self.axes = self.figure.add_subplot(111) 69 | self.axes.set_title(title) 70 | self.axes.set_xlabel(xlabel) 71 | self.axes.set_ylabel(ylabel) 72 | if xscale is not None: 73 | self.axes.set_xscale(xscale) 74 | if yscale is not None: 75 | self.axes.set_yscale(yscale) 76 | if xlim is not None: 77 | self.axes.set_xlim(*xlim) 78 | if ylim is not None: 79 | self.axes.set_ylim(*ylim) 80 | self.axes.hold(hold) 81 | 82 | Canvas.__init__(self, self.figure) 83 | self.setParent(parent) 84 | 85 | Canvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) 86 | Canvas.updateGeometry(self) 87 | 88 | def sizeHint(self): 89 | w, h = self.get_width_height() 90 | return QSize(w, h) 91 | 92 | def minimumSizeHint(self): 93 | return QSize(10, 10) 94 | 95 | 96 | 97 | #=============================================================================== 98 | # Example 99 | #=============================================================================== 100 | if __name__ == '__main__': 101 | import sys 102 | from PyQt4.QtGui import QMainWindow, QApplication 103 | from numpy import linspace 104 | 105 | class ApplicationWindow(QMainWindow): 106 | def __init__(self): 107 | QMainWindow.__init__(self) 108 | self.mplwidget = MatplotlibWidget(self, title='Example', 109 | xlabel='Linear scale', 110 | ylabel='Log scale', 111 | hold=True, yscale='log') 112 | self.mplwidget.setFocus() 113 | self.setCentralWidget(self.mplwidget) 114 | self.plot(self.mplwidget.axes) 115 | 116 | def plot(self, axes): 117 | x = linspace(-10, 10) 118 | axes.plot(x, x**2) 119 | axes.plot(x, x**3) 120 | 121 | app = QApplication(sys.argv) 122 | win = ApplicationWindow() 123 | win.show() 124 | sys.exit(app.exec_()) 125 | -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/ui_convert.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import uic 2 | import glob 3 | for fname in glob.glob("*.ui"): 4 | print("converting",fname) 5 | fin = open(fname,'r') 6 | fout = open(fname.replace(".ui",".py"),'w') 7 | uic.compileUi(fin,fout,execute=False) 8 | fin.close() 9 | fout.close() 10 | -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/ui_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_main.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_MainWindow(object): 26 | def setupUi(self, MainWindow): 27 | MainWindow.setObjectName(_fromUtf8("MainWindow")) 28 | MainWindow.resize(820, 650) 29 | MainWindow.setAutoFillBackground(False) 30 | MainWindow.setDocumentMode(False) 31 | self.centralwidget = QtGui.QWidget(MainWindow) 32 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 33 | self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) 34 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 35 | self.horizontalLayout = QtGui.QHBoxLayout() 36 | self.horizontalLayout.setContentsMargins(-1, -1, 0, 0) 37 | self.horizontalLayout.setSpacing(10) 38 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 39 | self.btnAdd = QtGui.QPushButton(self.centralwidget) 40 | self.btnAdd.setObjectName(_fromUtf8("btnAdd")) 41 | self.horizontalLayout.addWidget(self.btnAdd) 42 | self.chkMore = QtGui.QCheckBox(self.centralwidget) 43 | self.chkMore.setObjectName(_fromUtf8("chkMore")) 44 | self.horizontalLayout.addWidget(self.chkMore) 45 | self.verticalLayout.addLayout(self.horizontalLayout) 46 | self.matplotlibwidget = MatplotlibWidget(self.centralwidget) 47 | self.matplotlibwidget.setObjectName(_fromUtf8("matplotlibwidget")) 48 | self.verticalLayout.addWidget(self.matplotlibwidget) 49 | MainWindow.setCentralWidget(self.centralwidget) 50 | self.statusbar = QtGui.QStatusBar(MainWindow) 51 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 52 | MainWindow.setStatusBar(self.statusbar) 53 | 54 | self.retranslateUi(MainWindow) 55 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 56 | 57 | def retranslateUi(self, MainWindow): 58 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) 59 | self.btnAdd.setText(_translate("MainWindow", "update sine wave", None)) 60 | self.chkMore.setText(_translate("MainWindow", "keep updating", None)) 61 | 62 | from matplotlibwidget import MatplotlibWidget 63 | -------------------------------------------------------------------------------- /2016-07-30_qt_matplotlib_sine_scroll/ui_main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 820 10 | 650 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | false 18 | 19 | 20 | false 21 | 22 | 23 | 24 | 25 | 26 | 27 | 10 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 37 | 38 | update sine wave 39 | 40 | 41 | 42 | 43 | 44 | 45 | keep updating 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | MatplotlibWidget 61 | QWidget 62 |
matplotlibwidget
63 |
64 |
65 | 66 | 67 |
68 | -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2016] [Scott W Harden] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/README.md: -------------------------------------------------------------------------------- 1 | # PyQtGraph GraphWidget demo 2 | This was tested to be ~40x faster than a similar matplotlib graph 3 | 4 | PROJECT PAGE: http://www.swharden.com/wp/2016-07-31-live-data-in-pyqt4-with-plotwidget/ 5 | 6 | This is a minimal-case example how to get a PyQt4 GUI (designed with QT Designer) to display a 7 | pyqtgraph PlotWidget and update it automatically. This was tested with the WinPython 3.x distribution, 8 | but should be cross platform. Read the parent readme for full project details. 9 | 10 | * edit the ui_main.ui with "Qt Designer" 11 | * run ui_convert.py to turn ui_main.ui into ui_main.py 12 | * run go.py to launch the program (pulling UI from ui_main.py) 13 | * if the "keep updating" box is checked and the add buttin is hit, it does more and more! 14 | 15 | ![demo](demo2.gif) 16 | -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2016-07-31_qt_PyQtGraph_sine_scroll/demo2.gif -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/go.bat: -------------------------------------------------------------------------------- 1 | python go.py 2 | pause -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/go.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui,QtCore 2 | import sys 3 | import ui_main 4 | import numpy as np 5 | import pylab 6 | import time 7 | import pyqtgraph 8 | 9 | class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow): 10 | def __init__(self, parent=None): 11 | pyqtgraph.setConfigOption('background', 'w') #before loading widget 12 | super(ExampleApp, self).__init__(parent) 13 | self.setupUi(self) 14 | self.btnAdd.clicked.connect(self.update) 15 | self.grPlot.plotItem.showGrid(True, True, 0.7) 16 | 17 | def update(self): 18 | t1=time.clock() 19 | points=100 #number of data points 20 | X=np.arange(points) 21 | Y=np.sin(np.arange(points)/points*3*np.pi+time.time()) 22 | C=pyqtgraph.hsvColor(time.time()/5%1,alpha=.5) 23 | pen=pyqtgraph.mkPen(color=C,width=10) 24 | self.grPlot.plot(X,Y,pen=pen,clear=True) 25 | print("update took %.02f ms"%((time.clock()-t1)*1000)) 26 | if self.chkMore.isChecked(): 27 | QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat 28 | 29 | if __name__=="__main__": 30 | app = QtGui.QApplication(sys.argv) 31 | form = ExampleApp() 32 | form.show() 33 | form.update() #start with something 34 | app.exec_() 35 | print("DONE") -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/ui_convert.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import uic 2 | import glob 3 | for fname in glob.glob("*.ui"): 4 | print("converting",fname) 5 | fin = open(fname,'r') 6 | fout = open(fname.replace(".ui",".py"),'w') 7 | uic.compileUi(fin,fout,execute=False) 8 | fin.close() 9 | fout.close() 10 | -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/ui_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_main.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_MainWindow(object): 26 | def setupUi(self, MainWindow): 27 | MainWindow.setObjectName(_fromUtf8("MainWindow")) 28 | MainWindow.resize(820, 650) 29 | MainWindow.setAutoFillBackground(False) 30 | MainWindow.setDocumentMode(False) 31 | self.centralwidget = QtGui.QWidget(MainWindow) 32 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 33 | self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) 34 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 35 | self.horizontalLayout = QtGui.QHBoxLayout() 36 | self.horizontalLayout.setContentsMargins(-1, -1, 0, 0) 37 | self.horizontalLayout.setSpacing(10) 38 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 39 | self.btnAdd = QtGui.QPushButton(self.centralwidget) 40 | self.btnAdd.setObjectName(_fromUtf8("btnAdd")) 41 | self.horizontalLayout.addWidget(self.btnAdd) 42 | self.chkMore = QtGui.QCheckBox(self.centralwidget) 43 | self.chkMore.setObjectName(_fromUtf8("chkMore")) 44 | self.horizontalLayout.addWidget(self.chkMore) 45 | self.verticalLayout.addLayout(self.horizontalLayout) 46 | self.grPlot = PlotWidget(self.centralwidget) 47 | self.grPlot.setObjectName(_fromUtf8("grPlot")) 48 | self.verticalLayout.addWidget(self.grPlot) 49 | MainWindow.setCentralWidget(self.centralwidget) 50 | self.statusbar = QtGui.QStatusBar(MainWindow) 51 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 52 | MainWindow.setStatusBar(self.statusbar) 53 | 54 | self.retranslateUi(MainWindow) 55 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 56 | 57 | def retranslateUi(self, MainWindow): 58 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) 59 | self.btnAdd.setText(_translate("MainWindow", "update sine wave", None)) 60 | self.chkMore.setText(_translate("MainWindow", "keep updating", None)) 61 | 62 | from pyqtgraph import PlotWidget 63 | -------------------------------------------------------------------------------- /2016-07-31_qt_PyQtGraph_sine_scroll/ui_main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 820 10 | 650 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | false 18 | 19 | 20 | false 21 | 22 | 23 | 24 | 25 | 26 | 27 | 10 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 37 | 38 | update sine wave 39 | 40 | 41 | 42 | 43 | 44 | 45 | keep updating 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | PlotWidget 61 | QGraphicsView 62 |
pyqtgraph
63 |
64 |
65 | 66 | 67 |
68 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/LICENSE.rc: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Scott W Harden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/README.md: -------------------------------------------------------------------------------- 1 | 2 | # qt audio monitor 3 | 4 | PROJECT PAGE: http://www.swharden.com/wp/2016-07-31-real-time-audio-monitor-with-pyqt/ 5 | 6 | This is a minimal-case example how to get continuous PCM data from the sound card. A preliminary SWHEar class is included which can self-detect likely input devices. To manually define an input device, set it when SWHEar() is called. In most cases it will work right out of the box. If you're playing music and no microphone is detected, it will use the sound mapper and graph the audio being played. 7 | 8 | Youtube demo: https://youtu.be/lDS9rI0o6mM 9 | 10 | ![demo](demo.gif) 11 | 12 | ### Setup 13 | * pyaudio (which requires [portaudio](http://portaudio.com/)) comes ready to use if you install Anaconda 14 | * I did have to `conda install pyqtgraph pyaudio` 15 | 16 | ### Input overflow error? 17 | If you experience _[Errno -9981] Input overflowed_ errors, consider modifying [this line](https://github.com/swharden/Python-GUI-examples/blob/master/2016-07-37_qt_audio_monitor/SWHear.py#L119) and change: 18 | ```python 19 | self.stream.read(self.chunk) 20 | ``` 21 | to: 22 | ```python 23 | self.stream.read(self.chunk, exception_on_overflow=False) 24 | ``` 25 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/SWHear.py: -------------------------------------------------------------------------------- 1 | """ 2 | this is a stripped down version of the SWHear class. 3 | It's designed to hold only a single audio sample in memory. 4 | check my githib for a more complete version: 5 | http://github.com/swharden 6 | """ 7 | 8 | import pyaudio 9 | import time 10 | import numpy as np 11 | import threading 12 | 13 | def getFFT(data,rate): 14 | """Given some data and rate, returns FFTfreq and FFT (half).""" 15 | data=data*np.hamming(len(data)) 16 | fft=np.fft.fft(data) 17 | fft=np.abs(fft) 18 | #fft=10*np.log10(fft) 19 | freq=np.fft.fftfreq(len(fft),1.0/rate) 20 | return freq[:int(len(freq)/2)],fft[:int(len(fft)/2)] 21 | 22 | class SWHear(): 23 | """ 24 | The SWHear class is provides access to continuously recorded 25 | (and mathematically processed) microphone data. 26 | 27 | Arguments: 28 | 29 | device - the number of the sound card input to use. Leave blank 30 | to automatically detect one. 31 | 32 | rate - sample rate to use. Defaults to something supported. 33 | 34 | updatesPerSecond - how fast to record new data. Note that smaller 35 | numbers allow more data to be accessed and therefore high 36 | frequencies to be analyzed if using a FFT later 37 | """ 38 | 39 | def __init__(self,device=None,rate=None,updatesPerSecond=10): 40 | self.p=pyaudio.PyAudio() 41 | self.chunk=4096 # gets replaced automatically 42 | self.updatesPerSecond=updatesPerSecond 43 | self.chunksRead=0 44 | self.device=device 45 | self.rate=rate 46 | 47 | ### SYSTEM TESTS 48 | 49 | def valid_low_rate(self,device): 50 | """set the rate to the lowest supported audio rate.""" 51 | for testrate in [44100]: 52 | if self.valid_test(device,testrate): 53 | return testrate 54 | print("SOMETHING'S WRONG! I can't figure out how to use DEV",device) 55 | return None 56 | 57 | def valid_test(self,device,rate=44100): 58 | """given a device ID and a rate, return TRUE/False if it's valid.""" 59 | try: 60 | self.info=self.p.get_device_info_by_index(device) 61 | if not self.info["maxInputChannels"]>0: 62 | return False 63 | stream=self.p.open(format=pyaudio.paInt16,channels=1, 64 | input_device_index=device,frames_per_buffer=self.chunk, 65 | rate=int(self.info["defaultSampleRate"]),input=True) 66 | stream.close() 67 | return True 68 | except: 69 | return False 70 | 71 | def valid_input_devices(self): 72 | """ 73 | See which devices can be opened for microphone input. 74 | call this when no PyAudio object is loaded. 75 | """ 76 | mics=[] 77 | for device in range(self.p.get_device_count()): 78 | if self.valid_test(device): 79 | mics.append(device) 80 | if len(mics)==0: 81 | print("no microphone devices found!") 82 | else: 83 | print("found %d microphone devices: %s"%(len(mics),mics)) 84 | return mics 85 | 86 | ### SETUP AND SHUTDOWN 87 | 88 | def initiate(self): 89 | """run this after changing settings (like rate) before recording""" 90 | if self.device is None: 91 | self.device=self.valid_input_devices()[0] #pick the first one 92 | if self.rate is None: 93 | self.rate=self.valid_low_rate(self.device) 94 | self.chunk = int(self.rate/self.updatesPerSecond) # hold one tenth of a second in memory 95 | if not self.valid_test(self.device,self.rate): 96 | print("guessing a valid microphone device/rate...") 97 | self.device=self.valid_input_devices()[0] #pick the first one 98 | self.rate=self.valid_low_rate(self.device) 99 | self.datax=np.arange(self.chunk)/float(self.rate) 100 | msg='recording from "%s" '%self.info["name"] 101 | msg+='(device %d) '%self.device 102 | msg+='at %d Hz'%self.rate 103 | print(msg) 104 | 105 | def close(self): 106 | """gently detach from things.""" 107 | print(" -- sending stream termination command...") 108 | self.keepRecording=False #the threads should self-close 109 | while(self.t.isAlive()): #wait for all threads to close 110 | time.sleep(.1) 111 | self.stream.stop_stream() 112 | self.p.terminate() 113 | 114 | ### STREAM HANDLING 115 | 116 | def stream_readchunk(self): 117 | """reads some audio and re-launches itself""" 118 | try: 119 | self.data = np.fromstring(self.stream.read(self.chunk),dtype=np.int16) 120 | self.fftx, self.fft = getFFT(self.data,self.rate) 121 | 122 | except Exception as E: 123 | print(" -- exception! terminating...") 124 | print(E,"\n"*5) 125 | self.keepRecording=False 126 | if self.keepRecording: 127 | self.stream_thread_new() 128 | else: 129 | self.stream.close() 130 | self.p.terminate() 131 | print(" -- stream STOPPED") 132 | self.chunksRead+=1 133 | 134 | def stream_thread_new(self): 135 | self.t=threading.Thread(target=self.stream_readchunk) 136 | self.t.start() 137 | 138 | def stream_start(self): 139 | """adds data to self.data until termination signal""" 140 | self.initiate() 141 | print(" -- starting stream") 142 | self.keepRecording=True # set this to False later to terminate stream 143 | self.data=None # will fill up with threaded recording data 144 | self.fft=None 145 | self.dataFiltered=None #same 146 | self.stream=self.p.open(format=pyaudio.paInt16,channels=1, 147 | rate=self.rate,input=True,frames_per_buffer=self.chunk) 148 | self.stream_thread_new() 149 | 150 | if __name__=="__main__": 151 | ear=SWHear(updatesPerSecond=10) # optinoally set sample rate here 152 | ear.stream_start() #goes forever 153 | lastRead=ear.chunksRead 154 | while True: 155 | while lastRead==ear.chunksRead: 156 | time.sleep(.01) 157 | print(ear.chunksRead,len(ear.data)) 158 | lastRead=ear.chunksRead 159 | print("DONE") 160 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2016-07-37_qt_audio_monitor/demo.gif -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/go.py: -------------------------------------------------------------------------------- 1 | from PyQt5 import QtGui,QtCore 2 | 3 | import sys 4 | import ui_main 5 | import numpy as np 6 | import pyqtgraph 7 | import SWHear 8 | 9 | class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow): 10 | def __init__(self, parent=None): 11 | pyqtgraph.setConfigOption('background', 'w') #before loading widget 12 | super(ExampleApp, self).__init__(parent) 13 | self.setupUi(self) 14 | self.grFFT.plotItem.showGrid(True, True, 0.7) 15 | self.grPCM.plotItem.showGrid(True, True, 0.7) 16 | self.maxFFT=0 17 | self.maxPCM=0 18 | self.ear = SWHear.SWHear(rate=44100,updatesPerSecond=20) 19 | self.ear.stream_start() 20 | 21 | def update(self): 22 | if not self.ear.data is None and not self.ear.fft is None: 23 | pcmMax=np.max(np.abs(self.ear.data)) 24 | if pcmMax>self.maxPCM: 25 | self.maxPCM=pcmMax 26 | self.grPCM.plotItem.setRange(yRange=[-pcmMax,pcmMax]) 27 | if np.max(self.ear.fft)>self.maxFFT: 28 | self.maxFFT=np.max(np.abs(self.ear.fft)) 29 | #self.grFFT.plotItem.setRange(yRange=[0,self.maxFFT]) 30 | self.grFFT.plotItem.setRange(yRange=[0,1]) 31 | self.pbLevel.setValue(1000*pcmMax/self.maxPCM) 32 | pen=pyqtgraph.mkPen(color='b') 33 | self.grPCM.plot(self.ear.datax,self.ear.data,pen=pen,clear=True) 34 | pen=pyqtgraph.mkPen(color='r') 35 | self.grFFT.plot(self.ear.fftx,self.ear.fft/self.maxFFT,pen=pen,clear=True) 36 | QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat 37 | 38 | if __name__=="__main__": 39 | app = QtGui.QApplication(sys.argv) 40 | form = ExampleApp() 41 | form.show() 42 | form.update() #start with something 43 | app.exec_() 44 | print("DONE") 45 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/ui_convert.py: -------------------------------------------------------------------------------- 1 | from PyQt5 import uic 2 | import glob 3 | for fname in glob.glob("*.ui"): 4 | print("converting",fname) 5 | fin = open(fname,'r') 6 | fout = open(fname.replace(".ui",".py"),'w') 7 | uic.compileUi(fin,fout,execute=False) 8 | fin.close() 9 | fout.close() 10 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/ui_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_main.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_MainWindow(object): 26 | def setupUi(self, MainWindow): 27 | MainWindow.setObjectName(_fromUtf8("MainWindow")) 28 | MainWindow.resize(993, 692) 29 | self.centralwidget = QtGui.QWidget(MainWindow) 30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 31 | self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) 32 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 33 | self.pbLevel = QtGui.QProgressBar(self.centralwidget) 34 | self.pbLevel.setMaximum(1000) 35 | self.pbLevel.setProperty("value", 123) 36 | self.pbLevel.setTextVisible(False) 37 | self.pbLevel.setOrientation(QtCore.Qt.Vertical) 38 | self.pbLevel.setObjectName(_fromUtf8("pbLevel")) 39 | self.horizontalLayout.addWidget(self.pbLevel) 40 | self.frame = QtGui.QFrame(self.centralwidget) 41 | self.frame.setFrameShape(QtGui.QFrame.NoFrame) 42 | self.frame.setFrameShadow(QtGui.QFrame.Plain) 43 | self.frame.setObjectName(_fromUtf8("frame")) 44 | self.verticalLayout = QtGui.QVBoxLayout(self.frame) 45 | self.verticalLayout.setContentsMargins(0,0,0,0) 46 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 47 | self.label = QtGui.QLabel(self.frame) 48 | self.label.setObjectName(_fromUtf8("label")) 49 | self.verticalLayout.addWidget(self.label) 50 | self.grFFT = PlotWidget(self.frame) 51 | self.grFFT.setObjectName(_fromUtf8("grFFT")) 52 | self.verticalLayout.addWidget(self.grFFT) 53 | self.label_2 = QtGui.QLabel(self.frame) 54 | self.label_2.setObjectName(_fromUtf8("label_2")) 55 | self.verticalLayout.addWidget(self.label_2) 56 | self.grPCM = PlotWidget(self.frame) 57 | self.grPCM.setObjectName(_fromUtf8("grPCM")) 58 | self.verticalLayout.addWidget(self.grPCM) 59 | self.horizontalLayout.addWidget(self.frame) 60 | MainWindow.setCentralWidget(self.centralwidget) 61 | 62 | self.retranslateUi(MainWindow) 63 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 64 | 65 | def retranslateUi(self, MainWindow): 66 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) 67 | self.label.setText(_translate("MainWindow", "frequency data (FFT):", None)) 68 | self.label_2.setText(_translate("MainWindow", "raw data (PCM):", None)) 69 | 70 | from pyqtgraph import PlotWidget 71 | -------------------------------------------------------------------------------- /2016-07-37_qt_audio_monitor/ui_main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 993 10 | 692 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 1000 22 | 23 | 24 | 123 25 | 26 | 27 | false 28 | 29 | 30 | Qt::Vertical 31 | 32 | 33 | 34 | 35 | 36 | 37 | QFrame::NoFrame 38 | 39 | 40 | QFrame::Plain 41 | 42 | 43 | 44 | 0 45 | 46 | 47 | 48 | 49 | frequency data (FFT): 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | raw data (PCM): 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | PlotWidget 75 | QGraphicsView 76 |
pyqtgraph
77 |
78 |
79 | 80 | 81 |
82 | -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2017-06-10_python27_qt4/demo.png -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/readme.md: -------------------------------------------------------------------------------- 1 | # Live MatplotlibWidget with PyQt4 / Python 2.7 2 | The Python 2.7 PyQt4 toolsets are quite complete. WinPython 2.7 comes with QtDesigner and MatplotlibWidget out of the box. This project is a good starting point for a data visualization project for these platforms. 3 | 4 | ## Summary 5 | * in UI designer add a MatplotlibWidget and save as `ui_main.ui` 6 | * run ui2py.py to convert `ui_main.ui` -> `ui_main.py` 7 | * create a file like `run.py` and at the top import the ui with `import ui_main` 8 | * write some code to interact with the UI (look at the source code for details) 9 | * key lines for transparent matplotlib window (with transparent background and transparent frame): 10 | 11 | ``` 12 | self.matplotlibwidget.axes.set_axis_bgcolor('none') # make a transparent graph background 13 | self.matplotlibwidget.figure.set_facecolor('none') # make a transparent frame background 14 | ``` 15 | 16 | ## Output 17 | 18 | ![](demo.png) -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/run.cmd: -------------------------------------------------------------------------------- 1 | "C:\Users\scott\Documents\important\WinPython\WinPython-64bit-2.7.10.3\python-2.7.10.amd64\python.exe" run.py 2 | pause -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/run.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui,QtCore 2 | import sys 3 | import ui_main 4 | import numpy as np 5 | import pylab 6 | import time 7 | 8 | class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow): 9 | def __init__(self, parent=None): 10 | super(ExampleApp, self).__init__(parent) 11 | self.setupUi(self) 12 | #self.btnAdd.clicked.connect(self.update) 13 | self.matplotlibwidget.axes.hold(False) #clear on plot() 14 | self.matplotlibwidget.axes.set_axis_bgcolor('none') # make a transparent graph background 15 | self.matplotlibwidget.figure.set_facecolor('none') # make a transparent frame background 16 | 17 | def update(self): 18 | t1=time.time() 19 | nPoints=100 #number of data points 20 | Xs=np.arange(nPoints)+time.time()*3 # make an X axis 21 | Ys=np.sin(Xs/8) # add some slowly moving data 22 | Xs-=Xs[0] # make X-axis start at 0 23 | self.matplotlibwidget.axes.plot(Xs,Ys,alpha=.5,lw=2) 24 | self.matplotlibwidget.axes.grid() 25 | self.matplotlibwidget.axes.margins(0,0.1) 26 | self.matplotlibwidget.axes.get_figure().tight_layout() # fill space 27 | self.matplotlibwidget.draw() # required to update the window 28 | print("update took %.02f ms"%((time.time()-t1)*1000)) 29 | QtCore.QTimer.singleShot(100, self.update) # QUICKLY repeat 30 | 31 | if __name__=="__main__": 32 | app = QtGui.QApplication(sys.argv) 33 | form = ExampleApp() 34 | form.show() 35 | form.update() #start with something 36 | app.exec_() 37 | print("DONE") -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/ui2py.py: -------------------------------------------------------------------------------- 1 | # run this program to convert .ui files into .py files 2 | from PyQt4 import uic 3 | import glob 4 | for fname in glob.glob("*.ui"): 5 | print("converting",fname) 6 | fin = open(fname,'r') 7 | fout = open(fname.replace(".ui",".py"),'w') 8 | uic.compileUi(fin,fout,execute=False) 9 | fin.close() 10 | fout.close() -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/ui2py.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2017-06-10_python27_qt4/ui2py.pyc -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/ui_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_main.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_MainWindow(object): 26 | def setupUi(self, MainWindow): 27 | MainWindow.setObjectName(_fromUtf8("MainWindow")) 28 | MainWindow.resize(800, 600) 29 | self.centralwidget = QtGui.QWidget(MainWindow) 30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 31 | self.gridLayout = QtGui.QGridLayout(self.centralwidget) 32 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 33 | self.matplotlibwidget = MatplotlibWidget(self.centralwidget) 34 | self.matplotlibwidget.setObjectName(_fromUtf8("matplotlibwidget")) 35 | self.gridLayout.addWidget(self.matplotlibwidget, 0, 0, 1, 1) 36 | MainWindow.setCentralWidget(self.centralwidget) 37 | 38 | self.retranslateUi(MainWindow) 39 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 40 | 41 | def retranslateUi(self, MainWindow): 42 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) 43 | 44 | from matplotlibwidget import MatplotlibWidget 45 | -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/ui_main.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2017-06-10_python27_qt4/ui_main.pyc -------------------------------------------------------------------------------- /2017-06-10_python27_qt4/ui_main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | MatplotlibWidget 27 | QWidget 28 |
matplotlibwidget
29 |
30 |
31 | 32 | 33 |
34 | -------------------------------------------------------------------------------- /2019-02-03_pyQtGraph/pyQtGraph-example.py: -------------------------------------------------------------------------------- 1 | """ 2 | Minimal-case example how to launch a standalone, interactive, pyqtgraph 3 | 4 | First install pyqtgraph with: 5 | pip install --upgrade pyqtgraph 6 | """ 7 | import pyqtgraph as pg 8 | import pyqtgraph.exporters 9 | import numpy as np 10 | 11 | # set the styling of pyqtgraph 12 | pg.setConfigOption('background', 'w') 13 | pg.setConfigOption('foreground', 'k') 14 | 15 | # create some data 16 | pointCount = 1000 17 | xs = np.arange(pointCount)/pointCount*np.pi*2*5 18 | ys = np.sin(xs) 19 | 20 | # add noise 21 | ys += np.random.random_sample(len(ys))/10 22 | 23 | # create plot 24 | plt = pg.plot(xs, ys, title="Example PyQtGraph", pen='r') 25 | plt.showGrid(x=True,y=True) 26 | 27 | ## Start Qt event loop. 28 | if __name__ == '__main__': 29 | import sys 30 | if sys.flags.interactive != 1 or not hasattr(pg.QtCore, 'PYQT_VERSION'): 31 | pg.QtGui.QApplication.exec_() -------------------------------------------------------------------------------- /2019-02-03_pyQtGraph/readme.md: -------------------------------------------------------------------------------- 1 | This project demonstrates how to use the standalone `pyqtgraph` library (http://www.pyqtgraph.org/) with Python 3 to launch an interactive plot with a set of X/Y data. 2 | 3 | Unlike other projects in this repository, this one doesn't require the user to set up a GUI (like a GTK/Glade-centric projects do). This is a great alternative to [matplotlib](https://matplotlib.org/) when the goal is to rapidly display and manipulate high density data. 4 | 5 | ## Installation 6 | ``` 7 | pip install --upgrade pyqtgraph 8 | ``` 9 | 10 | ## Example Code 11 | 12 | ```python 13 | import pyqtgraph as pg 14 | import pyqtgraph.exporters 15 | import numpy as np 16 | 17 | # set the styling of pyqtgraph 18 | pg.setConfigOption('background', 'w') 19 | pg.setConfigOption('foreground', 'k') 20 | 21 | # create some data 22 | pointCount = 1000 23 | xs = np.arange(pointCount)/pointCount*np.pi*2*5 24 | ys = np.sin(xs) 25 | 26 | # add noise 27 | ys += np.random.random_sample(len(ys))/10 28 | 29 | # create plot 30 | plt = pg.plot(xs, ys, title="Example PyQtGraph", pen='r') 31 | plt.showGrid(x=True,y=True) 32 | 33 | ## Start Qt event loop. 34 | if __name__ == '__main__': 35 | import sys 36 | if sys.flags.interactive != 1 or not hasattr(pg.QtCore, 'PYQT_VERSION'): 37 | pg.QtGui.QApplication.exec_() 38 | ``` 39 | 40 | ## Screenshot 41 | ![](screenshot.PNG) -------------------------------------------------------------------------------- /2019-02-03_pyQtGraph/screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swharden/Python-GUI-examples/a6f9e86f890267f96a6011803652741716d2d2d5/2019-02-03_pyQtGraph/screenshot.PNG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Scott W Harden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python-GUI-examples 2 | This repository is a collection of minimal-case examples for performing common GUI-related tasks in python. Emphasis is placed on tasks involving linear data plotting, image processing, and audio/frequency analysis. 3 | 4 | Description | Screenshot 5 | ---|--- 6 | [scrolling live data with PlotWidget](2016-07-31_qt_PyQtGraph_sine_scroll) - extremely high speed graphing designed for realtime updates in GUI applications | 7 | [PyQt4 scrolling live data with MatplotlibWidget](2016-07-30_qt_matplotlib_sine_scroll) - pretty graphs with the MatPlotLib library (which many people already know how to use), but likely too slow for realtime / interactive graphing | 8 | [live PCM and FFT plotting with QtGraph](https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-37_qt_audio_monitor) (based on PlotWidget) | 9 | [quick and simple pyqtgraph example](2019-02-03_pyQtGraph) to launch an interactive chart starting with a set of X/Y data | 10 | ### Useful Links: 11 | * [working with UI files](https://github.com/awesomebytes/python_qt_tutorial/blob/master/README.md#script-the-behaviour) 12 | --------------------------------------------------------------------------------