Получить выбранный символ из графика NetworkX в Боке - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь получить индекс узлов, выбранных с помощью поля выбора из объекта GraphRender в Боке, чтобы создать связанную таблицу данных.(Я хочу иметь возможность получить индекс для выбранного узла)

Вопрос несколько похож на: Обратный вызов JavaScript для получения выбранного индекса глифа в Bokeh , однако я не смог его решитьиспользуя предложенное решение.

Полный код приведен ниже, и я попытался решить его с помощью пользовательского обратного вызова JS, но я не смог этого сделать.

Любая помощь очень ценится.Заранее спасибо!

(Примечание: это мой первый вопрос, поэтому, пожалуйста, дайте мне знать, если потребуется дополнительная информация.)

import pandas as pd
import numpy as np

from bokeh.layouts import row, widgetbox, column
from bokeh.models import ColumnDataSource, CustomJS, StaticLayoutProvider, Oval, Circle
from bokeh.models import HoverTool, TapTool, BoxSelectTool, GraphRenderer
from bokeh.models.widgets import RangeSlider, Button, DataTable, TableColumn, NumberFormatter
from bokeh.io import curdoc, show, output_notebook
from bokeh.plotting import figure

import networkx as nx

from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models.graphs import from_networkx, NodesAndLinkedEdges, EdgesAndLinkedNodes, NodesOnly

# Import / instantiate networkx graph
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)

# Node Characteristics
node_name = list(G.nodes())
positions = nx.spring_layout(G)

node_size = [k*4 for k in range(len(G.nodes()))]
nx.set_node_attributes(G, node_size, 'node_size')
visual_attributes=ColumnDataSource(
    pd.DataFrame.from_dict({k:v for k,v in G.nodes(data=True)},orient='index'))

# Edge characteristics
start_edge = [start_edge for (start_edge, end_edge) in G.edges()]
end_edge = [end_edge for (start_edge, end_edge) in G.edges()]
weight = list(nx.get_edge_attributes(G,'weight').values())

edge_df = pd.DataFrame({'source':start_edge, 'target':end_edge, 'weight':weight})

# Create full graph from edgelist 
G = nx.from_pandas_edgelist(edge_df,edge_attr=True)

# Convert full graph to Bokeh network for node coordinates and instantiate Bokeh graph object 
G_source = from_networkx(G, nx.spring_layout, scale=2, center=(0,0))
graph = GraphRenderer()

# Update loop where the magic happens
def update():
    selected_df = edge_df[(edge_df['weight'] >= slider.value[0]) & (edge_df['weight'] <= slider.value[1])]
    sub_G = nx.from_pandas_edgelist(selected_df,edge_attr=True)
    sub_graph = from_networkx(sub_G, nx.spring_layout, scale=2, center=(0,0))
    graph.edge_renderer.data_source.data = sub_graph.edge_renderer.data_source.data
    graph.node_renderer.data_source.data = G_source.node_renderer.data_source.data
    graph.node_renderer.data_source.add(node_size,'node_size')

def selected_points(attr,old,new):
    selected_idx = graph.node_renderer.selected.indices #does not work
    print(selected_idx)

# Slider which changes values to update the graph
slider = RangeSlider(title="Weights", start=0, end=1, value=(0.25, 0.75), step=0.10)
slider.on_change('value', lambda attr, old, new: update())

# Plot object which is updated 
plot = figure(title="Meetup Network Analysis", x_range=(-1.1,1.1), y_range=(-1.1,1.1),
             tools = "pan,wheel_zoom,box_select,reset,box_zoom,crosshair", plot_width=800, plot_height=800)

# Assign layout for nodes, render graph, and add hover tool
graph.layout_provider = StaticLayoutProvider(graph_layout=positions)
graph.node_renderer.glyph = Circle(size='node_size')
graph.selection_policy = NodesOnly()
plot.renderers.append(graph)
plot.tools.append(HoverTool(tooltips=[('Name', '@index')]))

# Set layout
layout = column(slider,plot)

# does not work
#graph.node_renderer.data_source.on_change("selected", selected_points)

# Create Bokeh server object
curdoc().add_root(layout)
update()

1 Ответ

0 голосов
/ 04 декабря 2018

Вместо того, чтобы помещать слушателя в graph.node_renderer.data_source.on_change, используйте вместо этого:

graph.node_renderer.data_source.selected.on_change("indices", selected_points)

Это вызовет ответ на стороне сервера.

Hongyi

...