【问题标题】:is there a way to save bokeh data table content有没有办法保存散景数据表内容
【发布时间】:2015-10-27 17:37:20
【问题描述】:

我正在尝试使用bokeh data table 在网页中显示数据embedded。它工作得很好。

有没有办法从显示的数据表中保存表内容?其他散景图具有用于各种功能的工具栏,包括保存,但 DataTable 似乎没有附带。我对散景数据表使用的 javascript 或 slickgrid 知之甚少。并且想知道是否可以做到。

谢谢!

编辑 - 我原来的问题似乎不够清楚。希望以下图片能帮助说明:

散景图有相关的工具栏:

但数据表默认没有,也不带'tools'参数:

是否可以在数据表中添加“保存”按钮,以便查看表的人可以下载制表符分隔或 csv 文件?不一定要长得一样,但保存功能要一样。

【问题讨论】:

    标签: python datatable slickgrid bokeh


    【解决方案1】:

    如果 bokeh 提供一个工具按钮来保存/导出数据表到 csv / txt / excel 文件,那就太好了。如果它已经存在,我还没有在文档中找到它。

    同时,一个可能的答案是使用本机 javascript 将 js 数组(位于散景数据表下方)导出到 CSV。它已被描述为herehere

    添加:散景具有使用 js 的回调。一个简单的描述是here。仍在阅读它...

    编辑:它可能已经存在了一段时间,但我刚刚注意到 Bokeh 网站上的 saving csv from data table 示例。

    【讨论】:

      【解决方案2】:

      2021 年更新:调整后的代码适用于 python 3.8 和 bokeh 2.2.3

      对于那些难以调整或在散景网站上查找示例或只是非常懒惰的人,下面的代码可以做最少的工作:

      from bokeh.models import ColumnDataSource, CustomJS
      from bokeh.models.widgets import Button
      from bokeh.io import show
      import os
      
      source = ColumnDataSource({'list1':[0,1,2,3],'list2':[4,5,6,7]})
      button = Button(label="Download", button_type="success")
      button.js_on_click(CustomJS(args=dict(source=source),code=open(os.path.join(os.path.dirname(__file__),"download.js")).read()))
      show(button)
      

      还有文件download.js:

      function table_to_csv(source) {
          const columns = Object.keys(source.data)
          const nrows = source.get_length()
          const lines = [columns.join(',')]
      
          for (let i = 0; i < nrows; i++) {
              let row = [];
              for (let j = 0; j < columns.length; j++) {
                  const column = columns[j]
                  row.push(source.data[column][i].toString())
              }
              lines.push(row.join(','))
          }
          return lines.join('\n').concat('\n')
      }
      
      
      const filename = 'data_result.csv'
      const filetext = table_to_csv(source)
      const blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' })
      
      //addresses IE
      if (navigator.msSaveBlob) {
          navigator.msSaveBlob(blob, filename)
      } else {
          const link = document.createElement('a')
          link.href = URL.createObjectURL(blob)
          link.download = filename
          link.target = '_blank'
          link.style.visibility = 'hidden'
          link.dispatchEvent(new MouseEvent('click'))
      }
      

      【讨论】:

      • 谢谢,这很有帮助。出于某种原因,我无法使 Bokeh 网站上的示例正常工作。
      • 这段代码的问题是Object.keys 检索到的列与表中的列顺序不同,而是始终按字母顺序检索。执行source.data 时,Python 中不会出现此问题。
      • @pablo,问题不在于列的顺序,而在于创建下载按钮。如果对您来说,要求列的顺序与数据框中的顺序相同,请创建一个新问题。或者,如果您已经知道如何操作,只需自己添加即可。
      【解决方案3】:

      与我对this stackoverflow question 的回复有关。回复复制如下:

      这是一个使用 Python 3.7.5 和 Bokeh 1.4.0 的工作示例

      此 jupyter 笔记本的公共 github 链接:
      https://github.com/surfaceowl-ai/python_visualizations/blob/master/notebooks/bokeh_save_linked_plot_data.ipynb

      环境报告:

      虚拟环境 python 版本:Python 3.7.5
      虚拟环境 ipython 版本:7.9.0

      水印包报告:

      散景 1.4.0
      jupyter 1.0.0
      numpy 1.17.4
      熊猫 0.25.3
      崛起 5.6.0
      水印 2.0.2

      # Generate linked plots + TABLE displaying data + save button to export cvs of selected data
      
      from random import random
      
      from bokeh.io import output_notebook  # prevent opening separate tab with graph
      from bokeh.io import show
      
      from bokeh.layouts import row
      from bokeh.layouts import grid
      from bokeh.models import CustomJS, ColumnDataSource
      from bokeh.models import Button  # for saving data
      from bokeh.models.widgets import DataTable, DateFormatter, TableColumn
      from bokeh.models import HoverTool
      from bokeh.plotting import figure
      
      
      # create data
      x = [random() for x in range(500)]
      y = [random() for y in range(500)]
      
      # create first subplot
      plot_width = 400
      plot_height = 400
      
      s1 = ColumnDataSource(data=dict(x=x, y=y))
      fig01 = figure(
          plot_width=plot_width,
          plot_height=plot_height,
          tools=["lasso_select", "reset", "save"],
          title="Select Here",
      )
      fig01.circle("x", "y", source=s1, alpha=0.6)
      
      # create second subplot
      s2 = ColumnDataSource(data=dict(x=[], y=[]))
      
      # demo smart error msg:  `box_zoom`, vs `BoxZoomTool`
      fig02 = figure(
          plot_width=400,
          plot_height=400,
          x_range=(0, 1),
          y_range=(0, 1),
          tools=["box_zoom", "wheel_zoom", "reset", "save"],
          title="Watch Here",
      )
      
      fig02.circle("x", "y", source=s2, alpha=0.6, color="firebrick")
      
      # create dynamic table of selected points
      columns = [
          TableColumn(field="x", title="X axis"),
          TableColumn(field="y", title="Y axis"),
      ]
      
      table = DataTable(
          source=s2,
          columns=columns,
          width=400,
          height=600,
          sortable=True,
          selectable=True,
          editable=True,
      )
      
      # fancy javascript to link subplots
      # js pushes selected points into ColumnDataSource of 2nd plot
      # inspiration for this from a few sources:
      # credit: https://stackoverflow.com/users/1097752/iolsmit via: https://stackoverflow.com/questions/48982260/bokeh-lasso-select-to-table-update
      # credit: https://stackoverflow.com/users/8412027/joris via: https://stackoverflow.com/questions/34164587/get-selected-data-contained-within-box-select-tool-in-bokeh
      
      s1.selected.js_on_change(
          "indices",
          CustomJS(
              args=dict(s1=s1, s2=s2, table=table),
              code="""
              var inds = cb_obj.indices;
              var d1 = s1.data;
              var d2 = s2.data;
              d2['x'] = []
              d2['y'] = []
              for (var i = 0; i < inds.length; i++) {
                  d2['x'].push(d1['x'][inds[i]])
                  d2['y'].push(d1['y'][inds[i]])
              }
              s2.change.emit();
              table.change.emit();
      
              var inds = source_data.selected.indices;
              var data = source_data.data;
              var out = "x, y\\n";
              for (i = 0; i < inds.length; i++) {
                  out += data['x'][inds[i]] + "," + data['y'][inds[i]] + "\\n";
              }
              var file = new Blob([out], {type: 'text/plain'});
      
          """,
          ),
      )
      
      # create save button - saves selected datapoints to text file onbutton
      # inspriation for this code:
      # credit:  https://stackoverflow.com/questions/31824124/is-there-a-way-to-save-bokeh-data-table-content
      # note: savebutton line `var out = "x, y\\n";` defines the header of the exported file, helpful to have a header for downstream processing
      
      savebutton = Button(label="Save", button_type="success")
      savebutton.callback = CustomJS(
          args=dict(source_data=s1),
          code="""
              var inds = source_data.selected.indices;
              var data = source_data.data;
              var out = "x, y\\n";
              for (i = 0; i < inds.length; i++) {
                  out += data['x'][inds[i]] + "," + data['y'][inds[i]] + "\\n";
              }
              var file = new Blob([out], {type: 'text/plain'});
              var elem = window.document.createElement('a');
              elem.href = window.URL.createObjectURL(file);
              elem.download = 'selected-data.txt';
              document.body.appendChild(elem);
              elem.click();
              document.body.removeChild(elem);
              """,
      )
      
      # add Hover tool
      # define what is displayed in the tooltip
      tooltips = [
          ("X:", "@x"),
          ("Y:", "@y"),
          ("static text", "static text"),
      ]
      
      fig02.add_tools(HoverTool(tooltips=tooltips))
      
      # display results
      # demo linked plots
      # demo zooms and reset
      # demo hover tool
      # demo table
      # demo save selected results to file
      
      layout = grid([fig01, fig02, table, savebutton], ncols=3)
      
      output_notebook()
      show(layout)
      
      # things to try:
      # select random shape of blue dots with lasso tool in 'Select Here' graph
      # only selected points appear as red dots in 'Watch Here' graph -- try zooming, saving that graph separately
      # selected points also appear in the table, which is sortable
      # click the 'Save' button to export a csv
      
      # TODO:  export from Bokeh to pandas dataframe
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-02
        • 2019-02-14
        • 2019-09-28
        • 2011-09-23
        • 2023-03-03
        • 1970-01-01
        • 2019-09-28
        • 1970-01-01
        相关资源
        最近更新 更多