使用日志功能个性化Matplotlib工具栏

时间:2014-10-17 20:43:03

标签: python matplotlib toolbar

我有一个带工具栏的简单图表。我添加了一个小部件,但无法找到告诉此按钮将主图从正常视图切换到日志视图的方法。我不知道如何从这个按钮事件(pickerToggled(self,checked))访问给出的数据。

这是我到目前为止的代码。

import sys, os, math
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg
from matplotlib.figure import Figure

class NavigationToolbar( NavigationToolbar2QTAgg ):

    picked=pyqtSignal(int,name='picked')

    def __init__(self, canvas, parent ):
        NavigationToolbar2QTAgg.__init__(self,canvas,parent)
        self.clearButtons=[]
        # Search through existing buttons
        # next use for placement of custom button
        next=None
        for c in self.findChildren(QToolButton):
            if next is None:
                next=c
            # Don't want to see subplots and customize
            if str(c.text()) in ('Subplots','Customize'):
                c.defaultAction().setVisible(False)
                continue
            # Need to keep track of pan and zoom buttons
            # Also grab toggled event to clear checked status of picker button
            if str(c.text()) in ('Pan','Zoom'):
                c.toggled.connect(self.clearPicker)
                self.clearButtons.append(c)
                next=None

        # create custom button
        pm=QPixmap(32,32)
        pm.fill(QApplication.palette().color(QPalette.Normal,QPalette.Button))
        painter=QPainter(pm)
        painter.fillRect(6,6,20,20,Qt.red)
        painter.fillRect(15,3,3,26,Qt.blue)
        painter.fillRect(3,15,26,3,Qt.blue)
        painter.end()
        icon=QIcon(pm)
        picker=QAction("Pick",self)
        picker.setIcon(icon)
        picker.setCheckable(True)
        picker.setToolTip("Pick data point")
        self.picker = picker
        button=QToolButton(self)
        button.setDefaultAction(self.picker)

        # Add it to the toolbar, and connect up event
        self.insertWidget(next.defaultAction(),button)
        picker.toggled.connect(self.pickerToggled)

        # Grab the picked event from the canvas
        canvas.mpl_connect('pick_event',self.canvasPicked)

    def clearPicker( self, checked ):
        if checked:
            self.picker.setChecked(False)

    def pickerToggled( self, checked ):
        if checked:
            #### code to add to display plot in logscale


            for c in self.clearButtons:
                c.defaultAction().setChecked(False)
            self.set_message('Reject/use observation')

        else: # linear plot
           #### code to come back to linear scale plot

    def canvasPicked( self, event ):
        if self.picker.isChecked():
            self.picked.emit(event.ind)

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.x=[i*0.1 for i in range(30)]
        self.y=[math.sin(x) for x in self.x]
        self.picked=[]
        self.setWindowTitle('Custom toolbar')

        self.frame = QWidget()

        self.fig = Figure((4.0, 4.0))
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.setParent(self.frame)

        self.axes = self.fig.add_subplot(111)

        # Create the navigation toolbar, tied to the canvas
        # and link the clicked event
        self.toolbar = NavigationToolbar(self.canvas, self.frame)
        self.toolbar.picked.connect(self.addPoint)

        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.toolbar)
        self.frame.setLayout(vbox)
        self.setCentralWidget(self.frame)
        self.draw()

    def draw(self):
        while self.axes.lines:
            self.axes.lines[0].remove()
        self.axes.plot(self.x,self.y,'b+',picker=5)
        xp=[self.x[i] for i in self.picked] 
        yp=[self.y[i] for i in self.picked] 
        self.axes.plot(xp,yp,'rs')
#        self.axes.set_xscale('log')
        self.canvas.draw()

    def addPoint(self,index):
        if index in self.picked:
            self.picked.remove(index)
        else:
            self.picked.append(index)
        self.draw()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = MainWindow()
    form.show()
    app.exec_()

1 个答案:

答案 0 :(得分:0)

这是设计中的一种选择,但这里是我可能做的事情的概要,这可能不一定是最好的,但会起作用。你已经有了一个绘图功能,可以根据某些参数重新绘制你的绘图,所以对于线性/日志,我会在你的MainWindow中添加一个表示日志切换的属性。

在MainWindow

# In the __init__ before the call to self.draw
self.islog = False

# Connect the new signal (defined below)
self.toolbar.picked.connect(self.addPoint)
self.toolbar.logtog.connect(self.logtoggle) # new

然后在self.draw中,我将绘图代码放入处理线性或日志的if语句中。

# In place of your commented line
if self.islog:
    self.axes.set_xscale('log')
else:
    self.axes.set_xscale('linear')

构建切换设置的新方法:

def logtoggle(self, checked):
    self.islog = checked
    self.draw()

在NavigationToolbar中

至于从工具栏中获取信号,您已经发送了一个自定义信号,因此您可以获得它的公式。类似的东西:

picked=pyqtSignal(int,name='picked')
logtog = pyqtSignal(bool) # new signal

然后添加一个自定义按钮就像你做另一个一样,让它像其他按钮一样......

# New button stuff
pm=QPixmap(32,32)
pm.fill(QColor(0,0,255)) # Uniform fill just for demonstration
ic = QIcon(pm)
ac = self.addAction(ic, "Toggle Log") # This will end up on the far right - you can place it wherever you want
ac.setCheckable(True)
ac.toggled.connect(self.logtoggle)

然后当然写下工具栏方法来发出信号:

def logtoggle(self, checked):
    self.logtog.emit(checked)

我将以上所有内容添加到您提供的代码中,并且工作正常。你已经拥有了所有的成分,我刚刚添加了类似的东西。