FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

PySide backend support by gstorer · Pull Request #80 · matplotlib/matplotlib · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (7) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
4 changes: 2 additions & 2 deletions lib/matplotlib/backend_bases.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):



class FigureCanvasBase:
class FigureCanvasBase(object):
"""
The canvas the figure renders into.

Expand Down Expand Up @@ -2306,7 +2306,7 @@ class Cursors: #namespace



class NavigationToolbar2:
class NavigationToolbar2(object):
"""
Base class for the navigation cursor, version 2

Expand Down
50 changes: 10 additions & 40 deletions lib/matplotlib/backends/backend_qt4.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,9 @@
except ImportError:
figureoptions = None

try:
from PyQt4 import QtCore, QtGui
except ImportError:
raise ImportError("Qt4 backend requires that PyQt4 is installed.")

import sip

try :
if sip.getapi("QString") > 1 :
# Use new getSaveFileNameAndFilter()
_getSaveFileName = lambda self, msg, start, filters, selectedFilter : \
QtGui.QFileDialog.getSaveFileNameAndFilter(self, \
msg, start, filters, selectedFilter)[0]
else :
# Use old getSaveFileName()
_getSaveFileName = QtGui.QFileDialog.getSaveFileName
except (AttributeError, KeyError) :
# call to getapi() can fail in older versions of sip
# Use the old getSaveFileName()
_getSaveFileName = QtGui.QFileDialog.getSaveFileName

backend_version = "0.9.1"
from qt4_compat import QtCore, QtGui, _getSaveFileName, __version__

backend_version = __version__
def fn_name(): return sys._getframe(1).f_code.co_name

DEBUG = False
Expand Down Expand Up @@ -292,22 +273,6 @@ def idle_draw(*args):
self._idle = True
if d: QtCore.QTimer.singleShot(0, idle_draw)


# XXX Hackish fix: There's a bug in PyQt. See this thread for details:
# http://old.nabble.com/Qt4-backend:-critical-bug-with-PyQt4-v4.6%2B-td26205716.html
# Once a release of Qt/PyQt is available without the bug, the version check
# below can be tightened further to only be applied in the necessary versions.
if QtCore.PYQT_VERSION_STR.startswith('4.6'):
class FigureWindow(QtGui.QMainWindow):
def __init__(self):
super(FigureWindow, self).__init__()
def closeEvent(self, event):
super(FigureWindow, self).closeEvent(event)
self.emit(QtCore.SIGNAL('destroyed()'))
else:
FigureWindow = QtGui.QMainWindow
# /end pyqt hackish bugfix

class FigureManagerQT( FigureManagerBase ):
"""
Public attributes
Expand All @@ -322,7 +287,7 @@ def __init__( self, canvas, num ):
if DEBUG: print 'FigureManagerQT.%s' % fn_name()
FigureManagerBase.__init__( self, canvas, num )
self.canvas = canvas
self.window = FigureWindow()
self.window = QtGui.QMainWindow()
self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose)

self.window.setWindowTitle("Figure %d" % num)
Expand All @@ -341,7 +306,7 @@ def __init__( self, canvas, num ):
if self.toolbar is not None:
self.window.addToolBar(self.toolbar)
QtCore.QObject.connect(self.toolbar, QtCore.SIGNAL("message"),
self.window.statusBar().showMessage)
self._show_message)
tbs_height = self.toolbar.sizeHint().height()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Does this drop support for PyQt 4.6 and earlier? At my institution, we are still standardized on RHEL5 which comes with PyQt 4.2. We should support at least that far back.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

As best I can tell this only has an impact on early versions of 4.6.x. The fix is certainly only applied to PyQt 4.6.x and the bug was apparently fixed in 4.6.2. Even if you're stuck with 4.6 I would've thought you'd at least have the most recent version of it.

I.e. this will only break support for 4.6.0 and 4.6.1 everything else will remain the same.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Great. Thanks for the confirmation. I think it's fine to not support obsolete maintenance releases.

else:
tbs_height = 0
Expand All @@ -366,6 +331,11 @@ def notify_axes_change( fig ):
self.toolbar.update()
self.canvas.figure.add_axobserver( notify_axes_change )

@QtCore.Slot()
def _show_message(self,s):
# Fixes a PySide segfault.
self.window.statusBar().showMessage(s)

def _widgetclosed( self ):
if self.window._destroying: return
self.window._destroying = True
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_qt4agg.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def paintEvent( self, e ):
else:
stringBuffer = self.renderer._renderer.tostring_argb()

qImage = QtGui.QImage(stringBuffer, self.renderer.width,
qImage = QtGui.QImage(stringBuffer, self.renderer.width,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

With ubuntu 11.4 (pyside 1.0.1 & qt4 4.7.2), I get a following exception.

TypeError: 'PySide.QtGui.QImage' called with wrong argument types:
PySide.QtGui.QImage(str, int, int, PySide.QtGui.QImage.Format)
Supported signatures:
PySide.QtGui.QImage()
PySide.QtGui.QImage(PySide.QtGui.QImage)
PySide.QtGui.QImage(PySide.QtCore.QSize, PySide.QtGui.QImage.Format)
PySide.QtGui.QImage(QString, str = None)
PySide.QtGui.QImage(int, int, PySide.QtGui.QImage.Format)
PySide.QtGui.QImage(buffer, int, int, PySide.QtGui.QImage.Format)
PySide.QtGui.QImage(buffer, int, int, int, PySide.QtGui.QImage.Format)

Converting stringBuffer to a buffer object explicitly seem to solve the problem (both pyqt and pyside works), but i'm not sure if this behavior will depend on the pyside version.

        qImage = QtGui.QImage(buffer(stringBuffer), int(self.renderer.width), 
                              int(self.renderer.height),

We may need a same change at line 117.
The agg renderer has a "buffer_rgba" method but QImage does not seem to support RGBA format.

-JJ

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This is a PySide bug fixed in 1.0.2 http://bugs.pyside.org/show_bug.cgi?id=489

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We should probably add a version check against PySide then, since we know 1.0.2 is the minimum workable version.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Good to know that this is a pyside bug. However, using explicit buffer call does any harm to matplotib w/ pyside v1.0.2?
I could be wrong but my guess is that if we call buffer explicitly, the code will work for both v1.0.2 and v1.0.1?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Yes. Wrapping with buffer makes it work in both versions. I was under the impression that mpl wasn't in the business of fixing bugs for specific versions of on specific platforms etc. In any case, there's another bug (819, see my opening comment) that wasn't fixed until 1.0.2 (try saving a figure). There is also an outstanding bug that prevents this backend working on mac (809) that won't be fixed until 1.0.3.

I'd suggest that 1.0.3 should probably be the minimum supported version to keep things simple. In which case this can stay as is. Unless there is a good reason to want to wrap with buffer() in any case?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

In my experience, mpl tries to broadly support as many versions of a library on as many platforms as feasible. I don't know if it's stated explicitly anywhere, but at least in my work environment, it is very important to support rather old and possibly buggy versions of core dependencies (e.g. GUI toolkits) for quite some time. Look at the GTK backend, for example, for a number of version-specific hacks that have been required over time. Eventually the idea is to prune that stuff out -- my own rule of thumb is to support at least as far back as whatever was in the (current release - 2) of RHEL.

In this specific case, however, with PySide being so new and cutting edge to begin with, I think it's ok to require a minimum version and not add hacks for 1.0.x which were fairly ephemeral and not widely-used releases. But the version check is important because user's should understand it's breaking because of an old version of PySide and not some other reason.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I was inclined to fix the buffer thing since pyside v1.0.1 is packaged for ubuntu, and this simple fix at least makes the backend usable. Anyhow, I agree with Michael and the current approach is okay.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ok, that's good then.

As a side note, I was under the impression that Ubuntu was more or less the development platform for PySide. Every version of PySide is packaged for it within a few hours of release isn't it?

self.renderer.height,
QtGui.QImage.Format_ARGB32)
p = QtGui.QPainter(self)
Expand Down
61 changes: 61 additions & 0 deletions lib/matplotlib/backends/qt4_compat.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
""" A Qt API selector that can be used to switch between PyQt and PySide.
"""

import os

# Available APIs.
QT_API_PYQT = 'pyqt'
QT_API_PYSIDE = 'pyside'

# Select PyQt4 or PySide using an environment variable, in the same way IPython does.
# IPython is using PyQt as default (for now) so we will too.
QT_API = os.environ.get('QT_API', QT_API_PYQT)

if QT_API == QT_API_PYQT:
try:
from PyQt4 import QtCore, QtGui
except ImportError:
raise ImportError("Qt4 backend requires that PyQt4 is installed.")
# Alias PyQt-specific functions for PySide compatibility.
try:
QtCore.Slot = QtCore.pyqtSlot
except AttributeError:
QtCore.Slot = pyqtSignature # Not a perfect match but
# works in simple cases
QtCore.Property = QtCore.pyqtProperty
__version__ = QtCore.PYQT_VERSION_STR
import sip
try :
if sip.getapi("QString") > 1 :
# Use new getSaveFileNameAndFilter()
_getSaveFileName = lambda self, msg, start, filters, \
selectedFilter : \
QtGui.QFileDialog.getSaveFileNameAndFilter( \
self, msg, start, filters, selectedFilter)[0]
else :
# Use old getSaveFileName()
_getSaveFileName = QtGui.QFileDialog.getSaveFileName
except (AttributeError, KeyError) :
# call to getapi() can fail in older versions of sip
# Use the old getSaveFileName()
_getSaveFileName = QtGui.QFileDialog.getSaveFileName

elif QT_API == QT_API_PYSIDE:
try:
from PySide import QtCore, QtGui, __version__, __version_info__
except ImportError:
raise ImportError("Qt4 backend requires that PySide is installed.")
if __version_info__ < (1,0,3):
raise ImportError("Matplotlib backend_qt4 and backend_qt4agg require PySide >=1.0.3")

# Alias PySide-specific function for PyQt compatibilty
QtCore.pyqtProperty = QtCore.Property
QtCore.pyqtSignature = QtCore.Slot # Not a perfect match but
# works in simple cases

_getSaveFileName = lambda self, msg, start, filters, selectedFilter : \
QtGui.QFileDialog.getSaveFileName(self, \
msg, start, filters, selectedFilter)[0]
else:
raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' %
(QT_API, QT_API_PYQT, QT_API_PYSIDE))
4 changes: 2 additions & 2 deletions lib/matplotlib/backends/qt4_editor/figureoptions.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import os.path as osp

import matplotlib.backends.qt4_editor.formlayout as formlayout
from PyQt4.QtGui import QIcon
from matplotlib.backends.qt4_compat import QtGui

def get_icon(name):
import matplotlib
basedir = osp.join(matplotlib.rcParams['datapath'], 'images')
return QIcon(osp.join(basedir, name))
return QtGui.QIcon(osp.join(basedir, name))

LINESTYLES = {
'-': 'Solid',
Expand Down
Loading

Back | FazBrowse Home | New Git URL