Use matplotlib to draw dynamic curves in pyqt, and use pyqtmatplotlib

Source: Internet
Author: User

Use matplotlib to draw dynamic curves in pyqt, and use pyqtmatplotlib

I. project background:

After reading the matplotlib for python developers book, I basically learned how to display curves in pyqt, so I wrote one myself.

Ii. Requirement Description:

1) the X axis shows the time point. The length is 1 minute, and a point is drawn every second. If the length of the X axis exceeds 1 minute, the scale is shifted to 1 second to achieve dynamic effect.

2) the Y axis shows a random value, ranging from 1 to 100.

Iii. Preparations

1 environment: python3.3, eric5, pyqt4

4. Start:

Use Eric to create a new project:

 

At the early stage of design coding, Eric's two windows are mainly used: source code and form browser, similar to delphi.

In the Form browser, right-click, new Form, and select Main Window as the Form type, as shown below:

 

The name is MplMainWindow.

 

Put two PushButton on the interface, horizontally layout, and then put a Widget to modify the name, horizontal and vertical policies.

The interface is designed as follows:

 

Finally, execute the grid layout.

To embed Matplotlib into mplCanvas, You need to upgrade mplCanvas, right-click and execute Promote, and enter the class name as MplCanvasWrapper. This class is used to compile matplotlib code. The file name is mplCanvasWrapper.

 

Click Add and then click upgrade.

 

Save the current design form.

This completes the interface design. The qt interface stores xml content and needs to be converted to python code in two ways:

Method 1: Use the built-in functions of Eric: In the form browser, right-click the form ui file and execute the compile form command. The ui_mplmain1_1_py file is generated in the current ui file directory.

Method 2: run the command [original file name of pyuic 4-o destination file] in cmd, as follows:

 

A MplMainWindow. py file is generated in the project folder.

 

Use method 1 in this document. The default file name is ui_mplmain1_1_py.

Open this file and do two things:

1) In the last line, there will be the following sentence: "from mplCodeWrapper import MplCodeWrapper", which is exactly the same as the class name file name entered during the upgrade. Cut this sentence to the top of the file, yes.

2) Change the inheritance of the form from object to QtGui. QMainWindow.

 

Then we will create the file mplCodeWrapper. py

In Eric's source code browser, create a new file, save it as mplCodeWrapper. py, and write two blank codes:

From PyQt4 import QtCore

From PyQt4 import QtGui

From Ui_MplMainWindow import Ui_MainWindow

Class Code_MainWindow (Ui_MainWindow): # modify to inherit from Ui_MainWindow

Def _ init _ (self, parent = None ):

Super (Code_MainWindow, self). _ init _ (parent)

Pass

So far, the entire framework has been set up, and both the interface file and the drawing file have been set up.

 

Add event processing for the form below.

In line with the principle of separation of interface and code, we create a new py file for writing interface code

Create the file code_mplmain1_0000py in the current directory. It is mainly used to bind button events and intermediate logic.

I have mentioned a bunch of things above, but I may not quite understand why I want to change it. Here I will draw a class diagram as follows:

 

The file Ui_MplMainWindow generated by PyQt is a pure interface file, similar to the designer file of C #. The Code_MplMainWindow file is similar to the cs file of C #, and the drawing logic is placed in MplCanvasWrapper, in this way, the interface and implementation are separated.

How can I display and change the time on the X axis?

1) matplotlib provides the plot_date Method for displaying the time on the X axis.

2) Design a thread for generating data and drawing. Based on the single function principle, we need to divide the generated data and drawing into two types for implementation, one for data processing and one for drawing board. The improved class diagram is as follows:

 

Notes:

1) when the form is closed, a close confirmation prompt should be provided, which is implemented by rewriting closeEvent.

2) The thread must have an exit signal.

The complete code is as follows:

1) ui_mplmain1_1_py

#-*-Coding: UTF-8 -*-

 

# Form implementation generated from reading ui file 'mplmainwindow. Ui'

#

# Created: Mon Aug 11 14:18:31 2014

# By: PyQt4 UI code generator 4.10.3

#

# WARNING! All changes made in this file will be lost!

 

From PyQt4 import QtCore, QtGui

From mplCanvasWrapper import MplCanvasWrapper

 

Try:

_ FromUtf8 = QtCore. QString. fromUtf8

T AttributeError:

Def _ fromUtf8 (s ):

Return s

 

Try:

_ Encoding = QtGui. QApplication. UnicodeUTF8

Def _ translate (context, text, disambig ):

Return QtGui. QApplication. translate (context, text, disambig, _ encoding)

T AttributeError:

Def _ translate (context, text, disambig ):

Return QtGui. QApplication. translate (context, text, disambig)

# Inheritent from QtGui. QMainWindow

Class Ui_MainWindow (QtGui. QMainWindow ):

Def setupUi (self, MainWindow ):

MainWindow. setObjectName (_ fromUtf8 ("MainWindow "))

MainWindow. resize (690,427)

Self. centralWidget = QtGui. QWidget (MainWindow)

Self. centralWidget. setObjectName (_ fromUtf8 ("centralWidget "))

Self. gridLayout = QtGui. QGridLayout (self. centralWidget)

Self. gridLayout. setObjectName (_ fromUtf8 ("gridLayout "))

Self. horizontalLayout = QtGui. QHBoxLayout ()

Self. horizontalLayout. setObjectName (_ fromUtf8 ("horizontalLayout "))

Self. btnStart = QtGui. QPushButton (self. centralWidget)

Self. btnStart. setObjectName (_ fromUtf8 ("btnStart "))

Self. horizontalLayout. addWidget (self. btnStart)

Self. btnPause = QtGui. QPushButton (self. centralWidget)

Self. btnPause. setObjectName (_ fromUtf8 ("btnPause "))

Self. horizontalLayout. addWidget (self. btnPause)

SpacerItem = QtGui. QSpacerItem (40, 20, QtGui. QSizePolicy. Expanding, QtGui. QSizePolicy. Minimum)

Self. horizontalLayout. addItem (spacerItem)

Self. gridLayout. addLayout (self. horizontalLayout, 0, 0, 1, 1)

Self. mplCanvas = MplCanvasWrapper (self. centralWidget)

SizePolicy = QtGui. QSizePolicy (QtGui. QSizePolicy. Expanding, QtGui. QSizePolicy. Expanding)

SizePolicy. setHorizontalStretch (0)

SizePolicy. setVerticalStretch (0)

SizePolicy. setHeightForWidth (self. mplCanvas. sizePolicy (). hasHeightForWidth ())

Self. mplCanvas. setSizePolicy (sizePolicy)

Self. mplCanvas. setObjectName (_ fromUtf8 ("mplCanvas "))

Self. gridLayout. addWidget (self. mplCanvas, 1, 0, 1, 1)

MainWindow. setCentralWidget (self. centralWidget)

 

Self. retranslateUi (MainWindow)

QtCore. QMetaObject. connectSlotsByName (MainWindow)

 

Def retranslateUi (self, MainWindow ):

MainWindow. setWindowTitle (_ translate ("MainWindow", "MainWindow", None ))

Self. btnStart. setText (_ translate ("MainWindow", "Start", None ))

Self. btnPause. setText (_ translate ("MainWindow", "Suspend", None ))

2) code_mplmain1_1_py

From PyQt4 import QtGui, QtCore

From Ui_MplMainWindow import Ui_MainWindow

Class Code_MainWindow (Ui_MainWindow ):

Def _ init _ (self, parent = None ):

Super (Code_MainWindow, self). _ init _ (parent)

Self. setupUi (self)

Self. btnStart. clicked. connect (self. startPlot)

Self. btnPause. clicked. connect (self. pausePlot)

Def startPlot (self ):

'''Beginto plot '''

Self. mplCanvas. startPlot ()

Pass

Def pausePlot (self ):

'''Pause plot '''

Self. mplCanvas. pausePlot ()

Pass

Def releasePlot (self ):

'''Stop and release thread '''

Self. mplCanvas. releasePlot ()

 

Def closeEvent (self, event ):

Result = QtGui. QMessageBox. question (self,

"Confirm Exit ...",

"Are you sure you want to exit? ",

QtGui. QMessageBox. Yes | QtGui. QMessageBox. No)

Event. ignore ()

 

If result = QtGui. QMessageBox. Yes:

Self. releasePlot () # release thread's resouce

Event. accept ()

 

If _ name _ = "_ main __":

Import sys

App = QtGui. QApplication (sys. argv)

Ui = Code_MainWindow ()

Ui. show ()

Sys.exit(app.exe c _())

 

3) mplCanvasWrapper. py

From PyQt4 import QtGui

From matplotlib. backends. backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

From matplotlib. backends. backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar

From matplotlib. figure import Figure

Import numpy as np

From array import array

Import time

Import random

Import threading

From datetime import datetime

From matplotlib. dates import date2num, MinuteLocator, SecondLocator, DateFormatter

 

X_MINUTES = 1

Y_MAX = 100.

Y_MIN = 1

INTERVAL = 1

MAXCOUNTER = int (X_MINUTES * 60/INTERVAL)

Class MplCanvas (FigureCanvas ):

Def _ init _ (self ):

Self. fig = Figure ()

Self. ax = self. fig. add_subplot (111)

FigureCanvas. _ init _ (self, self. fig)

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

FigureCanvas. updateGeometry (self)

Self. ax. set_xlabel ("time of data generator ")

Self. ax. set_ylabel ('random data value ')

Self. ax. legend ()

Self. ax. set_ylim (Y_MIN, Y_MAX)

Self. ax. xaxis. set_major_locator (MinuteLocator () # every minute is a major locator

Self. ax. xaxis. set_minor_locator (SecondLocator ([10, 20, 30, 40]) # every 10 second is a minor locator

Self. ax. xaxis. set_major_formatter (DateFormatter ('% H: % M: % s') # tick label formatter

Self. curveObj = None # draw object

Def plot (self, datax, datay ):

If self. curveObj is None:

# Create draw object once

Self. curveObj, = self. ax. plot_date (np. array (datax), np. array (datay), 'bo -')

Else:

# Update data of draw object

Self. curveObj. set_data (np. array (datax), np. array (datay ))

# Update limit of X axis, to make sure it can move

Self. ax. set_xlim (datax [0], datax [-1])

Ticklabels = self. ax. xaxis. get_ticklabels ()

For tick in ticklabels:

Tick. set_rotation (25)

Self. draw ()

Class MplCanvasWrapper (QtGui. QWidget ):

Def _ init _ (self, parent = None ):

QtGui. QWidget. _ init _ (self, parent)

Self. canvas = MplCanvas ()

Self. vbl = QtGui. QVBoxLayout ()

Self. ntb = NavigationToolbar (self. canvas, parent)

Self. vbl. addWidget (self. ntb)

Self. vbl. addWidget (self. canvas)

Self. setLayout (self. vbl)

Self. dataX = []

Self. dataY = []

Self. initDataGenerator ()

Def startPlot (self ):

Self. _ generating = True

Def pausePlot (self ):

Self. _ generating = False

Pass

Def initDataGenerator (self ):

Self. _ generating = False

Self. _ exit = False

Self. tData = threading. Thread (name = "dataGenerator", target = self. generateData)

Self. tData. start ()

Def releasePlot (self ):

Self. _ exit = True

Self. tData. join ()

Def generateData (self ):

Counter = 0

While (True ):

If self. _ exit:

Break

If self. _ generating:

NewData = random. randint (Y_MIN, Y_MAX)

NewTime = date2num (datetime. now ())

Self. dataX. append (newTime)

Self. dataY. append (newData)

Self. canvas. plot (self. dataX, self. dataY)

If counter> = MAXCOUNTER:

Self. dataX. pop (0)

Self. dataY. pop (0)

Else:

Counter + = 1

Time. sleep (INTERVAL)

 

:

 

Summary:

Through this program, I am familiar with the following points:

1) Eric and QtDesigner are used, and the interface and logic are separated.

2) rewrite a form event

3) bind signals and slots

4) use threads

5) Use of object-oriented matplotlib

 


How to dynamically display the interval between a column and a column as needed when using matplotlib in python to draw a Histogram

Static or dynamic,
It must be triggered at a specific time,
Or write it in the program, click or ..

Either accept the keyboard input or pass a parameter.
Hope to help you!
 
How to Use the matplotlib module of python to draw a cumulative distribution chart

The following program draws the cumulative distribution function of random variable X and the cumulative result of array p.
>>> Pl. plot (t, X. cdf (t ))
>>> Pl. plot (t2, np. add. accumulate (p) * (t2 [1]-t2 [0])
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.