简体   繁体   中英

Subclassing matplotlib NavigationToolbar throws error with Pan / Zoom

I'm developing a GUI based filter design and analysis tool ( https://github.com/chipmuenk/pyFDA ), subclassing matplotlib NavigationToolbar to implement some changes (added / deleted functions and buttons, new icon set). The full code is available under https://github.com/chipmuenk/pyFDA/ . Each (tabbed) plot_* widget instantiates a copy of the subclassed NavigationToolbar, eg from plot_widgets/plot_phi.py :

from plot_widgets.plot_utils import MplWidget
class PlotPhi(QtGui.QMainWindow):

    def __init__(self, parent = None, DEBUG = False): # default parent = None -> top Window
        super(PlotPhi, self).__init__(parent)
        self.mplwidget = MplWidget()
        self.mplwidget.setFocus()
        self.setCentralWidget(self.mplwidget)

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

In general, this works quite well but ...

  1. ... the functions "pan / zoom" and "zoom rectangle" throw the following error (but zoom and pan nevertheless). Traceback (most recent call last):

     File "D:\\Programme\\WinPython-64bit-3.4.3.1\\python-3.4.3.amd64\\lib\\site- packages\\matplotlib\\backends\\backend_qt5.py", line 666, in zoom self._update_buttons_checked() File "D:\\Programme\\WinPython-64bit-3.4.3.1\\python-3.4.3.amd64\\lib\\site- packages\\matplotlib\\backends\\backend_qt5.py", line 657, in _update_buttons_checked self._actions['pan'].setChecked(self._active == 'PAN') KeyError: 'pan' 

    The mouse modifiers x and y are not working and there is also no visual cue whether the function is selected or not. I must admit, I don't quite understand the interface (QAction?) to the combinated functions pan/zoom - I'm not a well seasoned Pythonista yet.

  2. ...my new function "zoom full view" works but the zoom setting cannot be undone using "previous / next view". This comes as no big surprise as I don't add the view setting to the list (?) of view settings, not knowing where to start :-)

Who could be so kind to give me a little jump start on how to properly apply the Navigation Toolbar?

And (shameless plug :-) ): Anyone caring to contribute to the project? Next steps will be VHDL / Verilog - Export using myHDL ( http://myhdl.org ) and save / load filter functionality

This is a trimmed snippet from plot_widgets/plot_utils.py

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backend_bases import cursors as mplCursors
from matplotlib.figure import Figure

class MyMplToolbar(NavigationToolbar):
    """
    Custom Matplotlib Navigationtoolbar, subclassed from
    NavigationToolbar.

    derived from http://www.python-forum.de/viewtopic.php?f=24&t=26437
    """

    def _init_toolbar(self):
#        self.basedir = os.path.join(rcParams[ 'datapath' ], 'images/icons')
        iconDir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
           '..','images','icons', '')
    # HOME:
    a = self.addAction(QtGui.QIcon(iconDir + 'home.svg'), \
                       'Home', self.home)
    a.setToolTip('Reset original view')
    # BACK:
    a = self.addAction(QtGui.QIcon(iconDir + 'action-undo.svg'), \
                       'Back', self.back)
    a.setToolTip('Back to previous view')

    # PAN:
    a = self.addAction(QtGui.QIcon(iconDir + 'move.svg'), \
                       'Pan', self.pan)
#                           'Pan', self.pan('self.move','self.pan')) # nearly works ...
    a.setToolTip('Pan axes with left mouse button, zoom with right')
    # ZOOM RECTANGLE:
    a = self.addAction(QtGui.QIcon(iconDir + 'magnifying-glass.svg'), \
                       'Zoom', self.zoom)
    a.setToolTip('Zoom in / out to rectangle with left / right mouse button.')
    # Full View:
    a = self.addAction(QtGui.QIcon(iconDir + 'fullscreen-enter.svg'), \
        'Full View', self.parent.pltFullView)
    a.setToolTip('Full view')
    self.buttons = {}

    # reference holder for subplots_adjust window
    self.adj_window = None

Doing some reverse engineering with the original NavigationToolbar showed me some missing bits:

# PAN:
self.a_pa = self.addAction(QtGui.QIcon(iconDir + 'move.svg'), \
                       'Pan', self.pan)
self.a_pa.setToolTip('Pan axes with left mouse button, zoom with right')
self._actions['pan'] = self.a_pa
self.a_pa.setCheckable(True)

self.a_pa.setEnabled(True) # enable / disable function programwise

The above code eliminates the error and gives the visual cue ("setCheckable") to whether Pan is selected or not.

The "full view" can easily be added to the history of view limits by calling

self.myNavigationToolbar.push_current()

before changing the view (eg by autoscale).

The solution to the missing mouse modifiers is equally simple (when you know how, that is ...) as shown in the SO post

matplotlib and Qt: mouse press event.key is always None

The issue is that key press events in general are not processed unless you "activate the focus of qt onto your mpl canvas". The solution is to add two lines to the MplWidget class:

self.canvas.setFocusPolicy( QtCore.Qt.ClickFocus )
self.canvas.setFocus()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM