0

I have an application that has worked for over a year. I added a new section. This section is opens a dialog upon pressing a button. In this dialog, I put a bland QWidget. I want to plot using matplotlib on that widget. Below I will show what I tried to use as a basis. I am not able to get this task done. Many of the example I took did not work at all - i.e. when I run the application, I get messages that methods do not exist. There were cases where I fixed those programming errors and then the plot opened in another window but not where I wanted it to open. Is there a humane way to put a matplotlib plot on a qwidget? If not, what should I do to get a plot there. I'm coming close to declaring this cannot be done. Please point me in the correct direction. I am trying to do this in python3 - not in python2 - the way the examples are written could have been from python2 and perhaps the examples are out dated.

I looked at

1- Plotting matplotlib figure inside QWidget using Qt Designer form and PyQt5. Note, I am using pyside2 and not qt5 directly.

2- https://www.pythonguis.com/tutorials/pyside-plotting-matplotlib/

3- https://forum.pythonguis.com/t/embed-a-matplotlib-graph-in-a-specific-widget-designed-with-designer/1066

Note- My qwidget is not the "central widget" it is a specific widget that I defined in the qt-designer at a specific place. In the end there will be several like this.

I expected that I would figure out a way to plot in the place that I wanted to plot. In the end, this did not work. Either I got errors or the plot was plotted in a new window that was opened up.

This code: I edited the code - sorry for the prints, it's my way to know where I got:

from PySide2.QtWidgets import *
import PySide2.QtWidgets as QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
from matplotlib.figure import Figure
import matplotlib
matplotlib.use('Qt5Agg')


class MplCanvas(Canvas):
    '''
    Class to represent the FigureCanvas widget
    '''
    def __init__(self):
        print('7')
        self.fig = Figure()
        print('8')
        self.ax = self.fig.add_subplot(111)
        print('9')
        super(MplCanvas, self).__init__(self.fig)
        print('10')
        #Canvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
        print('11')
        Canvas.updateGeometry(self)
        print('12')




class MplWidget(QWidget):
    '''
    Widget promoted and defined in Qt Designer
    '''
    def __init__(self, parent=None):
        #QWidget.__init__(self, parent)
        super(MplWidget, self).__init__(parent)
        print('1')
        self.vbl = QVBoxLayout()
        print('2')
        #self.canvas = Canvas(Figure())
        print('3')
        self.canvas = MplCanvas()
        print('3.5')
        self.vbl.addWidget(self.canvas)
        #self.vbl.addWidget(parent)
        print('4')
        self.setLayout(self.vbl)
        print('5')
        self.checkCanvas()
        print('5')

    def checkCanvas(self):
        print(self.canvas)

    def getCanvas(self):
        return self.canvas

When I run just the constuctor: plotWidget = MplWidget(self.ink_limit_master_dialog.pyplot_widget)

I print:

1
2
3
7
8
9
10
11
12
3.5

But Then I get the following errors:

Traceback (most recent call last):
  File "C:/Work/ResourceGenerator/ResCreatorNewGeneration/res_create_NewGen_uic.py", line 1109, in ink_limit_master_callback
    plotWidget = MplWidget(self.ink_limit_master_dialog.pyplot_widget)
  File "C:\Work\ResourceGenerator\ResCreatorNewGeneration\MplWidgetClass.py", line 70, in __init__
    self.vbl.addWidget(self.canvas)
TypeError: 'PySide2.QtWidgets.QBoxLayout.addWidget' called with wrong argument types:
  PySide2.QtWidgets.QBoxLayout.addWidget(MplCanvas)
Supported signatures:
  PySide2.QtWidgets.QBoxLayout.addWidget(PySide2.QtWidgets.QWidget, int = 0, PySide2.QtCore.Qt.Alignment = Default(Qt.Alignment))
  PySide2.QtWidgets.QBoxLayout.addWidget(PySide2.QtWidgets.QWidget)

Basically I can't add the MplCanvas as a widget.

Seems it is not trivial to attach matplotlib to a qwidget...

7
  • 1
    Right now your code does not reproduce any of those errors, since you're using _init_ with single underscores instead of __init__, so what you wrote there is never run at all. You should also avoid calling the class methods with the instance, and properly use super() or the function as actual instance methods: for instance, super().__init__(self.fig), super().__init__(parent) or self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding). Commented Apr 25, 2024 at 15:21
  • You are right and this is good because now my code reverted back to previous code with the following error: Canvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) TypeError: arguments did not match any overloaded call: setSizePolicy(self, QSizePolicy): argument 2 has unexpected type 'PySide2.QtWidgets.QSizePolicy.Policy' setSizePolicy(self, QSizePolicy.Policy, QSizePolicy.Policy): argument 2 has unexpected type 'PySide2.QtWidgets.QSizePolicy.Policy' Any idea why this is the case? PySide2 vs QT5 perhaps? Commented Apr 25, 2024 at 15:39
  • Please edit your post with the updated code and the full traceback of those errors. Also, as said, you should not call instance methods like that. Commented Apr 25, 2024 at 15:45
  • I edited and provided printouts. I'm a bit discouraged that it is so difficult to attach a matplotlib plot to qwidget. if there is another more straight forward way to get a plot where i want it, I'm willing to do it differently. Commented Apr 25, 2024 at 16:21
  • You probably have PyQt installed as well, which cannot be used at the same time with PySide, and matplotlib always tries to import PyQt first, if available, meaning that you should force it to use PySide instead. Try adding from PySide2 import QtCore at the very beginning of your code (or, at least, before any matplotlib import). See the Qt Bindings docs on matplotlib. Commented Apr 25, 2024 at 16:35

1 Answer 1

0

The answer has 2 parts. First, the way that I defined MplCanvas and MplWidget works but for versions of matplotlib higher than what I had so without going into details, this needed to be slightly altered for my version of matplotlib. But this is not the essence of the issue. I wrote my project gui using qt designer with PyPlot2. Indeed for the gui itself I used the correct script pyplot-uic to convert the ui into python code. When I wrote a stand alone project and tried to plot a pyplot graph on a widget in the main window suddenly the setLayout didn't give errors that the input was not of the correct type. However, when I used a resource (qrc) to add an icon to the main window - the errors returned. I noticed that I used the qt script to convert the resource arc file to a python file. This python file, therefore, imported qt and not pyside2 objects. Since the resource import is pretty much at the beginning, this really caused the confusion between pyqt and pyside2 - they are, as said before, incompatible. When I reran the conversion from resources to python file using the pyside2 script (pyside2-rcc) then the python file imported objects from pyside2. Now there is no confusion with pyside2 and pyqt so the incompatibility was gone and everything (again - changing the classes to be compatible with my version of matplotlib) worked. I succeeded to put qwidget "windows" on a dialog and use icons via qt-designer and have everything work including plotting matplotlib-pyplot "plots" on the qwidget windows. If anyone is interested in seeing exactly how I did this, I can supply code. I'm trying to be brief here so I refrained from posting a bunch of code. The bottom line is - this does work. If it doesn't work, than the issue usually is that pyqt and pyside2 cannot live together so sometimes one needs to seek and search for pyqt imports in the event that the code behaves weirdly. In my case it was the incorrect conversion from qrc to python - inconsistent with the desire to use pyside2 and the qt within throughout the code.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.