{"id":34619332,"url":"https://github.com/jorgeavilacartes/panricci","last_synced_at":"2026-05-28T04:31:42.056Z","repository":{"id":223771995,"uuid":"654044913","full_name":"jorgeavilacartes/panricci","owner":"jorgeavilacartes","description":"Alignment of Pangenome Graphs with Ricci Flow","archived":false,"fork":false,"pushed_at":"2025-04-02T23:04:23.000Z","size":1278,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T23:24:02.122Z","etag":null,"topics":["pangenome-graph","pangenomics","ricci-curvature","ricci-flow","riemannian-geometry","variation-graphs"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jorgeavilacartes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-15T09:19:00.000Z","updated_at":"2024-09-12T10:08:22.000Z","dependencies_parsed_at":"2024-09-12T19:59:09.591Z","dependency_job_id":"8fc2b6cd-24f1-48ee-86e5-4467f35b4d6b","html_url":"https://github.com/jorgeavilacartes/panricci","commit_stats":null,"previous_names":["jorgeavilacartes/panricci"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jorgeavilacartes/panricci","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgeavilacartes%2Fpanricci","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgeavilacartes%2Fpanricci/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgeavilacartes%2Fpanricci/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgeavilacartes%2Fpanricci/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jorgeavilacartes","download_url":"https://codeload.github.com/jorgeavilacartes/panricci/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgeavilacartes%2Fpanricci/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33594851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pangenome-graph","pangenomics","ricci-curvature","ricci-flow","riemannian-geometry","variation-graphs"],"created_at":"2025-12-24T14:59:21.635Z","updated_at":"2026-05-28T04:31:42.050Z","avatar_url":"https://github.com/jorgeavilacartes.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- ![pantera](images/PANRICCI-removebg-preview.png) --\u003e\n\u003cimg src=\"images/PANRICCI-removebg-preview.png\" width=\"200\" height=\"200\"\u003e\n\n\n# Alignment of Pangenome Graphs with Ricci Flow\n\n## Installation\n```bash\npip install git+https://github.com/jorgeavilacartes/panricci.git\n```\n\nor (recommended for developer) create a conda environment with the library in edition mode\n```bash\ngit clone git@github.com:jorgeavilacartes/panricci.git\ncd panricci\nconda env create -f panricci.yml\nconda activate panricci\n\npanricci --help\n```\n\n`panricci` is a library that deals with pangenome graphs (variation graphs and sequence graphs)\nwith tools from Riemannian Geometry. \n\nA pangenome graph in the `panricci` universe is a manifold $\\mathcal{X}$ provided of a metric $d$ \n(weights of the edges), where nodes encode information in probability distributions over its (1-hop) neighborhood. \n\nThis manifold is evolved over time by using the **Ricci-Flow**, an algorithm that leverages the notion\nof curvature of edges to modify its weights until the curvature is constant (equal to 0).\n\nOnce the graph reach the state of constant curvature, we can use it to perform alignment of two graphs\nby definining coordinates with respect to source and sink nodes in our (directed) pangenome graphs.\n\n**NOTE** Each pangenome graph (input file, and manifold) is assumed to be one single connected component.\n___\n## CLI\n`panricci` works with pangenome graphs (variation graphs or sequence graphs) in `.gfa` format.\n\n```bash\n$ panricci --help\n```\n\nAvailable commands:\n\n| Command | Description |\n|---------|-------------|\n| `ricci-flow` | Apply Ricci Flow to a graph |\n| `ricci-flow2` | Apply Ricci Flow (v2) with configurable step size and minimum weight |\n| `normalized-ricci-flow` | Apply Normalized Ricci Flow with weight rescaling |\n| `align` | Alignment of ricci graphs |\n| `modify-gfa` | Modify a GFA file by removing edges, nodes or paths |\n\n---\n\n### `ricci-flow`\n\nApply the discrete Ricci-Flow algorithm to evolve the metric of a pangenome graph.\n\n```bash\n$ panricci ricci-flow \\\n\t--gfa data/test5.gfa \\\n\t--iterations 1000 \\\n\t--tol-curvature 1e-15 \\\n\t--outdir output/test5\n```\n\n| Option | Short | Description | Default |\n|--------|-------|-------------|---------|\n| `--gfa` | `-g` | Path to the GFA file | *required* |\n| `--iterations` | `-i` | Maximum number of iterations | *required* |\n| `--outdir` | `-o` | Output directory | `output-ricci-flow/ricci-graph` |\n| `--tol-curvature` | `-t` | Tolerance for curvature convergence | `1e-11` |\n| `--sequence-graph` | `-s` | Use sequence graph node distributions (instead of variation graph) | `False` |\n| `--log-level` | `-l` | Log level | `INFO` |\n| `--save-intermediate-graphs` | `-si` | Save graphs at each iteration | `False` |\n| `--undirected` | `-u` | Load GFA as undirected graph | `False` |\n\n- The algorithm runs for at most `--iterations` iterations, or until all curvatures are smaller than `--tol-curvature` (the goal is to stop when all curvatures are 0).\n- The `--undirected` option allows the computation of the Wasserstein distance over the local subgraph avoiding directions, which is needed to keep the Wasserstein distance as a metric.\n- By default node distributions are defined for a variation graph (paths are considered). If you have a sequence graph where paths are not part of the `.gfa` file, use `--sequence-graph`.\n\n---\n\n### `ricci-flow2`\n\nAn alternative Ricci Flow implementation with configurable step size and minimum edge weight.\n\n```bash\n$ panricci ricci-flow2 \\\n\t--gfa data/test5.gfa \\\n\t--iterations 1000 \\\n\t--eps 0.1 \\\n\t--min-weight 0.000001 \\\n\t--outdir output/test5\n```\n\n| Option | Short | Description | Default |\n|--------|-------|-------------|---------|\n| `--gfa` | `-g` | Path to the GFA file | *required* |\n| `--iterations` | `-i` | Maximum number of iterations | *required* |\n| `--outdir` | `-o` | Output directory | `output-ricci-flow/ricci-graph` |\n| `--tol-curvature` | `-t` | Tolerance for curvature convergence | `1e-11` |\n| `--sequence-graph` | `-s` | Use sequence graph node distributions | `False` |\n| `--log-level` | `-l` | Log level (`INFO`/`DEBUG`) | `INFO` |\n| `--undirected` | `-u` | Load GFA as undirected graph | `False` |\n| `--eps` | | Step size for curvature to update weights | `0.1` |\n| `--min-weight` | | Minimum weight for an edge (prevents weights going to zero) | `0.000001` |\n\n---\n\n### `normalized-ricci-flow`\n\nApply Normalized Ricci Flow, which rescales weights after each iteration to maintain a constant total weight.\n\n```bash\n$ panricci normalized-ricci-flow \\\n\t--gfa data/test5.gfa \\\n\t--iterations 1000 \\\n\t--sigma 5 \\\n\t--eps 0.1 \\\n\t--outdir output/test5\n```\n\n| Option | Short | Description | Default |\n|--------|-------|-------------|---------|\n| `--gfa` | `-g` | Path to the GFA file | *required* |\n| `--iterations` | `-i` | Maximum number of iterations | *required* |\n| `--sigma` | | Target sum of weights after each iteration | `5` |\n| `--outdir` | `-o` | Output directory | `output-ricci-flow/ricci-graph` |\n| `--tol-curvature` | `-t` | Tolerance for curvature convergence | `1e-11` |\n| `--sequence-graph` | `-s` | Use sequence graph node distributions | `False` |\n| `--log-level` | `-l` | Log level (`INFO`/`DEBUG`) | `INFO` |\n| `--undirected` | `-u` | Load GFA as undirected graph | `False` |\n| `--eps` | | Step size for curvature to update weights | `0.1` |\n| `--min-weight` | | Minimum weight for an edge | `0.000001` |\n\n---\n\n### `align`\n\nAlign two ricci graphs by finding a mapping between their nodes based on relative node representations.\n\n```bash\n$ panricci align \\\n\t--ricci-graph1 output/test5/test5-ricciflow-52.edgelist \\\n\t--ricci-graph2 output/test5/test5-ricciflow-52.edgelist \\\n\t--path-save output/alignment.tsv\n```\n\n| Option | Short | Description | Default |\n|--------|-------|-------------|---------|\n| `--ricci-graph1` | `-r1` | Path to the first Ricci graph file | *required* |\n| `--ricci-graph2` | `-r2` | Path to the second Ricci graph file | *required* |\n| `--path-save` | `-p` | Path to save alignment results | `output-ricci-flow/align/ricci1-ricci2.tsv` |\n| `--weight-node-labels` | `-w` | Weight for node labels in the cost function (0-0.99). If \u003e 0, `--gfa1` and `--gfa2` must be provided | `0.0` |\n| `--gfa1` | `-g1` | Path to the first GFA file (for node metadata) | `None` |\n| `--gfa2` | `-g2` | Path to the second GFA file (for node metadata) | `None` |\n| `--log-level` | `-l` | Log level | `INFO` |\n| `--store-bipartite` | `-sb` | Store the bipartite graph used for alignment | `False` |\n\nThe output is a TSV file with the following columns:\n\n- `node1`: the identifier of the node in ricci graph 1\n- `node2`: the identifier of the node in ricci graph 2\n- `edge`: tuples of strings of the form `\u003cnode_id\u003e-\u003cgraph_id\u003e`\n- `cost_alignment`: the cost of aligning `node1` and `node2` (euclidean distance between their relative node representations)\n\nExample output:\n\n```\n \t edge          \t cost_alignment\t node1\t node2\n0\t ['4-1', '4-2']\t            0.0\t     4\t     4\n1\t ['3-1', '3-2']\t            0.0\t     3\t     3\n2\t ['2-1', '2-2']\t            0.0\t     2\t     2\n3\t ['1-1', '1-2']\t            0.0\t     1\t     1\n```\n\nTo include node metadata (label and node depth), provide the original `.gfa` files:\n\n```bash\n$ panricci align \\\n\t--ricci-graph1 output/test5/test5-ricciflow-52.edgelist \\\n\t--ricci-graph2 output/test5/test5-ricciflow-52.edgelist \\\n\t--path-save output/alignment.tsv \\\n\t--gfa1 data/test5.gfa \\\n\t--gfa2 data/test5.gfa\n```\n\nTo penalize alignment of nodes with different labels, use `--weight-node-labels`:\n\n```bash\n$ panricci align \\\n\t--ricci-graph1 output/test5/test5-ricciflow-52.edgelist \\\n\t--ricci-graph2 output/test5/test5-ricciflow-52.edgelist \\\n\t--path-save output/alignment.tsv \\\n\t--weight-node-labels 0.5 \\\n\t--gfa1 data/test5.gfa \\\n\t--gfa2 data/test5.gfa\n```\n\n---\n\n### `modify-gfa`\n\nModify a GFA file by removing edges, nodes, or paths. When removing edges, the adjacent nodes are collapsed into a single node with concatenated sequences by default. When removing nodes, predecessors and successors are reconnected by default.\n\n```bash\n$ panricci modify-gfa \\\n\t--gfa data/test5.gfa \\\n\t--outdir output/modified \\\n\t--remove-nodes \"6,7\"\n```\n\n| Option | Short | Description | Default |\n|--------|-------|-------------|---------|\n| `--gfa` | `-g` | Path to the GFA file | *required* |\n| `--outdir` | `-o` | Output directory for the modified GFA file | `output-ricci-flow/modified-gfa` |\n| `--remove-edges` | | Comma-separated edges to remove (format: `node1-node2`) | `None` |\n| `--remove-nodes` | | Comma-separated nodes to remove | `None` |\n| `--remove-paths` | | Comma-separated paths to remove | `None` |\n| `--no-collapse` | | Do not collapse adjacent nodes when removing edges | `False` |\n| `--no-reconnect` | | Do not reconnect predecessors to successors when removing nodes | `False` |\n| `--remove-unused-nodes` | | Remove nodes not used by any remaining path after path removal | `False` |\n\n#### Examples\n\nRemove edges (collapses nodes by default):\n```bash\n$ panricci modify-gfa --gfa input.gfa --remove-edges \"4-5,10-11\"\n```\n\nRemove edges without collapsing:\n```bash\n$ panricci modify-gfa --gfa input.gfa --remove-edges \"4-5\" --no-collapse\n```\n\nRemove nodes (reconnects predecessors to successors):\n```bash\n$ panricci modify-gfa --gfa input.gfa --remove-nodes \"6,7,8\"\n```\n\nRemove paths and clean up unused nodes:\n```bash\n$ panricci modify-gfa --gfa input.gfa --remove-paths \"seq1,seq2\" --remove-unused-nodes\n```\n\nThe modified GFA file is saved as `\u003coriginal_name\u003e_modified.gfa` in the output directory.\n\n\n## Python API\n\n#### 1. Create ricci-graphs\n```python\nfrom panricci.ricci_flow import RicciFlow\nfrom panricci.utils import GFALoader\nfrom panricci.node_distributions.variation_graph import DistributionNodes\n\n# load variation graph\ngfa_loader = GFALoader(undirected=False)\nG = gfa_loader(gfa)\n\n# compute distribution for each node of the graph\ndistribution_nodes = DistributionNodes(G, alpha=0.5)\n\n# Initialize Ricci-Flow\nricci_flow = RicciFlow(G, \n\tdistribution=distribution_nodes, # the distribution over the 1-hop neighborhood for each node in the graph\n\tsave_last=False,                 # will overwrite the results in each iteration to keep the last one: outfile will be \"{name}-ricciflow-{it}.edgelist\"\n\tsave_intermediate_graphs=True,   # will save results for all iteration: outfile will be \"{name}-ricciflow.edgelist\"\n\tdirsave_graphs=\"outdir\",         # directory to save results\n\ttol_curvature=1e-15,             # tolerance of minimum curvature to stop Ricci-Flow\n\toverwrite=False,                 # If the dirsave_graphs directory exists, it will raise an Exception\n\t)\n\n# apply Ricci-Flow\nG_ricci = ricci_flow.run(\n\titerations=1000,       # maximum number of iterations to run Ricci-Flow  \n\tname=\"id-graph\"        # some identifier to store results\n\t)\n``` \n\n#### 2. Align ricci-graphs\n\n```python\nfrom pathlib import Path\nimport networkx as nx\n\nfrom panricci.utils import GFALoader\nfrom panricci.alignment import GraphAlignment, parse_alignment\n\ndirsave=Path(path_save)\ndirsave.parent.mkdir(exist_ok=True, parents=True)\n\n# initialize aligner\naligner = GraphAlignment(\n\tricci_embedding = True, \n\tweight_node_labels = 0.5,    # set to 0 if you only want to consider embedding cost\n\tpath_save_bipartite = \"bipartite-graph.edgelist\", # store bipartite graph used for alignment\n\t) \n\n# load ricci graphs\ng1 = nx.read_edgelist(ricci_graph1, data=True, create_using=nx.DiGraph)    \ng2 = nx.read_edgelist(ricci_graph2, data=True, create_using=nx.DiGraph)\n\ngfa_loader = GFALoader(undirected=False)\ngraph1 = gfa_loader(gfa1)\nfor edge, d in g1.edges.items():\n\tgraph1.edges[edge][\"weight\"] = d[\"weight\"]\n\tgraph1.edges[edge][\"curvature\"] = d[\"curvature\"]\n\ngraph2 = gfa_loader(gfa2)\nfor edge, d in g2.edges.items():\n\tgraph2.edges[edge][\"weight\"] = d[\"weight\"]\n\tgraph2.edges[edge][\"curvature\"] = d[\"curvature\"]\n\nalignment = aligner(g1, g2, name=\"alignment\") \ndf_alignment = parse_alignment(alignment, graph1, graph2)\ndf_aligment.to_csv(\"alignment.tsv\", sep=\"\\t\")\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgeavilacartes%2Fpanricci","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjorgeavilacartes%2Fpanricci","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgeavilacartes%2Fpanricci/lists"}