Hello everyone,
I’m trying to interactively highlight a node of a graph in a diffferent color after the graph has been created.
This question provides a more concrete example than in my previously posted question in https://discourse.holoviz.org/t/how-to-add-node-attribute-after-a-graph-has-been-created/4128. I hope you might have an idea how to code this.
The code below shows what I mean:
import panel as pn
import numpy as np
import holoviews as hv
pn.extension()
def hv_graph():
# set up the graph
node_indices = np.arange(3, dtype=np.int32)
source = np.zeros(3, dtype=np.int32)
target = node_indices
# create graph
x, y = [0, 1, 1], [0, 1, 2] # some coordinates
nodes = hv.Nodes((x, y, node_indices),)
graph = hv.Graph(((source, target), nodes))
return graph
def adjust_graph(graph, highlight_node):
node_indices = graph.nodes.data["index"].values
# set node colors
node_colors = []
for node in node_indices:
# below the squared brackets are required as this example only allows one node to be colored
if node == highlight_node: # color the chosen node red
node_colors.append("red")
else:
node_colors.append("black") # color all other nodes with any other color
graph.nodes.data["color"] = node_colors
graph = graph.opts(node_color='color')
return graph
def both_function_combined_works(highlight_node):
node_indices = np.arange(3, dtype=np.int32)
# set node colors
node_colors = []
for node in node_indices:
# below the squared brackets are required as this example only allows one node to be colored
if node == highlight_node: # color the chosen node red
node_colors.append("red")
else:
node_colors.append("black") # color all other nodes with any other color
# set up the graph
source = np.zeros(3, dtype=np.int32)
target = node_indices
# create graph, this time with the node color integrated directly into the graph
x, y = [0, 1, 1], [0, 1, 2] # some coordinates
nodes = hv.Nodes((x, y, node_indices, node_colors), vdims='color')
graph = hv.Graph(((source, target), nodes))
graph = graph.opts(node_color='color')
return graph
## works
h = pn.interact(both_function_combined_works, highlight_node=[0, 1, 2])
h.save('works.html', embed=True)
#
## doesn't work for some reason
# error message:
# (BAD_COLUMN_NAME): Glyph refers to nonexistent column name.
# This could either be due to a misspelling or typo, or due to an expected #column being missing.
graph = hv_graph()
def adjust_helper(highlight_node):
return adjust_graph(graph, highlight_node)
h2 = pn.interact(adjust_helper, highlight_node=[0, 1, 2])
h2.save('does_not_work.html', embed=True)
If the color is directly specified as the graph is created then its easy. This is shown below in the function both_function_combined_works()
(saved in 'works.html
).
However, first creating the graph with hv_graph()
and then adjusting the color in the function adjust_graph()
results in the following error (result saved in 'does_not_work.html'
).
ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME): Glyph refers to nonexistent column name. This could either be due to a misspelling or typo, or due to an expected column being missing. : key "fill_color" value "color", key "hatch_color" value "color" [renderer: GlyphRenderer(id='2023', ...)]
This must be because graph.nodes.data["color"] = node_colors
is an insufficient way to specify a graph attribute after the fact. For example graph.nodes.columns()
does not show color
as a column, whereas graph.nodes.data
does.
So how do I resolve this error and get my code to work in that case?
I hope my question is clear. Feel free to ask if anything is confusing.