
This project combines a Pandas DataFrame with a Tkinter search interface. The user enters a value, Pandas filters the DataFrame, and the matching rows are displayed in a Treeview.
Using the sample student data, a numeric search can match the student id, while text searches match the name column. We will then extend the project to live searching, multiple words, sorting, saving the filtered DataFrame and copying it to the clipboard.
Excel / CSV
|
v
Pandas DataFrame
|
v
Search Entry
|
+--> numeric query --> exact id
|
+--> text query ----> name contains text
|
v
Filtered DataFrame
|
+--> Treeview
+--> Sort
+--> Save Excel / CSV
+--> Copy to clipboard
Show Table of Contents
The original project used read_excel() with a fixed local path:
df=pd.read_excel(
'F:\\data\\student.xlsx'
)
The revised application uses a Tkinter file browser, so the user can select either an Excel or CSV file.
file_path=filedialog.askopenfilename(
title='Select Excel or CSV file',
filetypes=[
('Excel files','*.xlsx *.xls'),
('CSV files','*.csv')
]
)
The extension determines which Pandas function is used:
if extension=='.csv':
df=pd.read_csv(file_path)
else:
df=pd.read_excel(file_path)
A Tkinter Entry collects the search text. A Button can also trigger the search manually.
search_entry=ttk.Entry(
search_frame,
textvariable=search_var,
width=35
)
search_button=ttk.Button(
search_frame,
text='Search',
command=search_data
)
The complete program supports both methods:
<KeyRelease> update the result automatically.The entered text is cleaned with strip():
query=search_var.get().strip()
If the query is numeric and the DataFrame contains an id column, an exact ID search is performed:
if query.isdigit() and 'id' in df.columns:
id_values=pd.to_numeric(
df['id'],
errors='coerce'
)
filtered_df=df[
id_values==int(query)
].copy()
For text input, the student example searches the name column.
Pandas str.contains() can perform a case-insensitive partial match:
names=df['name'].fillna('').astype(str)
mask=names.str.contains(
query,
case=False,
na=False,
regex=False
)
Two options are important here.
na=False prevents missing values from becoming an invalid search result.regex=False treats characters such as ., +, ( or * as normal search text instead of regular-expression syntax.The original project created another Treeview every time my_search() ran. With live KeyRelease searching, this can create many overlapping widgets.
The revised application creates the Treeview once and only replaces its contents:
for item in tree.get_children():
tree.delete(item)
DataFrame rows are then inserted:
for row in filtered_df.itertuples(
index=False,
name=None
):
tree.insert(
'',
tk.END,
values=row
)
We no longer use:
iid=v[0]
The first DataFrame value might not be unique, so Treeview is allowed to create its own unique internal item IDs.
For more details, see dynamic Treeview headers and columns and inserting Treeview rows.
The KeyRelease event can call the same search function whenever the user releases a key:
search_entry.bind(
'<KeyRelease>',
search_data
)
The function accepts the optional Tkinter event:
def search_data(event=None):
...
This means the same function works from both the Button and the keyboard event.
Use split() to break the entered search phrase into separate words:
words=query.split()
For example:
query = 'John Kumar'
words = [
'John',
'Kumar'
]
The original project also excluded common search words:
STOP_WORDS={
'to',
'and',
'or'
}
The revised version preserves that feature without converting the words to an unordered set:
words=[
word
for word in query.split()
if word.lower() not in STOP_WORDS
]
The default project behavior is an any-word search. A row is included if the name matches at least one entered word.
mask=pd.Series(
False,
index=df.index
)
for word in words:
mask |= names.str.contains(
word,
case=False,
na=False,
regex=False
)
Older Pandas versions allowed repeated use of:
df2=df2.append(...)
DataFrame.append() was deprecated and later removed from Pandas. The earlier replacement was pd.concat():
matches=[]
for word in words:
matches.append(
df[
names.str.contains(
word,
case=False,
na=False,
regex=False
)
]
)
df2=pd.concat(
matches,
ignore_index=True
).drop_duplicates()
However, when the goal is only to combine search conditions, repeatedly creating DataFrames is unnecessary. A Boolean mask is simpler:
mask |= names.str.contains(...)
The complete program below uses this Boolean-mask approach.
The filtered DataFrame can use the same heading-sorting method from our Pandas Treeview sorting tutorial.
Clicking a Treeview heading sorts only the current result:
filtered_df=filtered_df.sort_values(
by=column_name,
ascending=ascending,
na_position='last',
kind='stable'
).reset_index(
drop=True
)
Each column has its own ascending/descending state.
The filtered result can be saved with a Tkinter Save As dialog.
The user can select Excel or CSV output:
file_path=filedialog.asksaveasfilename(
filetypes=[
('Excel file','*.xlsx'),
('CSV file','*.csv')
],
defaultextension='.xlsx'
)
If the destination ends with .csv:
if file_path.lower().endswith(
'.csv'
):
filtered_df.to_csv(
file_path,
index=False
)
else:
filtered_df.to_excel(
file_path,
index=False
)
See Pandas DataFrame input and output formats for other export options.
Pandas to_clipboard() copies the current result:
filtered_df.to_clipboard(
index=False
)
The application displays a temporary confirmation message after copying.
status_var.set(
'Filtered DataFrame copied to clipboard.'
)
root.after(
3000,
clear_status
)
Use len() to get the number of rows in the filtered DataFrame:
result_var.set(
f'Matching records: {len(filtered_df)}'
)
This is updated every time the search changes.
With the sample student DataFrame:
id | name | class | mark
1 | John Deo | Four | 75
2 | Max Ruin | Three | 85
3 | Arnold | Three | 55
4 | Krish Star | Four | 60
Entering:
2
performs an exact ID lookup when an id column exists.
Entering:
john
performs a case-insensitive partial match against name.
Entering:
John Max
returns names matching either useful search word.
If the selected DataFrame does not contain a name column, the complete example falls back to searching text across all columns. This makes the application usable with files other than the sample student dataset.
When the Entry is cleared, the complete DataFrame is restored:
if not query:
filtered_df=df.copy()
This is useful with KeyRelease because deleting the final search character immediately restores all records.
The next tutorial works with selection of a matching Treeview row:
Select a Search Result Row in TreeviewYou can also let the user control which DataFrame columns are displayed:
Select DataFrame Columns using CheckbuttonsFor more on sortable results:
Treeview Column Sorting with PandasRelated database Treeview projects:
Display MySQL Records MySQL Treeview Pagination Delete MySQL Records Insert MySQL Row and Add to TreeviewRead the Entry value, create a Pandas Boolean condition and use that condition to create a filtered DataFrame. The matching rows can then be displayed in Treeview.
If the search text contains only digits and the DataFrame has an id column, the example performs an exact numeric ID comparison.
The example uses str.contains() with case=False, na=False and regex=False.
It treats the user's search text literally, so regular-expression characters do not unexpectedly change the search pattern.
Bind the Entry widget's <KeyRelease> event to the search function.
Reusing one Treeview avoids creating overlapping widgets every time the user types another character or runs another search.
Yes. The example saves the current result as Excel or CSV and can also copy it to the system clipboard.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.
17-06-2023 | |
| Sir I request you to make a video related to find data from excel like excel vlookup command in pythan. when i entered data in python tk box then automatically data populated in 2nd tk box | |