I would like to use kivy / kivymd with matplotlib to plot labelled points which I can then interact with. I want to be able to use mouse to interactively zoom and pan. I am using the mpl-interact library for this. https://github.com/espdev/mpl-interact I have successfully used this with WxPython and PyQt5 GUI with matplotlib. However it fails with kivy.
I am using Python: v3.9.12 Kivy: v2.1.0 Matplotlib: v3.5.3
below is example of kivy code I am using, followed by almost identical pyqt5 code which works fine. I suspect issue is with kivy.garden.matplotlib.backend_kivyagg but not sure how I can work around that.
I would prefer to use kivy but may have to resort to Qt if there is no easy solution for kivy.
kivy code:
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
#from matplotlib.backends.backend_agg import FigureCanvasAgg
import sys
import matplotlib
from matplotlib.figure import Figure
from mpl_interact import interact
class MplCanvas(FigureCanvasKivyAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
global fig
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
self.cid3 = self.mpl_connect("pick_event", self.onpick)
self.cid = interact(fig)
def onpick(self, event):
index = event.ind[0]
print('Point Picked = ', ptid[index])
class QC1(App):
def build(self):
global ptid, ax
canvas = MplCanvas(self, width=8, height=6, dpi=100)
ax = canvas.axes
ptid = ['1','2','3','4','5','6','7','8','9','10']
x = [2,4,5,7,6,8,9,11,12,12]
y = [1,2,3,4,5,6,7,8,9,10]
ax.set_title('Kivy Interactive Matplotlib')
ax.scatter(x, y, s=30, color='magenta', alpha=0.7, marker='x', picker=3)
for i, ptlbl in enumerate(ptid):
ax.annotate(ptlbl, (x[i], y[i]),xytext=(5,0),textcoords='offset points',size=8,color='darkslategrey')
box = BoxLayout()
#box.add_widget(FigureCanvasKivyAgg(fig))
box.add_widget(canvas)
return box
if __name__ == '__main__':
QC1().run()
PyQt5 code:
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
#from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from mpl_interact import interact
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
global fig
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
self.cid3 = self.mpl_connect("pick_event", self.onpick)
def onpick(self, event):
index = event.ind[0]
print('Point Picked = ', ptid[index])
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
global ptid
super(MainWindow, self).__init__(*args, **kwargs)
# Create the maptlotlib FigureCanvas object,
# which defines a single set of axes as self.axes.
sc = MplCanvas(self, width=8, height=6, dpi=100)
ax = sc.axes
ptid = ['1','2','3','4','5','6','7','8','9','10']
x = [2,4,5,7,6,8,9,11,12,12]
y = [1,2,3,4,5,6,7,8,9,10]
ax.set_title('PyQt Interactive Matplotlib')
ax.scatter(x, y, s=30, color='magenta', alpha=0.7, marker='x', picker=3)
for i, ptlbl in enumerate(ptid):
ax.annotate(ptlbl, (x[i], y[i]),xytext=(5,0),textcoords='offset points',size=8,color='darkslategrey')
layout = QtWidgets.QVBoxLayout()
layout.addWidget(sc)
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
cid = interact(fig)
self.show()
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()