biotite 1.5.0__cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
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.
Potentially problematic release.
This version of biotite might be problematic. Click here for more details.
- biotite/__init__.py +18 -0
- biotite/application/__init__.py +69 -0
- biotite/application/application.py +276 -0
- biotite/application/autodock/__init__.py +12 -0
- biotite/application/autodock/app.py +500 -0
- biotite/application/blast/__init__.py +14 -0
- biotite/application/blast/alignment.py +92 -0
- biotite/application/blast/webapp.py +428 -0
- biotite/application/clustalo/__init__.py +12 -0
- biotite/application/clustalo/app.py +223 -0
- biotite/application/dssp/__init__.py +12 -0
- biotite/application/dssp/app.py +216 -0
- biotite/application/localapp.py +342 -0
- biotite/application/mafft/__init__.py +12 -0
- biotite/application/mafft/app.py +116 -0
- biotite/application/msaapp.py +363 -0
- biotite/application/muscle/__init__.py +13 -0
- biotite/application/muscle/app3.py +227 -0
- biotite/application/muscle/app5.py +163 -0
- biotite/application/sra/__init__.py +18 -0
- biotite/application/sra/app.py +447 -0
- biotite/application/tantan/__init__.py +12 -0
- biotite/application/tantan/app.py +199 -0
- biotite/application/util.py +77 -0
- biotite/application/viennarna/__init__.py +18 -0
- biotite/application/viennarna/rnaalifold.py +310 -0
- biotite/application/viennarna/rnafold.py +254 -0
- biotite/application/viennarna/rnaplot.py +208 -0
- biotite/application/viennarna/util.py +77 -0
- biotite/application/webapp.py +76 -0
- biotite/copyable.py +71 -0
- biotite/database/__init__.py +23 -0
- biotite/database/afdb/__init__.py +12 -0
- biotite/database/afdb/download.py +197 -0
- biotite/database/entrez/__init__.py +15 -0
- biotite/database/entrez/check.py +60 -0
- biotite/database/entrez/dbnames.py +101 -0
- biotite/database/entrez/download.py +228 -0
- biotite/database/entrez/key.py +44 -0
- biotite/database/entrez/query.py +263 -0
- biotite/database/error.py +16 -0
- biotite/database/pubchem/__init__.py +21 -0
- biotite/database/pubchem/download.py +258 -0
- biotite/database/pubchem/error.py +30 -0
- biotite/database/pubchem/query.py +819 -0
- biotite/database/pubchem/throttle.py +98 -0
- biotite/database/rcsb/__init__.py +13 -0
- biotite/database/rcsb/download.py +161 -0
- biotite/database/rcsb/query.py +963 -0
- biotite/database/uniprot/__init__.py +13 -0
- biotite/database/uniprot/check.py +40 -0
- biotite/database/uniprot/download.py +126 -0
- biotite/database/uniprot/query.py +292 -0
- biotite/file.py +244 -0
- biotite/interface/__init__.py +19 -0
- biotite/interface/openmm/__init__.py +20 -0
- biotite/interface/openmm/state.py +93 -0
- biotite/interface/openmm/system.py +227 -0
- biotite/interface/pymol/__init__.py +201 -0
- biotite/interface/pymol/cgo.py +346 -0
- biotite/interface/pymol/convert.py +185 -0
- biotite/interface/pymol/display.py +267 -0
- biotite/interface/pymol/object.py +1228 -0
- biotite/interface/pymol/shapes.py +178 -0
- biotite/interface/pymol/startup.py +169 -0
- biotite/interface/rdkit/__init__.py +19 -0
- biotite/interface/rdkit/mol.py +490 -0
- biotite/interface/version.py +94 -0
- biotite/interface/warning.py +19 -0
- biotite/sequence/__init__.py +84 -0
- biotite/sequence/align/__init__.py +199 -0
- biotite/sequence/align/alignment.py +702 -0
- biotite/sequence/align/banded.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/banded.pyx +652 -0
- biotite/sequence/align/buckets.py +71 -0
- biotite/sequence/align/cigar.py +425 -0
- biotite/sequence/align/kmeralphabet.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmeralphabet.pyx +595 -0
- biotite/sequence/align/kmersimilarity.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmersimilarity.pyx +233 -0
- biotite/sequence/align/kmertable.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmertable.pyx +3411 -0
- biotite/sequence/align/localgapped.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/localgapped.pyx +892 -0
- biotite/sequence/align/localungapped.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/localungapped.pyx +279 -0
- biotite/sequence/align/matrix.py +631 -0
- biotite/sequence/align/matrix_data/3Di.mat +24 -0
- biotite/sequence/align/matrix_data/BLOSUM100.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM30.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM35.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM40.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM45.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM50.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM50_13p.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM50_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM50_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM55.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM60.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM62.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM62_13p.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM62_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM62_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM65.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM70.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM75.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM80.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM85.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM90.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUMN.mat +31 -0
- biotite/sequence/align/matrix_data/CorBLOSUM49_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM57_13p.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM57_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM61_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM66_13p.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM67_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/DAYHOFF.mat +32 -0
- biotite/sequence/align/matrix_data/GONNET.mat +26 -0
- biotite/sequence/align/matrix_data/IDENTITY.mat +25 -0
- biotite/sequence/align/matrix_data/MATCH.mat +25 -0
- biotite/sequence/align/matrix_data/NUC.mat +25 -0
- biotite/sequence/align/matrix_data/PAM10.mat +34 -0
- biotite/sequence/align/matrix_data/PAM100.mat +34 -0
- biotite/sequence/align/matrix_data/PAM110.mat +34 -0
- biotite/sequence/align/matrix_data/PAM120.mat +34 -0
- biotite/sequence/align/matrix_data/PAM130.mat +34 -0
- biotite/sequence/align/matrix_data/PAM140.mat +34 -0
- biotite/sequence/align/matrix_data/PAM150.mat +34 -0
- biotite/sequence/align/matrix_data/PAM160.mat +34 -0
- biotite/sequence/align/matrix_data/PAM170.mat +34 -0
- biotite/sequence/align/matrix_data/PAM180.mat +34 -0
- biotite/sequence/align/matrix_data/PAM190.mat +34 -0
- biotite/sequence/align/matrix_data/PAM20.mat +34 -0
- biotite/sequence/align/matrix_data/PAM200.mat +34 -0
- biotite/sequence/align/matrix_data/PAM210.mat +34 -0
- biotite/sequence/align/matrix_data/PAM220.mat +34 -0
- biotite/sequence/align/matrix_data/PAM230.mat +34 -0
- biotite/sequence/align/matrix_data/PAM240.mat +34 -0
- biotite/sequence/align/matrix_data/PAM250.mat +34 -0
- biotite/sequence/align/matrix_data/PAM260.mat +34 -0
- biotite/sequence/align/matrix_data/PAM270.mat +34 -0
- biotite/sequence/align/matrix_data/PAM280.mat +34 -0
- biotite/sequence/align/matrix_data/PAM290.mat +34 -0
- biotite/sequence/align/matrix_data/PAM30.mat +34 -0
- biotite/sequence/align/matrix_data/PAM300.mat +34 -0
- biotite/sequence/align/matrix_data/PAM310.mat +34 -0
- biotite/sequence/align/matrix_data/PAM320.mat +34 -0
- biotite/sequence/align/matrix_data/PAM330.mat +34 -0
- biotite/sequence/align/matrix_data/PAM340.mat +34 -0
- biotite/sequence/align/matrix_data/PAM350.mat +34 -0
- biotite/sequence/align/matrix_data/PAM360.mat +34 -0
- biotite/sequence/align/matrix_data/PAM370.mat +34 -0
- biotite/sequence/align/matrix_data/PAM380.mat +34 -0
- biotite/sequence/align/matrix_data/PAM390.mat +34 -0
- biotite/sequence/align/matrix_data/PAM40.mat +34 -0
- biotite/sequence/align/matrix_data/PAM400.mat +34 -0
- biotite/sequence/align/matrix_data/PAM410.mat +34 -0
- biotite/sequence/align/matrix_data/PAM420.mat +34 -0
- biotite/sequence/align/matrix_data/PAM430.mat +34 -0
- biotite/sequence/align/matrix_data/PAM440.mat +34 -0
- biotite/sequence/align/matrix_data/PAM450.mat +34 -0
- biotite/sequence/align/matrix_data/PAM460.mat +34 -0
- biotite/sequence/align/matrix_data/PAM470.mat +34 -0
- biotite/sequence/align/matrix_data/PAM480.mat +34 -0
- biotite/sequence/align/matrix_data/PAM490.mat +34 -0
- biotite/sequence/align/matrix_data/PAM50.mat +34 -0
- biotite/sequence/align/matrix_data/PAM500.mat +34 -0
- biotite/sequence/align/matrix_data/PAM60.mat +34 -0
- biotite/sequence/align/matrix_data/PAM70.mat +34 -0
- biotite/sequence/align/matrix_data/PAM80.mat +34 -0
- biotite/sequence/align/matrix_data/PAM90.mat +34 -0
- biotite/sequence/align/matrix_data/PB.license +21 -0
- biotite/sequence/align/matrix_data/PB.mat +18 -0
- biotite/sequence/align/matrix_data/RBLOSUM52_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM59_13p.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM59_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM64_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM69_13p.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM69_14.3.mat +25 -0
- biotite/sequence/align/multiple.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/multiple.pyx +619 -0
- biotite/sequence/align/pairwise.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/pairwise.pyx +585 -0
- biotite/sequence/align/permutation.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/permutation.pyx +313 -0
- biotite/sequence/align/primes.txt +821 -0
- biotite/sequence/align/selector.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/selector.pyx +954 -0
- biotite/sequence/align/statistics.py +264 -0
- biotite/sequence/align/tracetable.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/tracetable.pxd +64 -0
- biotite/sequence/align/tracetable.pyx +370 -0
- biotite/sequence/alphabet.py +555 -0
- biotite/sequence/annotation.py +836 -0
- biotite/sequence/codec.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/codec.pyx +155 -0
- biotite/sequence/codon.py +476 -0
- biotite/sequence/codon_tables.txt +202 -0
- biotite/sequence/graphics/__init__.py +33 -0
- biotite/sequence/graphics/alignment.py +1101 -0
- biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
- biotite/sequence/graphics/color_schemes/autumn.json +51 -0
- biotite/sequence/graphics/color_schemes/blossom.json +51 -0
- biotite/sequence/graphics/color_schemes/clustalx_dna.json +11 -0
- biotite/sequence/graphics/color_schemes/clustalx_protein.json +28 -0
- biotite/sequence/graphics/color_schemes/flower.json +51 -0
- biotite/sequence/graphics/color_schemes/jalview_buried.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_hydrophobicity.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_helix.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_strand.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_turn.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_taylor.json +28 -0
- biotite/sequence/graphics/color_schemes/jalview_zappo.json +28 -0
- biotite/sequence/graphics/color_schemes/ocean.json +51 -0
- biotite/sequence/graphics/color_schemes/pb_flower.json +40 -0
- biotite/sequence/graphics/color_schemes/rainbow_dna.json +11 -0
- biotite/sequence/graphics/color_schemes/rainbow_protein.json +30 -0
- biotite/sequence/graphics/color_schemes/spring.json +51 -0
- biotite/sequence/graphics/color_schemes/sunset.json +51 -0
- biotite/sequence/graphics/color_schemes/wither.json +51 -0
- biotite/sequence/graphics/colorschemes.py +170 -0
- biotite/sequence/graphics/dendrogram.py +231 -0
- biotite/sequence/graphics/features.py +544 -0
- biotite/sequence/graphics/logo.py +102 -0
- biotite/sequence/graphics/plasmid.py +712 -0
- biotite/sequence/io/__init__.py +12 -0
- biotite/sequence/io/fasta/__init__.py +22 -0
- biotite/sequence/io/fasta/convert.py +283 -0
- biotite/sequence/io/fasta/file.py +265 -0
- biotite/sequence/io/fastq/__init__.py +19 -0
- biotite/sequence/io/fastq/convert.py +117 -0
- biotite/sequence/io/fastq/file.py +507 -0
- biotite/sequence/io/genbank/__init__.py +17 -0
- biotite/sequence/io/genbank/annotation.py +269 -0
- biotite/sequence/io/genbank/file.py +573 -0
- biotite/sequence/io/genbank/metadata.py +336 -0
- biotite/sequence/io/genbank/sequence.py +173 -0
- biotite/sequence/io/general.py +201 -0
- biotite/sequence/io/gff/__init__.py +26 -0
- biotite/sequence/io/gff/convert.py +128 -0
- biotite/sequence/io/gff/file.py +449 -0
- biotite/sequence/phylo/__init__.py +36 -0
- biotite/sequence/phylo/nj.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/nj.pyx +221 -0
- biotite/sequence/phylo/tree.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/tree.pyx +1169 -0
- biotite/sequence/phylo/upgma.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/upgma.pyx +164 -0
- biotite/sequence/profile.py +561 -0
- biotite/sequence/search.py +117 -0
- biotite/sequence/seqtypes.py +720 -0
- biotite/sequence/sequence.py +373 -0
- biotite/setup_ccd.py +197 -0
- biotite/structure/__init__.py +135 -0
- biotite/structure/alphabet/__init__.py +25 -0
- biotite/structure/alphabet/encoder.py +332 -0
- biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
- biotite/structure/alphabet/i3d.py +109 -0
- biotite/structure/alphabet/layers.py +86 -0
- biotite/structure/alphabet/pb.license +21 -0
- biotite/structure/alphabet/pb.py +170 -0
- biotite/structure/alphabet/unkerasify.py +128 -0
- biotite/structure/atoms.py +1562 -0
- biotite/structure/basepairs.py +1403 -0
- biotite/structure/bonds.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/bonds.pyx +2036 -0
- biotite/structure/box.py +724 -0
- biotite/structure/celllist.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/celllist.pyx +864 -0
- biotite/structure/chains.py +310 -0
- biotite/structure/charges.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/charges.pyx +520 -0
- biotite/structure/compare.py +683 -0
- biotite/structure/density.py +109 -0
- biotite/structure/dotbracket.py +213 -0
- biotite/structure/error.py +39 -0
- biotite/structure/filter.py +591 -0
- biotite/structure/geometry.py +817 -0
- biotite/structure/graphics/__init__.py +13 -0
- biotite/structure/graphics/atoms.py +243 -0
- biotite/structure/graphics/rna.py +298 -0
- biotite/structure/hbond.py +425 -0
- biotite/structure/info/__init__.py +24 -0
- biotite/structure/info/atom_masses.json +121 -0
- biotite/structure/info/atoms.py +98 -0
- biotite/structure/info/bonds.py +149 -0
- biotite/structure/info/ccd.py +200 -0
- biotite/structure/info/components.bcif +0 -0
- biotite/structure/info/groups.py +128 -0
- biotite/structure/info/masses.py +121 -0
- biotite/structure/info/misc.py +137 -0
- biotite/structure/info/radii.py +267 -0
- biotite/structure/info/standardize.py +185 -0
- biotite/structure/integrity.py +213 -0
- biotite/structure/io/__init__.py +29 -0
- biotite/structure/io/dcd/__init__.py +13 -0
- biotite/structure/io/dcd/file.py +67 -0
- biotite/structure/io/general.py +243 -0
- biotite/structure/io/gro/__init__.py +14 -0
- biotite/structure/io/gro/file.py +343 -0
- biotite/structure/io/mol/__init__.py +20 -0
- biotite/structure/io/mol/convert.py +112 -0
- biotite/structure/io/mol/ctab.py +420 -0
- biotite/structure/io/mol/header.py +120 -0
- biotite/structure/io/mol/mol.py +149 -0
- biotite/structure/io/mol/sdf.py +940 -0
- biotite/structure/io/netcdf/__init__.py +13 -0
- biotite/structure/io/netcdf/file.py +64 -0
- biotite/structure/io/pdb/__init__.py +20 -0
- biotite/structure/io/pdb/convert.py +389 -0
- biotite/structure/io/pdb/file.py +1380 -0
- biotite/structure/io/pdb/hybrid36.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/io/pdb/hybrid36.pyx +242 -0
- biotite/structure/io/pdbqt/__init__.py +15 -0
- biotite/structure/io/pdbqt/convert.py +113 -0
- biotite/structure/io/pdbqt/file.py +688 -0
- biotite/structure/io/pdbx/__init__.py +23 -0
- biotite/structure/io/pdbx/bcif.py +674 -0
- biotite/structure/io/pdbx/cif.py +1091 -0
- biotite/structure/io/pdbx/component.py +251 -0
- biotite/structure/io/pdbx/compress.py +362 -0
- biotite/structure/io/pdbx/convert.py +2113 -0
- biotite/structure/io/pdbx/encoding.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/io/pdbx/encoding.pyx +1078 -0
- biotite/structure/io/trajfile.py +696 -0
- biotite/structure/io/trr/__init__.py +13 -0
- biotite/structure/io/trr/file.py +43 -0
- biotite/structure/io/util.py +38 -0
- biotite/structure/io/xtc/__init__.py +13 -0
- biotite/structure/io/xtc/file.py +43 -0
- biotite/structure/mechanics.py +72 -0
- biotite/structure/molecules.py +337 -0
- biotite/structure/pseudoknots.py +622 -0
- biotite/structure/rdf.py +245 -0
- biotite/structure/repair.py +302 -0
- biotite/structure/residues.py +716 -0
- biotite/structure/rings.py +451 -0
- biotite/structure/sasa.cpython-312-x86_64-linux-gnu.so +0 -0
- biotite/structure/sasa.pyx +322 -0
- biotite/structure/segments.py +328 -0
- biotite/structure/sequence.py +110 -0
- biotite/structure/spacegroups.json +1567 -0
- biotite/structure/spacegroups.license +26 -0
- biotite/structure/sse.py +306 -0
- biotite/structure/superimpose.py +511 -0
- biotite/structure/tm.py +581 -0
- biotite/structure/transform.py +736 -0
- biotite/structure/util.py +160 -0
- biotite/version.py +34 -0
- biotite/visualize.py +375 -0
- biotite-1.5.0.dist-info/METADATA +162 -0
- biotite-1.5.0.dist-info/RECORD +354 -0
- biotite-1.5.0.dist-info/WHEEL +6 -0
- biotite-1.5.0.dist-info/licenses/LICENSE.rst +30 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# This source code is part of the Biotite package and is distributed
|
|
2
|
+
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
|
|
3
|
+
# information.
|
|
4
|
+
|
|
5
|
+
__name__ = "biotite.sequence.graphics"
|
|
6
|
+
__author__ = "Patrick Kunzmann"
|
|
7
|
+
__all__ = [
|
|
8
|
+
"plot_feature_map",
|
|
9
|
+
"FeaturePlotter",
|
|
10
|
+
"MiscFeaturePlotter",
|
|
11
|
+
"CodingPlotter",
|
|
12
|
+
"PromoterPlotter",
|
|
13
|
+
"TerminatorPlotter",
|
|
14
|
+
"RBSPlotter",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
import abc
|
|
18
|
+
from biotite.sequence.annotation import Location
|
|
19
|
+
from biotite.visualize import AdaptiveFancyArrow, colors
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def plot_feature_map(
|
|
23
|
+
axes,
|
|
24
|
+
annotation,
|
|
25
|
+
loc_range=None,
|
|
26
|
+
multi_line=True,
|
|
27
|
+
symbols_per_line=1000,
|
|
28
|
+
show_numbers=False,
|
|
29
|
+
number_size=None,
|
|
30
|
+
line_width=0.05,
|
|
31
|
+
show_line_position=False,
|
|
32
|
+
spacing=0.25,
|
|
33
|
+
feature_plotters=None,
|
|
34
|
+
style_param=None,
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Plot a sequence annotation, by showing the range of each feature
|
|
38
|
+
on one or multiple position depicting line(s).
|
|
39
|
+
|
|
40
|
+
This function uses :class:`FeaturePlotter` objects to draw the
|
|
41
|
+
features.
|
|
42
|
+
This function internally uses a list of plotters, where the
|
|
43
|
+
first plotter in the list, that supports a feature, is used to draw
|
|
44
|
+
that feature.
|
|
45
|
+
The amount of features that can be visualized by default is limited.
|
|
46
|
+
Features, that are not supported otherwise, are visualized as simple
|
|
47
|
+
rectangles.
|
|
48
|
+
Additional :class:`FeaturePlotter` objects, that are supplied in the
|
|
49
|
+
`feature_plotters` parameters, can be used to add support for
|
|
50
|
+
further features or to customize the appearance of certain features.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
axes : Axes
|
|
55
|
+
A *Matplotlib* axes, that is used as plotting area.
|
|
56
|
+
annotation : Annotation
|
|
57
|
+
The annotation to be visualized.
|
|
58
|
+
loc_range : tuple (int, int), optional
|
|
59
|
+
The start and exclusive stop location that is visualized.
|
|
60
|
+
By default, the location range starts from the first
|
|
61
|
+
base/residue and ends at the last base/residue of all features,
|
|
62
|
+
ensuring that the entire annotation is drawn.
|
|
63
|
+
multi_line : bool, optional
|
|
64
|
+
If true, the annotation is segmented into multiple lines with a
|
|
65
|
+
line break all `symbols_per_line` lines.
|
|
66
|
+
Otherwise, the entire location range is put into a single line.
|
|
67
|
+
symbols_per_line : int, optional
|
|
68
|
+
The amount of
|
|
69
|
+
Does not have an effect, if `multi_line` is false.
|
|
70
|
+
show_numbers : bool, optional
|
|
71
|
+
If true, the sequence position the base/residue of a line is
|
|
72
|
+
shown on the right side of the plot.
|
|
73
|
+
number_size : float, optional
|
|
74
|
+
The font size of the position numbers.
|
|
75
|
+
line_width : float, optional
|
|
76
|
+
The size of the continuous line as fraction of the height of
|
|
77
|
+
the drawn features.
|
|
78
|
+
show_line_position : bool, optional
|
|
79
|
+
If true the position within a line is plotted.
|
|
80
|
+
spacing : float, optional
|
|
81
|
+
The size of the spacing between the lines as fraction of the
|
|
82
|
+
height of the drawn features.
|
|
83
|
+
feature_plotters : list of FeaturePlotter, optional
|
|
84
|
+
Custom plotters for features.
|
|
85
|
+
The list is iterated from the beginning until a
|
|
86
|
+
:class:`FeaturePlotter` matches the respective feature
|
|
87
|
+
(`FeaturePlotter.matches()` returns `True`).
|
|
88
|
+
This :class:`FeaturePlotter` is then used to draw the feature.
|
|
89
|
+
Therefore, the :class:`FeaturePlotter` instances in the list
|
|
90
|
+
have descending priority.
|
|
91
|
+
The default plotters are appended after this supplied list,
|
|
92
|
+
i.e. the default plotters have a lower priority.
|
|
93
|
+
style_param : dict
|
|
94
|
+
Additional style parameters that are given to the
|
|
95
|
+
:class:`FeaturePlotter` objects.
|
|
96
|
+
|
|
97
|
+
Notes
|
|
98
|
+
-----
|
|
99
|
+
Good visulation results are obtained only for non-overlapping
|
|
100
|
+
features.
|
|
101
|
+
When two features overlap, their drawing area does also overlap.
|
|
102
|
+
"""
|
|
103
|
+
from matplotlib.patches import Rectangle
|
|
104
|
+
from matplotlib.transforms import Bbox
|
|
105
|
+
|
|
106
|
+
if loc_range is None:
|
|
107
|
+
loc_range = annotation.get_location_range()
|
|
108
|
+
loc_range_length = loc_range[1] - loc_range[0]
|
|
109
|
+
if multi_line:
|
|
110
|
+
symbols_per_line = symbols_per_line
|
|
111
|
+
else:
|
|
112
|
+
# Line length covers the entire location range
|
|
113
|
+
symbols_per_line = loc_range_length
|
|
114
|
+
|
|
115
|
+
plotters = [
|
|
116
|
+
PromoterPlotter(),
|
|
117
|
+
TerminatorPlotter(),
|
|
118
|
+
RBSPlotter(),
|
|
119
|
+
CodingPlotter(),
|
|
120
|
+
MiscFeaturePlotter(),
|
|
121
|
+
]
|
|
122
|
+
if feature_plotters is not None:
|
|
123
|
+
plotters = list(feature_plotters) + plotters
|
|
124
|
+
|
|
125
|
+
style_param = {} if style_param is None else style_param
|
|
126
|
+
|
|
127
|
+
line_count = loc_range_length // symbols_per_line
|
|
128
|
+
# Only extend line count by 1 if there is a remainder
|
|
129
|
+
if loc_range_length % symbols_per_line != 0:
|
|
130
|
+
line_count += 1
|
|
131
|
+
|
|
132
|
+
### Draw lines ###
|
|
133
|
+
remaining_symbols = loc_range_length
|
|
134
|
+
y = 0.5
|
|
135
|
+
while remaining_symbols > 0:
|
|
136
|
+
if remaining_symbols > symbols_per_line:
|
|
137
|
+
# Line spans the entire plot (horizontally)
|
|
138
|
+
line_length = symbols_per_line
|
|
139
|
+
else:
|
|
140
|
+
# Last line -> Line spans to end of annotation
|
|
141
|
+
line_length = remaining_symbols
|
|
142
|
+
axes.add_patch(
|
|
143
|
+
Rectangle(
|
|
144
|
+
(0, y - line_width / 2),
|
|
145
|
+
line_length,
|
|
146
|
+
line_width,
|
|
147
|
+
color="gray",
|
|
148
|
+
linewidth=0,
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
# Increment by spacing and width (=1) of feature
|
|
152
|
+
y += spacing + 1
|
|
153
|
+
remaining_symbols -= symbols_per_line
|
|
154
|
+
|
|
155
|
+
### Draw features ###
|
|
156
|
+
line_start_loc = loc_range[0]
|
|
157
|
+
y = 0
|
|
158
|
+
while line_start_loc < loc_range[1]:
|
|
159
|
+
annotation_for_line = annotation[
|
|
160
|
+
line_start_loc : line_start_loc + symbols_per_line
|
|
161
|
+
]
|
|
162
|
+
for feature in annotation_for_line:
|
|
163
|
+
plotter = None
|
|
164
|
+
# Identify fitting plotter
|
|
165
|
+
for potentail_plotter in plotters:
|
|
166
|
+
if potentail_plotter.matches(feature):
|
|
167
|
+
# Take first fitting plotter in list
|
|
168
|
+
plotter = potentail_plotter
|
|
169
|
+
break
|
|
170
|
+
if plotter is not None:
|
|
171
|
+
for loc in feature.locs:
|
|
172
|
+
loc_len = loc.last - loc.first + 1
|
|
173
|
+
# Get start location realtive to start if line
|
|
174
|
+
loc_in_line = loc.first - line_start_loc
|
|
175
|
+
x = loc_in_line
|
|
176
|
+
# Line width multiplied by percentage of line
|
|
177
|
+
width = loc_len
|
|
178
|
+
height = 1
|
|
179
|
+
bbox = Bbox.from_bounds(x, y, width, height)
|
|
180
|
+
plotter.draw(axes, feature, bbox, loc, style_param=style_param)
|
|
181
|
+
# Increment by spacing and width (=1) of feature
|
|
182
|
+
y += spacing + 1
|
|
183
|
+
remaining_symbols += symbols_per_line
|
|
184
|
+
line_start_loc += symbols_per_line
|
|
185
|
+
|
|
186
|
+
### Draw position numbers ###
|
|
187
|
+
ticks = []
|
|
188
|
+
tick_labels = []
|
|
189
|
+
if show_numbers:
|
|
190
|
+
# Numbers at center height of each feature line -> 0.5
|
|
191
|
+
y = 0.5
|
|
192
|
+
for i in range(line_count):
|
|
193
|
+
if i == line_count - 1:
|
|
194
|
+
# Last line -> get number of last column in trace
|
|
195
|
+
loc = loc_range[1] - 1
|
|
196
|
+
else:
|
|
197
|
+
loc = loc_range[0] + ((i + 1) * symbols_per_line) - 1
|
|
198
|
+
ticks.append(y)
|
|
199
|
+
tick_labels.append(str(loc))
|
|
200
|
+
# Increment by spacing and width of feature (1)
|
|
201
|
+
y += spacing + 1
|
|
202
|
+
axes.set_yticks(ticks)
|
|
203
|
+
axes.set_yticklabels(tick_labels)
|
|
204
|
+
|
|
205
|
+
axes.set_xlim(0, symbols_per_line)
|
|
206
|
+
# Y-axis starts from top
|
|
207
|
+
axes.set_ylim(1 * line_count + spacing * (line_count - 1), 0)
|
|
208
|
+
axes.set_frame_on(False)
|
|
209
|
+
# Draw location numbers on right side
|
|
210
|
+
axes.get_yaxis().set_tick_params(
|
|
211
|
+
left=False, right=False, labelleft=False, labelright=True
|
|
212
|
+
)
|
|
213
|
+
# Remove ticks and set number font size
|
|
214
|
+
axes.yaxis.set_tick_params(left=False, right=False, labelsize=number_size)
|
|
215
|
+
|
|
216
|
+
if show_line_position:
|
|
217
|
+
axes.xaxis.set_tick_params(
|
|
218
|
+
top=False, bottom=True, labeltop=False, labelbottom=True
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
axes.xaxis.set_tick_params(
|
|
222
|
+
top=False, bottom=False, labeltop=False, labelbottom=False
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class FeaturePlotter(metaclass=abc.ABCMeta):
|
|
227
|
+
"""
|
|
228
|
+
A :class:`FeaturePlotter` is an object, that 'knows' how to draw a
|
|
229
|
+
certain type of sequence feature onto a :class:`matplotlib.Axes`.
|
|
230
|
+
|
|
231
|
+
Whether the :class:`FeaturePlotter` is able to draw a feature, is
|
|
232
|
+
checked via the :func:`matches()` method.
|
|
233
|
+
The visualization of a compatible feature is conducted in the
|
|
234
|
+
:func:`draw()` method.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
def __init__(self):
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
@abc.abstractmethod
|
|
241
|
+
def matches(self, feature):
|
|
242
|
+
"""
|
|
243
|
+
Check, whether this object is able to draw a given sequence
|
|
244
|
+
feature.
|
|
245
|
+
|
|
246
|
+
Parameters
|
|
247
|
+
----------
|
|
248
|
+
feature : Feature
|
|
249
|
+
The sequence feature to be checked.
|
|
250
|
+
|
|
251
|
+
Returns
|
|
252
|
+
-------
|
|
253
|
+
compatibility : bool
|
|
254
|
+
True, if this object is able to draw the given `feature`,
|
|
255
|
+
false otherwise.
|
|
256
|
+
"""
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
@abc.abstractmethod
|
|
260
|
+
def draw(self, axes, feature, bbox, location, style_param):
|
|
261
|
+
"""
|
|
262
|
+
Draw a feature onto an axes.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
axes : Axes
|
|
267
|
+
A *Matplotlib* axes, that is used as plotting area.
|
|
268
|
+
feature : Feature
|
|
269
|
+
The feature to be drawn.
|
|
270
|
+
bbox : Bbox
|
|
271
|
+
The bounding box, that describes the area on the `axes`,
|
|
272
|
+
where the feature should be drawn.
|
|
273
|
+
location : int
|
|
274
|
+
The location of the feature, that should be drawn.
|
|
275
|
+
Might be useful, when the visualization is dependent
|
|
276
|
+
on e.g. location defects.
|
|
277
|
+
style_param : dict
|
|
278
|
+
Additional style parameters.
|
|
279
|
+
"""
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class CodingPlotter(FeaturePlotter):
|
|
284
|
+
"""
|
|
285
|
+
A plotter for the *CDS* and *gene* features.
|
|
286
|
+
|
|
287
|
+
Draws an arrow with a 90 degrees tip.
|
|
288
|
+
|
|
289
|
+
Parameters
|
|
290
|
+
----------
|
|
291
|
+
tail_width : float, optional
|
|
292
|
+
The width of the arrow tail
|
|
293
|
+
as fraction of the feature drawing area height.
|
|
294
|
+
head_width : float, optional
|
|
295
|
+
The width of the arrow head
|
|
296
|
+
as fraction of the feature drawing area height.
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
def __init__(self, tail_width=0.5, head_width=0.8):
|
|
300
|
+
self._tail_width = tail_width
|
|
301
|
+
self._head_width = head_width
|
|
302
|
+
|
|
303
|
+
def matches(self, feature):
|
|
304
|
+
if feature.key in ["CDS", "gene"]:
|
|
305
|
+
return True
|
|
306
|
+
else:
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
def draw(self, axes, feature, bbox, loc, style_param):
|
|
310
|
+
y = bbox.y0 + bbox.height / 2
|
|
311
|
+
dy = 0
|
|
312
|
+
if loc.strand == Location.Strand.FORWARD:
|
|
313
|
+
x = bbox.x0
|
|
314
|
+
dx = bbox.width
|
|
315
|
+
else:
|
|
316
|
+
x = bbox.x1
|
|
317
|
+
dx = -bbox.width
|
|
318
|
+
|
|
319
|
+
if (
|
|
320
|
+
loc.strand == Location.Strand.FORWARD
|
|
321
|
+
and loc.defect & Location.Defect.MISS_RIGHT
|
|
322
|
+
) or (
|
|
323
|
+
loc.strand == Location.Strand.REVERSE
|
|
324
|
+
and loc.defect & Location.Defect.MISS_LEFT
|
|
325
|
+
):
|
|
326
|
+
# If the feature extends into the prevoius or next line
|
|
327
|
+
# do not draw an arrow head
|
|
328
|
+
draw_head = False
|
|
329
|
+
else:
|
|
330
|
+
draw_head = True
|
|
331
|
+
|
|
332
|
+
# Create head with 90 degrees tip -> head width/length ratio = 1/2
|
|
333
|
+
axes.add_patch(
|
|
334
|
+
AdaptiveFancyArrow(
|
|
335
|
+
x,
|
|
336
|
+
y,
|
|
337
|
+
dx,
|
|
338
|
+
dy,
|
|
339
|
+
self._tail_width,
|
|
340
|
+
self._head_width,
|
|
341
|
+
head_ratio=0.5,
|
|
342
|
+
draw_head=draw_head,
|
|
343
|
+
color=colors["dimgreen"],
|
|
344
|
+
linewidth=0,
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if feature.key == "CDS":
|
|
349
|
+
if "product" not in feature.qual:
|
|
350
|
+
label = None
|
|
351
|
+
elif feature.qual["product"] == "hypothetical protein":
|
|
352
|
+
label = None
|
|
353
|
+
else:
|
|
354
|
+
label = feature.qual["product"]
|
|
355
|
+
elif feature.key == "gene":
|
|
356
|
+
if "gene" not in feature.qual:
|
|
357
|
+
label = None
|
|
358
|
+
else:
|
|
359
|
+
label = feature.qual["gene"]
|
|
360
|
+
|
|
361
|
+
if label is not None:
|
|
362
|
+
center_x = bbox.x0 + bbox.width / 2
|
|
363
|
+
center_y = bbox.y0 + bbox.height / 2
|
|
364
|
+
axes.text(
|
|
365
|
+
center_x,
|
|
366
|
+
center_y,
|
|
367
|
+
label,
|
|
368
|
+
color="black",
|
|
369
|
+
ha="center",
|
|
370
|
+
va="center",
|
|
371
|
+
size=11,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class MiscFeaturePlotter(FeaturePlotter):
|
|
376
|
+
"""
|
|
377
|
+
A plotter that matches any feature.
|
|
378
|
+
|
|
379
|
+
Draws a simple Rectangle.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
height : float, optional
|
|
384
|
+
The width of the rectangle
|
|
385
|
+
as fraction of the feature drawing area height.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
def __init__(self, height=0.4):
|
|
389
|
+
self._height = height
|
|
390
|
+
|
|
391
|
+
def matches(self, feature):
|
|
392
|
+
return True
|
|
393
|
+
|
|
394
|
+
def draw(self, axes, feature, bbox, loc, style_param):
|
|
395
|
+
from matplotlib.patches import Rectangle
|
|
396
|
+
|
|
397
|
+
rect = Rectangle(
|
|
398
|
+
(bbox.x0, bbox.y0 + bbox.height / 2 * (1 - self._height)),
|
|
399
|
+
bbox.width,
|
|
400
|
+
bbox.height * self._height,
|
|
401
|
+
color=colors["dimorange"],
|
|
402
|
+
linewidth=0,
|
|
403
|
+
)
|
|
404
|
+
axes.add_patch(rect)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class PromoterPlotter(FeaturePlotter):
|
|
408
|
+
"""
|
|
409
|
+
A plotter for *regulatory* features with the *promoter* or
|
|
410
|
+
*TATA_box* class.
|
|
411
|
+
|
|
412
|
+
Draws a simple curved thin black arrow.
|
|
413
|
+
|
|
414
|
+
Parameters
|
|
415
|
+
----------
|
|
416
|
+
line_width : float, optional
|
|
417
|
+
The width of the curved arrow tail.
|
|
418
|
+
head_width : float, optional
|
|
419
|
+
The width of the arrow head.
|
|
420
|
+
head_length : float, optional
|
|
421
|
+
The length of the arrow.
|
|
422
|
+
head_height : float, optional
|
|
423
|
+
The Y-position of the arrow head
|
|
424
|
+
as fraction of the halffeature drawing area height.
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
def __init__(self, line_width=2, head_width=2, head_length=6, head_height=0.8):
|
|
428
|
+
self._line_width = line_width
|
|
429
|
+
self._head_width = head_width
|
|
430
|
+
self._head_length = head_length
|
|
431
|
+
self._head_height = head_height
|
|
432
|
+
|
|
433
|
+
def matches(self, feature):
|
|
434
|
+
if feature.key == "regulatory":
|
|
435
|
+
if "regulatory_class" in feature.qual:
|
|
436
|
+
if feature.qual["regulatory_class"] in ["promoter", "TATA_box"]:
|
|
437
|
+
return True
|
|
438
|
+
return False
|
|
439
|
+
|
|
440
|
+
def draw(self, axes, feature, bbox, loc, style_param):
|
|
441
|
+
from matplotlib.patches import ArrowStyle, FancyArrowPatch
|
|
442
|
+
from matplotlib.path import Path
|
|
443
|
+
|
|
444
|
+
x_center = bbox.x0 + bbox.width / 2
|
|
445
|
+
y_center = bbox.y0 + bbox.height / 2
|
|
446
|
+
|
|
447
|
+
path = Path(
|
|
448
|
+
vertices=[
|
|
449
|
+
(bbox.x0, y_center),
|
|
450
|
+
(bbox.x0, y_center - bbox.height / 2 * self._head_height),
|
|
451
|
+
(bbox.x1, y_center - bbox.height / 2 * self._head_height),
|
|
452
|
+
],
|
|
453
|
+
codes=[Path.MOVETO, Path.CURVE3, Path.CURVE3],
|
|
454
|
+
)
|
|
455
|
+
style = ArrowStyle.CurveFilledB(
|
|
456
|
+
head_width=self._head_width, head_length=self._head_length
|
|
457
|
+
)
|
|
458
|
+
arrow = FancyArrowPatch(
|
|
459
|
+
path=path, arrowstyle=style, linewidth=self._line_width, color="black"
|
|
460
|
+
)
|
|
461
|
+
axes.add_patch(arrow)
|
|
462
|
+
|
|
463
|
+
if "note" in feature.qual:
|
|
464
|
+
axes.text(
|
|
465
|
+
x_center,
|
|
466
|
+
y_center + bbox.height / 4,
|
|
467
|
+
feature.qual["note"],
|
|
468
|
+
color="black",
|
|
469
|
+
ha="center",
|
|
470
|
+
va="center",
|
|
471
|
+
size=9,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class TerminatorPlotter(FeaturePlotter):
|
|
476
|
+
"""
|
|
477
|
+
A plotter for *regulatory* features with the *terminator* class.
|
|
478
|
+
|
|
479
|
+
Draws a vertical bar.
|
|
480
|
+
|
|
481
|
+
Parameters
|
|
482
|
+
----------
|
|
483
|
+
bar_width : float, optional
|
|
484
|
+
The width of the line representing the bar.
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
def __init__(self, bar_width=5):
|
|
488
|
+
self._bar_width = bar_width
|
|
489
|
+
|
|
490
|
+
def matches(self, feature):
|
|
491
|
+
if feature.key == "regulatory":
|
|
492
|
+
if "regulatory_class" in feature.qual:
|
|
493
|
+
if feature.qual["regulatory_class"] == "terminator":
|
|
494
|
+
return True
|
|
495
|
+
return False
|
|
496
|
+
|
|
497
|
+
def draw(self, axes, feature, bbox, loc, style_param):
|
|
498
|
+
x = bbox.x0 + bbox.width / 2
|
|
499
|
+
|
|
500
|
+
axes.plot(
|
|
501
|
+
(x, x),
|
|
502
|
+
(bbox.y0, bbox.y1),
|
|
503
|
+
color="black",
|
|
504
|
+
linestyle="-",
|
|
505
|
+
linewidth=self._bar_width,
|
|
506
|
+
marker="None",
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
class RBSPlotter(FeaturePlotter):
|
|
511
|
+
"""
|
|
512
|
+
A plotter for *regulatory* features with the
|
|
513
|
+
*ribosome_binding_site* class.
|
|
514
|
+
|
|
515
|
+
Draws an ellipse.
|
|
516
|
+
|
|
517
|
+
Parameters
|
|
518
|
+
----------
|
|
519
|
+
height : float, optional
|
|
520
|
+
The width of the ellipse
|
|
521
|
+
as fraction of the feature drawing area height.
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
def __init__(self, height=0.4):
|
|
525
|
+
self._height = height
|
|
526
|
+
|
|
527
|
+
def matches(self, feature):
|
|
528
|
+
if feature.key == "regulatory":
|
|
529
|
+
if "regulatory_class" in feature.qual:
|
|
530
|
+
if feature.qual["regulatory_class"] == "ribosome_binding_site":
|
|
531
|
+
return True
|
|
532
|
+
return False
|
|
533
|
+
|
|
534
|
+
def draw(self, axes, feature, bbox, loc, style_param):
|
|
535
|
+
from matplotlib.patches import Ellipse
|
|
536
|
+
|
|
537
|
+
ellipse = Ellipse(
|
|
538
|
+
(bbox.x0 + bbox.width / 2, bbox.y0 + bbox.height / 2),
|
|
539
|
+
bbox.width,
|
|
540
|
+
self._height * bbox.height,
|
|
541
|
+
color=colors["dimorange"],
|
|
542
|
+
linewidth=0,
|
|
543
|
+
)
|
|
544
|
+
axes.add_patch(ellipse)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# This source code is part of the Biotite package and is distributed
|
|
2
|
+
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
|
|
3
|
+
# information.
|
|
4
|
+
|
|
5
|
+
__name__ = "biotite.sequence.graphics"
|
|
6
|
+
__author__ = "Patrick Kunzmann"
|
|
7
|
+
__all__ = ["plot_sequence_logo"]
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from biotite.sequence.alphabet import LetterAlphabet
|
|
11
|
+
from biotite.sequence.graphics.colorschemes import get_color_scheme
|
|
12
|
+
from biotite.visualize import plot_scaled_text
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def plot_sequence_logo(axes, profile, scheme=None, **kwargs):
|
|
16
|
+
"""
|
|
17
|
+
Create a sequence logo. :footcite:`Schneider1990`
|
|
18
|
+
|
|
19
|
+
A sequence logo is visualizes the positional composition and
|
|
20
|
+
conservation of a profile encoded in the size of the letters.
|
|
21
|
+
Each position displays all symbols that are occurring at this
|
|
22
|
+
position stacked on each other, with their relative heights depicting
|
|
23
|
+
their relative frequency.
|
|
24
|
+
The height of such a stack depicts its conservation.
|
|
25
|
+
It is the maximum possible Shannon entropy of the alphabet
|
|
26
|
+
subtracted by the positional entropy.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
axes : Axes
|
|
31
|
+
The axes to draw the logo one.
|
|
32
|
+
profile : SequenceProfile
|
|
33
|
+
The logo is created based on this profile.
|
|
34
|
+
scheme : str or list of (tuple or str)
|
|
35
|
+
Either a valid color scheme name
|
|
36
|
+
(e.g. ``"flower"``, ``"clustalx"``, ``blossom``, etc.)
|
|
37
|
+
or a list of *Matplotlib* compatible colors.
|
|
38
|
+
The list length must be at least as long as the
|
|
39
|
+
length of the alphabet used by the `profile`.
|
|
40
|
+
**kwargs
|
|
41
|
+
Additional parameters for the :class:`matplotlib.font_manager.FontProperties`
|
|
42
|
+
of the text or the created :class:`matplotlib.patches.PathPatch`.
|
|
43
|
+
|
|
44
|
+
References
|
|
45
|
+
----------
|
|
46
|
+
|
|
47
|
+
.. footbibliography::
|
|
48
|
+
"""
|
|
49
|
+
alphabet = profile.alphabet
|
|
50
|
+
if not isinstance(alphabet, LetterAlphabet):
|
|
51
|
+
raise TypeError("The sequences' alphabet must be a letter alphabet")
|
|
52
|
+
|
|
53
|
+
if scheme is None:
|
|
54
|
+
colors = get_color_scheme("flower", alphabet)
|
|
55
|
+
elif isinstance(scheme, str):
|
|
56
|
+
colors = get_color_scheme(scheme, alphabet)
|
|
57
|
+
else:
|
|
58
|
+
colors = scheme
|
|
59
|
+
|
|
60
|
+
# 'color' and 'size' property is not passed on to text
|
|
61
|
+
kwargs.pop("color", None)
|
|
62
|
+
kwargs.pop("size", None)
|
|
63
|
+
|
|
64
|
+
frequencies, entropies, max_entropy = _get_entropy(profile)
|
|
65
|
+
stack_heights = max_entropy - entropies
|
|
66
|
+
symbols_heights = stack_heights[:, np.newaxis] * frequencies
|
|
67
|
+
index_order = np.argsort(symbols_heights, axis=1)
|
|
68
|
+
for i in range(symbols_heights.shape[0]):
|
|
69
|
+
# Iterate over the alignment columns
|
|
70
|
+
index_order = np.argsort(symbols_heights)
|
|
71
|
+
start_height = 0
|
|
72
|
+
for j in index_order[i]:
|
|
73
|
+
# Stack the symbols at position on top of the preceding one
|
|
74
|
+
height = symbols_heights[i, j]
|
|
75
|
+
if height > 0:
|
|
76
|
+
symbol = alphabet.decode(j)
|
|
77
|
+
plot_scaled_text(
|
|
78
|
+
axes,
|
|
79
|
+
symbol,
|
|
80
|
+
i + 0.5,
|
|
81
|
+
start_height,
|
|
82
|
+
width=1,
|
|
83
|
+
height=height,
|
|
84
|
+
color=colors[j],
|
|
85
|
+
**kwargs,
|
|
86
|
+
)
|
|
87
|
+
start_height += height
|
|
88
|
+
|
|
89
|
+
axes.set_xlim(0.5, len(profile.symbols) + 0.5)
|
|
90
|
+
axes.set_ylim(0, max_entropy)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _get_entropy(profile):
|
|
94
|
+
freq = profile.symbols
|
|
95
|
+
freq = freq / np.sum(freq, axis=1)[:, np.newaxis]
|
|
96
|
+
# 0 * log2(0) = 0 -> Convert NaN to 0
|
|
97
|
+
no_zeros = freq != 0
|
|
98
|
+
pre_entropies = np.zeros(freq.shape)
|
|
99
|
+
pre_entropies[no_zeros] = freq[no_zeros] * np.log2(freq[no_zeros])
|
|
100
|
+
entropies = -np.sum(pre_entropies, axis=1)
|
|
101
|
+
max_entropy = np.log2(len(profile.alphabet))
|
|
102
|
+
return freq, entropies, max_entropy
|