3D-графики Python Tkinter не могут перемещаться или масштабироваться

Я пытался включить 2d/3d-графики с помощью matplotlib в свое приложение с графическим интерфейсом Python с помощью TKinter и добился успеха с 2d-графиками, но не с 3d-графиками. Моя проблема заключается в том, что ни один из 3D-графиков нельзя панорамировать или масштабировать, хотя кнопки на панели навигации реагируют на нажатия кнопок. Вот пример кода, демонстрирующий мою проблему:

import tkinter as tk

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np

root = tk.Tk()
frame = tk.Frame(root)
frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

#uncomment as needed to demonstrate 2d/3d plot
#subplot_kw = {'projection':'3d'}
subplot_kw = {}
fig, ax = plt.subplots(subplot_kw=subplot_kw)
if len(subplot_kw) > 0:
    ax.plot(range(100), np.random.rand(100), np.random.rand(100))
else:
    ax.plot(range(100), np.random.rand(100))

canvas = FigureCanvasTkAgg(fig, frame)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)

toolbar = NavigationToolbar2Tk(canvas, frame)
toolbar.update()

root.mainloop()

Поэтому, когда я рисую 2d, используя приведенный выше код, панорамирование/масштабирование работает, как и ожидалось. Когда я изменил прокомментированные строки и использовал 3D-график, панорамирование/масштабирование не работает. Я упустил что-то простое или есть проблема с 3D-панорамированием/масштабированием в tkinter с matplotlib?


person randomuser343884    schedule 09.01.2019    source источник


Ответы (1)


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

UserWarning: Axes3D.figure.canvas is 'None', mouse rotation disabled. Set canvas then call Axes3D.mouse_init().

По сути, это означает, что вам нужно либо вызвать mouse_init(), либо просто создать 3D-оси после настройки холста. Последний показан ниже.

import tkinter
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_tkagg import (
                                    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure

root = tkinter.Tk()
root.wm_title("Embedding in Tk")

fig = Figure(figsize=(5, 4), dpi=100)

canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
canvas.draw()

ax = fig.add_subplot(111, projection="3d")
t = np.arange(0, 3, .01)
ax.plot(t, 2 * np.sin(2 * np.pi * t))

toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)


tkinter.mainloop()
person ImportanceOfBeingErnest    schedule 10.01.2019
comment
Спасибо! Я видел пример кода, который вы указали, и не понял, почему pyplot не использовался, как и в других примерах, которые явно отображают цифры. Я обновлю все графики в своем графическом интерфейсе, чтобы напрямую создавать объекты Figure() вместо использования pyplot. - person randomuser343884; 10.01.2019
comment
Кроме того, знаете ли вы, почему canvas.get_tk_widget().pack() вызывается дважды? Я не вижу объяснения в примере и не могу найти его в документации. Я не заметил разницы ни с одной из двух закомментированных строк. - person randomuser343884; 10.01.2019
comment
Да, это, вероятно, оплошность в примере. Я отредактировал свой код выше. - person ImportanceOfBeingErnest; 10.01.2019