vdjtools 2.0.0a2__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 (253) hide show
  1. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/.gitignore +3 -0
  2. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/PKG-INFO +92 -13
  3. vdjtools-2.2.0/README.md +154 -0
  4. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/include/vdjtools/model.hpp +11 -1
  5. vdjtools-2.2.0/notebooks/model_explorer.py +142 -0
  6. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/pyproject.toml +6 -3
  7. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/__init__.py +1 -1
  8. vdjtools-2.2.0/python/vdjtools/biomarker/__init__.py +8 -0
  9. vdjtools-2.2.0/python/vdjtools/biomarker/fisher.py +202 -0
  10. vdjtools-2.2.0/python/vdjtools/biomarker/metaclonotype.py +114 -0
  11. vdjtools-2.2.0/python/vdjtools/cli/__init__.py +249 -0
  12. vdjtools-2.2.0/python/vdjtools/cli/__main__.py +4 -0
  13. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/features/kmer.py +5 -5
  14. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/features/physchem.py +12 -11
  15. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/io/__init__.py +18 -4
  16. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/io/batch.py +43 -2
  17. vdjtools-2.2.0/python/vdjtools/io/convert.py +395 -0
  18. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/io/read.py +13 -13
  19. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/io/schema.py +18 -15
  20. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/__init__.py +3 -0
  21. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/d2_del.parquet +0 -0
  22. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/d2_gene.parquet +0 -0
  23. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/d_del.parquet +0 -0
  24. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/d_gene.parquet +0 -0
  25. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/dd_dinucl.parquet +0 -0
  26. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/dd_ins.parquet +0 -0
  27. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/dj_dinucl.parquet +0 -0
  28. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/dj_ins.parquet +0 -0
  29. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/genes_d.parquet +0 -0
  30. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/genes_j.parquet +0 -0
  31. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/genes_v.parquet +0 -0
  32. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/j_5_del.parquet +0 -0
  33. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/j_choice.parquet +0 -0
  34. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/manifest.json +88 -0
  35. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/n_d.parquet +0 -0
  36. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/v_3_del.parquet +0 -0
  37. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/v_choice.parquet +0 -0
  38. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/vd_dinucl.parquet +0 -0
  39. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGH/vd_ins.parquet +0 -0
  40. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/genes_j.parquet +0 -0
  41. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/genes_v.parquet +0 -0
  42. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/j_5_del.parquet +0 -0
  43. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/j_choice.parquet +0 -0
  44. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/manifest.json +44 -0
  45. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/v_3_del.parquet +0 -0
  46. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/v_choice.parquet +0 -0
  47. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/vj_dinucl.parquet +0 -0
  48. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGK/vj_ins.parquet +0 -0
  49. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/genes_j.parquet +0 -0
  50. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/genes_v.parquet +0 -0
  51. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/j_5_del.parquet +0 -0
  52. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/j_choice.parquet +0 -0
  53. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/manifest.json +44 -0
  54. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/v_3_del.parquet +0 -0
  55. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/v_choice.parquet +0 -0
  56. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/vj_dinucl.parquet +0 -0
  57. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/IGL/vj_ins.parquet +0 -0
  58. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/genes_j.parquet +0 -0
  59. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/genes_v.parquet +0 -0
  60. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/j_5_del.parquet +0 -0
  61. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/j_choice.parquet +0 -0
  62. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/manifest.json +44 -0
  63. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/v_3_del.parquet +0 -0
  64. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/v_choice.parquet +0 -0
  65. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/vj_dinucl.parquet +0 -0
  66. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRA/vj_ins.parquet +0 -0
  67. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/d2_del.parquet +0 -0
  68. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/d2_gene.parquet +0 -0
  69. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/d_del.parquet +0 -0
  70. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/d_gene.parquet +0 -0
  71. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/dd_dinucl.parquet +0 -0
  72. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/dd_ins.parquet +0 -0
  73. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/dj_dinucl.parquet +0 -0
  74. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/dj_ins.parquet +0 -0
  75. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/genes_d.parquet +0 -0
  76. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/genes_j.parquet +0 -0
  77. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/genes_v.parquet +0 -0
  78. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/j_5_del.parquet +0 -0
  79. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/j_choice.parquet +0 -0
  80. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/manifest.json +88 -0
  81. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/n_d.parquet +0 -0
  82. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/v_3_del.parquet +0 -0
  83. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/v_choice.parquet +0 -0
  84. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/vd_dinucl.parquet +0 -0
  85. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRB/vd_ins.parquet +0 -0
  86. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/d2_del.parquet +0 -0
  87. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/d2_gene.parquet +0 -0
  88. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/d_del.parquet +0 -0
  89. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/d_gene.parquet +0 -0
  90. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/dd_dinucl.parquet +0 -0
  91. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/dd_ins.parquet +0 -0
  92. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/dj_dinucl.parquet +0 -0
  93. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/dj_ins.parquet +0 -0
  94. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/genes_d.parquet +0 -0
  95. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/genes_j.parquet +0 -0
  96. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/genes_v.parquet +0 -0
  97. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/j_5_del.parquet +0 -0
  98. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/j_choice.parquet +0 -0
  99. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/manifest.json +88 -0
  100. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/n_d.parquet +0 -0
  101. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/v_3_del.parquet +0 -0
  102. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/v_choice.parquet +0 -0
  103. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/vd_dinucl.parquet +0 -0
  104. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRD/vd_ins.parquet +0 -0
  105. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/genes_j.parquet +0 -0
  106. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/genes_v.parquet +0 -0
  107. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/j_5_del.parquet +0 -0
  108. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/j_choice.parquet +0 -0
  109. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/manifest.json +44 -0
  110. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/v_3_del.parquet +0 -0
  111. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/v_choice.parquet +0 -0
  112. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/vj_dinucl.parquet +0 -0
  113. vdjtools-2.2.0/python/vdjtools/model/_bundled/learned/TRG/vj_ins.parquet +0 -0
  114. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/d_del.parquet +0 -0
  115. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/d_gene.parquet +0 -0
  116. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/dj_dinucl.parquet +0 -0
  117. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/dj_ins.parquet +0 -0
  118. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/genes_d.parquet +0 -0
  119. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/genes_j.parquet +0 -0
  120. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/genes_v.parquet +0 -0
  121. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/j_5_del.parquet +0 -0
  122. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/j_choice.parquet +0 -0
  123. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/manifest.json +68 -0
  124. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/n_d.parquet +0 -0
  125. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/v_3_del.parquet +0 -0
  126. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/v_choice.parquet +0 -0
  127. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/vd_dinucl.parquet +0 -0
  128. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGH/vd_ins.parquet +0 -0
  129. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/genes_j.parquet +0 -0
  130. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/genes_v.parquet +0 -0
  131. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/j_5_del.parquet +0 -0
  132. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/j_choice.parquet +0 -0
  133. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/manifest.json +44 -0
  134. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/v_3_del.parquet +0 -0
  135. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/v_choice.parquet +0 -0
  136. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/vj_dinucl.parquet +0 -0
  137. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGK/vj_ins.parquet +0 -0
  138. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/genes_j.parquet +0 -0
  139. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/genes_v.parquet +0 -0
  140. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/j_5_del.parquet +0 -0
  141. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/j_choice.parquet +0 -0
  142. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/manifest.json +44 -0
  143. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/v_3_del.parquet +0 -0
  144. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/v_choice.parquet +0 -0
  145. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/vj_dinucl.parquet +0 -0
  146. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/IGL/vj_ins.parquet +0 -0
  147. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/genes_j.parquet +0 -0
  148. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/genes_v.parquet +0 -0
  149. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/j_5_del.parquet +0 -0
  150. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/j_choice.parquet +0 -0
  151. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/manifest.json +44 -0
  152. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/v_3_del.parquet +0 -0
  153. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/v_choice.parquet +0 -0
  154. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/vj_dinucl.parquet +0 -0
  155. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRA/vj_ins.parquet +0 -0
  156. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/d_del.parquet +0 -0
  157. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/d_gene.parquet +0 -0
  158. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/dj_dinucl.parquet +0 -0
  159. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/dj_ins.parquet +0 -0
  160. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/genes_d.parquet +0 -0
  161. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/genes_j.parquet +0 -0
  162. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/genes_v.parquet +0 -0
  163. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/j_5_del.parquet +0 -0
  164. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/j_choice.parquet +0 -0
  165. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/manifest.json +68 -0
  166. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/n_d.parquet +0 -0
  167. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/v_3_del.parquet +0 -0
  168. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/v_choice.parquet +0 -0
  169. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/vd_dinucl.parquet +0 -0
  170. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRB/vd_ins.parquet +0 -0
  171. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/d_del.parquet +0 -0
  172. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/d_gene.parquet +0 -0
  173. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/dj_dinucl.parquet +0 -0
  174. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/dj_ins.parquet +0 -0
  175. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/genes_d.parquet +0 -0
  176. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/genes_j.parquet +0 -0
  177. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/genes_v.parquet +0 -0
  178. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/j_5_del.parquet +0 -0
  179. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/j_choice.parquet +0 -0
  180. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/manifest.json +68 -0
  181. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/n_d.parquet +0 -0
  182. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/v_3_del.parquet +0 -0
  183. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/v_choice.parquet +0 -0
  184. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/vd_dinucl.parquet +0 -0
  185. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRD/vd_ins.parquet +0 -0
  186. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/genes_j.parquet +0 -0
  187. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/genes_v.parquet +0 -0
  188. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/j_5_del.parquet +0 -0
  189. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/j_choice.parquet +0 -0
  190. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/manifest.json +44 -0
  191. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/v_3_del.parquet +0 -0
  192. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/v_choice.parquet +0 -0
  193. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/vj_dinucl.parquet +0 -0
  194. vdjtools-2.2.0/python/vdjtools/model/_bundled/olga/TRG/vj_ins.parquet +0 -0
  195. vdjtools-2.2.0/python/vdjtools/model/bundled.py +56 -0
  196. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/generate.py +5 -5
  197. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/infer.py +31 -13
  198. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/native.py +43 -0
  199. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/reference.py +95 -4
  200. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/stitch.py +1 -1
  201. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/cluster.py +2 -2
  202. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/fuzzy.py +10 -10
  203. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/metrics.py +4 -4
  204. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/similarity.py +13 -13
  205. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/tcrnet.py +7 -7
  206. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/track.py +2 -2
  207. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/correct.py +7 -7
  208. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/decontaminate.py +3 -3
  209. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/filter.py +7 -7
  210. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/pool.py +13 -13
  211. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/sc/__init__.py +3 -0
  212. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/sc/pair.py +9 -9
  213. vdjtools-2.2.0/python/vdjtools/sc/pgen.py +90 -0
  214. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/sc/read.py +15 -15
  215. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/spectratype.py +4 -4
  216. vdjtools-2.2.0/skills/vdjtools/SKILL.md +99 -0
  217. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/src/_bindings.cpp +12 -2
  218. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/src/core.cpp +1 -1
  219. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/src/pgen.cpp +71 -6
  220. vdjtools-2.0.0a2/README.md +0 -73
  221. vdjtools-2.0.0a2/python/vdjtools/biomarker/__init__.py +0 -1
  222. vdjtools-2.0.0a2/python/vdjtools/cli/__init__.py +0 -1
  223. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/CMakeLists.txt +0 -0
  224. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/LICENSE +0 -0
  225. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/environment.yml +0 -0
  226. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/include/vdjtools/core.hpp +0 -0
  227. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/include/vdjtools/inext.hpp +0 -0
  228. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/features/__init__.py +0 -0
  229. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/io/cohort.py +0 -0
  230. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/analyze.py +0 -0
  231. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/data.py +0 -0
  232. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/dd.py +0 -0
  233. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/events.py +0 -0
  234. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/io.py +0 -0
  235. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/model.py +0 -0
  236. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/pgen.py +0 -0
  237. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/model/schema.py +0 -0
  238. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/overlap/__init__.py +0 -0
  239. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/__init__.py +0 -0
  240. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/batch.py +0 -0
  241. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/downsample.py +0 -0
  242. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/preprocess/join.py +0 -0
  243. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/py.typed +0 -0
  244. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/resources/.gitkeep +0 -0
  245. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/resources/aa_property_table.txt +0 -0
  246. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/sc/anndata.py +0 -0
  247. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/sc/cluster_eval.py +0 -0
  248. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/__init__.py +0 -0
  249. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/diversity.py +0 -0
  250. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/inext.py +0 -0
  251. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/rarefaction.py +0 -0
  252. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/python/vdjtools/stats/usage.py +0 -0
  253. {vdjtools-2.0.0a2 → vdjtools-2.2.0}/src/inext.cpp +0 -0
@@ -34,6 +34,9 @@ docs/_build/
34
34
  *.iml
35
35
  .DS_Store
36
36
 
37
+ # Claude Code local state (session config + nested agent worktrees — never commit)
38
+ .claude/
39
+
37
40
  # scratch
38
41
  tmp/
39
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: vdjtools
3
- Version: 2.0.0a2
3
+ Version: 2.2.0
4
4
  Summary: TCR/BCR repertoire analysis — Pgen/generation/inference, diversity, overlap, biomarkers (Python + C++)
5
5
  Keywords: immunology,tcr,bcr,airr,repertoire,pgen,olga,igor,bioinformatics
6
6
  Author-Email: Mikhail Shugay <mikhail.shugay@gmail.com>
@@ -18,6 +18,7 @@ Requires-Python: >=3.10
18
18
  Requires-Dist: polars>=1.0
19
19
  Requires-Dist: numpy
20
20
  Requires-Dist: scipy
21
+ Requires-Dist: typer>=0.12
21
22
  Provides-Extra: model
22
23
  Requires-Dist: arda-mapper>=2.5; extra == "model"
23
24
  Provides-Extra: overlap
@@ -31,8 +32,6 @@ Requires-Dist: scikit-learn; extra == "sc"
31
32
  Requires-Dist: pyyaml; extra == "sc"
32
33
  Requires-Dist: anndata; extra == "sc"
33
34
  Requires-Dist: huggingface_hub; extra == "sc"
34
- Provides-Extra: cli
35
- Requires-Dist: typer>=0.12; extra == "cli"
36
35
  Provides-Extra: examples
37
36
  Requires-Dist: marimo; extra == "examples"
38
37
  Requires-Dist: huggingface_hub; extra == "examples"
@@ -56,7 +55,6 @@ Requires-Dist: pybind11>=2.12; extra == "dev"
56
55
  Provides-Extra: all
57
56
  Requires-Dist: arda-mapper>=2.5; extra == "all"
58
57
  Requires-Dist: vdjmatch>=0.0.1; extra == "all"
59
- Requires-Dist: typer>=0.12; extra == "all"
60
58
  Description-Content-Type: text/markdown
61
59
 
62
60
  <p align="center">
@@ -88,9 +86,12 @@ Built on the antigenomics ecosystem:
88
86
  [vdjmatch](https://github.com/antigenomics/vdjmatch) (overlap + TCRnet),
89
87
  [arda](https://github.com/antigenomics/arda) (AIRR annotation + markup repair).
90
88
 
91
- > **Status: v2.0.0 under active development.** The legacy v1.x tool lives on the
92
- > [`legacy-1.x`](https://github.com/antigenomics/vdjtools/tree/legacy-1.x) branch and its
93
- > releases remain available under the repository tags (`v0.0.1` `1.2.1`).
89
+ > **Status: `v2.2.0`** the native V(D)J model engine plus the full analytics suite (diversity,
90
+ > overlap/TCRnet, preprocessing, biomarkers, single-cell), CDR features, and legacy-format ingestion
91
+ > (MiXcr, MiGec, immunoSEQ, IMGT/HighV-QUEST, Vidjil, RTCR). Clonotype columns follow the AIRR
92
+ > **junction** convention (`junction_nt` / `junction_aa`). The legacy v1.x tool lives on the
93
+ > [`legacy-1.x`](https://github.com/antigenomics/vdjtools/tree/legacy-1.x) branch and its releases
94
+ > remain available under the repository tags (`v0.0.1` … `1.2.1`).
94
95
 
95
96
  ## Install
96
97
 
@@ -117,17 +118,95 @@ pip install -e ".[dev,test]" # builds the _core C++ extension
117
118
 
118
119
  Or run the bootstrap script: `bash setup.sh --dev-parents --tests`.
119
120
 
120
- ## Capabilities (rolling out by phase — see [ROADMAP.md](ROADMAP.md))
121
+ ## Quickstart recombination model engine
121
122
 
122
- - **Model** native V(D)J recombination model: generation probability (Pgen), sequence
123
- generation, and EM model inference. Supersedes OLGA and IGoR: arda-driven scenario
124
- enumeration, polars marginal tables, D-D tandem support, and a native (pybind11) Pgen/EM core.
123
+ Precomputed models for all **7 human loci** ship in the wheel no OLGA or download needed:
124
+
125
+ ```python
126
+ from vdjtools.model import load_bundled, native
127
+ from vdjtools.model.generate import generate
128
+
129
+ model = load_bundled("TRB", source="olga") # or source="learned" (fit to real repertoires)
130
+
131
+ native.pgen_nt(model, "TGTGCCAGCAGC...") # nucleotide generation probability (native C++)
132
+ native.pgen_aa(model, "CASSLAPGATNEKLFF") # amino-acid Pgen (codon-marginalised)
133
+ native.pgen_aa(model, "CASSLAPGATNEKLFF", mismatches=1) # + the whole Hamming-1 ball
134
+ native.pgen_aa_batch(model, seqs, mismatches=1, threads=0) # Pgen over many CDR3s, thread-parallel (~11×)
135
+ generate(model, 1000) # sample a repertoire -> polars DataFrame
136
+ ```
137
+
138
+ Matches OLGA's Pgen to machine precision across all 7 loci, and adds tandem-D (D-D) support that
139
+ OLGA/IGoR lack. Learn a model from your own out-of-frame reads with `model.infer.infer_native`.
140
+
141
+ Explore any model's recombination **Bayes net** interactively (entropy, mutual information, marginals):
142
+
143
+ ```bash
144
+ pip install "vdjtools[examples]"
145
+ marimo edit notebooks/model_explorer.py
146
+ ```
147
+
148
+ ## Command line
149
+
150
+ `pip install vdjtools` installs the `vdjtools` command — the model engine (OLGA/IGoR-style) and the
151
+ repertoire analytics (over sample files or a metadata table, like the legacy tool):
152
+
153
+ ```bash
154
+ # recombination model engine — built-in models for all 7 loci (no download)
155
+ vdjtools models # list the bundled models
156
+ vdjtools generate -m TRB -n 1000 -o gen.tsv # sample sequences (cf. olga-generate_sequences)
157
+ vdjtools pgen seqs.tsv -m TRB -o pgen.tsv # Pgen per CDR3 (cf. olga-compute_pgen)
158
+ vdjtools pgen seqs.tsv -m TRB --mismatches 1 # + the Hamming-1 ball; --v-col/--j-col to condition
159
+
160
+ # repertoire analytics — sample files, or a cohort via -m/--metadata + --base-dir
161
+ vdjtools diversity sampleA.tsv sampleB.tsv -o diversity.tsv
162
+ vdjtools overlap *.tsv -o overlap.tsv
163
+ vdjtools segment-usage *.tsv --segment v -o usage.tsv
164
+ vdjtools spectratype *.tsv -o spectra.tsv
165
+ ```
166
+
167
+ Native vdjtools and AIRR Rearrangement inputs are auto-detected; every command writes TSV to `-o`
168
+ (or stdout, so it pipes). Run `vdjtools <command> --help` for options.
169
+
170
+ ## Performance
171
+
172
+ The Pgen / generation / EM / diversity hot paths are a native C++ (pybind11) core; everything else is
173
+ polars. Amino-acid Pgen matches OLGA to machine precision (1e-15) across all 7 loci while being
174
+ several times faster, and the built-in models keep the resident set small. Single thread, Apple M3
175
+ (arm64), bundled human TRB model:
176
+
177
+ | operation | throughput | vs OLGA |
178
+ |---|---|---|
179
+ | nucleotide Pgen (single-D VDJ) | **~0.5 ms/seq** | **9×** |
180
+ | amino-acid Pgen | **~0.6–0.9 ms/seq** | **8.6×** |
181
+ | Pgen + Hamming-1 ball (1 substitution) | **~15 ms/seq** | **8.7×** |
182
+ | sequence generation | **~32 000 seq/s** | — |
183
+
184
+ Nucleotide Pgen (via the same transfer-matrix DP as the aa path — an in-frame CDR3 is an aa query with
185
+ one codon fixed per position) is exact vs OLGA across all loci. Batched Pgen / 1-mismatch over many
186
+ CDR3s parallelises over sequences (`native.pgen_aa_batch`, **~11× on 16 cores**, bitwise-identical to
187
+ the serial result); the EM E-step parallelises over reads (~6.7× on 8 threads); diversity/rarefaction
188
+ run on a native iNEXT kernel (bootstrap + parallel batch). Memory
189
+ stays light — **~63 MB** resident for `import vdjtools` plus one loaded model, **~123 MB** with all
190
+ seven bundled models resident. Reproduce with `appendix/bench_pgen.py` and the `test_*_benchmark.py`
191
+ suites (`RUN_BENCHMARK=1`).
192
+
193
+ ## Capabilities (see [ROADMAP.md](ROADMAP.md) and the [API reference](https://docs.isalgo.dev/vdjtools/))
194
+
195
+ - **IO** — canonical clonotype frame on AIRR **junction** columns (`junction_nt` / `junction_aa`);
196
+ readers for native vdjtools, AIRR Rearrangement TSV, and Parquet, plus format-detecting converters
197
+ for MiXcr (v1/2 + v3/4), MiGec, Adaptive immunoSEQ (v1/v2), IMGT/HighV-QUEST, Vidjil, and RTCR
198
+ ([`vdjtools.io.convert`](python/vdjtools/io/convert.py)); metadata-driven batch + hive-partitioned cohorts.
199
+ - **Model** — native V(D)J recombination model: generation probability (Pgen — nt, aa,
200
+ 1-mismatch, V/J-agnostic, **thread-parallel batch**), sequence generation, and EM inference, all in a
201
+ native (pybind11) core. Supersedes OLGA and IGoR: arda-driven scenario enumeration, polars marginal
202
+ tables, read-parallelised EM, and **tandem-D (D-D)** support. Concordant with OLGA across all 7 loci;
203
+ precomputed OLGA + real-data-learned models bundled ([`load_bundled`](python/vdjtools/model/bundled.py)).
125
204
  - **Stats** — diversity (Chao1/Shannon/Simpson/…), spectratype, V/J/VJ usage.
126
205
  - **Features** — CDR physicochemical profiles, k-mer / V+k-mer summaries.
127
- - **Overlap** — sample overlap and TCRnet (via vdjmatch/seqtree).
206
+ - **Overlap** — sample overlap and TCRnet (via vdjmatch/seqtree), similarity-aware overlap, clustering.
128
207
  - **Preprocess** — downsampling, error-correction, VJ-usage batch-effect correction, pooling/joining.
129
208
  - **Biomarker** — incidence-based association (Fisher) vs HLA / condition / chain-pairing; metaclonotypes.
130
- - **Single-cell** — AIRR Cell / 10x interoperability.
209
+ - **Single-cell** — AIRR Cell / 10x interoperability, chain pairing + QC, and paired α/β Pgen.
131
210
 
132
211
  ## License
133
212
 
@@ -0,0 +1,154 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="assets/vdjtools_dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="assets/vdjtools_light.svg">
5
+ <!-- Absolute PNG fallback: PyPI strips <picture>/<source> and cannot render a relative or
6
+ raw-served SVG, so the logo must be an absolute-URL raster here. GitHub uses the SVG sources. -->
7
+ <img alt="vdjtools" src="https://raw.githubusercontent.com/antigenomics/vdjtools/master/assets/vdjtools_dark.png" width="320">
8
+ </picture>
9
+ </p>
10
+
11
+ <h1 align="center">vdjtools — immune-repertoire analysis</h1>
12
+
13
+ <p align="center">
14
+ <a href="https://pypi.org/project/vdjtools/"><img alt="PyPI" src="https://img.shields.io/pypi/v/vdjtools"></a>
15
+ <a href="https://github.com/antigenomics/vdjtools/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/antigenomics/vdjtools/actions/workflows/ci.yml/badge.svg"></a>
16
+ <a href="https://docs.isalgo.dev/vdjtools/"><img alt="docs" src="https://github.com/antigenomics/vdjtools/actions/workflows/docs.yml/badge.svg"></a>
17
+ <img alt="python" src="https://img.shields.io/badge/python-3.10%2B-blue">
18
+ <img alt="license" src="https://img.shields.io/badge/license-GPLv3-green">
19
+ </p>
20
+
21
+ TCR/BCR immune-repertoire analysis — a clean-room **Python + C++** rewrite of the legacy
22
+ Groovy/Java [vdjtools](https://doi.org/10.1371/journal.pcbi.1004503), standardised on the
23
+ **AIRR schema** and **polars** DataFrames with minimal object-orientation.
24
+
25
+ Built on the antigenomics ecosystem:
26
+ [seqtree](https://github.com/antigenomics/seqtree) (fuzzy search / e-value engine),
27
+ [vdjmatch](https://github.com/antigenomics/vdjmatch) (overlap + TCRnet),
28
+ [arda](https://github.com/antigenomics/arda) (AIRR annotation + markup repair).
29
+
30
+ > **Status: `v2.2.0`** — the native V(D)J model engine plus the full analytics suite (diversity,
31
+ > overlap/TCRnet, preprocessing, biomarkers, single-cell), CDR features, and legacy-format ingestion
32
+ > (MiXcr, MiGec, immunoSEQ, IMGT/HighV-QUEST, Vidjil, RTCR). Clonotype columns follow the AIRR
33
+ > **junction** convention (`junction_nt` / `junction_aa`). The legacy v1.x tool lives on the
34
+ > [`legacy-1.x`](https://github.com/antigenomics/vdjtools/tree/legacy-1.x) branch and its releases
35
+ > remain available under the repository tags (`v0.0.1` … `1.2.1`).
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install vdjtools
41
+ ```
42
+
43
+ Prebuilt wheels ship for CPython 3.10–3.13 on Linux, macOS (Apple Silicon), and Windows; the
44
+ native `_core` C++ extension is bundled (the source distribution compiles it on install). The
45
+ pure-analytics paths (diversity / spectratype / usage / overlap) work out of the box; the model
46
+ and annotation paths additionally pull in [arda](https://github.com/antigenomics/arda) (MMseqs2):
47
+
48
+ ```bash
49
+ pip install "vdjtools[model]"
50
+ ```
51
+
52
+ ### Development
53
+
54
+ ```bash
55
+ conda env create -f environment.yml # python + mmseqs2 (arda backend) + C++ toolchain
56
+ conda activate vdjtools
57
+ pip install -e ".[dev,test]" # builds the _core C++ extension
58
+ ```
59
+
60
+ Or run the bootstrap script: `bash setup.sh --dev-parents --tests`.
61
+
62
+ ## Quickstart — recombination model engine
63
+
64
+ Precomputed models for all **7 human loci** ship in the wheel — no OLGA or download needed:
65
+
66
+ ```python
67
+ from vdjtools.model import load_bundled, native
68
+ from vdjtools.model.generate import generate
69
+
70
+ model = load_bundled("TRB", source="olga") # or source="learned" (fit to real repertoires)
71
+
72
+ native.pgen_nt(model, "TGTGCCAGCAGC...") # nucleotide generation probability (native C++)
73
+ native.pgen_aa(model, "CASSLAPGATNEKLFF") # amino-acid Pgen (codon-marginalised)
74
+ native.pgen_aa(model, "CASSLAPGATNEKLFF", mismatches=1) # + the whole Hamming-1 ball
75
+ native.pgen_aa_batch(model, seqs, mismatches=1, threads=0) # Pgen over many CDR3s, thread-parallel (~11×)
76
+ generate(model, 1000) # sample a repertoire -> polars DataFrame
77
+ ```
78
+
79
+ Matches OLGA's Pgen to machine precision across all 7 loci, and adds tandem-D (D-D) support that
80
+ OLGA/IGoR lack. Learn a model from your own out-of-frame reads with `model.infer.infer_native`.
81
+
82
+ Explore any model's recombination **Bayes net** interactively (entropy, mutual information, marginals):
83
+
84
+ ```bash
85
+ pip install "vdjtools[examples]"
86
+ marimo edit notebooks/model_explorer.py
87
+ ```
88
+
89
+ ## Command line
90
+
91
+ `pip install vdjtools` installs the `vdjtools` command — the model engine (OLGA/IGoR-style) and the
92
+ repertoire analytics (over sample files or a metadata table, like the legacy tool):
93
+
94
+ ```bash
95
+ # recombination model engine — built-in models for all 7 loci (no download)
96
+ vdjtools models # list the bundled models
97
+ vdjtools generate -m TRB -n 1000 -o gen.tsv # sample sequences (cf. olga-generate_sequences)
98
+ vdjtools pgen seqs.tsv -m TRB -o pgen.tsv # Pgen per CDR3 (cf. olga-compute_pgen)
99
+ vdjtools pgen seqs.tsv -m TRB --mismatches 1 # + the Hamming-1 ball; --v-col/--j-col to condition
100
+
101
+ # repertoire analytics — sample files, or a cohort via -m/--metadata + --base-dir
102
+ vdjtools diversity sampleA.tsv sampleB.tsv -o diversity.tsv
103
+ vdjtools overlap *.tsv -o overlap.tsv
104
+ vdjtools segment-usage *.tsv --segment v -o usage.tsv
105
+ vdjtools spectratype *.tsv -o spectra.tsv
106
+ ```
107
+
108
+ Native vdjtools and AIRR Rearrangement inputs are auto-detected; every command writes TSV to `-o`
109
+ (or stdout, so it pipes). Run `vdjtools <command> --help` for options.
110
+
111
+ ## Performance
112
+
113
+ The Pgen / generation / EM / diversity hot paths are a native C++ (pybind11) core; everything else is
114
+ polars. Amino-acid Pgen matches OLGA to machine precision (1e-15) across all 7 loci while being
115
+ several times faster, and the built-in models keep the resident set small. Single thread, Apple M3
116
+ (arm64), bundled human TRB model:
117
+
118
+ | operation | throughput | vs OLGA |
119
+ |---|---|---|
120
+ | nucleotide Pgen (single-D VDJ) | **~0.5 ms/seq** | **9×** |
121
+ | amino-acid Pgen | **~0.6–0.9 ms/seq** | **8.6×** |
122
+ | Pgen + Hamming-1 ball (1 substitution) | **~15 ms/seq** | **8.7×** |
123
+ | sequence generation | **~32 000 seq/s** | — |
124
+
125
+ Nucleotide Pgen (via the same transfer-matrix DP as the aa path — an in-frame CDR3 is an aa query with
126
+ one codon fixed per position) is exact vs OLGA across all loci. Batched Pgen / 1-mismatch over many
127
+ CDR3s parallelises over sequences (`native.pgen_aa_batch`, **~11× on 16 cores**, bitwise-identical to
128
+ the serial result); the EM E-step parallelises over reads (~6.7× on 8 threads); diversity/rarefaction
129
+ run on a native iNEXT kernel (bootstrap + parallel batch). Memory
130
+ stays light — **~63 MB** resident for `import vdjtools` plus one loaded model, **~123 MB** with all
131
+ seven bundled models resident. Reproduce with `appendix/bench_pgen.py` and the `test_*_benchmark.py`
132
+ suites (`RUN_BENCHMARK=1`).
133
+
134
+ ## Capabilities (see [ROADMAP.md](ROADMAP.md) and the [API reference](https://docs.isalgo.dev/vdjtools/))
135
+
136
+ - **IO** — canonical clonotype frame on AIRR **junction** columns (`junction_nt` / `junction_aa`);
137
+ readers for native vdjtools, AIRR Rearrangement TSV, and Parquet, plus format-detecting converters
138
+ for MiXcr (v1/2 + v3/4), MiGec, Adaptive immunoSEQ (v1/v2), IMGT/HighV-QUEST, Vidjil, and RTCR
139
+ ([`vdjtools.io.convert`](python/vdjtools/io/convert.py)); metadata-driven batch + hive-partitioned cohorts.
140
+ - **Model** — native V(D)J recombination model: generation probability (Pgen — nt, aa,
141
+ 1-mismatch, V/J-agnostic, **thread-parallel batch**), sequence generation, and EM inference, all in a
142
+ native (pybind11) core. Supersedes OLGA and IGoR: arda-driven scenario enumeration, polars marginal
143
+ tables, read-parallelised EM, and **tandem-D (D-D)** support. Concordant with OLGA across all 7 loci;
144
+ precomputed OLGA + real-data-learned models bundled ([`load_bundled`](python/vdjtools/model/bundled.py)).
145
+ - **Stats** — diversity (Chao1/Shannon/Simpson/…), spectratype, V/J/VJ usage.
146
+ - **Features** — CDR physicochemical profiles, k-mer / V+k-mer summaries.
147
+ - **Overlap** — sample overlap and TCRnet (via vdjmatch/seqtree), similarity-aware overlap, clustering.
148
+ - **Preprocess** — downsampling, error-correction, VJ-usage batch-effect correction, pooling/joining.
149
+ - **Biomarker** — incidence-based association (Fisher) vs HLA / condition / chain-pairing; metaclonotypes.
150
+ - **Single-cell** — AIRR Cell / 10x interoperability, chain pairing + QC, and paired α/β Pgen.
151
+
152
+ ## License
153
+
154
+ GPL-3.0-or-later.
@@ -64,6 +64,13 @@ double pgen_aa(const PackedModel& m, const std::string& aa, int v_idx, int j_idx
64
64
  // via the inclusion-exclusion identity over per-position wildcards. v_idx/j_idx as above.
65
65
  double pgen_aa_hamming1(const PackedModel& m, const std::string& aa, int v_idx, int j_idx);
66
66
 
67
+ // Batch aa Pgen over many sequences, parallelized across sequences (mismatches: 0 = exact,
68
+ // 1 = Hamming-1 ball). Bitwise-identical to the per-sequence calls. Per-sequence v/j indices;
69
+ // empty v_idxs/j_idxs → all -1 (gene-agnostic). nthreads=0 → auto (hw-2).
70
+ std::vector<double> pgen_aa_batch(const PackedModel& m, const std::vector<std::string>& seqs,
71
+ const std::vector<int>& v_idxs, const std::vector<int>& j_idxs,
72
+ int mismatches, int nthreads);
73
+
67
74
  // EM soft counts — one accumulator per event realization, laid out like the PackedModel prob
68
75
  // arrays so the Python M-step can renormalize them directly.
69
76
  struct Counts {
@@ -85,12 +92,15 @@ Counts make_counts(const PackedModel& m);
85
92
  // in a fixed order); 0 = auto (hardware_concurrency - 2). Small batches run single-threaded so their
86
93
  // result stays bitwise-identical. The soft counts are exact regardless of thread count (up to the
87
94
  // float summation order, which the fixed reduction keeps deterministic per ``nthreads``).
95
+ // ``dd_allowed`` optionally gates the tandem (n_D=2) E-step per read (1 = may be tandem, 0 = single-D
96
+ // only); empty = every read may be tandem. Used to anchor D-D learning to arda's tandem calls.
88
97
  double estep_batch(const PackedModel& m,
89
98
  const std::vector<std::vector<int8_t>>& seqs,
90
99
  const std::vector<std::vector<int>>& vmasks,
91
100
  const std::vector<std::vector<int>>& jmasks,
92
101
  const std::vector<std::vector<int>>& dmasks,
93
102
  Counts& counts,
94
- int nthreads = 0);
103
+ int nthreads = 0,
104
+ const std::vector<int>& dd_allowed = {});
95
105
 
96
106
  } // namespace vdjtools
@@ -0,0 +1,142 @@
1
+ # vdjtools — interactive recombination-model explorer.
2
+ # Reactive marimo app: pick a locus and model source, see its Bayes net (nodes = marginal entropy H,
3
+ # edges = mutual information I), the per-event entropy / MI tables, a marginal distribution, and an
4
+ # OLGA-vs-learned comparison. Run with: marimo edit notebooks/model_explorer.py
5
+ import marimo
6
+
7
+ __generated_with = "0.23.14"
8
+ app = marimo.App(width="medium")
9
+
10
+
11
+ @app.cell
12
+ def _():
13
+ import marimo as mo
14
+ return (mo,)
15
+
16
+
17
+ @app.cell
18
+ def _(mo):
19
+ import subprocess
20
+
21
+ import matplotlib.pyplot as plt
22
+ import polars as pl
23
+
24
+ from vdjtools.model import analyze, list_bundled, load_bundled
25
+ return analyze, list_bundled, load_bundled, mo, pl, plt, subprocess
26
+
27
+
28
+ @app.cell
29
+ def _(mo):
30
+ mo.md(
31
+ """
32
+ # V(D)J recombination model explorer
33
+
34
+ Explore any bundled recombination model as a **Bayes net** — nodes are recombination events
35
+ (sized/annotated by their marginal Shannon entropy *H*), edges are the conditioning
36
+ dependencies (annotated by mutual information *I*). Compare the **OLGA** bootstrap models to
37
+ the **EM-learned** models fit to real out-of-frame repertoires.
38
+ """
39
+ )
40
+ return
41
+
42
+
43
+ @app.cell
44
+ def _(list_bundled, mo):
45
+ avail = list_bundled()
46
+ source = mo.ui.dropdown(list(avail), value="olga", label="Model source")
47
+ return avail, source
48
+
49
+
50
+ @app.cell
51
+ def _(avail, mo, source):
52
+ loci = avail.get(source.value, [])
53
+ locus = mo.ui.dropdown(loci, value=(loci[0] if loci else None), label="Locus")
54
+ mo.hstack([source, locus], justify="start", gap=2)
55
+ return (locus,)
56
+
57
+
58
+ @app.cell
59
+ def _(load_bundled, locus, mo, source):
60
+ mo.stop(locus.value is None, mo.md("*No bundled models found — build them first.*"))
61
+ model = load_bundled(locus.value, source.value)
62
+ mo.md(f"**{locus.value}** · *{source.value}* · chain **{model.chain_type}** · "
63
+ f"{model.genomic['genes_v'].height} V / {model.genomic['genes_j'].height} J genes")
64
+ return (model,)
65
+
66
+
67
+ @app.cell
68
+ def _(analyze, mo, model, subprocess):
69
+ # Render the Bayes net to inline SVG via the graphviz `dot` CLI (no python-graphviz dep).
70
+ dot = analyze.bayes_net_dot(model)
71
+ try:
72
+ svg = subprocess.run(["dot", "-Tsvg"], input=dot, capture_output=True, text=True, check=True).stdout
73
+ svg = svg[svg.index("<svg"):] # drop the <?xml?> / <!DOCTYPE> preamble for clean inline embedding
74
+ bn = mo.Html(svg)
75
+ except (FileNotFoundError, subprocess.CalledProcessError):
76
+ bn = mo.md("`dot` (graphviz) not found — showing the DOT source instead:").callout("warn")
77
+ bn = mo.vstack([bn, mo.plain_text(dot)])
78
+ mo.vstack([mo.md("### Bayes net &nbsp; *(node = event · H bits; edge = conditioning · I bits)*"), bn])
79
+ return
80
+
81
+
82
+ @app.cell
83
+ def _(analyze, mo, model):
84
+ ent = analyze.entropy_table(model)
85
+ mi = analyze.mutual_information(model)
86
+ mo.hstack([
87
+ mo.vstack([mo.md("### Marginal entropy *H* (bits)"), ent]),
88
+ mo.vstack([mo.md("### Mutual information *I* (bits)"), mi]),
89
+ ], widths=[1, 1], gap=2)
90
+ return
91
+
92
+
93
+ @app.cell
94
+ def _(mo, model):
95
+ # Pick a marginal to plot (insertion length or a gene-usage table).
96
+ plottable = [e for e in ("vd_ins", "dj_ins", "vj_ins", "dd_ins", "d_del", "n_d", "v_choice", "j_choice")
97
+ if e in model.tables]
98
+ event = mo.ui.dropdown(plottable, value=plottable[0] if plottable else None, label="Marginal to plot")
99
+ event
100
+ return (event,)
101
+
102
+
103
+ @app.cell
104
+ def _(event, mo, model, plt):
105
+ mo.stop(event.value is None)
106
+ df = model.tables[event.value]
107
+ fig, ax = plt.subplots(figsize=(7, 3))
108
+ cols = df.columns
109
+ if "length" in cols:
110
+ ax.bar(df["length"], df["p"]); ax.set_xlabel("insertion length (nt)")
111
+ elif "n_d" in cols:
112
+ ax.bar(df["n_d"].cast(str), df["p"]); ax.set_xlabel("number of D segments")
113
+ elif "ndel5" in cols: # 2D deletion: marginal over 3'
114
+ agg = df.group_by("ndel5").agg(__import__("polars").col("p").sum()).sort("ndel5")
115
+ ax.bar(agg["ndel5"], agg["p"]); ax.set_xlabel("D 5' deletion (nt; neg = P-nt)")
116
+ else: # gene usage: top 15 by probability
117
+ top = df.sort("p", descending=True).head(15)
118
+ gcol = [c for c in cols if c.endswith("_allele")][-1]
119
+ ax.barh(top[gcol].to_list()[::-1], top["p"].to_list()[::-1]); ax.set_xlabel("P")
120
+ ax.set_ylabel("probability"); ax.set_title(f"{event.value}"); fig.tight_layout()
121
+ ax
122
+ return
123
+
124
+
125
+ @app.cell
126
+ def _(analyze, avail, load_bundled, locus, mo):
127
+ # OLGA vs learned entropy side-by-side, when both are available for this locus.
128
+ both = {s: load_bundled(locus.value, s) for s in ("olga", "learned")
129
+ if locus.value in avail.get(s, [])}
130
+ if len(both) == 2:
131
+ import polars as _pl
132
+ cmp = analyze.compare_entropy(both).with_columns(
133
+ (_pl.col("learned") - _pl.col("olga")).round(3).alias("Δ (learned−olga)"))
134
+ out = mo.vstack([mo.md("### OLGA vs learned — marginal entropy *H* (bits)"), cmp])
135
+ else:
136
+ out = mo.md("*Load a locus present in both `olga` and `learned` to see the comparison.*").callout()
137
+ out
138
+ return
139
+
140
+
141
+ if __name__ == "__main__":
142
+ app.run()
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "vdjtools" # if the PyPI name is taken, fall back to a distinct dist name (cf. arda -> arda-mapper)
7
- version = "2.0.0a2"
7
+ version = "2.2.0"
8
8
  description = "TCR/BCR repertoire analysis — Pgen/generation/inference, diversity, overlap, biomarkers (Python + C++)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -26,21 +26,24 @@ dependencies = [
26
26
  "polars>=1.0",
27
27
  "numpy",
28
28
  "scipy",
29
+ "typer>=0.12", # the `vdjtools` CLI (Phase 8) is a core entry point
29
30
  ]
30
31
 
32
+ [project.scripts]
33
+ vdjtools = "vdjtools.cli:app"
34
+
31
35
  [project.optional-dependencies]
32
36
  model = ["arda-mapper>=2.5"] # Phase 1: scenario enumeration + markup repair (brings mmseqs2)
33
37
  overlap = ["vdjmatch>=0.0.1", "seqtree>=0.3", "scikit-learn"] # Phase 4: overlap + TCRnet (brings the seqtree engine); sklearn for MDS clustering; seqtree for similarity-weighted (TINA) overlap
34
38
  preprocess = ["seqtree>=0.3"] # Phase 5: freq-based error correction (near-neighbour search)
35
39
  sc = ["scikit-learn", "pyyaml", "anndata", "huggingface_hub"] # Phase 7: single-cell — sklearn for cluster_eval contingency, pyyaml for AIRR Cell export, anndata for the scverse bridge (to_anndata), HF for the dCODE benchmark fetch (tests only)
36
- cli = ["typer>=0.12"] # Phase 8
37
40
  examples = ["marimo", "huggingface_hub", "matplotlib", "scikit-learn"] # example notebooks (scipy is a base dep)
38
41
  oracle = ["olga"] # Pgen cross-check oracle (tests only)
39
42
  test = ["pytest>=7.4", "pytest-cov"]
40
43
  bench = ["huggingface_hub"] # test-only: real-data fetch; never a runtime dep
41
44
  docs = ["sphinx>=7", "pydata-sphinx-theme>=0.15", "nbsphinx"]
42
45
  dev = ["ruff", "pytest>=7.4", "pybind11>=2.12"]
43
- all = ["arda-mapper>=2.5", "vdjmatch>=0.0.1", "typer>=0.12"]
46
+ all = ["arda-mapper>=2.5", "vdjmatch>=0.0.1"]
44
47
 
45
48
  [project.urls]
46
49
  Homepage = "https://github.com/antigenomics/vdjtools"
@@ -13,5 +13,5 @@ vdjmatch/seqtree) until a feature that needs them is used.
13
13
  """
14
14
  from ._core import hamming
15
15
 
16
- __version__ = "2.0.0"
16
+ __version__ = "2.2.0"
17
17
  __all__ = ["hamming", "__version__"]
@@ -0,0 +1,8 @@
1
+ """vdjtools.biomarker — Incidence-based association (Fisher) and metaclonotype grouping."""
2
+ from .fisher import fisher_association
3
+ from .metaclonotype import metaclonotypes
4
+
5
+ __all__ = [
6
+ "fisher_association", # Fisher-exact clonotype-incidence vs phenotype association
7
+ "metaclonotypes", # edit-scope metaclonotype grouping (1mm matching)
8
+ ]