【问题标题】:Networkx (or Graphviz) rotate node labels clockwise around the center of the plotNetworkx(或 Graphviz)围绕绘图中心顺时针旋转节点标签
【发布时间】:2022-02-01 22:59:51
【问题描述】:

我用 Networkx/Graphviz 绘制了一个类似的图:

import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout

T = nx.balanced_tree(2, 5)
pos = graphviz_layout(T, prog="twopi")
nx.draw_networkx(T, pos, with_labels=True)
plt.show()

这给了我以下情节:

我想要什么:

我希望所有节点标签都围绕图形中心顺时针旋转。我该怎么做呢?我更喜欢直接使用 Networkx 或 Graphviz 的方式。

“顺时针旋转”是指类似于此极坐标图上的标签:

我也尝试了以下代码:

T = nx.balanced_tree(2, 5)
pos = graphviz_layout(T, prog="twopi")
nx.draw_networkx(T, pos, with_labels=False)

text = nx.draw_networkx_labels(T, pos=pos)
for _, t in text.items():
    t.set_rotation('clockwise')
    
plt.show()

但对于set_rotation(),仅支持'horizontal', 'vertical', numeric value, or None

我也发现了类似的问题,但没有一个可以帮助我:

不绘制节点标签,这是 2017 年以来一个安静的老问题,对我来说似乎也很复杂: NetworkX node labels relative position

答案是 2019 年的 graphviz 是不可能的: https://stackoverflow.com/questions/55009159/change-label-orientation-90º-of-a-node-in-graphviz

【问题讨论】:

    标签: python networkx graphviz


    【解决方案1】:

    @sroush 列出的限制的一种可能解决方法是一起删除节点标签并使用 plt.text 标记您的节点。

    见下面的代码:

    import networkx as nx
    import matplotlib.pyplot as plt
    
    T = nx.balanced_tree(2, 5)
    N_nodes=T.number_of_nodes()
    fig,ax=plt.subplots(figsize=(10,5))
    #Circular layout as an example
    pos = nx.circular_layout(T)
    
    #Setting up the text by using node position 
    texts=[plt.text(pos[i][0],pos[i][1],str(i),rotation=(i/N_nodes)*360,fontsize=10,horizontalalignment='center',verticalalignment='center') for i in range(N_nodes)]
    
    #Plot result
    nx.draw(T, pos)
    ax.set_aspect('equal')
    plt.show()
    

    输出给出:

    编辑:使用graphviz_layout(T, prog="twopi") 布局:

    import networkx as nx
    import matplotlib.pyplot as plt
    from networkx.drawing.nx_agraph import graphviz_layout
    
    T = nx.balanced_tree(2, 5)
    N_nodes=T.number_of_nodes()
    pos = pos = graphviz_layout(T, prog="twopi")
    fig,ax=plt.subplots(figsize=(10,5))
    texts=[plt.text(pos[i][0],pos[i][1],str(i),rotation=(i/N_nodes)*360,fontsize=10,horizontalalignment='center',verticalalignment='center') for i in range(N_nodes)]
    nx.draw(T, pos)
    ax.set_aspect('equal')
    plt.show()
    

    输出给出:

    EDIT 2:微调节点布局:

    import networkx as nx
    import matplotlib.pyplot as plt
    from networkx.drawing.nx_agraph import graphviz_layout
    
    T = nx.balanced_tree(2, 5)
    N_nodes=T.number_of_nodes()
    first_rot_node=31
    N_rot=T.number_of_nodes()-first_rot_node+1
    pos = pos = graphviz_layout(T, prog="twopi")
    
    fig,ax=plt.subplots(figsize=(10,5))
    cmt=0
    for i in range(N_nodes):
      if i>=first_rot_node:
        cmt+=1
        if ((cmt-1)/N_rot)*360<90 or ((cmt-1)/N_rot)*360>=270:
          plt.text(pos[i][0],pos[i][1],str(i),rotation=((cmt-1)/N_rot)*360,fontsize=11,horizontalalignment='center',verticalalignment='center') 
        elif ((cmt-1)/N_rot)*360>=90 and ((cmt-1)/N_rot)*360<270:
          plt.text(pos[i][0],pos[i][1],str(i),rotation=((cmt-1)/N_rot)*360+180,fontsize=11,horizontalalignment='center',verticalalignment='center') 
      else:
         plt.text(pos[i][0],pos[i][1],str(i),rotation=0,fontsize=11,horizontalalignment='center',verticalalignment='center') 
    
    nx.draw(T, pos)
    ax.set_aspect('equal')
    plt.show()
    

    输出给出:

    【讨论】:

    • 但是使用此解决方案,无法维护 twopi 布局或任何其他比简单圆圈更复杂的布局,对吗?
    • 要让这个方法起作用,你真正需要的只是节点的位置(我的代码中的pos 变量)。这意味着它适用于许多不同的布局类型。有关 twopi 布局的示例,请参阅我编辑的答案。
    • 感谢您的患者和您的努力,我不是开发人员...我认为它可以去某个地方。就我而言,美学也是一项要求,是否可以将节点 10、15 或 13 等数字自动更准确地向中间旋转?还有一些数字不是完全在中间,比如节点 15。最后,数字开始向下翻转,比如节点 31,我意识到我将要求描述为“顺时针旋转”,但我更寻求的是像我的第二个示例情节中的标签。
    • 这些规范很好且易于管理。我上面提供的示例主要是为了演示一种可能的方式来做你想做的事。您可能必须自己进行一些微调才能获得所需的确切结果。以下是您可以前往那里的几个方向。
    • 您可以通过修改 for 循环内的 rotation 参数的值来控制每个单独节点的旋转(如果需要,请使用 if 条件)。可以通过修改horizontalalignementverticalalignement 的值来更改标签相对于节点的位置。见doc here。请参阅我的帖子的编辑,其中我实施了您所描述的示例。编码愉快!
    【解决方案2】:

    Graphviz 不支持旋转文本。这是提供此功能的一项未决请求 - https://gitlab.com/graphviz/graphviz/-/issues/2006

    两种可能的 Graphviz 解决方法:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-22
      • 2021-06-06
      • 1970-01-01
      • 2014-10-05
      • 1970-01-01
      • 2013-05-20
      相关资源
      最近更新 更多