Python Forum

Full Version: Fixate graphs on scrollable canvas
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
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()
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()
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?
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.
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()
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()
You're welcome, please click Set Solved