genome-spy-python 0.2.0__tar.gz → 0.3.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 (273) hide show
  1. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/CHANGELOG.md +15 -0
  2. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/PKG-INFO +1 -1
  3. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/THIRD_PARTY_NOTICES.md +5 -6
  4. genome_spy_python-0.3.0/docs/_static/gallery/p53_sequence_comparison.png +0 -0
  5. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/datasets.md +5 -5
  6. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/brush_linked_genome_tracks.py +11 -5
  7. genome_spy_python-0.3.0/docs/examples/p53_sequence_comparison.md +41 -0
  8. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/p53_sequence_comparison.py +107 -52
  9. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/notebooks/brush_linked_genome_tracks.ipynb +89 -23
  10. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/pyproject.toml +1 -1
  11. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/__init__.py +1 -1
  12. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/__init__.py +1 -1
  13. genome_spy_python-0.3.0/src/genome_spy/datasets/data/p53_sequence_comparison_aligned.fasta.gz +0 -0
  14. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_chart.py +1 -1
  15. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_combined_gallery_data.py +21 -26
  16. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_docs_gallery.py +65 -16
  17. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/check_notebook_rendering.py +6 -1
  18. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/prepare_combined_gallery_data.py +3 -61
  19. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/uv.lock +1 -1
  20. genome_spy_python-0.2.0/docs/_static/gallery/p53_sequence_comparison.png +0 -0
  21. genome_spy_python-0.2.0/docs/examples/p53_sequence_comparison.md +0 -29
  22. genome_spy_python-0.2.0/src/genome_spy/datasets/data/p53_sequence_comparison.json.gz +0 -0
  23. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.agents/skills/commit/SKILL.md +0 -0
  24. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.agents/skills/proper-code-review/SKILL.md +0 -0
  25. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.agents/skills/proper-code-review/references/correctness.md +0 -0
  26. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.agents/skills/proper-code-review/references/design.md +0 -0
  27. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.agents/skills/proper-code-review/references/performance.md +0 -0
  28. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.claude/skills/commit/SKILL.md +0 -0
  29. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.claude/skills/proper-code-review/SKILL.md +0 -0
  30. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.claude/skills/proper-code-review/references/correctness.md +0 -0
  31. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.claude/skills/proper-code-review/references/design.md +0 -0
  32. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.claude/skills/proper-code-review/references/performance.md +0 -0
  33. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.gitattributes +0 -0
  34. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.github/workflows/ci.yml +0 -0
  35. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.github/workflows/docs.yml +0 -0
  36. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.github/workflows/release.yml +0 -0
  37. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.gitignore +0 -0
  38. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.pre-commit-config.yaml +0 -0
  39. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/.python-version +0 -0
  40. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/AGENTS.md +0 -0
  41. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/CLAUDE.md +0 -0
  42. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/CONTRIBUTING.md +0 -0
  43. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/LICENSE +0 -0
  44. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/LICENSES/ALTAIR-BSD-3-Clause.txt +0 -0
  45. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/LICENSES/GALLERY-DATA-MIT.txt +0 -0
  46. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/README.md +0 -0
  47. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_ext/genomespy_gallery.py +0 -0
  48. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/README.md +0 -0
  49. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/airway_metadata.csv +0 -0
  50. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/airway_scaledcounts.csv +0 -0
  51. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/hapmap_gwas.csv +0 -0
  52. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/oncoprint_dataset3.json +0 -0
  53. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/data/pik3ca_mutations.json +0 -0
  54. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/external-links.js +0 -0
  55. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/airway_ma_plot.png +0 -0
  56. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/airway_volcano_plot.png +0 -0
  57. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/ascat_copy_number.png +0 -0
  58. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/ascat_fitting.png +0 -0
  59. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/bam_read_alignments.png +0 -0
  60. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/bigbed_ccre_track.png +0 -0
  61. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/brush_linked_genome_tracks.png +0 -0
  62. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/clinvar_variants.png +0 -0
  63. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/combined_laml_oncoplot.png +0 -0
  64. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/composing_genome_browser.png +0 -0
  65. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/copy_number.png +0 -0
  66. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/cytobands.png +0 -0
  67. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/dynseq_bqtl.png +0 -0
  68. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/genome_tracks.png +0 -0
  69. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/gff3_gene_annotations.png +0 -0
  70. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/hcc1954_sv_cnv.png +0 -0
  71. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/indexed_fasta_sequence.png +0 -0
  72. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/link_mark.png +0 -0
  73. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/luad_oncoprint.png +0 -0
  74. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/manhattan_plot.png +0 -0
  75. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/multiple_sequence_alignment.png +0 -0
  76. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/needle_plot.png +0 -0
  77. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/oncoprint.png +0 -0
  78. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/pik3ca_tcga_brca_lollipop.png +0 -0
  79. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/point_mark.png +0 -0
  80. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/rainfall_plot.png +0 -0
  81. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/ranged_rule.png +0 -0
  82. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/rect_heatmap.png +0 -0
  83. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/refseq_scored_genes.png +0 -0
  84. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/sashimi_plot.png +0 -0
  85. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/scrollable_viewport.png +0 -0
  86. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/sequence_logo.png +0 -0
  87. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/six_frame_translation.png +0 -0
  88. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/stacked_genome_browser.png +0 -0
  89. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/tcga_ov_gistic.png +0 -0
  90. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/upset_mutations.png +0 -0
  91. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/vertical_concat.png +0 -0
  92. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/gallery/volcano_plot.png +0 -0
  93. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/genomespy.css +0 -0
  94. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_static/snaketie.svg +0 -0
  95. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_templates/autosummary/class.rst +0 -0
  96. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_templates/autosummary/class_own_members.rst +0 -0
  97. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/_templates/components/view-this-page.html +0 -0
  98. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/about.md +0 -0
  99. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/api.md +0 -0
  100. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/conf.py +0 -0
  101. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/airway_ma_plot.md +0 -0
  102. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/airway_ma_plot.py +0 -0
  103. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/airway_volcano_plot.md +0 -0
  104. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/airway_volcano_plot.py +0 -0
  105. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/ascat_copy_number.md +0 -0
  106. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/ascat_copy_number.py +0 -0
  107. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/ascat_fitting.md +0 -0
  108. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/ascat_fitting.py +0 -0
  109. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/bam_read_alignments.md +0 -0
  110. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/bam_read_alignments.py +0 -0
  111. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/bigbed_ccre_track.py +0 -0
  112. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/brush_linked_genome_tracks.md +0 -0
  113. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/clinvar_variants.md +0 -0
  114. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/clinvar_variants.py +0 -0
  115. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/combined_laml_oncoplot.md +0 -0
  116. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/combined_laml_oncoplot.py +0 -0
  117. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/composing_genome_browser.md +0 -0
  118. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/composing_genome_browser.py +0 -0
  119. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/copy_number.py +0 -0
  120. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/cytobands.md +0 -0
  121. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/cytobands.py +0 -0
  122. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/dynseq_bqtl.md +0 -0
  123. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/dynseq_bqtl.py +0 -0
  124. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/genome_tracks.py +0 -0
  125. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/gff3_gene_annotations.md +0 -0
  126. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/gff3_gene_annotations.py +0 -0
  127. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/hcc1954_sv_cnv.md +0 -0
  128. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/hcc1954_sv_cnv.py +0 -0
  129. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/indexed_fasta_sequence.py +0 -0
  130. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/link_mark.py +0 -0
  131. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/luad_oncoprint.md +0 -0
  132. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/luad_oncoprint.py +0 -0
  133. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/manhattan_plot.md +0 -0
  134. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/manhattan_plot.py +0 -0
  135. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/multiple_sequence_alignment.md +0 -0
  136. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/multiple_sequence_alignment.py +0 -0
  137. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/needle_plot.py +0 -0
  138. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/oncoprint.md +0 -0
  139. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/oncoprint.py +0 -0
  140. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/pik3ca_tcga_brca_lollipop.md +0 -0
  141. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/pik3ca_tcga_brca_lollipop.py +0 -0
  142. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/point_mark.py +0 -0
  143. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/rainfall_plot.md +0 -0
  144. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/rainfall_plot.py +0 -0
  145. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/ranged_rule.py +0 -0
  146. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/rect_heatmap.py +0 -0
  147. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/refseq_scored_genes.md +0 -0
  148. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/refseq_scored_genes.py +0 -0
  149. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/sashimi_plot.md +0 -0
  150. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/sashimi_plot.py +0 -0
  151. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/scrollable_viewport.py +0 -0
  152. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/sequence_logo.py +0 -0
  153. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/six_frame_translation.md +0 -0
  154. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/six_frame_translation.py +0 -0
  155. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/stacked_genome_browser.py +0 -0
  156. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/tcga_ov_gistic.md +0 -0
  157. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/tcga_ov_gistic.py +0 -0
  158. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/upset_mutations.md +0 -0
  159. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/upset_mutations.py +0 -0
  160. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/vertical_concat.py +0 -0
  161. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/volcano_plot.md +0 -0
  162. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/examples/volcano_plot.py +0 -0
  163. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/getting-started.md +0 -0
  164. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/index.md +0 -0
  165. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/annotations.py +0 -0
  166. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/charts_and_marks.py +0 -0
  167. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/composition.py +0 -0
  168. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/configuration.py +0 -0
  169. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/data_inputs.py +0 -0
  170. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/display_controls.py +0 -0
  171. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/encoding_channels.py +0 -0
  172. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/genome_browser_layouts.py +0 -0
  173. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/genomic_coordinates.py +0 -0
  174. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/genomic_data.py +0 -0
  175. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/getting_started.py +0 -0
  176. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/importing_specifications.py +0 -0
  177. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/interaction.py +0 -0
  178. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/notebooks.py +0 -0
  179. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/scales_and_guides.py +0 -0
  180. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/serialization.py +0 -0
  181. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/tutorials/transforms.py +0 -0
  182. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/annotations.md +0 -0
  183. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/charts.md +0 -0
  184. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/composition.md +0 -0
  185. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/configuration.md +0 -0
  186. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/data.md +0 -0
  187. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/display-controls.md +0 -0
  188. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/encodings.md +0 -0
  189. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/genome-browser-layouts.md +0 -0
  190. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/genomic-axes.md +0 -0
  191. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/genomic-data.md +0 -0
  192. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/importing-specifications.md +0 -0
  193. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/index.md +0 -0
  194. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/interaction.md +0 -0
  195. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/notebooks.md +0 -0
  196. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/scales-axes-legends.md +0 -0
  197. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/serialization.md +0 -0
  198. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/docs/user-guide/transforms.md +0 -0
  199. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_chart_authoring.py +0 -0
  200. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_conditions.py +0 -0
  201. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_embed.py +0 -0
  202. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_expressions.py +0 -0
  203. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_parameters.py +0 -0
  204. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_render.py +0 -0
  205. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_utils.py +0 -0
  206. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/_widget.py +0 -0
  207. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/api.py +0 -0
  208. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/arrow.py +0 -0
  209. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/channels.py +0 -0
  210. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/chart.py +0 -0
  211. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/data.py +0 -0
  212. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/data_transformers.py +0 -0
  213. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_airway.py +0 -0
  214. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_annotations.py +0 -0
  215. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_gistic.py +0 -0
  216. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_grammar.py +0 -0
  217. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_hapmap.py +0 -0
  218. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_mutation.py +0 -0
  219. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/_oncoprint.py +0 -0
  220. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/airway_metadata.csv +0 -0
  221. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/airway_scaledcounts.csv +0 -0
  222. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/brca.maf.gz +0 -0
  223. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/hapmap_gwas.csv +0 -0
  224. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/mutation_impact_reference.json +0 -0
  225. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/oncoprint_dataset3.json +0 -0
  226. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/pik3ca_mutations.json +0 -0
  227. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/pik3ca_tcga_brca_lollipop.json +0 -0
  228. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/refseq_gene_bodies.csv.gz +0 -0
  229. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tal1_alphagenome_reference.json.gz +0 -0
  230. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga.tsv +0 -0
  231. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga_laml.maf.gz +0 -0
  232. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga_laml_annot.tsv +0 -0
  233. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga_laml_combined_oncoplot.json.gz +0 -0
  234. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga_ov_gistic_lesions.tsv.gz +0 -0
  235. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/datasets/data/tcga_ov_gistic_scores.tsv.gz +0 -0
  236. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/helpers.py +0 -0
  237. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/jupyter.py +0 -0
  238. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/py.typed +0 -0
  239. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/__init__.py +0 -0
  240. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/_kwds.py +0 -0
  241. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/_typing.py +0 -0
  242. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/capabilities.json +0 -0
  243. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/channels.py +0 -0
  244. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/composition.py +0 -0
  245. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/core.py +0 -0
  246. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/ergonomics.py +0 -0
  247. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/expressions.py +0 -0
  248. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/genome-spy-schema.json +0 -0
  249. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/lazy.py +0 -0
  250. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schema/mixins.py +0 -0
  251. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/schemapi.py +0 -0
  252. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/src/genome_spy/static/widget.js +0 -0
  253. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/__init__.py +0 -0
  254. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_arrow.py +0 -0
  255. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_data_transformers.py +0 -0
  256. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_datasets.py +0 -0
  257. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_docs_api_reference.py +0 -0
  258. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_docs_tutorial.py +0 -0
  259. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_expressions.py +0 -0
  260. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_generated_schema_package.py +0 -0
  261. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_generated_transform_methods.py +0 -0
  262. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_render_thumbnails.py +0 -0
  263. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_schema_codegen.py +0 -0
  264. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/test_widget.py +0 -0
  265. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tests/widget.test.mjs +0 -0
  266. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/docs_gallery.py +0 -0
  267. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/generate_api_docs.py +0 -0
  268. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/generate_schema_wrapper.py +0 -0
  269. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/prepare_refseq_gene_annotations.py +0 -0
  270. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/render_thumbnails.py +0 -0
  271. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/schemapi/__init__.py +0 -0
  272. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/schemapi/codegen.py +0 -0
  273. {genome_spy_python-0.2.0 → genome_spy_python-0.3.0}/tools/schemapi/expression_codegen.py +0 -0
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.0] - 2026-09-09
9
+
10
+ ### Changed
11
+
12
+ - **Dataset format change:** `p53_sequence_comparison` now contains 34 protein
13
+ sequences aligned with MAFFT L-INS-i, replacing the unaligned JSON tables.
14
+ Load the aligned FASTA with
15
+ `load_dataset("p53_sequence_comparison", as_format="text")`; code expecting
16
+ the previous mapping of prepared tables must be updated.
17
+ - Updated the P53 gallery example to show the aligned sequences and calculate
18
+ conservation, gap-free fractions, and sequence logos in GenomeSpy.
19
+ - Made the brush notebook build progressively from a simple p-value chart to
20
+ linked tracks, and added an effect-size zero baseline in the notebook and gallery.
21
+
8
22
  ## [0.2.0] - 2026-09-09
9
23
 
10
24
  ### Added
@@ -45,5 +59,6 @@ First public alpha release, targeting GenomeSpy Core 0.87.0.
45
59
  - Packaged example datasets, documentation, tutorials, and an interactive
46
60
  visualization gallery.
47
61
 
62
+ [0.3.0]: https://github.com/genome-spy/genome-spy-python/compare/v0.2.0...v0.3.0
48
63
  [0.2.0]: https://github.com/genome-spy/genome-spy-python/compare/v0.1.0...v0.2.0
49
64
  [0.1.0]: https://github.com/genome-spy/genome-spy-python/releases/tag/v0.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: genome-spy-python
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: genome-spy-python is a declarative genomics visualization library for Python, built on top of the genome-spy JSON specification.
5
5
  Project-URL: Homepage, https://github.com/genome-spy/genome-spy-python
6
6
  Project-URL: Documentation, https://genomespy.app/genome-spy-python/
@@ -4,12 +4,11 @@
4
4
 
5
5
  `tcga_laml_combined_oncoplot.json.gz` contains prepared TCGA LAML tables from
6
6
  maftools revision `015a4cf8c69ba89a55a3fdcea911421509e9a198` (Anand Mayakonda,
7
- MIT). `p53_sequence_comparison.json.gz` contains p53 sequences and derived
8
- display tables from Plotly's datasets revision
9
- `0c447c47b757ad74edecab31f0d72f849d2e67c2` (Plotly Technologies Inc., MIT).
10
- Source file hashes are retained in the packaged data. The corresponding gallery
11
- pages describe processing. Copyright notices and terms are included in
12
- `LICENSES/GALLERY-DATA-MIT.txt`.
7
+ MIT). `p53_sequence_comparison_aligned.fasta.gz` contains p53 sequences from
8
+ Plotly's datasets revision `0c447c47b757ad74edecab31f0d72f849d2e67c2`
9
+ (Plotly Technologies Inc., MIT), aligned with MAFFT v7.526 using L-INS-i. The
10
+ corresponding gallery pages describe processing. Copyright notices and terms
11
+ are included in `LICENSES/GALLERY-DATA-MIT.txt`.
13
12
 
14
13
  ## Code adapted from Vega-Altair
15
14
 
@@ -1,10 +1,10 @@
1
1
  # Example datasets
2
2
 
3
3
  The combined LAML oncoplot uses `load_dataset("tcga_laml_combined_oncoplot")`;
4
- the p53 sequence comparison uses `load_dataset("p53_sequence_comparison")`.
5
- Both return mappings of prepared chart tables, display domains, and source
6
- provenance. Their MIT-licensed sources, processing, and interpretation limits
7
- are described in the [combined oncoplot](gallery/combined_laml_oncoplot.md) and
4
+ the p53 sequence comparison loads aligned FASTA text with
5
+ `load_dataset("p53_sequence_comparison", as_format="text")`. Their
6
+ MIT-licensed sources and processing are described in the
7
+ [combined oncoplot](gallery/combined_laml_oncoplot.md) and
8
8
  [p53 comparison](gallery/p53_sequence_comparison.md) gallery pages.
9
9
 
10
10
  The package ships the tables that the [gallery](gallery/index.md) examples use,
@@ -30,7 +30,7 @@ for JSON files. Pass `as_format="text"` to get the raw file contents instead.
30
30
  | `tcga_laml_maf` | Somatic mutation calls for TCGA acute myeloid leukemia |
31
31
  | `tcga_laml_annotations` | Clinical annotations for those leukemia samples |
32
32
  | `tcga_laml_combined_oncoplot` | Prepared mutation, copy-number, clinical, pathway, VAF, and MutSig tables |
33
- | `p53_sequence_comparison` | 34 unaligned p53 sequences, padded residue tiles, consensus, identity, and coverage |
33
+ | `p53_sequence_comparison` | 34 p53 protein sequences aligned with MAFFT L-INS-i, compressed FASTA |
34
34
  | `pyoncoprint_tcga` | Alteration matrix for TCGA lung adenocarcinoma samples |
35
35
  | `tcga_ov_gistic_scores` | GISTIC2 copy-number scores for TCGA ovarian tumors |
36
36
  | `tcga_ov_gistic_lesions` | GISTIC2 peak regions for the same cohort |
@@ -86,7 +86,7 @@ association_track = (
86
86
  )
87
87
 
88
88
  # Show effect sizes for the same range.
89
- effect_track = (
89
+ effect_points = (
90
90
  gs.Chart()
91
91
  .mark_point(filled=True, size=24, opacity=0.78, color="#f58518")
92
92
  .encode(
@@ -96,10 +96,16 @@ effect_track = (
96
96
  y=gs.Y("EFFECTSIZE:Q").scale(domain=[-3, 3]).title("Effect size"),
97
97
  tooltip=["SNP:N", "GENE:N", "EFFECTSIZE:Q"],
98
98
  )
99
- .properties(
100
- name="effect-size",
101
- height=95,
102
- )
99
+ )
100
+
101
+ # Put a zero line behind the points to separate positive and negative effects.
102
+ effect_baseline = (
103
+ gs.Chart([{"EFFECTSIZE": 0}])
104
+ .mark_rule(color="#888888", size=1, tooltip=None)
105
+ .encode(y=gs.Y("EFFECTSIZE:Q").scale(domain=[-3, 3]).title("Effect size"))
106
+ )
107
+ effect_track = (effect_baseline + effect_points).properties(
108
+ name="effect-size", height=95
103
109
  )
104
110
 
105
111
  # Add Z-scores as the third view of the selected range.
@@ -0,0 +1,41 @@
1
+ ## What to notice
2
+
3
+ Drag the overview at the bottom to choose the positions shown above. The
4
+ summary tracks, sequence logo, and residue matrix stay aligned as the view
5
+ moves. Move the pointer across the detail tracks to follow one position with
6
+ the vertical ruler. Hover a tile for its accession and position. Zoom in to
7
+ read letters.
8
+
9
+ **Conservation** shows the fraction of non-gap sequences that share the most
10
+ common amino acid at each alignment column. **Gap-free** shows
11
+ the fraction of sequences containing a residue there. Keeping the two measures
12
+ separate makes it clear whether a low score reflects disagreement or missing
13
+ aligned residues. The sequence logo shows the full non-gap residue mixture,
14
+ with larger letters for larger shares. The x-axis reports one-based alignment
15
+ columns, not residue numbers in any individual protein.
16
+
17
+ This adapts [Dash Bio AlignmentChart](https://dash.plotly.com/dash-bio/alignmentchart)
18
+ with GenomeSpy rectangles, text, bars, a sequence logo, and a shared brush.
19
+
20
+ :::{admonition} Data use and provenance
21
+ :class: note
22
+
23
+ The 34 UniProt-labelled p53 protein sequences come from the
24
+ [Plotly FASTA](https://github.com/plotly/datasets/blob/0c447c47b757ad74edecab31f0d72f849d2e67c2/Dash_Bio/Genetic/alignment_viewer_p53.fasta)
25
+ in Plotly's MIT-licensed datasets repository. They were aligned with MAFFT
26
+ v7.526 using the L-INS-i strategy:
27
+ `mafft-linsi p53.unaligned.fasta > p53.aligned.fasta`. The resulting alignment
28
+ is packaged as `p53_sequence_comparison_aligned.fasta.gz`.
29
+ :::
30
+
31
+ ## Python and GenomeSpy processing
32
+
33
+ Python reads the packaged compressed FASTA, splits its 34 records, preserves
34
+ the UniProt identifiers and headers, and verifies that every aligned sequence
35
+ has the same length. GenomeSpy then flattens each sequence into residues in the
36
+ browser and declaratively calculates gap-free fractions, non-gap conservation,
37
+ and logo stacks. The Python API authors and serializes
38
+ those transforms; GenomeSpy executes them while rendering and interacting with
39
+ the visualization. For comparison, the
40
+ [multiple sequence alignment example](multiple_sequence_alignment.md) sends
41
+ FASTA directly to GenomeSpy and parses it in the browser-side dataflow.
@@ -1,23 +1,52 @@
1
- """P53 sequence comparison with an overview brush.
1
+ """P53 multiple-sequence alignment with an overview brush.
2
2
 
3
- Explore the p53 FASTA used by Dash Bio, with residue tiles, a consensus logo,
4
- position agreement, sequence coverage, and a linked overview.
3
+ Explore a MAFFT alignment of the p53 proteins used by Dash Bio, with residue
4
+ tiles, a sequence logo, position agreement, gap prevalence, and a linked
5
+ overview.
5
6
  """
6
7
 
7
8
  import genome_spy as gs
8
- from genome_spy.datasets import _load_table_bundle as load_data
9
+ from genome_spy.datasets import load_dataset
9
10
 
10
11
  META = {
11
12
  "category": "Reference annotation tracks",
12
13
  "order": 29,
13
- "height": 870,
14
+ "height": 850,
14
15
  "max_width": 1000,
15
16
  }
16
17
 
17
- # Load prepared sequence rows and per-position summaries.
18
- data = load_data("p53_sequence_comparison", ("cells", "columns"))
19
- # DataFrames let the gallery store shared tables in separate Arrow files.
20
- # Use soft amino-acid colors; grey fills the ends of shorter sequences.
18
+
19
+ def _parse_fasta(text: str) -> list[dict[str, str]]:
20
+ records = []
21
+ for block in text.strip().split(">")[1:]:
22
+ header, *lines = block.splitlines()
23
+ source_id = header.split(maxsplit=1)[0]
24
+ parts = source_id.split("|")
25
+ records.append(
26
+ {
27
+ "identifier": parts[-1],
28
+ "accession": parts[1] if len(parts) >= 3 else source_id,
29
+ "header": header,
30
+ "sequence": "".join("".join(lines).split()).upper(),
31
+ }
32
+ )
33
+ if not records:
34
+ raise ValueError("The FASTA alignment contains no sequences.")
35
+ lengths = {len(record["sequence"]) for record in records}
36
+ if len(lengths) != 1:
37
+ raise ValueError(f"The FASTA sequences are not aligned: lengths={lengths}.")
38
+ return records
39
+
40
+
41
+ # Python handles packaged-file access and the small amount of header parsing.
42
+ alignment_records = _parse_fasta(
43
+ load_dataset("p53_sequence_comparison", as_format="text")
44
+ )
45
+ alignment_length = len(alignment_records[0]["sequence"])
46
+ sequence_order = [record["identifier"] for record in alignment_records]
47
+
48
+ # GenomeSpy flattens the sequences and calculates all column-level summaries.
49
+ # Use soft amino-acid colors; alignment gaps are pale grey.
21
50
  residue_colors = gs.Scale(
22
51
  domain=list("ACDEFGHIKLMNPQRSTVWY-"),
23
52
  range=[
@@ -79,17 +108,21 @@ detail_ruler = gs.ruler(
79
108
 
80
109
  # Keep all positions visible here; drag to choose the range shown below.
81
110
  overview = (
82
- gs.Chart(data["cells"])
111
+ gs.Chart()
83
112
  .mark_rect()
84
113
  .encode(
85
114
  x=gs.X("position:I")
86
- .scale(domain=[1, data["length"] + 1], zoom=False)
115
+ .scale(domain=[1, alignment_length + 1], zoom=False)
87
116
  .title(None),
88
- y=gs.Y("identifier:N")
89
- .scale(domain=data["sequence_order"], reverse=True)
90
- .axis(None),
117
+ y=gs.Y("identifier:N").scale(domain=sequence_order, reverse=True).axis(None),
91
118
  color=color,
92
- tooltip=["identifier:N", "accession:N", "position:Q", "residue:N"],
119
+ tooltip=[
120
+ "identifier:N",
121
+ "accession:N",
122
+ "position:Q",
123
+ "residue:N",
124
+ "header:N",
125
+ ],
93
126
  )
94
127
  .properties(height=100)
95
128
  .add_params(selection)
@@ -101,28 +134,60 @@ overview_group = (
101
134
  .properties(padding=gs.Paddings(top=6))
102
135
  )
103
136
 
104
- # Show the fraction matching the most common amino acid at each position.
137
+ # Calculate the most common non-gap residue and its share at each alignment column.
138
+ column_consensus = (
139
+ gs.Chart()
140
+ .transform_filter(gs.datum.residue != "-")
141
+ .transform_aggregate(groupby=["position", "residue"])
142
+ .transform_window(
143
+ ops=["sum", "row_number"],
144
+ fields=["count", None],
145
+ as_=["nonGapCount", "rank"],
146
+ frame=[None, None],
147
+ groupby=["position"],
148
+ sort=gs.compare(
149
+ field=["count", "residue"],
150
+ order=["descending", "ascending"],
151
+ ),
152
+ )
153
+ .transform_filter(gs.datum.rank == 1)
154
+ .transform_formula(
155
+ expr=gs.datum.count / gs.datum.nonGapCount,
156
+ as_="conservation",
157
+ )
158
+ )
159
+
160
+ # Show agreement among the non-gap amino acids at each position.
105
161
  conservation = (
106
- gs.Chart(data["columns"])
107
- .mark_rect()
162
+ column_consensus.mark_rect()
108
163
  .encode(
109
164
  x=gs.X("position:I").title(None),
110
- y=gs.Y("identity:Q").scale(domain=[0, 1]).axis(tickCount=3, title=None),
111
- color=gs.Color("identity:Q")
165
+ y=gs.Y("conservation:Q").scale(domain=[0, 1]).axis(tickCount=3, title=None),
166
+ color=gs.Color("conservation:Q")
112
167
  .scale(domain=[0, 1], scheme="viridis")
113
168
  .legend(title="Conservation", gradientLength=140, tickCount=3),
114
- tooltip=["position:Q", "identity:Q", "residue:N"],
169
+ tooltip=["position:Q", "conservation:Q", "residue:N", "nonGapCount:Q"],
115
170
  )
116
171
  .properties(height=60, title=gs.title("Conservation", style="track-title"))
117
172
  )
118
- # Show the fraction of sequences without a gap at each position.
173
+ # Show the fraction of sequences without a gap at each alignment column.
119
174
  gap_free = (
120
- gs.Chart(data["columns"])
175
+ gs.Chart()
176
+ .transform_formula(
177
+ expr=gs.expr.if_(gs.datum.residue == "-", 0, 1),
178
+ as_="hasResidue",
179
+ )
180
+ .transform_aggregate(
181
+ groupby=["position"],
182
+ fields=["hasResidue"],
183
+ ops=["mean"],
184
+ as_=["gapFree"],
185
+ )
121
186
  .mark_rect(color="#b4bbc2")
122
187
  .encode(
123
188
  x=gs.X("position:I").title(None),
124
- y=gs.Y("coverage:Q").scale(domain=[0, 1]).axis(tickCount=3, title=None),
125
- tooltip=["position:Q", "coverage:Q"],
189
+ y=gs.Y("gapFree:Q").scale(domain=[0, 1]).axis(tickCount=3, title=None),
190
+ tooltip=["position:Q", "gapFree:Q"],
126
191
  )
127
192
  .properties(
128
193
  height=30,
@@ -131,25 +196,9 @@ gap_free = (
131
196
  )
132
197
  )
133
198
 
134
- # Show the most common amino acid as a compact consensus row.
135
- consensus_tiles = (
136
- gs.Chart(data["columns"])
137
- .mark_rect()
138
- .encode(
139
- x=gs.X("position:I").title(None),
140
- y=gs.Y("identifier:N").title(None),
141
- color=color,
142
- tooltip=["position:Q", "residue:N", "identity:Q"],
143
- )
144
- )
145
- consensus_letters = consensus_tiles.mark_text(size=11, fitToBand=True).encode(
146
- text="residue:N", color=gs.value("#202020")
147
- )
148
- consensus = (consensus_tiles + consensus_letters).properties(height=15)
149
-
150
199
  # Summarize the residue mixture at each position as a sequence logo.
151
- consensus_logo = (
152
- gs.Chart(data["cells"])
200
+ sequence_logo = (
201
+ gs.Chart()
153
202
  .transform_filter(gs.datum.residue != "-")
154
203
  .transform_aggregate(groupby=["position", "residue"])
155
204
  .transform_stack(
@@ -182,15 +231,19 @@ consensus_logo = (
182
231
 
183
232
  # Draw one colored tile per amino acid, with sequence details on hover.
184
233
  tiles = (
185
- gs.Chart(data["cells"])
234
+ gs.Chart()
186
235
  .mark_rect()
187
236
  .encode(
188
237
  x=gs.X("position:I").title(None),
189
- y=gs.Y("identifier:N")
190
- .scale(domain=data["sequence_order"], reverse=True)
191
- .title(None),
238
+ y=gs.Y("identifier:N").scale(domain=sequence_order, reverse=True).title(None),
192
239
  color=legend_color,
193
- tooltip=["identifier:N", "accession:N", "position:Q", "residue:N"],
240
+ tooltip=[
241
+ "identifier:N",
242
+ "accession:N",
243
+ "position:Q",
244
+ "residue:N",
245
+ "header:N",
246
+ ],
194
247
  )
195
248
  )
196
249
  # Add letters when there is enough room to read them.
@@ -204,8 +257,7 @@ details = (
204
257
  gs.vconcat(
205
258
  gap_free,
206
259
  conservation,
207
- consensus,
208
- consensus_logo,
260
+ sequence_logo,
209
261
  sequences,
210
262
  spacing=6,
211
263
  )
@@ -228,10 +280,13 @@ chart = (
228
280
  gs.vconcat(details, overview_group, spacing=2)
229
281
  .add_params(brush)
230
282
  .properties(
283
+ data=alignment_records,
231
284
  width="container",
232
- title="P53 sequences: overview and residue detail",
233
- description="34 original, ungapped p53 sequences from the Dash Bio example. Drag the overview or zoom the detail tracks to compare positions; grey cells pad shorter sequences.",
285
+ title="P53 protein alignment: overview and residue detail",
286
+ description="A 34-sequence p53 protein alignment generated with MAFFT L-INS-i. Drag the overview or zoom the detail tracks to compare alignment columns; grey cells are alignment gaps.",
234
287
  )
288
+ .transform_flatten_sequence(as_=["position", "residue"])
289
+ .transform_formula(expr=gs.datum.position + 1, as_="position")
235
290
  .resolve_scale(x="independent", y="independent")
236
291
  .resolve_legend(color="collected")
237
292
  .configure_legend(
@@ -9,7 +9,7 @@
9
9
  "\n",
10
10
  "This notebook makes an interactive genome visualization with [GenomeSpy for Python](https://genomespy.app/genome-spy-python/).\n",
11
11
  "\n",
12
- "Think of the top track as a **map of the whole genome**. Drag a box across it to choose a region. The three tracks underneath act like magnifying glasses: they all zoom to the region you selected.\n",
12
+ "Start with a simple plot of p-values. Then add a draggable overview and two more tracks that follow the same selected region.\n",
13
13
  "\n",
14
14
  "You do not need to know GenomeSpy yet. Run each cell from top to bottom using the play button on its left."
15
15
  ]
@@ -109,12 +109,44 @@
109
109
  "variants[[\"SNP\", \"chrom\", \"BP\", \"P\", \"EFFECTSIZE\", \"ZSCORE\"]].head()"
110
110
  ]
111
111
  },
112
+ {
113
+ "cell_type": "markdown",
114
+ "id": "first-chart-explanation",
115
+ "metadata": {},
116
+ "source": [
117
+ "## 4. Draw a first chart\n",
118
+ "\n",
119
+ "Each point is a variant. Its position comes from `gs.Locus(\"chrom\", \"BP\")`, which combines chromosome and position into one axis. Taller points have smaller p-values. Hover over a point to see its values."
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": null,
125
+ "id": "first-chart",
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "association = (\n",
130
+ " gs.Chart()\n",
131
+ " .mark_point(filled=True, size=24, opacity=0.78, color=\"#4c78a8\")\n",
132
+ " .encode(\n",
133
+ " x=gs.Locus(\"chrom\", \"BP\"),\n",
134
+ " y=gs.Y(\"neglog:Q\").scale(domain=y_domain).title(\"−log10 p\"),\n",
135
+ " tooltip=[\"SNP:N\", \"GENE:N\", \"P:Q\"],\n",
136
+ " )\n",
137
+ " .properties(height=180)\n",
138
+ ")\n",
139
+ "\n",
140
+ "# Give this first chart its data and genome assembly, then show it.\n",
141
+ "association.properties(data=variants, assembly=\"hg18\")"
142
+ ]
143
+ },
112
144
  {
113
145
  "cell_type": "markdown",
114
146
  "id": "brush-explanation",
115
147
  "metadata": {},
116
148
  "source": [
117
- "## 4. Make a shared genomic selection\n",
149
+ "## 5. Add a brush\n",
118
150
  "\n",
119
151
  "A **brush** is the blue rectangle you draw with the mouse. Its only job is to remember the genomic interval you selected.\n",
120
152
  "\n",
@@ -159,11 +191,9 @@
159
191
  "id": "overview-explanation",
160
192
  "metadata": {},
161
193
  "source": [
162
- "## 5. Build the whole-genome overview\n",
194
+ "## 6. Build the whole-genome overview\n",
163
195
  "\n",
164
- "The `Locus` encoding combines a chromosome column and a position column into one continuous genome-wide axis. That is why points from chromosome 1 through chromosome X can share one x-axis.\n",
165
- "\n",
166
- "We turn zooming off only for this overview so it always remains our complete genome map."
196
+ "This smaller, gray plot will sit above our first chart. It stays zoomed out so you can always choose a different region."
167
197
  ]
168
198
  },
169
199
  {
@@ -206,18 +236,18 @@
206
236
  },
207
237
  {
208
238
  "cell_type": "markdown",
209
- "id": "details-explanation",
239
+ "id": "link-explanation",
210
240
  "metadata": {},
211
241
  "source": [
212
- "## 6. Build three detail tracks\n",
242
+ "## 7. Try the brush with one detail track\n",
213
243
  "\n",
214
- "Each detail track draws a different measurement, but all three ask the same brush for their x-axis range. Imagine three magnifying glasses tied to the same handle: moving the handle moves all three together."
244
+ "Reuse the first chart, but let the brush choose its visible range with `gs.SelectionDomainRef`. Drag across the gray overview: the blue chart below follows your selection."
215
245
  ]
216
246
  },
217
247
  {
218
248
  "cell_type": "code",
219
249
  "execution_count": null,
220
- "id": "build-details",
250
+ "id": "link-first-track",
221
251
  "metadata": {},
222
252
  "outputs": [],
223
253
  "source": [
@@ -227,18 +257,39 @@
227
257
  " initial=initial_region,\n",
228
258
  ")\n",
229
259
  "\n",
230
- "association_track = (\n",
231
- " gs.Chart()\n",
232
- " .mark_point(filled=True, size=24, opacity=0.78, color=\"#4c78a8\")\n",
233
- " .encode(\n",
234
- " x=gs.Locus(\"chrom\", \"BP\").scale(domain=selected_region).axis(None),\n",
235
- " y=gs.Y(\"neglog:Q\").scale(domain=y_domain).title(\"−log10 p\"),\n",
236
- " tooltip=[\"SNP:N\", \"GENE:N\", \"P:Q\"],\n",
237
- " )\n",
238
- " .properties(height=95)\n",
260
+ "association_track = association.encode(\n",
261
+ " x=gs.Locus(\"chrom\", \"BP\").scale(domain=selected_region)\n",
262
+ ").properties(height=95)\n",
263
+ "\n",
264
+ "linked_chart = (\n",
265
+ " (overview & association_track)\n",
266
+ " .properties(data=variants, assembly=\"hg18\", spacing=8)\n",
267
+ " .add_params(brush)\n",
268
+ " .resolve_scale(x=\"independent\", y=\"independent\")\n",
269
+ " .resolve_axis(x=\"independent\", y=\"independent\")\n",
239
270
  ")\n",
240
271
  "\n",
241
- "effect_track = (\n",
272
+ "linked_chart"
273
+ ]
274
+ },
275
+ {
276
+ "cell_type": "markdown",
277
+ "id": "details-explanation",
278
+ "metadata": {},
279
+ "source": [
280
+ "## 8. Add two more measurements\n",
281
+ "\n",
282
+ "Effect size and Z-score give two more views of the same variants. Both use `selected_region`, so they follow the same brush."
283
+ ]
284
+ },
285
+ {
286
+ "cell_type": "code",
287
+ "execution_count": null,
288
+ "id": "build-details",
289
+ "metadata": {},
290
+ "outputs": [],
291
+ "source": [
292
+ "effect_points = (\n",
242
293
  " gs.Chart()\n",
243
294
  " .mark_point(filled=True, size=24, opacity=0.78, color=\"#f58518\")\n",
244
295
  " .encode(\n",
@@ -246,9 +297,16 @@
246
297
  " y=gs.Y(\"EFFECTSIZE:Q\").scale(domain=[-3, 3]).title(\"Effect size\"),\n",
247
298
  " tooltip=[\"SNP:N\", \"GENE:N\", \"EFFECTSIZE:Q\"],\n",
248
299
  " )\n",
249
- " .properties(height=95)\n",
250
300
  ")\n",
251
301
  "\n",
302
+ "# A zero line separates positive and negative effects.\n",
303
+ "effect_baseline = (\n",
304
+ " gs.Chart([{\"EFFECTSIZE\": 0}])\n",
305
+ " .mark_rule(color=\"#888888\", size=1, tooltip=None)\n",
306
+ " .encode(y=gs.Y(\"EFFECTSIZE:Q\").scale(domain=[-3, 3]).title(\"Effect size\"))\n",
307
+ ")\n",
308
+ "effect_track = (effect_baseline + effect_points).properties(height=95)\n",
309
+ "\n",
252
310
  "zscore_track = (\n",
253
311
  " gs.Chart()\n",
254
312
  " .mark_point(filled=True, size=24, opacity=0.78, color=\"#54a24b\")\n",
@@ -266,7 +324,7 @@
266
324
  "id": "display-explanation",
267
325
  "metadata": {},
268
326
  "source": [
269
- "## 7. Stack the tracks and try the chart\n",
327
+ "## 9. Put it all together\n",
270
328
  "\n",
271
329
  "`vconcat` stacks charts vertically. The whole composition receives the same data, genome assembly, and brush parameter.\n",
272
330
  "\n",
@@ -286,7 +344,15 @@
286
344
  "outputs": [],
287
345
  "source": [
288
346
  "chart = (\n",
289
- " gs.vconcat(overview, association_track, effect_track, zscore_track)\n",
347
+ " gs.vconcat(\n",
348
+ " overview,\n",
349
+ " # Only the bottom detail track needs x-axis labels.\n",
350
+ " association_track.encode(\n",
351
+ " x=gs.Locus(\"chrom\", \"BP\").scale(domain=selected_region).axis(None)\n",
352
+ " ),\n",
353
+ " effect_track,\n",
354
+ " zscore_track,\n",
355
+ " )\n",
290
356
  " .properties(\n",
291
357
  " data=variants,\n",
292
358
  " assembly=\"hg18\",\n",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "genome-spy-python"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "genome-spy-python is a declarative genomics visualization library for Python, built on top of the genome-spy JSON specification."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -196,4 +196,4 @@ __all__ = [
196
196
  # END GENERATED INTERACTION EXPORTS
197
197
  ]
198
198
 
199
- __version__ = "0.2.0"
199
+ __version__ = "0.3.0"
@@ -21,7 +21,7 @@ _DATASETS = {
21
21
  "brca_maf": "brca.maf.gz",
22
22
  "hapmap_gwas": "hapmap_gwas.csv",
23
23
  "mutation_impact_reference": "mutation_impact_reference.json",
24
- "p53_sequence_comparison": "p53_sequence_comparison.json.gz",
24
+ "p53_sequence_comparison": "p53_sequence_comparison_aligned.fasta.gz",
25
25
  "pik3ca_mutations": "pik3ca_mutations.json",
26
26
  "pik3ca_tcga_brca_lollipop": "pik3ca_tcga_brca_lollipop.json",
27
27
  "tal1_alphagenome_reference": "tal1_alphagenome_reference.json.gz",
@@ -57,7 +57,7 @@ from genome_spy.schemapi import SchemaBase, SchemaValidationError
57
57
 
58
58
 
59
59
  def test_package_exposes_version() -> None:
60
- assert gs.__version__ == "0.2.0"
60
+ assert gs.__version__ == "0.3.0"
61
61
 
62
62
 
63
63
  def test_public_api_exports_are_unique() -> None: