kivy matplotlib interactive zoom

Viewed 26

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()

kivy / pyqt5 plot

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_()
0 Answers
Related