Skip to content

Instantly share code, notes, and snippets.

@JamesPHoughton
Last active August 29, 2024 15:36
Show Gist options
  • Save JamesPHoughton/55be4a6d30fe56ae163ada176c5c7553 to your computer and use it in GitHub Desktop.
Save JamesPHoughton/55be4a6d30fe56ae163ada176c5c7553 to your computer and use it in GitHub Desktop.
How to create rotary labels in networkx circular layout
g = nx.complete_graph([
    "playground equipment", "evanescent champagne", "curved spacetime", 
    "magic flute", "market returns", "spotty memory",
    "languid feeling", "include numpy as np", "acidic chemical", 
    "downton abbey", "tumble weeds", "precede the cause"])
node_locs = nx.circular_layout(g)
theta = {k: np.arctan2(v[1], v[0]) * 180/np.pi for k, v in node_locs.items() }


plt.figure(figsize=(8,8))
nx.draw_networkx_nodes(g, pos=node_locs, alpha=.5)
labels = nx.draw_networkx_labels(g, pos=node_locs, font_size=12, ha='left')

for key,t in labels.items():
    if 90 < theta[key] or theta[key] < -90 :
        angle = 180 + theta[key]
        t.set_ha('right')
    else:
        angle = theta[key]
        t.set_ha('left')
    t.set_va('center')
    t.set_rotation(angle)
    t.set_rotation_mode('anchor')

nx.draw_networkx_edges(g, pos=node_locs, alpha=.4)
plt.box("off")
plt.xlim(-2,2)
plt.ylim(-2,2)

Gives: image

@parthav1
Copy link

Immensely helpful. Posting my adapted code for anyone who wants to put labels outside the node:

# Adjust label positions slightly away from the nodes
label_offset = 1.5  # distance of the label from the node
adjusted_pos = {}
for k, v in pos.items():
    angle_rad = np.arctan2(v[1] - center[1], v[0] - center[0])
    adjusted_pos[k] = (
        v[0] + label_offset * np.cos(angle_rad),
        v[1] + label_offset * np.sin(angle_rad),
    )

@KrystynaMarcinek
Copy link

KrystynaMarcinek commented Aug 22, 2024

@parthav1 Would you mind providing the full code with your adaptation?

@parthav1
Copy link

@KrystynaMarcinek I can't provide full code but I'll give as much as I can:

# Calculate angles for label rotation
center = np.mean(list(pos.values()), axis=0)
theta = {
    k: np.arctan2(v[1] - center[1], v[0] - center[0]) * 180 / np.pi
    for k, v in pos.items()
}

# Adjust label positions slightly away from the nodes
label_offset = 6  # distance of the label from the node
adjusted_pos = {}
for k, v in pos.items():
    angle_rad = np.arctan2(v[1] - center[1], v[0] - center[0])
    adjusted_pos[k] = (
        v[0] + label_offset * np.cos(angle_rad),
        v[1] + label_offset * np.sin(angle_rad),
    )

labels = nx.draw_networkx_labels(
    self.G,
    adjusted_pos,
    labels=node_labels,
    font_size=6,
    horizontalalignment="left",
    font_family="Liberation Sans Narrow"
)

for key, t in labels.items():
    if 90 < theta[key] or theta[key] < -90:
        angle = 180 + theta[key]
        t.set_ha("right")
    else:
        angle = theta[key]
        t.set_ha("left")
    t.set_va("center")
    t.set_rotation(angle)
    t.set_rotation_mode("anchor")

@KrystynaMarcinek
Copy link

This is so helpful, thank you!! Defining "center" solved my problems! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment