使用JavaScript Papa Parse将CSV文件加载到静态Python Bokeh Web应用程序中



我有一个本地使用的静态Bokeh web应用程序,我希望能够在不运行python的情况下使用javascript加载文件。其想法是能够与其他非python用户共享Bokeh output.html文件,以运行该文件,并使用文件选择器加载他们的数据,从而实现交互式可视化。我根据这篇文章和这篇文章做了一个非常粗略的代码

我对JS一无所知,我提前为糟糕的实现道歉。如果您有类似的例子或更简单的方法在没有bokeh服务器的情况下读取文件,请放心。

from bokeh.models.widgets import Toggle
from bokeh.plotting import figure, output_file, show
output_file("load_data_buttons.html")
x = [0]
y = x
source = ColumnDataSource(data=dict(x=x, y=y))
plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
callback = CustomJS(args=dict(source=source), code="""
// initialize our parsed_csv to be used wherever we want
var parsed_csv;
var start_time, end_time;
// document.ready
$(function() {
$('.load-file').on('click', function(e) {
start_time = performance.now();
$('#report').text('Processing...');
console.log('initialize worker');
var worker = new Worker('worker.js');
worker.addEventListener('message', function(ev) {
console.log('received raw CSV, now parsing...');
// Parse our CSV raw text
Papa.parse(ev.data, {
header: true,
dynamicTyping: true,
complete: function (results) {
// Save result in a globally accessible var
parsed_csv = results;
console.log('parsed CSV!');
console.log(parsed_csv);
$('#report').text(parsed_csv.data.length + ' rows processed');
end_time = performance.now();
console.log('Took ' + (end_time - start_time) + " milliseconds to load and process the CSV file.")
}
});
// Terminate our worker
worker.terminate();
}, false);
// Submit our file to load
var file_to_load = document.getElementById("myFile").files[0];
console.log('call our worker');
worker.postMessage({file: file_to_load});
});
});
x =  parsed_csv.data['x']
y =  parsed_csv.data['y']
#load data stored in the file name and assign to x and y
source.trigger('change');
""")
toggle1 = Toggle(label="Load data file 1", callback=callback)
layout = Row(toggle1, plot)
show(layout)

worker.js

self.addEventListener('message', function(e) {
console.log('worker is running');
var file = e.data.file;
var reader = new FileReader();
reader.onload = function (fileLoadedEvent) {
console.log('file loaded, posting back from worker');
var textFromFileLoaded = fileLoadedEvent.target.result;
// Post our text file back from the worker
self.postMessage(textFromFileLoaded);
};
// Actually load the text file
reader.readAsText(file, "UTF-8");
}, false);

csv文件具有x,y数据

x   y
0   0
1   1
2   2
3   3
4   4

您不需要Web Workers来实现它,尤其是在您不熟悉JavaScript的情况下。我会这样做:

from bokeh.layouts import row, column
from bokeh.models import Div, ColumnDataSource, CustomJS, FileInput
from bokeh.plotting import figure, save
source = ColumnDataSource(data=dict(x=[0], y=[0]))
plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
fi_label = Div(text='Load data file 1')
fi = FileInput()
status = Div()
callback = CustomJS(args=dict(source=source,
status=status),
code="""
status.text = 'Loading...';
Papa.parse(atob(cb_obj.value), {
// For some reason, Papa didn't detect it automatically.
delimiter: 't',
header: true,
dynamicTyping: true,
complete: function (results) {
const acc = results.meta.fields.reduce((acc, f) => {
acc[f] = [];
return acc;
}, {});
source.data = results.data.reduce((acc, row) => {
for (const k in acc) {
acc[k].push(row[k]);
}
return acc;
}, acc);
status.text = 'Ready!';
}
});
""")
fi.js_on_change('value', callback)
template = """
{% block preamble %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"
integrity="sha256-Fh801SO9gqegfUdkDxyzXzIUPWzO/Vatqj8uN+5xcL4="
crossorigin="anonymous"></script>
{% endblock %}
"""
# Cannot use `show` because it doesn't have the `template` argument.
save(column(row(fi_label, fi), plot), template=template)

最新更新