【问题标题】:color text in a editable Bokeh DataTable if value has changed如果值已更改,可编辑 Bokeh DataTable 中的颜色文本
【发布时间】:2020-05-05 07:05:59
【问题描述】:

我正在使用 Bokeh DataTable 来呈现一个可编辑的表格,如果用户更改了值,我希望为单元格中的文本着色。
我试图使用HTMLTemplateFormatter,但我不知道该怎么做。
如果用户更改了第 2 行的值,我希望文本的颜色如下:

基于How to color rows and/or cells in a Bokeh DataTable?的示例:

from bokeh.plotting import curdoc
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import DataTable, TableColumn, HTMLTemplateFormatter

orig_data = dict(
    cola=[1, 2, 3, 4, 5, 6],
)
data = orig_data
source = ColumnDataSource(data)
template = """
            <div style="color: <%= 
                    (function colorfromint(){
                        if(orig_data.cola != data.cola){return('red')} // I don't know what to write here
                        }()) %>;"> 
                <%= value %>
                </font>
            </div>
            """
formatter = HTMLTemplateFormatter(template=template)
columns = [TableColumn(field="cola", title="CL1", formatter=formatter, width=100)]
data_table = DataTable(source=source,
                       columns=columns,
                       editable=True,
                       width=100)
curdoc().add_root(data_table)

我可以使用HTMLTemplateFormatter 块比较不同的表吗?
如果没有,来自HTMLTemplateFormatter Bokeh documentation
“格式化程序可以通过传递给格式化程序的 dataContext 对象访问行中的其他项目”
所以我能想到的一种解决方案是加入表格并与 dataContext 对象进行比较,只显示我选择的列
但是,我不知道该怎么做,在我看来这是一个“肮脏”的解决方法

我对 python 很熟悉,但我是 Bokeh 的新手。

有没有好又简单的方法呢?
也许除了HTMLTemplateFormatter之外的其他方法?

【问题讨论】:

  • 您想只为单个列提供这样的功能吗?或者任意数量的列?
  • 任意数量的列,我希望能够为DataTable中的每个单元格应用它

标签: python bokeh bokehjs


【解决方案1】:

由于默认的 Bokeh 格式化程序适用于整个列,因此您必须创建自己的格式化程序。

即使没有 Bokeh 服务器,下面的示例也可以工作,这就是它使用 show 的原因。但是您可以将其替换为 curdoc().add_root - 它应该可以正常工作。

from bokeh.core.property.container import List
from bokeh.core.property.primitive import Int
from bokeh.io import show
from bokeh.models import ColumnDataSource, CustomJS, StringFormatter
from bokeh.models.widgets import DataTable, TableColumn

data = dict(cola=[1, 2, 3, 4, 5, 6],
            colb=[1, 2, 3, 4, 5, 6])
orig_ds = ColumnDataSource(data)
ds = ColumnDataSource(copy.deepcopy(data))

class RowIndexFormatter(StringFormatter):
    rows = List(Int, default=[])

    # language=TypeScript
    __implementation__ = """\
import {StringFormatter} from "models/widgets/tables/cell_formatters"
import * as p from "core/properties"
import {div} from "core/dom"


export namespace RowIndexFormatter {
  export type Attrs = p.AttrsOf<Props>

  export type Props = StringFormatter.Props & {
    rows: p.Property<number[]>
  }
}

export interface RowIndexFormatter extends RowIndexFormatter.Attrs {}

export class RowIndexFormatter extends StringFormatter {
  properties: RowIndexFormatter.Props

  constructor(attrs?: Partial<RowIndexFormatter.Attrs>) {
    super(attrs)
  }

  static init_RowIndexFormatter(): void {
    this.define<RowIndexFormatter.Props>({
      rows: [ p.Array, [] ]
    })
  }

  doFormat(row: any, _cell: any, value: any, _columnDef: any, _dataContext: any): string {
    // Mostly copied from `StringFormatter`, except for taking `rows` into account.
    const {font_style, text_align, text_color} = this

    const text = div({}, value == null ? "" : `${value}`)
    switch (font_style) {
      case "bold":
        text.style.fontWeight = "bold"
        break
      case "italic":
        text.style.fontStyle = "italic"
        break
    }

    if (text_align != null)
      text.style.textAlign = text_align
    if (text_color != null && this.rows.includes(row))
      text.style.color = text_color

    return text.outerHTML
  }
}
    """

columns = [TableColumn(field="cola", title="CL1", formatter=RowIndexFormatter(text_color='red')),
           TableColumn(field="colb", title="CL2", formatter=RowIndexFormatter(text_color='blue'))]
table = DataTable(source=ds, columns=columns, editable=True)
cb = CustomJS(args=dict(orig_ds=orig_ds, table=table),
              code="""\
                  const columns = new Map(table.columns.map(c => [c.field, c]));
                  for (const c of cb_obj.columns()) {
                      const orig_col = orig_ds.data[c];
                      const formatter = columns.get(c).formatter;
                      formatter.rows = [];
                      cb_obj.data[c].forEach((val, idx) => {
                          if (val != orig_col[idx]) {
                              formatter.rows.push(idx);
                          }
                      });
                  }
                  table.change.emit();
              """)
ds.js_on_change('data', cb)
ds.js_on_change('patching', cb)

show(table)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 2023-02-16
    • 2016-02-02
    相关资源
    最近更新 更多