Source code for schrodinger.ui.qt.matplot_widget
# Matplot widget that can be used in Qt Designer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt.structure2d import LabeledStructureToolTip
[docs]class MatplotCanvas(FigureCanvas):
""" This is the class to represent FigureCanvas widget """
[docs] def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
[docs]class MatplotWidget(QtWidgets.QWidget):
""" This is a widget defined in Qt Designer """
[docs] def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.canvas = MatplotCanvas()
self.vLayout = QtWidgets.QVBoxLayout()
self.vLayout.addWidget(self.canvas)
#self.vLayout.addWidget(self.ntb) # matplot lib toolbar on/off
self.setLayout(self.vLayout)
[docs]class StructureTooltipMixin(object):
"""
A class that enables tooltip on matplotlib plots.
Derived classes might need to re-define showToolTip(), findPoint()
and addDataSet().
"""
TOOLTIP_SHOW_DELAY = 300
TOOLTIP_HIDE_DELAY = 0
[docs] def __init__(self):
self.tooltip = None
self.tooltip_annotation = None
# for project table use.
self.tooltip_ds = None
self.tooltip_eid = None
self.tooltip_show_timer = QtCore.QTimer()
self.tooltip_show_timer.setSingleShot(True)
self.tooltip_show_timer.timeout.connect(self.showToolTip)
self.tooltip_hide_timer = QtCore.QTimer()
self.tooltip_hide_timer.setSingleShot(True)
self.tooltip_hide_timer.timeout.connect(self.hideToolTip)
self.data_sets = []
self.st = None
self.title = ""
[docs] def showToolTip(self):
"""
Constructs and displays the tooltip.
Should be re-defined as needed in derived classes.
"""
if self.st:
self.tooltip = LabeledStructureToolTip(structure=self.st)
if self.title:
self.tooltip.addLabel(self.title)
self.tooltip.show()
[docs] def hideToolTip(self):
"""
Hide and remove the current tooltip, stops the show timer if
still running
"""
if self.tooltip_show_timer.isActive():
self.tooltip_show_timer.stop()
if self.tooltip:
self.tooltip.hide()
self.tooltip = None
self.tooltip_ds = None
self.tooltip_eid = None
[docs] def addDataSet(self, ds):
"""
Adds data sets. The reason it is a list of data sets is primarily
to work with projplot.PlotWindow. In the case of multiple sets,
derived class should overwrite findPoint method.
:param ds: Data set to add.
:type ds: list of 2-element tuples. [(x1, y1), (x2, y2), ...]
Derived class can use its own type of data sets.
"""
self.data_sets.append(ds)
[docs] def mouseMove(self, event):
"""
A mouse move event handler used to pick points in the plot
"""
if not event.inaxes:
self.tooltip_hide_timer.start(self.TOOLTIP_HIDE_DELAY)
return
found_point = self.findPoint(event)
if not found_point and self.tooltip:
self.tooltip_hide_timer.start(self.TOOLTIP_HIDE_DELAY)
[docs] def findPoint(self, event):
"""
Takes care of all the stuff needed if the data point is found.
Might need to redefine in derived classes.
:param event: mouse event
:type event: matplotlib.backend_bases.Event
:return: Whether the point at the mouse event is found
:rtype: bool
"""
if not self.data_sets:
return False
if event.xdata is None or event.ydata is None:
return False
ds = self.data_sets[0]
# ds is a list of 2-ele tuples [(x1, y1), (x2, y2)...]
x_min = min([data[0] for data in ds])
x_max = max([data[0] for data in ds])
y_min = min([data[1] for data in ds])
y_max = max([data[1] for data in ds])
if (event.xdata >= x_min and event.xdata <= x_max and
event.ydata >= y_min and event.ydata <= y_max):
return True
else:
return False