Source code for schrodinger.ui.qt.smatplotlib
"""
Contains Schrodinger helper widgets for matplotlib display in PyQt
"""
# Copyright Schrodinger, LLC. All rights reserved.
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import navtoolbar
[docs]class SmatplotlibCanvas(FigureCanvasQTAgg):
"""
Custom subclass of FigureCanvasQTAgg that does the following:
- Allows for simultaneous definition of the Canvas, Figure and toolbar
objects, and placing them in a layout
- Fixes known bugs with the mouse events detecting modifier keys
"""
[docs] def __init__(self,
width=5,
height=4,
dpi=100,
toolbar=True,
layout=None,
expanding=True,
**kwargs):
"""
:type width: number
:param width: width of the plot Figure in inches
:type height: number
:param height: height of the plot Figure in inches
:type dpi: int
:param dpi: resolution of the plot
:type toolbar: boolean
:param toolbar: True if the toolbar should be created, but the parent
parameter must be supplied in this case
:type layout: QLayout object
:param layout: If layout is supplied, the toolbar and canvas will be
placed in it.
Extra keyword arguments are passed to the toolbar function
"""
self.fig = Figure(figsize=(width, height), dpi=dpi)
# self._control_down is used to capture when the control key is down
self._control_down = False
FigureCanvasQTAgg.__init__(self, self.fig)
try:
# PYTHON-2324
import pyemf # noqa: F401
except ImportError:
try:
del self.filetypes['emf']
except KeyError:
pass
if expanding:
FigureCanvasQTAgg.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvasQTAgg.updateGeometry(self)
# Do not allow shrinking below this size (fixes PYAPP-6020):
self.setMinimumSize(100, 100)
# Create the toolbar if asked for
if toolbar:
self.toolbar = navtoolbar.NavToolbar(self, self, **kwargs)
self.toolbar.update()
if layout is not None:
layout.addWidget(self.toolbar)
if layout is not None:
layout.addWidget(self)
# Custom handling of events
self.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
"""
The canvas needs to grab keyboard input in order to reliably tell when
a modifier key (shift or control) is down when a mouse button is
pressed/released.
Some environments have trouble with passing the control key in events -
a control-left-click is often mapped to a right-click. Therefore we do
our best to capture on our own when the control key is down. Note that
even this breaks for multiple control-clicks on Linux running under
VMWare Fusion on Macs, because VMWare by default "lifts" the control
key after the first click.
:type obj: not used
:param obj: not used
:type event: QEvent
:param event: the event object
"""
# Grab and release the keyboard when the mouse enters or leaves the
# canvas
if event.type() == QtCore.QEvent.Enter:
self.grabKeyboard()
elif event.type() == QtCore.QEvent.Leave:
self.releaseKeyboard()
# Capture when the control key is pressed or raised.
elif event.type() == QtCore.QEvent.KeyPress:
key_event = QtGui.QKeyEvent(event)
if key_event.key() == QtCore.Qt.Key_Control:
self._control_down = True
elif event.type() == QtCore.QEvent.KeyRelease:
key_event = QtGui.QKeyEvent(event)
if key_event.key() == QtCore.Qt.Key_Control:
self._control_down = False
return False
[docs] def mousePressEvent(self, event):
"""
Add in the control modifier key to the button_press_event
:type event: QMouseEvent
:param event: the QMouseEvent that triggered this handler
self._key is matplotlib's way of storing the modifier keys
"""
if not self._key and self._control_down:
self._key = 'control'
FigureCanvasQTAgg.mousePressEvent(self, event)
[docs] def mouseReleaseEvent(self, event):
"""
Add in the control modifier key to the button_release_event
:type event: QMouseEvent
:param event: the QMouseEvent that triggered this handler
self._key is matplotlib's way of storing the modifier keys
"""
if not self._key and self._control_down:
self._key = 'control'
FigureCanvasQTAgg.mouseReleaseEvent(self, event)