如何根据条目的值立即更新 matplotlib 的颜色条范围?

how to instantly update the colorbar range of a matplotlib from values of entries?

我有一个简单的代码来绘制图形。我想手动更改颜色条的范围。 所以,我添加了两个 Entries 并定义了第二个函数 change()。我想在没有第二个按钮的情况下立即更改颜色条。

from tkinter import *
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

root = Tk()
root.geometry("500x500")

Max, Min = IntVar(), IntVar()

label1 = Label(root, text="Max")
label1.place(x=10, y=35)

label2 = Label(root, text="Min")
label2.place(x=10, y=60)

entry1 = Entry(root, textvariable=Max, width=5)
entry1.place(x=50, y=35)

entry2 = Entry(root, textvariable=Min, width=5)
entry2.place(x=50, y=60)

def plot():
    global x, y
    x, y = np.mgrid[slice(0, 100), slice(0, 100)]
    z = (x*y)

    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    c = ax.pcolormesh(x, y, z, cmap='YlGn')
    ax.figure.colorbar(c)

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=0, y=80)

def change():
    z = (x*y)
    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    c = ax.pcolormesh(x, y, z, cmap='YlGn', vmin=entry1.get(), vmax=entry2.get())
    ax.figure.colorbar(c)

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=0, y=80)

button1 = Button(root, text="Plot", command=plot)
button1.place(x=30, y=0)

button2 = Button(root, text="change", command=change)
button2.place(x=80, y=0)

root.mainloop()

我找到了这个post Constantly Update Label Widgets From Entry Widgets TKinter,我尝试使用方法2,我更改了这部分的代码:

...
def auto():
    c.config(vmin=entry1.get(), vmax=entry2.get())

entry1 = Entry(root, textvariable=Max, width=5)
entry1.place(x=50, y=35)

entry2 = Entry(root, textvariable=Min, width=5)
entry2.place(x=50, y=60)

auto()
...

但由于 c 是一个局部变量,所以代码不起作用。谁能帮我立即更新颜色条范围?

所以你最终想要的是在用户更改 Min 和 Max 输入时更改颜色图 vminvmax。您不需要不断更新颜色图,只需更改这些输入即可。

您可以通过使用更新回调跟踪输入更改来做到这一点。

这是修改后的代码,当最小和最大输入更改时更新颜色图:

from tkinter import *

import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

root = Tk()
root.geometry("500x500")

Max, Min = IntVar(), IntVar()

label1 = Label(root, text="Min")
label1.place(x=10, y=35)

label2 = Label(root, text="Max")
label2.place(x=10, y=60)

vmin_entry = Entry(root, textvariable=Min, width=5)
vmin_entry.place(x=50, y=35)

vmax_entry = Entry(root, textvariable=Max, width=5)
vmax_entry.place(x=50, y=60)

# Define global variables
c, canvas = None, None

def plot():
    global x, y, c, canvas
    x, y = np.mgrid[slice(0, 100), slice(0, 100)]
    z = (x * y)
    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    c = ax.pcolormesh(x, y, z, cmap='YlGn')
    ax.figure.colorbar(c)

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=0, y=80)
    canvas.draw()


def update_colormap(*args, **kwargs):
    global c, canvas
    if c is not None:
        try:
            # Get vmin and vmax
            vmin, vmax = int(vmin_entry.get()), int(vmax_entry.get())
        except ValueError:
            # Could not convert values to int, non integer value
            return
        if vmin > vmax:
            return
        # Set new limits
        c.set_clim(vmin, vmax)
        # Update plot
        canvas.flush_events()
        canvas.draw()


# Trace change of Min and Max and call update_colormap as a callabck
Min.trace("w", update_colormap)
Max.trace("w", update_colormap)

button1 = Button(root, text="Plot", command=plot)
button1.place(x=30, y=0)

root.mainloop()

您可以将输入小部件的 "<Key>" 事件绑定到更改函数作为回调,这将在输入小部件中输入任何内容时调用更改函数。

entry1.bind('<Key>', lambda x : change())

对两个条目执行此操作会将这些行添加到您的代码中 -:

entry1.bind('<Key>', lambda x : change())
entry2.bind('<Key>', lambda x : change())

完整代码将变为-:

from tkinter import *
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

root = Tk()
root.geometry("500x500")

Max, Min = IntVar(), IntVar()

label1 = Label(root, text="Max")
label1.place(x=10, y=35)

label2 = Label(root, text="Min")
label2.place(x=10, y=60)

entry1 = Entry(root, textvariable=Max, width=5)
entry1.place(x=50, y=35)

entry2 = Entry(root, textvariable=Min, width=5)
entry2.place(x=50, y=60)

def plot():
    global x, y
    x, y = np.mgrid[slice(0, 100), slice(0, 100)]
    z = (x*y)

    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    c = ax.pcolormesh(x, y, z, cmap='YlGn')
    ax.figure.colorbar(c)

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=0, y=80)

def change():
    z = (x*y)
    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    c = ax.pcolormesh(x, y, z, cmap='YlGn', vmin=entry1.get(), vmax=entry2.get())
    ax.figure.colorbar(c)

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=0, y=80)

button1 = Button(root, text="Plot", command=plot)
button1.place(x=30, y=0)

entry1.bind('<Key>', lambda x : change()) # binding the first entry's keypress event to the change function.
entry2.bind('<Key>', lambda x : change()) # binding the second entry's keypress event to the change function.

root.mainloop()

注意:

只要在小部件内按下某个键,就会触发 "<Key>" 事件的回调,有关详细信息,请查看 events and bindings