В Tkinter Python я хочу создать два фрейма и поместить один поверх другого, а затем вставить график matplotlib в каждый из этих двух фреймов. Это мне удалось сделать. Проблема в том, что при создании эти два кадра всегда кажутся разной высоты (нижний всегда меньше верхнего).
Моя цель — сделать так, чтобы два кадра имели одинаковую высоту.
Вот упрощенная версия кода, которая дает указанный нежелательный результат:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
# Root
root = tk.Tk()
root.state('zoomed')
# Upper frame
canv = tk.Frame(root)
canv.pack()
plt.rcParams["axes.prop_cycle"] = plt.cycler(color=["#4C2A85", "#BE96FF", "#957DAD", "#5E366E", "#A98CCC"])
plt.style.use('ggplot')
L = [i for i in range(10)]
fig, ax = plt.subplots()
l = ax.fill_between(L, L)
ax.set_title("Upper plot")
canvas = FigureCanvasTkAgg(fig, canv)
canvas.draw()
canvas.get_tk_widget().pack()
# Lower frame
canv2 = tk.Frame(root)
canv2.pack()
fig2, ax2 = plt.subplots()
l2 = ax2.fill_between(L, L)
ax2.set_title("Lower plot")
canvas2 = FigureCanvasTkAgg(fig2, canv2)
canvas2.draw()
canvas2.get_tk_widget().pack()
root.mainloop
Спасибо всем, кто готов помочь.
если вы получили widget = canvas.get_tk_widget()
, вы можете установить высоту вручную widget['height'] = 300
и позже widget.pack()
- и то же самое для canvas2
. Но его размер не изменится при изменении размера окна. Нужно будет добавить функцию, которая обновляет высоту при изменении размера окна. Я не проверял, будет ли работать grid()
с rowconfigure(..., weight=1)
другая идея: один FigureCanvasTkAgg
и используйте один subplots()
, чтобы создать два ax1, ax2
, чтобы сделать два сюжета на одном холсте.
Если вы используете grid()
вместо pack()
, чтобы поставить оба Frame
, вы можете использовать root.rowconfigure(.., weight=1)
, чтобы указать, как будет разбиваться высота окна на строки.
И он автоматически изменит размер фрейма height
при изменении размера окна.
root = tk.Tk()
root.rowconfigure(0, weight=1) # `weight/sum_of_all_row_weights` = 1/2 height
root.rowconfigure(1, weight=1) # `weight/sum_of_all_row_weights` = 1/2 height
#root.columnconfigure(0, weight=1) # `weight/sum_of_all_column_weights` = 1/1 width
canv = tk.Frame(root)
canv.grid(column=0, row=0)
#... code ...
canv2 = tk.Frame(root)
canv2.grid(column=0, row=1)
#... code ...
Я тестировал на Linux
без root.state('zoomed')
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
# Root
root = tk.Tk()
#root.state('zoomed')
root.rowconfigure(0, weight=1) # `weight/sum_of_all_row_weights` = 1/2 height
root.rowconfigure(1, weight=1) # `weight/sum_of_all_row_weights` = 1/2 height
#root.columnconfigure(0, weight=1) # `weight/sum_of_all_column_weights` = 1/1 width
# Upper frame
canv = tk.Frame(root)
canv.grid(column=0, row=0)
plt.rcParams["axes.prop_cycle"] = plt.cycler(color=["#4C2A85", "#BE96FF", "#957DAD", "#5E366E", "#A98CCC"])
plt.style.use('ggplot')
L = [i for i in range(10)]
fig, ax = plt.subplots()
l = ax.fill_between(L, L)
ax.set_title("Upper plot")
canvas = FigureCanvasTkAgg(fig, canv)
canvas.draw()
canvas.get_tk_widget().pack()
# Lower frame
canv2 = tk.Frame(root)
canv2.grid(column=0, row=1)
fig2, ax2 = plt.subplots()
l2 = ax2.fill_between(L, L)
ax2.set_title("Lower plot")
canvas2 = FigureCanvasTkAgg(fig2, canv2)
canvas2.draw()
canvas2.get_tk_widget().pack()
root.mainloop()
Обновлено:
И если вам нужно установить определенную высоту
widget = canvas.get_tk_widget()
widget['height'] = 300
widget.pack()
widget2 = canvas2.get_tk_widget()
widget2['height'] = 300
widget2.pack()
и для этого не нужно использовать grid()
, но он не будет изменять его размер при изменении размера окна.
Другая идея: создать один FigureCanvasTkAgg
, но два axis
fig, (ax1, ax2) = plt.subplots(2)
и matplotlib
будет контролировать размер.
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
root = tk.Tk()
#root.state('zoomed')
plt.rcParams["axes.prop_cycle"] = plt.cycler(color=["#4C2A85", "#BE96FF", "#957DAD", "#5E366E", "#A98CCC"])
plt.style.use('ggplot')
L = [i for i in range(10)]
fig, (ax1, ax2) = plt.subplots(2)
canvas = FigureCanvasTkAgg(fig, root)
canvas.draw()
canvas.get_tk_widget().pack(fill='both', expand=True)
l1 = ax1.fill_between(L, L)
ax1.set_title("Upper plot")
l2 = ax2.fill_between(L, L)
ax2.set_title("Lower plot")
fig.tight_layout() # suggestion from @Zakaria comment
root.mainloop()
Это работает, спасибо. Мне пришлось добавить fig.tight_layout() прямо перед последней строкой кода, чтобы предотвратить перекрытие двух подграфиков.
@Закария, спасибо! Я добавил твое предложение в код.
вы пытались использовать
height=
на холсте? Вы пытались записать графики в файл, чтобы проверить, имеют ли они одинаковый размер? Возможно, вам придется скорректировать высоту ваших участков.