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

NetworkX中connectionstyle=arc3绘制环形图出现弧反转问题求助

解决NetworkX环形网络图中弧线边反转的问题

问题描述

用NetworkX绘制节点按环形排列的网络图,设置connectionstyle="arc3,rad=.5"让边显示为弧线,但发现像10→1这类从大数指向小数的边,弧线会反转(与其他边的弯曲方向相反)。已固定节点的环形位置,调整边的连接列表后,反转问题仅转移到其他跨首尾的边上。需要让程序识别环形闭环特性,统一所有弧线的弯曲方向。

原代码

import random
from math import cos, sin
import matplotlib
import networkx as nx
from matplotlib import pyplot as plt
from pyvis.network import Network
import scipy as sp


def get_coordinates_in_circle(n, scale):
    return_list = []
    for i in range(n):
        theta = float(i) / n * 2 * 3.141592654

        y = cos(theta)
        x = sin(theta)
        return_list.append((x * scale, y * scale))
        # print(return_list)
    return return_list


def draw_number(length):
    """determines a random index number for selection."""
    from_index = random.randint(0, length)
    to_index = random.randint(0, length)
    return from_index, to_index


def netw(NodesN):
    G = nx.Graph()

    node_list = []
    fixed_positions = {}  # dict with two of the positions set
    for i in range(1, NodesN + 1):
        node_list.append(i)
    CirclePos = get_coordinates_in_circle(NodesN, 1)
  
    # jump by 1
    from_list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    to_list1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]

    # jump by 2
    from_list2 = [1,3,5,7,9]
    to_list2 =   [3,5,7,9,1]

    # jump by 3
    from_list3 = [1,4,7,10,3 ]
    to_list3 =   [4,7,10,3,6]
    from_list = from_list1
    to_list = to_list1
    
    for i in range(len(node_list)):
        G.add_node(node_list[i])
        fixed_positions[i+1] = CirclePos[i]
    for j in range(len(from_list)):
        G.add_edges_from([(from_list[j], to_list[j])])
    fixed_nodes = fixed_positions.keys()
    pos = nx.spring_layout(G, pos=fixed_positions, fixed=fixed_nodes)
    # pos = nx.kamada_kawai_layout(G, pos=fixed_positions)


    nx.draw_networkx_nodes(G,pos)
    nx.draw_networkx_labels(G,pos)
    nx.draw_networkx_edges(G,pos,arrows=True,connectionstyle=f"arc3,rad=.5")
    # nx.draw_networkx(G,pos)
    plt.show()

netw(10)

问题原因

NetworkX的arc3连接样式基于两点的直线连线计算弧的弯曲方向,无法自动识别环形的闭环结构。对于跨首尾的节点(如10→1),两点的直线连线会穿过环形中心,导致弧线向与其他边相反的方向弯曲。

解决方案

通过手动计算每条边的弯曲方向,基于节点在环形上的顺时针/逆时针位置动态调整rad参数的正负,确保所有弧线向同一侧(如环形外侧)弯曲。

修改后的代码

import random
from math import cos, sin
import matplotlib
import networkx as nx
from matplotlib import pyplot as plt
from pyvis.network import Network
import scipy as sp


def get_coordinates_in_circle(n, scale):
    return_list = []
    for i in range(n):
        theta = float(i) / n * 2 * 3.141592654
        y = cos(theta)
        x = sin(theta)
        return_list.append((x * scale, y * scale))
    return return_list


def draw_number(length):
    """determines a random index number for selection."""
    from_index = random.randint(0, length)
    to_index = random.randint(0, length)
    return from_index, to_index


def netw(NodesN):
    G = nx.DiGraph()  # 改为有向图更符合箭头需求,修正原代码的逻辑矛盾

    node_list = []
    fixed_positions = {}
    for i in range(1, NodesN + 1):
        node_list.append(i)
    CirclePos = get_coordinates_in_circle(NodesN, 1)
  
    # jump by 1
    from_list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    to_list1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]

    # jump by 2
    from_list2 = [1,3,5,7,9]
    to_list2 =   [3,5,7,9,1]

    # jump by 3
    from_list3 = [1,4,7,10,3 ]
    to_list3 =   [4,7,10,3,6]
    from_list = from_list1
    to_list = to_list1
    
    for i in range(len(node_list)):
        G.add_node(node_list[i])
        fixed_positions[i+1] = CirclePos[i]
    for j in range(len(from_list)):
        G.add_edge(from_list[j], to_list[j])  # 用add_edge简化代码
    
    # 直接使用固定位置,避免spring_layout的不必要微调
    pos = fixed_positions

    nx.draw_networkx_nodes(G, pos)
    nx.draw_networkx_labels(G, pos)

    # 动态计算每条边的弧线方向,统一弯曲方向
    for u, v in G.edges():
        u_x, u_y = pos[u]
        v_x, v_y = pos[v]
        # 通过向量叉积判断v在u的顺时针方向,调整rad正负
        cross_product = u_x * v_y - u_y * v_x
        rad = 0.5 if cross_product < 0 else -0.5
        nx.draw_networkx_edges(G, pos, edgelist=[(u, v)], arrows=True, 
                              connectionstyle=f"arc3,rad={rad}", arrowstyle='->')

    plt.show()

netw(10)

关键修改点

  1. 修正图类型:将nx.Graph()改为nx.DiGraph(),匹配箭头绘制的有向边逻辑。
  2. 简化位置设置:直接使用fixed_positions作为节点位置,去掉spring_layout的微调,确保节点严格按环形排列。
  3. 动态调整弧线方向:通过向量叉积判断节点间的顺时针/逆时针关系,设置rad的正负值,让所有弧线向环形外侧统一弯曲,彻底解决跨首尾边的反转问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:30:53