如何在散景中的networkx图表的节点上添加永久名称标签(不是交互式标签)?

时间:2018-04-16 02:43:38

标签: graph label visualization networkx bokeh

我正在尝试使用spring_layout和散景库在nodex图表的节点上添加永久标签。我希望重新定位此标签,因为图形会像字符串布局那样缩放或刷新,在图形缩放或刷新时重新定位节点。

我尝试创建图形和布局,然后从string_layout获取pos。但是,当我调用# Generate polar and cartesian meshgrids r = df_polar.columns theta = df_polar.index theta = np.deg2rad(theta) # Polar meshgrid rad_c, theta_c = np.meshgrid(r,theta) # Cartesian meshgrid X = rad_c * np.cos(theta_c) Y = rad_c * np.sin(theta_c) x,y = np.meshgrid(X,Y) # Interpolate from polar to cartesian grid new_grid = scipy.interpolate.griddata( (rad_c.flatten(), theta_c.flatten()), np.array(df_polar).flatten(), (x,y), method='nearest') 时,它将为图G中的节点生成一组位置,我可以获得放入LabelSet的坐标。但是,我必须致电catdatas = CarsDataset.query.all() locations = [d.serializer() for d in catdatas] carmap = Map( identifier="carmap", style="height:500px;width:500px;margin:0;", lat=locations[0]['lat'], lng=locations[0]['lng'], markers=[(loc['lat'], loc['lng']) for loc in locations] ) 来绘制网络图。这将为节点创建一组新位置。因此,节点和标签的位置将不相同。

如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

感谢您提出这个问题。通过它,我意识到它目前的工作量应该超出应有的水平。我非常强烈建议您打开GitHub issue,以便我们可以讨论哪些改进最能让用户更容易做到这一点。

这是一个完整的例子:

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(可能)在浏览器中计算布局,实际的节点位置只能通过&#34;布局提供商&#34;这访问目前有点乏味。正如我所说,请打开一个GitHub问题,建议让用户更好。我们可以做一些非常快速和简单的事情来使用户更加简单。

上面的代码导致:

enter image description here

答案 1 :(得分:-1)

固定节点位置

networkx.spring_layout()文档:您可以添加一个固定位置的节点列表作为参数。

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()

initial_graph

然后您可以在固定位置绘制节点:

pos = nx.spring_layout(g, pos=pos, fixed=[0,1,2,3])
nx.draw(g,pos)
plt.show()

fixed_nodes

答案 2 :(得分:-1)

与@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)