如何将分类图例添加到networkx散景图

bir*_*rah 5 python data-visualization networkx bokeh

我有以下代码来从NetworkX制作散景图

p = figure(x_range=(-1.1, 1.1), y_range=(-1.1, 1.1))
p.grid.visible = False
p.axis.visible = False

graph_renderer = from_networkx(G, nx.spring_layout, random_state=11, center=(0, 0), scale=1, k=0.5)
color_map = factor_cmap('domain_cat', factors=factors, palette=Category10_6)

graph_renderer.node_renderer.glyph = Circle(radius=0.02, fill_color=color_map, line_color=None, fill_alpha=1)
graph_renderer.edge_renderer.glyph = MultiLine(line_color='lightgray', line_alpha=0.3, line_width=2)
p.renderers.append(graph_renderer)

p.add_tools(HoverTool(tooltips='@index', show_arrow=None))

show(p)
Run Code Online (Sandbox Code Playgroud)

效果很好。但是,我为节点有一个分类颜色图。我想添加一个图例。

使用绘图界面时,只需输入源列名称(https://docs.bokeh.org/en/latest/docs/user_guide/categorical.html#colors),即可轻松添加分类图例。

但是,即使通过模型接口,我也无法使用分类图例Legend和LegendItem来生成方法。

我尝试了以下形式:

items = [LegendItem(label=factor, renderers=[graph_renderer.node_renderer]) for factor in factors]
legend = Legend(items=items)
p.add_layout(legend)
Run Code Online (Sandbox Code Playgroud)

但这会产生以下结果,其中的空白图例表示正确的高度,而控制台错误为TypeError: v is undefined; can't access its "draw_legend" property

在此处输入图片说明

小智 0

我遇到了同样的问题,花了几个小时研究不同的解决方案,但没有像您那样使用 graph_renderer 找到特定的方法。不管怎样,我想出了一个手动解决方案,使用散景Div

\n
from bokeh.io import show\nfrom bokeh.models import Div\n\nlegendEntries = {\'#1f77b4\': \'192.168.0.0/24\',\n \'#aec7e8\': \'192.168.1.128/25\',\n \'#ff7f0e\': \'192.168.0.0/23\',\n \'#ffbb78\': \'192.168.4.0/25\',\n \'#2ca02c\': \'192.168.5.0/25\'}\n\nwith open ("resources/legend.css", "r") as f:\n    legend_css=f.read()\n\nwith open ("resources/legend.html", "r") as f:\n    legend_html=f.read()\n\ndef str_legend():\n    return "<p>" + "</p><p>".join([f"<span class=\'legend-entry\' style=\'background:{n}\'>&nbsp;</span>{v}" for n, v in legendEntries.items()]) + "</p>"\n\ndiv_legend = Div(css_classes=["legend-container"],\n    text=f"<style>{legend_css}</style>{legend_html.replace(\'<p></p>\',str_legend())}")\n\nshow(div_legend)\n
Run Code Online (Sandbox Code Playgroud)\n

这个脚本main.py至少绘制了一个非交互式图例。

\n

注意 1,然后您需要能够从您的数据创建 legendEntries 字典,但这不应该是一个问题,并且是另一个故事......

\n

注意 2,将 html 和 css 文件放在 python 脚本之外会更方便,因为您的编辑器能够根据语法规则突出显示;)

\n

为了方便起见,这里是“项目”结构:

\n
project\n\xe2\x94\x82   main.py  \n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80resources\n\xe2\x94\x82   \xe2\x94\x82   legend.css\n\xe2\x94\x82   \xe2\x94\x82   legend.html\n
Run Code Online (Sandbox Code Playgroud)\n

以及资源文件 legend.html:

\n
<fieldset id="legend-1">\n  <legend><h4>Legende</h4></legend>\n  <p></p>\n</fieldset>\n
Run Code Online (Sandbox Code Playgroud)\n

和图例.css:

\n
.legend-container {\n    z-index: 2;\n    top: 80px !important;\n    left: 780px !important;\n}\n\n.legend-container h4, p {\n    margin: 0 0 2px 0;\n}\n\nspan.legend-entry {\n  border: solid 0.5px black;\n  border-radius: 0.8em;\n  -moz-border-radius: 0.8em;\n  -webkit-border-radius: 0.8em;\n  display: inline-block;\n  font-weight: bold;\n  line-height: 1.6em;\n  margin-right: 7px;\n  text-align: center;\n  width: 1.6em;\n}\n\n.legend-container fieldset {\n    min-width: 140px;\n    background: white;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

要获得这个图例:

\n

图例截图

\n

注3:我使用的css样式.legend-container在图中移动图例

\n