Source code for schrodinger.ui.qt.navtoolbar
"""
Custom versions of the Matplotlib Qt Navigation toolbar
Copyright Schrodinger, LLC. All rights reserved.
"""
import os
import os.path
import matplotlib
from matplotlib.backend_bases import cursors
from matplotlib.backends.backend_qt5 import SubplotToolQt
from matplotlib.backends.backend_qt5agg import \
NavigationToolbar2QT as NavToolbarQt
import schrodinger
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import figureoptions
from schrodinger.ui.qt import icons
Qt = QtCore.Qt
maestro = schrodinger.get_maestro()
cursord = {
cursors.MOVE: QtCore.Qt.SizeAllCursor,
cursors.HAND: QtCore.Qt.PointingHandCursor,
cursors.POINTER: QtCore.Qt.ArrowCursor,
cursors.SELECT_REGION: QtCore.Qt.CrossCursor,
cursors.WAIT: QtCore.Qt.WaitCursor,
}
CUSTOMIZE_TOOLITEM = ('Customize', 'Edit axis, curve and image parameters',
'qt4_editor_options', 'edit_parameters')
ACTION_NAMES = {
'PAN': 'pan',
'ZOOM': 'zoom',
}
[docs]class SchrodingerSubplotTool(SubplotToolQt):
BETTER_LABELS = {
'left': 'Left Margin',
'right': 'Right Margin',
'top': 'Top Margin',
'bottom': 'Bottom Margin',
'hspace': 'Vertical Gap\nBetween Plots',
'wspace': 'Horizontal Gap\nBetween Plots'
}
[docs] def __init__(self, *args):
SubplotToolQt.__init__(self, *args)
labels = self.findChildren(QtWidgets.QLabel)
for label in labels:
text = str(label.text())
try:
new_label = self.BETTER_LABELS[text]
except KeyError:
continue
label.setText(new_label)
label.setAlignment(Qt.AlignCenter)
[docs]class FeedbackSubplotToolQt(SubplotToolQt):
"""
Allows the parent panel to perform pre and post plot modification actions
"""
[docs] def __init__(self, targetfig, panel):
"""
:type panel: AppFramework object
:param panel: an object with setWaitCursor and restoreCursor methods
"""
self.panel = panel
SubplotToolQt.__init__(self, targetfig, panel)
[docs] def funcleft(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='funcleft')
SubplotToolQt.funcleft(self, val)
self.panel.postPlotAction(x, y, what='funcleft')
[docs] def funcright(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='funcright')
SubplotToolQt.funcright(self, val)
self.panel.postPlotAction(x, y, what='funcright')
[docs] def funcbottom(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='funcbottom')
SubplotToolQt.funcbottom(self, val)
self.panel.postPlotAction(x, y, what='funcbottom')
[docs] def functop(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='functop')
SubplotToolQt.functop(self, val)
self.panel.postPlotAction(x, y, what='functop')
[docs] def funcwspace(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='funcwspace')
SubplotToolQt.funcwspace(self, val)
self.panel.postPlotAction(x, y, what='funcwspace')
[docs] def funchspace(self, val):
"""
Allow the parent panel to to pre and post plot modification actions
"""
x, y = self.panel.prePlotAction(what='funchspace')
SubplotToolQt.funchspace(self, val)
self.panel.postPlotAction(x, y, what='funchspace')
[docs]class AtomInfoToolbar(NavToolbar):
"""
Overrides the set_message class of the normal toolbar to enable the
following enhancements:
1) Print the atom numbers and their distance.
2) Allow the user to turn off pan/zoom or zoom modes by clicking on the
depressed toolbar button
3) Call the parent panel prePlotAction and postPlotAction methods before
modifying the plot view in any way to allow the parent to properly
prepare for the modification (create a wait cursor, add/remove plot
features, etc.)
Used by residue_distance_map.py & pose_explorer_dir/multi_canvas_toolbar.py
"""
[docs] def __init__(self, canvas, parent, coordinates=True, **kwargs):
"""
Create a new toolbar instance
:type canvas: FigureCanvasQTAgg
:param canvas: The canvas this toolbar belongs to
:type parent: CaDistanceGUI
:param parent: The parent panel that contains information about atoms
and distances.
:type coordinates: bool
:param coordinates: not used
"""
self.panel = parent
NavToolbar.__init__(self, canvas, parent, coordinates, **kwargs)
[docs] def set_message(self, event):
"""
Place the atom numbers and distance between them that corresponds to the
atoms currently under the cursor.
:type event: mouse move event
:param event: the event object generated by the mouse movement
"""
x, y, axes = event.xdata, event.ydata, event.inaxes
# Some messages have status labels at the beginning, so chop off
# everything up to x=.
if (x is None or y is None or x < 0 or y < 0 or
(axes and axes != self.panel.sub_plot)):
self.panel.updateStatus()
return
try:
# Translate the plot coordinates into atom numbers and find the
# distance between them.
xint = int(x)
yint = int(y)
atomx = self.panel.ca_atoms[xint]
atomy = self.panel.ca_atoms[yint]
dist = self.panel.distance_matrix[xint, yint]
except (IndexError, AttributeError):
self.panel.updateStatus()
return
resx = self.panel.residueName(atomx)
resy = self.panel.residueName(atomy)
text = "".join([
'Atom:Residue (x,y) (',
str(atomx), ':', resx, ', ',
str(atomy), ':', resy,
') Distance=%.1f' % dist
])
self.panel.updateStatus(message=text)
[docs] def getSubplotDialog(self):
"""
Over-rides NavToolbar method, to initialize FeedbackSubplotToolQt class
in order to use the wait cursor when configuring the plot.
"""
return FeedbackSubplotToolQt(self.canvas.figure, self.parent)
[docs] def mouse_move(self, event):
"""
Overwrites the parent routine to always call set_message with the x and
y data for the event.
:type event: mouse move event
:param event: the event object generated by the mouse movement
"""
super()._update_cursor(event)
self.set_message(event)
[docs] def isActive(self, actor):
"""
Checks to see if the action with the name actor active, and if it is,
returns it.
:type actor: str
:param actor: the name of the action to check. The name is what is
returned by the action.text() method.
:rtype: Action object or False
:return: the Action object if it is active, or False if it is not
"""
for action in self.actions():
if str(action.text()) == actor and action.isChecked():
return action
return False