0

我是 tkinter 和 python 的新手。我正在尝试在嵌入 tkinter 画布的 matplotlib 图中使用 mplcursors。tkinter 画布中的图形大小可以按照 SO here上的讨论进行更改。我想添加 mplcursors 以将数据悬停在图上。

当我不改变图形大小时, mplcursors 工作。但是,当图形大小增加(例如 30 英寸)时,不会出现 mplcursors 悬停时出现问题。

我怀疑问题是使用带有 mplcursors 的 tkinter 画布滚动条。而且我不确定如何解决它。如果我遗漏了什么,有什么建议或想法吗?


import tkinter as tk
from tkinter import ttk
from tkinter.simpledialog import askfloat
from matplotlib.figure import Figure
from matplotlib.axes   import Axes
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import mplcursors
from matplotlib.colors import to_rgb          

class InteractivePlot(tk.Frame):
    def __init__(self,master,**kwargs):
        super().__init__(master,**kwargs)
        self._figure = Figure(dpi=150)
        self._canvas = FigureCanvasTkAgg(self._figure, master=self)
        buttonframe = tk.Frame(self)
        self._sizebutton = tk.Button(buttonframe,text="Size (in.)", command=self._change_size)
        self._dpibutton = tk.Button(buttonframe,text="DPI", command=self._change_dpi)
        self._axis = self._figure.add_subplot(111)

        # Plot some data just to have something to look at.
        self._axis.plot([0,1,2,3,4,5],[1,1,3,3,5,5],label='Dummy Data')

        self._cwidg = self._canvas.get_tk_widget()
        self._scrx = ttk.Scrollbar(self,orient="horizontal", command=self._cwidg.xview)
        self._scry = ttk.Scrollbar(self,orient="vertical", command=self._cwidg.yview)
        self._cwidg.configure(yscrollcommand=self._scry.set, xscrollcommand=self._scrx.set)

        self._cwidg.bind("<Configure>",self._refresh)

        self._sizebutton.grid(row=0,column=0,sticky='w')
        self._dpibutton.grid(row=0,column=1,sticky='w')
        buttonframe.grid(row=0,column=0,columnspan=2,sticky='W')
        self._cwidg. grid(row=1,column=0,sticky='news')
        self._scrx.  grid(row=2,column=0,sticky='ew')
        self._scry.  grid(row=1,column=1,sticky='ns')

        self.rowconfigure(1,weight=1)
        self.columnconfigure(0,weight=1)

        ## ADDED LINE 
        self.curs = mplcursors.cursor(self._axis,  hover=mplcursors.HoverMode.Transient) # hover=True 


        # Refresh the canvas to show the new plot
        self._canvas.draw()
    
    # Figure size change button callback
    def _change_size(self):
        newsize = askfloat('Size','Input new size in inches')
        if newsize is None:
            return
        w = newsize
        h = newsize/1.8
        self._figure.set_figwidth(w)
        self._figure.set_figheight(h)
        self._refresh()

    # Figure DPI change button callback
    def _change_dpi(self):
        newdpi = askfloat('DPI', 'Input a new DPI for the figure')
        if newdpi is None:
            return
        self._figure.set_dpi(newdpi)
        self._refresh()
    
    # Refresh function to make the figure canvas widget display the entire figure
    def _refresh(self,event=None):
        # Get the width and height of the *figure* in pixels
        w = self._figure.get_figwidth()*self._figure.get_dpi()
        h = self._figure.get_figheight()*self._figure.get_dpi()

        # Generate a blank tkinter Event object
        evnt = tk.Event()
        # Set the "width" and "height" values of the event
        evnt.width = w
        evnt.height = h

        # Set the width and height of the canvas widget
        self._cwidg.configure(width=w,height=h)
        self._cwidg.update_idletasks()

        # Pass the generated event object to the FigureCanvasTk.resize() function
        self._canvas.resize(evnt)
        # Set the scroll region to *only* the area of the last canvas item created.
        # Otherwise, the scrollregion will always be the size of the largest iteration
        # of the figure.
        self._cwidg.configure(scrollregion=self._cwidg.bbox(self._cwidg.find_all()[-1]))
        
root = tk.Tk()

plt = InteractivePlot(root,width=400,height=400)

plt.pack(fill=tk.BOTH,expand=True)

root.mainloop()
4

0 回答 0