0

I'm embedding a matplotlib figure in PyQt4 UI. Something like

Building a matplotlib GUI with Qt Designer.

FigureCanvasQTAgg and NavigationToolbar2QT are added in QVBoxlayout and right side of UI is a QListWidget of figure names.

None of the toolbar shortcuts are working. I tried changing focus of the both QVBoxlayout and QListWidget Widget.

Figure is generated as

from matplotlib.figure import Figure
fig=figure()
ax=fig.add_subplot(111)
ax.plot.plot(np.random.rand(5))

This figure is passed to addmpl method where canvas and toolbar are generated and added to the mainwindow widget.

def addmpl(self,fig):
    self.canvas = FigureCanvas(fig)
    self.mplvl.addWidget(self.canvas)
    self.canvas.draw()
    self.toolbar = NavigationToolbar(self.canvas,self.mplwindow)
    self.mplvl.addWidget(self.toolbar)

Workaround...

def menu(self):
    self.savefig=QtGui.QAction('&Save', self) 
    self.savefig.setShortcut('Ctrl+S')
    self.savefig.triggered.connect(self.save_figure)

    undo=QtGui.QAction('&Undo', self)
    undo.setShortcut('Ctrl+Z')
    undo.triggered.connect(self.back)

    redo=QtGui.QAction('&Redo', self)
    redo.setShortcut('Ctrl+Y')
    redo.triggered.connect(self.forward)

    figoptions=QtGui.QAction('&Figure Options', self)
    figoptions.setShortcut('Ctrl+F')
    figoptions.setStatusTip('Edit curves lines and axes parameters')
    figoptions.triggered.connect(self.edit_parameters)



def back(self):
    self.toolbar.back()
def forward(self):
    self.toolbar.forward()
def save_figure(self):
    self.toolbar.save_figure()
def edit_parameters(self):
    self.toolbar.edit_parameters()

But the shortcuts like Constrain pan/zoom to x axis - hold x when panning/zooming with mouse looks difficult and tedious to implement.

Solution of this Question has the same problem.(Replaced NavigationToolbar2QTAgg with NavigationToolbar2QT)

Community
  • 1
  • 1
inxp
  • 219
  • 3
  • 17
  • Are the slots called? Ie if you put print statements in back() forward() etc do you get anything in console from which GUI started? If not then the issue is likely related to how toolbar is integrated rather that the actual qactions, in that case you need to post related code. – Oliver Dec 28 '16 at 22:23
  • I have put 'print("Hello")' in pan method of backend_bases.py. On pressing p (shortcut for pan) console remains empty. But if I click pan button in toolbar, console prints Hello. – inxp Dec 29 '16 at 08:45
  • Example code is available [here](http://blog.rcnelson.com/wp-content/uploads/2015/02/mpldesigner.zip) – inxp Dec 29 '16 at 08:49
  • So you mean it's the keyboard shortcuts of the toolbar buttons that don't work, but the button actions actually work (if you click on them)? – Oliver Dec 29 '16 at 12:55
  • Yes... Only Keyboard shortcuts don't work... – inxp Dec 29 '16 at 14:16

2 Answers2

3

Without seeing the portion of your code where you intialize the figure, and after looking at the PyQt example, I'm taking a wild guess that you haven't configure keyboard shortcuts:

  1. Ensure you have from matplotlib.backend_bases import key_press_handler
  2. Bind the matplotlib figure canvas's keypresses to a handler:

    self.fig = Figure(...)
    self.canvas = FigureCanvas(self.fig)
    self.mpl_nav_toolbar = NavigationToolbar(...)
    ...
    self.canvas.mpl_connect('key_press_event', self.on_key_press)
    
  3. Configure the canvas widget to process keyboard events:

    ...
    self.canvas.setFocusPolicy(Qt.StrongFocus)
    
  4. Define your handler to call key_press_handler:

    def on_key_press(self, event):
        key_press_handler(event, self.canvas, self.mpl_nav_toolbar)
    

These steps should work for PyQt5 as well, BTW.

Oliver
  • 27,510
  • 9
  • 72
  • 103
  • Maybe this is mistake about focus....because when i click 'T' button the selection in figure list changes to 'Two Plot'.... – inxp Dec 29 '16 at 14:50
  • Tried this...but it didn't work....updated code is available [here](http://pasted.co/f1a4561e)....UI file is available [here](http://pasted.co/01627c4c)..... – inxp Dec 29 '16 at 14:54
  • 1
    Adding self.canvas.setFocusPolicy(Qt.StrongFocus) and self.canvas.setFocus() solved the problem.... Thanks for pointing me in the right direction..... – inxp Dec 29 '16 at 15:01
  • 1
    Ah thx forgot about the focus policy, which defaults to none, so I updated answer. However, I doubt the setFocus() is required: with StrongFocus, you should be able to just tab to or click on the canvas or toolbar to have canvas get focus. Let me know if there is more I can improve to the answer for upvote. – Oliver Dec 29 '16 at 15:07
0

This is an alternative solution which is PyQt specific (tested with PyQt5). It is not as concise as mpl_connect('key_press_event'...) but allows for more flexibility such as redefining the shortcut keys.

NavigationToolbar2QT inherits from QToolBar which in turn inherits from QWidget. All the actions on the toolbar are therefore available through QWidget.actions().

For example, a global shortcut can be defined and connected to zoom on toolbar:

class Main(QMainWindow, Ui_MainWindow):
    def __init__(self, ):
        ...        
        self.shortcut = QShortcut(QKeySequence(Qt.Key_Z), self)
        ....

    def addmpl(self, fig):
        ...
        for action in self.toolbar.actions():
            if action.text() == 'Zoom':
                self.shortcut.activated.connect(action.trigger)
bzu
  • 1,242
  • 1
  • 8
  • 14