I don't know if I'm doing something wrong or if this is a bug in Matplotlib. I have a main figure with various objects in it. When the user clicks on an object/artist a separate window should pop up to show a table populated with information about that object. The table can be quite large so the window needs to be scrollable. I also want both windows to handle pick events and keyboard press events, ideally using the same event handler functions, although that's not critical.
I adapted the scrollable window implementation from the PyQt5 version here. Here's some dummy code that illustrates the issue:
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
class ScrollableWindow(QtWidgets.QMainWindow):
def __init__(self, fig, windowTitle="Matplotlib"):
QtWidgets.QMainWindow.__init__(self)
self.widget = QtWidgets.QWidget()
self.setCentralWidget(self.widget)
self.widget.setLayout(QtWidgets.QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.fig = fig
self.canvas = FigureCanvasQTAgg(self.fig)
self.canvas.draw()
self.scroll = QtWidgets.QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)
self.widget.layout().addWidget(self.scroll)
self.setWindowTitle(windowTitle)
class MainClass(object):
def __init__(self):
self.scrollWindow = None
self.tableFig = None
lines = plt.plot([1, 2, 3], 'go-')
lines[0].set_picker(True)
canvas = plt.gcf().canvas
canvas.mpl_connect('pick_event', self.onPick)
canvas.mpl_connect('key_press_event', self.onKeyPress)
def onPick(self, event):
print("onPick called! Artist: %s" % event.artist)
if isinstance(event.artist, Line2D):
self.tableFig = self.createTableFigure()
self.scrollWindow = ScrollableWindow(self.tableFig, "Table")
canvas = self.tableFig.canvas
canvas.mpl_connect('pick_event', self.onPick)
canvas.mpl_connect('key_press_event', self.onKeyPress)
self.scrollWindow.show()
def onKeyPress(self, event):
print('onKeyPress called! Key: ' + event.key)
def createTableFigure(self):
columnLabels = ('Length', 'Width', 'Height', 'Sold?')
rowLabels = ['Jeep', 'Ferrari', 'Porsche']
data = [[2.2, 1.6, 1.2, True],
[2.1, 1.5, 1.4, False],
[2.0, 1.4, 1.5, False]]
tableFig = Figure(figsize=(6, 1))
ax = tableFig.gca()
ax.set_axis_off()
table = matplotlib.table.table(ax, cellText=data, colLabels=columnLabels, rowLabels=rowLabels, cellLoc='center', loc='center')
table.set_picker(True)
return tableFig
m = MainClass()
plt.show()
The main window shows a line. If I click on the line the scrollable window appears with the table inside. If I click on the table you can see the onPick
method is called as expected.
However, the onKeyPress
method only gets called when I make the main window the current one. When the table window is selected key press events are ignored. Why?? Is this a bug in Matplotlib or should key-press events be handled in a different way to pick events? How do I make the table window respond to key-press events? I've seen PyQt-specific answers like this one about handling keyboard events but it would seem odd to have to do that when pick events work exactly as you'd expect. Maybe it's a mouse vs keyboard event thing. I'm very new to PyQt.
Using Python 2.7 and Matplotlib 2.2.2.