Bokeh TapTool для отображения текста в Div при нажатии и сброса до пустого, если не нажать - PullRequest
0 голосов
/ 28 апреля 2020

это мой первый вопрос здесь, поэтому, пожалуйста, дайте мне знать, если мне нужно добавить какие-либо детали.

Я экспериментирую с созданием интерактивного сетевого графика в Bokeh. Я взял этот простой пример и пытаюсь воспроизвести часть этого примера , чтобы при нажатии на узел он и его края были видны.

У меня также есть Div, который изначально пуст, который я хочу заполнить при нажатии на узел. Прямо сейчас я могу это сделать ( см. Здесь ). Тем не менее, текст все еще там, когда я отменил выбор узла ( здесь ). Я довольно невежественен, когда дело доходит до JS, хотя у меня есть некоторый предыдущий опыт работы с Bokeh для простых сюжетов и взаимодействий, поэтому я немного растерялся, как поступить.

I Ниже приведен код, с которым я играл. Использование bokeh 1.0.2 и python 3.6.4.

Заранее спасибо!

import networkx as nx
from bokeh.io import show
from bokeh.models import Plot, TapTool, ColumnDataSource, LabelSet, StaticLayoutProvider, Circle, MultiLine
from bokeh.models.widgets import Div
from bokeh.models.graphs import NodesAndLinkedEdges, EdgesAndLinkedNodes
from bokeh.plotting import figure
from bokeh.models.renderers import GraphRenderer, GlyphRenderer
from bokeh.layouts import layout, row
from bokeh.models import CustomJS

G = nx.Graph()

G.add_edge('a', 'b', weight=0.6)
G.add_edge('a', 'c', weight=0.2)
G.add_edge('c', 'd', weight=0.1)
G.add_edge('c', 'e', weight=0.7)
G.add_edge('c', 'f', weight=0.9)
G.add_edge('a', 'd', weight=0.3)

elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] <= 0.5]

for u,v in G.edges():
    G[u][v]['color'] = 'red' if G[u][v]['weight'] <= 0.5 else 'black'

pos = nx.spring_layout(G)

node_ids = list(G.nodes())
start_ids = [a for a,b in G.edges()]
end_ids = [b for a,b in G.edges()]
weights = [10*G[a][b]['weight'] for a,b in G.edges()]
colors = [G[a][b]['color'] for a,b in G.edges()]

graph_layout = pos
label_layout = pos
x_graph, y_graph = [v[0] for v in graph_layout.values()], [v[1] for v in graph_layout.values()]
x_label, y_label = [v[0] for v in label_layout.values()], [v[1] for v in label_layout.values()]


node_ds = ColumnDataSource(data=dict(index=list(G.nodes()),
                                     x = x_graph,
                                     y = y_graph,
                                     color=['red', 'green', 'blue', 'black', 'orange', 'grey']),
                           name="Node Renderer")
edge_ds = ColumnDataSource(data=dict(start= start_ids,
                                      end=end_ids,
                                      weight = weights,
                                      color = colors),
                            name="Edge Renderer")

graph_plot = GraphRenderer(node_renderer=GlyphRenderer(glyph=Circle(size=15, fill_color="color"),
                                                       selection_glyph=Circle(size=15, fill_color="color"),
                                                  data_source=node_ds),
                      edge_renderer=GlyphRenderer(glyph=MultiLine(line_alpha=0.4, line_width= 'weight', line_color = 'color'),
                                                  selection_glyph=MultiLine(line_alpha=1, line_width = 'weight', line_color = 'color'),
                                                  nonselection_glyph=MultiLine(line_alpha=0, line_width = 'weight', line_color = 'color'),
                                                  data_source=edge_ds),
                      layout_provider=StaticLayoutProvider(graph_layout=graph_layout),
                      selection_policy=NodesAndLinkedEdges())

label_ds = ColumnDataSource(data=dict(index=list(G.nodes()),
                                      x = x_label,
                                      y = y_label))
labels = LabelSet(x='x', y='y', text='index', source=label_ds,
                  background_fill_color='lightgrey')

div = Div(text='', width=300)

plot = figure(x_range=(-1,1), y_range=(-1.1,1.1), plot_width=400, plot_height=400, name='main_plot')
plot.add_tools(TapTool(callback=CustomJS(args={'div': div}, code="""
    String.prototype.format = function() {
      a = this;
      for (k in arguments) {
        a = a.replace("{" + k + "}", arguments[k])
      }
      return a
    }
    var ind = cb_data.source.selected['1d'].indices;
    var color = cb_data.source.data['color'][ind];
    var name = cb_data.source.data['index'][ind];
    div.text = 'This is node {0}, it is colored {1}'.format(name, color);
""")))
plot.renderers.append(graph_plot)
plot.renderers.append(labels)
layout=row(plot,div)
show(layout)

1 Ответ

1 голос
/ 29 апреля 2020

Я действительно заставил это работать, просто добавив следующее:

plot.js_on_event('tap', CustomJS(args={'src': node_ds, 'div': div}, code="""
    if (src.selected.indices.length == 0){
        div.text = '';
    }
"""))

Я не знаю, является ли это лучшим способом сделать это, но пока это работает.

...