Tabbed window for matplotlib figures, is it possible?
Asked Answered
F

6

12

I have a python project that outputs several Matplotlib figures; each figure contains several charts. The problem that project launches about 15 figures (windows) every run, which I can not reduce.

Is it possible to concatenate all these figures (windows) to a single tabbed window so that each tab represents one figure?

Any help is much appreciated.

Thanks in advance


Workaround

Thanks to @mobiusklein comments below he suggested a workaround, to export the figures as myltipage pdf file as shown here.

Important note about the multipage pdf example mentioned above.

I tried it, but I got an error regarding the LaTeX use in matplotlib. Because fixing this error is beyond the scope of this question, so I suggest if it occurs to anyone, to set plt.rc('text', usetex=False) instead of usetex=True

I still hope if someone have other solution or workaround to post it for the benefit of others.

Fevre answered 20/5, 2016 at 12:32 Comment(5)
Are you talking about the GUI rendering backends that matplotlib provides, or does your project have its own GUI?Fructuous
Thank you for you comment. I am using pyCharm with its standard interface. I use no GUI in this project till now, do you suggest an easy one?Fevre
Based on some quick googling, it looks like PyCharm assumes you're using the Tk backend for matplotlib by default. I'll write an answer accordingly.Fructuous
Tk GUI supports only hard-coding, which I do not prefer (as a VB.net programmer). Do you advise me a simpler GUI for Python and pyCharm.Fevre
It depends upon whether you want a convenient display system for your plots for yourself, a GUI in some way associated with PyCharm, or a way to export your figures in a convenient format.Fructuous
F
3

The backend you choose to use for matplotlib controls how each figure is displayed. Some backends just render figures to file, while others like the tk, qt, or gtk backends render figures in graphical windows. Those backends determine what functionality those GUI windows have.

The existing backends don't support the type of tabbed navigation you're looking for. Someone else here implemented this using Qt4.

You might also try writing your own report files with PDF or HTML which would let you more easily write more complex image arrangements with simpler libraries.

Fructuous answered 20/5, 2016 at 13:12 Comment(3)
Thank you for your answer. Regarding the last part of your answer, do you mean that matplotlib can export figures to PDF format?Fevre
Yes. pdf is an available format. You can either set the the backend to pdf or call savefig with a pdf file extension to save each figure to an individual file. You can also use matplotlib.org/examples/pylab_examples/multipage_pdf.html to save multiple figures to a multipage pdf fileFructuous
Great, thank you very much for this explanation. I hope I could vote up your answer, but I can't because of my insufficient reputation. For now, I will accept your answer, and edit my question to include the last part of your comment as a workaround.Fevre
F
11

I wrote a simple wrapper for matplotlib that does something like you're describing. You need pyqt5 for it to work though.

Here is the code, you build a plotWindow object and feed it figure handles. It'll create a new tab for each figure.

import matplotlib
# prevent NoneType error for versions of matplotlib 3.1.0rc1+ by calling matplotlib.use()
# For more on why it's nececessary, see
# https://mcmap.net/q/1009064/-using-qt5agg-backend-with-matplotlib-3-1-2-get_backend-changes-behavior
matplotlib.use('qt5agg')

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QTabWidget, QVBoxLayout
import matplotlib.pyplot as plt
import sys

class plotWindow():
    def __init__(self, parent=None):
        self.app = QApplication(sys.argv)
        self.MainWindow = QMainWindow()
        self.MainWindow.__init__()
        self.MainWindow.setWindowTitle("plot window")
        self.canvases = []
        self.figure_handles = []
        self.toolbar_handles = []
        self.tab_handles = []
        self.current_window = -1
        self.tabs = QTabWidget()
        self.MainWindow.setCentralWidget(self.tabs)
        self.MainWindow.resize(1280, 900)
        self.MainWindow.show()

    def addPlot(self, title, figure):
        new_tab = QWidget()
        layout = QVBoxLayout()
        new_tab.setLayout(layout)

        figure.subplots_adjust(left=0.05, right=0.99, bottom=0.05, top=0.91, wspace=0.2, hspace=0.2)
        new_canvas = FigureCanvas(figure)
        new_toolbar = NavigationToolbar(new_canvas, new_tab)

        layout.addWidget(new_canvas)
        layout.addWidget(new_toolbar)
        self.tabs.addTab(new_tab, title)

        self.toolbar_handles.append(new_toolbar)
        self.canvases.append(new_canvas)
        self.figure_handles.append(figure)
        self.tab_handles.append(new_tab)

    def show(self):
        self.app.exec_()

if __name__ == '__main__':
    import numpy as np

    pw = plotWindow()

    x = np.arange(0, 10, 0.001)

    f = plt.figure()
    ysin = np.sin(x)
    plt.plot(x, ysin, '--')
    pw.addPlot("sin", f)

    f = plt.figure()
    ycos = np.cos(x)
    plt.plot(x, ycos, '--')
    pw.addPlot("cos", f)
    pw.show()

This is also posted at: https://github.com/superjax/plotWindow

Hopefully this could be a good starting point for your application.

Flu answered 19/9, 2019 at 23:14 Comment(3)
Thanks a lot for your effort, I will give it a try soon.Fevre
I'm getting an error in plotWindow.py line 55. "TypeError: 'NoneType' object is not callable". Is this code for python 2? Can you port to python 3? I'm newbieRota
I updated the code to avoid the NoneType errorFlu
F
3

The backend you choose to use for matplotlib controls how each figure is displayed. Some backends just render figures to file, while others like the tk, qt, or gtk backends render figures in graphical windows. Those backends determine what functionality those GUI windows have.

The existing backends don't support the type of tabbed navigation you're looking for. Someone else here implemented this using Qt4.

You might also try writing your own report files with PDF or HTML which would let you more easily write more complex image arrangements with simpler libraries.

Fructuous answered 20/5, 2016 at 13:12 Comment(3)
Thank you for your answer. Regarding the last part of your answer, do you mean that matplotlib can export figures to PDF format?Fevre
Yes. pdf is an available format. You can either set the the backend to pdf or call savefig with a pdf file extension to save each figure to an individual file. You can also use matplotlib.org/examples/pylab_examples/multipage_pdf.html to save multiple figures to a multipage pdf fileFructuous
Great, thank you very much for this explanation. I hope I could vote up your answer, but I can't because of my insufficient reputation. For now, I will accept your answer, and edit my question to include the last part of your comment as a workaround.Fevre
A
1

Something that is functionally similar might be implemented using the widgets. For example, provide a row of buttons, one button for each "tab", and repaint the graphical portion of the window in response to each button.

Alisonalissa answered 19/1, 2018 at 13:51 Comment(1)
Thanks for your contribution.Fevre
B
1

The buttons example as a workaround is creative. As another stated you can use PyQt to create a tabbed window.

It is for this reason I use PyQtGraph. PyQtGraph only uses PyQt as a backend and therefor "natively" supports both tabbed windows and "docks". Docks allow for movable tabs and splits as well as breaking off a tab or split to a new floating window.

In general, PyQtGraph's docks provide a method for organizing your graphs/plots/images that I haven't been able to get with other libraries.

Bokeh offers tabbed windows through their Panels and Tabs widgets.

I know it is not always feasible to move away from matplotlib but I felt like there was a lack of representation of libraries which have considered and implemented tools specifically for your use case.

Beckwith answered 3/5, 2018 at 15:2 Comment(0)
S
1

I shared my code that allows docking and tabbing with drag-n-drop (qt docking system). It acts as a matplotlib backend, so it's easy to integrate.

https://github.com/peper0/mpldock

Snuffle answered 10/11, 2019 at 0:35 Comment(1)
How add figures at the same tab withou load an layout?Rota
B
0

I recently released a python package which contains a class called DockablePlotWindow which provides a solution similar to superjax's answer but which provides a little more flexibility to organize how the plots are initially displayed.

I'm interested to continue improving this package so feel free to open pull requests or issues on github. You can find information about it here: https://github.com/nanthony21/mpl_qt_viz and here: https://nanthony21.github.io/mpl_qt_viz/

Briefs answered 18/1, 2021 at 20:24 Comment(2)
First, thank you for your efforts and for your reply. Second, could you please add pictures and screenshots of what your module does? It is not a good idea to put documentation with code only! should everyone install the module to see what is it doing?Fevre
Thanks for the feedback, I'll plan to improve on the documentation in the future.Briefs

© 2022 - 2024 — McMap. All rights reserved.