Python - Embed seaborn plots in tkinter GUI - python

I'm trying to embed plots from seaborn into tkinter gui for iris dataset. It works all fine when i save the image and reuse it but it is not an effective solution,Is there any alternate way to dynamically do the same without saving img in local filesystem
Here is the code
import tkinter as tk
import seaborn as sns
class Application(object):
def __init__(self,parent,**kwargs):
self.parent = parent
self.parent.geometry("900x600")
super().__init__(**kwargs)
self.vis_frame = tk.LabelFrame(self.parent)
self.vis_frame.grid(column=1,row=5,sticky='WE')
self.gui_button()
def gui_button(self):
df = sns.load_dataset('iris')
columns = df.columns
for i in range(len(columns)):
button = tk.Button(self.vis_frame,text=columns[i],command = lambda c=columns[i]: self.gui_plot(df,c))
button.grid(row=i+1,column=0,sticky='W')
def gui_plot(self,data,column):
from PIL import ImageTk, Image
self.sns_plot = sns.pairplot(data,hue=column,size=1.5)
self.sns_plot.savefig('plot.png')
img = ImageTk.PhotoImage(Image.open('plot.png'))
self.vis = tk.Label(self.vis_frame,image=img)
self.vis.image = img
self.vis.grid(row=0,column=1)
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
root.mainloop()

Related

displaying an Image in python within a function [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 2 years ago.
I'm trying to display the image from the link the code below works and shows image as intended
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_link =Label(root, image = my_img)
image_link.grid(row = 0, column = 0 )
root.mainloop()
but now i have to update my code a little bit and have to put this in a function
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
def image_func():
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label =Label(root, image = my_img)
image_label.grid(row = 0, column = 0 )
image_func()
root.mainloop()
the above doesn't shows the image so I tried to to put the image label inside a frame but that just shows the frame with nothing inside also the powershell or cmd doesn't show any error
All the objects you create inside the function are local. So these object are deleted when the function exits. You need a way to keep these object existing. For example by using global variables
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
my_img = None
image_label = None
def image_func():
global my_img, image_label
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label = Label(root, image = my_img)
image_label.grid(row = 0, column = 0 )
image_func()
root.mainloop()
Another way could be returning the objects from the function and keep the returned values
from tkinter import *
from PIL import ImageTk, Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
def image_func():
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label = Label(root, image=my_img)
image_label.grid(row=0, column=0)
return my_img, image_label
my_img, image_label = image_func()
root.mainloop()

Import pandas table into tkinter project

I have used tkinter and its treeview widget thus far in my project to import and view some data from a csv file. However Im finding its functions limited as to what Im trying to achieve.
I have read in other SO questions that a Pandas data-frame can be imported to Tkinter project and display in the tkinter GUI. I have found some code online # https://gist.github.com/gugat/7cf57eb628f3bb0a3d54b3f8d0023b63 but I cant work out how to migrate this into my existing tkinter code.
import tkinter as tk
from tkinter import *
import tkinter.ttk as tkrttk
from PIL import Image, ImageFont, ImageTk
import csv
from tkinter import filedialog
import pandas as pd
from pandastable import Table, TableModel
root = tk.Tk()
root.geometry("2000x1000")
filepath = (r"C:/Users\James\Desktop\test_data.csv")
root.title('Workshop Manager')
style = tkrttk.Style()
style.configure("Treeview.Heading", foreground='Red', font=('Helvetica', 10))
df = pd.read_csv(filepath)
pt = Table(parent)
class TestApp(Frame):
"""Basic test frame for the table"""
def __init__(self, parent=root):
self.parent = parent
Frame.__init__(self)
self.main = self.master
self.main.geometry('600x400+200+100')
self.main.title('Table app')
f = Frame(self.main)
f.pack(fill=BOTH,expand=1)
df = TableModel.getSampleData()
self.table = pt = Table(f, dataframe=df,
showtoolbar=True, showstatusbar=True)
pt.show()
return
app = TestApp()
root.mainloop()
I get an error NameError name parent is not defined im assuming this pt = Table(parent) is my issue. I have tried pt = Table(root) as I thought this would place it on the tkinter root window. But this didnt work.
Part of your code is from the example used in the document of pandastable, but it is not a good example.
If you just want to show your CSV file using pandastable, below is a simple example:
import tkinter as tk
from pandastable import Table, TableModel
filepath = 'C:/Users/James/Desktop/test_data.csv'
root = tk.Tk()
root.geometry('1600x900+10+10')
root.title('Workshop Manager')
class TestApp(tk.Frame):
def __init__(self, parent, filepath):
super().__init__(parent)
self.table = Table(self, showtoolbar=True, showstatusbar=True)
self.table.importCSV(filepath)
self.table.show()
app = TestApp(root, filepath)
app.pack(fill=tk.BOTH, expand=1)
root.mainloop()

How can i generate another plot after clicking a button in tkinter?

I am trying to show different slices of an image using entry points in tkinter. However, when i enter a new slice number it is creating the image under the previous one. I dont know how to remove the first one to make space for the 2nd one. A
The code is the following
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import *
import numpy.ma as ma
import cv2
from os import listdir
from os.path import isfile, join
import ellipse as el
class mclass:
def __init__(self, window):
self.window = window
self.box = Entry(window)
self.button = Button (window, text="check", command=self.plot)
self.box.pack ()
self.button.pack()
def plot (self):
mypath='C:\\Users\\mehmet\\Desktop\\a1'
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
images = np.empty(len(onlyfiles), dtype=object)
for n in range(0, len(onlyfiles)):
images[n] = cv2.imread( join(mypath,onlyfiles[n]),cv2.IMREAD_GRAYSCALE)
image = np.stack([images[i] for i in range(13,299)])
arr_size = (265,490,286)
sphere_center = (120,238,76)
a=11
b=10
c=12
sphere = el.create_bin_sphere(arr_size,sphere_center, a,b,c)
sphere1=255*sphere.astype(np.uint8)
sphere2=np.swapaxes(sphere1,0,2)
dst = cv2.bitwise_or(sphere2, image)
img_p=dst[:,:,int(self.box.get())]
fig = Figure(figsize=(3,3))
a = fig.add_subplot(111)
a.imshow(img_p,cmap='gray')
a.plot()
canvas = FigureCanvasTkAgg(fig, master=self.window)
canvas.get_tk_widget().pack(side="top")
canvas.draw()
window= Tk()
start= mclass (window)
window.mainloop()

How to update value in Tkinter plot of brain slices to be able to page through different brain volumes from a 4D image

I am trying to design a python gui to be able to assess impacts of motion by plotting brain slices, the framewise displacement timeseries, and different outputs of motion detection algorithms. I want to be able to slide through each of the brain volumes individually (180 volumes per scan) so that I can compare the FD timecourse to what the actual brain data looks like.
I've been using tkinter and I can plot several slices of one brain volume, but I'm having updating volume that is selected. I've tried creating buttons to advance and go back, and also using a tkinter Scale.
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
import os
import nibabel
from nilearn import plotting
from nilearn import image
from matplotlib.widgets import Slider, Button, RadioButtons
data_path = os.getcwd()
file='sub-HV01baseline_task-EA1_bold.nii'
file_path = os.path.join(data_path,file)
EA1=nibabel.load(file_path)
struct_arr2 = EA1.get_data()
vol=1
import tkinter as tk
from tkinter import ttk
fig = plt.Figure(figsize=(10,5), dpi=100)
class App:
def __init__(self, master):
self.event_num = 1
frame = tk.Frame(master)
frame.pack()
self.txt = tk.Entry(frame,width=10)
self.txt.pack(side="bottom")
self.lbl = tk.Label(frame, text="FD Value")
self.lbl.pack(side="bottom")
self.btn = tk.Button(frame, text = "Update",command=self.clicked)
self.btn.pack(side="bottom")
self.txt.focus()
self.var =tk.IntVar(frame)
self.var.set(0)
self.vol_scale=tk.Scale(frame,from_=0, to=180,orient="horizontal",sliderlength=20,command=self.show_slices(fig))
self.increase_btn = tk.Button(frame, text = "Increase",command=self.show_slices(fig))
self.increase_btn.pack(side="bottom")
self.vol_scale.pack(side="bottom")
#self.spin = tk.Spinbox(frame, from_=0, to=180, width=5, textvariable=self.var)
#self.spin.pack(side="bottom")
self.canvas = FigureCanvasTkAgg(fig,master=master)
self.canvas.get_tk_widget().pack(side=tk.TOP)
def clicked(self):
res = "FD = " + self.txt.get()
self.lbl.configure(text = res)
def show_slices(self,fig):
vol = self.vol_scale.get()
slice_0 = struct_arr2[:, :, 10,vol]
slice_1 = struct_arr2[:, : , 15,vol]
slice_2 = struct_arr2[:, :, 20,vol]
slice_3 = struct_arr2[:, :, 25,vol]
slice_4 = struct_arr2[:, : , 30,vol]
slices=[slice_0, slice_1, slice_2, slice_3, slice_4]
axes = fig.subplots(1, len(slices))
#svol = Slider(axes, 'Vol', 0, 180, valinit=0, valstep=1)
fig.subplots_adjust(hspace=0, wspace=0)
for i, slice in enumerate(slices):
axes[i].xaxis.set_major_locator(plt.NullLocator())
axes[i].yaxis.set_major_locator(plt.NullLocator())
axes[i].imshow(slice.T, origin="lower")
root=tk.Tk()
app = App(root)
root.mainloop()
Currently I'm getting an error that "App has no attribute 'vol_scale'" even though I've defined it above.

Multiple GUIs communicate back and forth

I have two GUIs and I want these guis to be able communicate together. I used Matlab in the past and in Matlab I was using addlistener and basically communicate between multiple guis. I am new to python and I want when I am clicking on the show button on my second gui it update the axes on my first gui. Basically, plot the image on the other gui based on the path I choose on another.
Here is the image for better understanding
Here is the code:
from tkinter import *
from PIL import Image, ImageTk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import
FigureCanvasTkAgg
import PySimpleGUI as sg
import tkinter.filedialog as fdialog
from natsort import natsorted
import os
import cv2
class MyCanvas(Canvas):
def __init__(self, parent=None, img=None, *parms, **kparms):
Canvas.__init__(self, parent, *parms, **kparms)
self._width = 20;
self._height = 10;
self._starting_drag_position = ()
self.config(width=self._width, height=self._height, bg='white')
self._draw_some_example_objects()
self.pack(fill=BOTH, expand=YES)
def _draw_some_example_objects(self):
self.fig = Figure()
gs = self.fig.add_gridspec(5, 2)
self.axis= self.fig.add_subplot(gs[0:4, 0])
self.canvas = FigureCanvasTkAgg(self.fig, master=self)
self.canvas.get_tk_widget().pack(side="top", fill='both', expand=True)
colors = dict(outline="black")
class MyGUI(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
self.title("Drag canvas with mouse")
self.geometry("700x700")
"""For some reason menu should be added here"""
self.menuBar = Menu(master=self)
self.filemenu = Menu(self.menuBar, tearoff=0)
self.filemenu.add_command(label="listview!", command=self.list)
self.menuBar.add_cascade(label="File", menu=self.filemenu)
self.config(menu=self.menuBar)
self._addWidgets()
def _addWidgets(self):
my_canvas = MyCanvas(self)
def list(self):
listView(self)
def listView(self):
sg.ChangeLookAndFeel('GreenTan')
dir = fdialog.askdirectory()
filesList = os.listdir(dir)
filesList = natsorted(filesList)
layout = [
[sg.Listbox(values=(filesList), size=(60, 30), key='_IN_')],
[sg.Button('Show')]
]
window = sg.Window('Everything bagel', default_element_size=(40, 1), grab_anywhere=False).Layout(layout)
while True:
event, values = window.Read()
if event is None or event == 'Exit':
break
print(dir + values.get('_IN_')[0])
if __name__ == '__main__':
MyGUI().mainloop()`
Take a look at this demo program.
Drop your code into the section where it says:
#------------------------ PASTE YOUR MATPLOTLIB CODE HERE ----------------------
Make sure your drawing is in the variable 'fig'. It will create a window with GUI options and your Matplotlib plot embedded in it.

Categories