You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Holoviews图转为Bokeh GraphRenderer,兼顾箭头与节点样式控制?

解决Holoviews有向图+Bokeh节点属性控制的兼容问题

我明白你的痛点——想同时用上Holoviews的有向图箭头效果,又想用Bokeh的GraphRenderer来精细控制节点的颜色、大小和交互状态,但Holoviews渲染后返回的是Figure对象,没法直接调用node_renderer对吧?这里有两种靠谱的解决办法:

方法一:直接用Holoviews的opts完成所有配置(推荐)

其实Holoviews的Graph对象本身就支持绑定节点属性来控制样式,完全不需要切换到Bokeh的底层API。这样既可以保留directed=True的箭头,又能实现你要的基于属性的节点定制:

import networkx as nx
import holoviews as hv
from holoviews import opts
hv.extension('bokeh')
from bokeh.io import show, output_file
from bokeh.palettes import Viridis256, Inferno6

# 构建有向图
edgeList = [("A", "B"), ("B", "C"), ("A", "C"), ("C", "D"), ("D", "A")]
G = nx.DiGraph(edgeList)

# 给节点添加属性
numConnections = {k:v for k,v in G.out_degree()}
nx.set_node_attributes(G, numConnections, name='numConnections')
# 模拟节点大小属性(根据连接数调整)
node_sizes = {k: v*10 for k, v in numConnections.items()}
nx.set_node_attributes(G, node_sizes, name='node_size')

# 创建Holoviews Graph并一次性配置所有样式
hvGraph = hv.Graph.from_networkx(G, nx.spring_layout).opts(
    tools=['hover', 'tap', 'box_select'],
    directed=True,
    arrowhead_length=0.01,
    # 绑定节点属性到大小和颜色
    node_size='node_size',
    node_color='numConnections',
    node_cmap=Viridis256,
    node_fill_alpha=0.8,
    # 配置选中/悬停时的节点样式
    selection_fill_color=Inferno6[4],
    selection_node_size=25,
    hover_fill_color=Inferno6[3],
    hover_node_size=20,
    # 配置边的基础/选中/悬停样式
    edge_color="#CCCCCC",
    edge_alpha=0.8,
    edge_line_width=3,
    selection_edge_color=Inferno6[4],
    selection_edge_line_width=4,
    hover_edge_color=Inferno6[3],
    hover_edge_line_width=4,
    # 添加颜色条
    colorbar=True,
    colorbar_title='#connections'
)

# 渲染并导出
hvRendered = hv.render(hvGraph, 'bokeh')
output_file("holoviews_bokeh_combined.html")
show(hvRendered)

这种方式用Holoviews的声明式语法就能搞定一切,代码更简洁,也不用在两个库的API之间切换。

方法二:从Holoviews渲染的Figure中提取GraphRenderer

如果你一定要用Bokeh的GraphRenderer API来做更精细的控制,可以遍历渲染后Figure的renderers列表,找到其中的GraphRenderer实例,之后就可以像纯Bokeh代码一样操作它:

import networkx as nx
import holoviews as hv
from holoviews import opts
hv.extension('bokeh')
from bokeh.io import show, output_file
from bokeh.models import LinearColorMapper, Circle, MultiLine
from bokeh.palettes import Viridis256, Inferno6
from bokeh.models.graphs import NodesAndLinkedEdges

# 构建有向图和属性(同方法一)
edgeList = [("A", "B"), ("B", "C"), ("A", "C"), ("C", "D"), ("D", "A")]
G = nx.DiGraph(edgeList)
numConnections = {k:v for k,v in G.out_degree()}
nx.set_node_attributes(G, numConnections, name='numConnections')
node_sizes = {k: v*10 for k, v in numConnections.items()}
nx.set_node_attributes(G, node_sizes, name='node_size')

# 创建带箭头的Holoviews有向图
hvGraph = hv.Graph.from_networkx(G, nx.spring_layout).opts(
    tools=['hover'],
    directed=True,
    arrowhead_length=0.01
)

# 渲染为Bokeh Figure
hvRendered = hv.render(hvGraph, 'bokeh')

# 从Figure的渲染器中找到GraphRenderer
graph_renderer = None
for renderer in hvRendered.renderers:
    if hasattr(renderer, 'node_renderer'):
        graph_renderer = renderer
        break

# 现在可以像纯Bokeh代码一样配置样式了
if graph_renderer:
    # 配置颜色映射
    mapper = LinearColorMapper(
        palette="Viridis256", 
        low=min(numConnections.values()), 
        high=max(numConnections.values())
    )
    
    # 节点样式配置
    graph_renderer.node_renderer.glyph = Circle(
        size='node_size',
        fill_color={'field': "numConnections", "transform": mapper},
        fill_alpha=.8
    )
    graph_renderer.node_renderer.selection_glyph = Circle(
        size=25,
        fill_color=Inferno6[4]
    )
    graph_renderer.node_renderer.hover_glyph = Circle(
        size=20,
        fill_color=Inferno6[3]
    )
    
    # 边样式配置
    graph_renderer.edge_renderer.glyph = MultiLine(
        line_color="#CCCCCC",
        line_alpha=0.8,
        line_width=3
    )
    graph_renderer.edge_renderer.selection_glyph = MultiLine(
        line_color=Inferno6[4],
        line_width=4
    )
    graph_renderer.edge_renderer.hover_glyph = MultiLine(
        line_color=Inferno6[3],
        line_width=4
    )
    
    # 配置选择和检查策略
    graph_renderer.selection_policy = NodesAndLinkedEdges()
    graph_renderer.inspection_policy = NodesAndLinkedEdges()
    
    # 添加颜色条
    from bokeh.models import ColorBar, BasicTicker
    bar = ColorBar(color_mapper=mapper, location=(0,0), title='#connections')
    hvRendered.add_layout(bar, 'right')

# 保存并显示
output_file("holoviews_extract_graphrenderer.html")
show(hvRendered)

为什么之前会报错?

你遇到的AttributeError: 'BokehRenderer' object has no attribute 'node_renderer',是因为hv.render()返回的是Bokeh的Figure对象,而node_renderer是GraphRenderer独有的属性。所以必须先从Figure的renderers集合里找到对应的GraphRenderer实例,才能访问这些属性。

内容的提问来源于stack exchange,提问作者albertk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:45:13