我希望用户能够上传一个csv文件,然后在Bokeh中处理和可视化。输入文件有三列(a,b和c),我想读取其中两列进行显示。
我从https://github.com/bokeh/bokeh/issues/6096复制了一些内容以获取Javascript输入按钮。
现在我的输入文件正在控制台中显示,但我无法弄清楚如何将其输入DataTable小部件。我是否需要编写更新功能?谢谢你的帮助!
import pandas as pd
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import Button, DataTable, TableColumn
from bokeh.io import curdoc
import io
import base64
file_source = ColumnDataSource(data=dict(a=[],b=[],c=[]))
def file_callback(attr,old,new):
print ('filename:', file_source.data['file_name'])
raw_contents = file_source.data['file_contents'][0]
prefix, b64_contents = raw_contents.split(",", 1)
file_contents = base64.b64decode(b64_contents)
file_io = io.StringIO(bytes.decode(file_contents))
df = pd.read_csv(file_io)
print('file contents:', df)
return df
file_source.on_change('data', file_callback)
columns = [
TableColumn(field="a", title="a"),
TableColumn(field="b", title="b")
]
table = DataTable(source=file_source.data,columns=columns, width=400)
button = Button(label="Upload", button_type="success")
button.callback = CustomJS(args=dict(file_source=file_source,table=table), code = """
function read_file(filename) {
var reader = new FileReader();
reader.onload = load_handler;
reader.onerror = error_handler;
// 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.onchange = function(){
if (window.FileReader) {
read_file(input.files[0]);
} else {
alert('FileReader is not supported in this browser');
}
}
input.click();
""")
curdoc().add_root(row(button,table))
答案 0 :(得分:1)
这对我有用(Python 3.6和散景0.12.13):
import pandas as pd
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import Button, DataTable, TableColumn
from bokeh.io import curdoc
from io import StringIO
import base64
dict1 = {
'x':[0]*6,
'y':[1,1,1,2,2,2]
}
table_source = ColumnDataSource(data=dict1)
columns = [
TableColumn(field="x", title="x"),
TableColumn(field="y", title="y")
]
data_table = DataTable(
source=table_source, columns=columns,
width=800, editable=True
)
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)
# print("B64 decoded: file_contents : %s" % file_contents)
# Remove byte order mask and decode to str
file_contents = file_contents.decode("utf-8-sig")
# print("Decoded file_contents : %s" % file_contents)
file_io = StringIO(file_contents)
# Separator might need to be adjusted
df = pd.read_csv(file_io, sep=";")
table_source.data = table_source.from_df(df)
print("Table source data: %s" % table_source.data)
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.onload = load_handler;
reader.onerror = error_handler;
// 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.onchange = function(){
if (window.FileReader) {
read_file(input.files[0]);
} else {
alert('FileReader is not supported in this browser');
}
}
input.click();
""")
curdoc().add_root(row(button, data_table))
我创建了一个;
分隔的.csv文件。要将其作为DataFrame加载,我必须在file_callback
中添加和调整您的代码。这是因为(至少我的.csv)包含Byte Order mark我删除了:
file_contents = file_contents.decode("utf-8-sig")
df = pd.read_csv(file_io, sep=";")
然后,我为DataTable小部件定义了一个新的table_source
。在转换为DataFrame后,上传的.csv中的数据会更新。这发生在file_callback
这里:
table_source.data = table_source.from_df(df)
这些最后的部分是你缺少的部分。 我将此answer用于您提到的github问题,作为我的代码的基础。