Python -Seaborn heatmap bind to mouse click event - python-3.x

I am developing a simple (so far) GUI on tkinter.
What I have right now is a GUI window with a canvas object and a treeview table in the same window.
My aim is to load csv data generate a heat map and use the positions to show further data about the clicked locations.
I can already generate the heat map(picture below) from the csv.
What I need now is for the canvas to detect my mouse click and based on the click transfer data from the same (or a different it doesn't matter as of yet) csv to the table. I tried a few things but I quite don't seem to understand how to assign the data on the canvas or the table for it to recognize it.
def tableDisplayFromGraph(self):
tableframe = tk.Frame(self.master)
tableframe.grid(row=2, column=10, ipadx=4, pady=2, sticky ="e") ## Packing against tableframe Frame
COLUMNS = ['Type', 'Value'] ## Column Headers for Data
## See Documentation for more info on Treeview
table = ttk.Treeview(tableframe, columns=COLUMNS, show='headings', padding=4)
table.grid(row=0, column=0)
for column in COLUMNS: ## Setting Column Header
table.heading(column, text=column)
scroll = tk.Scrollbar(tableframe, command=table.yview) ## Adding Vertical Scrollbar
scroll.grid(row=0, column=1) # problem how to set scrollbar inside the table :/
table.configure(yscrollcommand=scroll.set) ## Attach Scrollbar :/
def canvas(self):
f = plt.figure(figsize=(8, 8), dpi=110)
a = f.add_subplot(111)
if not self.Data.empty:
pivot_table = self.Data.pivot('Rows', 'Columns', 'B635 Mean')
plt.xlabel('Columns', size=12)
plt.ylabel('Rows', size=12)
plt.title('Heat Map', size=15)
sns.heatmap(pivot_table, annot=True, annot_kws={'size': 8},fmt="0.0f", linewidths=0, square=True, cmap='Reds')
#a.clear()
canvasFig = FigureCanvasTkAgg(f, master=self.master)
canvasFig.get_tk_widget().grid(row=0, column=0, rowspan=5, columnspan=5, padx=30, pady=10, sticky="ew")
navigatorFrame = tk.Frame(self.master)
navigatorFrame.grid(row=21, column=0, columnspan=5, padx=30, sticky="nw")
toolbar = NavigationToolbar2TkAgg(canvasFig, navigatorFrame)
toolbar.update()
canvasFig._tkcanvas.grid()
f.canvas.mpl_connect('pick_event', self.pick)
def pick(self, event):
if canvas.find_withtag(CURRENT):
canvas.itemconfig(CURRENT, fill="blue")
canvas.update_idletasks()
canvas.after(200)
canvas.itemconfig(CURRENT, fill="red")
canvas.bind("<Button-1>", self.pick)enter code here
When I hover around the heat map the canvas doesn't show x,y coordinates.
pick is my function for the click event.
Any help would be appreciated.
This is the image of my GUI. On the left is my heat map and on the right is my table treeview widget for displaying further data:

Related

The bar in my Scrollbar is missing from my python program using Tkinter GUI

I want to make a window to display data stored inside dictionaries. I have created a canvas, scrollbar and a frame inside the canvas to place my Text widgets to display the information. When I execute my code the layout is just as I want it, but the bar is missing from the scroll bar and I can't figure out why. Here is my code for the GUI portion:
root = Tk()
# create top part
top=Frame(root)
# create a canvas to scroll
holder = Canvas(top)
# create scroll bar
scroll = Scrollbar(top, orient=VERTICAL, command=holder.yview)
# configure scrollbar for canvas
holder.configure(yscrollcommand=scroll.set)
holder.bind('<Configure>', lambda e: holder.configure(scrollregion=holder.bbox("all")))
# create frame for content inside canvas and add it to the canvas
content = Frame(holder, relief=RAISED)
holder.create_window(0, 0, window=content, anchor='nw')
# create bottom part
bottom = Frame(root, relief=SUNKEN)
root.rowconfigure(0, weight=18)
root.rowconfigure(1, weight=1, minsize=50)
root.columnconfigure(0, weight=1)
holder.pack(side=LEFT, fill=BOTH, expand=1)
scroll.pack(side=RIGHT, fill=Y)
content.pack(fill=X)
top.grid(row=0, column=0, sticky='NSEW')
bottom.grid(row=1, column=0, sticky='NSEW')
num=0
for site in sites:
temp=Text(content, height = 5)
temp.configure(state= DISABLED)
temp.pack(fill=X, side=TOP, padx= 5, pady= 5)
siteBoxes.append(temp)
num += 1
root.mainloop()
here is a screenshot of what the result looks like
Program GUI screenshot
there are that many text boxes there just to test the scrollbar, the data display within the Text widgets haven't been written yet.
I found the culprit, it was the line content.pack(fill=X), since I already have it in the window of the canvas this line of code was causing the issue. How ever now the Text widget no longer spans all of the horizontal space, how would I fix this issue while still using .create_window()?

tkinter Treeview remove separators between columns in the header

I have a Tkinter Treeview with a header row. I am using the following style to style the header.
style = tk.ttk.Style()
style.theme_use('clam')
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'))
style.map('Treeview', background=[('selected', 'blue')])
But I want the table to have just a title saying "INVOICES" and I do not want the separators in the header separating the columns, as seen in the photo below.
Is there a way to get rid of these separators?
Bonus points if you you can help me get the scrollbar to actually look like a scrollbar instead of being full (there are over 100 records in this test table).
Here is the rest of the code to place the treeview into a frame.
self.invoice_frame = tk.Frame(self, border=1, relief=tk.GROOVE, bg='white')
self.invoice_frame.place(relx=0.3, rely=row_3_top, relwidth=0.3425, relheight=0.3)
self.invoice_tree = tk.ttk.Treeview(self.invoice_frame, column=('c1', 'c2', 'c3'), show='headings')
self.invoice_tree.pack(side='left', fill='both', expand=True)
tree_scrollbar = tk.ttk.Scrollbar(self.invoice_frame, orient='vertical', command=self.invoice_tree.yview)
tree_scrollbar.pack(side='right', fill='y')
self.invoice_tree.column('c1', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c1', text='')
self.invoice_tree.column('c2', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c2', text='INVOICES')
self.invoice_tree.column('c3', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c3', text='')
# adding random info
contacts = []
for n in range(1,100):
contacts.append((f'first {n}', f'last {n}', f'test{n}'))
for contact in contacts:
self.invoice_tree.insert('', tk.END, values=contact)
Thanks
You can set the relief style option to none to remove the separators.
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'), relief='none')
For the scrollbar issue, you need to configure yscrollcommand option of the treeview:
self.invoice_tree.config(yscrollcommand=tree_scrollbar.set)

Tkinter - How to center a Widget (Python)

I started with the GUI in Python and have a problem.
I've added widgets to my frame, but they're always on the left side.
I have tried some examples from the internet, but I did not manage it .
I tried .place, but it does not work for me. Can one show me how to place the widgets in the middle?
Code:
import tkinter as tk
def site_open(frame):
frame.tkraise()
window = tk.Tk()
window.title('Test')
window.geometry('500x300')
StartPage = tk.Frame(window)
FirstPage = tk.Frame(window)
for frame in (StartPage, FirstPage):
frame.grid(row=0, column=0, sticky='news')
lab = tk.Label(StartPage, text='Welcome to the Assistant').pack()
lab1 = tk.Label(StartPage, text='\n We show you helpful information about you').pack()
lab2 = tk.Label(StartPage, text='\n \n Name:').pack()
ent = tk.Entry(StartPage).pack()
but = tk.Button(StartPage, text='Press', command=lambda:site_open(FirstPage)).pack()
lab1 = tk.Label(FirstPage, text='1Page').pack()
but1 = tk.Button(FirstPage, text='Press', command=lambda:site_open(StartPage)).pack()
site_open(StartPage)
window.mainloop()
After you have created window, add:
window.columnconfigure(0, weight=1)
More at The Grid Geometry Manager
You are mixing two different Layout Managers. I suggest you either use The Grid Geometry Manager or The Pack Geometry Manager.
Once you have decided which one you would like to use, it is easier to help you :)
For example you could use the Grid Geometry Manager with two rows and two columns and place the widgets like so:
label1 = Label(start_page, text='Welcome to the Assistant')
# we place the label in the page as the fist element on the very left
# and allow it to span over two columns
label1.grid(row=0, column=0, sticky='w', columnspan=2)
button1 = Button(start_page, text='Button1', command=self.button_clicked)
button1.grid(row=1, column=0)
button2 = Button(start_page, text='Button2', command=self.button_clicked)
button2.grid(row=1, column=1)
This will lead to having the label in the first row and below the two buttons next to each other.

Adding a background image to a root window and placing labels on the top of the background image

I'm trying to add a background image to my root window but it doesn't seem to be working for me. This is my code. I would like the background image to cover the whole window and place the labels on top of the background image.
from tkinter import *
from tkinter import messagebox
top = Tk()
textButton = Frame(top)
textButton.pack()
img = PhotoImage(file="bk.gif")
img = img.subsample(1, 1)
background = Label(top, image = img, bd=0)
background.pack()
background.image = img
name_label = Label(textButton, text="Username")
name_label.grid(row=1, sticky=W)
name_entry = Entry(textButton)## the Entry will let the user entre text inside the text box
name_entry.grid(row=1, column=1)
password_label = Label(textButton, text="Password")
password_label.grid(row=2, sticky=W)
password_entry = Entry(textButton, show="*")
password_entry.grid(row=2, column=1)
top.mainloop
You can use place to use an image as a background for other widgets. place doesn't affect the geometry of other widgets so you can use it with grid or pack.
The main think to keep in mind is that you should do this before creating other widgets so that it is lowest in the stacking order. That, or be sure to call lower on it, otherwise it will overlay the other widgets rather than underlay them.
With your code, just remove background.pack() and replace it with these two lines:
background.place(relx=.5, rely=.5, anchor="center")
background.lower()
You don't need to change anything else. The above centers the image. If you instead want the image to start in the upper-left corner you can do it like this:
background.place(x=0, y=0, anchor="nw")
You have to use background as parent for widgets to put them inside Label with background.
I remove Frame to make it simpler. And now I can use weight to automatically resize empty rows and columns around widgets so they will be in the center.
import tkinter as tk
top = tk.Tk()
top.geometry('250x250')
img = tk.PhotoImage(file="hal_9000.gif")
img = img.subsample(1, 1)
background = tk.Label(top, image=img, bd=0)
background.pack(fill='both', expand=True)
background.image = img
# resize empty rows, columns to put other elements in center
background.rowconfigure(0, weight=100)
background.rowconfigure(3, weight=100)
background.columnconfigure(0, weight=100)
background.columnconfigure(3, weight=100)
name_label = tk.Label(background, text="Username")
name_label.grid(row=1, column=1, sticky='news')
name_entry = tk.Entry(background)## the Entry will let the user entre text inside the text box
name_entry.grid(row=1, column=2)
password_label = tk.Label(background, text="Password")
password_label.grid(row=2, column=1, sticky='news')
password_entry = tk.Entry(background, show="*")
password_entry.grid(row=2, column=2)
top.mainloop()
Result:
As you see widgets have gray background which you can't remove. If you need text without gray background then you have to use Canvas with create_text() (and create_window() to put Entry)
Gif file (with HAL 9000) to test code:

Raise Frame on top in PanedWindow in tkinter python 3.5

I have a frame in PanedWindow which i need on every tkinter GUI (in this case it's topFrame). Below it are many frames and I want to switch between those frame on button click (just like in any software where the top portion of screen is fixed and clicking on buttons the lower portion of GUI changes).
I know i need grid layout for it. But, it is not happening and i am not getting a solution anywhere.I have researched a lot on this topic everywhere but this solution is nowhere. Here is my code... i have written in comments those code which i feel are not working fine.
#python 3.5
from tkinter import *
#function to raise the frame on button click
def raiseFrame(frame):
frame.tkraise()
m = PanedWindow(height=500, width=1000, orient=VERTICAL)
m.pack(fill=BOTH, expand=1)
#to expand the column and row to fill the extra space
m.grid_columnconfigure(index=0, weight=1) #this code is not working as it should
m.grid_rowconfigure(index=0, weight=1) #this code is not working as it should
#top frame has two buttons which switches the bottom frames
topFrame = Frame(m, bg="blue")
m.add(topFrame)
button1 = Button(topFrame, text="Raise Frame 2", command=lambda: raiseFrame(frame2)) #raises frame 2 on clicking it
button1.pack(side=LEFT)
button2 = Button(topFrame, text="Raise Frame 1", command=lambda: raiseFrame(frame1)) #raises frame 1 on clicking it
button2.pack(side=LEFT)
#bottomframe acts as container for two other frames which i need to switch
bottomframe = Frame(m, bg="orange")
m.add(bottomframe)
frame1 = Frame(bottomframe, bg="yellow")
frame1.grid(row=0, column=0, sticky="news") ## sticky is not working ##
frame2 = Frame(bottomframe, bg="green")
frame2.grid(row=0, column=0, sticky="news") ## sticky is not working ##
label1 = Label(frame1, text="i should change")
label1.pack(padx=10, pady=10)
label2 = Label(frame2, text="i am changed !!")
label2.pack(padx=10, pady=10)
mainloop()
1)Please correct my code.
2)Explain me why in the "topFrame" even though i have not written
topFrame.pack(fill=BOTH, expand=True)
my code is showing the above property and it's expanding as well as filling both X and Y.
Same goes for the bottomFrame, it's orange colour is filling the entire space which does not happen in normal frames. So, is it some special feature of PanedWindow ?
You don't want to call topFrame.pack() and m.add(topFrame). You either pack/place/grid the window, or you add it to a paned window, you don't do both.
Also, if the frame is going to be in the paned window it needs to be a child of the paned window rather than a child of the root window.

Resources