More details regarding "Embedding custom widgets from Qt Designer" and "Creating custom GUI widgets in PyQt5"

I am new to python. After reading “Embedding custom widgets from Qt Designer”, I tried to embed matplotlib into the GUI. I followed the steps until the changing header name in the “promote” step, I entered matplotlib but there is an error msg " cannot import name ‘PlotWidget’ from ‘matplotlib’ (C:\ProgramData\Anaconda3\lib\site-packages\matplotlib_init_.py)"

I tried matplotlib.plot for the header name then it showed
“cannot import name ‘PlotWidget’ from ‘matplotlib.pyplot’ (C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\pyplot.py)”

Is it possible to add more explanations about the correct name of the head in the article? I tried pyqtgraph and it works. I have no idea why it doesn’t work.

I also tried to refer to “Creating custom GUI widgets in PyQt5”. However, I have no idea how to apply the new gui widget in another new main window. I hope there would be more steps and explanations.

Could I know if your book would include more details of those steps?
Thank you very much.

Hi @Revox_Dyna welcome to the forum! Sorry for the delay in getting back to you, I’ve just had a baby and things are a bit busy.

The problem here is that PlotWidget isn’t a matplotlib class, it’s from PyQtGraph which is a different library. To embed matplotlib you would need to use the matplotlib canvas class.

There is another tutorial on matplotlib which shows the class to use – FigureCanvasQTAgg which is imported as follows.

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg

We can compare that to PyQtGraph, where the PlotWidget is imported as follows.

from pyqtgraph import PlotWidget

When we promote the PlotWidget we use PlotWidget as the name, and pyqtgraph as the header file. The “header file” is the complete package path required to find the class. For matplotlib’s we would give FigureCanvasQTAgg as the name and matplotlib.backends.backend_qt5agg as the header file.

I’ll write up a complete example of this, as it’s not straightforward.

Congratulations on your baby :smile:and
Thank you very much, Martin!
I am looking forward to the example

Thanks @Revox_Dyna

I got some time to sit down and work this out – and it was a littl trickier than I was expecting. As I mentioned above, you can promote widgets in Qt Designer, and in theory all that should be needed is to promote a widget to a FigureCanvasQTAgg using the correct import path for the header file.

Unfortunately, this doesn’t work – all of the matplotlib “widget” classes expect a figure object as their first parameter while Qt expects the first parameter to be parent, and passes this in regardless. This doesn’t work.

The solution is to create our own custom “widget” which wraps the FigureCanvasQTAgg accepting the parent value and then creates the figure/etc. itself. This will allow this class to be created automatically by Qt from the ui file.

In a file named canvas.py in the root of my project, I added the following –

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure

class MplCanvas(FigureCanvasQTAgg):

    def __init__(self, parent=None):
        # self.setParent(parent) optional
        fig = Figure(figsize=(5, 5))
        super(MplCanvas, self).__init__(fig)

Now in Qt designer we can use this custom widget as our promote target, eg.
A custom UI was created as a single QWidget added to a main window, which was then promoted to a canvas.MplCanvas.

The QWidget is promoted by right-clicking on it and choosing promote.

The Promoted class name is “MplCanvas” and header file is “canvas” (no extension) and we’re using QWidget as the base class.

Saving this file as mainwindow.ui we can then load the working plot UI with the following code. This is a very basic example, but you can use these widgets just like any other in your applications. The “canvas” has a figure property to which you can add subplots, etc.

import sys
from PyQt5 import QtWidgets, uic


app = QtWidgets.QApplication(sys.argv)

window = uic.loadUi("mainwindow.ui")
axes = window.canvas.figure.add_subplot(1,1,1)
axes.plot([1,2,3],[4,5,6])
window.show()
app.exec()

Which produces the following window…

Hope that helps? Let me know if you have any questions.

Thank you very much, Martin.
I followed the example and there is no error message. However, the graph doesn’t show up (the other buttons, combobox were ok).
I am not sure where are some potential mistakes

My IDE is spyder

Object inspector

Some of the code:

class MyApp(QtWidgets.QMainWindow):
  def __init__(self, *args, **kwargs):
    super(MyApp, self).__init__(*args, **kwargs)
    #Load the UI Page
    window= uic.loadUi('interf_1.ui', self)  
    axes = window.canvas.figure.add_subplot(1,1,1)
    axes.plot([1,2,3],[4,5,6])
    window.show()

if __name__ == '__main__':
  def run_app():
     if not QtWidgets.QApplication.instance():
       app = QtWidgets.QApplication(sys.argv)
    else:
       app = QtWidgets.QApplication.instance()
   app.setStyle(QtWidgets.QStyleFactory.create('Fusion'))
   main = MyApp()
   main.show()
   QtWidgets.QApplication.setQuitOnLastWindowClosed(True)
   app.exec()
run_app()

Strange – do your widgets in your window have a layout applied, or are they just positioning on the window? I’m wondering if the canvas widget is collapsing to zero size.

Using a layout would be preferable, but you could also try setting a fixed size on the widget (either in Qt Designer, or with).

window.canvas.setMinimumSize(500,500)

It that’s not it, can you put your project in a zip file and upload it somewhere, will be easier to debug with everything to work with.

Thank you very much for looking into it, Martin!
The widget was selected under the “Containers” category and positioned on the window.
I have simplified the code and uploaded here: ( file name: embedded graph.rar)


or

The layout is similar to your example
s