上传CSV文件并在Bokeh Web应用程序中阅读

时间:2016-11-24 20:36:42

标签: javascript python file upload bokeh

我有一个Bokeh绘图应用程序,我需要允许用户上传CSV文件并根据其中的数据修改绘图。 是否可以使用Bokeh的可用小部件执行此操作? 非常感谢你。

2 个答案:

答案 0 :(得分:3)

虽然没有用于文件输入的原生Bokeh小部件。扩展Bokeh提供的当前工具是非常可行的。这个答案将尝试引导您完成创建自定义小部件和修改散景javascript以读取,解析和输出文件的步骤。

首先,虽然在创建窗口小部件时有很多功劳归于bigreddot's previous answer。我只是在他的答案中扩展了coffescript以添加文件处理功能。

现在我们首先在python上创建一个新的bokeh类,它将链接到javascript类并保存文件输入生成的信息。

models.py

from bokeh.core.properties import List, String, Dict, Int
from bokeh.models import LayoutDOM

class FileInput(LayoutDOM):
__implementation__ = 'static/js/extensions_file_input.coffee'
__javascript__ = './input_widget/static/js/papaparse.js'

value = String(help="""
Selected input file.
""")

file_name = String(help="""
Name of the input file.
""")

accept = String(help="""
Character string of accepted file types for the input. This should be
written like normal html.
""")

data = List(Dict(keys_type=String, values_type=Int), default=[], help="""
List of dictionary containing the inputed data. This the output of the parser.
""")

然后我们为新的python类创建coffeescript实现。在这个新类中,有一个添加的文件处理函数,它在更改文件输入小部件时触发。此文件处理程序使用PapaParse来解析csv,然后将结果保存在类的data属性中。 PapaParse的javascript可以在他们的网站上下载。

您可以扩展和修改所需应用程序和数据格式的解析器。

extensions_file_input.coffee

import * as p from "core/properties"
import {WidgetBox, WidgetBoxView} from "models/layouts/widget_box"

export class FileInputView extends WidgetBoxView

  initialize: (options) ->
    super(options)
    input = document.createElement("input")
    input.type = "file"
    input.accept = @model.accept
    input.id = @model.id
    input.style = "width:" + @model.width + "px"
    input.onchange = () =>
      @model.value = input.value
      @model.file_name = input.files[0].name
      @file_handler(input)
    @el.appendChild(input)

  file_handler: (input) ->
    file = input.files[0]
    opts =  
      header: true,
      dynamicTyping: true,
      delimiter: ",",
      newline: "\r\n",
      complete: (results) =>
        input.data = results.data
        @.model.data = results.data
    Papa.parse(file, opts)


export class FileInput extends WidgetBox
  default_view: FileInputView
  type: "FileInput"
  @define {
    value: [ p.String ]
    file_name: [ p.String ]
    accept: [ p.String ]
    data : [ p.Array ]
  }

一个 回到python端,然后我们可以将一个散景on_change附加到我们的新输入类,以便在它的数据属性发生变化时触发。这将在csv解析完成后发生。此示例展示了所需的交互。

main.py

from bokeh.core.properties import List, String, Dict, Int
from bokeh.models import LayoutDOM

from bokeh.layouts import column
from bokeh.models import Button, ColumnDataSource
from bokeh.io import curdoc
from bokeh.plotting import Figure

import pandas as pd

from models import FileInput

# Starting data
x = [1, 2, 3, 4]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))

plot = Figure(plot_width=400, plot_height=400)
plot.circle('x', 'y', source=source, color="navy", alpha=0.5, size=20)

button_input = FileInput(id="fileSelect",
                         accept=".csv")


def change_plot_data(attr, old, new):
    new_df = pd.DataFrame(new)
    source.data = source.from_df(new_df[['x', 'y']])


button_input.on_change('data', change_plot_data)

layout = column(plot, button_input)
curdoc().add_root(layout)

此应用程序的.csv文件示例如下。确保csv末尾没有额外的行。

x,y
0,2
2,3
6,4
7,5
10,25

要正确运行此示例,必须以正确的应用程序文件树格式设置散景。

input_widget
   |
   +---main.py
   +---models.py
   +---static
        +---js
            +--- extensions_file_input.coffee
            +--- papaparse.js

要运行此示例,您需要位于最顶层文件上方的目录中,并在终端中执行bokeh serve input_widget

答案 1 :(得分:0)

据我所知,Bokeh没有可以上传文件的小部件。

如果您能更多地阐明当前的设置,将会很有帮助。您的图表是在散景服务器上运行还是仅通过生成图表的Python脚本运行?

一般情况下,如果你需要通过浏览器公开它,你可能会想要像Flask这样的东西运行一个页面,让用户将文件上传到散景脚本可以读取和绘制的目录。 / p>