Introduction
Relational data — who talks to whom, which accounts transact with which, which entities share membership — usually arrives as two columns: one row per relationship. That shape is fine for storage, but it can't answer the questions that matter most about a network: who is central, which entities cluster together, how something could propagate through the system, or which single relationship is structurally critical. BuildGraphFromEdgeList converts a raw edge list into a real networkx graph object so those questions become answerable, while transparently reporting what got dropped along the way — self-loops, duplicate edges, and rows with missing endpoints. It's the foundational function in this module: every other network_analysis function either accepts the graph it returns, or wraps this function internally so you never have to touch networkx directly.
Relational data — who talks to whom, which entities transact with which, which organizations share members — is usually collected and stored in "long" edge-list form: one row per relationship, with columns identifying the two endpoints. That tabular shape is convenient for storage and collection, but it is the wrong shape for the questions network analysis answers: who is central, which entities cluster together, how information or risk could propagate, which relationships are structurally critical. Answering those questions requires a graph object with real traversal and algorithmic structure, not just two columns of a DataFrame.
Real-world edge lists are also rarely clean. The same relationship can be logged twice (multi-edges), an entity can be linked to itself through a data error or a legitimate reflexive relationship (self-loops), and analysts often want to reason about node-level metadata (a person's organization, a company's country, an account's type) that lives in a separate lookup table rather than in the edge list itself. Deciding how to handle these cases — silently, or with a transparent accounting of what was dropped — matters because self-loops and duplicate edges can distort centrality, community detection, and path-based metrics if they slip through unnoticed. Surfacing a drop report keeps that data-cleaning decision visible to the analyst instead of hidden inside a conversion utility.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
dataframerequired | pd.DataFrame | — | A pandas DataFrame in long format, with one row per edge (relationship). |
node_1_columnrequired | str | — | Name of the column containing the first endpoint of each edge. |
node_2_columnrequired | str | — | Name of the column containing the second endpoint of each edge. |
is_directed | bool | False | Whether the relationship is directional (node_1 -> node_2). If True, a DiGraph (or MultiDiGraph) is built; otherwise an undirected Graph (or MultiGraph) is built. Defaults to False. |
edge_weight_column | str | None | Optional name of a column containing edge weights. If provided, the values are attached to each edge as a 'weight' attribute, which is the attribute name networkx algorithms (e.g., shortest path, centrality) expect by default. Defaults to None. |
node_attributes_dataframe | pd.DataFrame | None | Optional DataFrame of node-level metadata (e.g., name, type, organization, country) to attach to nodes as attributes. Must be used together with node_id_column. Nodes present in this table but absent from the edge list are still added to the graph as isolated nodes, so analysts can attach a full roster of entities even if some have no recorded relationships yet. Defaults to None. |
node_id_column | str | None | Name of the column in node_attributes_dataframe that identifies each node. Required if node_attributes_dataframe is provided. Defaults to None. |
allow_self_loops | bool | False | Whether to keep edges where node_1 and node_2 are the same entity. If False, self-loop rows are dropped before the graph is built. Defaults to False. |
allow_multi_edges | bool | False | Whether to keep multiple edges between the same pair of nodes. If True, the resulting graph is a MultiGraph/MultiDiGraph. If False, duplicate edges (the same unordered pair for undirected graphs, or the same ordered pair for directed graphs) are collapsed to a single edge, keeping the first occurrence. Defaults to False. |
print_summary | bool | True | Whether to print a report of how many rows were dropped for missing endpoints, self-loops, and duplicate/multi-edges, along with the resulting node and edge counts. Defaults to True. |
Returns
A networkx.Graph, DiGraph, MultiGraph, or MultiDiGraph, depending on is_directed and allow_multi_edges. The graph's .graph dict includes an edge_list_build_summary key with the drop counts, so downstream functions can report on data quality without recomputing it.
Example
from analysistoolbox.network_analysis import BuildGraphFromEdgeList
import pandas as pd
# Build a simple undirected graph from a list of collaborations
edges_df = pd.DataFrame({
'person_a': ['Alice', 'Alice', 'Bob', 'Carol'],
'person_b': ['Bob', 'Carol', 'Carol', 'Carol'],
'projects_together': [3, 1, 2, 4]
})
graph = BuildGraphFromEdgeList(
edges_df,
node_1_column='person_a',
node_2_column='person_b',
edge_weight_column='projects_together'
)
# Build a directed graph with node metadata attached
node_lookup_df = pd.DataFrame({
'entity_id': ['Alice', 'Bob', 'Carol', 'Dave'],
'org': ['Acme', 'Acme', 'Globex', 'Globex'],
'country': ['US', 'US', 'DE', 'DE']
})
directed_graph = BuildGraphFromEdgeList(
edges_df,
node_1_column='person_a',
node_2_column='person_b',
is_directed=True,
node_attributes_dataframe=node_lookup_df,
node_id_column='entity_id'
)