我需要你对我几天来面临的一些挑战的意见。
我的目标是有一个上传按钮,我可以从中分享.xlsx
个文件。一旦我加载这些数据并将其读入pandas DataFrame
,我就会执行一些pythonic计算/优化代码等,并得到一些结果(表格总结)。现在,基于唯一“级别”/“组”的数量,我将创建许多选项卡,然后在每个选项卡中显示此汇总结果。在主页面上也有一般(常见)图。
以下是我的努力(不是我的,但社区的:) :):
## Load library
###########################################################################
import pandas as pd
import numpy as np
from xlrd import XLRDError
import io
import base64
import os
from bokeh.layouts import row, column, widgetbox, layout
from bokeh.models import ColumnDataSource, CustomJS, LabelSet
from bokeh.models.widgets import Button, Div, TextInput, DataTable, TableColumn, Panel, Tabs
from bokeh.io import curdoc
from bokeh.plotting import figure
###########################################################################
## Upload Button Widget
file_source = ColumnDataSource({'file_contents':[], 'file_name':[]})
cds_test = ColumnDataSource({'v1':[], 'v2':[]})
def file_callback(attr,old,new):
global tabs, t
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.BytesIO(file_contents)
# Here it errors out when trying '.xlsx' file but work for .csv Any Idea ????
#df1 = pd.read_excel(file_io, sheet = 'Sheet1')
#df2 = pd.read_excel(file_io, sheet = 'Sheet2')
# call some python functions for analysis
# returns few results
# for now lets assume main_dt has all the results of analysis
df1 = pd.read_excel(file_path, sheet_name = 'Sheet1')
df2 = pd.read_excel(file_path, sheet_name = 'Sheet2')
main_dt = pd.DataFrame({'v1':df1['v1'], 'v2': df2['v2']})
level_names = main_dt['v2'].unique().tolist()
sum_v1_level = []
for i in level_names:
csd_temp = ColumnDataSource(main_dt[main_dt['v2'] == i])
columns = [TableColumn(field=j, title="First") for j in main_dt.columns]
dt = DataTable(source = csd_temp, columns = columns, width=400, height=280)
temp = Panel(child = dt, title = i)
t.append(temp)
sum_v1_level.append(sum(csd_temp.data['v1']))
tabs = Tabs(tabs = t)
cds_plot = ColumnDataSource({'x':level_names, 'y':sum_v1_level})
p_o = figure(x_range = level_names, plot_height=250, title="Plot")
p_o.vbar(x='x', top = 'y', width=0.9, source = cds_plot)
p_o.xgrid.grid_line_color = None
p_o.y_range.start = 0
p_o.y_range.end = max(sum_v1_level)*1.2
labels_o = LabelSet(x='x', y = 'y', text='y', level='glyph',
x_offset=-13.5, y_offset=0, render_mode='canvas', source = cds_plot)
p_o.add_layout(labels_o)
curdoc().add_root(p_o)
curdoc().add_root(tabs)
print('successful upload')
file_source.on_change('data', file_callback)
button = Button(label="Upload Data", button_type="success")
# when butotn is clicked, below code in CustomJS will be called
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();
""")
Bdw:有什么方法可以抑制这个警告,或者我是以错误的方式做的?(将读取列插入CDS时)
BokehUserWarning:ColumnDataSource的列长度必须相同。当前长度:('v1',19),('v2',0)
curdoc().title = 'Test Joel'
curdoc().add_root(button)
这是原始数据:
注意:这里共享的所有数据都是虚拟的,真实案例有更多的工作表和更多的维度。
总结一下:
无法通过上传按钮
.xlsx
文件
在按钮回调函数中执行所有步骤是否正确?
答案 0 :(得分:2)
对于那些您将参考此线程的人:这是一个有上传按钮来处理.xlsx
文件的解决方案。这是为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 :)
答案 1 :(得分:1)
现在以这种方式使用CDS的一般想法是合理的。在未来,应该有更好的机制,但我不能推测它们何时可以实施。关于read_excel
的错误,这是一个熊猫问题/问题,而不是一个散景问题。
关于列长度的警告,几乎可以肯定地表明使用问题。它告诉您,您的v2
列是空的,这似乎不是您想要的,并且还违反了所有CDS列始终长度相同的基本假设。我不知道你为什么要为v2
生成一个空列表,但却无法运行代码。
编辑:例如,如果一切都是相同的长度,逐个添加工作正常:
In [4]: s.add([1,2,3], 'foo')
Out[4]: 'foo'
In [5]: s.add([1,2,3], 'bar')
Out[5]: 'bar'
当你添加的东西不是正确的长度时,这只是一个问题,这就是错误信息所说的:
In [6]: s.add([], 'baz')
/Users/bryanv/work/bokeh/bokeh/models/sources.py:138: BokehUserWarning: ColumnDataSource's columns must be of the same length. Current lengths: ('bar', 3), ('baz', 0), ('foo', 3)
"Current lengths: %s" % ", ".join(sorted(str((k, len(v))) for k, v in data.items())), BokehUserWarning))
Out[6]: 'baz'
如果您没有预先填写列的数据,请不要将“空列表”作为占位符放入,或者只要放入实际列,就会产生不一致的长度。这是你的问题的原因。