I'm interested in using file dialogs to choose the files I want to use for analysis in python versus just copying and pasting the pathname into a variable. With keeping user experience in mind, most people are used to navigating their files through the file dialog box on windows or mac.
I'd like to replicate this experience here. The below code will utilize ipywidgets in an .ipynb file to allow the user to choose a file they'd like to upload.
import pandas as pd
import ipywidgets as widgets
from IPython.display import clear_output
from ipyfilechooser import FileChooser
from ipywidgets import interact
from pathlib import Path
# get home dir of user
home = str(Path.home())
# initialize a dict for the excel file; this removes the need to set global values
dict_file = {}
# change to simply `home` if you want users to navigate through diff dirs
fc = FileChooser(f'{home}/')
# same here
fc.sandbox_path = f'{home}/'
# don't limit file extensions to '.xls, .xlsb, .xlsm, .xlsx'
fc.filter_pattern = ['*.*']
fc.title = '<b>Select your file</b>'
display(fc)
# create empty dropdown for sheet names
dropdown = widgets.Dropdown(options=[''], value='', description='Sheets:', disabled=False)
# create output frame for the df
out = widgets.Output(layout=widgets.Layout(display='flex', flex_flow='column', align_items='flex-start', width='100%'))
However, once this runs, it does not actually upload the file path name to a variable that I can use for further analysis. Where do I go from here?
Epected output: modify above code to retrieve a selected file's pathname in a variable. I am running Python 3.9.12, for what that's worth.
CodePudding user response:
See the ipyfilechooser
documentation:
# Print the selected path, filename, or both
print(fc.selected_path)
print(fc.selected_filename)
print(fc.selected)
On account of this, you may think that you could simply do something like this:
# don't limit file extensions to '.xls, .xlsb, .xlsm, .xlsx'
fc.filter_pattern = ['*.*']
fc.title = '<b>Select your file</b>'
display(fc)
# add var to store `fc.selected`
my_fname = fc.selected
However, if you do this, run the cell and then try a print in the next cell, you'll find that it prints None
:
print(my_fname)
# None
The problem here is that assignment of fc.selected
to our variable my_fname
is executed before the actual selection has taken place by the user. What we need then, is to make use of the so-called register_callback
that will be triggered after a selection has been made. So, at the end of the code in your cell we could add something like:
def update_my_fname():
global my_fname
my_fname = fc.selected
return
# bind FileChooser to callback
fc.register_callback(update_my_fname)
Now, if you try the print again in the next cell after you have selected a certain file, you'll find that the variable has been updated correctly with that file's path and name.
Note: instead of fc.selected
, you can also use fc.value
; both seem to store the exact same value.