为Matplotlib工具栏添加日志功能的个性化设置
我有一个简单的图表,上面有一个工具栏。我添加了一个小部件,但不知道怎么让这个按钮切换主图表的显示方式,从正常视图切换到对数视图。我不太清楚如何在这个按钮的事件(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
这其实是一个设计选择的问题,不过我可以给你一个大概的做法,这可能不是最好的方法,但肯定能用。你已经有一个绘图函数,它会根据一些参数重新绘制你的图表,所以对于线性和对数图,我会在你的 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
中,我会把绘图的代码放到一个条件语句里,这样就能处理线性或对数的情况。
# 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)
我把以上所有内容都加到了你提供的代码中,效果很好。你已经有了所有的要素,我只是添加了一些类似的东西。