biotite 1.5.0__cp311-cp311-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.

Files changed (354) hide show
  1. biotite/__init__.py +18 -0
  2. biotite/application/__init__.py +69 -0
  3. biotite/application/application.py +276 -0
  4. biotite/application/autodock/__init__.py +12 -0
  5. biotite/application/autodock/app.py +500 -0
  6. biotite/application/blast/__init__.py +14 -0
  7. biotite/application/blast/alignment.py +92 -0
  8. biotite/application/blast/webapp.py +428 -0
  9. biotite/application/clustalo/__init__.py +12 -0
  10. biotite/application/clustalo/app.py +223 -0
  11. biotite/application/dssp/__init__.py +12 -0
  12. biotite/application/dssp/app.py +216 -0
  13. biotite/application/localapp.py +342 -0
  14. biotite/application/mafft/__init__.py +12 -0
  15. biotite/application/mafft/app.py +116 -0
  16. biotite/application/msaapp.py +363 -0
  17. biotite/application/muscle/__init__.py +13 -0
  18. biotite/application/muscle/app3.py +227 -0
  19. biotite/application/muscle/app5.py +163 -0
  20. biotite/application/sra/__init__.py +18 -0
  21. biotite/application/sra/app.py +447 -0
  22. biotite/application/tantan/__init__.py +12 -0
  23. biotite/application/tantan/app.py +199 -0
  24. biotite/application/util.py +77 -0
  25. biotite/application/viennarna/__init__.py +18 -0
  26. biotite/application/viennarna/rnaalifold.py +310 -0
  27. biotite/application/viennarna/rnafold.py +254 -0
  28. biotite/application/viennarna/rnaplot.py +208 -0
  29. biotite/application/viennarna/util.py +77 -0
  30. biotite/application/webapp.py +76 -0
  31. biotite/copyable.py +71 -0
  32. biotite/database/__init__.py +23 -0
  33. biotite/database/afdb/__init__.py +12 -0
  34. biotite/database/afdb/download.py +197 -0
  35. biotite/database/entrez/__init__.py +15 -0
  36. biotite/database/entrez/check.py +60 -0
  37. biotite/database/entrez/dbnames.py +101 -0
  38. biotite/database/entrez/download.py +228 -0
  39. biotite/database/entrez/key.py +44 -0
  40. biotite/database/entrez/query.py +263 -0
  41. biotite/database/error.py +16 -0
  42. biotite/database/pubchem/__init__.py +21 -0
  43. biotite/database/pubchem/download.py +258 -0
  44. biotite/database/pubchem/error.py +30 -0
  45. biotite/database/pubchem/query.py +819 -0
  46. biotite/database/pubchem/throttle.py +98 -0
  47. biotite/database/rcsb/__init__.py +13 -0
  48. biotite/database/rcsb/download.py +161 -0
  49. biotite/database/rcsb/query.py +963 -0
  50. biotite/database/uniprot/__init__.py +13 -0
  51. biotite/database/uniprot/check.py +40 -0
  52. biotite/database/uniprot/download.py +126 -0
  53. biotite/database/uniprot/query.py +292 -0
  54. biotite/file.py +244 -0
  55. biotite/interface/__init__.py +19 -0
  56. biotite/interface/openmm/__init__.py +20 -0
  57. biotite/interface/openmm/state.py +93 -0
  58. biotite/interface/openmm/system.py +227 -0
  59. biotite/interface/pymol/__init__.py +201 -0
  60. biotite/interface/pymol/cgo.py +346 -0
  61. biotite/interface/pymol/convert.py +185 -0
  62. biotite/interface/pymol/display.py +267 -0
  63. biotite/interface/pymol/object.py +1228 -0
  64. biotite/interface/pymol/shapes.py +178 -0
  65. biotite/interface/pymol/startup.py +169 -0
  66. biotite/interface/rdkit/__init__.py +19 -0
  67. biotite/interface/rdkit/mol.py +490 -0
  68. biotite/interface/version.py +94 -0
  69. biotite/interface/warning.py +19 -0
  70. biotite/sequence/__init__.py +84 -0
  71. biotite/sequence/align/__init__.py +199 -0
  72. biotite/sequence/align/alignment.py +702 -0
  73. biotite/sequence/align/banded.cpython-311-x86_64-linux-gnu.so +0 -0
  74. biotite/sequence/align/banded.pyx +652 -0
  75. biotite/sequence/align/buckets.py +71 -0
  76. biotite/sequence/align/cigar.py +425 -0
  77. biotite/sequence/align/kmeralphabet.cpython-311-x86_64-linux-gnu.so +0 -0
  78. biotite/sequence/align/kmeralphabet.pyx +595 -0
  79. biotite/sequence/align/kmersimilarity.cpython-311-x86_64-linux-gnu.so +0 -0
  80. biotite/sequence/align/kmersimilarity.pyx +233 -0
  81. biotite/sequence/align/kmertable.cpython-311-x86_64-linux-gnu.so +0 -0
  82. biotite/sequence/align/kmertable.pyx +3411 -0
  83. biotite/sequence/align/localgapped.cpython-311-x86_64-linux-gnu.so +0 -0
  84. biotite/sequence/align/localgapped.pyx +892 -0
  85. biotite/sequence/align/localungapped.cpython-311-x86_64-linux-gnu.so +0 -0
  86. biotite/sequence/align/localungapped.pyx +279 -0
  87. biotite/sequence/align/matrix.py +631 -0
  88. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  89. biotite/sequence/align/matrix_data/BLOSUM100.mat +31 -0
  90. biotite/sequence/align/matrix_data/BLOSUM30.mat +31 -0
  91. biotite/sequence/align/matrix_data/BLOSUM35.mat +31 -0
  92. biotite/sequence/align/matrix_data/BLOSUM40.mat +31 -0
  93. biotite/sequence/align/matrix_data/BLOSUM45.mat +31 -0
  94. biotite/sequence/align/matrix_data/BLOSUM50.mat +31 -0
  95. biotite/sequence/align/matrix_data/BLOSUM50_13p.mat +25 -0
  96. biotite/sequence/align/matrix_data/BLOSUM50_14.3.mat +25 -0
  97. biotite/sequence/align/matrix_data/BLOSUM50_5.0.mat +25 -0
  98. biotite/sequence/align/matrix_data/BLOSUM55.mat +31 -0
  99. biotite/sequence/align/matrix_data/BLOSUM60.mat +31 -0
  100. biotite/sequence/align/matrix_data/BLOSUM62.mat +31 -0
  101. biotite/sequence/align/matrix_data/BLOSUM62_13p.mat +25 -0
  102. biotite/sequence/align/matrix_data/BLOSUM62_14.3.mat +25 -0
  103. biotite/sequence/align/matrix_data/BLOSUM62_5.0.mat +25 -0
  104. biotite/sequence/align/matrix_data/BLOSUM65.mat +31 -0
  105. biotite/sequence/align/matrix_data/BLOSUM70.mat +31 -0
  106. biotite/sequence/align/matrix_data/BLOSUM75.mat +31 -0
  107. biotite/sequence/align/matrix_data/BLOSUM80.mat +31 -0
  108. biotite/sequence/align/matrix_data/BLOSUM85.mat +31 -0
  109. biotite/sequence/align/matrix_data/BLOSUM90.mat +31 -0
  110. biotite/sequence/align/matrix_data/BLOSUMN.mat +31 -0
  111. biotite/sequence/align/matrix_data/CorBLOSUM49_5.0.mat +25 -0
  112. biotite/sequence/align/matrix_data/CorBLOSUM57_13p.mat +25 -0
  113. biotite/sequence/align/matrix_data/CorBLOSUM57_14.3.mat +25 -0
  114. biotite/sequence/align/matrix_data/CorBLOSUM61_5.0.mat +25 -0
  115. biotite/sequence/align/matrix_data/CorBLOSUM66_13p.mat +25 -0
  116. biotite/sequence/align/matrix_data/CorBLOSUM67_14.3.mat +25 -0
  117. biotite/sequence/align/matrix_data/DAYHOFF.mat +32 -0
  118. biotite/sequence/align/matrix_data/GONNET.mat +26 -0
  119. biotite/sequence/align/matrix_data/IDENTITY.mat +25 -0
  120. biotite/sequence/align/matrix_data/MATCH.mat +25 -0
  121. biotite/sequence/align/matrix_data/NUC.mat +25 -0
  122. biotite/sequence/align/matrix_data/PAM10.mat +34 -0
  123. biotite/sequence/align/matrix_data/PAM100.mat +34 -0
  124. biotite/sequence/align/matrix_data/PAM110.mat +34 -0
  125. biotite/sequence/align/matrix_data/PAM120.mat +34 -0
  126. biotite/sequence/align/matrix_data/PAM130.mat +34 -0
  127. biotite/sequence/align/matrix_data/PAM140.mat +34 -0
  128. biotite/sequence/align/matrix_data/PAM150.mat +34 -0
  129. biotite/sequence/align/matrix_data/PAM160.mat +34 -0
  130. biotite/sequence/align/matrix_data/PAM170.mat +34 -0
  131. biotite/sequence/align/matrix_data/PAM180.mat +34 -0
  132. biotite/sequence/align/matrix_data/PAM190.mat +34 -0
  133. biotite/sequence/align/matrix_data/PAM20.mat +34 -0
  134. biotite/sequence/align/matrix_data/PAM200.mat +34 -0
  135. biotite/sequence/align/matrix_data/PAM210.mat +34 -0
  136. biotite/sequence/align/matrix_data/PAM220.mat +34 -0
  137. biotite/sequence/align/matrix_data/PAM230.mat +34 -0
  138. biotite/sequence/align/matrix_data/PAM240.mat +34 -0
  139. biotite/sequence/align/matrix_data/PAM250.mat +34 -0
  140. biotite/sequence/align/matrix_data/PAM260.mat +34 -0
  141. biotite/sequence/align/matrix_data/PAM270.mat +34 -0
  142. biotite/sequence/align/matrix_data/PAM280.mat +34 -0
  143. biotite/sequence/align/matrix_data/PAM290.mat +34 -0
  144. biotite/sequence/align/matrix_data/PAM30.mat +34 -0
  145. biotite/sequence/align/matrix_data/PAM300.mat +34 -0
  146. biotite/sequence/align/matrix_data/PAM310.mat +34 -0
  147. biotite/sequence/align/matrix_data/PAM320.mat +34 -0
  148. biotite/sequence/align/matrix_data/PAM330.mat +34 -0
  149. biotite/sequence/align/matrix_data/PAM340.mat +34 -0
  150. biotite/sequence/align/matrix_data/PAM350.mat +34 -0
  151. biotite/sequence/align/matrix_data/PAM360.mat +34 -0
  152. biotite/sequence/align/matrix_data/PAM370.mat +34 -0
  153. biotite/sequence/align/matrix_data/PAM380.mat +34 -0
  154. biotite/sequence/align/matrix_data/PAM390.mat +34 -0
  155. biotite/sequence/align/matrix_data/PAM40.mat +34 -0
  156. biotite/sequence/align/matrix_data/PAM400.mat +34 -0
  157. biotite/sequence/align/matrix_data/PAM410.mat +34 -0
  158. biotite/sequence/align/matrix_data/PAM420.mat +34 -0
  159. biotite/sequence/align/matrix_data/PAM430.mat +34 -0
  160. biotite/sequence/align/matrix_data/PAM440.mat +34 -0
  161. biotite/sequence/align/matrix_data/PAM450.mat +34 -0
  162. biotite/sequence/align/matrix_data/PAM460.mat +34 -0
  163. biotite/sequence/align/matrix_data/PAM470.mat +34 -0
  164. biotite/sequence/align/matrix_data/PAM480.mat +34 -0
  165. biotite/sequence/align/matrix_data/PAM490.mat +34 -0
  166. biotite/sequence/align/matrix_data/PAM50.mat +34 -0
  167. biotite/sequence/align/matrix_data/PAM500.mat +34 -0
  168. biotite/sequence/align/matrix_data/PAM60.mat +34 -0
  169. biotite/sequence/align/matrix_data/PAM70.mat +34 -0
  170. biotite/sequence/align/matrix_data/PAM80.mat +34 -0
  171. biotite/sequence/align/matrix_data/PAM90.mat +34 -0
  172. biotite/sequence/align/matrix_data/PB.license +21 -0
  173. biotite/sequence/align/matrix_data/PB.mat +18 -0
  174. biotite/sequence/align/matrix_data/RBLOSUM52_5.0.mat +25 -0
  175. biotite/sequence/align/matrix_data/RBLOSUM59_13p.mat +25 -0
  176. biotite/sequence/align/matrix_data/RBLOSUM59_14.3.mat +25 -0
  177. biotite/sequence/align/matrix_data/RBLOSUM64_5.0.mat +25 -0
  178. biotite/sequence/align/matrix_data/RBLOSUM69_13p.mat +25 -0
  179. biotite/sequence/align/matrix_data/RBLOSUM69_14.3.mat +25 -0
  180. biotite/sequence/align/multiple.cpython-311-x86_64-linux-gnu.so +0 -0
  181. biotite/sequence/align/multiple.pyx +619 -0
  182. biotite/sequence/align/pairwise.cpython-311-x86_64-linux-gnu.so +0 -0
  183. biotite/sequence/align/pairwise.pyx +585 -0
  184. biotite/sequence/align/permutation.cpython-311-x86_64-linux-gnu.so +0 -0
  185. biotite/sequence/align/permutation.pyx +313 -0
  186. biotite/sequence/align/primes.txt +821 -0
  187. biotite/sequence/align/selector.cpython-311-x86_64-linux-gnu.so +0 -0
  188. biotite/sequence/align/selector.pyx +954 -0
  189. biotite/sequence/align/statistics.py +264 -0
  190. biotite/sequence/align/tracetable.cpython-311-x86_64-linux-gnu.so +0 -0
  191. biotite/sequence/align/tracetable.pxd +64 -0
  192. biotite/sequence/align/tracetable.pyx +370 -0
  193. biotite/sequence/alphabet.py +555 -0
  194. biotite/sequence/annotation.py +836 -0
  195. biotite/sequence/codec.cpython-311-x86_64-linux-gnu.so +0 -0
  196. biotite/sequence/codec.pyx +155 -0
  197. biotite/sequence/codon.py +476 -0
  198. biotite/sequence/codon_tables.txt +202 -0
  199. biotite/sequence/graphics/__init__.py +33 -0
  200. biotite/sequence/graphics/alignment.py +1101 -0
  201. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  202. biotite/sequence/graphics/color_schemes/autumn.json +51 -0
  203. biotite/sequence/graphics/color_schemes/blossom.json +51 -0
  204. biotite/sequence/graphics/color_schemes/clustalx_dna.json +11 -0
  205. biotite/sequence/graphics/color_schemes/clustalx_protein.json +28 -0
  206. biotite/sequence/graphics/color_schemes/flower.json +51 -0
  207. biotite/sequence/graphics/color_schemes/jalview_buried.json +31 -0
  208. biotite/sequence/graphics/color_schemes/jalview_hydrophobicity.json +31 -0
  209. biotite/sequence/graphics/color_schemes/jalview_prop_helix.json +31 -0
  210. biotite/sequence/graphics/color_schemes/jalview_prop_strand.json +31 -0
  211. biotite/sequence/graphics/color_schemes/jalview_prop_turn.json +31 -0
  212. biotite/sequence/graphics/color_schemes/jalview_taylor.json +28 -0
  213. biotite/sequence/graphics/color_schemes/jalview_zappo.json +28 -0
  214. biotite/sequence/graphics/color_schemes/ocean.json +51 -0
  215. biotite/sequence/graphics/color_schemes/pb_flower.json +40 -0
  216. biotite/sequence/graphics/color_schemes/rainbow_dna.json +11 -0
  217. biotite/sequence/graphics/color_schemes/rainbow_protein.json +30 -0
  218. biotite/sequence/graphics/color_schemes/spring.json +51 -0
  219. biotite/sequence/graphics/color_schemes/sunset.json +51 -0
  220. biotite/sequence/graphics/color_schemes/wither.json +51 -0
  221. biotite/sequence/graphics/colorschemes.py +170 -0
  222. biotite/sequence/graphics/dendrogram.py +231 -0
  223. biotite/sequence/graphics/features.py +544 -0
  224. biotite/sequence/graphics/logo.py +102 -0
  225. biotite/sequence/graphics/plasmid.py +712 -0
  226. biotite/sequence/io/__init__.py +12 -0
  227. biotite/sequence/io/fasta/__init__.py +22 -0
  228. biotite/sequence/io/fasta/convert.py +283 -0
  229. biotite/sequence/io/fasta/file.py +265 -0
  230. biotite/sequence/io/fastq/__init__.py +19 -0
  231. biotite/sequence/io/fastq/convert.py +117 -0
  232. biotite/sequence/io/fastq/file.py +507 -0
  233. biotite/sequence/io/genbank/__init__.py +17 -0
  234. biotite/sequence/io/genbank/annotation.py +269 -0
  235. biotite/sequence/io/genbank/file.py +573 -0
  236. biotite/sequence/io/genbank/metadata.py +336 -0
  237. biotite/sequence/io/genbank/sequence.py +173 -0
  238. biotite/sequence/io/general.py +201 -0
  239. biotite/sequence/io/gff/__init__.py +26 -0
  240. biotite/sequence/io/gff/convert.py +128 -0
  241. biotite/sequence/io/gff/file.py +449 -0
  242. biotite/sequence/phylo/__init__.py +36 -0
  243. biotite/sequence/phylo/nj.cpython-311-x86_64-linux-gnu.so +0 -0
  244. biotite/sequence/phylo/nj.pyx +221 -0
  245. biotite/sequence/phylo/tree.cpython-311-x86_64-linux-gnu.so +0 -0
  246. biotite/sequence/phylo/tree.pyx +1169 -0
  247. biotite/sequence/phylo/upgma.cpython-311-x86_64-linux-gnu.so +0 -0
  248. biotite/sequence/phylo/upgma.pyx +164 -0
  249. biotite/sequence/profile.py +561 -0
  250. biotite/sequence/search.py +117 -0
  251. biotite/sequence/seqtypes.py +720 -0
  252. biotite/sequence/sequence.py +373 -0
  253. biotite/setup_ccd.py +197 -0
  254. biotite/structure/__init__.py +135 -0
  255. biotite/structure/alphabet/__init__.py +25 -0
  256. biotite/structure/alphabet/encoder.py +332 -0
  257. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  258. biotite/structure/alphabet/i3d.py +109 -0
  259. biotite/structure/alphabet/layers.py +86 -0
  260. biotite/structure/alphabet/pb.license +21 -0
  261. biotite/structure/alphabet/pb.py +170 -0
  262. biotite/structure/alphabet/unkerasify.py +128 -0
  263. biotite/structure/atoms.py +1562 -0
  264. biotite/structure/basepairs.py +1403 -0
  265. biotite/structure/bonds.cpython-311-x86_64-linux-gnu.so +0 -0
  266. biotite/structure/bonds.pyx +2036 -0
  267. biotite/structure/box.py +724 -0
  268. biotite/structure/celllist.cpython-311-x86_64-linux-gnu.so +0 -0
  269. biotite/structure/celllist.pyx +864 -0
  270. biotite/structure/chains.py +310 -0
  271. biotite/structure/charges.cpython-311-x86_64-linux-gnu.so +0 -0
  272. biotite/structure/charges.pyx +520 -0
  273. biotite/structure/compare.py +683 -0
  274. biotite/structure/density.py +109 -0
  275. biotite/structure/dotbracket.py +213 -0
  276. biotite/structure/error.py +39 -0
  277. biotite/structure/filter.py +591 -0
  278. biotite/structure/geometry.py +817 -0
  279. biotite/structure/graphics/__init__.py +13 -0
  280. biotite/structure/graphics/atoms.py +243 -0
  281. biotite/structure/graphics/rna.py +298 -0
  282. biotite/structure/hbond.py +425 -0
  283. biotite/structure/info/__init__.py +24 -0
  284. biotite/structure/info/atom_masses.json +121 -0
  285. biotite/structure/info/atoms.py +98 -0
  286. biotite/structure/info/bonds.py +149 -0
  287. biotite/structure/info/ccd.py +200 -0
  288. biotite/structure/info/components.bcif +0 -0
  289. biotite/structure/info/groups.py +128 -0
  290. biotite/structure/info/masses.py +121 -0
  291. biotite/structure/info/misc.py +137 -0
  292. biotite/structure/info/radii.py +267 -0
  293. biotite/structure/info/standardize.py +185 -0
  294. biotite/structure/integrity.py +213 -0
  295. biotite/structure/io/__init__.py +29 -0
  296. biotite/structure/io/dcd/__init__.py +13 -0
  297. biotite/structure/io/dcd/file.py +67 -0
  298. biotite/structure/io/general.py +243 -0
  299. biotite/structure/io/gro/__init__.py +14 -0
  300. biotite/structure/io/gro/file.py +343 -0
  301. biotite/structure/io/mol/__init__.py +20 -0
  302. biotite/structure/io/mol/convert.py +112 -0
  303. biotite/structure/io/mol/ctab.py +420 -0
  304. biotite/structure/io/mol/header.py +120 -0
  305. biotite/structure/io/mol/mol.py +149 -0
  306. biotite/structure/io/mol/sdf.py +940 -0
  307. biotite/structure/io/netcdf/__init__.py +13 -0
  308. biotite/structure/io/netcdf/file.py +64 -0
  309. biotite/structure/io/pdb/__init__.py +20 -0
  310. biotite/structure/io/pdb/convert.py +389 -0
  311. biotite/structure/io/pdb/file.py +1380 -0
  312. biotite/structure/io/pdb/hybrid36.cpython-311-x86_64-linux-gnu.so +0 -0
  313. biotite/structure/io/pdb/hybrid36.pyx +242 -0
  314. biotite/structure/io/pdbqt/__init__.py +15 -0
  315. biotite/structure/io/pdbqt/convert.py +113 -0
  316. biotite/structure/io/pdbqt/file.py +688 -0
  317. biotite/structure/io/pdbx/__init__.py +23 -0
  318. biotite/structure/io/pdbx/bcif.py +674 -0
  319. biotite/structure/io/pdbx/cif.py +1091 -0
  320. biotite/structure/io/pdbx/component.py +251 -0
  321. biotite/structure/io/pdbx/compress.py +362 -0
  322. biotite/structure/io/pdbx/convert.py +2113 -0
  323. biotite/structure/io/pdbx/encoding.cpython-311-x86_64-linux-gnu.so +0 -0
  324. biotite/structure/io/pdbx/encoding.pyx +1078 -0
  325. biotite/structure/io/trajfile.py +696 -0
  326. biotite/structure/io/trr/__init__.py +13 -0
  327. biotite/structure/io/trr/file.py +43 -0
  328. biotite/structure/io/util.py +38 -0
  329. biotite/structure/io/xtc/__init__.py +13 -0
  330. biotite/structure/io/xtc/file.py +43 -0
  331. biotite/structure/mechanics.py +72 -0
  332. biotite/structure/molecules.py +337 -0
  333. biotite/structure/pseudoknots.py +622 -0
  334. biotite/structure/rdf.py +245 -0
  335. biotite/structure/repair.py +302 -0
  336. biotite/structure/residues.py +716 -0
  337. biotite/structure/rings.py +451 -0
  338. biotite/structure/sasa.cpython-311-x86_64-linux-gnu.so +0 -0
  339. biotite/structure/sasa.pyx +322 -0
  340. biotite/structure/segments.py +328 -0
  341. biotite/structure/sequence.py +110 -0
  342. biotite/structure/spacegroups.json +1567 -0
  343. biotite/structure/spacegroups.license +26 -0
  344. biotite/structure/sse.py +306 -0
  345. biotite/structure/superimpose.py +511 -0
  346. biotite/structure/tm.py +581 -0
  347. biotite/structure/transform.py +736 -0
  348. biotite/structure/util.py +160 -0
  349. biotite/version.py +34 -0
  350. biotite/visualize.py +375 -0
  351. biotite-1.5.0.dist-info/METADATA +162 -0
  352. biotite-1.5.0.dist-info/RECORD +354 -0
  353. biotite-1.5.0.dist-info/WHEEL +6 -0
  354. biotite-1.5.0.dist-info/licenses/LICENSE.rst +30 -0
@@ -0,0 +1,712 @@
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_plasmid_map"]
8
+
9
+ import re
10
+ import warnings
11
+ import numpy as np
12
+ from biotite.sequence.annotation import Feature, Location
13
+ from biotite.visualize import colors
14
+
15
+
16
+ def plot_plasmid_map(
17
+ axes,
18
+ annotation,
19
+ plasmid_size,
20
+ tick_length=0.02,
21
+ tick_step=200,
22
+ ring_width=0.01,
23
+ feature_width=0.06,
24
+ spacing=0.01,
25
+ arrow_head_length=0.04,
26
+ label=None,
27
+ face_properties=None,
28
+ label_properties=None,
29
+ omit_oversized_labels=True,
30
+ feature_formatter=None,
31
+ ):
32
+ """
33
+ Plot a plasmid map using the sequence features in the given
34
+ :class:`Annotation`.
35
+
36
+ Each feature location is depicted either by a curved arrow,
37
+ indicating on which strand the feature resides, or an arc.
38
+ The ticks indicate the sequence position.
39
+
40
+ **EXPERIMENTAL**: The API and the resulting plots will probably
41
+ change in future versions.
42
+
43
+ Parameters
44
+ ----------
45
+ axes : PolarAxes
46
+ A *Matplotlib* axes, that is used as plotting area.
47
+ A polar projection is required.
48
+ annotation : Annotation
49
+ The annotation to be visualized.
50
+ plasmid_size : int
51
+ The size of the plasmid, i.e. the length of its sequence.
52
+ tick_length : float, optional
53
+ The length of the axis ticks as percentage of the plot radius.
54
+ tick_step : int, optional
55
+ The interval between the displayed sequence positions.
56
+ For example ``tick_step=200`` means that ticks will be displayed
57
+ at ``1``, ``200``, ``400``, ``600``, etc.
58
+ ring_width : float, optional
59
+ The width of the outer ring as percentage of the plot radius.
60
+ feature_width : float, optional
61
+ The width of each feature arrow/arc as percentage of the
62
+ plot radius.
63
+ spacing : float, optional
64
+ The spacing between the rows of feature arrows/arcs as
65
+ percentage of the plot radius.
66
+ arrow_head_length : float, optional
67
+ The length of the arrow heads as percentage of the radius
68
+ at which the respective arrow is plotted.
69
+ label : str, optional
70
+ The central label of the plot. Ususally the plasmid name.
71
+ face_properties : dict, optional
72
+ A dictionary of properties given to the patches that make up the
73
+ feature arrows/arcs.
74
+ Internally the arrow tail is a *Matplotlib* :class:`Rectangle`,
75
+ and the arrow head is a :class:`Polygon`.
76
+ For example this parameter could be used to add edge lines to
77
+ the arrows/arcs.
78
+ label_properties : dict, optional
79
+ A dictionary of properties given to the feature labels.
80
+ Internally each feature label is one or multiple *Matplotlib*
81
+ :class:`Text` instances.
82
+ For example this parameter could be used to set the font weight
83
+ or size.
84
+ omit_oversized_labels : bool, optional
85
+ If true, a feature label will not be displayed, if the label is
86
+ larger than its containing arc/arrow.
87
+ This ensures, that labels from different features will not
88
+ overlap each other.
89
+ If false, the feature labels will always be displayed.
90
+ feature_formatter : function, optional
91
+ A function that determines *how* each feature is displayed.
92
+ The given function must take a :class:`Feature` and must return
93
+ the following tuple:
94
+
95
+ - *directional* : bool
96
+
97
+ True, if the direction of the feature should be indicated by
98
+ an arrow.
99
+ Otherwise, the feature is plotted is arc.
100
+
101
+ - *face_color* : tuple or str, optional
102
+
103
+ A *Matplotlib* compatible color for the feature arrow/arc.
104
+
105
+ - *label_color* : tuple or str, optional
106
+
107
+ A *Matplotlib* compatible color for the feature label.
108
+
109
+ - *label* : str or None
110
+
111
+ The label to be displayed for this feature.
112
+ None, if no label should be displayed.
113
+ """
114
+ from matplotlib.projections.polar import PolarAxes
115
+
116
+ if not isinstance(axes, PolarAxes):
117
+ raise TypeError("The given axes must be a 'PolarAxes'")
118
+
119
+ ### Setup parameters ###
120
+ if plasmid_size is None:
121
+ # 'stop' of 'get_location_range()' is exclusive -> -1
122
+ plasmid_size = annotation.get_location_range()[1] - 1
123
+ if face_properties is None:
124
+ face_properties = {}
125
+ if label_properties is None:
126
+ label_properties = {}
127
+ if feature_formatter is None:
128
+ feature_formatter = _default_feature_formatter
129
+
130
+ ### Setup matplotlib ###
131
+ # The x-coordinate is given as angle (rad)
132
+ # Full circle -> 2*pi
133
+ axes.set_xlim(0, 2 * np.pi)
134
+ axes.set_ylim(0, 1)
135
+ axes.yaxis.set_visible(False)
136
+ axes.xaxis.set_tick_params(bottom=False, labelbottom=True)
137
+ axes.set_theta_zero_location("N")
138
+ axes.set_theta_direction("clockwise")
139
+ axes.spines["polar"].set_visible(False)
140
+ axes.grid(False)
141
+ # Setup ticks
142
+ ticks = [1]
143
+ tick_labels = [str(1)]
144
+ for tick in range(tick_step, plasmid_size, tick_step):
145
+ ticks.append(tick)
146
+ tick_labels.append(str(tick))
147
+ # Sequence location is replaced by angle
148
+ axes.xaxis.set_ticks([_loc_to_rad(tick, plasmid_size) for tick in ticks])
149
+ axes.xaxis.set_ticklabels(tick_labels)
150
+ ### Draw plasmid ring with ticks and central label ###
151
+
152
+ # Plasmid ring
153
+ # Use 'barh()' instead of a Rectangle patch to ensure that the axes
154
+ # is properly initialized
155
+ # Otherwise the feature rectangles are not curved, but straight
156
+ axes.barh(
157
+ 1 - ring_width - tick_length, 2 * np.pi, ring_width, align="edge", color="black"
158
+ )
159
+
160
+ # Ticks (ticks itself, not the tick labels)
161
+ for tick in ticks:
162
+ angle = _loc_to_rad(tick, plasmid_size)
163
+ axes.plot(
164
+ (angle, angle),
165
+ (1 - tick_length, 1),
166
+ color="black",
167
+ linewidth=1,
168
+ linestyle="-",
169
+ )
170
+
171
+ # Central plasmid label
172
+ if label is not None:
173
+ axes.text(
174
+ 0,
175
+ 0,
176
+ label,
177
+ ha="center",
178
+ va="center",
179
+ color="black",
180
+ size=32,
181
+ fontweight="bold",
182
+ )
183
+
184
+ ### Draw plasmid interior ###
185
+ inner_radius = 1 - ring_width - tick_length
186
+ features = sorted(
187
+ [
188
+ _merge_over_periodic_boundary(feature, plasmid_size)
189
+ for feature in annotation
190
+ ],
191
+ # Features are sorted by the length of their location range
192
+ # The shortest come first
193
+ key=lambda feature: np.diff(feature.get_location_range())[0],
194
+ reverse=True,
195
+ )
196
+ axes.add_artist(
197
+ PlasmidMap(
198
+ axes,
199
+ 0,
200
+ features,
201
+ plasmid_size,
202
+ inner_radius,
203
+ feature_width,
204
+ spacing,
205
+ arrow_head_length,
206
+ label,
207
+ face_properties,
208
+ label_properties,
209
+ omit_oversized_labels,
210
+ feature_formatter,
211
+ )
212
+ )
213
+
214
+
215
+ try:
216
+ # Only create these classes when matplotlib is installed
217
+ from matplotlib.artist import Artist
218
+ from matplotlib.patches import Polygon, Rectangle
219
+ from matplotlib.transforms import Bbox
220
+
221
+ class PlasmidMap(Artist):
222
+ def __init__(
223
+ self,
224
+ axes,
225
+ zorder,
226
+ features,
227
+ plasmid_size,
228
+ radius,
229
+ feature_width,
230
+ spacing,
231
+ arrow_head_length,
232
+ label,
233
+ face_properties,
234
+ label_properties,
235
+ omit_oversized_labels,
236
+ feature_formatter,
237
+ ):
238
+ super().__init__()
239
+ self._axes = axes
240
+ self.zorder = zorder
241
+ self._features = features
242
+ self._plasmid_size = plasmid_size
243
+ self._radius = radius
244
+ self._feature_width = feature_width
245
+ self._spacing = spacing
246
+
247
+ self._all_indicators = []
248
+ for feature in features:
249
+ indicators_for_feature = []
250
+ for loc in feature.locs:
251
+ # Set proper positions in 'draw()' method
252
+ bbox = Bbox.from_extents(0, 0, 0, 0)
253
+ # Draw features as curved arrows (feature indicator)
254
+ indicator = axes.add_artist(
255
+ FeatureIndicator(
256
+ axes,
257
+ self.zorder + 1,
258
+ feature,
259
+ loc,
260
+ bbox,
261
+ arrow_head_length,
262
+ face_properties,
263
+ label_properties,
264
+ omit_oversized_labels,
265
+ feature_formatter,
266
+ )
267
+ )
268
+ indicators_for_feature.append(indicator)
269
+ self._all_indicators.append(indicators_for_feature)
270
+
271
+ def draw(self, renderer, *args, **kwargs):
272
+ # Find the maximum amount of feature rows
273
+ # (used for overlapping features)
274
+ row_count = int(self._radius // (self._feature_width + self._spacing))
275
+ # Tracks the location ranges of feature that were added to
276
+ # a row in order to check if that row is occupied
277
+ ranges_in_row = [[] for i in range(row_count)]
278
+ # Stores the bottom coordinate (radius) for each row
279
+ row_bottoms = [
280
+ self._radius - (row + 1) * (self._feature_width + self._spacing)
281
+ for row in range(row_count)
282
+ ]
283
+
284
+ # Arrange the feature indicators in an way,
285
+ # that there is no overlap between them
286
+ for feature, indicators_for_feature in zip(
287
+ self._features, self._all_indicators
288
+ ):
289
+ row_bottom = None
290
+ first, last = feature.get_location_range()
291
+
292
+ for row_i, curr_range in enumerate(ranges_in_row):
293
+ is_occupied = False
294
+ if curr_range is not None:
295
+ # Check if row is occupied
296
+ for curr_first, curr_last in curr_range:
297
+ # If the location extends over periodic
298
+ # boundary the 'first' location is negative
299
+ if first > 0:
300
+ # 'Normal feature'
301
+ if first <= curr_last and last >= curr_first:
302
+ is_occupied = True
303
+ else: # first < 1
304
+ # Location is over periodic boundary
305
+ if (
306
+ first + self._plasmid_size <= curr_last
307
+ or last >= curr_first
308
+ ):
309
+ is_occupied = True
310
+ if not is_occupied:
311
+ # Row is not occupied by another feature
312
+ # in the location range of the new feature
313
+ # -> Use this row
314
+ if first > 0:
315
+ # 'Normal feature'
316
+ ranges_in_row[row_i].append((first, last))
317
+ else:
318
+ # Location is over periodic boundary
319
+ # Split into 'end' and 'start' part
320
+ ranges_in_row[row_i].append(
321
+ (first + self._plasmid_size, self._plasmid_size)
322
+ )
323
+ ranges_in_row[row_i].append((1, last))
324
+ row_bottom = row_bottoms[row_i]
325
+ break
326
+ if row_bottom is None:
327
+ # No free row -> ignore feature and raise warning
328
+ warnings.warn(
329
+ "Too many feature overlaps, try to increase the "
330
+ "radius or decrease the feature width or spacing"
331
+ )
332
+ else:
333
+ for loc, indicator in zip(feature.locs, indicators_for_feature):
334
+ # Calculate arrow shape parameters
335
+ row_top = row_bottom + self._feature_width
336
+ start_ang = _loc_to_rad(loc.first, self._plasmid_size)
337
+ stop_ang = _loc_to_rad(loc.last, self._plasmid_size)
338
+ bbox = Bbox.from_extents(
339
+ start_ang, row_bottom, stop_ang, row_top
340
+ )
341
+ indicator.set_bbox(bbox)
342
+
343
+ class FeatureIndicator(Artist):
344
+ def __init__(
345
+ self,
346
+ axes,
347
+ zorder,
348
+ feature,
349
+ loc,
350
+ bbox,
351
+ head_length,
352
+ arrow_properties,
353
+ label_properties,
354
+ omit_oversized_labels,
355
+ feature_formatter,
356
+ ):
357
+ super().__init__()
358
+ self._axes = axes
359
+ self.zorder = zorder
360
+ self._direction = loc.strand
361
+ self._bbox = bbox
362
+ self._head_length = head_length
363
+ self._omit_oversized_labels = omit_oversized_labels
364
+
365
+ # Determine how to draw the feature
366
+ directional, face_color, label_color, label = feature_formatter(feature)
367
+
368
+ # Draw arrow as composition of a rectangle and a triangle,
369
+ # as FancyArrow does not properly work for polar plots
370
+
371
+ self._arrow_tail = axes.add_patch(
372
+ Rectangle(
373
+ # Set positions in 'draw()' method
374
+ (0, 0),
375
+ 0,
376
+ 0,
377
+ # Line width is set to 1 to avoid strange artifact in
378
+ # the transition from rectangle (tail) to polygon (head)
379
+ color=face_color,
380
+ linewidth=1,
381
+ zorder=self.zorder + 1,
382
+ **arrow_properties,
383
+ )
384
+ )
385
+
386
+ if directional:
387
+ # Only draw any arrow head when feature has a direction,
388
+ # otherwise simply draw the tail (rectangle)
389
+ self._arrow_head = axes.add_patch(
390
+ Polygon(
391
+ # Set positions in 'draw()' method
392
+ [(0, 0), (0, 0), (0, 0)],
393
+ color=face_color,
394
+ linewidth=1,
395
+ zorder=self.zorder + 1,
396
+ **arrow_properties,
397
+ )
398
+ )
399
+ else:
400
+ self._arrow_head = None
401
+
402
+ if label is not None:
403
+ label_properties["color"] = label_color
404
+ self._label = axes.add_artist(
405
+ CurvedText(
406
+ # Set positions in 'draw()' method
407
+ axes,
408
+ self.zorder + 1,
409
+ 0,
410
+ 0,
411
+ label,
412
+ label_properties,
413
+ )
414
+ )
415
+ else:
416
+ self._label = None
417
+
418
+ def set_bbox(self, bbox):
419
+ self._bbox = bbox
420
+ center_x = (bbox.x0 + bbox.x1) / 2
421
+ center_y = (bbox.y0 + bbox.y1) / 2
422
+ if self._label is not None:
423
+ self._label.set_position(center_x, center_y)
424
+
425
+ def draw(self, renderer, *args, **kwargs):
426
+ bbox = self._bbox
427
+ center_y = (bbox.y0 + bbox.y1) / 2
428
+
429
+ # Constant absolute width for all arrows
430
+ # irrespective of the radius in the polar plot
431
+ # Calculate actual angle from given absolute width
432
+ head_length = self._head_length / center_y
433
+
434
+ # Check if the head should be drawn
435
+ if self._arrow_head is None:
436
+ head_length = 0
437
+ # Check if the feature location is too small for
438
+ elif head_length > bbox.width:
439
+ # Limit size of arrow head to range of location
440
+ head_length = bbox.width
441
+
442
+ if self._direction == Location.Strand.FORWARD:
443
+ rect_pos = (bbox.x0, bbox.y0)
444
+ # (x0, y0), (x1, y1), (x2, y2)
445
+ triangle_coord = [
446
+ (bbox.x1 - head_length, bbox.y0), # base 1
447
+ (bbox.x1 - head_length, bbox.y1), # base 2
448
+ (bbox.x1, center_y), # tip
449
+ ]
450
+ else:
451
+ rect_pos = (bbox.x0 + head_length, bbox.y0)
452
+ triangle_coord = [
453
+ (bbox.x0 + head_length, bbox.y0), # base 1
454
+ (bbox.x0 + head_length, bbox.y1), # base 2
455
+ (bbox.x0, center_y), # tip
456
+ ]
457
+
458
+ # Update coordinates of sub-artists
459
+ self._arrow_tail.set_xy(rect_pos)
460
+ self._arrow_tail.set_width(bbox.width - head_length)
461
+ self._arrow_tail.set_height(bbox.height)
462
+ if self._arrow_head is not None:
463
+ self._arrow_head.set_xy(triangle_coord)
464
+
465
+ if self._label is not None:
466
+ # Do not draw the labels if it is larger than the
467
+ # indicator
468
+ if (
469
+ self._omit_oversized_labels
470
+ and self._label.get_total_angle(renderer) > bbox.width
471
+ ):
472
+ self._label.set_visible(False)
473
+ else:
474
+ self._label.set_visible(True)
475
+
476
+ class CurvedText(Artist):
477
+ def __init__(self, axes, zorder, angle, radius, string, text_properties):
478
+ super().__init__()
479
+ self._axes = axes
480
+ self.zorder = zorder
481
+ self._angle = angle
482
+ self._radius = radius
483
+
484
+ self._texts = []
485
+ for word in _split_into_words(string):
486
+ text = axes.text(
487
+ # Set position in 'draw()' method
488
+ 0,
489
+ 0,
490
+ word,
491
+ ha="center",
492
+ va="center",
493
+ zorder=self.zorder + 1,
494
+ **text_properties,
495
+ )
496
+ self._texts.append(text)
497
+
498
+ def set_visible(self, visible):
499
+ super().set_visible(visible)
500
+ for text in self._texts:
501
+ text.set_visible(visible)
502
+
503
+ def set_position(self, angle, radius):
504
+ self._angle = angle
505
+ self._radius = radius
506
+
507
+ def get_total_angle(self, renderer):
508
+ return np.sum(self.get_word_angles(renderer))
509
+
510
+ def get_word_angles(self, renderer):
511
+ ax_px_radius = self._axes.get_window_extent(renderer).width / 2
512
+ ax_unit_radius = self._axes.get_ylim()[1]
513
+ circle_px_circumference = (
514
+ ax_px_radius * 2 * np.pi * (self._radius / ax_unit_radius)
515
+ )
516
+
517
+ angles = []
518
+ for text in self._texts:
519
+ orig_rot = text.get_rotation()
520
+ orig_visible = text.get_visible()
521
+ # Reset rotation and visibility
522
+ # for correct window extent calculation
523
+ text.set_rotation(0)
524
+ text.set_visible(True)
525
+ word_px_width = text.get_window_extent(renderer).width
526
+ # In some Matplotlib versions the window extent of
527
+ # whitespace characters is 'nan'
528
+ # In this case, assign a fixed width
529
+ if np.isnan(word_px_width):
530
+ word_px_width = 5.0
531
+ word_angle = 2 * np.pi * word_px_width / circle_px_circumference
532
+ angles.append(word_angle)
533
+ # Restore
534
+ text.set_rotation(orig_rot)
535
+ text.set_visible(orig_visible)
536
+ return angles
537
+
538
+ def draw(self, renderer, *args, **kwargs):
539
+ angles = self.get_word_angles(renderer)
540
+ total_angle = np.sum(angles)
541
+
542
+ rad_angle = 360 - np.rad2deg(self._angle)
543
+ # Avoid to draw the text upside down, when drawn on the
544
+ # bottom half of the map
545
+ if rad_angle > 90 and rad_angle < 270:
546
+ turn_around = True
547
+ else:
548
+ turn_around = False
549
+
550
+ # Now that the angle for each word is known,
551
+ # the appropriate position and rotation can be set
552
+ if turn_around:
553
+ # curr_angle is the left-aligned position of the
554
+ # upcoming word
555
+ curr_angle = self._angle + total_angle / 2
556
+ else:
557
+ curr_angle = self._angle - total_angle / 2
558
+ for text, angle in zip(self._texts, angles):
559
+ if turn_around:
560
+ # The text itself is centered
561
+ # -> The position itself must be corrected with
562
+ # half of the word angle
563
+ angle_corrected = curr_angle - angle / 2
564
+ text_rot = 360 - np.rad2deg(angle_corrected) + 180
565
+ curr_angle -= angle
566
+ else:
567
+ angle_corrected = curr_angle + angle / 2
568
+ text_rot = 360 - np.rad2deg(angle_corrected)
569
+ curr_angle += angle
570
+ text.set_position((angle_corrected, self._radius))
571
+ text.set_rotation(text_rot)
572
+
573
+
574
+ except ImportError:
575
+ pass
576
+
577
+
578
+ def _loc_to_rad(loc, plasmid_size):
579
+ if loc > plasmid_size:
580
+ raise ValueError(
581
+ f"Location {loc} is larger then the plasmid size of {plasmid_size}"
582
+ )
583
+ # Location starts at 1 -> (loc-1)
584
+ return ((loc - 1) / plasmid_size) * 2 * np.pi
585
+
586
+
587
+ def _rad_to_loc(rad, plasmid_size):
588
+ # Location starts at 1 -> + 1
589
+ return rad / (2 * np.pi) * plasmid_size + 1
590
+
591
+
592
+ def _merge_over_periodic_boundary(feature, plasmid_size):
593
+ if len(feature.locs) == 1:
594
+ # Only one location -> no merge possible
595
+ return feature
596
+ first_loc = None
597
+ last_loc = None
598
+ # Find total first location of the feature
599
+ for loc in feature.locs:
600
+ if first_loc is None or loc.first < first_loc.first:
601
+ first_loc = loc
602
+ # Find total last location of the feature
603
+ for loc in feature.locs:
604
+ if last_loc is None or loc.last > last_loc.last:
605
+ last_loc = loc
606
+ # If the first and last location meet at the periodic boundary of
607
+ # the plasmid -> merge them
608
+ if (
609
+ first_loc.first == 1
610
+ and last_loc.last == plasmid_size
611
+ and first_loc.strand == last_loc.strand
612
+ ):
613
+ new_locs = set(feature.locs)
614
+ new_locs.remove(first_loc)
615
+ new_locs.remove(last_loc)
616
+ new_locs.add(
617
+ Location(
618
+ # the fist base is now at negative location
619
+ # by shifting by one plasmid 'period'
620
+ first=last_loc.first - plasmid_size,
621
+ last=first_loc.last,
622
+ strand=first_loc.strand,
623
+ defect=first_loc.defect | last_loc.defect,
624
+ )
625
+ )
626
+ return Feature(feature.key, new_locs, feature.qual)
627
+ else:
628
+ return feature
629
+
630
+
631
+ # ' ', '-' and '_' are word delimiters
632
+ separators = re.compile(r"\s|_|-")
633
+
634
+
635
+ def _split_into_words(string):
636
+ match_indices = sorted([match.start() for match in separators.finditer(string)])
637
+ current_index = 0
638
+ words = []
639
+ for i in match_indices:
640
+ # Add word up to delimiter
641
+ words.append(string[current_index:i])
642
+ # Add delimiter
643
+ words.append(string[i : i + 1])
644
+ current_index = i + 1
645
+ # If there is a word after the last delimiter, add it too
646
+ if current_index < len(string):
647
+ words.append(string[current_index:])
648
+ return words
649
+
650
+
651
+ def _default_feature_formatter(f):
652
+ """
653
+ Returns
654
+ -------
655
+ directional : bool
656
+ True, if the direction of the feature should be indicated by
657
+ an arrow.
658
+ face_color: tuple or str, optional
659
+ A matplotlib compatible color for the feature indicator.
660
+ label_color: tuple or str, optional
661
+ A matplotlib compatible color for the feature label.
662
+ label: str or None
663
+ The label to be displayed for this feature.
664
+ None, if no label should be displayed.
665
+ """
666
+ # Source
667
+ if f.key == "source":
668
+ if f.qual.get("organism") is not None:
669
+ label = f"Source: {f.qual.get('organism')}"
670
+ else:
671
+ label = None
672
+ return False, "black", "white", label
673
+
674
+ # Origin of Replication
675
+ elif f.key == "rep_origin":
676
+ return False, "indigo", "white", f.qual.get("standard_name", "ori")
677
+
678
+ # Coding sequences
679
+ elif f.key in ["gene", "CDS", "rRNA"]:
680
+ label = f.qual.get("product")
681
+ if label is None:
682
+ label = f.qual.get("gene")
683
+ return True, colors["orange"], "black", label
684
+
685
+ elif f.key == "regulatory":
686
+ # Promoters
687
+ if f.qual.get("regulatory_class") in [
688
+ "promoter",
689
+ "TATA_box",
690
+ "minus_35_signal",
691
+ "minus_10_signal",
692
+ ]:
693
+ return True, colors["dimgreen"], "black", f.qual.get("note")
694
+
695
+ # Terminators
696
+ elif f.qual.get("regulatory_class") in "terminator":
697
+ return False, "firebrick", "white", f.qual.get("note")
698
+
699
+ # RBS
700
+ elif f.qual.get("regulatory_class") == "ribosome_binding_site":
701
+ return False, colors["brightorange"], "white", None
702
+
703
+ # Primers
704
+ elif f.key == "primer_bind":
705
+ return True, "royalblue", "black", f.qual.get("note")
706
+
707
+ # Binding proteins
708
+ elif f.key == "protein_bind":
709
+ return False, colors["lightgreen"], "black", f.qual.get("note")
710
+
711
+ # Misc
712
+ return True, "dimgray", "white", f.qual.get("note")