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

Qt widget with matplotlib API #30

Closed
anntzer opened this issue Jan 28, 2017 · 10 comments
Closed

Qt widget with matplotlib API #30

anntzer opened this issue Jan 28, 2017 · 10 comments

Comments

@anntzer
Copy link

anntzer commented Jan 28, 2017

gr can currently be used as a matplotlib backend and as a Qt widget, but could it be possible to use both simultaneously? Namely, have a Qt widget (say, of MatplotlibGRWidget class), which would have a .figure attribute, that would be a matplotlib.figure.Figure.

@jheinen
Copy link
Collaborator

jheinen commented Jan 29, 2017

GR fully supports Qt4 and Qt5 - there are several examples in the GR source distribution. I don't see any problem doing similar thing with Matplotlib when using GR's backend.

We will try to provide an example next week ...

@jheinen
Copy link
Collaborator

jheinen commented Jan 29, 2017

This is a very simple PyQt4 + Matplotlib + GR backend example:

screen shot 2017-01-29 at 12 37 27

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
GR / PyQt4 interoperability example
"""

import sys
import os
from PyQt4 import QtCore, QtGui
import sip

os.environ["GKS_WSTYPE"] = "381"
os.environ["MPLBACKEND"] = "module://gr.matplotlib.backend_gr"

import gr
from gr.pygr import *
gr.setregenflags(gr.MPL_POSTPONE_UPDATE)

import numpy as np
import matplotlib.pyplot as plt

class GrWidget(QtGui.QWidget) :
    def __init__(self, *args) :
        QtGui.QWidget.__init__(self)
        
        self.setupUi(self)

        self.connect(self.DrawButton, QtCore.SIGNAL("clicked()"), self.draw)
        self.connect(self.QuitButton, QtCore.SIGNAL("clicked()"), self.quit)
        self.w = 500
        self.h = 500
        self.sizex = 1
        self.sizey = 1
 
    def setupUi(self, Form) :

        Form.setWindowTitle("GrWidget")
        Form.resize(QtCore.QSize(500, 500).expandedTo(Form.minimumSizeHint()))

        self.DrawButton = QtGui.QPushButton(Form)
        self.DrawButton.setText("Draw")
        self.DrawButton.setGeometry(QtCore.QRect(290, 5, 100, 25))
        self.DrawButton.setObjectName("draw")

        self.QuitButton = QtGui.QPushButton(Form)
        self.QuitButton.setText("Quit")
        self.QuitButton.setGeometry(QtCore.QRect(395, 5, 100, 25))
        self.QuitButton.setObjectName("quit")

        QtCore.QMetaObject.connectSlotsByName(Form)

    def quit(self) :
        gr.emergencyclosegks()
        self.close()

    def draw(self) :
        self.setStyleSheet("background-color:white;");

        plt.cla()

        mu, sigma = 100, 15
        x = mu + sigma * np.random.randn(10000)

        # the histogram of the data
        n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75)

        plt.xlabel('Smarts')
        plt.ylabel('Probability')
        plt.title('Histogram of IQ')
        plt.axis([40, 160, 0, 0.03])
        plt.show()

        self.update()

    def resizeEvent(self, event):
        self.w = event.size().width()
        self.h = event.size().height()
        if self.w > self.h:
          self.sizex = 1
          self.sizey = float(self.h)/self.w
        else:
          self.sizex = float(self.w)/self.h
          self.sizey = 1
        self.draw()

    def paintEvent(self, ev) :
        self.painter = QtGui.QPainter()
        self.painter.begin(self)
        self.painter.drawText(15, 15, "Contour Example using PyQt4 ...")
        os.environ['GKSconid'] = "%x!%x" % (sip.unwrapinstance(self), sip.unwrapinstance(self.painter))
        gr.updatews()
        self.painter.end()

app = QtGui.QApplication(sys.argv)
if not sys.platform == "linux2" :
    app.setStyle('Windows')

w = GrWidget()
w.show()

sys.exit(app.exec_())

@anntzer
Copy link
Author

anntzer commented Jan 29, 2017

Thank you for your quick reply. However, the example currently segfaults for me:

$ python /tmp/example.py
GKS: can't obtain Qt drawable
Fatal Python error: Segmentation fault

Current thread 0x00007f1f86212400 (most recent call first):
  File "/usr/lib/python3.6/site-packages/gr/__init__.py", line 2333 in setregenflags
  File "/tmp/example.py", line 17 in <module>
[1]    5693 segmentation fault (core dumped)  python /tmp/example.py

(gr 0.23.0 and matplotlib 2.0 installed with pip on Python 3.6, Arch Linux.)

Moreover, it is not clear from the example whether this would work for multiple figures simultaneously, as you don't specify an explicit Figure/Axes object, relying on pyplot's notion of "current figure/axes" (I would have tried if I could...). However, trying plt.figure(1); plt.figure(2); plt.show() from IPython only raises one window with the gr backend, as opposed to two with the qt5agg backend.

@jheinen
Copy link
Collaborator

jheinen commented Jan 29, 2017

.. I only tested on macOS X. Will do further test tomorrow ... (when I'm back in office)

@cfelder
Copy link
Contributor

cfelder commented Jan 30, 2017

This code can further be reduced using the qtgr module which is part of gr see below::

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
GR / PyQt4 interoperability example
"""

import sys
import os
from PyQt4 import QtCore, QtGui

os.environ["GKS_WSTYPE"] = "381"
os.environ["MPLBACKEND"] = "module://gr.matplotlib.backend_gr"

import numpy as np
import matplotlib.pyplot as plt

from gr.pygr import *
gr.setregenflags(gr.MPL_POSTPONE_UPDATE)
from qtgr import GRWidget


class GrWidget(GRWidget) :
    def __init__(self, *args, **kwargs) :
        GRWidget.__init__(self, *args, **kwargs)
        
        self.setupUi(self)

        self.connect(self.DrawButton, QtCore.SIGNAL("clicked()"), self.update)
        self.connect(self.QuitButton, QtCore.SIGNAL("clicked()"), self.close)

    def setupUi(self, Form) :
        Form.setWindowTitle("GrWidget")
        Form.resize(QtCore.QSize(500, 500).expandedTo(Form.minimumSizeHint()))

        self.DrawButton = QtGui.QPushButton(Form)
        self.DrawButton.setText("Draw")
        self.DrawButton.setGeometry(QtCore.QRect(290, 5, 100, 25))
        self.DrawButton.setObjectName("draw")

        self.QuitButton = QtGui.QPushButton(Form)
        self.QuitButton.setText("Quit")
        self.QuitButton.setGeometry(QtCore.QRect(395, 5, 100, 25))
        self.QuitButton.setObjectName("quit")

        QtCore.QMetaObject.connectSlotsByName(Form)

    def draw(self) :
        plt.cla()

        mu, sigma = 100, 15
        x = mu + sigma * np.random.randn(10000)

        # the histogram of the data
        plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75)

        plt.xlabel('Smarts')
        plt.ylabel('Probability')
        plt.title('Histogram of IQ')
        plt.axis([40, 160, 0, 0.03])
        plt.show()


app = QtGui.QApplication(sys.argv)
if not sys.platform == "linux2" :
    app.setStyle('Windows')

w = GrWidget()
w.show()

sys.exit(app.exec_())

@jheinen
Copy link
Collaborator

jheinen commented Jan 30, 2017

@cfelder : Thanks - my script was just a Sunday morning hack ...

@FlorianRhiem
Copy link
Member

We are closing this issue due to inactivity. Please reopen the issue and let us know if its cause still persists with the current version of GR.

@mfreer
Copy link

mfreer commented May 23, 2019

Apologies for resurrecting a dead thread (and if this has already been addressed somewhere), but hopefully this issue fits within the original scope. Like the original question, I'm looking to use GR as a matplotlib backend, but also as a Qt widget (to speed up the plotting I'm doing in my program). Currently, I am adding a FigureCanvas instance from the matplotlib qt5agg backend as a widget to my Qt layout. I see there is a FigureCanvas class in the GR backend, but this FigureCanvas is of type FigureCanvasGR and not recognized by Qt. Should this, perhaps, be wrapped in a QtGR class so it can be displayed in a Qt layout?

@FlorianRhiem
Copy link
Member

That sounds like it could be done by combining the FigureCanvasGR and the GRWidget in something like a FigureCanvasQtGR. Could you create a small example to show how you are currently doing this with qt5agg and how you would like to do this using GR?

Ideally open a new issue in the python-gr repository for this.

@mfreer
Copy link

mfreer commented May 23, 2019

Thanks - will open a new issue there.

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

5 participants