Getting index of every optionmenu from multiple optionmenus - python-3.x

Given multiple optionmenu with stringvar trace,how to get the index of every option menu's first option?
self.path_list=[]
def load(self,inputt):
for i in range(0,self.x):
self.variable = StringVar(root)
self.variable.set("abc")
self.variable.trace('w',partial(self.rb_mode,i=i))
w=OptionMenu(root,self.variable,"Hello","World")
w.grid(row=i+100,column=1)
self.opt_menu.append(self.variable.get())
def rb_mode(self,*args,inx):
self.variable.get.__setitem__(i)
if(self.variable.get()=="Hello"):
do something
Here as shown,the drop down box index should be mapped with the corresponding file path
There are multiple dynamic drop down lists. Each drop down box index should be mapped with the corresponding path.
Am getting the output like:
World(printing 2 times which is the 2nd option,on clicking the 1st option)

Related

How may I dynamically create global variables within a function based on input in Python

I'm trying to create a function that returns a dynamically-named list of columns. Usually I can manually name the list, but I now have 100+ csv files to work with.
My goal:
Function creates a list, and names it based on dataframe name
Created list is callable outside of the function
I've done my research, and this answer from an earlier post came very close to helping me.
Here is what I've adapted
def test1(dataframe):
# Using globals() to get dataframe name
df_name = [x for x in globals() if globals()[x] is dataframe][0]
# Creating local dictionary to use exec function
local_dict = {}
# Trying to generate a name for the list, based on input dataframe name
name = 'col_list_' + df_name
exec(name + "=[]", globals(), local_dict)
# So I can call this list outside the function
name = local_dict[name]
for feature in dataframe.columns:
# Append feature/column if >90% of values are missing
if dataframe[feature].isnull().mean() >= 0.9:
name.append(feature)
return name
To ensure the list name changes based on the DataFrame supplied to the function, I named the list using:
name = 'col_list_' + df_name
The problem comes when I try to make this list accessible outside the function:
name = local_dict[name].
I cannot find away to assign a dynamic list name to the local dictionary, so I am forced to always call name outside the function to return the list. I want the list to be named based on the dataframe input (eg. col_list_df1, col_list_df2, col_list_df99).
This answer was very helpful, but it seems specific to variables.
global 'col_list_' + df_name returns a syntax error.
Any help would be greatly appreciated!

How to delete an arrow created with ax.arrow()?

For context, I have a curve where I would like to highlight the width of a plateau with an annotation + an arrow (this one was made in Paint.NET).
To update the text and arrow, every time an input parameter changes I do:
ax.texts = [] # Clear the previous annotations.
ax.text(x, y, plateau_width_str)
??? # What goes here to clear the arrow?
ax.arrow(x, y, dx=plateau_width, dy=0)
For now I'm not using gids here because I only have one text and one annotation at a time. What should be the third line? After calling ax.arrow() I tried exploring ax.collections and ax.patches but they are empty lists. Thanks in advance.
I have tried the following:
ax.get_children() -> to get the list of all objects of axes after
ax.get_children()[0].remove() -> to remove the 0-element of axes list.
If you try ax.get_children() again you get a new list with the number of objects reduced, and the place "0" was substituted by the [1] element of the previous list. Then, every time you use ax.get_children()[0].remove() you will remove the sequence of elements, erasing each element that takes place which was removed before. Be careful!
Or you can try to choose the right element by setting the ID_number when you use ax.get_children()[ID_number].remove().
You could directly create a method that removes the old and creates a new arrow, like self.create_arrow(*args, **kwargs).
It might look like
def create_arrow(self, *args, **kwargs):
gid = kwargs.get("gid")
if gid in self.some_dic:
self.some_dic[gid].remove()
arrow = self.ax.arrow(*args, **kwargs)
self.some_dic.update({kwargs.get("gid") : arrow})
Where you have a dictionary self.some_dic to store the references in.

Write values from Pandas DataFrame columns into tkinter TreeView/Table Columns

I want to write values from a dataframe into a tkinter treeview/Table, I am not able to do this.
my code:
#Setting up tkinter window.
root = Tk()
tree = ttk.Treeview(root)
#taking file input through a dialog box from the user.
file = filedialog.askopenfile(parent=root,mode='rb',title='Choose a xlsx file')
#readinf the excel file selected by the user and then creating a dataframe of that file.
xls = pd.read_excel(file)
df = pd.DataFrame(xls)
#taking all the columns heading in a variable"df_col".
df_col = df.columns.values
#all the column name are generated dynamically.
tree["columns"]=(df_col)
counter = len(df)
#generating for loop to create columns and give heading to them through df_col var.
for x in range(len(df_col)):
tree.column(x, width=100 )
tree.heading(x, text=df_col[x])
#generating for loop to print values of dataframe in treeview column.
for i in range(counter):
tree.insert('', 0, values=(df[df_col[x]]][i]))
It is not printing the columns and showing the KeyError:0.
Output Required:
The first argument of tree.column() should be the column name, which you assigned with:
tree["columns"]=(df_col)
The problem is that you have named the columns using a string, but you are attempting to access them using integers in:
for x in range(len(df_col)):
tree.column(x, width=100 )
tree.heading(x, text=df_col[x])
Above, you are attempting to access tree.columns(0), instead of tree.columns('Company'), hence the key error.
Try instead:
for x in range(len(df_col)):
tree.column(df_col[x], width=100)
tree.heading(df_col[x], text=df_col[x])
Note that df_col is an ndarray, not a dataframe, which is why df_col[x] works correctly (df[x] would give a key error). This is because df.columns.values returns an ndarray. As a side note, it may be a bit confusing to name an ndarray df_col.
There are also a few issues with your insert. The second argument should correspond to the index of the entry you wish to address. One solution is then to use a row index as the second argument, followed by a row label as text="rowLabel", followed by a list of values for the row:
tree.insert('', i, text=rowLabels[i], values=df.iloc[i,:].tolist())
Where rowLabels should be defined as whatever you want to use in the first column of the table. I would suggest using an index column from the spreadsheet here, if possible. It could be defined by:
rowLabels = df.iloc[:,indexColumn].tolist()
or:
rowLabels = df.index.tolist()
The latter is viable if df has named indices defined by a column during the spreadsheet import. In the former, indexColumn is an int referring to a column number in df that contains unique identifiers.
The option values=df.iloc[i,:].tolist() converts all columns of the ith row into a list, and, since we have passed an index value (the second argument) that gets larger, the call will insert a new row every loop (from the python tkinter docs entry on Treeview --> insert: "if index is greater than or equal to the current number of children, it is inserted at the end").
Finally, I am not sure if you did not post the end of your code, but, in order for the tree to show up, you will also need to use pack, grid, etc.
tree.pack()
or
tree.grid(row=0, column=0)
References:
https://docs.python.org/3/library/tkinter.ttk.html#tkinter.ttk.Treeview
This helpful example makes a few of the steps clear:
https://knowpapa.com/ttk-treeview/
As I was reading over your code. I noticed at the end line you have an extra bracket #:
df[df_col[x]]]
for i in range(counter):
tree.insert('', 0, values=(df[df_col[x]]][i]))
I would assume that would explain the KeyError.

QlistWidget how to select items one by one

i want open images sequence and i load all images in a list; i want when i click to a button called next the current list index change from 1 to 2 than from 2 to 3 ...etc right the last frame.
this code always give me the last frame
self.nextbtn.clicked.connect(self.changeitem)
def changeitem(self):
self.listWidget.count()
count_list = self.listWidget.count()
self.listWidget.setCurrentRow(0)
for i in range(count_list):
self.listWidget.setCurrentRow(i+1)
solution :
def changeitem(self):
cur = self.listWidget.currentRow()
self.listWidget.setCurrentRow(cur+1)

PyQt5 QTableWidget showing only first line and column

I have a QTableWidget populated with a list of lists. Each inner list have eight elements and my table have a ninth control column calculated after the others are loaded.
I can read and print to console the content of any cell of the table like print(self.tAccounts.item(52,3).text()), so I think there is no problem with the data, but the table shows only the cell's content for the first line and column in the table, leaving the others bank.
I should be making a mistake in some place, but I can't see.
Using PyQt 5 and Python 3.
The constructor
class Table(QWidget):
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.accounts = [] # The source is created in the constructor\
# and populate in other member function
self.tAccounts = QTableWidget(0,9)
self.tAccounts.setSortingEnabled(True)
self.tAccounts.setHorizontalHeaderLabels(['1','2','3','4','5','6','7','8','9'])
self.tAccounts.resizeColumnsToContents()
self.tAccounts.verticalHeader().hide()
The member function:
def loadDay(self):
for row, account in enumerate(self.accounts):
self.tAccounts.insertRow(row)
for col in range(8):
self.tAccounts.setItem(row, col, QTableWidgetItem(str(accounts[col])))
self.tAccounts.item(row,col).setTextAlignment(Qt.AlignRight)
self.tAccounts.setItem(row, 8, QTableWidgetItem('')) # defined for further use
Finally I found it.
The problem is in enabling the sorting in the constructor. Seems the default sorting is Z-A. Changing the sort to A-Z by clicking in the header of the empty table solves the bug but the best solution is to move the line self.tAccounts.setSortingEnabled(True) to the end of the loadDay function. Seems to be a clash between the ever changing row number because of enabled sorting and the updating algorithm of QTableWidget

Resources