Я пытаюсь отобразить 4-5 гистограмму Matplotlib в окне Tkinter. Но почему-то в рамку помещаются только 3. Пожалуйста, найдите приведенный ниже код.
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
frame_top = tk.Frame(root)
frame_top.pack(fill='both', expand=True)
fig = Figure(dpi=100) # figsize=(10, 6),
fig.add_subplot(111).plot(x, y)
# fig.add_subplot(111).plot(AS)
canvas = FigureCanvasTkAgg(fig, master=frame_top) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side = "left",fill='both', expand=True)
fig1 = Figure(dpi=100) # figsize=(10, 6),
fig1.add_subplot(111).plot(x, y)
# fig.add_subplot(111).plot(AS)
canvas1 = FigureCanvasTkAgg(fig1, master=frame_top) # A tk.DrawingArea.
canvas1.draw()
canvas1.get_tk_widget().pack(side = "left",fill='both', expand=True)
fig2 = Figure(dpi=100) # figsize=(10, 6),
fig2.add_subplot(111).plot(x, y)
# fig.add_subplot(111).plot(AS)
canvas2 = FigureCanvasTkAgg(fig2, master=frame_top) # A tk.DrawingArea.
canvas2.draw()
canvas2.get_tk_widget().pack(side = "left",fill='both', expand=True)
fig3 = Figure(dpi=100) # figsize=(10, 6),
fig3.add_subplot(111).plot(x, y)
# fig.add_subplot(111).plot(AS)
canvas3 = FigureCanvasTkAgg(fig3, master=frame_top) # A tk.DrawingArea.
canvas3.draw()
canvas3.get_tk_widget().pack(side = "left",fill='both', expand=True)
# toolbar = NavigationToolbar2Tk(canvas, frame_top)
# toolbar.update()
# tool = tk.Button(toolbar, text = "my tool")
# tool.pack(side='left')#, fill='x', expand=True)
root.mainloop()
Пробовал использовать горизонтальную полосу прокрутки, но она тоже почему-то не работает. Если есть какие-либо другие предложения или какой-либо другой способ показать несколько гистограмм внутри фрейма.
в вашем коде я вижу только 3 графика - так где же остальные? Покажите код, который действительно создает проблему.
возможно, создайте только один рисунок с 5 подграфиками. И он может автоматически вместить все графики на рисунке.
код мог бы быть короче и проще в использовании, если бы вы использовали for
-цикл для создания всех графиков и сохраняли бы их в списке - вместо отдельных переменных canvas1,canvas2,canvas3
fig1,fig2,fig3
и т. д.
возможно, используйте grid()
вместо pack()
— это позволяет установить weight
для всех столбцов, и они должны иметь одинаковую ширину. ИЛИ вам придется вручную добавлять ширину к каждому графику canvas3.get_tk_widget()['width'] = 100
, но размер может не рассчитываться автоматически
В моем Linux помогает, когда я присваиваю любое значение (событие 1
) ширине всего холста.
canvas.get_tk_widget()['width'] = 1
canvas1.get_tk_widget()['width'] = 1
canvas2.get_tk_widget()['width'] = 1
canvas3.get_tk_widget()['width'] = 1
Минимальный рабочий код с 10 графиками
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
frame_top = tk.Frame(root)
frame_top.pack(fill='both', expand=True)
plots = []
for _ in range(10):
fig = Figure(dpi=100) # figsize=(10, 6),
fig.add_subplot(111).plot(x, y)
# fig.add_subplot(111).plot(AS)
canvas = FigureCanvasTkAgg(fig, master=frame_top) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side = "left", fill='both', expand=True)
canvas.get_tk_widget()['width'] = 1
plots.append({'fig': fig, 'canvas': canvas})
root.mainloop()
Результат:
Но это не так полезно, потому что все участки маленькие.
Это также работает, когда я помещаю все графики на один холст.
for i in range(10):
fig.add_subplot(1, 10, i+1).plot(x, y)
Но это может быть бесполезно, если вы планируете добавить панели инструментов или переместить/закрыть некоторые графики.
Полный рабочий код:
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
frame_top = tk.Frame(root)
frame_top.pack(fill='both', expand=True)
plots = []
fig = Figure(dpi=100) # figsize=(10, 6),
canvas = FigureCanvasTkAgg(fig, master=frame_top) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side = "left", fill='both', expand=True)
for i in range(10):
line = fig.add_subplot(1, 10, i+1).plot(x, y)
plots.append(line)
root.mainloop()
Используя grid()
, мне нужно было установить правильное значение ширины и высоты, поэтому я использовал событие <Configure>
, чтобы сделать это при создании (или изменении размера) окна.
Но с grid()
я могу разложить это во много рядов.
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- functions ---
def resize_widgets(event):
#print(dir(event))
print(event.widget, event.width/5, event.height/2)
for row in range(2):
for col in range(5):
widget = plots[(row,col)]['canvas'].get_tk_widget()
widget['width'] = event.width / 5
widget['height'] = event.height / 2
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
frame_top = tk.Frame(root)
frame_top.pack(fill='both', expand=True)
plots = {}
for row in range(2):
for col in range(5):
fig = Figure(dpi=100) # figsize=(10, 6),
fig.add_subplot(111).plot(x, y)
#fig.add_subplot(212).plot(x, AS)
canvas = FigureCanvasTkAgg(fig, master=frame_top) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().grid(row=row, column=col)
#canvas.get_tk_widget()['width'] = 200
#canvas.get_tk_widget()['height'] = 500
plots[(row,col)] = {'fig': fig, 'canvas': canvas}
frame_top.bind('<Configure>', resize_widgets)
root.mainloop()
Работает также, когда я устанавливаю weight=1
для каждой строки и столбца в grid()
- и в этом нет необходимости <Configure>
- так что это кажется самым простым методом.
for row in range(2):
frame_top.rowconfigure(row, weight=1)
for col in range(5):
frame_top.columnconfigure(col, weight=1)
Полный рабочий код:
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
frame_top = tk.Frame(root)
frame_top.pack(fill='both', expand=True)
plots = {}
for row in range(2):
frame_top.rowconfigure(row, weight=1)
for col in range(5):
frame_top.columnconfigure(col, weight=2)
frame_top.columnconfigure(0, weight=1) # resize first column
frame_top.columnconfigure(4, weight=1) # resize last column
for row in range(2):
for col in range(5):
fig = Figure(dpi=100) # figsize=(10, 6),
fig.add_subplot(111).plot(x, y)
#fig.add_subplot(212).plot(x, AS)
canvas = FigureCanvasTkAgg(fig, master=frame_top) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().grid(row=row, column=col)
plots[(row,col)] = {'fig': fig, 'canvas': canvas}
root.mainloop()
Это позволяет задавать разные размеры, используя пропорции - например. первый и последний столбец в 2 раза шире.
for col in range(5):
frame_top.columnconfigure(col, weight=2)
frame_top.columnconfigure(0, weight=1)
frame_top.columnconfigure(4, weight=1)
Другим решением может быть установка Frame
на tkinter.Canvas
и использование скроллеров для перемещения по холсту — таким образом график может быть больше размера окна. Но это требует дополнительной работы — например, мой класс ScrolledFrame на GitHub.
Привет, Фурас, спасибо. Теперь я могу показать несколько диаграмм, но я пробовал аналогичный подход с полосой прокрутки, но он не работает. Найдите ветку ниже stackoverflow.com/questions/78656980/…
если вы хотите прокручивать все элементы в окне, вам следует поместить все графики в один tkinter.Frame
, а в этот кадр вставить tkinter.Canvas
и прокрутить его. Но кажется, вы пытаетесь прокручивать каждый сюжет отдельно. Если вы хотите прокручивать данные/строку на графике, то у него есть собственные функции для перехвата событий мыши и выполнения функции, которая будет изменять данные на графике - у него даже есть панель инструментов, инструменты для масштабирования и прокрутки данных.
Вы можете уменьшить диаграммы или объединить их. И как вы пытались добавить полосу прокрутки? Почему это не работает?