0

当我将鼠标悬停在热图的特定元素上时,我想显示它的值。

我已经得到它来显示热图的值,但它也显示了我不想要的信息,当我第一次运行程序时,有很多错误,我不知道为什么。

我已经尝试了各种方法来显示我在网上看到的值,例如datacursor(hover=True)butmplcursors.cursor(hover=True)是唯一一种“有效”的方法。

import tkinter as tk                                                    
from tkinter import ttk
from tkinter import messagebox
import numpy as np
from math import pi
import random
import matplotlib.pyplot as plt

from mpldatacursor import datacursor
import mplcursors

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


import pandas as pd
from openpyxl import load_workbook
from tkinter import filedialog

root = tk.Tk()                                                          
root.title("Stage 2 GUI")                                               
root.geometry("1270x590")  

mapArr = np.zeros([2,2],dtype=float)

mapArr=([113,62,31,63],
        [50,101,72,47],
        [92,10,40,12],
        [83,21,128,16])

xy=(['A','B','C','D','E','F'])


figure, axis = plt.subplots(figsize=(8,7))                              
heatmap = axis.imshow(
    mapArr,cmap="gray",interpolation='nearest',vmin=0, vmax=128)        

heatmap.axes.get_xaxis().set_visible(False)                             
heatmap.axes.get_yaxis().set_visible(False)

cb = figure.colorbar(heatmap)                                           

canvas = FigureCanvasTkAgg(figure, root)                                
canvas.get_tk_widget().place(x=-60,y=-60)                               

mplcursors.cursor(hover=True)

plt.show()

我想显示热图元素的值,但不显示 x 和 y 坐标,但我不确定如何删除/自定义显示的信息,如果我在运行程序时没有错误(即使它技术上确实有效)。

4

3 回答 3

2

您需要决定是要使用 pyplot 还是将 matplotlib 嵌入 tk。以下假设您要嵌入(在这种情况下,不要使用 pyplot !!)。

使用 mplcursors

mplcursors文档解释了如何自定义输出。本质上,它包括连接到一个名为"add".

import numpy as np
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import mplcursors

root = tk.Tk()
root.geometry("1270x590")  

mapArr=np.array(([113,62,31,63],
                 [50,101,72,47],
                 [92,10,40,12],
                 [83,21,128,16]))

xy=(['A','B','C','D','E','F'])


fig = matplotlib.figure.Figure() 
ax = fig.add_subplot()

heatmap = ax.imshow(mapArr,cmap="gray",interpolation='nearest',vmin=0, vmax=128)        

cb = fig.colorbar(heatmap)                                           

canvas = FigureCanvasTkAgg(fig, root)                                
canvas.get_tk_widget().place(x=60,y=60)                               

cursor = mplcursors.cursor(heatmap, hover=True)

@cursor.connect("add")
def on_add(sel):
    i,j = sel.target.index
    sel.annotation.set_text(mapArr[i,j])

tk.mainloop()

手动创建悬停框

您可以在不使用 mplcursors 的情况下执行与上述相同的操作。这将通过创建注释并根据鼠标位置更改其位置和文本来完成。

import numpy as np
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk

root = tk.Tk()
root.geometry("1270x590")  

mapArr=np.array(([113,62,31,63],
                 [50,101,72,47],
                 [92,10,40,12],
                 [83,21,128,16]))

xy=(['A','B','C','D','E','F'])


fig = matplotlib.figure.Figure() 
ax = fig.add_subplot()

heatmap = ax.imshow(mapArr,cmap="gray",interpolation='nearest',vmin=0, vmax=128)        

cb = fig.colorbar(heatmap)                                           

canvas = FigureCanvasTkAgg(fig, root)                                
canvas.get_tk_widget().place(x=60,y=60)                               

annot = ax.annotate("", xy=(0,0), xytext=(20,20), textcoords="offset points",
                    arrowprops=dict(arrowstyle="->"), visible=False,
                    bbox=dict(boxstyle="round", fc="w"))

def hover(event):
    if event.inaxes == ax:
        x,y = event.xdata, event.ydata
        j,i = np.round(np.array((x,y))).astype(int)
        annot.xy = (x,y)
        annot.set_text(str(mapArr[i,j]))
        annot.set_visible(True)
    else:
        annot.set_visible(False)
    fig.canvas.draw_idle()

canvas.mpl_connect("motion_notify_event", hover)

tk.mainloop()
于 2019-07-19T14:01:40.057 回答
0

您可以连接到coursor将更改注释中的文本的功能

cursor = mplcursors.cursor(hover=True)

@cursor.connect("add")
def on_mouse_move(sel):
    x = sel.target[0]
    y = sel.target[1]

    value = sel.artist.get_cursor_data(_Event(x, y))

    sel.annotation.set_text("value {} at ({:1.2f}, {:1.2f})".format(value, x,y))

为了获得它需要的价值namedtuple(我在 Cursor 的源代码中找到了它)

from collections import namedtuple

_Event = namedtuple('_Event', 'xdata ydata')

完整的工作示例(仅需要代码,因此没有错误)

import tkinter as tk                                                    
import matplotlib.pyplot as plt
import mplcursors
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

# --- data ---

mapArr = (
    [113, 62, 31, 63],
    [50, 101, 72, 47],
    [92, 10, 40, 12],
    [83, 21, 128, 16]
)

xy = ('A','B','C','D','E','F')

# --- main ---

root = tk.Tk()                                                          

figure, axis = plt.subplots(figsize=(8, 7))

canvas = FigureCanvasTkAgg(figure, root)                                
canvas.get_tk_widget().pack(fill='both', expand=True)

heatmap = axis.imshow(mapArr, cmap="gray", interpolation='nearest', vmin=0, vmax=128)        
heatmap.axes.get_xaxis().set_visible(False)                             
heatmap.axes.get_yaxis().set_visible(False)

colorbar = figure.colorbar(heatmap)                                           

#--- connect function to cursor

from collections import namedtuple
_Event = namedtuple('_Event', 'xdata ydata')

cursor = mplcursors.cursor(hover=True)

@cursor.connect("add")
def on_mouse_move(sel):
    x = sel.target[0]
    y = sel.target[1]

    value = sel.artist.get_cursor_data(_Event(x, y))

    sel.annotation.set_text("value {} at ({:1.2f}, {:1.2f})".format(value, x,y))

#--- 

root.mainloop()

编辑:使用@ImportanceOfBeingErnest 示例我发现我的版本错误在哪里canvas.mpl_connect(),现在它可以工作了。

此示例显示如何使用Checkbutton打开/关闭注释。

import tkinter as tk                                                    
import matplotlib.pyplot as plt
import mplcursors
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

# --- data ---

mapArr = (
    [113, 62, 31, 63],
    [50, 101, 72, 47],
    [92, 10, 40, 12],
    [83, 21, 128, 16]
)

xy = ('A','B','C','D','E','F')

# --- functions ---

def on_mouse_move(event):
    if checkbuttonvariable.get() == 0:
        return

    if event.inaxes == axis:
        annotation.xy = (event.xdata, event.ydata)
        row = int(round(event.ydata))
        col = int(round(event.xdata))
        value = mapArr[row][col]
        annotation.set_text(str(value))
        annotation.set_visible(True)
    else:
        annotation.set_visible(False)
    canvas.draw()

# --- main ---

root = tk.Tk()                                                          

figure, axis = plt.subplots(figsize=(8, 7))

canvas = FigureCanvasTkAgg(figure, root)                                
canvas.get_tk_widget().pack(fill='both', expand=True)

heatmap = axis.imshow(mapArr, cmap="gray", interpolation='nearest', vmin=0, vmax=128)        
heatmap.axes.get_xaxis().set_visible(False)                             
heatmap.axes.get_yaxis().set_visible(False)

colorbar = figure.colorbar(heatmap)

# ---

annotation = axis.annotate("", xy=(0,0), xytext=(20,20), textcoords="offset points",
                    arrowprops=dict(arrowstyle="->"), visible=False,
                    bbox=dict(boxstyle="round", fc="w"))

canvas.mpl_connect('motion_notify_event', on_mouse_move)

# ---

checkbuttonvariable = tk.IntVar(value=1)
button = tk.Checkbutton(root, text='visible', variable=checkbuttonvariable)
button.pack()


root.mainloop()
于 2019-07-19T13:04:23.913 回答
-1

你总是可以使用袖扣和情节,我相信他们已经内置了这个功能:https ://plot.ly/ipython-notebooks/cufflinks/

于 2019-07-19T12:53:02.780 回答