Как создать два фрейма (сверху и снизу) одинаковой высоты с помощью Tkinter?

В 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

Спасибо всем, кто готов помочь.

вы пытались использовать height= на холсте? Вы пытались записать графики в файл, чтобы проверить, имеют ли они одинаковый размер? Возможно, вам придется скорректировать высоту ваших участков.

furas 04.05.2024 10:32

если вы получили widget = canvas.get_tk_widget(), вы можете установить высоту вручную widget['height'] = 300 и позже widget.pack() - и то же самое для canvas2. Но его размер не изменится при изменении размера окна. Нужно будет добавить функцию, которая обновляет высоту при изменении размера окна. Я не проверял, будет ли работать grid() с rowconfigure(..., weight=1)

furas 04.05.2024 10:46

другая идея: один FigureCanvasTkAgg и используйте один subplots(), чтобы создать два ax1, ax2, чтобы сделать два сюжета на одном холсте.

furas 04.05.2024 11:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы используете 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() прямо перед последней строкой кода, чтобы предотвратить перекрытие двух подграфиков.

Zakaria 05.05.2024 17:29

@Закария, спасибо! Я добавил твое предложение в код.

furas 05.05.2024 20:58

Другие вопросы по теме