Network objects¶
Every network, downloaded or generated, converts and writes the same way:
to_networkx(), to_infomap(), and to_pajek(directory) /
to_link_list(directory).
- class netgamut.Network(dataset, file, archive_path, member=None, source='', edge_file=None, columns=Columns(weight=None, time=None, layer=None, names=()))[source]¶
A downloaded network on local disk.
- dataset: DatasetLike¶
Full metadata for the dataset this file belongs to.
- member: str | None = None¶
For sources that ship a bundle, the member holding the edge list – Netzschleuder’s
csv.zipcontainsedges.csvalongside node and graph properties.Nonewhen the download is a single file.
- source: str = ''¶
Which
netgamut.<source>produced this handle.nodes()uses it to reach the reader that understands this source’s metadata layout, since no two sources keep node attributes in the same place.
- edge_file: Path | None = None¶
For sources whose download needs rewriting before any tool can read it, the rewritten edge list. KONECT’s files open with a
%header Infomap rejects and number the two sides of a bipartite network independently, sonetgamut.konectwrites a clean copy and keeps the archive beside it.
- columns: Columns = Columns(weight=None, time=None, layer=None, names=())¶
What the fields beyond source and target hold – weight, time, layer – as the source declares it from its metadata. Everything that reads links follows it, so a timestamp or a sign is never mistaken for a weight. Replace it with
dataclasses.replace()to read a column differently.
- property is_archive: bool¶
Whether reading needs
extract()rather thanpath.False for a bundle with a designated member: that member is the network, so reading works directly even though the download is an archive. Use
is_bundleto ask about the file itself.
- property path: Path¶
A path you can hand to any tool that reads a text file.
Gzipped files are decompressed once, next to the archive. A designated member is extracted from its bundle the same way. For a bundle with no member there is no single text file, so this returns the archive; use
extract()instead.
- extract(destination=None)[source]¶
Unpack a
.tar.gzor.zipbundle and return the directory.Works even when a member has been designated as the network, so a Netzschleuder bundle’s node and graph properties stay reachable.
Extraction lands in a scratch directory and is published with a rename, so a crashed or interrupted run cannot leave a partial directory that a later call would mistake for the real thing.
- rows(*, delimiter=None)[source]¶
Yield every non-comment line, split into its fields.
Use this for the datasets that carry more than two columns, such as timestamps in the temporal category or signs in the signed category.
The separator is detected from the first data line, since a few SNAP files are CSV rather than whitespace-separated. Pass delimiter to override that.
- nodes()[source]¶
Read this network’s per-node metadata, in the shape every source uses.
Where the attributes live differs completely by source – a separate SNAP artifact, a member of a Netzschleuder bundle, OGB’s
raw/andmapping/folders, a materialised PyG table – so the reading is delegated to the source. What comes back is always aNodeTable:nodes = netgamut.load("ogbn-arxiv").nodes() nodes.columns # ('arxiv_category', 'year', 'paper') nodes["arxiv_category"] # {node: 'arxiv cs na', ...} nodes.partition("arxiv_category") # {node: 0..k-1}, for AMI/NMI/D
Sources that keep metadata in a separate artifact download it here, on the same cache-once terms as
load().Node metadata is not ground truth for community structure: a partition that disagrees with an attribute is not thereby wrong. See
netgamut._core.nodes.- Raises:
LookupError – The source publishes no per-node metadata, or this dataset ships none.
- communities(*, cast=None)[source]¶
Stream communities from a SNAP ground-truth file.
Each line of a
*.cmty.txtfile is one community, listed as tab-separated node ids. Communities overlap, so a node may appear in several. Use this as the reference partition when scoring a community-detection run.
- edges(*, cast=None)[source]¶
Stream
(source, target)pairs.Values are strings unless you pass cast;
cast=intis usual, since most SNAP files use integer node ids. Streaming means memory stays flat no matter how large the file is.
- to_networkx(*, directed=None, cast=<class 'int'>)[source]¶
Build a networkx graph.
Direction defaults to what SNAP reports for the dataset. Requires the
networkxextra:pip install "netgamut[networkx]"
Be deliberate here: a networkx graph holds every node and edge in memory, so check
dataset.edgesbefore calling this on a large one.
- property partition: None¶
a downloaded network has no planted partition.
Present so code written for generated networks runs on downloaded ones too. Per-node metadata, which is not ground truth, is
nodes().- Type:
Always
None
- to_pajek(directory, *, name=None, directed=None, names=None)[source]¶
Write
<directory>/<name>.netin Pajek format and return its path.name defaults to the dataset’s name and directed to the direction the source reports. Integer node ids are kept; any other labels are numbered
1..Nand kept as*Verticesnames. The file is streamed in two passes – nodes, then links – so memory holds the node set but never the links.names maps a node id to the name shown on its
*Verticesline. By default it is the source’s own names, where they come in the download already made – Netzschleuder’snodes.csv, KONECT’sent.*files; seeNodeTable.labels(). A node without one shows its id. Pass{}to label every node by its id.
- to_link_list(directory, *, name=None, directed=None)[source]¶
Write
<directory>/<name>.txtas a link list and return its path.Streams in one pass. A
# directedor# undirectedcomment records directed, which defaults to what the source reports.- Raises:
ValueError – A node id is not a non-negative integer; use
to_pajek(), which keeps labels as names.
- to_infomap(*, directed=None, **kwargs)[source]¶
Build an
infomap.Infomapinstance with this network loaded.Direction defaults to what SNAP reports. Extra keyword arguments are passed to the
Infomapconstructor. Requires theinfomapextra:pip install "netgamut[infomap]"
- property times: Any[source]¶
The time of every link, as a numpy array in file order.
One entry per link row, aligned with
edges(). Integers stayint64(Unix timestamps usually), fractional times arefloat64and ISO datesdatetime64[s]. Read once and kept, so look at it before choosing how to bin:t = net.times t.min(), t.max() numpy.histogram(t, bins="auto")
Needs numpy.
- Raises:
LookupError – The source declares no time column for this file.
- time_bins(bins=10, range=None)[source]¶
The bin edges
snapshots()would use, fromtimes.bins and range mean what they mean to
numpy.histogram_bin_edges(): a number of equal-width bins, a sequence of edges, or an estimator such as"auto"or"fd".
- snapshots(bins=10, range=None, *, directed=None)[source]¶
Yield one first-order network per time bin, built only when reached.
Bins follow
time_bins(); biniholds the links withedges[i] <= t < edges[i + 1](the last bin alsot == edges[-1]), and links outside every bin are left out. Every bin yields, empty ones included, so the position in the iteration is the bin. A link’s weight is how many times it occurs in the bin – the sum of its weights if the file has a weight column. Each snapshot’sinfoholds itsbin,start,endand the number ofevents.The file is read once, on the first
next(); each snapshot is assembled from its rows when it is reached.- Raises:
LookupError – The source declares no time column for this file.
- to_multilayer(*, bins=None, range=None, layer=None, directed=None)[source]¶
Build a
MultilayerNetworkfrom a layer or time column.With bins, the layers are time bins, exactly the
snapshots(): layeriis bini, empty ones kept so layer ids stay time order, andinfo["bin_edges"]records the edges. Without, the layers come from the source’s layer column, or from the column named layer – any categorical field, e.g. a type of interaction. Link weights are counts of occurrences, summed weights where the file has a weight column.There are no inter-layer links: give Infomap a relax rate, and for time layers a relax limit so flow moves only between neighbouring bins:
ml.to_infomap(multilayer_relax_rate=0.15, multilayer_relax_limit=1)
- Raises:
LookupError – No time column (with bins), or no layer column.
ValueError – Both bins and layer given.
- class netgamut.InMemoryNetwork(name, nodes, links, directed=False, weighted=False, partition=None, info=<factory>)[source]¶
A first-order network in memory: generated, or a time slice of a download.
Instances are frozen; the containers are the generator’s result and must not be mutated. Convert with
to_networkx()for anything that edits.- name: str¶
Used as the file name by
to_pajek()andto_link_list().
- links: dict[tuple[Hashable, Hashable], float]¶
(source, target) -> weight; weight 1.0 throughout when unweighted.
- partition: dict[Hashable, Any] | None = None¶
The planted ground truth of a generated network,
{node: module}; a module is anint, a path tuple for a hierarchical partition, or a tuple of memberships for an overlapping cover.Nonefor real data.
- info: dict[str, Any]¶
For a generated network,
"generator"and"parameters"and the generator’s diagnostics; for a snapshot, its bin and time span.
- classmethod from_networkx(graph, *, name, partition=None, info=None)[source]¶
Capture a networkx graph;
"weight"is the only edge data kept.
- edges()[source]¶
Yield
(source, target)pairs, asNetwork.edges()does.
- to_networkx(*, partition_attribute='module')[source]¶
Build a networkx graph, with the planted partition as a node attribute.
Each node’s module lands under partition_attribute (
"module"by default;Noneleaves it out), sonetworkx.get_node_attributes(G, "module")gives backpartition. Weights are set only for a weighted network.
- to_infomap(**kwargs)[source]¶
Build an
infomap.Infomapinstance with this network loaded.Direction follows the network; extra keyword arguments go to the
Infomapconstructor. Node ids are the labels when those are non-negative integers, as every generator here produces; otherwise1..Nwith the labels as names.
- to_pajek(directory, *, name=None)[source]¶
Write
<directory>/<name>.netin Pajek format and return its path.name defaults to
name. Generator names include the parameters that matter, but not all of them: pass name when writing a sweep that varies something else into one directory.
- to_link_list(directory, *, name=None)[source]¶
Write
<directory>/<name>.txtas a link list and return its path.A link list holds links only, so isolated nodes are not in the file;
to_pajek()keeps them.- Raises:
ValueError – A node label is not a non-negative integer; use
to_pajek(), which keeps labels as names.
- class netgamut.StateNetwork(order, physical_nodes, states, links, num_paths=0, num_short_paths=0, name='', partition=None, info=<factory>)[source]¶
A memory network in Infomap’s state format.
Build one from paths with
from_paths()– or sample one withnetgamut.generate.memory_benchmark()– then write it for the Infomap CLI withto_pajek()or hand it to the Python API withto_infomap(). Instances are frozen; the dicts are the construction result and must not be mutated.- states: dict[int, tuple[int, ...]]¶
State id -> window of physical ids; the current node is the last entry.
- num_short_paths: int = 0¶
they contain no state transition and contribute nothing. Nonzero here is not an error, but a large fraction means the chosen order overreaches the data – or, if the paths were cut to a node subset, that cutting fragmented them.
- Type:
Paths shorter than
order + 1nodes
- name: str = ''¶
Used as the file name by
to_pajek(); the dataset’s name when built from a path dataset.
- partition: dict[int, Any] | None = None¶
The planted ground truth of a sampled state network,
{state_id: module}.
- info: dict[str, Any]¶
For a sampled network,
"generator","parameters"and the sampler’s diagnostics.
- classmethod from_paths(paths, *, order=2, name='')[source]¶
Accumulate paths into a state network of the given Markov order.
Each item is a sequence of node labels, or a
(sequence, weight)pair – itineraries flown by many passengers count that many times. A sliding window turns every(order + 1)-gram into one state link: with the default order 2,i -> j -> kadds weight to the link(i, j) -> (j, k). Repeated transitions accumulate.Labels can be any hashable value; they are compared as given and rendered with
strin output. Ids are assigned in first-seen order, so the same paths in the same order produce identical output files.- Raises:
ValueError –
orderis smaller than 1.
- write(target)[source]¶
Write the Infomap states format:
*Vertices,*States,*Links.The file works directly as CLI input:
infomap network_states.net output/ --directed
Output is sorted by id, so equal networks produce equal files.
- to_pajek(directory, *, name=None)[source]¶
Write
<directory>/<name>.netand return its path.The states format (see
write()) for order 2 and up; at order 1, where states and physical nodes coincide, a plain directed Pajek file, matching whatto_infomap()loads. name defaults toname.
- to_link_list(directory, *, name=None)[source]¶
Write
<directory>/<name>.txtat order 1 and return its path.- Raises:
TypeError – Order 2 and up; a link list cannot say which physical node a state belongs to, so use
to_pajek().
- to_networkx(*, partition_attribute='module')[source]¶
Build a
networkx.DiGraphover state ids.Each node carries
physical(its physical id) andname(its memory, e.g."LAX -> JFK"), plus the planted module under partition_attribute when there is one. Edges carryweight.
- to_infomap(**kwargs)[source]¶
Build an
infomap.Infomapinstance with this state network loaded.Directed flow is the default – transitions are inherently directed. Pass
flow_model="rawdir"to use the accumulated counts as raw flow instead of smoothing them with the default PageRank iteration; which is right depends on whether the paths sample a stationary process. Requires theinfomapextra:pip install "netgamut[infomap]"
- class netgamut.MultilayerNetwork(name, intra, inter=<factory>, directed=False, weighted=False, partition=None, names=<factory>, info=<factory>)[source]¶
Intra-layer links per layer, optional inter-layer links, planted partition.
Instances are frozen; the containers are the generator’s result and must not be mutated.
- name: str¶
Used as the file name by
to_pajek().
- intra: dict[Hashable, dict[tuple[Hashable, Hashable], float]]¶
{layer: {(u, v): weight}}, weight 1.0 throughout when unweighted.
- inter: dict[tuple[tuple[Hashable, Hashable], tuple[Hashable, Hashable]], float]¶
{((node, layer), (node, layer)): weight}, both ends on the same physical node – Infomap’s*Interlinks, which it spreads to the node’s neighbours in the target layer. Empty for a multiplex whose layers are coupled by the relax rate rather than by links.
- weighted: bool = False¶
Whether link weights are worth writing; multilayer files always carry a weight column, so this only affects
to_networkx().
- partition: dict[tuple[Hashable, Hashable], Any] | None = None¶
The planted ground truth,
{(node, layer): module}.
- info: dict[str, Any]¶
"generator"and"parameters"say how this was made; the rest is the generator’s own diagnostics.
- to_networkx(*, layer=None, partition_attribute='module')[source]¶
Build a networkx graph of the whole network or of one layer.
With layer
None, the supra-graph: nodes are(node, layer)tuples carryingnodeandlayerattributes, intra-layer edges join state nodes of one layer and inter-layer edges are markedinterlayer=True. With a layer, that layer alone over physical nodes – what{layer: graph}used to hold. Either way each node’s planted module lands under partition_attribute (Noneto skip).
- to_infomap(**kwargs)[source]¶
Build an
infomap.Infomapinstance with this network loaded.Pass
multilayer_relax_rate(and friends) to control how Infomap couples layers that have no inter-layer links. Ids follownetgamut._core.formats.node_ids(): kept when they are non-negative integers, renumbered otherwise.
- to_pajek(directory, *, name=None)[source]¶
Write
<directory>/<name>.netin Infomap’s multilayer format.*Vertices, then*Intra, and*Interwhen there are inter-layer links. Returns the path.
- to_link_list(directory, *, name=None)[source]¶
Not available: a link list cannot say which layer a link is in.
- Raises:
TypeError – Always; use
to_pajek(), whose*Intra/*Intersections are the multilayer equivalent.
- class netgamut.Hypergraph(dataset, file, archive_path, source='', revision=None)[source]¶
A downloaded higher-order dataset on local disk.
- dataset: DatasetLike¶
Full metadata for the dataset this file belongs to.
- property metadata: dict[str, Any]¶
The dataset-level JSON object on the first line, exactly as written.
Keys are the file’s own –
_format-versionon every currently published file. Useformat_version,file_revisionandnum_networksto read the reserved ones without caring which spelling this file used.
- property file_revision: int | None¶
The revision number the file itself records, or
None.Format 0.1 wrote no revision at all, so older published revisions have none to report.
revision– the one that was asked for – is always known.
- property num_networks: int¶
How many constituent networks the file holds; 1 unless it says otherwise.
- interactions(*, cast=None, network=None)[source]¶
Stream
(nodes, attributes)for every interaction.Members come back as strings unless you pass cast;
cast=intis usual. Streaming means memory stays flat however large the file is:for members, attributes in hypergraph.interactions(cast=int): ... # ((2, 12, 20), {'category': 'lie-algebras'})
In a multi-network file, pass network to take only the constituent network with that
id; without it every interaction is streamed and the marker attributes are the way to tell them apart.
- node_records(*, cast=None)[source]¶
Stream
(node, attributes)for every explicitly declared node.Most datasets declare no nodes at all and let the interactions imply them, so an empty stream is normal rather than an error.
- networks()[source]¶
The marker objects of a multi-network file, in file order.
Each is that constituent network’s own metadata –
MANTRA-2-manifoldsgives 43,214 of them, one per triangulated manifold, carrying Betti numbers, orientability and genus. Empty for an ordinary file.
- interaction_labels(attribute, *, network=None)[source]¶
The value of attribute on each interaction, in file order.
This is the reference labelling for a hyperedge-classification dataset:
interaction_labels("category")onalgebra-questionsgives the question category each co-answering group belongs to. Interactions missing the attribute contributeNonerather than being dropped, so the list stays aligned withinteractions().
- nodes()[source]¶
Read per-node metadata into the shape every source uses.
Delegates to the source, as
netgamut.Network.nodes()does. Node metadata is not ground truth for community structure; seenetgamut._core.nodes.- Raises:
LookupError – The source publishes no per-node metadata, or this dataset declares no nodes explicitly.
- to_networkx(*, projection='clique', cast=<class 'int'>, weighted=True)[source]¶
Build a networkx graph by projecting the interactions.
projection="clique"connects every pair that shares an interaction, weighting each edge by how many interactions they share."star"keeps the interactions as nodes – labellede0,e1, … and markedbipartite=1– joined to their members, which loses nothing.Requires the
networkxextra:pip install "netgamut[networkx]"
- Raises:
ValueError – Unknown projection.
- to_infomap(**kwargs)[source]¶
Build an
infomap.Infomapinstance holding the bipartite projection.Infomap reads bipartite networks natively, so the interactions stay in the model rather than being flattened away: physical nodes take ids
0..n-1, each interaction takes an id at or abovebipartite_start_id, and the modules Infomap reports span both. That is the whole reason for keeping a hypergraph handle at all – the clique projection would have thrown the interaction sizes away before Infomap ever saw them.The file is read twice: once to number the nodes in first-seen order, once to add the links. Extra keyword arguments go to the
Infomapconstructor. Requires theinfomapextra:pip install "netgamut[infomap]"
- to_network(*, projection='clique', cast=None, force=False)[source]¶
Flatten to a dyadic edge list and return a
Networkover it.The projected edge list is written next to the cached archive and reused on later calls, so this costs one pass the first time and nothing after. Use it to feed a hypergraph to anything that wants an ordinary graph –
netgamut.generate, an external tool reading a two-column file.What comes back describes the projection, not the dataset: no source tag, so per-node metadata stays here rather than on the result, and no sizes, because an interaction count is not an edge count.
The star projection labels its interaction nodes
e0,e1, … , so the file mixes those with the source’s own identifiers and cannot be read withcast=int. Preferto_infomap(), which builds the bipartite network directly and keeps the two kinds of node properly separated.- Raises:
ValueError – Unknown projection.
- class netgamut.Columns(weight=None, time=None, layer=None, names=())[source]¶
Which field of each row holds what. Field 0 is the source, 1 the target.
Nonemeans the file has no such field. The default – no weight, no time, no layer – reads every file as an unweighted edge list, which is the safe reading of a column nobody has vouched for.- time: int | None = None¶
Timestamp of the link, for
Network.timesand time snapshots.
- layer: int | None = None¶
Layer of the link, for
Network.to_multilayer().
- find(name)[source]¶
The index of the field called name.
- Raises:
LookupError – No field has that name.