python - 使用用户 tkinter 输入作为 Matplotlib 坐标绘制一条线
问题描述
我在我的 Tkinter GUI 环境中嵌入了一个 Matplotlib 折线图。我的“实验”基本上从用户那里获取两个输入(数字),然后它应该使用它们来画一条线。但是,我不知道如何根据用户输入绘制折线图。有人可以解释一下怎么做吗?这是我的代码:
from tkinter import *
import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
import numpy as np
root = tk.Tk()
root.geometry('500x700')
first_input = StringVar()
second_input = StringVar()
class Graph():
def linechart():
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
y = [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5]
plt.plot(x, y)
plt.xticks(np.arange(min(x), max(x)+1, 1.0))
plt.show()
class Random(Graph):
def __init__(self):
self.label1 = None
self.label2 = None
self.userEntry = None
def first_input(self):
self.label1 = ttk.Label(text="Insert:")
self.label1.pack()
self.userEntry = ttk.Entry(textvariable=first_input)
self.userEntry.pack()
self.button_2 = Button(root, text="Enter", command=self.second_input)
self.button_2.pack()
def second_input(self):
self.label2 = ttk.Label(text="Insert:")
self.label2.pack()
self.userEntry = ttk.Entry(textvariable=second_input)
self.userEntry.pack()
self.button_3 = Button(root, text="Enter", command=self.create_window)
self.button_3.pack()
def create_window(self):
Graph.linechart()
random = Random()
button_1 = Button(root, text="random", command=lambda:random.first_input())
button_1.pack()
root.mainloop()
解决方案
以下是如何在 tkinter 框架中嵌入 matplotlib 图,根据用户输入的坐标在此图上绘制线条,并直接在 tkinter 级别覆盖轴:
另请参阅matplotlib 文档以获取更简单的示例。
彩色线条绘制在嵌入在 tkinter 画布中的 matplotlib 图形上,一条线从 绘制p0=(0, 0), p1=(500, 500)
,另一条线从p0=(0, 500), p1=(500, 0)
. (从弹出窗口输入)
黑白叠加层直接绘制在 tkinter 画布上
import matplotlib as mpl
import tkinter as tk
import matplotlib.backends.tkagg as tkagg
from matplotlib.backends.backend_agg import FigureCanvasAgg
def draw_figure(canvas, figure, loc=(0, 0)):
""" Draw a matplotlib figure onto a Tk canvas
loc: location of top-left corner of figure on canvas in pixels.
Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py
"""
figure_canvas_agg = FigureCanvasAgg(figure)
figure_canvas_agg.draw()
figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds
figure_w, figure_h = int(figure_w), int(figure_h)
photo = tk.PhotoImage(master=canvas, width=figure_w, height=figure_h)
canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo)
tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)
return photo
class LineCoordsEntry(tk.Toplevel):
def __init__(self, master):
self.master = master
super().__init__(self.master)
self.label_x0 = tk.Label(self, text='x0:')
self.label_x0.grid(row=0, column=0)
self.entry_x0 = tk.Entry(self, width=6)
self.entry_x0.grid(row=0, column=1)
self.label_y0 = tk.Label(self, text='y0:')
self.label_y0.grid(row=0, column=2)
self.entry_y0 = tk.Entry(self, width=6)
self.entry_y0.grid(row=0, column=3)
self.label_x1 = tk.Label(self, text='x1:')
self.label_x1.grid(row=1, column=0)
self.entry_x1 = tk.Entry(self, width=6)
self.entry_x1.grid(row=1, column=1)
self.label_y1 = tk.Label(self, text='y1:')
self.label_y1.grid(row=1, column=2)
self.entry_y1 = tk.Entry(self, width=6)
self.entry_y1.grid(row=1, column=3)
self.quit_button = tk.Button(self, text='quit', command=self.destroy)
self.quit_button.grid(row=2, column=0)
self.validate_button = tk.Button(self, text='validate', command=self.send_data)
self.validate_button.grid(row=2, column=1, columnspan=3)
def send_data(self):
p0 = float(self.entry_x0.get()), float(self.entry_y0.get())
p1 = float(self.entry_x1.get()), float(self.entry_y1.get())
self.master.retrieve_line_data(p0, p1)
class App(tk.Frame):
def __init__(self, master, w=500, h=500):
self.master = master
super().__init__(self.master)
self.w = w
self.h = h
self.canvas = tk.Canvas(self.master, width=self.w, height=self.h)
self.canvas.pack()
self.enter_line_coordinates_button = tk.Button(self, text='make new line', command=self.spawn_entry_coordinates)
self.enter_line_coordinates_button.pack()
self.draw_lines_button = tk.Button(self, text='draw lines', command=self.draw_lines)
self.draw_lines_button.pack()
self.draw_overlay_button = tk.Button(self, text='draw overlaid axis', command=self.draw_overlay)
self.draw_overlay_button.pack()
self.erase_overlay_button = tk.Button(self, text='remove overlaid axis', command=self.erase_overlay)
self.erase_overlay_button.pack()
self.lines = []
def spawn_entry_coordinates(self):
LineCoordsEntry(self)
def retrieve_line_data(self, p0, p1):
self.lines.append((p0, p1))
print(self.lines)
def draw_lines(self):
"""draw the lines on the matplotlib canvas
"""
fig = mpl.figure.Figure(figsize=(5, 5))
ax = fig.add_axes([0, 0, 1, 1])
for p0, p1 in self.lines:
x0, y0, x1, y1 = *p0, *p1
X = x0, x1
Y = y0, y1
print(X, Y)
ax.plot(X, Y)
self.fig_x, self.fig_y = 0, 0 #self.w, self.h
self.fig_photo = draw_figure(self.canvas, fig, loc=(self.fig_x, self.fig_y))
self.fig_w, self.fig_h = self.fig_photo.width(), self.fig_photo.height()
def draw_overlay(self):
"""draw lines on the tkinter canvas, overlaid on the matplotlib canvas
"""
self.canvas.create_line(0, self.h//2, self.w, self.h//2, tags=('overlay',))
self.canvas.create_line(self.w//2, 0, self.w//2, self.h, tags=('overlay',))
def erase_overlay(self):
self.canvas.delete('overlay')
root = tk.Tk()
App(root).pack()
root.mainloop()
推荐阅读
- xamarin - 以单独的形式使用 App 类中的方法 xamarin
- c++ - 解构 SDL_Texture 是否调用 SDL_DestroyTexture?
- nginx - Nginx Laravel 和 phpmyadmin 配置
- bootstrap-4 - 如何修复只有div没有表单的搜索表单
- java - 模拟器无法启动:等待设备时出错
- reactjs - 找不到模块:无法解析“C:\Users\adcal\dvmtn7\myapp\node_modules\react-dom\cjs”中的“计划”
- three.js - three.js 骨骼控制/可视化和骨骼动画
- r - R中嵌套循环的输出结果
- ios - 如何解析单个 JSON 对象数组?
- javascript - 画布脉冲动画效果