【问题标题】:Why can't I draw numpy matrix in tkinter canvas?为什么我不能在 tkinter 画布中绘制 numpy 矩阵?
【发布时间】:2020-08-10 13:51:07
【问题描述】:

我正在尝试使用 numpy、matplotlib 和 tkinter 创建生命游戏。我计划首先询问用户游戏板上将有多少行和列,以及一个单元格会活着产生的概率。输入这些信息后,用户将按下“生成”按钮开始游戏。但是,无论何时按下按钮,都会弹出错误:“AttributeError: 'numpy.ndarray' object has no attribute 'set_canvas'”。我不知道为什么 FigureCanvasTkAgg 不能绘制一个 numpy 矩阵。有没有办法在 tkinter 窗口中绘制一个 numpy 矩阵?这是我的代码:

from tkinter import *
import numpy as np
import matplotlib.pyplot as plt
from board import Board
from PIL import Image, ImageTk
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)

def num():
    n1 = int(t1.get())
    n2 = int(t2.get())
    n3 = int(t3.get()) / 100.00
    initBoard = np.zeros((n1, n2))
    for row in range(0,n1):
            for column in range(0,n2):
                initBoard[row][column] = np.random.choice(np.arange(0, 2), p = [1 - n3, n3])
    #game_board = Board(n1, n2, initBoard)
    canvas = FigureCanvasTkAgg(initBoard, master=root)  # A tk.DrawingArea.
    canvas.draw()
    canvas.get_tk_widget().grid(row = 4, column = 0)
    root.quit()

root = Tk()
root.title('Game of Life')
root.geometry('800x600')
Label(root, text="How many rows?: ").grid(row = 0)
Label(root, text="How many columns?: ").grid(row = 1)
Label(root, text="Probability of spawn (between 0 and 100): ").grid(row = 2)

t1 = Entry(root)
t2 = Entry(root)
t3 = Entry(root)

t1.grid(row = 0, column = 1)
t2.grid(row = 1, column = 1)
t3.grid(row = 2, column = 1)


Button(root, text = 'Generate', command = num).grid(row = 3, column = 1, sticky = W, pady = 4)

fig= plt.figure()
canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().grid(row = 4, column = 0)

mainloop()

【问题讨论】:

    标签: python numpy matplotlib tkinter


    【解决方案1】:

    你的代码至少有两个问题:

    1. 你没有以正确的方式使用FigureCanvasTkAgg,这个类创建了一个包含 matplotlib 图形的画布,你可以将它集成到你的 tkinter 应用程序中。但是,绘制绘图的不是这个类,而是AxesSubplot 类(即Figure 中的子图)。以下是如何创建 matplotlib 图形并将其集成到 tkinter 应用程序中:

      fig = plt.figure()  # matplotlib figure
      ax = fig.subplot_add(111)  # subplot inside figure
      canvas = FigureCanvasTkAgg(fig, master=root)  # integrate the figure in a tkinter widget
      canvas.get_tk_widget().grid(row = 4, column = 0)  # display figure in tkinter app
      

      现在,如果你想在图中绘制一些东西,只需使用ax.plot(...)(或任何其他绘图功能)。在你的情况下,因为你想显示一个二维数组,所以你可能想使用ax.imshow(initBoard)

    2. 您在num() 中退出root,这也会破坏包含您的图形的窗口。我宁愿创建一个Toplevel 向用户询问参数,然后关闭这个顶层,而不是num() 中的根窗口。

    完整代码:

    from tkinter import *  # not a good idea in my opinion, can lead to accidental 
                           # naming conflicts, "import tkinter as tk" is a better alternative
    import numpy as np
    import matplotlib.pyplot as plt
    #~from board import Board
    from PIL import Image, ImageTk
    from matplotlib.backends.backend_tkagg import (
        FigureCanvasTkAgg, NavigationToolbar2Tk)
    
    def num():
        n1 = int(t1.get())
        n2 = int(t2.get())
        n3 = int(t3.get()) / 100.00
        top.destroy()  # close dialog
        initBoard = np.zeros((n1, n2))
        for row in range(0, n1):
            for column in range(0, n2):
                initBoard[row][column] = np.random.choice(np.arange(0, 2), p=[1 - n3, n3])
        #game_board = Board(n1, n2, initBoard)
        ax.imshow(initBoard)  # draw board
        canvas.draw_idle()  # update matplotlib figure
    
    root = Tk()
    root.title('Game of Life')
    root.geometry('800x600')
    # create matplotlib figure
    fig = plt.figure()
    ax = fig.add_subplot(111)  # create axis
    ax.axis('off')
    canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
    canvas.get_tk_widget().grid(row=4, column=0)
    
    # toplevel to choose parameters
    top = Toplevel(root)
    Label(top, text="How many rows?: ").grid(row=0)
    Label(top, text="How many columns?: ").grid(row=1)
    Label(top, text="Probability of spawn (between 0 and 100): ").grid(row=2)
    
    t1 = Entry(top)
    t2 = Entry(top)
    t3 = Entry(top)
    
    t1.grid(row=0, column=1)
    t2.grid(row=1, column=1)
    t3.grid(row=2, column=1)
    
    Button(top, text='Generate', command=num).grid(row=3, column=1, sticky=W, pady=4)
    
    mainloop()
    

    【讨论】:

    • 是的,我现在可以显示我的矩阵了。是否有详细说明 FigureCanvasTkAgg 的用法和属性的资源?我在网上搜了一下,主要的结果就是如何嵌入到Tk中。
    • @James FigureCanvasTkAgg 除了嵌入部分之外不打算使用,其余的都可以使用有据可查的常用 matplotlib 内容。唯一的问题是每次更改绘图刷新图形时都需要调用canvas.draw_idle()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多