【问题标题】:How can I use Tkinter to visualise time-series data?如何使用 Tkinter 可视化时间序列数据?
【发布时间】:2017-10-17 18:49:24
【问题描述】:

我正在尝试使用 Tkinter 来可视化一些时间序列数据。我的数据是二维矩阵的形式,行代表块,列代表某个时间段。所有值都在 0 和 1 之间。

我想使用 Tkinter 创建一个 python 脚本,它创建一个窗口,以方矩阵显示块,第一列确定每个块的亮度,然后在预定的时间后,根据改变块的亮度到数据中的连续列。

我已经创建了迄今为止的精简版:

#!/usr/bin/python

import sys
import os.path
import Tkinter as tk
import math

# program constants
WINDOW_WIDTH = 900

# function to change the colours of the blocks based on current period
def redrawPeriod(t):
    for b in xrange(len(blocks)):
        luminance = int(blocks[b][t] * 255)
        colour = "#%x%x%x" % (luminance,luminance,luminance)
        canvas.itemconfig(block_ids[b],fill=colour)

# sample data (4 blocks 4 periods)
blocks = [
        [0.0, 0.2, 0.5, 0.8],
        [0.3, 0.0, 0.4, 0.0],
        [0.5, 0.7, 0.0, 1.0],
        [0.0, 0.0, 0.3, 0.6],
        [1.0, 0.5, 0.2, 0.9]
      ]

# get number of blocks and periods
nB = len(blocks)
nT = len(blocks[0])

n_cols = int(math.sqrt(nB))
n_rows = n_cols

# if not perfect square number of blocks, add extra row
if (nB % n_rows != 0):
    n_rows = n_rows + 1

# calculate block size
BLOCK_SIZE = WINDOW_WIDTH / n_cols
WINDOW_HEIGHT = BLOCK_SIZE * n_rows

# initialise Tkinter
root = tk.Tk()

# initialise canvas
canvas = tk.Canvas(root, width=WINDOW_WIDTH, height=WINDOW_HEIGHT, background="#002080")

# open canvas
canvas.pack()

# container for block objects
block_ids = []

x = 0
y = -1*BLOCK_SIZE

# initialise block objects
for b in xrange(nB):
    if (b % n_cols == 0):
        x = 0
        y = y + BLOCK_SIZE

    luminance = int(blocks[b][0] * 255)
    colour = "#%x%x%x" % (luminance,luminance,luminance)
    id = canvas.create_rectangle(x, y, x+BLOCK_SIZE, y+BLOCK_SIZE, outline="",fill = colour)
    block_ids.append(id)
    x = x + BLOCK_SIZE

for t in xrange(nT):
    root.after(1000, redrawPeriod,t)

root.mainloop()

这似乎做了我想做的事,但是每次它都会直接跳到最后一帧 - 即。它不会绘制一帧、暂停、绘制另一帧、再次暂停等。

谁能帮我弄清楚我做错了什么?

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    你的问题是当你打电话时:

    for t in xrange(nT):
        root.after(1000, redrawPeriod,t)
    

    root.after() 不会阻塞执行,因此 for 循环执行得非常快,并且在 1000 毫秒后会同时调用所有重绘事件。

    在 Tkinter 中运行动画的常用方法是编写一个动画方法,该方法会在延迟后调用自身(有关更多信息,请参阅 Method for having animated movement for canvas objects pythonTkinter, executing functions over time)。

    在你的情况下,你可以这样做:

    # Create all widgets
    ...
    
    # Store the period indices to be redrawn ([0, 1, 2, ..., nT-1])
    periods = range(nT)
    
    # Define the animation method
    def animation_loop(delay):
        # Check if there are still periods to be drawn
        if len(periods) > 0:
            t = periods[0]
            redrawPeriod(t)
            # Remove the period that was just drawn from the list of periods
            del periods[0]
            # Call the animation_loop again after a delay
            root.after(delay, animation_loop, delay)
    
    # Start the animation loop
    animation_loop(1000)
    
    # Launch the app
    root.mainloop()
    

    【讨论】:

    • 谢谢,效果很好。我曾假设“root.after()”调用暂停了执行。但显然不是这样!再次感谢..
    猜你喜欢
    • 2016-04-10
    • 2021-09-15
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 2017-12-14
    • 2018-03-17
    相关资源
    最近更新 更多