Hi. I have a circular layout graph with 12 nodes outside of the layout (by design).
num_miR_nodes = len(miR_nodes['nodes'])
angle_increment = 2*math.pi / num_miR_nodes
miR_radius = 1.5
for i, node in enumerate(miR_nodes['nodes']):
angle = i * angle_increment
x = miR_radius * math.cos(angle)
y = miR_radius * math.sin(angle)
pos[node] = (x, y)
G.add_node(node)
I want to make a bezier path (or similar to bezier) for each of the (straight) edges of the outer 12 nodes, that will stay outside of the nodes in the circular layout until reaching the circular layout target node, by spiraling in (I don't want the edge to leap away from the graph like what happens when you increase the midpoint of the edge too much).
Currently I only have the bezier curve math worked out for the inner circular layout edges:
def draw_curved_edges2(G, pos, ax, alpha):
for u, v, d in G.edges(data=True):
edge_color = d['edge_color']
weight = d['width']
pos_u = pos[u]
pos_v = pos[v]
x_u, y_u = pos_u
x_v, y_v = pos_v
if 'miR' not in u:
# midpoint of the edge
x_mid = 0 * (x_u + x_v)
y_mid = 0 * (y_u + y_v)
# control point for Bezier
x_ctrl = 0.25 * (x_mid + 0.5 * (x_u + x_v))
y_ctrl = 0.25 * (y_mid + 0.5 * (y_u + y_v))
# Bezier curve path
bezier_path = Path([(x_u, y_u), (x_ctrl, y_ctrl), (x_v, y_v)], [Path.MOVETO, Path.CURVE3, Path.CURVE3])
width = G[u][v]['width']# for u, v in G.edges()]
#patch = PathPatch(bezier_path, facecolor='none', edgecolor=edge_color, linewidth=width, alpha=alpha)
#ax.add_patch(patch)
arrow = FancyArrowPatch(path=bezier_path, color=edge_color, linewidth=width, alpha=alpha,
arrowstyle="->, head_length=6, head_width=2, widthA=1.0, widthB=1.0, lengthA=0.4, lengthB=0.4")
ax.add_patch(arrow)
draw_curved_edges2(G, pos, ax, alpha=0.4)

This solution creates splines between two points that are routed around a central origin. For each spline, the distances of its interior points to the origin are interpolated between the distances of the start and end points of the spline to the same origin, resulting in spiral-like appearance.
This solution also selects the shortest path around the origin (rather than always wrapping around counter-clockwise).