Bokeh Networkx 图形滑块未正确更新

Bokeh Networkx graph slider not updating correctly

这是我面临的问题的最小工作示例:

我正在使用 Networkx 构建一个简单的图形,然后使用 Bokeh 显示它,添加一个滑块以仅显示权重大于滑块值的边。 不幸的是,当值增加时,这非常有效,即滑块向右移动,而当滑块值减小时它停止工作(一些边缘重新出现,但随后,当单击图形时,一切都爆炸了)。 在 customJS 回调函数中,我正在修改边缘数据,并且在将它的每一部分打印到控制台时,它们都按预期工作,但在浏览器控制台中我得到一个 Shape Mismatch 错误,即使未指定正在比较的两个形状。

import pandas as pd
import networkx as nx
from bokeh.io import show 
from bokeh.plotting import figure, from_networkx
from bokeh.models import CustomJS, Slider
from bokeh.layouts import row, column
import copy

df = pd.DataFrame(data={'Source': {0: 'A', 1: 'A', 2: 'A', 3: 'B', 4: 'B', 5: 'C'},
                        'Target': {0: 'B', 1: 'C', 2: 'D', 3: 'C', 4: 'D', 5: 'D'},
                        'Weight': {0: 0, 1: 1, 2: 1.5, 3: 0.6, 4: 3, 5: 4}}) 

G = nx.from_pandas_edgelist(df, 'Source', 'Target', 'Weight')

plot = figure(title='Attempt')
network_graph = from_networkx(G, nx.circular_layout, scale=1, center=(0, 0))
plot.renderers.append(network_graph)

# save edge data to select only a subset of the edges
backup_edge_data = copy.deepcopy(network_graph.edge_renderer.data_source.data)

slider = Slider(start=0, end=4, value=0, step=.2)


# the last line of this object (the one with change.emit()) is probably unnecessary
code = """
const old_Weight = edata["Weight"];
const old_start = edata["start"];
const old_end = edata["end"];

let acceptableIndexes = old_Weight.reduce(function(acc, curr, index) {
  if (curr >= cb_obj.value) {
    acc.push(index);
  }
  return acc;
}, []);


const new_Weight = acceptableIndexes.map(i => old_Weight[i]);
const new_start = acceptableIndexes.map(i => old_start[i]);
const new_end = acceptableIndexes.map(i => old_end[i]);

const new_data_edge = {'Weight': new_Weight, 
                       'start': new_start, 
                       'end': new_end};

graph_setup.edge_renderer.data_source.data = new_data_edge; 
graph_setup.edge_renderer.data_source.change.emit();
"""

callback = CustomJS(args = dict(graph_setup = network_graph,
                                edata = backup_edge_data),
                    code = code)

slider.js_on_change('value', callback)

layout = row(
    plot,
    column(slider),
)

show(layout)

image of the networkx graph and the slider

我发现这实际上是由于 bug 造成的: https://discourse.bokeh.org/t/dynamic-layout-behavior-changes-between-bokeh-2-2-3-and-bokeh-2-3-0/7594

为了在 bokeh 库未更新之前解决此问题(我使用的是 2.4.0 版),我修改了 customJS 代码以添加占位符数据以匹配初始数据源维度:

code = """
const old_Weight = edata["Weight"];
const old_start = edata["start"];
const old_end = edata["end"];

let acceptableIndexes = old_Weight.reduce(function(acc, curr, index) {
  if (curr >= cb_obj.value) {
    acc.push(index);
  }
  return acc;
}, []);

\ compute how many fake edges have to be added
const num_ph = old_Weight.length - acceptableIndexes.length
\ create an array of that dimension with fake value '9999'
const placeholder = Array(num_ph).fill('9999')

\ for each new value, concatenate the new array with the placeholder array
const new_Weight = acceptableIndexes.map(i => old_Weight[i]).concat(placeholder);
const new_start = acceptableIndexes.map(i => old_start[i]).concat(placeholder);
const new_end = acceptableIndexes.map(i => old_end[i]).concat(placeholder);

const new_data_edge = {'Weight': new_Weight, 
                       'start': new_start, 
                       'end': new_end};

graph_setup.edge_renderer.data_source.data = new_data_edge; 
graph_setup.edge_renderer.data_source.change.emit();
"""