Skip to content

Usage Guide

LaNet-vi can be used from the command line (lanet-vi) or as a Python library (lanet_vi). Both run the same pipeline: load a network → decompose it (k-cores, k-denses or d-cores) → compute the layout → render. This guide is the reference for both; the concepts are in concepts.md and the picture itself is explained in visualization.md. Users of the C++ LaNet-vi 3.x will find the flag translation in cpp-migration.md.

Command line

Commands

Command What it does
lanet-vi visualize --input FILE --output FILE [options] Decompose and draw a network
lanet-vi info FILE [--weighted] Print node/edge counts, degree statistics and the decomposition range
lanet-vi config FILE [--decomp kcores\|kdenses\|dcores] Write a YAML configuration template with every setting and its default
lanet-vi generate --output FILE --nodes N [--model ...] Write a random graph as an edge list

Quick start

lanet-vi visualize --input network.txt --output network.png
# The network statistics first
lanet-vi info network.txt
# K-dense (m-core) instead of k-cores, and the decomposition as CSV next to the picture
lanet-vi visualize --input network.txt --output kdense.png --decomp kdenses --cores-file kdense.csv
# Directed graph, d-cores
lanet-vi visualize --input citations.txt --output dcores.png --directed --decomp dcores
# Weighted graph: strength-based cores, 20 intervals with the same number of nodes each
lanet-vi visualize --input weighted.txt --output weighted.png \
  --weighted --granularity 20 --strength-intervals equalNodesPerInterval
# A large network: draw 10 % of the edges (at least 50,000), white background, wide picture
lanet-vi visualize --input big.txt --output big.png \
  --edges-percent 0.1 --min-edges 50000 --background white --width 3200 --height 2400
# Only the nodes of k-core index 5 and up, drawn as a network of their own
lanet-vi visualize --input network.txt --output core5.png --from-layer 5
# The central half of the picture at full pixel size: a 2x zoom on the core
# (give --width/--height the window's aspect ratio, 4:3 here, for an exact crop)
lanet-vi visualize --input network.txt --output core.png \
  --window 0.25 0.75 0.25 0.75 --width 2400 --height 1800
# Reproducible pictures: the seed fixes the random choices of the layout and the edge sample
lanet-vi visualize --input network.txt --output network.png --seed 42
# A synthetic network to try things on
lanet-vi generate --output ba.txt --model barabasi-albert --nodes 2000 --edges 3 --seed 1

visualize options

The C++ column gives the flag of LaNet-vi 3.x with the same meaning (see cpp-migration.md). Options marked inert are accepted for compatibility and do nothing yet; their --help text names the tracking issue.

Input and output

Option Default Meaning C++
--input, -i PATH required Edge list (see Input format); .gz / .bz2 are read transparently -input
--output, -o PATH output.png Picture; the extension selects PNG, PDF or SVG -output
--config, -c PATH YAML settings file (see Configuration file)
--cores-file PATH Write the decomposition: .json for the full result, anything else as CSV node,index -coresfile
--dcore-table PATH With --decomp dcores: write the (k, l)-core table, one node k l line per node and out-degree threshold l (see Concepts) dcores_list.txt of -directed (4.0)
--names PATH Node names, one node name per line; turns --node-labels on -names
--colors-file PATH Node colors, node r g b per line (values in 0–1); nodes absent from the file are drawn white on black / black on white and the color legend is hidden -colorsFile
--weighted, -w off Third column is an edge weight; cores are computed on strengths -weighted
--multigraph off Keep repeated edges (they count in the degree; with --weighted their weights add up) -multigraph
--directed off Read a directed graph (required for --decomp dcores) -directed (4.0)

Decomposition

Option Default Meaning C++
--decomp, -d kcores\|kdenses\|dcores kcores Which decomposition -decomp
--measure mcore\|kdense mcore Numbering of the k-dense legend: mcore labels each k-dense as k − 2 (the m-core) and reads --color-scale-max in those units; kdense keeps k -measure
--no-cliques off Spread the top core uniformly instead of by cliques -nocliques
--from-layer K 0 Zoom into the center: keep the subgraph induced by the nodes of index ≥ K, recompute the decomposition on it and draw that (see Zooming into the center) -fromlayer
--kconn off Compute the k-connectivity of the shells and paint the nodes that are not k-connected black on white / white on black, squares in bw and bwi (see K-connectivity); k-cores of a simple unweighted graph only -kconn
--kconn-type wide\|strict wide wide gives the clusters skipped by the walk another chance at every lower index; strict drops them -kconntype
--kconn-file PATH With --kconn: write node shell_index k_connectivity lines (0 = not k-connected) log/kconn.log
--granularity N max degree Weighted graphs: number of strength intervals -granularity
--strength-intervals equalIntervalSize\|equalNodesPerInterval\|equalLogIntervalSize\|custom equalIntervalSize Weighted graphs: how the intervals are built (concepts.md) -strengthsIntervals
--maximum-strength S data Weighted graphs: top of the strength scale, to compare pictures of different networks -maximumStrength
--strength-intervals-file PATH Interval boundaries, one per line, for --strength-intervals custom -strengthsIntervalsFile (4.0)

Layout

Option Default Meaning C++
--epsilon E 0.18 Ring thickness as a fraction of its radius (formula (1) of the paper) -eps
--delta D 1.3 Shrink factor of sibling components (classic) -delta
--gamma G 1.5 Component diameter; scales the whole picture -gamma
--coord-distribution classic\|pow\|log classic Placement of sibling components: concentric rings, or circle packing (visualization.md) -coordDistributionAlgorithm
--alpha A, --beta B 0.3, 1.0 Constant and exponent of the disc area law of the packing (pow / log) -alpha, -beta
--ratio-constant C auto Node radius factor of pow / log -ratioConstant
--seed N 0 Random seed: cluster order, ties, angle frames, the packing and the edge sample -seed

Picture

Option Default Meaning C++
--width, -W PX; --height, -H PX 2400 × 2400 Picture size in pixels; any aspect ratio (the layout is scaled uniformly, legends in the margins) -W, -H
--window HSTART HEND VSTART VEND 0 1 0 1 Render only that part of the picture, as fractions from the top-left corner, at the full pixel size -window
--background black\|white black Background -bckgnd
--color-scheme col\|bw\|bwi col Rainbow (red for the top core), grayscale, or interlaced grayscale -color
--color-scale-max K max index Indices at or above K share the top color (m-core units for k-dense with --measure mcore) -colorScaleMaxValue
--edges-percent P 0.5 Fraction of edges drawn; each edge is kept with probability max(P, min_edges / E) -edges
--min-edges N 50000 Lower bound on the number of edges drawn -minedges
--opacity O 0.2 Edge opacity (--edge-alpha is a deprecated alias) -opacity
--gradient-edges / --no-gradient-edges on Each half of an edge takes the color of the opposite endpoint
--node-size-scale S 1.0 Multiplier on the node radius (1.0 is the C++ size)
--node-edge-color COLOR none Border color of the nodes (the C++ drew none)
--draw-circles off Draw the disc of every component -drawCircles
--show-color-legend / --no-show-color-legend on Index color legend (right margin)
--show-degree-scale / --no-show-degree-scale on Degree (node size) legend (left margin); --show-size-legend is a deprecated alias -showDegreeScale
--node-labels / --no-node-labels on with --names Draw node names; without --names, every node is labeled with its number (the C++ -names with no file) -names
--font-zoom Z 1.0 Font size multiplier for node names -font
--legend-fontsize PT auto Legend font size in points (default: the C++ size, relative to the picture)
--min-edge-width, --max-edge-width inert, deprecated: widths follow the C++ rule

Communities (a NetworkX-based addition; the C++ tool had none):

Option Default Meaning
--detect-communities off Detect the communities of the drawn graph (the layer subgraph with --from-layer) and show them
--community-algorithm louvain\|greedy_modularity louvain NetworkX's Louvain (seeded by --seed) or greedy modularity maximization
--community-resolution R 1.0 Modularity resolution; higher gives more, smaller communities
--color-by-community / --no-color-by-community on Nodes (and gradient edges) take their community's color instead of the index color; the index color legend is then not drawn. A --colors-file takes precedence
--draw-community-boundaries / --no-draw-community-boundaries on A translucent convex hull under each community of three or more nodes

The YAML community section also has draw_circles (a translucent circle around each community instead of, or besides, the hull), boundary_alpha (opacity of the overlays, 0.2) and colormap (tab20; a qualitative colormap is used entry by entry, a continuous one is sampled evenly). The number of communities and the modularity of the partition are printed after the decomposition. Communities are found on the undirected version of a directed graph and use the edge weights when present. The layout places nodes by index, not by community, so the hulls of a large graph with many communities overlap into a haze: there, keep the colors and pass --no-draw-community-boundaries.

Logging--verbose, -v (debug output), --quiet, -q (no console output), --log-file PATH (also write the log to a file). lanet-vi generate and lanet-vi info take the same three.

generate options

--model erdos-renyi|barabasi-albert|watts-strogatz|powerlaw-cluster (default erdos-renyi), --nodes N (required), and per model: --probability P or --edges M (Erdős–Rényi G(n, p) / G(n, m)), --edges M (Barabási–Albert attachment, powerlaw-cluster), --neighbors K --rewire P (Watts–Strogatz), --triangle-prob P (powerlaw-cluster); --directed (Erdős–Rényi only; the other models ignore it), --weighted (random weights), --seed N. The output is a plain edge list that visualize reads back.

Configuration file

lanet-vi config settings.yaml writes every setting with its default, grouped as graph, decomposition, visualization, layout and community; edit it and pass it with --config. Precedence is that of the C++: built-in defaults < the YAML file < flags given explicitly on the command line, so a file can hold the standing choices and a flag override one of them:

lanet-vi config settings.yaml
lanet-vi visualize --input network.txt --output network.png --config settings.yaml --background white

The same file loads in Python with lanet_vi.load_config_from_yaml(path) and can be written with save_config_to_yaml(config, path). A minimal file:

decomposition:
  decomp_type: kcores
visualization:
  background: black
  width: 2400
  height: 2400
  edges_percent: 0.5
  opacity: 0.2
layout:
  seed: 0

Zooming into the center

--window crops the picture; --from-layer K changes the network instead: it keeps the subgraph induced by the nodes of index ≥ K, computes the decomposition of that subgraph and runs the usual pipeline on it, as the C++ -fromlayer did. The outer layers disappear, the remaining ones get the whole frame, and the legends and --cores-file describe the subgraph (lanet-vi info has no such option and always reports the whole file). Details:

  • For k-cores the indices of the kept nodes do not change (the K-core of a graph contains all its higher cores). Weighted graphs reuse the strength intervals of the whole graph, so the layer numbers keep their meaning.
  • For k-denses K is the k-dense index (the value in --cores-file, not the m-core label of the legend) and the indices are recomputed on the induced subgraph, which can hold edges that were not in the K-dense; some nodes may end up below K.
  • For d-cores K applies to max(k_in, k_out), the index the rings are drawn by.
  • K above the maximum index is a usage error.

K-connectivity

--kconn runs the k-connectivity analysis of Beiró, Alvarez-Hamelin & Busch (NJP 2008) on the k-core picture: a walk from the top shell down that grows a k-connected set cluster by cluster (see Concepts). Nodes that never join it are painted black on a white background, white on a black one, and drawn as squares in the grayscale schemes, exactly as the C++ did; the color legend is unchanged. --kconn-file writes every node's value (the C++ log/kconn.log); --kconn-type strict selects the stricter variant. Both need the k-core decomposition of an undirected, unweighted, simple graph. In Python, Network.compute_kconnectivity() returns the mapping and Network.kconnectivity keeps it for compute_layout().

lanet-vi visualize --input network.txt --output kconn.png --kconn --kconn-file kconn.txt

Input format

An edge per line, source target [weight], separated by spaces or tabs; lines starting with # are comments; .gz and .bz2 files are decompressed on the fly. Node ids can be integers or names (names with spaces need a --names file). Self-loops are dropped; repeated edges are merged unless --multigraph. Without --weighted a third column is ignored; with it, a missing weight counts as 1.

# source target weight
0 1 2.5
1 2 3.0
2 0

CAIDA AS-relationship snapshots (<as1>|<as2>|<relation> lines) are read by lanet_vi.io.readers.read_caida_snapshot, from a local file or a URL.

Python API

import networkx as nx
from lanet_vi import DecompositionType, LaNetConfig, Network

# networkx's karate club carries edge weights, which LaNet-vi would detect and use
# (strength-based cores); nx.Graph(G.edges()) keeps the plain graph
G = nx.Graph(nx.karate_club_graph().edges())
net = Network(G, LaNetConfig())
result = net.decompose(DecompositionType.KCORES)
net.visualize("karate.png")

print(result.min_index, result.max_index)   # 1 4: the k-core range
print(result.node_indices[0])               # 4: the k-core number of node 0

Edge weights are detected automatically: a graph whose edges carry a weight attribute (or a third column with --weighted) gets strength-based cores; see concepts.md.

Network takes a NetworkX graph (Graph, DiGraph, MultiGraph) or reads an edge list:

net = Network.from_edge_list("network.txt", LaNetConfig())

Every setting of the CLI is a field of LaNetConfig, in the same groups as the YAML file (the CLI flag --edges-percent is config.visualization.edges_percent, and so on):

from lanet_vi import DecompositionType, LaNetConfig
from lanet_vi.models.config import BackgroundColor, CoordDistributionAlgorithm

config = LaNetConfig()
config.decomposition.decomp_type = DecompositionType.KDENSES
config.visualization.width = 3200
config.visualization.height = 2400
config.visualization.background = BackgroundColor.WHITE
config.visualization.edges_percent = 0.1
config.layout.coord_distribution = CoordDistributionAlgorithm.POWER
config.layout.seed = 42

The pipeline can be run step by step when the intermediate results are needed:

result = net.decompose()          # DecompositionResult
layout = net.compute_layout()     # VisualizationLayout: positions, colors, sizes, edges
net.visualize("network.png", layout)
  • result.node_indices maps every node to its index (k-core number, k-dense index, or max(k_in, k_out) for d-cores; the pairs are in result.metadata["d_cores"]); result.components lists the connected pieces of each shell; k-dense results also carry result.metadata["edge_indices"].
  • layout.node_positions, layout.node_colors (RGB in 0–1), layout.node_sizes (layout units), layout.visible_edges, layout.components (nested components with center and radius) and layout.bounds are what the renderer draws.
  • net.get_metadata() returns node and edge counts, density and degree statistics.

Results can be written with the same writers the CLI uses:

from lanet_vi.io.writers import write_decomposition_csv, write_decomposition_json

write_decomposition_csv(result, "cores.csv")    # node,index
write_decomposition_json(result, "cores.json")  # indices, components, metadata

Community detection

lanet_vi.community wraps NetworkX's Louvain and greedy-modularity algorithms and lanet_vi.metrics provides partition comparison metrics (NMI and friends). They are NetworkX-based replacements, not ports of the C++ research code (#26). Network detects the communities of the drawn graph when config.community.detect_communities is set, or on demand:

from lanet_vi import LaNetConfig, Network
from lanet_vi.models.config import CommunityConfig

config = LaNetConfig(community=CommunityConfig(algorithm="greedy_modularity"))
net = Network.from_edge_list("network.txt", config)
net.decompose()
communities = net.detect_communities()   # kept in net.communities
print(communities.num_communities, communities.modularity)
net.visualize("communities.png")         # community colors and hulls

compute_layout() then colors the nodes by community (color_by_community) and visualize() draws the hulls and circles (draw_boundaries, draw_circles); the overlay functions themselves are in lanet_vi.visualization.community_viz.

Notes on large networks

  • The CAIDA AS graph (78k nodes, 489k edges) takes about a minute end to end at the default 2400 × 2400; the layout is the expensive part and grows with the number of nodes and shells.
  • Drawing is dominated by the edges: --edges-percent (with --min-edges as a floor) is the knob. On a black background 0.1–0.5 with the default opacity reads well; on white, raise the opacity.
  • --seed makes the picture reproducible; a different seed only changes the random choices (cluster order, angle frames, the edge sample), not the structure.
  • Everything is in memory; a few million edges are fine on a laptop, but the matplotlib rendering of millions of edges is slow — sample them.