Changelog¶
All notable changes to LaNet-vi will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
Added¶
--kconn,--kconn-type wide|strictand--kconn-file FILE(kconn,kconn_typein YAML;Network.compute_kconnectivity()/Network.kconnectivityin Python): the k-connectivity of the shells, the C++-kconn(#47). Port ofcomputeKConnectivityWide/computeKConnectivityStrictofgraph_kcores_components.cpp(Beiró, Alvarez-Hamelin & Busch, NJP 2008): a walk from the top shell down that seeds a k-connected set with the first cluster of diameter ≤ 2 (wide: or minimum edge cut ≥ shell; strict: and minimum degree ≥ shell) and grows it with the contracted-diameter and frontier / φ conditions, each shell's clusters examined once in the order of the component tree. Verified against a literal transcription of the C++ loops on 2 400 random graphs. Nodes that are not k-connected are painted black on white / white on black and drawn as squares in thebw/bwischemes, as the C++ did; the C++ "border color" (a same-radius circle under the node in its SVG, invisible) is not drawn.--kconn-filewrites the C++log/kconn.log(node shell_index k_connectivity, 0 = not k-connected). Refused for k-denses, d-cores, weighted, directed and multigraph inputs, as the C++ did. Not reproduced: the crash on a shell without clusters and theshell == 77debugging escape of the strict seed.
Documentation¶
- Issue #25 is closed as won't-fix for the Gomory-Hu connectivity report and the POV-Ray
scenes; k-connectivity (
-kconn) moves to #47.docs/cpp-migration.mdand the parity checklist below say so.
5.2.0 - 2026-09-20¶
Every item of the September 2026 C++ comparison is now closed except the features listed
under #25 (k-connectivity, Gomory-Hu connectivity, POV-Ray): the community flags,
--from-layer, --window and the C++ -names forms work, the dead options are gone,
the d-core table of the 4.0.0 tool is available, the tests cover 95 % of the package and
the documentation site is live.
Added¶
--dcore-table FILEandcompute_dcore_table(#21): the (k, l)-core table of Giatsidis et al. for a directed graph — for every out-degree threshold l, the largest k with each node in the (k, l)-core — written as the C++ 4.0.0dcores_list.txt(node k llines). That driver computed only this table for a directed graph and drew nothing; it also kept a node in the in-degree peeling after its out-degree had dropped below l, reporting a larger k for such nodes, while this implementation follows the definition (checked against a brute-force table in the tests). The picture and the(k_in, k_out)pairs are unchanged.- Community detection is wired into the picture (#23):
--detect-communities(and thecommunityYAML section) detects the communities of the drawn graph with Louvain or greedy modularity (--community-algorithm,--community-resolution, seeded by--seed), colors the nodes and the gradient edges by community (--color-by-community, which hides the index color legend; a colors file takes precedence) and draws a translucent convex hull under each community (--draw-community-boundaries);draw_circles,boundary_alphaandcolormapare YAML-only. The CLI prints the number of communities and the modularity. In the API:Network.detect_communities(),Network.communities,Network.colors_by_community,lanet_vi.community.detect_communities(graph, config, seed), aresolutionfordetect_communities_greedy_modularity, andrender_network(communities=, community_config=).community.colormapmust name a matplotlib colormap (a short validation error otherwise). The community flags are no longer marked inert. --from-layer K(from_layerin YAML) works: the C++-fromlayer(#23). The subgraph induced by the nodes of index ≥ K is decomposed again (weighted k-cores reuse the strength intervals of the whole graph) and the layout, the picture, the legends and--cores-filedescribe that subgraph.compute_kcorestakes ap_functionto reuse. A layer above the maximum index is a usage error.--node-labelswithout--nameslabels every node with its number, the C++-nameswith no file (-names 0) (#23). With a names file only the named nodes are labeled, as before.--window HSTART HEND VSTART VEND(windowin YAML), the C++-window: render only that fraction of the frame, measured from the top-left corner, at the full pixel size (#25). PDF and SVG output (by the--outputextension) already worked and is now documented.
Removed¶
- The dead
renderersetting (LaNetConfig.renderer, theRendererenum and the top-levelrenderer:key oflanet-vi configoutput): matplotlib is the only renderer and nothing read it (#23). Older YAML files that still have the key load unchanged (unknown keys are ignored). - The inert spiral layout and spatial index:
visualization/spiral_layout.pyandvisualization/spatial_index.py(nothing called them; the C++espiral.cppwas never in a release), the--use-spiral-layout,--spiral-K,--spiral-betaand--spiral-separationflags, and thelayout.use_spiral_layout,spiral_k,spiral_beta,spiral_separationanduse_spatial_hashingsettings. YAML files that still contain those keys keep loading (unknown keys are ignored); the flags are now an error. The placement is selected by--coord-distributionalone.
Fixed¶
compute_dcorescounted a self-loop toward both the in- and the out-degree, so a node with only a self-loop was a (1, 1) node; self-loops are ignored now, as the edge-list reader, the k-core path and the (k, l)-core table already do.get_community_colorsignored itscolormapargument and, for 21-40 communities, sampledtab20bat fractions that repeat colors. A qualitative colormap is now used entry by entry (up to 10 communities take thetab10shades instead oftab20's dark/light pairs), a continuous one is sampled evenly, and beyond the entries of a qualitative map the colors are spread overhsv. Community colors follow the community id rather than its position in the list.draw_community_boundariesprinted Qhull's full diagnostic for a community whose nodes are collinear or share positions; collinear communities now get a sliver hull (Qhull's joggle) and communities with fewer than three distinct positions are skipped.- Community detection on a graph without edges (isolated nodes) raised a
ZeroDivisionErrorfrom NetworkX's modularity; the modularity is now 0. write_graph_json(include_node_attrs=False)wrote every node withid: 0(the id was read after the attributes were cleared); the real ids are kept now.write_graph_jsonalways writes the edges under"links": NetworkX 3.6 changes the default key ofnode_link_datato"edges", which would have silently changed the file format.- Loggers were named
lanet_vi.lanet_vi.<module>;get_loggerno longer doubles the package prefix.setup_loggingcloses the handlers of a previous call instead of leaking the log file handle. draw_community_circlesno longer triggers a matplotlib warning aboutcoloroverridingedgecolor.
Changed¶
- Coverage gate raised from 60 % to 80 % (#11) now that
metrics/,generators/,community/,visualization/community_viz.py,io/writers.pyandlogging_config.pyhave tests (the suite covers 95 %).
Documentation¶
- Documentation site at https://conexdat.github.io/LaNet-vi/ (#12): MkDocs with the
Material theme, the existing guides, the changelog and an API reference generated from
the docstrings by mkdocstrings.
mkdocs build --strictruns in CI on every PR;.github/workflows/docs.ymldeploys to GitHub Pages on every push tomain. Thedocsextra installs the tooling;uv run mkdocs servepreviews the site. - Content pass on the docs:
docs/usage.mdis now the reference for every CLI option (default, meaning, C++ equivalent, inert ones marked), the configuration file, the input and output formats and the Python API; newdocs/cpp-migration.mdtranslates every LaNet-vi 3.x flag; the README is shorter, drops the claims that did not hold (rendering "millions of nodes", community detection as a CLI feature) and links to the guides;docs/concepts.mdcites the actual papers (NIPS 2005, NJP 2008, D-cores, k-truss). Every shell block in the docs is now a command that runs as written (the multi-line ones had\\continuations that broke when pasted).
5.1.0 - 2026-09-18¶
The first release after a source-level comparison with the original C++ LaNet-vi 3.x. The
5.0.0 rewrite had replaced most of the algorithms with approximations; 5.1.0 ports them
faithfully, so the pictures are the LaNet-vi pictures again: the placement of
Alvarez-Hamelin, Dall'Asta, Barrat & Vespignani (NIPS 2005), the triangle peeling of
k-dense, the weighted k-core peeling, the color scale of types.cpp with red for the top
core, the per-edge sampling seeded by --seed, and the pow/log circle packing of
sibling components. It also fixes the crashes and CLI problems found on the way (d-cores through
the CLI, tab-separated input, self-loops, --multigraph, YAML round trip, --config
precedence, --names), drops Python 3.9, resolves every open security alert and adds
CITATION.cff. The details, by category:
Documentation¶
- American English is now the mandatory spelling for identifiers, docstrings, comments
and docs (
AGENTS.md,CONTRIBUTING.md, PR template). Existing British spellings in comments, docstrings and docs were corrected; the only renamed identifiers are private (_Placer.place_centre→place_center) and six test names, so no public API changed. CITATION.cff(validated withcffconvert): software citation with the package authors, version and release date, plus the NIPS 2005 and New Journal of Physics 2008 papers as references; the release checklist now updates it with each version.- README now has a Heritage section crediting the original C++ LaNet-vi (Beiró, Alvarez-Hamelin et al., 2005–2016), its SourceForge distribution under the Academic Free License 3.0 and the original homepage; the License section states the relation between the MIT-licensed rewrite and the AFL-licensed original.
- The 5.0.0 entry below overstated feature parity with the C++ version; it now carries a note pointing to the tracking issues (#18–#26).
Security¶
- Refreshed
uv.lock: resolves all 79 open Dependabot alerts (1 critical in jupyter-server, 42 high across Pillow, tornado, urllib3, mistune, jupyterlab and others). Onlyrequestsand Pillow (via matplotlib) are runtime dependencies; the rest were pulled in by thedevextra. - New
Securityworkflow:pip-auditover the locked tree on every lockfile change and weekly, pluszizmorover the workflow files. - GitHub Actions pinned to commit SHAs,
persist-credentials: falseon every checkout, and no cache restore in the release workflow. SECURITY.mdnow states supported versions, the private reporting channel, response targets and the coordinated-disclosure process.
Added¶
- The
powandlogcoordinate distributions of the C++ (--coord-distribution, #18): the network is a unit disc, the children of a component share a disc of radius((T - S) / T)^(1/8) Rcapped at0.96 R(log:sqrt((n - s) / n) R) and sibling components are packed as non-overlapping discs whose areas followalpha w^betaof theirsum(log(1 + d)^(2 / beta))share, inflated 1 % per round until they no longer fit (distribute_components.cpp, seeded by--seed). Node radii in these modes are0.007 ratio_constant log(1 + d)^1.5(computeHostRatio), with the new--ratio-constant(C++-ratioConstant, default 1). K-dense pictures use the variant ofkdenses_component.cpp(fixed0.92shrink, same-index neighbors in formula (1) and the angle,epsilonscaled bytau, nou, node radiusratio_constant sqrt(log(1 + d))withratio_constantauto-adjusted by the top cores).--alphaand--betanow act;alphadefaults to the C++ 0.3 (was an inert 1.0). Deliberate deviations: inflated discs keep their angle and are pulled towards their container's center (the C++ pulled them towards the picture's origin, and overwrotexbefore computingyfrom it, skewing the angle), unplaced neighbors are skipped in the angle.classicstays the default for every decomposition, although the C++ k-dense only ever had this placement (its default flags behaved aspow).
Deprecated¶
use_spatial_hashingis accepted and ignored: the circle packing follows the C++ algorithm (#18).edge_alpha(--edge-alpha) is an alias ofopacity(--opacity, the C++-opacity, default 0.2);min_edge_width/max_edge_width(--min-edge-width,--max-edge-width) are accepted and ignored (#24).lanet-vi configno longer writes the deprecated aliases (edge_alpha,show_size_legend) into the template, where they were ignored next to the current field.
Removed¶
visualization.circular_averageandlayout.compute_hierarchical_layout(replaced bylanet_layout);layout.distribute_componentsis now the faithful port used by thepow/logmodes (the earlier version lacked the growth loop) andlayout.SpatialHashGridis gone with it.- Python 3.9 support. 3.9 reached end of life in October 2025 and the patched
releases of Pillow, jupyter-server and others require 3.10+.
requires-pythonis now>=3.10; the code base usesX | Noneunions andzip(..., strict=True).
Fixed¶
- Rendering follows the C++ LaNet-vi again (#24). Color scale from
types.cpp: the rainbow runs magenta → blue → cyan → green → yellow → red (the maximum index was magenta), the black-and-white scale runs white → gray → black (it was inverted) andbwiinterlaces that same scale; consecutive shells alternate a luminosity of 0.7 and 1.2 (was 0.7/1.0), with the k-dense rules ofgraphics_kdenses.cpp(constant 0.9 on a white background; withmeasure = mcore, the default,--color-scale-maxis read in m-core units and the legend labels each k-dense ask - 2under the titlem-core;--measure kdensekeeps the k-dense numbers). Nodes absent from a--colors-fileare white on black / black on white, and the color legend is hidden in that case. - Edges: every edge is kept with probability
max(edges_percent, min_edges / E)(the C++ per-edge Bernoulli) using the layoutseed, so--seedmakes pictures reproducible (the stratified sampler used the unseededrandommodule). Edge colors darken by 0.75 incolpictures and lighten by 1.2 inbw/bwiones; k-dense edges are one color, their own dense index darkened by 0.5 (the flat gray the 3.0.1 release used for edges between clusters was removed in the 3.0.2 and 4.0.0 drivers and is not reproduced). Edge width is 0.2 host radii of the smaller endpoint degree (the C++ratioEdge), in layout units with a one-pixel floor; edges are drawn under the nodes in increasing index order. Nodes are opaque (the >1000-node path drew them at alpha 0.9). - Legends are drawn in layout units where
generateNetworkFileput them, so they scale with the picture: the color legend has one circle per index (from 1, or 2 for k-denses), labeled in the index color everymax // 15 + 1indices; the degree legend showsceil(dmax / 4^i)(down to 2, at most five) with the radius those nodes have in the picture (it used its own size formulas and ignorednode_size_scale), or strengths for weighted graphs. Weighted graphs whose strengths never exceed 1 (where the C++ strength law divides bylog(max) <= 0) now size nodes by the degree law instead of a constant radius, and the legend follows. - The PNG is exactly
width x heightpixels (bbox_inches="tight"cropped it); the frame is scaled uniformly to fit and centered, so any aspect ratio works and the validator that rejected sizes such as 3200x800 is gone. - Weighted k-cores (#20) now peel, as the C++
findCoresweighted branch does: every node starts in the strength interval of its total strength and, when a shell is removed, its neighbors are re-binned using only the strength they still receive from nodes above that shell. The previous code only binned total strengths (a histogram, not a core decomposition; it disagreed with the C++ on 1,570 of the 2,070 random configurations checked, see PR #31). Default granularity is the maximum degree again (the cap at 100 is gone). Indices run1..granularityin every interval method (0 for isolated nodes); the C++ 3.0.1 ran2..granularity+1inequalIntervalSizeandequalNodesPerIntervalbecause of a duplicated0.0boundary.equalLogIntervalSizestarts from the smallest positive strength instead of dividing by zero. The remaining strength of each node is kept incrementally while peeling (the C++ re-summed it on every re-binning), and negative weights are refused with a clear error. - New
--maximum-strength(configmaximum_strength, the C++-maximumStrength) and--strength-intervals customwith--strength-intervals-file(configstrength_intervals_file, the C++ 4.0.0-strengthsIntervalsFile) (#20). - Invalid configuration (from the YAML file or the flags), an unusable
--strength-intervals-fileand inputs the decomposition refuses (negative weights,--decomp dcoreson an undirected graph) are reported as usage errors instead of tracebacks. - K-dense decomposition (#19) now implements the C++ triangle-pair peeling (the k-truss
decomposition): every edge starts with its triangle count and removing an edge lowers the
count of the two other sides of each triangle it closed. The previous code took a plain
vertex k-core of the edge/triangle dual graph, which over-estimates the index of edges
whose triangles share a side, and its triangle enumeration assumed sorted adjacency, so
it silently missed triangles on real edge lists. Parallel edges and self-loops are
ignored. Per-edge indices are exposed as
result.metadata["edge_indices"](JSON export writes them as[u, v, index]triples). Verified against a brute-force k-truss on random graphs. The CAIDA 20251001 example now spans k-dense 2–105 (was 2–55); its image is regenerated. - The color legend is titled after the decomposition (
k-dense,d-core) instead of alwaysk-core(#10). --directed --decomp dcorescrashed with a PydanticValidationErrorwhile building components (Componentwas constructed withid/indexinstead ofcomponent_id/shell_index). The d-core path throughNetwork.decompose()and the CLI works again and is now covered by tests (#21).- Edge-list reader (#22): columns may be separated by any whitespace (tabs and repeated
spaces used to abort with
invalid literal for int()); an unused third column is ignored when the graph is not weighted;--weightedon a two-column file uses weight 1.0 instead of NaN; self-loops are dropped with a warning instead of crashing the decomposition; non-integer node ids and single-column files give a clear error. All of this matches the C++ reader. --multigraphno longer crashes k-cores: parallel edges count towards the degree (the C++ behavior) and, for weighted multigraphs, their weights are summed into the strength.write_edge_list(and thereforelanet-vi generate) now defaults to space-separated output; its files were tab-separated and could not be read back bylanet-vi visualize.- Node names may contain spaces (the name is the rest of the line, quotes stripped) and the colors file accepts tabs.
lanet-vi configwrote YAML with!!python/object/applytags that--configcould not load; enums are now written as plain strings (#23).--configno longer discards the other command-line flags. Precedence is now the C++ one: defaults < YAML file < flags given explicitly on the command line (#23).--namesnow draws the labels (it loaded them and drew nothing); use--no-node-labelsto load names without drawing them. A node named0is no longer skipped (#23).--show-degree-scaletoggled the color legend instead of the degree legend. It now controls the degree (node size) legend, as the C++-showDegreeScale; the color legend has its own--show-color-legend/--no-show-color-legend(configshow_color_legend).show_size_legendis kept as a deprecated alias that folds intoshow_degree_scale(#23).- Default-true boolean flags (
--show-degree-scale,--gradient-edges,--color-by-community,--draw-community-boundaries) now have--no-...forms (#23). - Options that the current implementation does not use (
--from-layer,--use-spiral-layoutand the--spiral-*settings,--detect-communitiesand the other community flags) say so in their help text, with the tracking issue (#18, #23). (--delta,--gamma,--alpha,--betaand--coord-distribution, inert at the time, act since the layout ports below.) write_decomposition_jsoncrashed when components were present (it read non-existentComponent.id/Component.indexattributes).lanet_vi.community.basefailed to import on Python 3.9 because ofX | Nonereturn annotations evaluated at runtime.get_community_colorsreturned RGBA quadruples and used the removedmatplotlib.cm.get_cmapAPI; it now returns RGB triples viapyplot.get_cmap.--community-algorithmnow rejects unknown values with a usage error instead of a Pydantic validation traceback.- D-core decomposition (
--directed --decomp dcores) crashed becauseDecompositionResulthad nometadatafield; the field now exists and holds the(k_in, k_out)pairs.min_indexis now derived from the data instead of hard-coded to 1. lanet_vi.community.baseusedX | Noneannotations that fail to import on Python 3.9.lanet_vi.__version__reported4.0.0; it now reads the installed package version (5.0.0) from package metadata, sopyproject.tomlis the single source of truth.
Changed¶
- The degree legend stacks its rows so that a sample never overlaps the previous one
(needed in the
pow/logmodes, whose radii reach a fifth of the unit disc) and keeps the C++ text size instead of growing with the row pitch; unchanged on large classic pictures, where the C++ pitch is the larger. - Layout (#18): the actual LaNet-vi placement is back.
visualization/lanet_layout.pyportskcores_component.cpp/graph_kcores_components.cpp(classic mode): nested components (connected pieces of the inner core, recursively) with their own center, radius and scale (formulas (3)-(5) of NIPS 2005), rings one unit apart with the top core as a disc whose radius follows its log-degrees, node radius from the depth of its higher-index neighbors (formula (1)), angle from the circular average of their angles, top cores split into cliques laid along U-shaped paths in angular sectors, and the--no-cliquessector formula (2). The previous code placed every shell on a fixed 80-unit ring at a random radius and measured neighbor angles from the origin. K-dense and d-core results use the same classic placement, building the component tree with their own edge index (the edge dense index, askdenses_component.cppwalks it); the rest of that file's variant (>=neighbors,tau, sibling circle packing,ratioConstantradii) belongs to the C++pow/logmode, ported afterwards (see "Added" above).epsilon,delta,gamma,unit_length,seed,--no-cliquesand--draw-circlesnow do what the C++ flags did;epsilondefaults to the C++ 0.18 again. The picture is framed as the C++ viewport (1.6 x 1.2 times the network radius), leaving the margin the legends sit in. - Node radii follow the C++
computeHostRatio(0.4 (log(1+d)/log(dmax))^0.7layout units, strength-based for weighted graphs) and are drawn in layout units for graphs of any size (anEllipseCollectionreplaces the point-sized scatter), floored at one pixel so peripheral nodes stay visible.node_size_scaleis a plain multiplier and defaults to 1.0. - CAIDA examples, README and docs now use the 20251001 AS-relationships snapshot (78,370 ASes, 489,407 relationships, k-cores 1-149); example images regenerated.
Infrastructure¶
mainis protected by a GitHub ruleset: changes land through pull requests with green CI and an automatically requested Copilot code review; force-pushes and deletions are blocked.- mypy is now a blocking CI check (
disallow_untyped_defs); the whole package type-checks cleanly. Pydantic models useConfigDictinstead of the deprecated innerConfigclass. - CI split into
lint(ruff check, ruff format, mypy), atestmatrix on Python 3.9–3.13 (Ubuntu) plus macOS 3.12, andbuild(uv build + twine check). Coverage is enforced with a minimum threshold and uploaded as an artifact. - Ruff formatter adopted;
UP(pyupgrade) andB(bugbear) rule sets enabled and the codebase migrated to PEP 585 built-in generics. - pre-commit hooks (ruff lint/format, file hygiene) via
.pre-commit-config.yaml. - Dependabot for GitHub Actions and Python (uv) dependencies.
- PyPI releases use trusted publishing (OIDC) through the
pypienvironment instead of a long-lived API token. - Added
CONTRIBUTING.md,SECURITY.md,CODE_OF_CONDUCT.md,CODEOWNERS, issue and pull request templates, andAGENTS.md(agent/contributor instructions;CLAUDE.mdnow includes it). - New tests for the CLI, rendering pipeline, d-cores, writers and version metadata.
- Python 3.13 added to the supported versions.
5.0.0 - 2025-10-18¶
Overview¶
Note (September 2026): the parity claims in this entry were later found to be overstated. Several features listed as ported are missing, inert or behave differently; see issues #18–#26 for the current state.
Complete Python refactor of LaNet-vi 3.x (C++) with all legacy features included. This version brings all functionality from the latest C++ codebase (previously in legacy/Source/) into a modern Python implementation using NetworkX, pandas, and matplotlib.
Core Features (Ported from C++ LaNet-vi 3.x)¶
- K-core decomposition: Classic k-core algorithm using NetworkX
- K-dense decomposition: Triangle-based decomposition (m-cores)
- D-core decomposition: Directed graphs with (k_in, k_out) pairs per node
- Not a port of
legacy/Source/graph_dcores.cpp, which computed the per-l (k, l)-core table and drew nothing (see--dcore-tableunder Unreleased); the independent in/out cores are the oldergraph_dcores_old.cpp(#21) - CLI:
--directed --decomp dcores - Spiral/semicircular layout: Mathematical spiral placement using Newton-Raphson solver
- Inspired by
legacy/Source/espiral.cpp, which was never linked into a C++ release; the option is accepted but inert (#18) - CLI:
--use-spiral-layout - Community detection: Louvain and greedy modularity algorithms
- A NetworkX-based replacement, not a port: the C++ community code
(
solution_lanci*.cpp,solution_submodular.cpp) was research code never linked into a LaNet-vi binary, and its local-growth and submodular methods are not in Python (#26) - CLI:
--detect-communities - Community visualization: Color-coded nodes with boundary overlays
- Random graph generation: Testing and benchmarking utilities
- Erdős-Rényi, Barabási-Albert, Watts-Strogatz, Powerlaw cluster
- NetworkX wrappers; the C++
erdos_renyi.cppwas a 12-line unlinked G(n, p) loop (#26) - CLI:
lanet-vi generate
New Python-Specific Features¶
- Type-safe configuration: Pydantic models for all settings
- Modern CLI: Typer + Rich with
--double-hyphenflags (Unix/GNU standard) - Comprehensive logging: DEBUG and INFO levels (
--verbose,--quiet,--log-file) - Enhanced JSON export: D3.js-compatible graph exports with full metadata
- Spatial indexing: KD-tree based indexing for O(log N) queries on large graphs
- Information theory metrics: MI, NMI, ARI, VI for partition comparison
- Pandas integration: Efficient data management for large networks
- YAML configuration: Easy-to-edit config files
Architecture Improvements¶
- NetworkX integration: Leverages battle-tested graph algorithms
- Modular design: Clean separation of concerns (io, decomposition, visualization, metrics)
- Better performance: NumPy vectorization, spatial indexing, optimized layouts
- No external renderers: Pure Python/Matplotlib (removed POV-Ray dependency)
- Comprehensive testing: Type checking with mypy, linting with ruff
Dependencies¶
Core libraries:
- networkx>=3.0 - Graph algorithms
- pandas>=2.0 - Data management
- matplotlib>=3.7 - Visualization
- scipy>=1.10 - Spatial indexing, convex hulls
- scikit-learn>=1.3 - Clustering metrics
- pydantic>=2.0 - Configuration validation
- typer>=0.9 + rich>=13.0 - CLI interface
Usage Examples¶
# Basic k-core visualization
lanet-vi visualize --input network.txt --output viz.png
# D-core decomposition on directed networks
lanet-vi visualize --input network.txt --directed --decomp dcores --output dcores.png
# Community detection
lanet-vi visualize --input network.txt --detect-communities --output communities.png
# Spiral layout
lanet-vi visualize --input network.txt --use-spiral-layout --output spiral.png
# Generate random graph for testing
lanet-vi generate --output test.txt --model barabasi-albert --nodes 1000 --edges 3
# Verbose logging
lanet-vi visualize --input network.txt --verbose --log-file debug.log
Migration from C++ LaNet-vi 3.x¶
LaNet-vi 5.x is a complete Python rewrite of the C++ version. Parity was overstated in 5.0.0 and restored piece by piece in 5.1.0 (see the 5.1.0 entry and issues #18–#26):
Key Differences: - Language: C++ → Python 3.10+ - Rendering: POV-Ray / SVG → Matplotlib - Configuration: Custom format → YAML - CLI: Single-hyphen → Double-hyphen flags (Unix/GNU standard) - Dependencies: No external renderers, pure Python stack
Feature Parity (as of 5.2.0):
- ✅ K-core decomposition, including the weighted peeling
- ✅ K-dense (m-core) decomposition (triangle-pair peeling)
- ✅ D-core decomposition (directed graphs), with the (k, l)-core table of the 4.0.0 tool
- ✅ The LaNet-vi placement: classic, pow and log coordinate distributions
- ✅ Color scale, grayscale, legends, edge sampling, -window, -fromlayer, -names
- ✅ K-connectivity (-kconn, -kconntype)
- ✅ SVG and PDF output (matplotlib, by the --output extension; not the C++ SVG writer)
- ⚠️ Community detection: NetworkX Louvain / greedy modularity drawn on the picture; a
5.x addition, the C++ had no community rendering (#26)
- ⚠️ Random graph generation: NetworkX wrappers (#26)
- ❌ Not ported: Gomory-Hu connectivity and POV-Ray scenes (won't-fix, #25). The spiral
layout of the development tree was never in a C++ release and was removed.
- ➕ Enhanced JSON exports
- ➕ Information theory metrics
- ➕ Type-safe configuration