20

Is it possible to do something like the following to modify the navigation toolbar in matplotlib?

  1. Generate a figure window, with: fig = figure()
  2. Get a reference of the navigation tool-bar, with: tbar = fig.get_navigation_toolbar(), or better yet, just by: tbar = fig.navtbar
  3. Modify the tool-bar through the reference tbar, such as delete/add/edit a button with something like this:
       tbar.add_button(<a Button object>);
       tbar.remove_button(a reference to a button);
       tbar.edit_button(a reference to a button);
  4. Update the figure with: fig.canvas.draw()

Thank you very much.

Littm
  • 4,923
  • 4
  • 30
  • 38
JBT
  • 8,498
  • 18
  • 65
  • 104
  • 1
    Does http://dalelane.co.uk/blog/?p=778 help? – halex Oct 02 '12 at 18:02
  • Well, I saw this solution before. I am looking for something even simpler if it is all possible. I have a feeling that it may not be possible to edit the navigation toolbar object directly, so I may have to settle on the solution you mentioned. Thanks :-) – JBT Oct 02 '12 at 18:12

6 Answers6

28

The way I found to remove unwanted toolbar items is making a subclass, which is instantiated and used in a GTK application. As I manually create Figure, FigureCanvas and NavigationToolbar objects anyway, this was the easiest way.

class NavigationToolbar(NavigationToolbar2GTKAgg):
    # only display the buttons we need
    toolitems = [t for t in NavigationToolbar2GTKAgg.toolitems if
                 t[0] in ('Home', 'Pan', 'Zoom', 'Save')]

If you want to create custom buttons, you should take a look on the definition of NavigationToolbar2 in backend_bases. You can easily add your own entries to the toolitems list and define appropriate callback functions in your toolbar subclass.

torfbolt
  • 1,101
  • 12
  • 8
  • genious solution ! – SAAD May 26 '16 at 14:07
  • 1
    Works for NavigationToolbar2QT too. – Hashimoto Mar 26 '19 at 05:47
  • 4
    You don't need to subclass the toolbar, just use the [`ToolManager`](https://matplotlib.org/3.1.1/api/backend_managers_api.html#matplotlib.backend_managers.ToolManager). [Here is a nice example](https://matplotlib.org/3.1.1/gallery/user_interfaces/toolmanager_sgskip.html). – Trevin Avery Jul 24 '19 at 22:05
8

With MPL 1.2.1 it is possible to get an handler of the navigation toolbar of a standard MPL figure through figure.canvas.toolbar. I'm not sure about previous versions.

At least with the QT backend it is possible to add arbitrary widgets to the navigation toolbar using the QT method .addWidget(). I suppose other backends will work using similar methods, but I haven't tested them.

Here it is a working example (using the QT backend) that adds a QLineEdit() to the navigation toolbar to change the title of a MPL figure (run from IPython (pylab) with run -i ..., then launch test()):

from PySide import QtGui, QtCore

def test():
    plot([1,2,3], lw=2)
    q = qt4_interface(gcf())
    return q   # WARNING: it's paramount to return the object otherwise, with 
               # no references, python deletes it and the GUI doesn't respond!

class qt4_interface:
    def __init__(self,fig):
        self.fig = fig

        toolbar = fig.canvas.toolbar
        self.line_edit = QtGui.QLineEdit()
        toolbar.addWidget(self.line_edit)
        self.line_edit.editingFinished.connect(self.do_something) 

    def do_something(self, *args):
        self.fig.axes[0].set_title(self.line_edit.text())
        self.fig.canvas.draw()
        #f = open('l','a'); f.write('yes\n'); f.flush(); f.close()
user2304916
  • 7,882
  • 5
  • 39
  • 53
2

The previous answers work but are very backend-specific. A slighly more elegant solution is to subclass NavigationToolbar2, as done in this other answer: Matplotlib/Tkinter - customizing toolbar tooltips There the aim was to change the tooltips, but adding or removing a button is equally trivial.

Community
  • 1
  • 1
glep
  • 104
  • 9
1

In addition to torfbotl's solution above, you might have an extra button hanging at the end (the one with the green check mark).

That can be mitigated in the subclass constructor:

from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar

class PanOnlyToolbar(NavigationToolbar):
    # only display the buttons we need
    toolitems = [t for t in NavigationToolbar2GTKAgg.toolitems if
                 t[0] in ("Pan", )]

    def __init__(self, *args, **kwargs):
        super(PanOnlyToolbar, self).__init__(*args, **kwargs)
        self.layout().takeAt(1)  #or more than 1 if you have more buttons
MadeOfAir
  • 2,933
  • 5
  • 31
  • 39
1

Using PyQt5 and matplotlib version '3.0.2'

If you want to add some buttons just follow the doc given by the class NavigationToolbar2() that is initialised in NavigationToolbar2QT() wich is imported from matplotlib.backends.backend_qt5agg :

# list of toolitems to add to the toolbar, format is:
# (
#   text, # the text of the button (often not visible to users)
#   tooltip_text, # the tooltip shown on hover (where possible)
#   image_file, # name of the image for the button (without the extension)
#   name_of_method, # name of the method in NavigationToolbar2 to call
# )

So you need to redefine your class as previously said (you can also see under, the pre-defined buttons available atm). In my case I wanted to remove 2 buttons ('Save' and 'Subplots' that I commented) so that gave me :

class NavigationToolbar2QT(NavigationToolbar2QT):
    # only display the buttons we need
    NavigationToolbar2QT.toolitems = (
        ('Home', 'Reset original view', 'home', 'home'),
        ('Back', 'Back to previous view', 'back', 'back'),
        ('Forward', 'Forward to next view', 'forward', 'forward'),
        (None, None, None, None),
        ('Pan', 'Pan axes with left mouse, zoom with right', 'move', 'pan'),
        ('Zoom', 'Zoom to rectangle', 'zoom_to_rect', 'zoom'),
        # ('Subplots', 'Configure subplots', 'subplots', 'configure_subplots'),
        (None, None, None, None),
        # ('Save', 'Save the figure', 'filesave', 'save_figure'),
    )

And calling the NavigationToolbar2QT (still in my case) :

figure = plt.figure()
canvas = FigureCanvas(figure)
toolbar = NavigationToolbar2QT(canvas, self)
Nqsir
  • 829
  • 11
  • 19
0

I found that just that

fig = plt.figure()
toolbar = fig.canvas.manager.toolbar
tb=toolbar.toolitems
while len(tb)>0:
    tb.pop(0)

worked to remove all tools, and popping individual tools worked too. That said,

toolbar.toolitems=[]

didnt work, so the code must have another reference to this array somewhere.

Donald
  • 1
  • I just tried to pop one of the tools, and it was removed from `toolbar.toolitems`, but the tool still showed up in the figure. – alwaysCurious Feb 24 '21 at 05:55