LZGraphs 2.1.1__tar.gz → 2.2.0__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 (72) hide show
  1. lzgraphs-2.2.0/PKG-INFO +401 -0
  2. lzgraphs-2.2.0/README.md +350 -0
  3. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/pyproject.toml +2 -4
  4. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/__init__.py +20 -20
  5. lzgraphs-2.2.0/src/LZGraphs/constants.py +6 -0
  6. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/exceptions/__init__.py +1 -1
  7. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/amino_acid_positional.py +209 -178
  8. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/edge_data.py +22 -8
  9. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/graph_operations.py +39 -39
  10. lzgraphs-2.2.0/src/LZGraphs/graphs/lz_graph_base.py +962 -0
  11. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/naive.py +65 -57
  12. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/nucleotide_double_positional.py +122 -92
  13. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/__init__.py +14 -14
  14. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/convenience.py +3 -4
  15. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/diversity.py +28 -28
  16. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/entropy.py +21 -21
  17. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/saturation.py +58 -49
  18. lzgraphs-2.2.0/src/LZGraphs/mixins/__init__.py +8 -0
  19. lzgraphs-2.2.0/src/LZGraphs/mixins/bayesian_posterior.py +267 -0
  20. lzgraphs-2.2.0/src/LZGraphs/mixins/gene_logic.py +104 -0
  21. lzgraphs-2.2.0/src/LZGraphs/mixins/graph_topology.py +59 -0
  22. lzgraphs-2.2.0/src/LZGraphs/mixins/lzpgen_distribution.py +457 -0
  23. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/mixins/random_walk.py +16 -16
  24. lzgraphs-2.2.0/src/LZGraphs/mixins/serialization.py +615 -0
  25. lzgraphs-2.2.0/src/LZGraphs/mixins/walk_analysis.py +177 -0
  26. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/utilities/misc.py +18 -7
  27. lzgraphs-2.2.0/src/LZGraphs/visualization/__init__.py +18 -0
  28. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/visualization/visualize.py +11 -11
  29. lzgraphs-2.2.0/src/LZGraphs.egg-info/PKG-INFO +401 -0
  30. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs.egg-info/SOURCES.txt +8 -0
  31. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs.egg-info/requires.txt +2 -4
  32. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_aap_lzgraph.py +15 -15
  33. lzgraphs-2.2.0/tests/test_abundance.py +796 -0
  34. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_base_class_methods.py +8 -8
  35. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_diversity_theory.py +24 -24
  36. lzgraphs-2.2.0/tests/test_flexible_input.py +213 -0
  37. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_graph_operations.py +8 -8
  38. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_metrics.py +36 -36
  39. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_naive_lzgraph.py +11 -11
  40. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_ndp_lzgraph.py +11 -11
  41. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_new_features.py +9 -9
  42. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_pgen_fixes.py +22 -22
  43. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_serialization.py +10 -8
  44. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_simulate.py +22 -22
  45. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_utilities.py +12 -14
  46. lzgraphs-2.1.1/PKG-INFO +0 -230
  47. lzgraphs-2.1.1/README.md +0 -177
  48. lzgraphs-2.1.1/src/LZGraphs/graphs/lz_graph_base.py +0 -1943
  49. lzgraphs-2.1.1/src/LZGraphs/mixins/__init__.py +0 -3
  50. lzgraphs-2.1.1/src/LZGraphs/mixins/gene_logic.py +0 -95
  51. lzgraphs-2.1.1/src/LZGraphs/visualization/__init__.py +0 -18
  52. lzgraphs-2.1.1/src/LZGraphs.egg-info/PKG-INFO +0 -230
  53. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/CHANGELOG.md +0 -0
  54. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/CONTRIBUTING.md +0 -0
  55. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/LICENSE +0 -0
  56. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/MANIFEST.in +0 -0
  57. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/requirements.txt +0 -0
  58. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/setup.cfg +0 -0
  59. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/bag_of_words/__init__.py +0 -0
  60. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/bag_of_words/bow_encoder.py +0 -0
  61. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/graphs/__init__.py +0 -0
  62. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/metrics/pgen_distribution.py +0 -0
  63. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/mixins/gene_prediction.py +0 -0
  64. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/py.typed +0 -0
  65. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/utilities/__init__.py +0 -0
  66. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/utilities/decomposition.py +0 -0
  67. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs/utilities/helpers.py +0 -0
  68. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs.egg-info/dependency_links.txt +0 -0
  69. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/src/LZGraphs.egg-info/top_level.txt +0 -0
  70. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_analytical_distribution.py +0 -0
  71. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_bow_encoder.py +0 -0
  72. {lzgraphs-2.1.1 → lzgraphs-2.2.0}/tests/test_lzpgen_distribution.py +0 -0
@@ -0,0 +1,401 @@
1
+ Metadata-Version: 2.4
2
+ Name: LZGraphs
3
+ Version: 2.2.0
4
+ Summary: An Implementation of LZ76 Based Graphs for Repertoire Representation and Analysis
5
+ Author-email: Thomas Konstantinovsky <thomaskon90@gmail.com>
6
+ Maintainer-email: Thomas Konstantinovsky <thomaskon90@gmail.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/MuteJester/LZGraphs
9
+ Project-URL: Documentation, https://mutejester.github.io/LZGraphs/
10
+ Project-URL: Repository, https://github.com/MuteJester/LZGraphs
11
+ Project-URL: Issues, https://github.com/MuteJester/LZGraphs/issues
12
+ Project-URL: Changelog, https://github.com/MuteJester/LZGraphs/blob/master/CHANGELOG.md
13
+ Keywords: Graph Theory,Immunology,Analytics,Biology,T-cell,Repertoire,CDR3,Bioinformatics,LZ76,Lempel-Ziv
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
18
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Operating System :: OS Independent
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: networkx>=3.0
31
+ Requires-Dist: numpy>=1.24
32
+ Requires-Dist: tqdm>=4.65
33
+ Requires-Dist: scipy>=1.10
34
+ Provides-Extra: viz
35
+ Requires-Dist: matplotlib>=3.7; extra == "viz"
36
+ Requires-Dist: seaborn>=0.12; extra == "viz"
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=7.0; extra == "dev"
39
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
40
+ Requires-Dist: pandas>=1.5; extra == "dev"
41
+ Requires-Dist: black>=23.0; extra == "dev"
42
+ Requires-Dist: isort>=5.12; extra == "dev"
43
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
44
+ Requires-Dist: pre-commit>=3.0; extra == "dev"
45
+ Requires-Dist: build>=1.0; extra == "dev"
46
+ Requires-Dist: twine>=4.0; extra == "dev"
47
+ Provides-Extra: docs
48
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
49
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
50
+ Dynamic: license-file
51
+
52
+ <p align="center">
53
+
54
+ [![PyPI version](https://img.shields.io/pypi/v/LZGraphs.svg)](https://pypi.org/project/LZGraphs/)
55
+ [![Python versions](https://img.shields.io/pypi/pyversions/LZGraphs.svg)](https://pypi.org/project/LZGraphs/)
56
+ [![CI/CD](https://github.com/MuteJester/LZGraphs/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/MuteJester/LZGraphs/actions/workflows/ci-cd.yml)
57
+ [![License](https://img.shields.io/github/license/MuteJester/LZGraphs.svg)](https://github.com/MuteJester/LZGraphs/blob/master/LICENSE)
58
+ [![Downloads](https://img.shields.io/pypi/dm/LZGraphs.svg)](https://pypi.org/project/LZGraphs/)
59
+
60
+ [![Stargazers][stars-shield]][stars-url]
61
+ [![Issues][issues-shield]][issues-url]
62
+ [![LinkedIn][linkedin-shield]][linkedin-url]
63
+
64
+ </p>
65
+
66
+
67
+ <!-- PROJECT LOGO -->
68
+ <br />
69
+ <p align="center">
70
+ <a href="https://github.com/MuteJester/LZGraphs">
71
+ <img src="https://github.com/MuteJester/LZGraphs/blob/master/misc/lzglogo2.png" alt="Logo" width="480" height="330">
72
+ </a>
73
+
74
+ <h2 align="center">LZGraphs</h2>
75
+
76
+ <p align="center">
77
+ LZ76 Graphs and Applications in Immunology
78
+ <br />
79
+ <a href="https://MuteJester.github.io/LZGraphs/"><strong>Explore the docs &raquo;</strong></a>
80
+ <br />
81
+ <br />
82
+ <a href="https://github.com/MuteJester/LZGraphs/issues">Report Bug</a>
83
+ &middot;
84
+ <a href="https://github.com/MuteJester/LZGraphs/issues">Request Feature</a>
85
+ </p>
86
+ </p>
87
+
88
+ ---
89
+
90
+ > **:dna: New to LZGraphs?** Head over to the **[full documentation and tutorials](https://MuteJester.github.io/LZGraphs/)** for comprehensive guides, API reference, and worked examples covering every feature of the library.
91
+
92
+ ---
93
+
94
+ ## Table of Contents
95
+
96
+ * [About the Project](#about-the-project)
97
+ * [Key Features](#key-features)
98
+ * [Installation](#installation)
99
+ * [Quick Start](#quick-start)
100
+ * [Graph Types](#graph-types)
101
+ * [Sequence Abundance Weighting](#sequence-abundance-weighting)
102
+ * [Core Capabilities](#core-capabilities)
103
+ * [Contributing](#contributing)
104
+ * [License](#license)
105
+ * [Contact](#contact)
106
+
107
+
108
+ <!-- ABOUT THE PROJECT -->
109
+ ## About The Project
110
+
111
+ LZGraphs :dna: is a Python library for immune receptor repertoire analysis based on the Lempel-Ziv 76 (LZ-76) compression algorithm. It builds directed graph models from TCR and BCR CDR3 sequences, capturing the sequential structure of repertoires without relying on alignment.
112
+
113
+ The methodology is presented in the research paper *"A Novel Approach to T-Cell Receptor Beta Chain (TCRB) Repertoire Encoding Using Lossless String Compression"*.
114
+
115
+ ### Background
116
+
117
+ The diversity of T-cells and B-cells is crucial for producing receptors that recognize the wide range of pathogens encountered throughout life. V(D)J recombination generates this diversity through a stochastic process, making repertoire analysis challenging. LZGraphs addresses this by decomposing sequences into LZ-76 subpatterns and encoding them as graph transitions, providing a compact, information-rich representation of an entire repertoire.
118
+
119
+
120
+ ## Key Features
121
+
122
+ - **Alignment-free analysis** -- no error-prone sequence alignment required
123
+ - **Generation probability inference** -- compute P(sequence) under the learned graph model
124
+ - **Sequence simulation** -- generate realistic synthetic sequences from the graph
125
+ - **Diversity estimation** -- LZ-based diversity indices (K-diversity family)
126
+ - **Information-theoretic metrics** -- entropy, perplexity, Jensen-Shannon divergence, mutual information, and more
127
+ - **Repertoire comparison** -- compare two repertoires via graph-level statistics
128
+ - **Analytical probability distributions** -- exact moments and scipy-like distribution objects for generation probabilities
129
+ - **Gene annotation support** -- optional V/J gene tracking on edges for gene usage analysis
130
+ - **Bayesian posterior personalization** -- adapt population-level models to individual repertoires using Dirichlet-Multinomial conjugacy
131
+ - **Abundance weighting** -- weight sequences by clonal abundance for more realistic models
132
+ - **Serialization** -- save and load graphs in JSON format
133
+
134
+
135
+ ## Installation
136
+
137
+ Install from PyPI:
138
+
139
+ ```bash
140
+ pip install LZGraphs
141
+ ```
142
+
143
+ LZGraphs requires Python 3.9 or later. To verify the installation:
144
+
145
+ ```python
146
+ import LZGraphs
147
+ print(LZGraphs.__version__)
148
+ ```
149
+
150
+
151
+ ## Quick Start
152
+
153
+ Build an amino acid positional graph from CDR3 sequences and compute sequence probabilities:
154
+
155
+ ```python
156
+ from LZGraphs import AAPLZGraph
157
+
158
+ # Pass a plain list of CDR3 amino acid sequences
159
+ sequences = [
160
+ 'CASSLAPGATNEKLFF',
161
+ 'CASSLGQAYEQYF',
162
+ 'CASSFSTCSANYGYTF',
163
+ 'CASSQEGTEAFF',
164
+ 'CASSLGQGNIQYF',
165
+ # ... your CDR3 amino acid sequences
166
+ ]
167
+
168
+ # Construct the graph
169
+ graph = AAPLZGraph(sequences, verbose=True)
170
+
171
+ # Compute the log-probability of a sequence under the model
172
+ log_prob = graph.walk_log_probability('CASSLAPGATNEKLFF')
173
+ print(f"Log P(seq): {log_prob:.4f}")
174
+
175
+ # Simulate 100 new sequences from the graph
176
+ generated = graph.simulate(100, seed=42)
177
+ print(f"Generated {len(generated)} sequences")
178
+
179
+ # Access graph properties
180
+ print(f"Nodes: {graph.num_subpatterns}, Edges: {graph.num_transitions}")
181
+ print(f"Length distribution: {graph.length_probabilities}")
182
+ ```
183
+
184
+
185
+ ## Graph Types
186
+
187
+ LZGraphs provides three graph variants, each suited to different sequence types and analysis goals:
188
+
189
+ ### AAPLZGraph -- Amino Acid Positional
190
+
191
+ Best for **CDR3 amino acid sequences**. Each LZ-76 subpattern is annotated with its position in the sequence, creating a directed acyclic graph (DAG). This enables exact analytical computations including `lzpgen_moments()` and `lzpgen_analytical_distribution()`.
192
+
193
+ ```python
194
+ from LZGraphs import AAPLZGraph
195
+
196
+ graph = AAPLZGraph(data, verbose=True) # data has 'cdr3_amino_acid' column
197
+ ```
198
+
199
+ ### NDPLZGraph -- Nucleotide Double Positional
200
+
201
+ Best for **CDR3 nucleotide sequences** where reading frame matters. Encodes both the subpattern and a double positional index derived from nucleotide positions. Also a DAG, supporting exact analytical methods.
202
+
203
+ ```python
204
+ from LZGraphs import NDPLZGraph
205
+
206
+ graph = NDPLZGraph(data, verbose=True) # data has 'cdr3_rearrangement' column
207
+ ```
208
+
209
+ ### NaiveLZGraph -- Basic Nucleotide
210
+
211
+ A simpler model for **nucleotide sequences** that uses raw LZ-76 subpatterns without positional annotation. The resulting graph may contain cycles. Use Monte Carlo methods (`lzpgen_distribution()`) rather than exact analytics for this graph type.
212
+
213
+ ```python
214
+ from LZGraphs import NaiveLZGraph
215
+ from LZGraphs import generate_kmer_dictionary
216
+
217
+ cdr3_list = ['TGTGCCAGCAGC...', 'TGTGCCAGCAGT...', ...]
218
+ dictionary = generate_kmer_dictionary(cdr3_list)
219
+ graph = NaiveLZGraph(cdr3_list, dictionary, verbose=True)
220
+ ```
221
+
222
+ ### Gene Annotation
223
+
224
+ All three graph types support optional V and J gene annotation. Pass gene lists alongside sequences to track gene usage on graph edges:
225
+
226
+ ```python
227
+ sequences = ['CASSLEPSGGTDTQYF', 'CASSDTSGGTDTQYF', ...]
228
+ v_genes = ['TRBV16-1*01', 'TRBV1-1*01', ...]
229
+ j_genes = ['TRBJ1-2*01', 'TRBJ1-5*01', ...]
230
+
231
+ graph = AAPLZGraph(sequences, v_genes=v_genes, j_genes=j_genes, verbose=True)
232
+
233
+ # Gene data is now available
234
+ print(graph.has_gene_data) # True
235
+ print(graph.marginal_v_genes) # V gene usage distribution
236
+ print(graph.marginal_j_genes) # J gene usage distribution
237
+ ```
238
+
239
+
240
+ ## Sequence Abundance Weighting
241
+
242
+ Immune repertoire datasets often include clonal abundance information -- the number of times each unique clonotype was observed. LZGraphs supports abundance-weighted graph construction, where each sequence contributes proportionally to its observed count rather than being treated as a single observation.
243
+
244
+ This is particularly important for:
245
+
246
+ - **More accurate probability estimates** -- highly expanded clones exert greater influence on transition probabilities, reflecting the true distribution of the repertoire
247
+ - **Better representation of clonal expansion** -- dominant clones shape the graph structure proportionally to their prevalence
248
+ - **More realistic sequence generation** -- simulated sequences reflect the abundance-weighted landscape, not just the unique sequence set
249
+
250
+ To use abundance weighting, pass an `abundances` list alongside your sequences:
251
+
252
+ ```python
253
+ sequences = ['CASSLAPGATNEKLFF', 'CASSLGQAYEQYF', 'CASSFSTCSANYGYTF']
254
+ abundances = [150, 42, 7]
255
+
256
+ # Each sequence is weighted by its abundance during graph construction
257
+ graph = AAPLZGraph(sequences, abundances=abundances, verbose=True)
258
+ ```
259
+
260
+ For `NaiveLZGraph`, pass abundances as a separate parameter:
261
+
262
+ ```python
263
+ graph = NaiveLZGraph(
264
+ cdr3_list,
265
+ dictionary,
266
+ verbose=True,
267
+ abundances=[150, 42, 7, ...],
268
+ )
269
+ ```
270
+
271
+ When no abundance information is provided, every sequence is implicitly weighted as 1.
272
+
273
+
274
+ ## Core Capabilities
275
+
276
+ ### Probability Inference
277
+
278
+ Compute the probability of a sequence under the learned Markov model:
279
+
280
+ ```python
281
+ prob = graph.walk_probability('CASSLAPGATNEKLFF')
282
+ log_prob = graph.walk_log_probability('CASSLAPGATNEKLFF')
283
+ ```
284
+
285
+ ### Sequence Simulation
286
+
287
+ Generate new sequences by sampling random walks through the graph:
288
+
289
+ ```python
290
+ sequences = graph.simulate(1000, seed=42)
291
+ ```
292
+
293
+ ### Generation Probability Distributions
294
+
295
+ Characterize the distribution of generation probabilities across the repertoire:
296
+
297
+ ```python
298
+ # Monte Carlo empirical distribution (works on all graph types)
299
+ log_probs = graph.lzpgen_distribution(n=10000, seed=42)
300
+
301
+ # Exact analytical moments (DAG graphs only: AAPLZGraph, NDPLZGraph)
302
+ moments = graph.lzpgen_moments()
303
+ print(moments['mean'], moments['std'])
304
+
305
+ # Full scipy-like distribution object (DAG graphs only)
306
+ dist = graph.lzpgen_analytical_distribution()
307
+ print(dist.mean(), dist.std())
308
+ x = dist.ppf(0.05) # 5th percentile
309
+ ```
310
+
311
+ ### Diversity Metrics
312
+
313
+ ```python
314
+ from LZGraphs import lz_centrality, k_diversity
315
+
316
+ centrality = lz_centrality(graph, 'CASSLAPGATNEKLFF')
317
+ diversity = k_diversity(sequences, graph.encode_sequence, sample_size=1000)
318
+ ```
319
+
320
+ ### Information-Theoretic Analysis
321
+
322
+ ```python
323
+ from LZGraphs import (
324
+ node_entropy, edge_entropy, graph_entropy,
325
+ jensen_shannon_divergence, compare_repertoires,
326
+ )
327
+
328
+ print(f"Graph entropy: {graph_entropy(graph):.4f}")
329
+
330
+ # Compare two repertoires
331
+ jsd = jensen_shannon_divergence(graph1, graph2)
332
+ comparison = compare_repertoires(graph1, graph2)
333
+ ```
334
+
335
+ ### Bayesian Posterior Personalization
336
+
337
+ ```python
338
+ # Adapt a population graph to an individual
339
+ posterior = population_graph.get_posterior(
340
+ individual_sequences,
341
+ abundances=clonal_counts,
342
+ kappa=100.0 # prior strength
343
+ )
344
+
345
+ # The posterior is a full graph
346
+ simulated = posterior.simulate(1000, seed=42)
347
+ ```
348
+
349
+ ### Visualization
350
+
351
+ ```python
352
+ from LZGraphs import plot_graph, plot_possible_paths
353
+
354
+ plot_graph(graph)
355
+ plot_possible_paths(graph, 'CASSLAPGATNEKLFF')
356
+ ```
357
+
358
+ ### Saturation Analysis
359
+
360
+ ```python
361
+ from LZGraphs import NodeEdgeSaturationProbe
362
+
363
+ probe = NodeEdgeSaturationProbe()
364
+ # Feed sequences incrementally and track node/edge saturation curves
365
+ ```
366
+
367
+ For detailed usage of every feature, see the **[documentation](https://MuteJester.github.io/LZGraphs/)**.
368
+
369
+
370
+ ## Contributing
371
+
372
+ Contributions are what make the open-source community such a powerful place to create new ideas, inspire, and make progress. Any contributions you make are **greatly appreciated**.
373
+
374
+ 1. Fork the Project
375
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
376
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
377
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
378
+ 5. Open a Pull Request
379
+
380
+
381
+ <!-- LICENSE -->
382
+ ## License
383
+
384
+ Distributed under the MIT license. See `LICENSE` for more information.
385
+
386
+
387
+ <!-- CONTACT -->
388
+ ## Contact
389
+
390
+ [Thomas Konstantinovsky]() - thomaskon90@gmail.com
391
+
392
+ Project Link: [https://github.com/MuteJester/LZGraphs](https://github.com/MuteJester/LZGraphs)
393
+
394
+
395
+ <!-- MARKDOWN LINKS & IMAGES -->
396
+ [stars-shield]: https://img.shields.io/github/stars/MuteJester/LZGraphs.svg?style=flat-square
397
+ [stars-url]: https://github.com/MuteJester/LZGraphs/stargazers
398
+ [issues-shield]: https://img.shields.io/github/issues/MuteJester/LZGraphs.svg?style=flat-square
399
+ [issues-url]: https://github.com/MuteJester/LZGraphs/issues
400
+ [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
401
+ [linkedin-url]: https://www.linkedin.com/in/thomas-konstantinovsky-56230117b/