Library of the week #12: Pelote + ipysigma
Library of the week #12: Pelote + ipysigma 🧶
2 super libraries to work with graphs

Library of the week #12: Pelote + ipysigma 🧶
I normally do the libraries one by one, but these 2 are very much related and are meant to be together… So here you go!
Why Pelote and ipysigma?
Python offers 2 main libraries to work with networks and graphs: NetworkX ( I wrote a Library of the Week about it ) and igraph . These libraries offer many methods and algorithms to explore the relationships in a graph structure.
If you find yourself lacking some functionalities with NetworkX, such as transforming graphs to tabular format (CSV) or from tabular to graph, transform monopartite to bipartite graphs, transforming graphs to graphology format, Pelote can help you with all that!
If you wish to have some extra analytical algorithms to analyze your graphs, such as the edge disparity or the triangular strength , Pelote is your friend as well.
If you wish to have dynamic and interactive JavaScript-like representations of your network , then ipysigma is your new best friend (it certainly became mine!).
[embed]
What are Pelote and ipysigma
Pelote is a toolbox that extends the capabilities of NetworkX.
ipysigma is a jupyter widget that turns graphs into interactive objects , this way you can explore them in more depth, zoom in and out, turn them around… Is is developed with a JavaScript library called Graphology and the sigma.js web renderer.
- Check Pipy’s page for Pelote
- Check Github repo for pelote
- Check Pipy’s page for ipysigma
- Check Github repo for ipysigma
Basic Statistics and facts
Pelote:

Basic stats and facts about Pelote, as of November 3rd, 2023
ipysigma:

Basic stats and facts about Ipysigma, as of November 3rd, 2023
The people of Pelote and ipysigma
Both projects come from Sciences Po médialab . Sciences Po , (which stands for Sciences Poliques in French or “Political Science” in English) is a very famous French University. Medialab is a research Lab from Sciences Po, and they develop tools to conduct their own studies. I guess it makes sense that a research center for social sciences developed tools to study Networks, but in any case, big thanks to them for these 2 amazing Python libraries.
Both projects are mostly maintained by Guillaume Plique .
Pros, cons and alternatives
Pelote can be considered like a toolbox with a diverse set of tools to work with networks and analyze them. As such, I can’t think of any similar library, nor any “disadvantage”. It offers very specific algorithms to work with, but also a quick way to turn CSV files into networks, which is pretty cool.
An alternative to ipysigma can be a library called pyvis , you can look in the additional resources for a comparison of both libraries, it allows to display networks interactively and I have not (yet) tested it.
How to Pelote and ipysigma
Install Pelote and ipysigma
They can be installed withpip install pelote andpip install ipysigma respectively.
There are no conda downloads for these packages.
Easy example:
For the easy example, I’m going to show you how to turn a Pandas DataFrame into a NetworkX graph with pelote’sedges_table_to_graph function and then use ipysigma to visualize it. I will first create a DataFrame with a few stations from the Madrid metro system (just a small subset of lines 1 and 2). The DataFrame has 3 columns:
"Station": The name of the station."Station_from": The name of the station that is linked to the first station (referenced in the column"Station")."Line": The line of that connection. Notice how "Sol" is referred as "Line 1" when connected to "Gran Via", and referred as "Line 2" when connected to "Sevilla". This is because the Lines are an attribute of the edges (the links between nodes), not the nodes.
import pandas as pd
df_metro_madrid = pd.DataFrame(
{
"Station": [
"Tetuán",
"Estrecho",
"Alonso Cano",
"RÃos Rosas",
"Iglesia",
"Bilbao",
"Tribunal",
"Gran VÃa",
"Sol",
"Sevilla",
"Sol",
"Opera",
"Santo Domingo",
"Noviciado",
"San Bernardo",
],
"Station_from": [
"Valdeacederas",
"Tetuán",
"Estrecho",
"Alonso Cano",
"RÃos Rosas",
"Iglesia",
"Bilbao",
"Tribunal",
"Gran VÃa",
"Banco de Espana",
"Sevilla",
"Sol",
"Opera",
"Santo Domingo",
"Noviciado",
],
"Line": [
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 1",
"Line 2",
"Line 2",
"Line 2",
"Line 2",
"Line 2",
"Line 2",
],
}
)
Now it’s time to use our new toolbox, to transform this DataFrame into a NetworkX object, we can do it with theedges_table_to_graph function, like the following:
from pelote import edges_table_to_graph
g = edges_table_to_graph(
df_metro_madrid,
edge_source_col="Station",
edge_target_col="Station_from",
edge_data=["Line"],
)
Now that we have our NetworkX object, we can plot it with NetworkX, or we can plot it with ipysigma . Let’s see both ways, so you can see the difference. With NetworkX:
import networkx as nx
nx.draw_networkx(g)

NetworkX graph
With ipysigma you just need to import theSigma function. We can use theedge_color parameter. The result at first looks messy, but clicking on the "start layout" button (a "play" triangle) will optimize how the graph looks:
from ipysigma import Sigma
Sigma(g, edge_color="Line")

ipysigma graph
Complex examples
In order to see some more complex examples, let’s create a graph object with the NetworkXgnm_random_graph function. This is explained in the NetworkX Library of the Week article. It gives a random weight (integer between 1 and 10) to the edges (the connections) between the nodes, and it also adds random attributes to the nodes (on this case, nodes represent people): age and gender.
import random
# Set the random seed for reproducibility
random_seed = 42
random.seed(random_seed)
# We create a random graph with 50 nodes and 100 edges
G_social_network = nx.gnm_random_graph(50, 100)
# We add attributes
for node in G_social_network.nodes():
G_social_network.nodes[node]["name"] = f"Person_{node + 1}"
G_social_network.nodes[node]["age"] = random.randint(18, 60)
G_social_network.nodes[node]["gender"] = random.choice(["male", "female"])
# We add random weights to edges
for edge in G_social_network.edges():
G_social_network.edges[edge]["weight"] = random.randint(1, 10)
We can create the graph with ipysigma like this, with a distinctive coloring for the nodes for males and females:
Sigma(G_social_network, node_color="gender")

Social Network with Ipysigma
Pelote lets us create graphs from a DataFrame, but it also lets us convert NetworkX objects to DataFrames. Thegraph_to_nodes_dataframe function lets us create a DataFrame from the nodes, and thegraph_to_edges_dataframe function lets us create a DataFrame from the edges :
from pelote import graph_to_edges_dataframe, graph_to_nodes_dataframe
df_social_network_nodes = graph_to_nodes_dataframe(G_social_network)
df_social_network_edges = graph_to_edges_dataframe(G_social_network)
df_social_network_nodes.head()
key name age gender
0 0 Person_1 19 male
1 1 Person_2 41 female
2 2 Person_3 33 male
3 3 Person_4 33 male
4 4 Person_5 23 female
df_social_network_edges.head()
source target weight
0 0 17 8
1 0 43 5
2 0 46 7
3 0 38 9
4 1 47 8
A super-duper cool function, still from Pelote, isglobal_threshold_sparsification . It takes a graph object and a threshold as parameters, and it returns a graph without the edges under that value. In the example below, we delete the edges with weight under 5 (we assigned a random value between 1 and 10). It is interesting to see that only 2 nodes get totally disconnected from the network by removing about half the edges!
from pelote import global_threshold_sparsification
G_social_network_strong = global_threshold_sparsification(G_social_network, 5)
Sigma(G_social_network_strong, node_color="gender")

Sparsed social network
Statistical methods
As stated earlier, Pelote is an academic project. It comes with advanced tools for graph analysis, such as backbone disparity filter ( the documentation also references this paper ).
I don’t deeply analyze networks for a living, so I don’t use these methods in my day to day life, but I’m very glad I learned about them! This is how you get the multiscale backbone of our “social network”. You need to use the functionmultiscale_backbone . This will keep the relationships that are statistically significant, so I guess it is a good sign that the graph has almost no relationships when this function is applied, since the relationships have been assigned randomly!
from pelote import multiscale_backbone
G_social_network_backbone = multiscale_backbone(G_social_network)
Sigma(G_social_network_backbone, node_color="gender")

The above function only keeps the edges with an edge disparity score of under 0.05. Theedge_disparity function returns all the scores for all the edges of the graph. Let's see how the scores look, and let's also focus on the edge between nodes 24 and 29, one of the 2 relationships left:
from pelote import edge_disparity
print(edge_disparity(G_social_network))
print("\n __________ \n")
print(edge_disparity(G_social_network)[(24, 29)])
{(0, 17): 0.18170794500179158, (0, 43): 0.43976479295863985, (0, 46): 0.34548271604938263, (0, 38): 0.1580398285189781, (1, 47): 0.2177777777777778, (1, 2): 0.4551661356395083, (1, 38): 0.471904399320412, (2, 46): 0.23304506144742834, (2, 42): 0.3318161128812016, (2, 14): 0.7865270823850706, (3, 49): 0.21058644037331048, (3, 7): 0.2668771743774414, (4, 45): 0.7023319615912207, (4, 38): 0.03703703703703705, (4, 17): 0.7023319615912207, (4, 24): 0.7023319615912207, (5, 34): 0.18683877994499784, (5, 13): 0.2603082049146189, (5, 6): 0.16777216, (5, 35): 0.279581552734375, (5, 18): 0.5289256198347108, (5, 48): 0.8751664033829021, (6, 47): 0.16777216, (6, 24): 0.534824985896467, (6, 14): 0.506631121177321, (6, 40): 0.7163929600000001, (7, 40): 0.1798095207903914, (7, 24): 0.534824985896467, (7, 46): 0.564167901234568, (7, 21): 0.17361111111111108, (8, 14): 0.6410499929876159, (8, 15): 0.16666666666666663, (9, 13): 0.5397750937109539, (9, 16): 0.21599999999999997, (9, 40): 0.1798095207903914, (9, 12): 0.8264462809917354, (10, 48): 0.21720617794361222, (10, 23): 0.7846649345673543, (10, 40): 0.3148817043247643, (10, 15): 0.29265335009166243, (10, 43): 0.16446348194331412, (10, 29): 0.2149341667858102, (10, 34): 0.3869947966895575, (11, 32): 0.4552806773219491, (12, 35): 0.4049586776859504, (12, 36): 0.20661157024793392, (13, 42): 0.5, (13, 36): 0.4552806773219491, (13, 41): 0.28518127866671344, (14, 32): 0.506631121177321, (14, 26): 0.3071983141623866, (14, 49): 0.13281030862990761, (14, 43): 0.23528156316670773, (15, 17): 0.6777417535403871, (16, 38): 0.8360074295644685, (16, 34): 0.2718820268938179, (16, 35): 0.3057268372091616, (16, 46): 0.19753086419753096, (17, 21): 0.6777417535403871, (17, 24): 0.534824985896467, (17, 44): 0.14213274739207304, (17, 40): 0.4489371143192646, (17, 48): 0.14213274739207304, (18, 40): 0.29752066115702475, (18, 27): 0.4551661356395083, (19, 40): 0.37593703992309235, (20, 49): 0.6869529818847954, (20, 25): 0.44718094850396894, (20, 45): 0.0625, (20, 31): 0.3517199267250152, (21, 48): 0.5625, (22, 23): 0.34196190179715275, (23, 39): 0.2923104668287018, (23, 25): 0.5216049382716049, (23, 48): 0.21720617794361222, (24, 29): 0.023078380428451596, (24, 38): 0.7385081737104511, (25, 31): 0.25, (27, 37): 0.23304506144742834, (27, 44): 0.6058261265361857, (27, 38): 0.4551661356395083, (28, 37): 0.44444444444444453, (29, 34): 0.7385081737104511, (29, 40): 0.732594938221513, (29, 41): 0.18276889814782396, (29, 33): 0.5714285714285714, (31, 32): 0.4552806773219491, (32, 48): 0.4552806773219491, (32, 38): 0.12370690685545004, (33, 49): 0.4285714285714286, (34, 44): 0.3869947966895575, (34, 46): 0.5401410745587889, (34, 43): 0.43976479295863985, (35, 44): 0.27952890304961314, (35, 47): 0.3541464389837568, (37, 47): 0.44444444444444453, (41, 45): 0.765625, (41, 43): 0.7260249991246807, (41, 49): 0.28518127866671344, (43, 47): 0.43976479295863985}
__________
0.023078380428451596
As we can see, most edges have a value way over 0.05, but the edge (24, 29) has a value of 0.023, which is lower.
Graph subsets
Pelote also comes with some functions to get subsets of a graph. The functionlargest_connected_component returns a Python set with the largest amount of nodes which are connected to each other. In the example below, for theG_social_network graph, it's all the nodes except the node 30, which is alone. The functionlargest_connected_component_subgraph returns another graph that only keeps the nodes that are part of the largest subset:
from pelote import largest_connected_component, largest_connected_component_subgraph
largest_component = largest_connected_component(G_social_network)
print(largest_component)
G_social_network_largest_component = largest_connected_component_subgraph(
G_social_network, as_view=True
)
Sigma(G_social_network_largest_component)

Social network’s largest cmponent
Trim the graph
In this last section I’m going to cover some functions that remove the leaves of the network. A leaf is a node connected to only one other node. The functionfilter_leaves returns a graph without the leaves, and the functionremove_leaves will eliminate the leaves of the input graph. Both functions do almost the same, but the first one returns a copy of the graph, while the second trims the graph itself.
However, keep in mind that single nodes are not leaves, they won’t be removed!
from pelote import filter_leaves, remove_leaves
G_social_network_no_leaves = filter_leaves(G_social_network)
Sigma(G_social_network_no_leaves)

Social network with no leaves
remove_leaves(G_social_network)
list(G_social_network)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 25, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
Additional resources
This video from FOSDEM 2023 shows a presentation of ipysigma’s library by Benjamin Ooghe-Tabanou, a member of the Medialab Team.
This Medium article by Bl3e967 is very interesting and compares ipysigma with pyvis.
Thank you for reading! Find all the other libraries of the week:
[embed]Libraries of the week Edit descriptionericnarro.medium.com
If you liked my content and want to connect:
- You can connect with me on LinkedIn
- You can check my personal website
In Plain English
Thank you for being a part of our community! Before you go:
- Be sure to clap and follow the writer! 👏
- You can find even more content at **PlainEnglish.io 🚀**
- Sign up for our **free weekly newsletter**. 🗞️
- Follow us: **Twitter(X**), ***LinkedIn, [YouTube](https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw), [Discord](https://discord.gg/in-plain-english-709094664682340443).***
- Check out our other platforms: **Stackademic**, ***CoFeed, [Venture](https://venturemagazine.net/)***.
메타데이터
- post_id
- 2aabcc661aef
- slug
- library-of-the-week-12-pelote-ipysigma-2aabcc661aef
- url
- https://python.plainenglish.io/library-of-the-week-12-pelote-ipysigma-2aabcc661aef
- canonical_url
- https://python.plainenglish.io/library-of-the-week-12-pelote-ipysigma-2aabcc661aef
- author_url
- https://medium.com/@ericnarro
- status
- ok
- fetched_at
- 2026-07-24 23:06:50