0

I try to embed the EditableGraph function into a PyQt5 application. I developed the following program for testing, based on solutions found online.

from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from netgraph import EditableGraph, InteractiveGraph
class MainWindow(QtWidgets.QMainWindow):
 def __init__(self):
 super(MainWindow, self).__init__()
 self.canvas = FigureCanvas(Figure())
 self.canvas.ax = self.canvas.figure.add_subplot(111)
 self.editgraph = EditableGraph([(0, 1), (1,2), (2,0)], 
 ax=self.canvas.ax)
 # Enable key_press_event events:
 self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
 self.canvas.setFocus()
 widget = QtWidgets.QWidget()
 self.setCentralWidget(widget)
 layout = QtWidgets.QVBoxLayout(widget)
 layout.addWidget(self.canvas)
if __name__ == "__main__":
 app = QtWidgets.QApplication([])
 w = MainWindow()
 w.show()
 app.exec_()

However I have the following error:

self.fig.canvas.manager.key_press = key_press_handler AttributeError: 'NoneType' object has no attribute 'key_press'

More in detail, the error message is:

Traceback (most recent call last):
 File "C:... \testit.py", line 26, in <module>
 w = MainWindow()
 ^^^^^^^^^^^^
 File "C:... \testit.py", line 13, in __init__
 self.graph = EditableGraph([(0, 1), (1,2), (2,0)], ax=self.canvas.ax)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 File "C: ... \netgraph\_interactive_graph_classes.py", line 1971, in __init__
 self.fig.canvas.manager.key_press = key_press_handler
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'key_press'

When I exchange EditableGraph by InteractiveGraph, it works well.

I use the following dev version of NetGraph.

pip install https://github.com/paulbrodersen/netgraph/archive/dev.zip

I don't know where the problem originated from, and I couldn't find a solution on the Web. Can you please help me? This embedding is crucial for my application. Thank you.

asked Feb 24, 2024 at 10:40

1 Answer 1

1

Finally I found the solution. The issue is to properly assign a manager to the canvas. First, matplotlib.figure.Figure does not produce a manager while pyplot.figure() does. In the following program the result is None for fig1 while it corresponds to an object reference for fig2.

from matplotlib.figure import Figure
import matplotlib.pyplot as plt
fig1 = Figure()
fig2 = plt.figure()
print("fig1>",fig1.figure.canvas.manager)
print("fig2>",fig2.figure.canvas.manager)

However, merely replacing Figure() with plt.figure() is insufficient because the manager is not copied/exported/transmitted to the canvas. Therefore, this must be achieved explicitly. The final code is as follows:

from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from netgraph import EditableGraph
import matplotlib.pyplot as plt
class MainWindow(QtWidgets.QMainWindow):
 def __init__(self, *args, **kwargs):
 super(MainWindow, self).__init__(*args, **kwargs)
 fig = plt.figure() # use pyplot.figure() instead of Figure()
 
 manager = fig.canvas.manager # keep the manager 
 self.canvas = FigureCanvas(fig) 
 self.canvas.ax = self.canvas.figure.add_subplot(111)
 self.canvas.figure.canvas.manager = manager # <-- assign the manager to the canvas figure.
 self.graph = EditableGraph([(0, 1), (1, 2), (2, 0)], ax=self.canvas.ax)
 self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
 self.canvas.setFocus()
 widget = QtWidgets.QWidget()
 self.setCentralWidget(widget)
 layout = QtWidgets.QVBoxLayout(widget)
 layout.addWidget(self.canvas)
if __name__ == "__main__":
 app = QtWidgets.QApplication([])
 w = MainWindow()
 w.show()
 app.exec_()

The creation of a matplotlib canvas in PyQT5 is typically defined by a class. Here is the definition of such a class including the manager:

class MplCanvas(FigureCanvasQTAgg)
def __init__(self, parent=None, width=5, height=5, dpi=100):
 fig = plt.figure(figsize=(width, height), dpi=dpi)
 manager = fig.canvas.manager
 self.axes = fig.add_subplot(111)
 super(MplCanvas, self).__init__(fig)
 self.figure.canvas.manager = manager
 self.figure.subplots_adjust(left=0, bottom=0, right=1, top=1)
answered Feb 25, 2024 at 17:31
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.