Uploading files using Browse Button in Jupyter and Using/Saving them

24,525

Solution 1

_cb is called when the upload finishes. As described in the comment above, you can write to a file there, or store it in a variable. For example:

from IPython.display import display
import fileupload

uploader = fileupload.FileUploadWidget()

def _handle_upload(change):
    w = change['owner']
    with open(w.filename, 'wb') as f:
        f.write(w.data)
    print('Uploaded `{}` ({:.2f} kB)'.format(
        w.filename, len(w.data) / 2**10))

uploader.observe(_handle_upload, names='data')

display(uploader)

After the upload has finished, you can access the filename as:

uploader.filename

Solution 2

I am working on ML with Jupyter notebook, and I was looking for a solution to select the local files containing the datasets by browsing amongst the local file system. Although, the question here refers more to uploading than selecting a file. I am putting here a snippet that I found here because when I was looking for a solution for my particular case, the result of the search took me several times to here.

import os
import ipywidgets as widgets

class FileBrowser(object):
    def __init__(self):
        self.path = os.getcwd()
        self._update_files()

    def _update_files(self):
        self.files = list()
        self.dirs = list()
        if(os.path.isdir(self.path)):
            for f in os.listdir(self.path):
                ff = os.path.join(self.path, f)
                if os.path.isdir(ff):
                    self.dirs.append(f)
                else:
                    self.files.append(f)

    def widget(self):
        box = widgets.VBox()
        self._update(box)
        return box

    def _update(self, box):

        def on_click(b):
            if b.description == '..':
                self.path = os.path.split(self.path)[0]
            else:
                self.path = os.path.join(self.path, b.description)
            self._update_files()
            self._update(box)

        buttons = []
        if self.files:
            button = widgets.Button(description='..', background_color='#d0d0ff')
            button.on_click(on_click)
            buttons.append(button)
        for f in self.dirs:
            button = widgets.Button(description=f, background_color='#d0d0ff')
            button.on_click(on_click)
            buttons.append(button)
        for f in self.files:
            button = widgets.Button(description=f)
            button.on_click(on_click)
            buttons.append(button)
        box.children = tuple([widgets.HTML("<h2>%s</h2>" % (self.path,))] + buttons)

And to use it:

f = FileBrowser()
f.widget()
#   <interact with widget, select a path>
# in a separate cell:
f.path # returns the selected path

Solution 3

4 years later this remains an interesting question, though Fileupload has slightly changed and belongs to ipywidgets....

Here is some demo that shows how to get the file/files after the button click and reset the button to get more files....

from ipywidgets import FileUpload

def on_upload_change(change):
    if not change.new:
        return
    up = change.owner
    for filename,data in up.value.items():
        print(f'writing [{filename}] to ./')
        with open(filename, 'wb') as f:
            f.write(data['content'])
    up.value.clear()
    up._counter = 0

upload_btn = FileUpload()
upload_btn.observe(on_upload_change, names='_counter')
upload_btn

And here is a "debug" version that shows what is going on / why things work...

from ipywidgets import FileUpload

def on_upload_change(change):
    if change.new==0:
        print ('cleared')
        return
    up = change.owner
    print (type(up.value))
    for filename,data in up.value.items():
        print('==========================================================================================')
        print(filename)
        for k,v in data['metadata'].items():
            print(f'    -{k:13}:[{v}]')
        print(f'    -content len  :[{len(data["content"])}]')
        print('==========================================================================================')
    up.value.clear()
    up._counter = 0

upload_btn = FileUpload()
upload_btn.observe(on_upload_change, names='_counter')
upload_btn

Solution 4

I stumbled into this thread ~2 years late. For those still confused about how to work with the fileupload widget I have built off of the excellent answer posted by minrk with some other usage examples below.

from IPython.display import display
import fileupload

uploader = fileupload.FileUploadWidget()

def _handle_upload(change):
    w = change['owner']
    with open(w.filename, 'wb') as f:
        f.write(w.data)
    print('Uploaded `{}` ({:.2f} kB)'.format(
        w.filename, len(w.data) / 2**10))

uploader.observe(_handle_upload, names='data')

display(uploader)

From the widget documentation:

class FileUploadWidget(ipywidgets.DOMWidget):
    '''File Upload Widget.
    This widget provides file upload using `FileReader`.
    '''
    _view_name = traitlets.Unicode('FileUploadView').tag(sync=True)
    _view_module = traitlets.Unicode('fileupload').tag(sync=True)

    label = traitlets.Unicode(help='Label on button.').tag(sync=True)
    filename = traitlets.Unicode(help='Filename of `data`.').tag(sync=True)
    data_base64 = traitlets.Unicode(help='File content, base64 encoded.'
                                    ).tag(sync=True)
    data = traitlets.Bytes(help='File content.')

    def __init__(self, label="Browse", *args, **kwargs):
        super(FileUploadWidget, self).__init__(*args, **kwargs)
        self._dom_classes += ('widget_item', 'btn-group')
        self.label = label

    def _data_base64_changed(self, *args):
        self.data = base64.b64decode(self.data_base64.split(',', 1)[1])

Get the data in bytestring format:

uploader.data

Get the data in a regular utf-8 string:

datastr= str(uploader.data,'utf-8')

Make a new pandas dataframe from the utf-8 string (e.g. from a .csv input):

import pandas as pd
from io import StringIO

datatbl = StringIO(datastr)
newdf = pd.read_table(datatbl,sep=',',index_col=None)

Share:
24,525
Mona Jalal
Author by

Mona Jalal

contact me at [email protected] I am a 5th-year computer science Ph.D. Candidate at Boston University advised by Professor Vijaya Kolachalama in computer vision as the area of study. Currently, I am working on my proposal exam and thesis on the use of efficient computer vision and deep learning for cancer detection in H&amp;E stained digital pathology images.

Updated on November 13, 2020

Comments

  • Mona Jalal
    Mona Jalal over 3 years

    I came across this snippet for uploading files in Jupyter however I don't know how to save this file on the machine that executes the code or how to show the first 5 lines of the uploaded file. Basically I am looking for proper commands for accessing the file after it has been uploaded:

    import io
    from IPython.display import display
    import fileupload
    
    def _upload():
    
        _upload_widget = fileupload.FileUploadWidget()
    
        def _cb(change):
            decoded = io.StringIO(change['owner'].data.decode('utf-8'))
            filename = change['owner'].filename
            print('Uploaded `{}` ({:.2f} kB)'.format(
                filename, len(decoded.read()) / 2 **10))
    
        _upload_widget.observe(_cb, names='data')
        display(_upload_widget)
    
    _upload()
    
  • Rustikal
    Rustikal almost 4 years
    fileupload is deprecated, the new way is from ipywidgets import FileUpload However, with nearly no documentation so far and the syntax is pretty much the same