Graph 如何在bokeh中的networkx图形的节点上添加永久名称标签(非交互式标签)?
我正在尝试使用spring_布局和bokeh库在networkx图形的节点上添加永久标签。我希望这个标签可以像字符串布局一样,在图形缩放或刷新时重新定位,在图形缩放或刷新时重新定位节点 我尝试创建图形和布局,然后从字符串布局中获取pos。但是,当我调用Graph 如何在bokeh中的networkx图形的节点上添加永久名称标签(非交互式标签)?,graph,label,visualization,networkx,bokeh,Graph,Label,Visualization,Networkx,Bokeh,我正在尝试使用spring_布局和bokeh库在networkx图形的节点上添加永久标签。我希望这个标签可以像字符串布局一样,在图形缩放或刷新时重新定位,在图形缩放或刷新时重新定位节点 我尝试创建图形和布局,然后从字符串布局中获取pos。但是,当我调用pos=nx.spring\u layout(G)时,它将为图G中的节点生成一组位置,我可以将其坐标放入标签集。但是,我必须调用graph=from_networkx(G,spring_布局,scale=2,center=(0,0))来绘制网络图。
pos=nx.spring\u layout(G)
时,它将为图G中的节点生成一组位置,我可以将其坐标放入标签集。但是,我必须调用graph=from_networkx(G,spring_布局,scale=2,center=(0,0))
来绘制网络图。这将为节点创建一组新的位置。因此,节点和标签的位置将不相同
如何解决此问题?固定节点位置
从文档中:您可以添加一个节点列表,并将固定位置作为参数
import networkx as nx
import matplotlib.pyplot as plt
g = nx.Graph()
g.add_edges_from([(0,1),(1,2),(0,2),(1,3)])
pos = nx.spring_layout(g)
nx.draw(g,pos)
plt.show()
然后可以在固定位置绘制节点:
pos = nx.spring_layout(g, pos=pos, fixed=[0,1,2,3])
nx.draw(g,pos)
plt.show()
谢谢你提出这个问题。通过这项工作,我意识到目前的工作比它应该做的更多。我非常强烈地鼓励你打开一个网站,这样我们就可以讨论什么样的改进可以让用户更容易地完成这类事情 下面是一个完整的示例:
import networkx as nx
from bokeh.io import output_file, show
from bokeh.models import CustomJSTransform, LabelSet
from bokeh.models.graphs import from_networkx
from bokeh.plotting import figure
G=nx.karate_club_graph()
p = figure(x_range=(-3,3), y_range=(-3,3))
p.grid.grid_line_color = None
r = from_networkx(G, nx.spring_layout, scale=3, center=(0,0))
r.node_renderer.glyph.size=15
r.edge_renderer.glyph.line_alpha=0.2
p.renderers.append(r)
到目前为止,这都是相当正常的Bokeh图形布局代码。以下是需要为每个节点添加永久标签的附加部分:
from bokeh.transform import transform
# add the labels to the node renderer data source
source = r.node_renderer.data_source
source.data['names'] = [str(x*10) for x in source.data['index']]
# create a transform that can extract the actual x,y positions
code = """
var result = new Float64Array(xs.length)
for (var i = 0; i < xs.length; i++) {
result[i] = provider.graph_layout[xs[i]][%s]
}
return result
"""
xcoord = CustomJSTransform(v_func=code % "0", args=dict(provider=r.layout_provider))
ycoord = CustomJSTransform(v_func=code % "1", args=dict(provider=r.layout_provider))
# Use the transforms to supply coords to a LabelSet
labels = LabelSet(x=transform('index', xcoord),
y=transform('index', ycoord),
text='names', text_font_size="12px",
x_offset=5, y_offset=5,
source=source, render_mode='canvas')
p.add_layout(labels)
show(p)
来自bokeh.transform导入转换
#将标签添加到节点渲染器数据源
source=r.node\u renderer.data\u source
source.data['names']=[str(x*10)表示source.data['index']]
#创建可以提取实际x、y位置的变换
代码=”“
var result=new Float64Array(xs.length)
对于(变量i=0;i
基本上,由于Bokeh(可能)在浏览器中计算布局,因此实际的节点位置只能通过“布局提供程序”获得,而“布局提供程序”目前访问起来有点繁琐。正如我所说的,请打开一个GitHub问题,为用户提供更好的建议。我们可能可以做一些非常快速和简单的事情来让用户更简单
上述代码导致:
类似于@bigreddot的解决方案
#Libraries for this solution
from bokeh.plotting import figure ColumnDataSource
from bokeh.models import LabelSet
#Remove randomness
import numpy as np
np.random.seed(1337)
#Load positions
pos = nx.spring_layout(G)
#Dict to df
labels_df = pd.DataFrame.from_dict(pos).T
#Reset index + column names
labels_df = labels_df.reset_index()
labels_df.columns = ["names", "x", "y"]
graph_renderer = from_networkx(G, pos, center=(0,0))
.
.
.
plot.renderers.append(graph_renderer)
#Set labels
labels = LabelSet(x='x', y='y', text='names', source=ColumnDataSource(labels_df))
#Add labels
plot.add_layout(labels)
我要补充一点,当然还有其他方法可以做到这一点。由于
nx
图形生成静态布局,因此您还可以在Python中提取(x,y)
坐标,并将它们放入标签集的数据源中。这将避免JS转换,但我认为上面的方法是最通用和“正确的”。x,y=zip(*graph_renderer.layout_provider.graph_layout.values())和索引或G.nodes.keys()之间缺少的链接在哪里?我将打开一个问题,我找不到它。@pierre请对这个新的现有问题发表任何评论(链接到这里以供参考),也就是说,您上面的内容在一般情况下是不可行的,只是在一些特殊情况下。正如我所提到的,布局可能只在浏览器中用JavaScript计算,在这种情况下,Python端根本不可用。问题是如何使用Bokeh而不是Matplotlib来实现这一点。另外,关于如何向节点添加文本标签,这一点也没有。来自网络X的Bokeh函数正在使用来自网络X的spring\u layout
函数定义节点位置。因此,在spring\u layout
函数中定义位置似乎更容易。虽然问题的标题是关于文本标签的,但如果仔细阅读问题的主体,您会发现具体问题与节点位置有关。“我正在尝试使用spring_布局和bokeh库在networkx图形的节点上添加永久标签。我希望此标签在图形缩放时重新定位或像字符串布局那样刷新,在图形缩放或刷新时重新定位节点。”此答案没有提供任何帮助,尤其是在任何情况下都无法与dynamic(客户端生成)保持同步布局发生了变化。如果你阅读了问题的其余部分,你就会清楚地看到spring\u布局的用法。