Как заставить (3d) интерактивность работать при встраивании фигуры matplotlib в холст tkinter - PullRequest
2 голосов
/ 09 июля 2020

Я встроил трехмерный график matplotlib в холст tkinter gui, но не могу заставить (мышь) интерактивность (поворот / масштабирование и c) работать. Если я просто использую команду pyplot.show () без встраивания в tk, интерактивность работает, нужно ли мне вручную устанавливать все обратные вызовы, чтобы это работало с встраиванием tkinter, или есть простой способ?

Simple пример скрипта, отображающего куб:

import tkinter as tk
from tkinter.ttk import *

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib import pyplot
from mpl_toolkits import mplot3d

import numpy
from stl import mesh


tk_root = tk.Tk()

figure = pyplot.figure()
axes = mplot3d.Axes3D(figure)

data = numpy.zeros(6, dtype=mesh.Mesh.dtype)
data['vectors'][0] = numpy.array([[0, 1, 1],[1, 0, 1],[0, 0, 1]])
data['vectors'][1] = numpy.array([[1, 0, 1],[0, 1, 1],[1, 1, 1]])
data['vectors'][2] = numpy.array([[1, 0, 0],[1, 0, 1],[1, 1, 0]])
data['vectors'][3] = numpy.array([[1, 1, 1],[1, 0, 1],[1, 1, 0]])
data['vectors'][4] = numpy.array([[0, 0, 0],[1, 0, 0],[1, 0, 1]])
data['vectors'][5] = numpy.array([[0, 0, 0],[0, 0, 1],[1, 0, 1]])
msh = mesh.Mesh(data)

axes.add_collection3d(mplot3d.art3d.Poly3DCollection(msh.vectors))
# pyplot.show()

canvas = FigureCanvasTkAgg(figure, tk_root)
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
toolbar = NavigationToolbar2Tk(canvas, tk_root)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

tk_root.mainloop()

Ответы [ 2 ]

1 голос
/ 19 июля 2020

Необходимо повторно привязать / подключить обратные вызовы взаимодействия от объекта холста к объекту осей фигуры

canvas.mpl_connect('button_press_event', view.axes._button_press)
canvas.mpl_connect('button_release_event', view.axes._button_release)
canvas.mpl_connect('motion_notify_event', view.axes._on_move)

, как это было сделано в этом примере:

https://github.com/precise-simulation/mesh-viewer/blob/master/meshviewer_mpl_tk.py#L296 -L298

0 голосов
/ 24 июля 2020

Принятый ответ является допустимым решением вашего вопроса, но я бы рекомендовал не использовать pyplot с tkinter, поскольку это может привести ко всем видам проблем, которые я сам не понимаю (например: закрытие окна tkinter оставит pyplot запущенным ). Вместо этого я бы сделал что-то вроде этого:

import tkinter as tk
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure


data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
X=np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2]])
Y=np.array([[2, 2, 2], [1, 1, 1], [0, 0, 0]])
tk_root = tk.Tk()

figure = Figure(figsize=(12, 8))
ax= figure.add_subplot(1, 1, 1, projection='3d')
ax.plot_surface(data, X, Y, shade=True)
canvas = FigureCanvasTkAgg(figure, tk_root)
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
canvas.mpl_connect('button_press_event', ax._button_press)
canvas.mpl_connect('button_release_event', ax._button_release)
canvas.mpl_connect('motion_notify_event', ax._on_move)

tk_root.mainloop()

Я понимаю, что этот ответ не совсем соответствует контексту вашего вопроса, но это общая идея

...