2011-04-24 100 views
3

任何人都可以暗示爲什麼下面的代碼(取自here)segfaults退出?Segfault使用matplotlib與PyQt

""" 
This demo demonstrates how to embed a matplotlib (mpl) plot 
into a PyQt4 GUI application, including: 

* Using the navigation toolbar 
* Adding data to the plot 
* Dynamically modifying the plot's properties 
* Processing mpl events 
* Saving the plot to a file from a menu 

The main goal is to serve as a basis for developing rich PyQt GUI 
applications featuring mpl plots (using the mpl OO API). 

Eli Bendersky ([email protected]) 
License: this code is in the public domain 
Last modified: 19.01.2009 
""" 
import sys, os, random 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 

import matplotlib 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar 
from matplotlib.figure import Figure 


class AppForm(QMainWindow): 
    def __init__(self, parent=None): 
     QMainWindow.__init__(self, parent) 
     self.setWindowTitle('Demo: PyQt with matplotlib') 

     self.create_menu() 
     self.create_main_frame() 
     self.create_status_bar() 

     self.textbox.setText('1 2 3 4') 
     self.on_draw() 

    def save_plot(self): 
     file_choices = "PNG (*.png)|*.png" 

     path = unicode(QFileDialog.getSaveFileName(self, 
         'Save file', '', 
         file_choices)) 
     if path: 
      self.canvas.print_figure(path, dpi=self.dpi) 
      self.statusBar().showMessage('Saved to %s' % path, 2000) 

    def on_about(self): 
     msg = """ A demo of using PyQt with matplotlib: 

     * Use the matplotlib navigation bar 
     * Add values to the text box and press Enter (or click "Draw") 
     * Show or hide the grid 
     * Drag the slider to modify the width of the bars 
     * Save the plot to a file using the File menu 
     * Click on a bar to receive an informative message 
     """ 
     QMessageBox.about(self, "About the demo", msg.strip()) 

    def on_pick(self, event): 
     # The event received here is of the type 
     # matplotlib.backend_bases.PickEvent 
     # 
     # It carries lots of information, of which we're using 
     # only a small amount here. 
     # 
     box_points = event.artist.get_bbox().get_points() 
     msg = "You've clicked on a bar with coords:\n %s" % box_points 

     QMessageBox.information(self, "Click!", msg) 

    def on_draw(self): 
     """ Redraws the figure 
     """ 
     str = unicode(self.textbox.text()) 
     self.data = map(int, str.split()) 

     x = range(len(self.data)) 

     # clear the axes and redraw the plot anew 
     # 
     self.axes.clear()   
     self.axes.grid(self.grid_cb.isChecked()) 

     self.axes.bar(
      left=x, 
      height=self.data, 
      width=self.slider.value()/100.0, 
      align='center', 
      alpha=0.44, 
      picker=5) 

     self.canvas.draw() 

    def create_main_frame(self): 
     self.main_frame = QWidget() 

     # Create the mpl Figure and FigCanvas objects. 
     # 5x4 inches, 100 dots-per-inch 
     # 
     self.dpi = 100 
     self.fig = Figure((5.0, 4.0), dpi=self.dpi) 
     self.canvas = FigureCanvas(self.fig) 
     self.canvas.setParent(self.main_frame) 

     # Since we have only one plot, we can use add_axes 
     # instead of add_subplot, but then the subplot 
     # configuration tool in the navigation toolbar wouldn't 
     # work. 
     # 
     self.axes = self.fig.add_subplot(111) 

     # Bind the 'pick' event for clicking on one of the bars 
     # 
     self.canvas.mpl_connect('pick_event', self.on_pick) 

     # Create the navigation toolbar, tied to the canvas 
     # 
     self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame) 

     # Other GUI controls 
     # 
     self.textbox = QLineEdit() 
     self.textbox.setMinimumWidth(200) 
     self.connect(self.textbox, SIGNAL('editingFinished()'), self.on_draw) 

     self.draw_button = QPushButton("&Draw") 
     self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw) 

     self.grid_cb = QCheckBox("Show &Grid") 
     self.grid_cb.setChecked(False) 
     self.connect(self.grid_cb, SIGNAL('stateChanged(int)'), self.on_draw) 

     slider_label = QLabel('Bar width (%):') 
     self.slider = QSlider(Qt.Horizontal) 
     self.slider.setRange(1, 100) 
     self.slider.setValue(20) 
     self.slider.setTracking(True) 
     self.slider.setTickPosition(QSlider.TicksBothSides) 
     self.connect(self.slider, SIGNAL('valueChanged(int)'), self.on_draw) 

     # 
     # Layout with box sizers 
     # 
     hbox = QHBoxLayout() 

     for w in [ self.textbox, self.draw_button, self.grid_cb, 
        slider_label, self.slider]: 
      hbox.addWidget(w) 
      hbox.setAlignment(w, Qt.AlignVCenter) 

     vbox = QVBoxLayout() 
     vbox.addWidget(self.canvas) 
     vbox.addWidget(self.mpl_toolbar) 
     vbox.addLayout(hbox) 

     self.main_frame.setLayout(vbox) 
     self.setCentralWidget(self.main_frame) 

    def create_status_bar(self): 
     self.status_text = QLabel("This is a demo") 
     self.statusBar().addWidget(self.status_text, 1) 

    def create_menu(self):   
     self.file_menu = self.menuBar().addMenu("&File") 

     load_file_action = self.create_action("&Save plot", 
      shortcut="Ctrl+S", slot=self.save_plot, 
      tip="Save the plot") 
     quit_action = self.create_action("&Quit", slot=self.close, 
      shortcut="Ctrl+Q", tip="Close the application") 

     self.add_actions(self.file_menu, 
      (load_file_action, None, quit_action)) 

     self.help_menu = self.menuBar().addMenu("&Help") 
     about_action = self.create_action("&About", 
      shortcut='F1', slot=self.on_about, 
      tip='About the demo') 

     self.add_actions(self.help_menu, (about_action,)) 

    def add_actions(self, target, actions): 
     for action in actions: 
      if action is None: 
       target.addSeparator() 
      else: 
       target.addAction(action) 

    def create_action( self, text, slot=None, shortcut=None, 
         icon=None, tip=None, checkable=False, 
         signal="triggered()"): 
     action = QAction(text, self) 
     if icon is not None: 
      action.setIcon(QIcon(":/%s.png" % icon)) 
     if shortcut is not None: 
      action.setShortcut(shortcut) 
     if tip is not None: 
      action.setToolTip(tip) 
      action.setStatusTip(tip) 
     if slot is not None: 
      self.connect(action, SIGNAL(signal), slot) 
     if checkable: 
      action.setCheckable(True) 
     return action 


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

除了關於退出的段錯誤,否則它工作正常。

版本信息:

[email protected]:~/co/python/resampling$ python 
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import matplotlib 
>>> matplotlib.__version__ 
'0.99.1.1' 
[email protected]:~/co/python/resampling$ qmake-qt4 -v 
QMake version 2.01a 
Using Qt version 4.6.2 in /usr/lib 
[email protected]:~/co/python/resampling$ pyuic4 --version 
Python User Interface Compiler 4.7.2 for Qt version 4.6.2 
+0

misha,這個示例對我來說一直工作正常,而且我沒有得到類似問題的用戶報告。你能找出段錯誤來自哪裏,例如Python,matplotlib的DLL或PyQt的DLL嗎? – 2011-04-24 12:37:49

+0

@Eli我試着通過'gdb'運行它,但奇怪的是,它正常退出。如果我在調試環境之外運行它,我會在退出(始終)時收到段錯誤。有任何想法嗎?另外,謝謝你提供樣品,它爲我節省了很多時間。 – misha 2011-04-26 03:14:31

+0

嘗試使用'gdb'檢查覈心轉儲 - 即使沒有運行它,也可以這樣做。然後,我會爲相關項目打開一個錯誤,因爲它必須是一個*錯誤。 - 由於運行純Python代碼,Python實現或庫不會有段錯誤 – 2011-04-26 03:58:53

回答

1

的QApplication對象是被垃圾出口在表格前收集。對您的代碼進行以下更改:

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

並且段錯誤消失。它出現在PyQt或matplotlib中,取決於QApplication對象在退出時釋放資源時仍然存在。

+0

不錯的嘗試,但它仍然seg段在我身邊。我更新了我的答案的源代碼。不過謝謝你的想法。 – misha 2011-11-29 10:43:47

+0

這真的很奇怪。我擁有與您完全相同的環境,並且在我進行此更改時,它會停止對我進行部門管理。 – 2011-11-29 12:17:44

+0

好吧,如果您按照我的指示完全改變*,段錯誤會消失。但是,如果您按照您的要求進行更改(這應該是等同的),那麼segfault仍然存在。去搞清楚。 – 2011-11-29 12:58:24