girafi 0.1.0rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. girafi-0.1.0rc1/AUTHORS.md +11 -0
  2. girafi-0.1.0rc1/CHANGELOG.md +10 -0
  3. girafi-0.1.0rc1/CITATION.cff +37 -0
  4. girafi-0.1.0rc1/IMPORT_PROVENANCE.json +78 -0
  5. girafi-0.1.0rc1/LICENSE +22 -0
  6. girafi-0.1.0rc1/MANIFEST.in +7 -0
  7. girafi-0.1.0rc1/PKG-INFO +93 -0
  8. girafi-0.1.0rc1/README.md +98 -0
  9. girafi-0.1.0rc1/README.pypi.md +59 -0
  10. girafi-0.1.0rc1/configs/biology.yaml +17 -0
  11. girafi-0.1.0rc1/configs/nested.yaml +19 -0
  12. girafi-0.1.0rc1/docs/CONFIGURATION.md +53 -0
  13. girafi-0.1.0rc1/docs/METHODS.md +49 -0
  14. girafi-0.1.0rc1/docs/RELEASE.md +20 -0
  15. girafi-0.1.0rc1/docs/VALIDATION.md +41 -0
  16. girafi-0.1.0rc1/docs/assets/README.md +13 -0
  17. girafi-0.1.0rc1/docs/assets/girafi-overview.png +0 -0
  18. girafi-0.1.0rc1/examples/expression.csv +49 -0
  19. girafi-0.1.0rc1/examples/generate.py +29 -0
  20. girafi-0.1.0rc1/examples/ppi.tsv +25 -0
  21. girafi-0.1.0rc1/pyproject.toml +66 -0
  22. girafi-0.1.0rc1/scripts/check_wheel.py +71 -0
  23. girafi-0.1.0rc1/scripts/generate_reference.py +75 -0
  24. girafi-0.1.0rc1/setup.cfg +4 -0
  25. girafi-0.1.0rc1/src/girafi/__init__.py +20 -0
  26. girafi-0.1.0rc1/src/girafi/__main__.py +3 -0
  27. girafi-0.1.0rc1/src/girafi/cli.py +62 -0
  28. girafi-0.1.0rc1/src/girafi/config.py +194 -0
  29. girafi-0.1.0rc1/src/girafi/core.py +200 -0
  30. girafi-0.1.0rc1/src/girafi/data.py +95 -0
  31. girafi-0.1.0rc1/src/girafi/pipeline.py +139 -0
  32. girafi-0.1.0rc1/src/girafi/provenance.json +45 -0
  33. girafi-0.1.0rc1/src/girafi/result.py +82 -0
  34. girafi-0.1.0rc1/src/girafi/validation.py +121 -0
  35. girafi-0.1.0rc1/src/girafi.egg-info/PKG-INFO +93 -0
  36. girafi-0.1.0rc1/src/girafi.egg-info/SOURCES.txt +47 -0
  37. girafi-0.1.0rc1/src/girafi.egg-info/dependency_links.txt +1 -0
  38. girafi-0.1.0rc1/src/girafi.egg-info/entry_points.txt +2 -0
  39. girafi-0.1.0rc1/src/girafi.egg-info/requires.txt +11 -0
  40. girafi-0.1.0rc1/src/girafi.egg-info/top_level.txt +1 -0
  41. girafi-0.1.0rc1/tests/conftest.py +36 -0
  42. girafi-0.1.0rc1/tests/data/ppi_reference.json +45 -0
  43. girafi-0.1.0rc1/tests/data/ppi_reference.npz +0 -0
  44. girafi-0.1.0rc1/tests/reference/README.md +7 -0
  45. girafi-0.1.0rc1/tests/reference/ppi_engine.py +345 -0
  46. girafi-0.1.0rc1/tests/test_cli.py +41 -0
  47. girafi-0.1.0rc1/tests/test_contracts.py +123 -0
  48. girafi-0.1.0rc1/tests/test_reference.py +41 -0
  49. girafi-0.1.0rc1/tests/test_workflows.py +104 -0
@@ -0,0 +1,11 @@
1
+ # Authors and attribution
2
+
3
+ The **GIRAFI method and research** are credited to **Huan Zhong and the GIRAFI research collaborators**, as documented in the manuscript cited below.
4
+
5
+ **Existing implementation attribution** includes **Ziming Wang and the GIRAFI contributors**. The original Python packaging metadata names Ziming Wang; the implementation source hashes and existing credits are retained in `src/girafi/provenance.json`.
6
+
7
+ **Junseo Park** is the **Python package maintainer and distribution contact**. This role concerns package maintenance and release distribution; it does not identify Junseo Park as the originator of the GIRAFI method.
8
+
9
+ The software is distributed under the **MIT License**. Existing copyright and permission notices are retained in `LICENSE`.
10
+
11
+ Please cite **Zhong, H., Chi, S., et al. Recovering biological structure in sparse single-cell proteomics with GIRAFI. bioRxiv (2026). https://doi.org/10.64898/2026.05.18.726081** and record the software version used. The manuscript author list is retained in `CITATION.cff`.
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0rc1
4
+
5
+ - Credit Huan Zhong and the GIRAFI research collaborators explicitly, retain existing implementation attribution, and identify Junseo Park as the package maintainer.
6
+ - Add a self-contained PyPI description and include attribution in source and wheel distributions.
7
+ - Unified Local and Neighbor learners with count-weighted empirical/PPI graphs.
8
+ - Added dataset-level (`biology`) and nested entry-masking (`nested`) workflows.
9
+ - Added validation-only variant selection, explicit configuration, Python API, CLI, and run artifacts.
10
+ - Added synthetic reference fixtures, leakage checks, and installed-package verification.
@@ -0,0 +1,37 @@
1
+ cff-version: 1.2.0
2
+ message: "Please cite the GIRAFI manuscript and identify the software version used."
3
+ type: software
4
+ title: "GIRAFI: Graph-informed random-forest imputation"
5
+ version: 0.1.0rc1
6
+ repository-code: "https://github.com/dorothyzh/GIRAFI/tree/package"
7
+ license: MIT
8
+ authors:
9
+ - family-names: Zhong
10
+ given-names: Huan
11
+ - family-names: Wang
12
+ given-names: Ziming
13
+ - name: GIRAFI contributors
14
+ preferred-citation:
15
+ type: article
16
+ title: "Recovering biological structure in sparse single-cell proteomics with GIRAFI"
17
+ doi: "10.64898/2026.05.18.726081"
18
+ journal: bioRxiv
19
+ year: 2026
20
+ authors:
21
+ - {family-names: Zhong, given-names: Huan}
22
+ - {family-names: Chi, given-names: Shuxin}
23
+ - {family-names: Wong, given-names: Rachel}
24
+ - {family-names: Rogalski, given-names: Jason}
25
+ - {family-names: Wang, given-names: Ziming}
26
+ - {family-names: Chan, given-names: Susanna}
27
+ - {family-names: Bailey, given-names: Melanie L.}
28
+ - {family-names: Ebrahimi, given-names: Arpa}
29
+ - {family-names: Jayme, given-names: Gabrielle}
30
+ - {family-names: Yin, given-names: Jerry}
31
+ - {family-names: Gong, given-names: Albie}
32
+ - {family-names: Zhong, given-names: Peipei}
33
+ - {family-names: Snutch, given-names: Terrance P.}
34
+ - {family-names: Maier, given-names: Claudia S.}
35
+ - {family-names: Marra, given-names: Marco A.}
36
+ - {family-names: Foster, given-names: Leonard J.}
37
+ - {family-names: Tang, given-names: Xin}
@@ -0,0 +1,78 @@
1
+ {
2
+ "source_repository": "https://github.com/junseoparkX/girafi-package",
3
+ "source_commit": "e2f4055bd6b662f14c1a0658e29aed69bec0e989",
4
+ "destination": "https://github.com/dorothyzh/GIRAFI/tree/package",
5
+ "method_sources_unchanged": true,
6
+ "adaptations": [
7
+ "README paths and figure",
8
+ "repository and citation URLs",
9
+ "root workflows with package working directory",
10
+ "release instructions",
11
+ "synthetic fixture ignore exceptions",
12
+ "include overview figure in source distribution",
13
+ "installable source at package branch root; branch-specific documentation and workflows",
14
+ "workflow overview rendered from the original manuscript drawing with recorded crop and export settings"
15
+ ],
16
+ "source_file_sha256": {
17
+ ".gitattributes": "401203af7ba8102643f21ddcaefeb3ff49c3afbb891a8ee4325f8f4b18ebfa09",
18
+ ".github/workflows/ci.yml": "6c6f269efb9bff7ee23de691108440f4ef517b7619d24f7950eaf0afee98e14d",
19
+ ".github/workflows/release.yml": "7c5b00d6f4d5ee8ac63d37d7cf100cde5da95136597aba5b232687949cac1576",
20
+ ".gitignore": "100c0b804cc90b86c1225d6e4515f438759c13e7f63dff39062ac98aca70c15b",
21
+ "CHANGELOG.md": "d3f2b1fe12131c00a2b203ff256415b57745d703e4ff24e33501092a606fbd14",
22
+ "CITATION.cff": "023a545a238de6490cb442aef41004cc968f9b4569d094dcf755b7ae995e3e77",
23
+ "LICENSE": "c55118c93f5e2423040d3282533ac62d9e262d0317f9da4e844ed565b954c221",
24
+ "MANIFEST.in": "aebe7e74251087835de5aecc809b7068ae7787ffc8aebc1a735dbb22d62f46e7",
25
+ "README.md": "4f413e80c99dc5dbe1469dc2252313813e8a9c5d797dfec52f9db1f5a8c2a8e4",
26
+ "configs/biology.yaml": "a4578d844be8297af268b85a1b78c49720c8962512ba796264783b8a6165ba7b",
27
+ "configs/nested.yaml": "d4115dad828797b38763c58305211a35d290183e6c87eadce66a7df7ae756138",
28
+ "docs/CONFIGURATION.md": "156e790091a0d264dec211a49ddf1a24c98e0c83ed86c112fe9b1a147dff5de7",
29
+ "docs/METHODS.md": "a030474a40696a10784680cb7b9fad118b5cbf88234e32dca50308f5e85ca371",
30
+ "docs/RELEASE.md": "563c9e0a36d6f59205b4610a6180b831c21b71eb9c911d610cd52fbef31eb398",
31
+ "docs/VALIDATION.md": "edcd964085005cdf83f881cc3df0b12e06ba0ddae533e492109ab4293373500b",
32
+ "examples/expression.csv": "bd4c044ca14fe97010e3eb9af79fb3b6e55dccb1ae735667e3edb4b793358c2e",
33
+ "examples/generate.py": "f266917c9ce291efa7b8caa2b4b7e785cab64895c3b83907e360fb1ef5fdd8b9",
34
+ "examples/ppi.tsv": "8c4cfccd8c3afb2c1e9be5155c783a610c0ebccd5e2654cf39c1f07e4bf91942",
35
+ "pyproject.toml": "3ec33fd3f670e4898e085d6ab2b7c801f341ab0f76d7f36172b969b378c653e6",
36
+ "scripts/check_wheel.py": "778119bb4950f3c349217f4872aa095e608be30cb54ee10a361a820a71e2296c",
37
+ "scripts/generate_reference.py": "d80152bffe8d28835de37ce2ec2537c9bb1fc4d0305732e2461be7f976ec82df",
38
+ "src/girafi/__init__.py": "e8e3078c47a4fd230a8dad03191922711a5ccb4f196523e92234af9e317e557f",
39
+ "src/girafi/__main__.py": "935a1c1166b0c1ea35a82256345000bf2c73ded718d77773bc27a71ecce28f7d",
40
+ "src/girafi/cli.py": "30742f1b6a73a05938fa6450bf14ee4019e03e787c3e668357281b6850e73606",
41
+ "src/girafi/config.py": "f3d27c7fa74ea339d28fec1e6753fe0d646516c5d2464dc26424b4407d037d93",
42
+ "src/girafi/core.py": "c43d878c1cb4790263497485e9ccbe28c96eb5b3ed8ac3461801b3feaf00fe5e",
43
+ "src/girafi/data.py": "55289bdadd41ae95846bb172a7860cad8bd25a577c6b696647263a479c89280d",
44
+ "src/girafi/pipeline.py": "100eda29d6bff70781901550b2b71441b55023292720cd0f0c0bd8956d92a77e",
45
+ "src/girafi/provenance.json": "5e51ccd62e764614aafeb51d04da69f1773cbf4b5a3cea2976824df9997add6f",
46
+ "src/girafi/result.py": "a57d006b899c7c54d57085066842c7dbd5965cc7045eeaada444564ebcaaa586",
47
+ "src/girafi/validation.py": "00caa00dff516a2e71677076d1267a0492e37d1fb36be2bdc0788d62f25d3ffc",
48
+ "tests/conftest.py": "b7e789c773a41a66f9f58080d2e496fdf32196b4c7af6c92a26c506a6870e4a3",
49
+ "tests/data/ppi_reference.json": "4a8f629c71ee873c2700f0f1a2b53091e81af9dc3409c3febe54752ffc855fbe",
50
+ "tests/data/ppi_reference.npz": "338c1e031b578b6d1571db0a3fe44804469c392ca435382fd20b82e5222da508",
51
+ "tests/reference/README.md": "103100d7e8af981fc47f2cd05621d59f45db1e339395c7bfd46522b3cf415917",
52
+ "tests/reference/ppi_engine.py": "318f84fe7047d959ba8ee5fab3dba831a0a81f025be8a2266ea9ff3ffb745a81",
53
+ "tests/test_cli.py": "f1614ca52583a0e7bb24119770b4d2d0a6b7ed08b870a0721c887979d9cd85a2",
54
+ "tests/test_contracts.py": "d4af3d47d1a340af6f2db33ca79a87245049b5aa5df0cf1244324703e7809595",
55
+ "tests/test_reference.py": "4014265fad1e0394f85cb9ce9e745fc3e0cbe6b7827e67d7b10d375fc78dce50",
56
+ "tests/test_workflows.py": "25c2318ccbd34c486a5e7d38e522fb6aaaf563f828a2c6457786c8b10fb0f50a"
57
+ },
58
+ "initial_import_destination": "https://github.com/dorothyzh/GIRAFI/tree/master/package",
59
+ "branch_split_parent": "3a124a668e6822a04cb7518382b77780baa3a156",
60
+ "overview_figure": {
61
+ "path": "docs/assets/girafi-overview.png",
62
+ "source_name": "figure.pdf",
63
+ "source_sha256": "640daad2dd77967b885ad4656376e15ecacbc6662df84abf6bc4dc46d5003faf",
64
+ "crop_box_points": [
65
+ 0.0,
66
+ 303.765,
67
+ 482.111,
68
+ 623.986
69
+ ],
70
+ "png_dimensions": [
71
+ 4018,
72
+ 2669
73
+ ],
74
+ "png_dpi": 600,
75
+ "png_sha256": "ad86636d79a7b6f6b83e780adef1f3a1e6910d22fa66c67b7ac5323c22ba88ef",
76
+ "content_changes": "None; crop and raster export only"
77
+ }
78
+ }
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 GIRAFI contributors
4
+ Copyright (c) 2026 GIRAFI package contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md README.pypi.md AUTHORS.md LICENSE CITATION.cff CHANGELOG.md
2
+ include IMPORT_PROVENANCE.json
3
+ recursive-include configs *.yaml
4
+ recursive-include docs *.md *.png
5
+ recursive-include examples *.py *.csv *.tsv
6
+ recursive-include scripts *.py
7
+ recursive-include tests *.py *.md *.json *.npz
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: girafi
3
+ Version: 0.1.0rc1
4
+ Summary: Graph-informed random-forest imputation for single-cell proteomics
5
+ Author: Huan Zhong, Ziming Wang, GIRAFI contributors
6
+ Maintainer: Junseo Park
7
+ License-Expression: MIT
8
+ Project-URL: Repository, https://github.com/dorothyzh/GIRAFI/tree/package
9
+ Project-URL: Documentation, https://github.com/dorothyzh/GIRAFI/blob/package/README.md
10
+ Project-URL: Issues, https://github.com/dorothyzh/GIRAFI/issues
11
+ Project-URL: Manuscript, https://doi.org/10.64898/2026.05.18.726081
12
+ Keywords: proteomics,imputation,random-forest,protein-interactions
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy<3,>=1.26
24
+ Requires-Dist: pandas<4,>=2.2
25
+ Requires-Dist: scipy<2,>=1.12
26
+ Requires-Dist: scikit-learn<2,>=1.8
27
+ Requires-Dist: PyYAML<7,>=6
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8; extra == "dev"
30
+ Requires-Dist: build>=1.2; extra == "dev"
31
+ Requires-Dist: twine>=6; extra == "dev"
32
+ Requires-Dist: ruff>=0.11; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # GIRAFI
36
+
37
+ **Graph-informed random-forest imputation for single-cell proteomics**
38
+
39
+ The **GIRAFI method and research** are credited to **Huan Zhong and the GIRAFI research collaborators**. Existing implementation credits include **Ziming Wang and the GIRAFI contributors**. **Junseo Park** maintains the Python package and its distribution.
40
+
41
+ GIRAFI estimates missing protein abundances using empirical protein associations and an optional curated protein interaction prior. Protein-specific random forests use graph-restricted predictors, and graph polishing updates only missing entries. Measured values are preserved.
42
+
43
+ The package provides Local and Neighbor variants, validation-based selection for dataset completion, and nested masking for reconstruction evaluation.
44
+
45
+ ## Installation
46
+
47
+ Python 3.11 or later is required. The initial distribution is a release candidate:
48
+
49
+ ```bash
50
+ python -m pip install "girafi==0.1.0rc1"
51
+ girafi --help
52
+ ```
53
+
54
+ ## Python example
55
+
56
+ Use a CSV matrix with cells in rows, proteins in columns, and cell IDs in the first column. Empty fields and `NaN` represent missing values; zero is an observed value. This example assumes linear intensities and explicitly disables the PPI prior:
57
+
58
+ ```python
59
+ import pandas as pd
60
+ from girafi import GIRAFIConfig, GIRAFIPipeline
61
+
62
+ X = pd.read_csv("expression.csv", index_col=0)
63
+ config = GIRAFIConfig.from_dict({
64
+ "workflow": "biology",
65
+ "input_scale": "linear",
66
+ "graph": {"ppi_weight": 0.0},
67
+ })
68
+ result = GIRAFIPipeline(config).run(X)
69
+ result.save("runs/my-analysis")
70
+ ```
71
+
72
+ For log2-transformed input, set `input_scale` to `log2`. To use a PPI prior, provide a table with `source`, `target`, and optional `weight` columns with matching protein identifiers, set `graph.ppi_weight` explicitly, and pass the table to `run(X, ppi=ppi)`.
73
+
74
+ ## Workflows and command line
75
+
76
+ - `biology` selects a variant using validation masks and then completes the supplied matrix.
77
+ - `nested` selects variants within inner validation masks and evaluates reconstruction on held-out outer entries.
78
+
79
+ ```bash
80
+ girafi run --config config.yaml --matrix expression.csv --out runs/my-analysis
81
+ ```
82
+
83
+ Configurations accept YAML or JSON. Results include resolved settings, selection records, masks, input hashes, and software versions. The source distribution includes the Methods, Configuration, and Validation guides, synthetic examples, and tests. Repository documentation is available on the [GIRAFI package branch](https://github.com/dorothyzh/GIRAFI/tree/package), subject to repository access.
84
+
85
+ Reconstruction scores on artificially withheld observations do not establish accuracy at naturally missing entries. Nested entry masking evaluates reconstruction within the supplied cells, rather than prediction for unseen cells. Validation scores from `biology` are not independent test estimates.
86
+
87
+ ## Citation and license
88
+
89
+ Zhong, H., Chi, S., et al. *Recovering biological structure in sparse single-cell proteomics with GIRAFI*. bioRxiv (2026). [doi:10.64898/2026.05.18.726081](https://doi.org/10.64898/2026.05.18.726081).
90
+
91
+ Please cite the manuscript and report the GIRAFI software version. Publication through a package maintainer's account does not change the method or manuscript authorship. Original implementation attribution is retained in the packaged `girafi/provenance.json`. The source distribution includes `AUTHORS.md` and `CITATION.cff`.
92
+
93
+ MIT License. Existing copyright and permission notices are retained in the distribution.
@@ -0,0 +1,98 @@
1
+ # GIRAFI
2
+
3
+ [![Python 3.11 | 3.12 | 3.13](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-007EC6)](docs/VALIDATION.md)
4
+ [![CI](https://github.com/dorothyzh/GIRAFI/actions/workflows/package-ci.yml/badge.svg?branch=package&event=push)](https://github.com/dorothyzh/GIRAFI/actions/workflows/package-ci.yml?query=branch%3Apackage)
5
+
6
+ **Graph-informed random-forest imputation for single-cell proteomics**
7
+
8
+ The GIRAFI method and research are credited to **Huan Zhong and the GIRAFI research collaborators**. Existing implementation credits include **Ziming Wang and the GIRAFI contributors**. **Junseo Park** maintains the Python package and its distribution. See [Authors and attribution](AUTHORS.md) and cite the manuscript below.
9
+
10
+ GIRAFI estimates missing protein abundances by combining empirical protein associations with a curated protein interaction prior. Protein-specific random forests learn from observed intensities using graph-restricted predictors; a graph-polishing step updates only missing entries. Measured values are preserved.
11
+
12
+ ![GIRAFI overview: protein association and interaction graphs inform imputation and downstream analyses.](docs/assets/girafi-overview.png)
13
+
14
+ *GIRAFI overview. Empirical protein associations and a protein interaction prior inform imputation for downstream analyses.*
15
+
16
+ This package provides the **Local** and **Neighbor** variants through a common implementation, with validation-based selection for dataset completion and nested masking for reconstruction evaluation.
17
+
18
+ This is the **package** branch. Manuscript experiments, benchmarks, and figure reproduction are maintained on the [reproducibility branch](https://github.com/dorothyzh/GIRAFI/tree/reproducibility).
19
+
20
+ ## Method
21
+
22
+ The empirical graph uses positive Spearman correlations, weighted by shared observation counts and restricted to the strongest neighbors. Row normalization gives $W^{(\mathrm{corr})}$. Following the manuscript notation, a weighted PPI adjacency $A^{(\mathrm{ppi})}$ is symmetrically degree-normalized as $W^{(\mathrm{ppi})} = D^{-1/2} A^{(\mathrm{ppi})} D^{-1/2}$, where $D$ is its diagonal degree matrix. The graphs are fused using the PPI weight $\lambda$:
23
+
24
+ $$
25
+ W = \lambda W^{(\mathrm{ppi})} + (1-\lambda) W^{(\mathrm{corr})}.
26
+ $$
27
+
28
+ The fused graph is then row-normalized, with self-loops excluded.
29
+
30
+ - **Local** predicts a target from the weighted mean and standard deviation of its observed neighbors.
31
+ - **Neighbor** predicts a target directly from neighboring protein abundances.
32
+
33
+ The PPI weight and other model parameters are explicit settings. Automatic selection compares Local and Neighbor using masked-entry reconstruction error; downstream biological outcomes are not selection inputs. See [Methods](docs/METHODS.md) for the exact graph, support, and scoring definitions.
34
+
35
+ ## Installation
36
+
37
+ Python 3.11 or later is required. [Compatibility checks](docs/VALIDATION.md) passed on Python 3.11, 3.12, and 3.13; the CI matrix includes these versions on Linux, Windows, and macOS. Install the `package` branch from this repository:
38
+
39
+ ```bash
40
+ git clone --branch package --single-branch https://github.com/dorothyzh/GIRAFI.git
41
+ cd GIRAFI
42
+ python -m pip install .
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ Expression data have **cells in rows and proteins in columns**, with cell IDs in the first CSV column and missing values represented by empty fields or `NaN`. PPI tables contain `source`, `target`, and an optional `weight` column using the same protein identifiers. Zero is treated as an observed value.
48
+
49
+ Run the examples below from the cloned repository root. The supplied configurations expect linear intensities (`input_scale: linear`); for data already on the log2 scale, set `input_scale: log2`. See [input and transformation](docs/METHODS.md#input-and-transformation) for preprocessing details.
50
+
51
+ ```python
52
+ import pandas as pd
53
+ from girafi import GIRAFIConfig, GIRAFIPipeline
54
+
55
+ X = pd.read_csv("examples/expression.csv", index_col=0)
56
+ ppi = pd.read_csv("examples/ppi.tsv", sep="\t")
57
+ config = GIRAFIConfig.from_yaml("configs/biology.yaml")
58
+
59
+ result = GIRAFIPipeline(config).run(X, ppi=ppi)
60
+ result.save("runs/python-example")
61
+ ```
62
+
63
+ The supplied example is synthetic. Both workflows are also available from the command line:
64
+
65
+ ```bash
66
+ girafi run --config configs/biology.yaml --matrix examples/expression.csv --ppi examples/ppi.tsv --out runs/biology
67
+ girafi run --config configs/nested.yaml --matrix examples/expression.csv --ppi examples/ppi.tsv --out runs/nested
68
+ ```
69
+
70
+ ## Selection workflows
71
+
72
+ | Workflow | Variant selection | Output |
73
+ | :--- | :--- | :--- |
74
+ | **`biology`** | Select once using mean NRMSE across repeated validation masks, then refit on the full input. | One completed matrix and its selection record. |
75
+ | **`nested`** | Select by inner validation within each outer masking repeat, then refit and evaluate on held-out outer entries. | Outer reconstruction scores and a selection record for each repeat. |
76
+
77
+ Set `variant` to `auto`, `local`, or `neighbor`. The example configurations use 100 trees; the API default is 500. Masking fractions, repeats, scoring support, tie rules, and PPI weight are configurable. To run without a PPI prior, explicitly set `graph.ppi_weight: 0`. See [Configuration](docs/CONFIGURATION.md).
78
+
79
+ Each run saves its resolved configuration, masks, candidate scores, graph and input hashes, and software versions. The `biology` workflow also writes `imputed.csv.gz`; the `nested` workflow writes `outer_scores.csv`. Existing output directories are preserved.
80
+
81
+ Reconstruction scores describe artificially withheld observed entries. They do not establish accuracy at naturally missing values. Nested entry masking evaluates reconstruction within the supplied cells; it is distinct from predicting previously unseen cells. Selection scores from `biology` are validation scores, not independent test estimates.
82
+
83
+ ## Citation
84
+
85
+ Zhong, H., Chi, S., et al. *Recovering biological structure in sparse single-cell proteomics with GIRAFI*. bioRxiv (2026). [doi:10.64898/2026.05.18.726081](https://doi.org/10.64898/2026.05.18.726081).
86
+
87
+ Software citation metadata are provided in [CITATION.cff](CITATION.cff). Implementation provenance and historical compatibility are documented in [Methods](docs/METHODS.md#implementation-provenance). The PyPI project description is maintained in [README.pypi.md](README.pypi.md).
88
+
89
+ ## Development
90
+
91
+ ```bash
92
+ python -m pip install -e ".[dev]"
93
+ python -m pytest
94
+ python -m build
95
+ python -m twine check dist/*
96
+ ```
97
+
98
+ MIT License. Original GIRAFI method and implementation credits are retained in the source provenance.
@@ -0,0 +1,59 @@
1
+ # GIRAFI
2
+
3
+ **Graph-informed random-forest imputation for single-cell proteomics**
4
+
5
+ The **GIRAFI method and research** are credited to **Huan Zhong and the GIRAFI research collaborators**. Existing implementation credits include **Ziming Wang and the GIRAFI contributors**. **Junseo Park** maintains the Python package and its distribution.
6
+
7
+ GIRAFI estimates missing protein abundances using empirical protein associations and an optional curated protein interaction prior. Protein-specific random forests use graph-restricted predictors, and graph polishing updates only missing entries. Measured values are preserved.
8
+
9
+ The package provides Local and Neighbor variants, validation-based selection for dataset completion, and nested masking for reconstruction evaluation.
10
+
11
+ ## Installation
12
+
13
+ Python 3.11 or later is required. The initial distribution is a release candidate:
14
+
15
+ ```bash
16
+ python -m pip install "girafi==0.1.0rc1"
17
+ girafi --help
18
+ ```
19
+
20
+ ## Python example
21
+
22
+ Use a CSV matrix with cells in rows, proteins in columns, and cell IDs in the first column. Empty fields and `NaN` represent missing values; zero is an observed value. This example assumes linear intensities and explicitly disables the PPI prior:
23
+
24
+ ```python
25
+ import pandas as pd
26
+ from girafi import GIRAFIConfig, GIRAFIPipeline
27
+
28
+ X = pd.read_csv("expression.csv", index_col=0)
29
+ config = GIRAFIConfig.from_dict({
30
+ "workflow": "biology",
31
+ "input_scale": "linear",
32
+ "graph": {"ppi_weight": 0.0},
33
+ })
34
+ result = GIRAFIPipeline(config).run(X)
35
+ result.save("runs/my-analysis")
36
+ ```
37
+
38
+ For log2-transformed input, set `input_scale` to `log2`. To use a PPI prior, provide a table with `source`, `target`, and optional `weight` columns with matching protein identifiers, set `graph.ppi_weight` explicitly, and pass the table to `run(X, ppi=ppi)`.
39
+
40
+ ## Workflows and command line
41
+
42
+ - `biology` selects a variant using validation masks and then completes the supplied matrix.
43
+ - `nested` selects variants within inner validation masks and evaluates reconstruction on held-out outer entries.
44
+
45
+ ```bash
46
+ girafi run --config config.yaml --matrix expression.csv --out runs/my-analysis
47
+ ```
48
+
49
+ Configurations accept YAML or JSON. Results include resolved settings, selection records, masks, input hashes, and software versions. The source distribution includes the Methods, Configuration, and Validation guides, synthetic examples, and tests. Repository documentation is available on the [GIRAFI package branch](https://github.com/dorothyzh/GIRAFI/tree/package), subject to repository access.
50
+
51
+ Reconstruction scores on artificially withheld observations do not establish accuracy at naturally missing entries. Nested entry masking evaluates reconstruction within the supplied cells, rather than prediction for unseen cells. Validation scores from `biology` are not independent test estimates.
52
+
53
+ ## Citation and license
54
+
55
+ Zhong, H., Chi, S., et al. *Recovering biological structure in sparse single-cell proteomics with GIRAFI*. bioRxiv (2026). [doi:10.64898/2026.05.18.726081](https://doi.org/10.64898/2026.05.18.726081).
56
+
57
+ Please cite the manuscript and report the GIRAFI software version. Publication through a package maintainer's account does not change the method or manuscript authorship. Original implementation attribution is retained in the packaged `girafi/provenance.json`. The source distribution includes `AUTHORS.md` and `CITATION.cff`.
58
+
59
+ MIT License. Existing copyright and permission notices are retained in the distribution.
@@ -0,0 +1,17 @@
1
+ workflow: biology
2
+ variant: auto
3
+ input_scale: linear
4
+ random_state: 123
5
+ model:
6
+ trees: 100
7
+ graph:
8
+ ppi_weight: 0.1
9
+ selection:
10
+ strategy: repeated_holdout
11
+ mask_scope: complete_region
12
+ n_repeats: 5
13
+ mask_fraction: 0.1
14
+ tie_breaker: mean_rmse_then_local
15
+ nrmse_tie_atol: 1.0e-12
16
+ min_region_rows: 10
17
+ min_region_cols: 5
@@ -0,0 +1,19 @@
1
+ workflow: nested
2
+ variant: auto
3
+ input_scale: linear
4
+ random_state: 29101
5
+ model:
6
+ trees: 100
7
+ graph:
8
+ ppi_weight: 0.1
9
+ selection:
10
+ strategy: holdout
11
+ mask_scope: observed_entries
12
+ n_repeats: 1
13
+ mask_fraction: 0.1
14
+ tie_breaker: local_first
15
+ nrmse_tie_atol: 0.0
16
+ evaluation:
17
+ mask_scope: observed_entries
18
+ mask_fraction: 0.1
19
+ n_repeats: 5
@@ -0,0 +1,53 @@
1
+ # Configuration
2
+
3
+ Load YAML with `GIRAFIConfig.from_yaml`, JSON with `GIRAFIConfig.from_json`, or a mapping with `GIRAFIConfig.from_dict`. Unknown keys and invalid values are errors. The same configuration drives the Python and command-line interfaces.
4
+
5
+ | Setting | Meaning | Default |
6
+ | --- | --- | --- |
7
+ | `workflow` | Dataset completion or nested entry evaluation | `biology` |
8
+ | `variant` | `auto`, `local`, or `neighbor` | `auto` |
9
+ | `input_scale` | `linear` or already `log2` | `linear` |
10
+ | `output_scale` | `input` or standardized `model` | `input` |
11
+ | `random_state` | Base seed | `123` |
12
+ | `model.trees` | Trees per fitted target forest | `500` |
13
+ | `model.neighbors` | Maximum graph neighbors per target | `24` |
14
+ | `model.min_leaf` | Minimum samples per leaf | `5` |
15
+ | `model.local_min_obs` | Minimum eligible Local training cells | `8` |
16
+ | `model.neighbor_min_obs` | Minimum eligible Neighbor training cells | `12` |
17
+ | `graph.ppi_weight` | Fixed fusion weight; zero disables the prior | `0.1` |
18
+ | `graph.corr_topk` | Empirical neighbors retained per protein | `50` |
19
+ | `graph.overlap_exponent` | Shared-observation shrinkage exponent | `0.5` |
20
+ | `graph.polish_weight` | Missing-entry polishing weight | `0.2` |
21
+ | `execution.n_jobs` | Forest workers; `-1` uses available cores | `1` |
22
+
23
+ ## Workflow presets
24
+
25
+ When no selection settings are supplied, workflow-dependent defaults are:
26
+
27
+ | Selection setting | `biology` | `nested` |
28
+ | --- | --- | --- |
29
+ | `strategy` | `repeated_holdout` | `holdout` |
30
+ | `mask_scope` | `complete_region` | `observed_entries` |
31
+ | `mask_fraction` | `0.1` | `0.1` |
32
+ | `n_repeats` | `5` | `1` |
33
+ | `tie_breaker` | `mean_rmse_then_local` | `local_first` |
34
+ | `nrmse_tie_atol` | `1e-12` | `0` |
35
+
36
+ `holdout` requires one repeat. To average several inner validation masks in a nested run, set `selection.strategy: repeated_holdout` and `selection.n_repeats` explicitly. A complete region must contain at least `selection.min_region_rows` rows and `selection.min_region_cols` columns (defaults: 10 and 5). The region defines scoring support; the full permitted matrix remains the learner input.
37
+
38
+ Nested evaluation has separate `evaluation.mask_scope`, `evaluation.mask_fraction`, and `evaluation.n_repeats`, defaulting to `observed_entries`, `0.1`, and `5`. Outer scoring never participates in selection. Seeds are base seed plus outer repeat index; validation mask seeds add 100000 plus the inner repeat index, and forest seeds add 10000 for validation or 20000 for refitting. Mask sampling uses a further offset of 1000. Each resolved seed and mask hash is saved.
39
+
40
+ For no-PPI imputation:
41
+
42
+ ```yaml
43
+ workflow: biology
44
+ variant: auto
45
+ graph:
46
+ ppi_weight: 0
47
+ selection:
48
+ mask_scope: observed_entries
49
+ ```
50
+
51
+ `artifacts.save_masks` defaults to true. `artifacts.save_predictions` defaults to true for biology and false for nested. A biology run always saves its final completed matrix. Nested prediction matrices are optional and correspond to the outer-visible input, not a final imputation of all original observations. Each run includes an environment report and audit manifest.
52
+
53
+ The CLI can override `variant` and `ppi_weight`, with the resolved values saved. A supplied `--workflow` must agree with the configuration file. With no configuration file, `--workflow` selects the corresponding defaults. Use `girafi run --help` for input and output options.
@@ -0,0 +1,49 @@
1
+ # Methods
2
+
3
+ ## Input and transformation
4
+
5
+ GIRAFI operates on a cell-by-protein matrix with explicit missingness. Protein membership and any upstream quality control are supplied by the caller. Each protein must retain at least one observed value. Zero is an observed value, not a missing-value marker.
6
+
7
+ For nonnegative linear intensities, the pseudocount is half the smallest positive value in the permitted training view, bounded below by `1e-12`. Values are transformed by `log2(x + pseudocount)` and standardized per protein using the population standard deviation (`ddof=0`). A zero training standard deviation is replaced by one. For `input_scale: log2`, the logarithm is omitted. All fitted quantities are recomputed for each validation or refit view.
8
+
9
+ Output is returned to the input scale by default, and originally observed entries are copied exactly from the input. Missing-entry predictions are inverse transformed without clipping. Consequently, a linear-scale model prediction is not constrained to be nonnegative. `output_scale: model` instead returns the standardized model scale, with the associated transformation recorded in the manifest.
10
+
11
+ ## Protein graphs
12
+
13
+ Positive pairwise-complete Spearman correlations require at least three shared observations. A correlation is multiplied by `(n_ij / n_cells)^overlap_exponent`, where `n_ij` is the **integer number** of shared observations. Each row retains up to `corr_topk` positive neighbors, followed by row normalization.
14
+
15
+ PPI edges are aligned by protein ID, made undirected, and combined by maximum weight when duplicate edges occur. Self-edges are excluded. A square PPI DataFrame must already be symmetric, nonnegative, finite, and loop-free. Missing protein IDs have zero prior weight. A positive requested PPI weight requires at least one aligned positive edge.
16
+
17
+ The aligned prior is symmetrically degree-normalized, fused with the empirical graph, and row-normalized. `ppi_weight=0` makes the model independent of the supplied prior. Neighbor ranking follows descending `numpy.argsort` order on the given protein order. Input order and numerical environment are therefore recorded.
18
+
19
+ ## Local and Neighbor
20
+
21
+ Both variants use at most `model.neighbors` graph neighbors per target.
22
+
23
+ **Local** builds weighted neighbor mean and standard-deviation predictors from currently observed neighbors. Training cells require an observed target and finite predictors. Missing prediction features use medians from those eligible training cells. The forest uses two candidate features at each split.
24
+
25
+ **Neighbor** uses neighboring abundance columns with observed-column median completion. A training cell requires an observed target and at least `max(2, floor(0.3 * n_neighbors))` observed neighbors. The forest uses `max_features="sqrt"`.
26
+
27
+ The minimum training support is eight cells for Local and twelve for Neighbor by default. A target with insufficient neighbors or training support receives its observed training median, with the reason counted in the run audit. Unexpected fitting errors propagate. Forest seeds are the fit seed plus the target column index, reduced modulo `2**32 - 1`.
28
+
29
+ After target-wise fitting, the source cleanup stage receives an already finite matrix and is an identity operation: it fits no additional forests. Polishing updates only missing positions using `(1-gamma) * X_imp + gamma * (X_imp @ W)`. The right-multiplication direction is retained explicitly.
30
+
31
+ ## Masking and selection
32
+
33
+ Scoring support can be all observed entries or an NA-free region found by deterministic greedy row/column elimination. The latter is a found region, not a guaranteed largest submatrix. In either case the learner receives the full permitted matrix.
34
+
35
+ Masks are sampled without replacement by position, independent of intensity values. The requested count is `floor(mask_fraction * eligible_entries)`, with at least two entries required. The sampler retains at least one training observation per protein; infeasible requests fail. This support guard can make masks differ from historical runners without the guard. Both variants use identical masks and fitted transformations within each validation repeat.
36
+
37
+ NRMSE is RMSE divided by the population standard deviation of masked reference values on the training-standardized scale. Zero reference variance and nonfinite scored values are errors. Candidate scores are averaged equally over validation repeats. `mean_rmse_then_local` uses mean RMSE among candidates within the declared NRMSE tolerance, then Local for remaining exact ties. `local_first` uses Local among candidates within that tolerance. The PPI weight and other parameters are fixed; automatic selection only chooses the variant.
38
+
39
+ The **biology** workflow selects once, then refits on the complete permitted input without artificial masking. The **nested** workflow selects independently within each outer repeat and scores outer values only after refitting. The selector accepts only the outer-visible matrix, not outer truth or biological endpoints. A fixed variant skips selection. Any downstream cell-level cross-validation must independently fit its complete analysis pipeline within training folds; this package does not implement retained-model prediction for new cells.
40
+
41
+ ## Implementation provenance
42
+
43
+ Method ID: `girafi-count-overlap-v1`.
44
+
45
+ The learner and graph arithmetic were extracted from the audited Python engine used for the fixed-PPI experiments. Its SHA-256 and attribution are included in `girafi/provenance.json`. The original GIRAFI Python/R implementations and paper analyses are separate provenance sources.
46
+
47
+ In particular, one archived public Python graph implementation used boolean matrix multiplication before converting to float. This release uses integer shared-observation counts. Original paper scores, that public implementation, and this maintained implementation must not be assumed numerically identical. The package also adds explicit input contracts, repeat aggregation, ID alignment, output inversion, and support-preserving masking.
48
+
49
+ Reference fixtures test the extracted computation against the source engine on synthetic inputs with fixed masks. The fixture metadata specify the software versions used. Bitwise reproducibility across untested library versions or platforms is not asserted.
@@ -0,0 +1,20 @@
1
+ # Release procedure
2
+
3
+ The initial distribution is `girafi==0.1.0rc1`. The repository is `dorothyzh/GIRAFI`, with the installable source at the root of the `package` branch. The Python import and command are both `girafi`. Check out the `package` branch and run local build and verification commands from the repository root.
4
+
5
+ ## Authorship and account roles
6
+
7
+ Retain Huan Zhong and the GIRAFI research collaborators as the method/research credits, Ziming Wang and the GIRAFI contributors as the existing implementation credits, and Junseo Park as the Python package maintainer. The upload account and PyPI project roles control distribution access; they do not replace the author metadata or manuscript citation. Keep `AUTHORS.md`, `CITATION.cff`, `README.pypi.md`, and the packaged provenance consistent. Preserve `LICENSE` verbatim.
8
+
9
+ ## Build and publish
10
+
11
+ 1. Run the test suite and build the wheel/source distribution. Check metadata with `python -m twine check dist/*`, then verify the wheel with `python scripts/check_wheel.py --wheel dist/<wheel filename>`.
12
+ 2. Confirm the version in `pyproject.toml`, `src/girafi/__init__.py`, `CITATION.cff`, and `CHANGELOG.md`. Verify that the examples, method ID, and source provenance match the release.
13
+ 3. After the `package` branch has been pushed, inspect the GitHub test matrix. Select `package` when manually running the release workflow. The **Package Release** workflow defaults to `build`, which uploads distribution artifacts without publishing a package.
14
+ 4. An authenticated PyPI/TestPyPI account must configure the publisher. For a new project, use a pending Trusted Publisher with project name `girafi`, GitHub owner `dorothyzh`, repository `GIRAFI`, workflow filename `package-release.yml`, and environment `testpypi` (TestPyPI) or `pypi` (PyPI). The PyPI account may belong to the distribution maintainer. Use the official GIRAFI repository for the workflow. Existing projects require an account with the necessary project management role.
15
+ 5. Choose `testpypi` in the manual Package Release workflow and inspect an installation of that release. After checking the release candidate, choose `pypi` explicitly. No stored PyPI API token is needed. The `pypi`/`testpypi` GitHub environment names must match the registered publishers; do not weaken existing environment protections.
16
+ 6. Record the release tag, commit, distribution hashes, and environment. Package versions and uploaded filenames cannot be reused; increment the version for subsequent releases.
17
+
18
+ The publishing jobs consume the distributions produced and checked by the build job. Ordinary pushes and pull requests run tests only. Account-side publishers and environments are configured by the repository/package owner; they are not created by these source files.
19
+
20
+ Only after a successful upload and public readback should the reviewer response say that GIRAFI is available on PyPI. Record the exact version and project URL; retain a preparation-only statement while account setup or publication is pending.