8000 File Open Dialog · Issue #6096 · bokeh/bokeh · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File Open Dialog #6096

Closed
harrispilton opened this issue Apr 4, 2017 · 18 comments · Fixed by #9083
Closed

File Open Dialog #6096

harrispilton opened this issue Apr 4, 2017 · 18 comments · Fixed by #9083

Comments

@harrispilton
Copy link

Hello,

I would like to have a "File Open Dialog" to interactively specify local data files.
This was previously discussed in the Bokeh Google Groups.

Best regards

@bryevdv
Copy link
Member
bryevdv commented Apr 4, 2017

Just FYI. This might be a reasonable addition, but I can't speculate about when it might make it into the core library. In the mean time your option is to create custom extension:

http://bokeh.pydata.org/en/latest/docs/user_guide/extensions.html

@kevinsa5
Copy link
Contributor
kevinsa5 commented Apr 7, 2017

For anyone searching for help: in the meantime before this is added to bokeh, here's how I implemented sending a file from the user's computer to a Bokeh server:

  • Using templates (Bokeh's, Flask's, whatever you're using), insert an HTML file choosing input: <input id="file-input" type="file">
  • Attach a javascript callback to a button that reads the selected file's contents
  • If the file is complex like an excel document, you can base64 encode it. If it's something like a text file or a csv, you might as well leave it as-is
  • Insert it into a dedicated ColumnDataSource, treating it as a dictionary to transfer data from browser to server
  • On the server side, implement an on_change("data", callback) for the data source
  • Base64 decode the file if necessary
  • If you just need the file contents as a string, you're done. If you need it as a proper file (for instance, to use with pandas.read_excel), you can wrap it in a StringIO object to make it file-like

It's a bit complicated, but the upcoming namespace model for Bokeh would make it a bit easier. Feel free to ping me for code samples.

@divyamounika
Copy link
divyamounika commented May 2, 2017

Hello @kevinsa5 ,

could you provide code samples. Thank you
The following is my code

import pandas as pd
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import Button
from bokeh.io import curdoc

source = ColumnDataSource(dict())

print(source.data.keys)

def callback1(attr,old,new):
print('data got changed')

button = Button(label="Upload", button_type="success")
button.callback = CustomJS(args=dict(source=source),
code="""
fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');

                        selectDialogueLink = document.createElement('a');
                        selectDialogueLink.setAttribute('href', '');

                        selectDialogueLink.

                        document.body.appendChild(selectDialogueLink);

                        if ('files' in fileSelector) {
                            if (fileSelector.files.length == 0) {
                                alert("Select file.");
                            } else {
                                for (var i = 0; i < fileSelector.files.length; i++) {
                                    var file = fileSelector.files[i];
                                    var reader = new FileReader();
                                    source.data = reader.readAsArrayBuffer(file);
                                    if ('name' in file) {
                                        alert("name: " + file.name);
                                    }
                                    if ('size' in file) {
                                        alert("size: " + file.size);
                                    }
                                }
                            }
                         } 
                       """) 

source.on_change('data',callback1)

curdoc().add_root(row(button))

@kevinsa5
Copy link
Contributor
kevinsa5 commented May 3, 2017

Hi @divyamounika, here is an example script that you can work from. Try uploading a simple excel file to see if it works for you. I also added the filename, as you can see. This code is largely untested -- you may want to add filesize limits, only allow certain file types, etc.

# -*- coding: utf-8 -*-
"""
Created on Wed May 03 11:26:21 2017

@author: Kevin Anderson
"""

import pandas as pd
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import Button
from bokeh.io import curdoc

import StringIO
import base64

file_source = ColumnDataSource({'file_contents':[], 'file_name':[]})

def file_callback(attr,old,new):
    print 'filename:', file_source.data['file_name']
    raw_contents = file_source.data['file_contents'][0]
    # remove the prefix that JS adds  
    prefix, b64_contents = raw_contents.split(",", 1)
    file_contents = base64.b64decode(b64_contents)
    file_io = StringIO.StringIO(file_contents)
    df = pd.read_excel(file_io)
    print "file contents:"
    print df

file_source.on_change('data', file_callback)

button = Button(label="Upload", button_type="success")
button.callback = CustomJS(args=dict(file_source=file_source), code = """
function read_file(filename) {
    var reader = new FileReader();
    reader.
    reader.
    // readAsDataURL represents the file's data as a base64 encoded string
    reader.readAsDataURL(filename);
}

function load_handler(event) {
    var b64string = event.target.result;
    file_source.data = {'file_contents' : [b64string], 'file_name':[input.files[0].name]};
    file_source.trigger("change");
}

function error_handler(evt) {
    if(evt.target.error.name == "NotReadableError") {
        alert("Can't read file!");
    }
}

var input = document.createElement('input');
input.setAttribute('type', 'file');
input.
    if (window.FileReader) {
        read_file(input.files[0]);
    } else {
        alert('FileReader is not supported in this browser');
    }
}
input.click();
""")

curdoc().add_root(row(button))

@divyamounika
Copy link

Hello @kevinsa5 ,

Thank you for the code. I was able to upload .csv files data with a minor modification on my system.

modification -->file_io = io.StringIO(bytes.decode(file_contents))
It worked like magic.

@ijstokes
Copy link

There is some content here that may be useful to this issue:

https://stackoverflow.com/questions/40794180/upload-a-csv-file-and-read-it-in-bokeh-web-app

@ghost
Copy link
ghost commented Jan 17, 2018

@kevinsa5 and @divyamounika - could you throw some light on what ‘file_io’ contents would be? Because this works for csv file but for .xlsx throws TypeError. Could you guide me here?

@kevinsa5
Copy link
Contributor

@joel-wilson file_io is a StringIO object, basically an in-memory file. StringIO behaves slightly different between python 2 and 3, fyi. You should narrow down what exactly the issue on your end is, since it probably isn't a problem with Bokeh based on your description. Try making the smallest possible script that still has the issue, that should help you to figure it out.

@ghost
Copy link
ghost commented Jan 18, 2018

For those you would infuture reference this thread : Here is a solution to have a upload button to handle .xlsx file . This was ofr python3

import pandas as pd
import io
import base64


def file_callback_dt1(attr,old,new):
    print('filename:', file_source_dt1.data['file_name'])
    raw_contents = file_source_dt1.data['file_contents'][0]
    prefix, b64_contents = raw_contents.split(",", 1)
    file_contents = base64.b64decode(b64_contents)
    file_io = io.BytesIO(file_contents)
    excel_object = pd.ExcelFile(file_io, engine='xlrd')
    dt_1 = excel_object.parse(sheet_name = 'Sheet1', index_col = 0)
    # rest is upto you :)

@amishra159
Copy link

I am creating a pie chart but the problem is that I want to load a tsv file from the file open dialog box when the link is clicked.how it can be possible to get the data file from dialog box and as the user opens it a pie chart is displayed.

@bryevdv bryevdv added this to the short-term milestone Sep 11, 2018
@joaochenriques
Copy link

Help please!
I need to get the filename and the folder where the file is stored for the "kevinsa5 commented on May 3, 2017"

@kevinsa5
Copy link
Contributor

@joaochenriques that snippet of code does not store the file -- it only brings the file contents into memory. If you want to store the file somewhere on disk, you can try something like

with open("/path/to/output_file") as f:
    f.write(file_contents)

@joaochenriques
Copy link

Thank you @kevinsa5. I am a new user of Bokeh, and I forgot that it is a client/server architecture!

@bryevdv bryevdv modified the milestones: short-term, 1.1.2 May 8, 2019
@bryevdv
Copy link
Member
bryevdv commented May 8, 2019

Noting the SO example to create a custom extension it far out of date:

https://stackoverflow.com/a/42613897/3406693

Should either add a file dialog directly or create an updated example (and update that SO answer accordingly either way)

@philippjfr
Copy link
Contributor

Note that panel has an implementation of a FileInput widget, which could be moved into bokeh.

@bryevdv
Copy link
Member
bryevdv commented May 8, 2019

Note that panel has an implementation of a FileInput widget, which could be moved into bokeh.

It's not my birthday but I wouldn't turn down this present

@bryevdv
Copy link
Member
bryevdv commented Jul 12, 2019

@philippjfr I am going to see about doing this now, so it can be in the next release.

Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants
0