Python Forum
[Tkinter] Fixate graphs on scrollable canvas
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Fixate graphs on scrollable canvas
#1
The idea is that I want the graphs only to appear on the scrollable canvas next to the previous graph. At this moment when I create another graph it will just be plotted outside the canvas. Note that I just set the scrollregion to a random high number. It actually needs to grow with each extra graph added. However, I did not figure out how.

Anyone knows what I am doing wrong here? Huh

import tkinter as tk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Example:
    def __init__(self, master):
        self.clicks = 0
        self.master = master
        self.frame= tk.Frame(master,width=600,height=100,background="green")
        self.canv = tk.Canvas(master, width=600, height=400,background="blue",scrollregion=(0,0,2000,2000))

        button = tk.Button(master,text='click',command= lambda: self.select(master))

        self.scrollY = tk.Scrollbar(master, orient=tk.VERTICAL,
                                    command=self.canv.yview)
        self.scrollX = tk.Scrollbar(master, orient=tk.HORIZONTAL,
                                    command=self.canv.xview)

        self.canv['xscrollcommand'] = self.scrollX.set
        self.canv['yscrollcommand'] = self.scrollY.set

        self.frame.grid(row=0,column=0,rowspan=3)
        self.scrollY.grid(row=3, column=1, sticky=tk.N+tk.S)
        button.grid(row=2,column=0,padx=10,sticky=tk.NW)
        self.scrollX.grid(row=4, column=0, sticky=tk.E+tk.W)
        self.canv.grid(row=3, column=0)
    def select(self,master):
        self.clicks +=1
        shape = np.random.randint(0,2,[5,5])
        lon = np.arange(5)
        lat = np.arange(5)
        fig = Figure(figsize=(4,4))
        ax = fig.add_subplot(111)
        c = ax.pcolor(lon,lat,shape)
        fig.colorbar(c,ax=ax,fraction=0.046,pad=0.04)
        canvas = FigureCanvasTkAgg(fig,self.canv)

        canvas.get_tk_widget().grid(row=0,column=self.clicks)

if __name__ == "__main__":
    root=tk.Tk()
    Example(root)
    root.mainloop()
Reply
#2
The following changes will widen your frame and canvas.
You can fix the graph positioning math so that the second one uses the proper coordinates.
import tkinter as tk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure


class Example:
    def __init__(self, master):
        self.clicks = 0
        self.master = master

        self.frame_width = 600
        self.frame_height = 100

        self.canvas_width = 600
        self.canvas_height = 400

        self.frame= tk.Frame(master, width=self.frame_width, height=self.frame_height,
            background="green")
        self.canv = tk.Canvas(master, width=self.canvas_width, height=self.canvas_height,
            background="blue",scrollregion=(0,0,2000,2000))
 
        button = tk.Button(master,text='click',command= lambda: self.select(master))
 
        self.scrollY = tk.Scrollbar(master, orient=tk.VERTICAL,
                                    command=self.canv.yview)
        self.scrollX = tk.Scrollbar(master, orient=tk.HORIZONTAL,
                                    command=self.canv.xview)
 
        self.canv['xscrollcommand'] = self.scrollX.set
        self.canv['yscrollcommand'] = self.scrollY.set
 
        self.frame.grid(row=0,column=0,rowspan=3)
        self.scrollY.grid(row=3, column=1, sticky=tk.N+tk.S)
        button.grid(row=2,column=0,padx=10,sticky=tk.NW)
        self.scrollX.grid(row=4, column=0, sticky=tk.E+tk.W)
        self.canv.grid(row=3, column=0)

    def select(self,master):
        if self.clicks > 0:        
            self.frame_width += 600
            self.canvas_width += 600
            self.frame.configure(width=self.frame_width)
            self.canvas.configure(width=self.canvas_width)

        self.clicks +=1

        shape = np.random.randint(0,2,[5,5])
        lon = np.arange(5)
        lat = np.arange(5)
        fig = Figure(figsize=(4,4))
        ax = fig.add_subplot(111)
        c = ax.pcolor(lon,lat,shape)
        fig.colorbar(c,ax=ax,fraction=0.046,pad=0.04)
        canvas = FigureCanvasTkAgg(fig,self.canv)
 
        canvas.get_tk_widget().grid(row=0,column=self.clicks)
 

if __name__ == "__main__":
    root=tk.Tk()
    Example(root)
    root.mainloop()
Reply
#3
Thank you very much for your response! However, I don't want the size of the canvas or frame to expand. That's why I used a scrollable canvas. Or is this not possible?
Reply
#4
Ok, misunderstood. You can use scrollable canvas.
To do this, I think you need to attach the scrollbars to the frame, not master, and not the canvas.
Reply
#5
Thanks! I tried that and I also set the canvas attached to the frame. That did not work, so I tried to also create a new frame attached to the canvas and attached to canvas with graph to that new frame.
And it is still not working, I really don't understand why

import tkinter as tk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Example:
    def __init__(self, master):
        self.clicks = 0
        self.master = master
        self.frame= tk.Frame(master,width=600,height=400,background="green")
        self.canv = tk.Canvas(self.frame, width=600, height=400,background="blue",scrollregion=(0,0,2000,2000))
        button = tk.Button(master,text='click',command= lambda: self.select(master))
 
        self.scrollY = tk.Scrollbar(self.frame, orient=tk.VERTICAL,
                                    command=self.canv.yview)
        self.scrollX = tk.Scrollbar(self.frame, orient=tk.HORIZONTAL,
                                    command=self.canv.xview)
 
        self.canv['xscrollcommand'] = self.scrollX.set
        self.canv['yscrollcommand'] = self.scrollY.set
 
        self.frame.grid(row=0,column=0,rowspan=3)
        self.scrollY.grid(row=3, column=1, sticky=tk.N+tk.S)
        button.grid(row=2,column=0,padx=10,sticky=tk.NW)
        self.scrollX.grid(row=4, column=0, sticky=tk.E+tk.W)
        self.canv.grid(row=3, column=0)
        self.framesub = tk.Frame(self.canv)
        self.framesub.bind("<Configure>",self.canv.configure(scrollregion=self.canv.bbox("all"),width=200,height=200))
        
    def select(self,master):
        self.clicks +=1

        shape = np.random.randint(0,2,[5,5])
        lon = np.arange(5)
        lat = np.arange(5)
        fig = Figure(figsize=(4,4))
        ax = fig.add_subplot(111)
        c = ax.pcolor(lon,lat,shape)
        fig.colorbar(c,ax=ax,fraction=0.046,pad=0.04)
        canvas1= FigureCanvasTkAgg(fig,self.framesub)
        #framesub.grid(row=0,column=self.clicks)
        canvas1.get_tk_widget().grid(row=0,column=0)


if __name__ == "__main__":
    root=tk.Tk()
    Example(root)
    root.mainloop()
Reply
#6
I got it working!! Thank you :-)

Here's how it looks now (sorry, may have changed the names a bit):

import tkinter as tk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class tkintertool:
    def __init__(self,master):
        self.clicks= 0 
        self.master = master
        
        master.geometry("2000x1000")
        
        self.myframe = tk.Frame(master,relief=tk.GROOVE,width=500,height=300,bd=1,background="blue")
        self.myframe.grid(row=0,column=0)

        self.canvas=tk.Canvas(self.myframe,background="green")
        self.frame=tk.Frame(self.canvas,background="red")
        
        button = tk.Button(master,text='click',command=lambda: self.data())
        
        myscrollbar=tk.Scrollbar(self.myframe,orient="vertical",command=self.canvas.yview)
        myscrollbarx=tk.Scrollbar(self.myframe,orient="horizontal",command=self.canvas.xview)
        self.canvas.configure(yscrollcommand=myscrollbar.set,xscrollcommand=myscrollbarx.set)

        myscrollbar.pack(side="right",fill="y")
        myscrollbarx.pack(side="bottom",fill="x")
        button.grid(row=2,column=0)
        self.canvas.pack(side="left")
        self.canvas.create_window((0,0),window=self.frame,anchor='nw')
        self.frame.bind("<Configure>",self.myfunction())
        size = (self.frame.winfo_reqwidth(), self.frame.winfo_reqheight())
        print(size)
    def data(self):
        self.clicks+=1
        self.frame.bind("<Configure>",self.myfunction())
        shape = np.random.randint(0,(3),[5,5])
        lon = np.arange(5)
        lat = np.arange(5)
        fig = Figure(figsize=(4,4))
        ax = fig.add_subplot(111)
        c = ax.pcolor(lon,lat,shape)
        fig.colorbar(c,ax=ax,fraction=0.046,pad=0.04)
        canvas = FigureCanvasTkAgg(fig,self.frame)
        canvas.get_tk_widget().grid(row=0,column=(self.clicks))
    #    self.canvas.config(scrollregion='0 0 %s %s' % size)

    def myfunction(self):
        self.canvas.configure(scrollregion=(0,0,288*(self.clicks),288),width=500,height=300)
        
root = tk.Tk()
my_gui = tkintertool(root)
root.mainloop()
Reply
#7
You're welcome, please click Set Solved
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] PyQt5 drawing on scrollable area HeinKurz 3 1,259 Mar-28-2023, 12:58 PM
Last Post: Axel_Erfurt
  [Tkinter] Scrollable buttons with an add/delete button Clich3 5 3,332 Jun-16-2022, 07:19 PM
Last Post: rob101
  [Tkinter] How to create scrollable frame mandiatutti 7 4,339 Aug-07-2021, 03:34 PM
Last Post: deanhystad
Question [Tkinter] Scrollable Treeview: change behavior of Prior/Next keys? RockDoctor 2 3,156 Apr-10-2021, 05:40 PM
Last Post: RockDoctor
  python GUI with google sheets graphs Omri_sap 1 1,838 Sep-22-2020, 09:21 PM
Last Post: Larz60+
  Scrollable big image in a window (TKinter) Prospekteur 3 4,415 Sep-14-2020, 03:06 AM
Last Post: Larz60+
  [Tkinter] Resizing image inside Canvas (with Canvas' resize) Gupi 2 25,027 Jun-04-2019, 05:05 AM
Last Post: Gupi
  [Tkinter] ListBox not contained or scrollable kellykimble 6 5,099 Apr-05-2018, 11:59 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020