I am trying to display 4-5 Matplotlib bar chart in a Tkinter window. But some how only 3 are fitting inside the frame. Please find the below code.
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()
I tried to use the horizontal scroll bar, but somehow it is also not working. If there are any other suggestions, or and any other way to show multiple bar charts inside a frame.
On my Linux helps when I assign any value (event 1
) to all canvas' width
canvas.get_tk_widget()['width'] = 1
canvas1.get_tk_widget()['width'] = 1
canvas2.get_tk_widget()['width'] = 1
canvas3.get_tk_widget()['width'] = 1
Minimal working code with 10 plots
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()
Result:
But it not so useful because all plots are small.
It also works when I put all plots on one canvas
for i in range(10):
fig.add_subplot(1, 10, i+1).plot(x, y)
But it may not be useful if you plan to add toolbars or move/close some plots.
Full working code:
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()
Using grid()
I had to set correct value for width and height - so I used event <Configure>
to do it when it create (or resize) window.
But with grid()
I can put it in many rows.
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()
Works also when I set weight=1
to every rows and columns in grid()
- and it doesn't need <Configure>
- so it seems the simplest method.
for row in range(2):
frame_top.rowconfigure(row, weight=1)
for col in range(5):
frame_top.columnconfigure(col, weight=1)
Full working code:
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()
It allows to set different sizes using proportions - e.g. first and last column 2 times wider.
for col in range(5):
frame_top.columnconfigure(col, weight=2)
frame_top.columnconfigure(0, weight=1)
frame_top.columnconfigure(4, weight=1)
Other solution could be putting Frame
on tkinter.Canvas
and use `Scrollers to move it on canvas - this way plot can be bigger then windows size. But this needs more work - e.g my class ScrolledFrame on GitHub.