【问题标题】:Interactive matplotlib plot in PySimpleGUIPySimpleGUI 中的交互式 matplotlib 绘图
【发布时间】:2021-01-31 20:01:54
【问题描述】:

我正在尝试让 RectangleSelector 表单 matplotlib.widgets 与 PySimpleGUI 一起使用。 我的测试代码基于接受的答案on this question 中显示的 RectangleSelector 演示。

我正在 PySimpleGUI 中显示该图,但它不是交互式的。在 PySimpleGUI 中是否有可能拥有交互式 matplotlib 小部件?

import PySimpleGUI as sg
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.widgets  import RectangleSelector
import matplotlib
matplotlib.use('TkAgg')

xdata = np.linspace(0,9*np.pi, num=301)
ydata = np.sin(xdata)

fig, ax = plt.subplots()
line, = ax.plot(xdata, ydata)


def draw_figure(canvas, figure):
    figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
    figure_canvas_agg.draw()
    figure_canvas_agg.get_tk_widget().pack(side="top", fill="both", expand=1)
    return figure_canvas_agg


def line_select_callback(eclick, erelease):
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata

    rect = plt.Rectangle( (min(x1,x2),min(y1,y2)), np.abs(x1-x2), np.abs(y1-y2) )
    ax.add_patch(rect)


rs = RectangleSelector(ax, line_select_callback,
                       drawtype='box', useblit=False, button=[1],
                       minspanx=5, minspany=5, spancoords='pixels',
                       interactive=True)
                       

layout = [[sg.Canvas(key="-CANVAS-")]]

window = sg.Window('test', layout, finalize=True, element_justification='center', font='Helvetica 16')
draw_figure(window["-CANVAS-"].TKCanvas, fig)
event, values = window.read()

编辑:感谢 MikeyB 提供的指针,我现在有了以下代码,它显示了一个交互式绘图,但仍然无法绘制矩形。回调函数似乎没有被触发。新代码如下:

import PySimpleGUI as sg
import numpy as np
from matplotlib.widgets  import RectangleSelector
import matplotlib.figure as figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk

# instantiate matplotlib figure
fig = figure.Figure()
ax = fig.add_subplot(111)
DPI = fig.get_dpi()
fig.set_size_inches(505 * 2 / float(DPI), 707 / float(DPI))

# ------------------------------- This is to include a matplotlib figure in a Tkinter canvas
def draw_figure_w_toolbar(canvas, fig, canvas_toolbar):
    if canvas.children:
        for child in canvas.winfo_children():
            child.destroy()
    if canvas_toolbar.children:
        for child in canvas_toolbar.winfo_children():
            child.destroy()
    figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas)
    figure_canvas_agg.draw()
    toolbar = Toolbar(figure_canvas_agg, canvas_toolbar)
    toolbar.update()
    figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1)


def line_select_callback(eclick, erelease):
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata

    rect = plt.Rectangle( (min(x1,x2),min(y1,y2)), np.abs(x1-x2), np.abs(y1-y2) )
    print(rect)
    ax.add_patch(rect)


class Toolbar(NavigationToolbar2Tk):
    def __init__(self, *args, **kwargs):
        super(Toolbar, self).__init__(*args, **kwargs)


# ------------------------------- PySimpleGUI CODE

layout = [
    [sg.B('start', key='start')],
    [sg.Canvas(key='controls_cv')],
    [sg.Column(
        layout=[
            [sg.Canvas(key='fig_cv',
                       # it's important that you set this size
                       size=(500 * 2, 700)
                       )]
        ],
        background_color='#DAE0E6',
        pad=(0, 0)
    )],
]

window = sg.Window('Test', layout)

while True:
    event, values = window.read()
    print(event, values)
    if event == sg.WIN_CLOSED:
        break
    elif event == 'start':
        x = np.linspace(0, 2 * np.pi)
        y = np.sin(x)
        line, = ax.plot(x, y)
        rs = RectangleSelector(ax, line_select_callback,
                       drawtype='box', useblit=False, button=[1],
                       minspanx=5, minspany=5, spancoords='pixels',
                       interactive=True)
        draw_figure_w_toolbar(window['fig_cv'].TKCanvas, fig, window['controls_cv'].TKCanvas)

window.close()

【问题讨论】:

    标签: matplotlib pysimplegui matplotlib-widget


    【解决方案1】:

    你需要添加

        fig.canvas.draw()
    

    如果您希望在回调触发后更新绘图,请发送到您的回调函数!

    这是您的代码的更新版本,可以正常工作:

    import PySimpleGUI as sg
    import numpy as np
    from matplotlib.widgets  import RectangleSelector
    import matplotlib.figure as figure
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
    import matplotlib.pyplot as plt
    
    # instantiate matplotlib figure
    fig = figure.Figure()
    ax = fig.add_subplot(111)
    DPI = fig.get_dpi()
    fig.set_size_inches(505 * 2 / float(DPI), 707 / float(DPI))
    
    # ------------------------------- This is to include a matplotlib figure in a Tkinter canvas
    def draw_figure_w_toolbar(canvas, fig, canvas_toolbar):
        if canvas.children:
            for child in canvas.winfo_children():
                child.destroy()
        if canvas_toolbar.children:
            for child in canvas_toolbar.winfo_children():
                child.destroy()
        figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas)
        figure_canvas_agg.draw()
        toolbar = Toolbar(figure_canvas_agg, canvas_toolbar)
        toolbar.update()
        figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1)
    
    
    def line_select_callback(eclick, erelease):
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
    
        rect = plt.Rectangle( (min(x1,x2),min(y1,y2)), np.abs(x1-x2), np.abs(y1-y2) )
        print(rect)
        ax.add_patch(rect)
        fig.canvas.draw()
    
    class Toolbar(NavigationToolbar2Tk):
        def __init__(self, *args, **kwargs):
            super(Toolbar, self).__init__(*args, **kwargs)
    
    
    # ------------------------------- PySimpleGUI CODE
    
    layout = [
        [sg.B('start', key='start')],
        [sg.Canvas(key='controls_cv')],
        [sg.Column(
            layout=[
                [sg.Canvas(key='fig_cv',
                           # it's important that you set this size
                           size=(500 * 2, 700)
                           )]
            ],
            background_color='#DAE0E6',
            pad=(0, 0)
        )],
    ]
    
    window = sg.Window('Test', layout)
    
    while True:
        event, values = window.read()
        print(event, values)
        if event == sg.WIN_CLOSED:
            break
        elif event == 'start':
            x = np.linspace(0, 2 * np.pi)
            y = np.sin(x)
            line, = ax.plot(x, y)
            rs = RectangleSelector(ax, line_select_callback,
                           drawtype='box', useblit=False, button=[1],
                           minspanx=5, minspany=5, spancoords='pixels',
                           interactive=True)
            draw_figure_w_toolbar(window['fig_cv'].TKCanvas, fig, window['controls_cv'].TKCanvas)
    
    window.close()
    

    【讨论】:

      【解决方案2】:

      在 PySimpleGUI 中是否有可能拥有交互式 matplotlib 小部件?

      是的。

      项目 GitHub 上的演示程序展示了如何制作交互式 Matplotlib 绘图。

      https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Matplotlib_Embedded_Toolbar.py

      您需要将控件嵌入到窗口中。

      【讨论】:

      • 谢谢!我现在使用这个演示作为起点并更新了我的问题中的代码,但仍然没有任何运气可以绘制任何东西。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 2012-05-29
      • 2018-04-28
      相关资源
      最近更新 更多