|
- from tkinter import ttk
- import tkinter.messagebox
- import tkinter as tk
- import queue
-
- from matplotlib.backends.backend_tkagg import (
- FigureCanvasTkAgg, NavigationToolbar2Tk)
- from matplotlib.figure import Figure
- import matplotlib.animation as animation
- import matplotlib.pyplot as plt
- import matplotlib
- matplotlib.use("TkAgg")
-
-
- class CurvatureScope(tk.Frame):
- def __init__(self, parent, config, **options):
- """
- Required keys in config:
- title, xlabel, ylabel
- """
- tk.Frame.__init__(self, parent, **options)
- self._config = config
- self._parent = parent
-
- self._interval = 30
-
- self._lines = {'major': [[], []], 'minor': [[], []]}
- self._line_objs = []
-
- self._y_filter_limit = 0.5 if 'y_filter_limit' not in self._config else self._config['y_filter_limit']
-
- self._msg_queue = queue.Queue()
-
- if 'interval' in self._config:
- self._interval = self._config['interval']
-
- self._setup_ui()
-
- def put_msg(self, obj):
- """Caution: Always run in sub-thread"""
- self._msg_queue.put_nowait(obj)
-
- def clear(self):
- for line in self._lines.values():
- line[0].clear()
- line[1].clear()
-
- self._fig.canvas.draw()
- self._fig.canvas.flush_events()
-
- def _setup_ui(self):
- self._fig = plt.figure(figsize=(5, 4), dpi=100)
- self._ax = self._fig.add_subplot()
-
- self._ax.set_title(self._config['title'])
- self._ax.set_xlabel(self._config['xlabel'])
- self._ax.set_ylabel(self._config['ylabel'], color='blue')
- self._ax.tick_params(axis='y', colors='blue')
-
- self._minor_ax = self._ax.twinx()
- self._minor_ax.set_ylabel(self._config['rylabel'], color='red')
- self._minor_ax.tick_params(axis='y', colors='red')
- self._minor_ax.set_ylim(self._config['rylim'][0], self._config['rylim'][1])
-
- self._ax.grid(True)
-
- if 'xlim' not in self._config and 'ylim' not in self._config:
- self._ax.autoscale()
-
- if 'xlim' in self._config:
- self._ax.set_xlim(self._config['xlim'][0], self._config['xlim'][1])
-
- if 'ylim' in self._config:
- self._ax.set_ylim(self._config['ylim'][0], self._config['ylim'][1])
-
- self._line_objs.append(self._ax.plot([], [], color='blue')[0])
- self._line_objs.append(self._minor_ax.plot([], [], color='red')[0])
-
- self.show()
-
- def _update_data(self, data):
- major_line = self._lines['major']
- minor_line = self._lines['minor']
-
- while self._msg_queue.qsize() > 0:
- (x, y), (mx, my) = self._msg_queue.get_nowait()
- major_line[0].append(x)
- major_line[1].append(y)
-
- minor_line[0].append(mx)
- minor_line[1].append(my)
-
- self._line_objs[0].set_data(major_line[0], major_line[1])
- self._line_objs[1].set_data(minor_line[0], minor_line[1])
-
- return self._line_objs
-
- def show(self):
- canvas = FigureCanvasTkAgg(self._fig, self)
-
- if 'toolbar' in self._config and self._config['toolbar']:
- toolbar = NavigationToolbar2Tk(canvas, self)
- toolbar.update()
-
- canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
-
- self._animation = animation.FuncAnimation(
- fig=self._fig, func=self._update_data, interval=self._interval, blit=True)
-
- class LkaScope(tk.Frame):
- def __init__(self, parent, config, **options):
- """
- Required keys in config:
- title, xlabel, ylabel
- """
- tk.Frame.__init__(self, parent, **options)
- self._config = config
- self._parent = parent
-
- self._interval = 30
-
- self._lines = []
- for i in self._config['colors']:
- self._lines.append([[], []])
- self._line_objs = []
-
- self._y_filter_limit = 0.5 if 'y_filter_limit' not in self._config else self._config['y_filter_limit']
-
- self._msg_queue = queue.Queue()
-
- if 'interval' in self._config:
- self._interval = self._config['interval']
-
- self._setup_ui()
-
- def put_msg(self, obj):
- """Caution: Always run in sub-thread"""
- self._msg_queue.put_nowait(obj)
-
- def clear(self):
- for line in self._lines:
- line[0].clear()
- line[1].clear()
-
- self._fig.canvas.draw()
- self._fig.canvas.flush_events()
-
- def _setup_ui(self):
- self._fig = plt.figure(figsize=(5, 4), dpi=100)
- self._ax = self._fig.add_subplot()
-
- self._ax.set_title(self._config['title'])
- self._ax.set_xlabel(self._config['xlabel'])
- self._ax.set_ylabel(self._config['ylabel'])
-
- self._ax.grid(True)
-
- if 'xlim' not in self._config and 'ylim' not in self._config:
- self._ax.autoscale()
-
- if 'xlim' in self._config:
- self._ax.set_xlim(self._config['xlim'][0], self._config['xlim'][1])
-
- if 'ylim' in self._config:
- self._ax.set_ylim(self._config['ylim'][0], self._config['ylim'][1])
-
- for i in range(len(self._lines)):
- self._line_objs.append(self._ax.plot(self._lines[i][0], self._lines[i][1], color=self._config['colors'][i], label=self._config['labels'][i])[0])
-
- self._ax.legend(self._line_objs, [l.get_label() for l in self._line_objs])
-
- self.show()
-
- def collision(self, enabled: bool) -> None:
- self._ax.set_xlabel(self._config['xlabel'], color='red' if enabled else 'black')
-
- def _update_data(self, data):
- while self._msg_queue.qsize() > 0:
- lines = self._msg_queue.get_nowait()
- i = 0
- for line in lines:
- self._lines[i][0].append(line[0])
- if line[1] < 0:
- if len(self._lines[i][1]) > 0:
- self._lines[i][1].append(self._lines[i][1][-1])
- else:
- self._lines[i][1].append(0.0)
- else:
- self._lines[i][1].append(line[1])
- i += 1
-
- for i in range(len(self._lines)):
- self._line_objs[i].set_data(self._lines[i][0], self._lines[i][1])
-
- return self._line_objs
-
- def show(self):
- canvas = FigureCanvasTkAgg(self._fig, self)
-
- if 'toolbar' in self._config and self._config['toolbar']:
- toolbar = NavigationToolbar2Tk(canvas, self)
- toolbar.update()
-
- canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
-
- self._animation = animation.FuncAnimation(
- fig=self._fig, func=self._update_data, interval=self._interval, blit=True)
|