Прямо сейчас я использую Tkinter как интерфейсную среду для отображения данных, поступающих через очередь. Затем эти данные выводятся на экран с помощью функции draw () и т. Д.
В цикле используется функция Tkinters after, которая вызывает определенную функцию через n миллисекунд. У меня такое ощущение, что при вызове уничтожения или просто закрытии окна этот цикл останавливается? Причинение некоторого внутреннего процесса неудовлетворительным.
Я разместил код ниже, так как вы пропустите абстрактный класс. Удаление (Updater) и супер в init удовлетворит его, так как абстрактный класс больше похож на интерфейс.
Воспроизведение проблемы: Во время выполнениявремя выполнения сценария, если окно Tkinter закрыто любым доступным способом, прежде чем выводить все данные из очереди на график. Скрипт никогда не возвращается в командную строку и навсегда застрял. Эта ситуация неблагоприятна, так как я могу выйти из окна и ожидать, что процесс будет уничтожен.
Дальнейшее отслеживание: При неудачной передаче oscy.run () программа быстро завершает работу, но не возвращается в командную строку;как видно из запуска и быстрого выхода из программы до завершения. Это начинает намекать на то, что происходит в init ?
from __future__ import division
import logging
import atexit
import matplotlib
import numpy as np
matplotlib.use('TkAgg')
from functools import wraps
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from Tkinter import Scale, Button, Tk, TOP, BOTTOM, BOTH, HORIZONTAL
class Oscilloscope():
""" Displays the Oscilloscope provided the data streaming in. """
def __init__(
self,
data_queue,
closed_callback,
title="DRP",
xlabel="Range Cells",
ylabel="Magnitude"
):
"""
Initialization function for the Osc oscilloscope.
:param data_queue: List data representative of magnitudes per update.
:type data_queue: Queue
:param closed_callback: When the figure is closed, callback should be used to remove the figure.
:type closed_callback: Function
:param title: Title of the plot being drawn for the Oscilloscope.
:type title: String
:param xlabel: X-axis of the plot being drawn, should either be Range or Doppler.
:type xlabel: String
:param ylabel: Y-axis of the plot being drawn, should always be Magnitude.
:type ylabel: String
"""
self.data_queue = data_queue
self.closed_callback = closed_callback
self.window = Tk()
atexit.register(self.closed_callback)
self.title = title
self.xlabel = xlabel
self.ylabel = ylabel
self.y_limits = np.array([0, np.finfo(np.float).eps])
def _adjust_ylim_if_req(self, magnitude):
"""
Changes the limits based on magnitudes.
:param magnitude: Size of the magnitude being plotted.
:type magnitude: Float
"""
if magnitude < self.y_limits[0]:
self.y_limits[0] = magnitude
elif magnitude > self.y_limits[1]:
self.y_limits[1] = magnitude
self.ax.set_ylim(self.y_limits[0], self.y_limits[1])
def draw(self):
"""
Draws the main line plot.
"""
try:
magnitudes = self.data_queue.get_nowait()
except:
pass
else:
# Adjust y limits
for magnitude in magnitudes:
self._adjust_ylim_if_req(magnitude)
# Plot the graph
self.ax.cla()
self.ax.set_title(self.title, fontdict={'fontsize': 16, 'fontweight': 'medium'})
self.ax.set_xlabel(self.xlabel, fontdict={'fontsize': 12, 'fontweight': 'medium'})
self.ax.set_ylabel(self.ylabel, fontdict={'fontsize': 12, 'fontweight': 'medium'})
self.ax.plot([n for n in range(len(magnitudes))], magnitudes, '-bo')
def run(self):
"""
Sets up and runs the main logic of the Window
"""
self.plot()
self.updateplot()
self.window.mainloop()
def plot(self):
"""
Creates the initial base plot
"""
figure = matplotlib.figure.Figure()
self.ax = figure.add_subplot(1,1,1)
self.ax.set_title(self.title, fontdict={'fontsize': 16, 'fontweight': 'medium'})
self.ax.set_xlabel(self.xlabel, fontdict={'fontsize': 12, 'fontweight': 'medium'})
self.ax.set_ylabel(self.ylabel, fontdict={'fontsize': 12, 'fontweight': 'medium'})
self.canvas = FigureCanvasTkAgg(figure, master=self.window)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
self.draw()
def close_fig():
self.window.destroy()
self.closed_callback
button = Button(self.window, text='Close', command=close_fig)
button.pack()
def updateplot(self):
"""
Updates the plot by gathering more data from the Queue.
"""
print('Start')
self.draw()
self.canvas.draw()
self.window.after(1, self.updateplot)
print('End')
if __name__ == '__main__':
from threading import Thread
from multiprocessing import Queue
q = Queue()
for i in xrange(100):
l = []
for i in xrange(1000):
l.append(np.random.randint(0, 100))
q.put(l)
def cb():
print('Closed')
oscy = Oscilloscope(q, cb)
oscy.run()
