starplast 0.42.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 (282) hide show
  1. starplast-0.42.0/LICENSE +21 -0
  2. starplast-0.42.0/PKG-INFO +66 -0
  3. starplast-0.42.0/README.md +139 -0
  4. starplast-0.42.0/packaging/PYPI_README.md +19 -0
  5. starplast-0.42.0/pyproject.toml +69 -0
  6. starplast-0.42.0/setup.cfg +4 -0
  7. starplast-0.42.0/starplast/__init__.py +7 -0
  8. starplast-0.42.0/starplast/__main__.py +5 -0
  9. starplast-0.42.0/starplast/ambient.py +205 -0
  10. starplast-0.42.0/starplast/analysis_panel.py +2653 -0
  11. starplast-0.42.0/starplast/annotations.py +214 -0
  12. starplast-0.42.0/starplast/app.py +4225 -0
  13. starplast-0.42.0/starplast/archive.py +304 -0
  14. starplast-0.42.0/starplast/benchmark.py +98 -0
  15. starplast-0.42.0/starplast/build_graph.py +626 -0
  16. starplast-0.42.0/starplast/cellcycle.py +249 -0
  17. starplast-0.42.0/starplast/celldiagram.py +650 -0
  18. starplast-0.42.0/starplast/chat.py +374 -0
  19. starplast-0.42.0/starplast/chromatin.py +169 -0
  20. starplast-0.42.0/starplast/clustering.py +549 -0
  21. starplast-0.42.0/starplast/codons.py +206 -0
  22. starplast-0.42.0/starplast/console.py +238 -0
  23. starplast-0.42.0/starplast/corpus.py +156 -0
  24. starplast-0.42.0/starplast/data/antisense_level.tsv +8141 -0
  25. starplast-0.42.0/starplast/data/cdpk1_substrates.tsv +375 -0
  26. starplast-0.42.0/starplast/data/crosslink_models.parquet +0 -0
  27. starplast-0.42.0/starplast/data/crosslink_partners.tsv +495 -0
  28. starplast-0.42.0/starplast/data/escrt_recruitment_maxvit.tsv +9 -0
  29. starplast-0.42.0/starplast/data/escrt_recruitment_xgboost.tsv +14 -0
  30. starplast-0.42.0/starplast/data/graph.npz +0 -0
  31. starplast-0.42.0/starplast/data/hf_release/README.md +39 -0
  32. starplast-0.42.0/starplast/data/hf_release/studies.parquet +0 -0
  33. starplast-0.42.0/starplast/data/hf_release/study_gene_membership.parquet +0 -0
  34. starplast-0.42.0/starplast/data/host_bridges.parquet +0 -0
  35. starplast-0.42.0/starplast/data/host_interactions.parquet +0 -0
  36. starplast-0.42.0/starplast/data/host_proteins.parquet +0 -0
  37. starplast-0.42.0/starplast/data/icons/Animal_cells.svg +2464 -0
  38. starplast-0.42.0/starplast/data/icons/Apicomplexa_cells.svg +1250 -0
  39. starplast-0.42.0/starplast/data/icons/logo_01_constellation_1.svg +1 -0
  40. starplast-0.42.0/starplast/data/icons/logo_02_constellation_2.svg +1 -0
  41. starplast-0.42.0/starplast/data/icons/logo_03_constellation_3.svg +1 -0
  42. starplast-0.42.0/starplast/data/icons/logo_04_constellation_4.svg +1 -0
  43. starplast-0.42.0/starplast/data/icons/logo_05_constellation_5.svg +1 -0
  44. starplast-0.42.0/starplast/data/icons/logo_06_constellation_6.svg +1 -0
  45. starplast-0.42.0/starplast/data/icons/logo_07_constellation_7.svg +1 -0
  46. starplast-0.42.0/starplast/data/icons/logo_08_constellation_8.svg +1 -0
  47. starplast-0.42.0/starplast/data/icons/logo_09_apicoplast_1.svg +1 -0
  48. starplast-0.42.0/starplast/data/icons/logo_10_apicoplast_2.svg +1 -0
  49. starplast-0.42.0/starplast/data/icons/logo_11_apicoplast_3.svg +1 -0
  50. starplast-0.42.0/starplast/data/icons/logo_12_apicoplast_4.svg +1 -0
  51. starplast-0.42.0/starplast/data/icons/logo_13_apicoplast_5.svg +1 -0
  52. starplast-0.42.0/starplast/data/icons/logo_14_apicoplast_6.svg +1 -0
  53. starplast-0.42.0/starplast/data/icons/logo_15_crescent_1.svg +1 -0
  54. starplast-0.42.0/starplast/data/icons/logo_16_crescent_2.svg +1 -0
  55. starplast-0.42.0/starplast/data/icons/logo_17_crescent_3.svg +1 -0
  56. starplast-0.42.0/starplast/data/icons/logo_18_crescent_4.svg +1 -0
  57. starplast-0.42.0/starplast/data/icons/logo_19_crescent_5.svg +1 -0
  58. starplast-0.42.0/starplast/data/icons/logo_20_crescent_6.svg +1 -0
  59. starplast-0.42.0/starplast/data/icons/logo_21_orbit_1.svg +1 -0
  60. starplast-0.42.0/starplast/data/icons/logo_22_orbit_2.svg +1 -0
  61. starplast-0.42.0/starplast/data/icons/logo_23_orbit_3.svg +1 -0
  62. starplast-0.42.0/starplast/data/icons/logo_24_orbit_4.svg +1 -0
  63. starplast-0.42.0/starplast/data/icons/logo_25_orbit_5.svg +1 -0
  64. starplast-0.42.0/starplast/data/icons/logo_26_orbit_6.svg +1 -0
  65. starplast-0.42.0/starplast/data/icons/logo_27_letter_s_1.svg +1 -0
  66. starplast-0.42.0/starplast/data/icons/logo_28_letter_s_2.svg +1 -0
  67. starplast-0.42.0/starplast/data/icons/logo_29_letter_s_3.svg +1 -0
  68. starplast-0.42.0/starplast/data/icons/logo_30_letter_s_4.svg +1 -0
  69. starplast-0.42.0/starplast/data/icons/logo_31_letter_s_5.svg +1 -0
  70. starplast-0.42.0/starplast/data/icons/logo_32_letter_s_6.svg +1 -0
  71. starplast-0.42.0/starplast/data/icons/logo_33_letter_s_7.svg +1 -0
  72. starplast-0.42.0/starplast/data/icons/logo_34_dark_field_1.svg +1 -0
  73. starplast-0.42.0/starplast/data/icons/logo_35_dark_field_2.svg +1 -0
  74. starplast-0.42.0/starplast/data/icons/logo_36_dark_field_3.svg +1 -0
  75. starplast-0.42.0/starplast/data/icons/logo_37_dark_field_4.svg +1 -0
  76. starplast-0.42.0/starplast/data/icons/logo_38_dark_field_5.svg +1 -0
  77. starplast-0.42.0/starplast/data/icons/logo_39_dark_field_6.svg +1 -0
  78. starplast-0.42.0/starplast/data/icons/logo_40_dark_field_7.svg +1 -0
  79. starplast-0.42.0/starplast/data/icons/logo_41_galaxy_1.svg +1 -0
  80. starplast-0.42.0/starplast/data/icons/logo_42_galaxy_2.svg +1 -0
  81. starplast-0.42.0/starplast/data/icons/logo_43_galaxy_3.svg +1 -0
  82. starplast-0.42.0/starplast/data/icons/logo_44_galaxy_4.svg +1 -0
  83. starplast-0.42.0/starplast/data/icons/logo_45_galaxy_5.svg +1 -0
  84. starplast-0.42.0/starplast/data/icons/logo_46_galaxy_6.svg +1 -0
  85. starplast-0.42.0/starplast/data/icons/logo_47_galaxy_7.svg +1 -0
  86. starplast-0.42.0/starplast/data/icons/logo_48_galaxy_8.svg +1 -0
  87. starplast-0.42.0/starplast/data/icons/logo_49_galaxy_9.svg +1 -0
  88. starplast-0.42.0/starplast/data/icons/starplast.svg +1 -0
  89. starplast-0.42.0/starplast/data/iedb_bcell_epitopes.tsv +35 -0
  90. starplast-0.42.0/starplast/data/interaction_studies.parquet +0 -0
  91. starplast-0.42.0/starplast/data/interaction_study_members.parquet +0 -0
  92. starplast-0.42.0/starplast/data/m6a_peaks.tsv +867 -0
  93. starplast-0.42.0/starplast/data/melting_temperature.tsv +3194 -0
  94. starplast-0.42.0/starplast/data/mentions.parquet +0 -0
  95. starplast-0.42.0/starplast/data/metabolites.parquet +0 -0
  96. starplast-0.42.0/starplast/data/mrna_stability.tsv +427 -0
  97. starplast-0.42.0/starplast/data/myristoylome.tsv +66 -0
  98. starplast-0.42.0/starplast/data/nodes.parquet +0 -0
  99. starplast-0.42.0/starplast/data/pf_graph.npz +0 -0
  100. starplast-0.42.0/starplast/data/pf_host_bridges.parquet +0 -0
  101. starplast-0.42.0/starplast/data/pf_mentions.parquet +0 -0
  102. starplast-0.42.0/starplast/data/pf_nodes.parquet +0 -0
  103. starplast-0.42.0/starplast/data/plasmodb_cds.tsv.gz +0 -0
  104. starplast-0.42.0/starplast/data/plasmodb_identity.tsv +5792 -0
  105. starplast-0.42.0/starplast/data/pvm_proximity.tsv +1275 -0
  106. starplast-0.42.0/starplast/data/questions.json +3543 -0
  107. starplast-0.42.0/starplast/data/secretome_partition.tsv +172 -0
  108. starplast-0.42.0/starplast/data/sexual_stages.tsv +4567 -0
  109. starplast-0.42.0/starplast/data/slot_hierarchy.json +1968 -0
  110. starplast-0.42.0/starplast/data/slots.json +12631 -0
  111. starplast-0.42.0/starplast/data/structure_search.parquet +0 -0
  112. starplast-0.42.0/starplast/data/structure_search_perlabel.parquet +0 -0
  113. starplast-0.42.0/starplast/data/study_licenses.parquet +0 -0
  114. starplast-0.42.0/starplast/data/toxodb_arginine_methylation.tsv +369 -0
  115. starplast-0.42.0/starplast/data/toxodb_cds.tsv.gz +0 -0
  116. starplast-0.42.0/starplast/data/toxodb_ec_numbers.tsv +8843 -0
  117. starplast-0.42.0/starplast/data/toxodb_enteroepithelial.tsv +7799 -0
  118. starplast-0.42.0/starplast/data/toxodb_epitopes.tsv +223 -0
  119. starplast-0.42.0/starplast/data/toxodb_gene_location.tsv +8843 -0
  120. starplast-0.42.0/starplast/data/toxodb_h4_acetylation.tsv +7747 -0
  121. starplast-0.42.0/starplast/data/toxodb_identity.tsv +8843 -0
  122. starplast-0.42.0/starplast/data/toxodb_macrophage.tsv +8205 -0
  123. starplast-0.42.0/starplast/data/toxodb_nanopore_isoforms.tsv +814 -0
  124. starplast-0.42.0/starplast/data/toxodb_palmitome_hydroxylamine.tsv +477 -0
  125. starplast-0.42.0/starplast/data/toxodb_palmitome_palmitate.tsv +496 -0
  126. starplast-0.42.0/starplast/data/toxodb_strain_gt1.tsv +8638 -0
  127. starplast-0.42.0/starplast/data/toxodb_strain_snps.tsv +8843 -0
  128. starplast-0.42.0/starplast/data/toxodb_strain_veg.tsv +8564 -0
  129. starplast-0.42.0/starplast/datasets.py +2525 -0
  130. starplast-0.42.0/starplast/discover.py +225 -0
  131. starplast-0.42.0/starplast/discovery.py +535 -0
  132. starplast-0.42.0/starplast/drug_sensitivity.py +97 -0
  133. starplast-0.42.0/starplast/embedding.py +484 -0
  134. starplast-0.42.0/starplast/enteric.py +144 -0
  135. starplast-0.42.0/starplast/expression.py +639 -0
  136. starplast-0.42.0/starplast/fetch_names.py +112 -0
  137. starplast-0.42.0/starplast/gallery.py +351 -0
  138. starplast-0.42.0/starplast/gpu.py +277 -0
  139. starplast-0.42.0/starplast/hf_publish.py +175 -0
  140. starplast-0.42.0/starplast/holdout_cv.py +186 -0
  141. starplast-0.42.0/starplast/host.py +767 -0
  142. starplast-0.42.0/starplast/identity.py +291 -0
  143. starplast-0.42.0/starplast/iedb.py +57 -0
  144. starplast-0.42.0/starplast/importer.py +243 -0
  145. starplast-0.42.0/starplast/install_gpu.py +145 -0
  146. starplast-0.42.0/starplast/interaction_studies.py +220 -0
  147. starplast-0.42.0/starplast/interactions.py +179 -0
  148. starplast-0.42.0/starplast/interpret.py +227 -0
  149. starplast-0.42.0/starplast/jobs.py +221 -0
  150. starplast-0.42.0/starplast/lighting.py +612 -0
  151. starplast-0.42.0/starplast/lipids.py +159 -0
  152. starplast-0.42.0/starplast/literature.py +197 -0
  153. starplast-0.42.0/starplast/localization.py +188 -0
  154. starplast-0.42.0/starplast/lod.py +148 -0
  155. starplast-0.42.0/starplast/logging_util.py +203 -0
  156. starplast-0.42.0/starplast/metabolites.py +149 -0
  157. starplast-0.42.0/starplast/methods.py +451 -0
  158. starplast-0.42.0/starplast/metrics.py +312 -0
  159. starplast-0.42.0/starplast/objectives.py +323 -0
  160. starplast-0.42.0/starplast/optimize.py +332 -0
  161. starplast-0.42.0/starplast/palmitome.py +80 -0
  162. starplast-0.42.0/starplast/paths.py +202 -0
  163. starplast-0.42.0/starplast/pf_graph.py +460 -0
  164. starplast-0.42.0/starplast/phenotype_screen.py +136 -0
  165. starplast-0.42.0/starplast/plasmodium.py +1683 -0
  166. starplast-0.42.0/starplast/proteomics.py +245 -0
  167. starplast-0.42.0/starplast/questions.py +113 -0
  168. starplast-0.42.0/starplast/rays.py +181 -0
  169. starplast-0.42.0/starplast/recipes.py +897 -0
  170. starplast-0.42.0/starplast/report.py +354 -0
  171. starplast-0.42.0/starplast/resistance.py +124 -0
  172. starplast-0.42.0/starplast/results.py +186 -0
  173. starplast-0.42.0/starplast/runs.py +225 -0
  174. starplast-0.42.0/starplast/screens.py +547 -0
  175. starplast-0.42.0/starplast/search.py +1056 -0
  176. starplast-0.42.0/starplast/searches.py +217 -0
  177. starplast-0.42.0/starplast/slot_tree.py +461 -0
  178. starplast-0.42.0/starplast/slots.py +421 -0
  179. starplast-0.42.0/starplast/small_tables.py +185 -0
  180. starplast-0.42.0/starplast/sources.py +273 -0
  181. starplast-0.42.0/starplast/sprite.py +677 -0
  182. starplast-0.42.0/starplast/structures.py +166 -0
  183. starplast-0.42.0/starplast/theme.py +763 -0
  184. starplast-0.42.0/starplast/tuning.py +358 -0
  185. starplast-0.42.0/starplast/validate.py +369 -0
  186. starplast-0.42.0/starplast/variation.py +65 -0
  187. starplast-0.42.0/starplast/verify.py +132 -0
  188. starplast-0.42.0/starplast.egg-info/PKG-INFO +66 -0
  189. starplast-0.42.0/starplast.egg-info/SOURCES.txt +280 -0
  190. starplast-0.42.0/starplast.egg-info/dependency_links.txt +1 -0
  191. starplast-0.42.0/starplast.egg-info/entry_points.txt +4 -0
  192. starplast-0.42.0/starplast.egg-info/requires.txt +35 -0
  193. starplast-0.42.0/starplast.egg-info/top_level.txt +1 -0
  194. starplast-0.42.0/tests/test_analysis.py +267 -0
  195. starplast-0.42.0/tests/test_analysis_panel.py +2405 -0
  196. starplast-0.42.0/tests/test_annotations.py +219 -0
  197. starplast-0.42.0/tests/test_app_controls.py +1648 -0
  198. starplast-0.42.0/tests/test_app_menus.py +1224 -0
  199. starplast-0.42.0/tests/test_app_polish.py +69 -0
  200. starplast-0.42.0/tests/test_app_smoke.py +238 -0
  201. starplast-0.42.0/tests/test_archive.py +310 -0
  202. starplast-0.42.0/tests/test_benchmark.py +269 -0
  203. starplast-0.42.0/tests/test_build_graph.py +972 -0
  204. starplast-0.42.0/tests/test_cellcycle.py +282 -0
  205. starplast-0.42.0/tests/test_celldiagram.py +566 -0
  206. starplast-0.42.0/tests/test_chat_stream.py +356 -0
  207. starplast-0.42.0/tests/test_chromatin.py +245 -0
  208. starplast-0.42.0/tests/test_clustering.py +623 -0
  209. starplast-0.42.0/tests/test_codons.py +231 -0
  210. starplast-0.42.0/tests/test_dataset_scripts.py +205 -0
  211. starplast-0.42.0/tests/test_datasets.py +483 -0
  212. starplast-0.42.0/tests/test_discover_cli.py +194 -0
  213. starplast-0.42.0/tests/test_discovery.py +355 -0
  214. starplast-0.42.0/tests/test_display.py +1603 -0
  215. starplast-0.42.0/tests/test_docs.py +91 -0
  216. starplast-0.42.0/tests/test_docstrings.py +69 -0
  217. starplast-0.42.0/tests/test_documented_numbers.py +191 -0
  218. starplast-0.42.0/tests/test_drug_sensitivity.py +107 -0
  219. starplast-0.42.0/tests/test_embedding_edges.py +542 -0
  220. starplast-0.42.0/tests/test_enteric.py +160 -0
  221. starplast-0.42.0/tests/test_expression.py +790 -0
  222. starplast-0.42.0/tests/test_gallery.py +487 -0
  223. starplast-0.42.0/tests/test_gl_compat.py +143 -0
  224. starplast-0.42.0/tests/test_gpu.py +507 -0
  225. starplast-0.42.0/tests/test_holdout_cv.py +125 -0
  226. starplast-0.42.0/tests/test_host.py +841 -0
  227. starplast-0.42.0/tests/test_identity_and_corpus.py +464 -0
  228. starplast-0.42.0/tests/test_iedb.py +90 -0
  229. starplast-0.42.0/tests/test_importer.py +300 -0
  230. starplast-0.42.0/tests/test_install_gpu.py +187 -0
  231. starplast-0.42.0/tests/test_interaction_studies.py +311 -0
  232. starplast-0.42.0/tests/test_interactions.py +247 -0
  233. starplast-0.42.0/tests/test_interpret.py +227 -0
  234. starplast-0.42.0/tests/test_jobs_console_chat.py +439 -0
  235. starplast-0.42.0/tests/test_leakage_attacks.py +140 -0
  236. starplast-0.42.0/tests/test_lipids.py +230 -0
  237. starplast-0.42.0/tests/test_literature_layers.py +375 -0
  238. starplast-0.42.0/tests/test_localization.py +300 -0
  239. starplast-0.42.0/tests/test_lod.py +140 -0
  240. starplast-0.42.0/tests/test_logging.py +309 -0
  241. starplast-0.42.0/tests/test_logos.py +165 -0
  242. starplast-0.42.0/tests/test_metabolites.py +218 -0
  243. starplast-0.42.0/tests/test_methods.py +378 -0
  244. starplast-0.42.0/tests/test_metrics.py +200 -0
  245. starplast-0.42.0/tests/test_notebook.py +96 -0
  246. starplast-0.42.0/tests/test_objectives.py +238 -0
  247. starplast-0.42.0/tests/test_optimize.py +341 -0
  248. starplast-0.42.0/tests/test_packaging.py +102 -0
  249. starplast-0.42.0/tests/test_palmitome.py +136 -0
  250. starplast-0.42.0/tests/test_paths.py +274 -0
  251. starplast-0.42.0/tests/test_pf_graph.py +532 -0
  252. starplast-0.42.0/tests/test_phenotype_screen.py +200 -0
  253. starplast-0.42.0/tests/test_pipeline_end_to_end.py +386 -0
  254. starplast-0.42.0/tests/test_plasmodium.py +2652 -0
  255. starplast-0.42.0/tests/test_proteomics.py +248 -0
  256. starplast-0.42.0/tests/test_publishing.py +476 -0
  257. starplast-0.42.0/tests/test_questions.py +111 -0
  258. starplast-0.42.0/tests/test_questions_tab.py +285 -0
  259. starplast-0.42.0/tests/test_rays.py +144 -0
  260. starplast-0.42.0/tests/test_readme.py +131 -0
  261. starplast-0.42.0/tests/test_recipes.py +757 -0
  262. starplast-0.42.0/tests/test_release.py +116 -0
  263. starplast-0.42.0/tests/test_report.py +169 -0
  264. starplast-0.42.0/tests/test_resistance.py +126 -0
  265. starplast-0.42.0/tests/test_results.py +173 -0
  266. starplast-0.42.0/tests/test_runs.py +198 -0
  267. starplast-0.42.0/tests/test_screens.py +700 -0
  268. starplast-0.42.0/tests/test_search.py +1390 -0
  269. starplast-0.42.0/tests/test_searches.py +169 -0
  270. starplast-0.42.0/tests/test_slot_tree.py +264 -0
  271. starplast-0.42.0/tests/test_slots.py +770 -0
  272. starplast-0.42.0/tests/test_small_tables.py +517 -0
  273. starplast-0.42.0/tests/test_sources.py +433 -0
  274. starplast-0.42.0/tests/test_sprite.py +453 -0
  275. starplast-0.42.0/tests/test_structures.py +325 -0
  276. starplast-0.42.0/tests/test_theme_and_literature.py +297 -0
  277. starplast-0.42.0/tests/test_tuning_edges.py +377 -0
  278. starplast-0.42.0/tests/test_validate.py +350 -0
  279. starplast-0.42.0/tests/test_variation.py +110 -0
  280. starplast-0.42.0/tests/test_verify.py +205 -0
  281. starplast-0.42.0/tests/test_visual.py +171 -0
  282. starplast-0.42.0/tests/test_wheel.py +33 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Einar Olafsson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: starplast
3
+ Version: 0.42.0
4
+ Summary: Explore gene evidence and screen results in Toxoplasma and Plasmodium
5
+ Author-email: Einar Olafsson <einar.olafsson@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/EinarOlafsson/starplast
8
+ Project-URL: Documentation, https://einarolafsson.github.io/starplast/
9
+ Project-URL: Issues, https://github.com/EinarOlafsson/starplast/issues
10
+ Project-URL: Changelog, https://github.com/EinarOlafsson/starplast/blob/main/CHANGELOG.md
11
+ Keywords: toxoplasma,plasmodium,bioinformatics,CRISPR,visualization
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: numpy>=1.24
20
+ Requires-Dist: pandas>=2.0
21
+ Requires-Dist: pyarrow>=12
22
+ Requires-Dist: PyQt6>=6.5
23
+ Requires-Dist: pyqtgraph>=0.13
24
+ Requires-Dist: PyOpenGL>=3.1
25
+ Requires-Dist: scikit-learn>=1.3
26
+ Requires-Dist: umap-learn>=0.5
27
+ Requires-Dist: openpyxl>=3.1
28
+ Requires-Dist: xlrd>=2.0.1
29
+ Requires-Dist: pypdf>=4.0
30
+ Requires-Dist: networkx>=3.0
31
+ Requires-Dist: scipy>=1.10
32
+ Requires-Dist: matplotlib>=3.7
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7; extra == "dev"
35
+ Requires-Dist: build>=1.2; extra == "dev"
36
+ Requires-Dist: twine>=6; extra == "dev"
37
+ Requires-Dist: tomli>=2; python_version < "3.11" and extra == "dev"
38
+ Provides-Extra: docs
39
+ Requires-Dist: pdoc<17,>=15; extra == "docs"
40
+ Requires-Dist: markdown2<3,>=2.5; extra == "docs"
41
+ Provides-Extra: ingest
42
+ Requires-Dist: pyBigWig>=0.3; extra == "ingest"
43
+ Provides-Extra: gpu
44
+ Requires-Dist: cuml-cu12>=24.10; (sys_platform == "linux" and platform_machine == "x86_64") and extra == "gpu"
45
+ Requires-Dist: cupy-cuda12x>=13.0; (sys_platform == "linux" and platform_machine == "x86_64") and extra == "gpu"
46
+ Dynamic: license-file
47
+
48
+ # Starplast
49
+
50
+ Explore gene evidence and screen results in *Toxoplasma gondii* and
51
+ *Plasmodium falciparum*.
52
+
53
+ ```bash
54
+ pip install starplast
55
+ starplast
56
+ ```
57
+
58
+ Requires Python 3.10+, a display, and OpenGL. Built gene tables and graphs are
59
+ included for offline browsing. Analysis runs on the CPU by default.
60
+ Install `starplast[gpu]` for optional CUDA 12 acceleration on Linux x86_64.
61
+
62
+ [Documentation](https://einarolafsson.github.io/starplast/) ·
63
+ [Source code](https://github.com/EinarOlafsson/starplast)
64
+
65
+ The package contains the application, analysis modules, and cached gene data.
66
+ Use `starplast[ingest]` for optional genome-coverage import support.
@@ -0,0 +1,139 @@
1
+ # Starplast
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/starplast-wordmark-white.svg">
5
+ <img src="docs/assets/starplast-wordmark.svg" alt="Starplast — a Toxoplasma silhouette enclosing a constellation" width="520">
6
+ </picture>
7
+
8
+ [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)](#install)
9
+ [![Linux, macOS, Windows](https://img.shields.io/badge/Platforms-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey)](#install)
10
+ [![Qt / PyQt6](https://img.shields.io/badge/GUI-PyQt6-41CD52?logo=qt&logoColor=white)](https://einarolafsson.github.io/starplast/guide.html)
11
+ [![MIT license](https://img.shields.io/github/license/EinarOlafsson/starplast?color=3DA639)](LICENSE)
12
+
13
+ [![Documentation on main](https://github.com/EinarOlafsson/starplast/actions/workflows/docs.yml/badge.svg?branch=main&event=push)](https://github.com/EinarOlafsson/starplast/actions/workflows/docs.yml?query=branch%3Amain)
14
+ [![Python API](https://img.shields.io/badge/API-reference-007EC6)](https://einarolafsson.github.io/starplast/API.html)
15
+ [![GitHub issues](https://img.shields.io/github/issues/EinarOlafsson/starplast?logo=github)](https://github.com/EinarOlafsson/starplast/issues)
16
+ [![spaCR integration](https://img.shields.io/badge/spaCR-integrated-7B61A8)](https://github.com/EinarOlafsson/spacr)
17
+
18
+ Starplast is a desktop app for exploring gene evidence in *Toxoplasma gondii* and
19
+ *Plasmodium falciparum*. It brings expression, fitness screens, localization,
20
+ protein features, interactions, and literature annotations into one place.
21
+
22
+ Use it to look up a gene, investigate hits from a screen, compare groups of genes,
23
+ and choose candidates for follow-up experiments. The bundled maps contain 8,140
24
+ *T. gondii* genes and 5,720 *P. falciparum* genes, viewed separately.
25
+
26
+ [User guide](docs/guide.md) · [Python API](docs/API.md) ·
27
+ [Dataset catalogue](docs/datasets.md) · [Changes](CHANGELOG.md)
28
+
29
+ ## Install
30
+
31
+ Python 3.10 or newer is required. The desktop app needs a display and OpenGL.
32
+
33
+ ```bash
34
+ pip install starplast
35
+ starplast
36
+ ```
37
+
38
+ From a checkout:
39
+
40
+ ```bash
41
+ git clone https://github.com/EinarOlafsson/starplast.git
42
+ cd starplast
43
+ pip install -e .
44
+ starplast
45
+ ```
46
+
47
+ The default installation runs analyses on the CPU. For an NVIDIA GPU on Linux
48
+ x86_64 with a CUDA 12 compatible driver:
49
+
50
+ ```bash
51
+ pip install "starplast[gpu]"
52
+ ```
53
+
54
+ GPU dependencies are large and optional. `starplast-install-gpu` can also inspect
55
+ your driver and offer an installation command. macOS and Windows use CPU analysis;
56
+ the 3D display still uses OpenGL.
57
+
58
+ The built gene tables and graphs ship with the package. Browsing them works offline.
59
+ Protein structures are downloaded when requested and cached locally. Rebuilding
60
+ the bundled data requires the original source datasets.
61
+
62
+ ## Explore a screen
63
+
64
+ 1. Choose the organism under **File → Species**.
65
+ 2. Search for a gene ID. For *T. gondii*, **File → Import data** adds your screen results.
66
+ 3. Colour and filter the map using the measurements you want to compare.
67
+ 4. Click a gene to read its evidence and inspect each type of relationship separately.
68
+ 5. Select a group with a lasso or brush, then export the gene list for follow-up.
69
+
70
+ [![A rotating gene map with CDPK1 and its connections illuminated](docs/screenshots/map_rotation.gif)](docs/screenshots/map_rotation.png)
71
+
72
+ The *T. gondii* map with CDPK1 (`TGME49_301440`) selected. The selected gene and
73
+ its five neighbours emit light; lines show attention-corrected literature
74
+ co-mention links. Colours show compartments. [View a still image](docs/screenshots/map_rotation.png).
75
+
76
+ Each point is a gene. Its position comes from an embedding of selected features;
77
+ nearby points have similar inputs, but proximity alone does not demonstrate a
78
+ shared function or physical interaction. Colours, relationship edges, and the
79
+ evidence panel provide the context needed to interpret the map. Missing evidence
80
+ is shown separately from measured values.
81
+
82
+ The analysis panel lets you change feature sets, build embeddings, cluster genes,
83
+ and evaluate recovery of labels held out from the input. Search scores help
84
+ prioritize candidates; they are not experimental validation. See the
85
+ [user guide](docs/guide.md) for controls and analysis settings.
86
+
87
+ ## Working with spaCR
88
+
89
+ [spaCR](https://github.com/EinarOlafsson/spacr) handles microscopy and image-based
90
+ screen analysis. Its Starplast launcher installs and opens this app in a separate
91
+ Python environment. Starplast provides a place to explore the biological evidence
92
+ around those screen results. Export a gene-level table from spaCR and import it
93
+ into Starplast; launching the app does not transfer results automatically.
94
+
95
+ ## Data and reproducibility
96
+
97
+ **[Full table of included data and source links →](docs/datasets.md)**
98
+
99
+ The catalogue lists all 128 registered datasets and computed layers, with their
100
+ measurements, coverage, publication references, and links to source data or inputs.
101
+ Coverage differs by organism and assay;
102
+ absence from a literature search does not establish that a gene has never been studied.
103
+
104
+ ```bash
105
+ python -m starplast.paths # show data locations and missing cache files
106
+ python -m starplast.build_graph # rebuild from available source datasets
107
+ ```
108
+
109
+ | Variable | Purpose |
110
+ |---|---|
111
+ | `STARPLAST_CACHE` | Override the directory containing built gene tables and graphs |
112
+ | `STARPLAST_DATA` | Locate raw datasets used for rebuilding |
113
+ | `STARPLAST_STATE` | Override the directory for saved runs, annotations, and downloads |
114
+
115
+ Methods are described in [MATERIALS_AND_METHODS.md](MATERIALS_AND_METHODS.md).
116
+ [HANDOFF.md](HANDOFF.md) contains the development history and earlier design decisions.
117
+ The [repository review](docs/repository-review.md) describes the current architecture
118
+ and its limitations.
119
+
120
+ ## Development
121
+
122
+ ```bash
123
+ pip install -e ".[dev,docs]"
124
+ QT_QPA_PLATFORM=offscreen pytest tests/test_app_smoke.py tests/test_docstrings.py -q
125
+ python scripts/build_docs.py
126
+ ```
127
+
128
+ Open `docs/site/index.html` for the guide and generated API reference.
129
+ Some tests need source datasets, CUDA, or a working OpenGL context; see
130
+ [development and releases](docs/releases.md) for the release checks.
131
+
132
+ Develop on `nightly` and merge checked changes into `main`. To release, update all
133
+ package and runtime versions together with `python scripts/release.py bump 0.43.0` and update
134
+ the changelog before merging. A version increase on `main` triggers checks,
135
+ builds, PyPI publishing, and a GitHub release. Ordinary merges do not publish.
136
+ The initial PyPI account setup is described in the release guide.
137
+
138
+ The source code is distributed under the [MIT license](LICENSE).
139
+ Source datasets and third-party artwork retain their own licenses and attribution.
@@ -0,0 +1,19 @@
1
+ # Starplast
2
+
3
+ Explore gene evidence and screen results in *Toxoplasma gondii* and
4
+ *Plasmodium falciparum*.
5
+
6
+ ```bash
7
+ pip install starplast
8
+ starplast
9
+ ```
10
+
11
+ Requires Python 3.10+, a display, and OpenGL. Built gene tables and graphs are
12
+ included for offline browsing. Analysis runs on the CPU by default.
13
+ Install `starplast[gpu]` for optional CUDA 12 acceleration on Linux x86_64.
14
+
15
+ [Documentation](https://einarolafsson.github.io/starplast/) ·
16
+ [Source code](https://github.com/EinarOlafsson/starplast)
17
+
18
+ The package contains the application, analysis modules, and cached gene data.
19
+ Use `starplast[ingest]` for optional genome-coverage import support.
@@ -0,0 +1,69 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "starplast"
7
+ version = "0.42.0"
8
+ description = "Explore gene evidence and screen results in Toxoplasma and Plasmodium"
9
+ readme = "packaging/PYPI_README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{name = "Einar Olafsson", email = "einar.olafsson@gmail.com"}]
14
+ keywords = ["toxoplasma", "plasmodium", "bioinformatics", "CRISPR", "visualization"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Science/Research",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
20
+ ]
21
+ dependencies = [
22
+ "numpy>=1.24",
23
+ "pandas>=2.0",
24
+ "pyarrow>=12",
25
+ "PyQt6>=6.5",
26
+ "pyqtgraph>=0.13",
27
+ "PyOpenGL>=3.1",
28
+ "scikit-learn>=1.3",
29
+ "umap-learn>=0.5",
30
+ "openpyxl>=3.1",
31
+ "xlrd>=2.0.1",
32
+ "pypdf>=4.0",
33
+ "networkx>=3.0",
34
+ "scipy>=1.10",
35
+ "matplotlib>=3.7"
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = ["pytest>=7", "build>=1.2", "twine>=6", "tomli>=2; python_version < '3.11'"]
40
+ docs = ["pdoc>=15,<17", "markdown2>=2.5,<3"]
41
+ ingest = ["pyBigWig>=0.3"]
42
+ gpu = [
43
+ "cuml-cu12>=24.10; sys_platform == 'linux' and platform_machine == 'x86_64'",
44
+ "cupy-cuda12x>=13.0; sys_platform == 'linux' and platform_machine == 'x86_64'"
45
+ ]
46
+
47
+ [project.scripts]
48
+ starplast = "starplast.app:main"
49
+ starplast-discover = "starplast.discover:main"
50
+ starplast-install-gpu = "starplast.install_gpu:main"
51
+
52
+ [project.urls]
53
+ Homepage = "https://github.com/EinarOlafsson/starplast"
54
+ Documentation = "https://einarolafsson.github.io/starplast/"
55
+ Issues = "https://github.com/EinarOlafsson/starplast/issues"
56
+ Changelog = "https://github.com/EinarOlafsson/starplast/blob/main/CHANGELOG.md"
57
+
58
+ [tool.setuptools]
59
+ packages = ["starplast"]
60
+ include-package-data = false
61
+
62
+ [tool.setuptools.package-data]
63
+ starplast = ["data/*.npz", "data/*.parquet", "data/*.tsv", "data/*.tsv.gz", "data/*.json", "data/hf_release/*.parquet", "data/hf_release/*.md", "data/icons/*.svg"]
64
+
65
+ [tool.setuptools.exclude-package-data]
66
+ starplast = ["data/embeddings/*"]
67
+
68
+ [tool.pytest.ini_options]
69
+ markers = ["slow: runs a real build or a full documentation pass; minutes rather than seconds"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ """Explore gene evidence in Toxoplasma gondii and Plasmodium falciparum.
2
+
3
+ Use the analysis modules from Python, ``starplast-discover`` for batch searches,
4
+ or ``starplast`` for the desktop browser. The user guide and API examples are
5
+ available at https://einarolafsson.github.io/starplast/.
6
+ """
7
+ __version__ = "0.42.0"
@@ -0,0 +1,5 @@
1
+ """Run the browser with `python -m starplast`."""
2
+ from starplast.app import main
3
+
4
+ if __name__ == "__main__":
5
+ main()
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ """A drifting field of soft colour blobs, behind the panels.
3
+
4
+ Ported from spaCR's ambient background so the two programs look like one pair of tools, and kept to
5
+ the one animation that was asked for -- the blobs -- with the same controls under the same names:
6
+ speed, size, density, blur.
7
+
8
+ The design decision worth carrying across: **position is a pure function of the clock**, two
9
+ independent sines per blob rather than a random walk. A walk accumulates error, cannot be rewound,
10
+ and gives a different picture every time a frame is dropped; a function of time can be asked for any
11
+ instant, which is what makes the field paintable at whatever rate the window can manage and
12
+ identical at the same `t` on any machine.
13
+
14
+ Blobs are seeded on a jittered grid rather than uniformly at random. With a dozen of them, uniform
15
+ sampling reliably leaves one corner empty and puts three in the middle -- which reads as a bug in
16
+ the drawing rather than as a random arrangement.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import math
21
+ import random
22
+ from dataclasses import dataclass
23
+
24
+ from PyQt6 import QtCore, QtGui, QtWidgets
25
+
26
+ #: The controls, and the range each is allowed -- the same names and bounds spaCR uses, so a person
27
+ #: who has set this up once does not have to learn it twice.
28
+ SPEED_RANGE = (0.1, 4.0)
29
+ SIZE_RANGE = (0.25, 2.5)
30
+ DENSITY_RANGE = (0.25, 3.0)
31
+ BLUR_RANGE = (0.0, 3.0)
32
+ DEFAULT_SPEED = 1.0
33
+ DEFAULT_SIZE = 1.0
34
+ DEFAULT_DENSITY = 1.0
35
+ DEFAULT_BLUR = 0.0
36
+
37
+ #: How many blobs at density 1.0, and the grid they are seeded on.
38
+ BLOB_COUNT = 12
39
+ GRID = (4, 3)
40
+
41
+
42
+ @dataclass
43
+ class Blob:
44
+ """One blob: where it sits, how far and how fast it wanders, how it breathes."""
45
+ x: float
46
+ y: float
47
+ drift_x: float
48
+ drift_y: float
49
+ rate_x: float
50
+ rate_y: float
51
+ phase_x: float
52
+ phase_y: float
53
+ radius: float
54
+ pulse: float
55
+ pulse_rate: float
56
+ pulse_phase: float
57
+ color: int
58
+
59
+
60
+ def field(seed: int = 0, density: float = DEFAULT_DENSITY) -> list:
61
+ """A reproducible set of blobs, seeded on a jittered grid.
62
+
63
+ The pool is always rolled at the top of the density range and a prefix of it painted, so raising
64
+ the density adds blobs rather than redrawing the ones already there: the random numbers are
65
+ consumed in the same order either way, and blob 3 keeps the numbers blob 3 always had.
66
+ """
67
+ rng = random.Random(seed)
68
+ cols, rows = GRID
69
+ cells = list(range(cols * rows))
70
+ rng.shuffle(cells)
71
+ pool = int(round(BLOB_COUNT * DENSITY_RANGE[1]))
72
+ blobs = []
73
+ for i in range(pool):
74
+ cell = cells[i % len(cells)]
75
+ col, row = cell % cols, cell // cols
76
+ small = (i % 3) == 0
77
+ lo, hi = (0.10, 0.18) if small else (0.22, 0.38)
78
+ blobs.append(Blob(
79
+ x=(col + 0.15 + 0.7 * rng.random()) / cols,
80
+ y=(row + 0.15 + 0.7 * rng.random()) / rows,
81
+ drift_x=rng.uniform(0.02, 0.09), drift_y=rng.uniform(0.02, 0.09),
82
+ rate_x=2 * math.pi / rng.uniform(19.0, 43.0),
83
+ rate_y=2 * math.pi / rng.uniform(23.0, 51.0),
84
+ phase_x=rng.uniform(0.0, 2 * math.pi), phase_y=rng.uniform(0.0, 2 * math.pi),
85
+ radius=rng.uniform(lo, hi), pulse=rng.uniform(0.05, 0.16),
86
+ pulse_rate=2 * math.pi / rng.uniform(11.0, 29.0),
87
+ pulse_phase=rng.uniform(0.0, 2 * math.pi),
88
+ # Round-robin, not a random pick: with three colours and a dozen blobs a random
89
+ # assignment leaves one colour missing about one run in fifty.
90
+ color=i))
91
+ keep = max(1, int(round(BLOB_COUNT * _clamp(density, DENSITY_RANGE))))
92
+ return blobs[:keep]
93
+
94
+
95
+ def _clamp(value: float, bounds) -> float:
96
+ lo, hi = bounds
97
+ return float(min(max(value, lo), hi))
98
+
99
+
100
+ def geometry(blobs, t: float, width: int, height: int, speed: float = DEFAULT_SPEED,
101
+ size: float = DEFAULT_SIZE) -> list:
102
+ """(cx, cy, radius, colour index) per blob, in pixels, at time `t`."""
103
+ short = max(min(width, height), 1)
104
+ out = []
105
+ tt = t * _clamp(speed, SPEED_RANGE)
106
+ for b in blobs:
107
+ cx = (b.x + b.drift_x * math.sin(b.rate_x * tt + b.phase_x)) * width
108
+ cy = (b.y + b.drift_y * math.sin(b.rate_y * tt + b.phase_y)) * height
109
+ r = b.radius * (1.0 + b.pulse * math.sin(b.pulse_rate * tt + b.pulse_phase))
110
+ out.append((cx, cy, max(r * short * _clamp(size, SIZE_RANGE), 1.0), b.color))
111
+ return out
112
+
113
+
114
+ class AmbientWidget(QtWidgets.QWidget):
115
+ """The blob field, painted behind everything else.
116
+
117
+ Transparent to the mouse -- it is scenery, and a background that swallowed a click on the panel
118
+ in front of it would be a bug nobody could describe. The timer runs only while the widget is
119
+ visible, because sixty repaints a second of a picture nobody is looking at is sixty repaints a
120
+ second of a picture nobody is looking at.
121
+ """
122
+
123
+ def __init__(self, colors=None, background="#0b0d10", parent=None, seed: int = 0):
124
+ super().__init__(parent)
125
+ self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
126
+ self.background = QtGui.QColor(background)
127
+ self.colors = [QtGui.QColor(c) for c in (colors or ["#43c6d8", "#7a5cd8", "#2a9fb0"])]
128
+ # `blob_size`, NOT `size`: QWidget.size() is a method, and an attribute of that name
129
+ # shadows it -- every caller asking this widget how big it is gets a float back and
130
+ # "'float' object is not callable" from somewhere that never mentioned size.
131
+ self.speed, self.blob_size, self.density = DEFAULT_SPEED, DEFAULT_SIZE, DEFAULT_DENSITY
132
+ self.blur = DEFAULT_BLUR
133
+ self.seed = seed
134
+ self.blobs = field(seed, self.density)
135
+ self._t = 0.0
136
+ self._timer = QtCore.QTimer(self)
137
+ self._timer.setInterval(40) # 25 fps: scenery, not an animation to watch
138
+ self._timer.timeout.connect(self._tick)
139
+
140
+ def configure(self, **kw) -> None:
141
+ """Set any of speed, size, density, blur, colors -- and rebuild if the count changed.
142
+
143
+ `size` is accepted under spaCR's name and stored as `blob_size`, since a widget cannot have
144
+ an attribute called `size`.
145
+ """
146
+ density = kw.pop("density", None)
147
+ if "size" in kw:
148
+ kw["blob_size"] = kw.pop("size")
149
+ for k, v in kw.items():
150
+ if k == "colors":
151
+ self.colors = [QtGui.QColor(c) for c in v]
152
+ elif hasattr(self, k):
153
+ setattr(self, k, float(v))
154
+ if density is not None and float(density) != self.density:
155
+ self.density = float(density)
156
+ self.blobs = field(self.seed, self.density)
157
+ self.update()
158
+
159
+ def start(self) -> None:
160
+ """Begin animating, if it is not already."""
161
+ if not self._timer.isActive():
162
+ self._timer.start()
163
+
164
+ def stop(self) -> None:
165
+ """Stop animating. The field keeps its time, so starting again continues rather than jumps."""
166
+ self._timer.stop()
167
+
168
+ def _tick(self) -> None:
169
+ self._t += self._timer.interval() / 1000.0
170
+ self.update()
171
+
172
+ def set_time(self, t: float) -> None:
173
+ """Jump to an instant. Position is a function of the clock, so this is exact."""
174
+ self._t = float(t)
175
+ self.update()
176
+
177
+ def showEvent(self, ev):
178
+ self.start()
179
+ super().showEvent(ev)
180
+
181
+ def hideEvent(self, ev):
182
+ self.stop()
183
+ super().hideEvent(ev)
184
+
185
+ def paintEvent(self, _ev):
186
+ p = QtGui.QPainter(self)
187
+ p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing)
188
+ p.fillRect(self.rect(), self.background)
189
+ p.setPen(QtCore.Qt.PenStyle.NoPen)
190
+ p.setCompositionMode(QtGui.QPainter.CompositionMode.CompositionMode_Plus)
191
+ for cx, cy, r, ci in geometry(self.blobs, self._t, self.width(), self.height(),
192
+ self.speed, self.blob_size):
193
+ base = self.colors[ci % len(self.colors)]
194
+ grad = QtGui.QRadialGradient(cx, cy, r)
195
+ # Alpha to zero at the rim rather than a hard edge: a blob with an edge is a circle, and
196
+ # a circle drifting behind a panel reads as a loading spinner.
197
+ inner = QtGui.QColor(base)
198
+ inner.setAlpha(int(70 * max(0.35, 1.0 - self.blur / (BLUR_RANGE[1] + 1e-9))))
199
+ outer = QtGui.QColor(base)
200
+ outer.setAlpha(0)
201
+ grad.setColorAt(0.0, inner)
202
+ grad.setColorAt(1.0, outer)
203
+ p.setBrush(QtGui.QBrush(grad))
204
+ p.drawEllipse(QtCore.QRectF(cx - r, cy - r, 2 * r, 2 * r))
205
+ p.end()