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

ssm*_*ssm 10 javascript python upload file bokeh

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

DuC*_*rey 5

尽管没有用于文件输入的本机Bokeh小部件。扩展Bokeh提供的当前工具是完全可行的。该答案将尝试指导您完成创建自定义小部件以及修改bokeh javascript以读取,解析和输出文件的步骤。

首先,尽管很多功劳归功于bigreddot先前创建小部件的答案。我只是在他的答案中扩展了文字,以添加文件处理功能。

现在,我们在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.
""")
Run Code Online (Sandbox Code Playgroud)

然后,我们为新的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 ]
  }
Run Code Online (Sandbox Code Playgroud)

在python的Back上,我们可以将bokeh 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)
Run Code Online (Sandbox Code Playgroud)

此应用程序的.csv文件的示例为。确保csv的末尾没有多余的行。

x,y
0,2
2,3
6,4
7,5
10,25
Run Code Online (Sandbox Code Playgroud)

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

input_widget
   |
   +---main.py
   +---models.py
   +---static
        +---js
            +--- extensions_file_input.coffee
            +--- papaparse.js
Run Code Online (Sandbox Code Playgroud)

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


Qic*_*hao 1

据我所知,Bokeh 本身没有允许文件上传的小部件。

如果您能进一步澄清当前的设置,将会很有帮助。您的绘图是在散景服务器上运行还是仅通过生成绘图的 Python 脚本运行?

一般来说,如果您需要通过浏览器公开它,您可能需要像 Flask 这样的东西来运行一个页面,让用户将文件上传到一个目录,然后 bokeh 脚本可以读取和绘制该目录。