Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong behavior when integrating with a Qt app (PySide2) #662

Open
ismael-benito opened this issue Nov 21, 2023 · 3 comments
Open

Wrong behavior when integrating with a Qt app (PySide2) #662

ismael-benito opened this issue Nov 21, 2023 · 3 comments

Comments

@ismael-benito
Copy link

Hi!

We are trying to integrate seaborn-image into an app developed at our lab, the app is written in Python+Qt, using PySide2. To be specific the app contains a QMDIArea, where several subwindows can appear, one of them is supposed to be a Matplotlib figure. With Matplotlib this works just fine, however when using isbn.imgplot inside the subclassed matplotlib figure this happens:

image

Another image window is opened. The main reason this occours is in seaborn_image._core:

    def _setup_figure(self):
        """Wrapper to setup image with the desired parameters"""
        if self.ax is None:
            f, ax = plt.subplots()
        else:
            f = plt.gcf()
            ax = self.ax

When providing a matplotlib axes object, I think should use the axes itself to determine the figure rather than pyplot. So, I would say this has to be something like:

   def _setup_figure(self):
       """Wrapper to setup image with the desired parameters"""
       if self.ax is None:
           f, ax = plt.subplots()
       else:
           f = self.ax.get_figure() or plt.gcf()
           ax = self.ax

I might oversighted something and there is a way to deal with this situation in the seaborn-image API, if that is the case, sorry for the inconvenience.

Cheers,

Ismael

@SarthakJariwala
Copy link
Owner

Hi @ismael-benito, thanks for reporting. Can you share how you are calling the imgplot function (starting from setting up the figure)?

I tried replicating the behavior that you are seeing in a python (and ipython) terminal, and I've been able to replicate it in some instances, even with native matplotlib calls.

For instance, if I do the following in the Python interpreter, it leads to the behavior you are likely seeing -

>>> import matplotlib.pyplot as plt
>>> import seaborn_image as isns
>>> pol = isns.load_image("polymer")
>>> fig, ax = plt.subplots()
>>> ax.imshow(pol)
<matplotlib.image.AxesImage object at 0x1491d6170>
>>> plt.show()

But, if I update it to create subplots, and use matplotlib's imshow in the same line it succeeds...

>>> import matplotlib.pyplot as plt
>>> import seaborn_image as isns
>>> pol = isns.load_image("polymer")
>>> fig, ax = plt.subplots(); ax.imshow(pol)
<matplotlib.image.AxesImage object at 0x1450586d0>
>>> plt.show()

The same thing happens for imgplot in seaborn_image. (using ax.get_figure() like you suggested does not resolve the issue)

Could you share the code snippet of matplotlib only code (that you said worked) and with seaborn-image (that didn't work as expected)? Thanks!

@ismael-benito
Copy link
Author

I cannot share the full code, but I've created a reduced script which does the same functionality. It seems is also dependent on the environment, as you pointed out. Running this snippet from python directly inside PyCharm with the run configuration set to not use the Python Console does not trigger the second window. However, running the snippet using the Python Console, e.g. using IPython, triggers the error.

Regarding this, I would assume there is something that changes in how matplotlib handles the environment using the QT backends. Would be wise to implement the avobe mentioned method using the .get_figure method from the plt.Axes object, I think.

Here is the snippet:

import numpy as np
import seaborn_image as isns
from PySide2 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Seaborn-Image Example")
        self.setGeometry(100, 100, 800, 600)

        self.mdi_area = QtWidgets.QMdiArea(self)
        self.setCentralWidget(self.mdi_area)

        sub_window = QtWidgets.QMdiSubWindow()
        self.mdi_area.addSubWindow(sub_window)

        main_widget = QtWidgets.QWidget()
        sub_window.setWidget(main_widget)

        layout = QtWidgets.QVBoxLayout(main_widget)

        # Create a Matplotlib figure and canvas
        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)
        layout.addWidget(self.canvas)

        # Create a custom toolbar for seaborn-image settings (you can add your tools here)

        # Create an Axes for Matplotlib
        self.ax = self.figure.add_subplot(111)
        self.ax.axis('off')  # Turn off axes

        # Load and display an example image (e.g., scipy.misc.face())
        example_image = np.random.random((512, 512))  # Replace this with your image data
        isns.imgplot(example_image, ax=self.ax)  # Use isns.imgplot to display the image


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

@SarthakJariwala
Copy link
Owner

Yeah, this seems to be matplotlib backend-related. Unfortunately, I haven't been able to track it down.

Regarding ax.get_figure(): I agree, it's a cleaner way to determine the figure from axis - I've updated it in this PR. Thanks for suggesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants