Connect Qslider and MatplotlibWidget

2019-07-24 16:47发布

I am a real beginner in python and try to connect a qslider to a matplotlibwidget. That means if I change the value of the slider the graph should change. It seems that the value changes correctly, while the graph stays the same. Can anyone tell me how to connect the change of the slider with the graph? Here is my algorithm so far:

# -*- coding: utf-8 -*-
"""
Created on Tue Feb 04 16:48:12 2014

@author: Christoph
"""

from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as Canvas
from matplotlib.figure import Figure
from matplotlib import rcParams

import numpy as np
import scipy.constants as const
import sys

rcParams['font.size'] = 9


class MatplotlibWidget(Canvas):
    """
    MatplotlibWidget inherits PyQt4.QtGui.QWidget
    and matplotlib.backend_bases.FigureCanvasBase

    Options: option_name (default_value)
    -------    
    parent (None): parent widget
    title (''): figure title
    xlabel (''): X-axis label
    ylabel (''): Y-axis label
    xlim (None): X-axis limits ([min, max])
    ylim (None): Y-axis limits ([min, max])
    xscale ('linear'): X-axis scale
    yscale ('linear'): Y-axis scale
    width (4): width in inches
    height (3): height in inches
    dpi (100): resolution in dpi
    hold (False): if False, figure will be cleared each time plot is called

    Widget attributes:
    -----------------
    figure: instance of matplotlib.figure.Figure
    axes: figure axes

    Example:
    -------
    self.widget = MatplotlibWidget(self, yscale='log', hold=True)
    from numpy import linspace
    x = linspace(-10, 10)
    self.widget.axes.plot(x, x**2)
    self.wdiget.axes.plot(x, x**3)
    """
    def __init__(self, parent=None, title='', xlabel='', ylabel='',
                 xlim=None, ylim=None, xscale='linear', yscale='linear',
                 width=4, height=3, dpi=100, hold=False):
        self.figure = Figure(figsize=(width, height), dpi=dpi)
        self.axes = self.figure.add_subplot(111)
        self.axes.set_title(title)
        self.axes.set_xlabel(xlabel)
        self.axes.set_ylabel(ylabel)
        if xscale is not None:
            self.axes.set_xscale(xscale)
        if yscale is not None:
            self.axes.set_yscale(yscale)
        if xlim is not None:
            self.axes.set_xlim(*xlim)
        if ylim is not None:
            self.axes.set_ylim(*ylim)
        self.axes.hold(hold)

        Canvas.__init__(self, self.figure)
        self.setParent(parent)

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

    def sizeHint(self):
        w, h = self.get_width_height()
        return QtGui.QSize(w, h)

    def minimumSizeHint(self):
        return QtGui.QSize(10, 10)

class ApplicationWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        # Graphics Window
        self.mpl = MatplotlibWidget(self, title='Graph',
                                          xlabel='x',
                                          ylabel='y',
                                          hold=True)
        self.mpl.setGeometry(0,0,1300,800)
        self.setGeometry(0, 30, 1680, 800)

        # Slider Resistance
        title1=QtGui.QLabel(self)
        title1.setText('R')
        title1.move(1400,10)

        self.value1=QtGui.QLabel(self)
        self.value1.setText('1')
        self.value1.move(1550,40)

        cb=QtGui.QSlider(QtCore.Qt.Horizontal, self)
        cb.setGeometry(1400,40,100,30)
        cb.setMinimum(1)
        cb.setMaximum(10000)
        cb.valueChanged.connect(self.Rout)


        self.plot(1, self.mpl.axes)


    def Rout(self, position):
        self.value1.setText('%i' %position)
        self.plot(position, self.mpl.axes)

    def plot(self, R, axes):
        x=np.linspace(0,5,1001)

        B=0.035
        n1=0.115
        H=2.06227451e-15
        n2=1.37040209e-01
        gamma=0.001*const.e
        C=0.13
        x=np.array(x)
        diodetheo = H*(np.exp((const.e*x*n2)/(const.k*300))-1)

        zaehler = 1+np.exp((B-C+n1*x)*const.e/(const.k*300))
        nenner =  1+np.exp((B-C-n1*x)*const.e/(const.k*300))
        A=8.7476434*10**(29)*gamma
        D=gamma/2
        klammer2 = (const.pi/2)+np.arctan((C-n1*x)/D)
        y1 = A*np.log(zaehler/nenner)*klammer2    
       # plt.figure()
       # plt.plot(x, diodetheo, 'g')
       # plt.show() 
        indup=[]
        inddown=[]
        iup=[]
        idown=[]
        theo = (y1+diodetheo)*(10**(-12))*(100)/4
        for i, Volt in enumerate(x):
            xup=np.linspace(0,Volt,i+1) 
            last=Volt/R-xup/R
            diff=np.array(last)-np.array(theo[0:i+1])
            inter=np.where(np.diff(np.sign(diff)))[0]
            if inter.size==0:
                inter=np.array([0])

            indup.append(inter[0])
            inddown.append(inter[-1])
            iup.append(theo[inter[0]])
            idown.append(theo[inter[-1]])


        up = np.array(iup)
        down = np.array(idown)
        down=np.flipud(down)
        ytotal=np.concatenate((up, down))
        xneg=np.flipud(x)
        xtotal=np.concatenate((x,xneg)) 

        #plt.figure()
        #plt.plot(xtotal, ytotal, 'g')
        #plt.show() 

        axes.plot(xtotal, ytotal, 'r')



if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    win = ApplicationWindow()
    win.show()
    sys.exit(app.exec_())

Greetings Christoph

1条回答
萌系小妹纸
2楼-- · 2019-07-24 16:53

OK I've made some changes to your code in order to make it works:

  1. Change the function definition def plot(self, R, axes): for def plot(self, R):
  2. Change the call self.plot(position, self.mpl.axes) on Rout accordingly to self.plot(position)
  3. Change the final line axes.plot(xtotal, ytotal, 'r') on the previous plot function by:

    self.mpl.axes.clear() #clear the previous plot
    self.mpl.axes.plot(xtotal, ytotal, 'r') #replot
    self.mpl.figure.canvas.draw() #redraw the canvas
    

Explanations: First, you don't need to pass the axes to the plot function if it's already an attribute of self.mpl and is easy accessible. Second, when you make another plot you need to clear the previous one and also refresh the canvas.

Next all the code with modifications for easy use of copy-paste:

from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as Canvas
from matplotlib.figure import Figure
from matplotlib import rcParams

import numpy as np
import scipy.constants as const
import sys

rcParams['font.size'] = 9


class MatplotlibWidget(Canvas):
    """
    MatplotlibWidget inherits PyQt4.QtGui.QWidget
    and matplotlib.backend_bases.FigureCanvasBase

    Options: option_name (default_value)
    -------    
    parent (None): parent widget
    title (''): figure title
    xlabel (''): X-axis label
    ylabel (''): Y-axis label
    xlim (None): X-axis limits ([min, max])
    ylim (None): Y-axis limits ([min, max])
    xscale ('linear'): X-axis scale
    yscale ('linear'): Y-axis scale
    width (4): width in inches
    height (3): height in inches
    dpi (100): resolution in dpi
    hold (False): if False, figure will be cleared each time plot is called

    Widget attributes:
    -----------------
    figure: instance of matplotlib.figure.Figure
    axes: figure axes

    Example:
    -------
    self.widget = MatplotlibWidget(self, yscale='log', hold=True)
    from numpy import linspace
    x = linspace(-10, 10)
    self.widget.axes.plot(x, x**2)
    self.wdiget.axes.plot(x, x**3)
    """
    def __init__(self, parent=None, title='', xlabel='', ylabel='',
                 xlim=None, ylim=None, xscale='linear', yscale='linear',
                 width=4, height=3, dpi=100, hold=False):
        self.figure = Figure(figsize=(width, height), dpi=dpi)
        self.axes = self.figure.add_subplot(111)
        self.axes.set_title(title)
        self.axes.set_xlabel(xlabel)
        self.axes.set_ylabel(ylabel)
        if xscale is not None:
            self.axes.set_xscale(xscale)
        if yscale is not None:
            self.axes.set_yscale(yscale)
        if xlim is not None:
            self.axes.set_xlim(*xlim)
        if ylim is not None:
            self.axes.set_ylim(*ylim)
        self.axes.hold(hold)

        Canvas.__init__(self, self.figure)
        self.setParent(parent)

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

    def sizeHint(self):
        w, h = self.get_width_height()
        return QtGui.QSize(w, h)

    def minimumSizeHint(self):
        return QtGui.QSize(10, 10)

class ApplicationWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        # Graphics Window
        self.mpl = MatplotlibWidget(self, title='Graph',
                                          xlabel='x',
                                          ylabel='y',
                                          hold=True)
        self.mpl.setGeometry(0,0,1300,800)
        self.setGeometry(0, 30, 1680, 800)

        # Slider Resistance
        title1=QtGui.QLabel(self)
        title1.setText('R')
        title1.move(1400,10)

        self.value1=QtGui.QLabel(self)
        self.value1.setText('1')
        self.value1.move(1550,40)

        cb=QtGui.QSlider(QtCore.Qt.Horizontal, self)
        cb.setGeometry(1400,40,100,30)
        cb.setMinimum(1)
        cb.setMaximum(10000)
        cb.valueChanged.connect(self.Rout)


        self.plot(1)


    def Rout(self, position):
        self.value1.setText('%i' %position)
        self.plot(position)

    def plot(self, R):
        x=np.linspace(0,5,1001)

        B=0.035
        n1=0.115
        H=2.06227451e-15
        n2=1.37040209e-01
        gamma=0.001*const.e
        C=0.13
        x=np.array(x)
        diodetheo = H*(np.exp((const.e*x*n2)/(const.k*300))-1)

        zaehler = 1+np.exp((B-C+n1*x)*const.e/(const.k*300))
        nenner =  1+np.exp((B-C-n1*x)*const.e/(const.k*300))
        A=8.7476434*10**(29)*gamma
        D=gamma/2
        klammer2 = (const.pi/2)+np.arctan((C-n1*x)/D)
        y1 = A*np.log(zaehler/nenner)*klammer2    
       # plt.figure()
       # plt.plot(x, diodetheo, 'g')
       # plt.show() 
        indup=[]
        inddown=[]
        iup=[]
        idown=[]
        theo = (y1+diodetheo)*(10**(-12))*(100)/4
        for i, Volt in enumerate(x):
            xup=np.linspace(0,Volt,i+1) 
            last=Volt/R-xup/R
            diff=np.array(last)-np.array(theo[0:i+1])
            inter=np.where(np.diff(np.sign(diff)))[0]
            if inter.size==0:
                inter=np.array([0])

            indup.append(inter[0])
            inddown.append(inter[-1])
            iup.append(theo[inter[0]])
            idown.append(theo[inter[-1]])


        up = np.array(iup)
        down = np.array(idown)
        down=np.flipud(down)
        ytotal=np.concatenate((up, down))
        xneg=np.flipud(x)
        xtotal=np.concatenate((x,xneg)) 

        #plt.figure()
        #plt.plot(xtotal, ytotal, 'g')
        #plt.show() 

        self.mpl.axes.clear()
        self.mpl.axes.plot(xtotal, ytotal, 'r')
        self.mpl.figure.canvas.draw()



if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    win = ApplicationWindow()
    win.show()
    sys.exit(app.exec_())
查看更多
登录 后发表回答