biotite 1.0.1__cp311-cp311-win_amd64.whl → 1.2.0__cp311-cp311-win_amd64.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 (177) hide show
  1. biotite/application/application.py +3 -3
  2. biotite/application/autodock/app.py +1 -1
  3. biotite/application/blast/webapp.py +1 -1
  4. biotite/application/clustalo/app.py +1 -1
  5. biotite/application/dssp/app.py +13 -3
  6. biotite/application/localapp.py +36 -2
  7. biotite/application/msaapp.py +10 -10
  8. biotite/application/muscle/app3.py +5 -18
  9. biotite/application/muscle/app5.py +5 -5
  10. biotite/application/sra/app.py +0 -5
  11. biotite/application/util.py +22 -2
  12. biotite/application/viennarna/rnaalifold.py +8 -8
  13. biotite/application/viennarna/rnaplot.py +9 -3
  14. biotite/application/viennarna/util.py +1 -1
  15. biotite/application/webapp.py +1 -1
  16. biotite/database/afdb/__init__.py +12 -0
  17. biotite/database/afdb/download.py +191 -0
  18. biotite/database/entrez/dbnames.py +10 -0
  19. biotite/database/entrez/download.py +9 -10
  20. biotite/database/entrez/key.py +1 -1
  21. biotite/database/entrez/query.py +5 -4
  22. biotite/database/pubchem/download.py +6 -6
  23. biotite/database/pubchem/error.py +10 -0
  24. biotite/database/pubchem/query.py +12 -23
  25. biotite/database/rcsb/download.py +3 -2
  26. biotite/database/rcsb/query.py +8 -9
  27. biotite/database/uniprot/check.py +22 -17
  28. biotite/database/uniprot/download.py +3 -6
  29. biotite/database/uniprot/query.py +4 -5
  30. biotite/file.py +14 -2
  31. biotite/interface/__init__.py +19 -0
  32. biotite/interface/openmm/__init__.py +16 -0
  33. biotite/interface/openmm/state.py +93 -0
  34. biotite/interface/openmm/system.py +227 -0
  35. biotite/interface/pymol/__init__.py +198 -0
  36. biotite/interface/pymol/cgo.py +346 -0
  37. biotite/interface/pymol/convert.py +185 -0
  38. biotite/interface/pymol/display.py +267 -0
  39. biotite/interface/pymol/object.py +1226 -0
  40. biotite/interface/pymol/shapes.py +178 -0
  41. biotite/interface/pymol/startup.py +169 -0
  42. biotite/interface/rdkit/__init__.py +15 -0
  43. biotite/interface/rdkit/mol.py +490 -0
  44. biotite/interface/version.py +71 -0
  45. biotite/interface/warning.py +19 -0
  46. biotite/sequence/align/__init__.py +0 -4
  47. biotite/sequence/align/alignment.py +49 -14
  48. biotite/sequence/align/banded.cp311-win_amd64.pyd +0 -0
  49. biotite/sequence/align/banded.pyx +26 -26
  50. biotite/sequence/align/cigar.py +2 -2
  51. biotite/sequence/align/kmeralphabet.cp311-win_amd64.pyd +0 -0
  52. biotite/sequence/align/kmeralphabet.pyx +19 -2
  53. biotite/sequence/align/kmersimilarity.cp311-win_amd64.pyd +0 -0
  54. biotite/sequence/align/kmertable.cp311-win_amd64.pyd +0 -0
  55. biotite/sequence/align/kmertable.pyx +58 -48
  56. biotite/sequence/align/localgapped.cp311-win_amd64.pyd +0 -0
  57. biotite/sequence/align/localgapped.pyx +47 -47
  58. biotite/sequence/align/localungapped.cp311-win_amd64.pyd +0 -0
  59. biotite/sequence/align/localungapped.pyx +10 -10
  60. biotite/sequence/align/matrix.py +284 -57
  61. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  62. biotite/sequence/align/matrix_data/PB.license +21 -0
  63. biotite/sequence/align/matrix_data/PB.mat +18 -0
  64. biotite/sequence/align/multiple.cp311-win_amd64.pyd +0 -0
  65. biotite/sequence/align/pairwise.cp311-win_amd64.pyd +0 -0
  66. biotite/sequence/align/pairwise.pyx +35 -35
  67. biotite/sequence/align/permutation.cp311-win_amd64.pyd +0 -0
  68. biotite/sequence/align/selector.cp311-win_amd64.pyd +0 -0
  69. biotite/sequence/align/selector.pyx +2 -2
  70. biotite/sequence/align/statistics.py +1 -1
  71. biotite/sequence/align/tracetable.cp311-win_amd64.pyd +0 -0
  72. biotite/sequence/alphabet.py +5 -2
  73. biotite/sequence/annotation.py +19 -13
  74. biotite/sequence/codec.cp311-win_amd64.pyd +0 -0
  75. biotite/sequence/codon.py +1 -2
  76. biotite/sequence/graphics/alignment.py +25 -39
  77. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  78. biotite/sequence/graphics/color_schemes/pb_flower.json +2 -1
  79. biotite/sequence/graphics/colorschemes.py +44 -11
  80. biotite/sequence/graphics/dendrogram.py +4 -2
  81. biotite/sequence/graphics/features.py +2 -2
  82. biotite/sequence/graphics/logo.py +10 -12
  83. biotite/sequence/io/fasta/convert.py +1 -2
  84. biotite/sequence/io/fasta/file.py +1 -1
  85. biotite/sequence/io/fastq/file.py +3 -3
  86. biotite/sequence/io/genbank/file.py +3 -3
  87. biotite/sequence/io/genbank/sequence.py +2 -0
  88. biotite/sequence/io/gff/convert.py +1 -1
  89. biotite/sequence/io/gff/file.py +1 -2
  90. biotite/sequence/phylo/nj.cp311-win_amd64.pyd +0 -0
  91. biotite/sequence/phylo/tree.cp311-win_amd64.pyd +0 -0
  92. biotite/sequence/phylo/upgma.cp311-win_amd64.pyd +0 -0
  93. biotite/sequence/profile.py +105 -29
  94. biotite/sequence/search.py +0 -1
  95. biotite/sequence/seqtypes.py +136 -8
  96. biotite/sequence/sequence.py +1 -2
  97. biotite/setup_ccd.py +197 -0
  98. biotite/structure/__init__.py +6 -3
  99. biotite/structure/alphabet/__init__.py +25 -0
  100. biotite/structure/alphabet/encoder.py +332 -0
  101. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  102. biotite/structure/alphabet/i3d.py +109 -0
  103. biotite/structure/alphabet/layers.py +86 -0
  104. biotite/structure/alphabet/pb.license +21 -0
  105. biotite/structure/alphabet/pb.py +170 -0
  106. biotite/structure/alphabet/unkerasify.py +128 -0
  107. biotite/structure/atoms.py +163 -66
  108. biotite/structure/basepairs.py +26 -26
  109. biotite/structure/bonds.cp311-win_amd64.pyd +0 -0
  110. biotite/structure/bonds.pyx +79 -25
  111. biotite/structure/box.py +19 -21
  112. biotite/structure/celllist.cp311-win_amd64.pyd +0 -0
  113. biotite/structure/celllist.pyx +83 -67
  114. biotite/structure/chains.py +5 -37
  115. biotite/structure/charges.cp311-win_amd64.pyd +0 -0
  116. biotite/structure/compare.py +420 -13
  117. biotite/structure/density.py +1 -1
  118. biotite/structure/dotbracket.py +27 -28
  119. biotite/structure/filter.py +8 -8
  120. biotite/structure/geometry.py +74 -127
  121. biotite/structure/hbond.py +17 -19
  122. biotite/structure/info/__init__.py +1 -0
  123. biotite/structure/info/atoms.py +24 -15
  124. biotite/structure/info/bonds.py +12 -6
  125. biotite/structure/info/ccd.py +125 -34
  126. biotite/structure/info/{ccd/components.bcif → components.bcif} +0 -0
  127. biotite/structure/info/groups.py +62 -19
  128. biotite/structure/info/masses.py +9 -6
  129. biotite/structure/info/misc.py +15 -22
  130. biotite/structure/info/radii.py +92 -22
  131. biotite/structure/info/standardize.py +4 -4
  132. biotite/structure/integrity.py +4 -6
  133. biotite/structure/io/general.py +2 -2
  134. biotite/structure/io/gro/file.py +8 -9
  135. biotite/structure/io/mol/convert.py +1 -1
  136. biotite/structure/io/mol/ctab.py +33 -28
  137. biotite/structure/io/mol/mol.py +1 -1
  138. biotite/structure/io/mol/sdf.py +80 -53
  139. biotite/structure/io/pdb/convert.py +4 -3
  140. biotite/structure/io/pdb/file.py +85 -25
  141. biotite/structure/io/pdb/hybrid36.cp311-win_amd64.pyd +0 -0
  142. biotite/structure/io/pdbqt/file.py +36 -36
  143. biotite/structure/io/pdbx/__init__.py +1 -0
  144. biotite/structure/io/pdbx/bcif.py +54 -15
  145. biotite/structure/io/pdbx/cif.py +92 -66
  146. biotite/structure/io/pdbx/component.py +15 -4
  147. biotite/structure/io/pdbx/compress.py +321 -0
  148. biotite/structure/io/pdbx/convert.py +410 -75
  149. biotite/structure/io/pdbx/encoding.cp311-win_amd64.pyd +0 -0
  150. biotite/structure/io/pdbx/encoding.pyx +98 -17
  151. biotite/structure/io/trajfile.py +9 -6
  152. biotite/structure/io/util.py +38 -0
  153. biotite/structure/mechanics.py +0 -1
  154. biotite/structure/molecules.py +141 -156
  155. biotite/structure/pseudoknots.py +7 -13
  156. biotite/structure/repair.py +2 -4
  157. biotite/structure/residues.py +13 -24
  158. biotite/structure/rings.py +335 -0
  159. biotite/structure/sasa.cp311-win_amd64.pyd +0 -0
  160. biotite/structure/sasa.pyx +2 -1
  161. biotite/structure/segments.py +69 -11
  162. biotite/structure/sequence.py +0 -1
  163. biotite/structure/sse.py +0 -2
  164. biotite/structure/superimpose.py +74 -62
  165. biotite/structure/tm.py +581 -0
  166. biotite/structure/transform.py +12 -25
  167. biotite/structure/util.py +76 -4
  168. biotite/version.py +9 -4
  169. biotite/visualize.py +111 -1
  170. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/METADATA +6 -2
  171. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/RECORD +173 -143
  172. biotite/structure/info/ccd/README.rst +0 -8
  173. biotite/structure/info/ccd/amino_acids.txt +0 -1663
  174. biotite/structure/info/ccd/carbohydrates.txt +0 -1135
  175. biotite/structure/info/ccd/nucleotides.txt +0 -798
  176. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/WHEEL +0 -0
  177. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/licenses/LICENSE.rst +0 -0
biotite/file.py CHANGED
@@ -44,7 +44,7 @@ class File(Copyable, metaclass=abc.ABCMeta):
44
44
 
45
45
  Returns
46
46
  -------
47
- file_object : File
47
+ file : File
48
48
  An instance from the respective :class:`File` subclass
49
49
  representing the parsed file.
50
50
  """
@@ -57,7 +57,7 @@ class File(Copyable, metaclass=abc.ABCMeta):
57
57
 
58
58
  Parameters
59
59
  ----------
60
- file_name : file-like object or str
60
+ file : file-like object or str
61
61
  The file to be written to.
62
62
  Alternatively a file path can be supplied.
63
63
  """
@@ -207,6 +207,18 @@ def wrap_string(text, width):
207
207
 
208
208
  This function simply wraps the given `text` after `width`
209
209
  characters, ignoring sentences, whitespaces, etc.
210
+
211
+ Parameters
212
+ ----------
213
+ text : str
214
+ The text to be wrapped.
215
+ width : int
216
+ The maximum number of characters per line.
217
+
218
+ Returns
219
+ -------
220
+ lines : list of str
221
+ The wrapped lines.
210
222
  """
211
223
  lines = []
212
224
  for i in range(0, len(text), width):
@@ -0,0 +1,19 @@
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
+ """
6
+ This subpackage provides interfaces to other Python packages in the bioinformatics
7
+ ecosystem.
8
+ Its purpose is to convert between native Biotite objects, such as :class:`.AtomArray`
9
+ and :class:`.Sequence`, and the corresponding objects in the respective interfaced
10
+ package.
11
+ In contrast to :mod:`biotite.application`, where an entire application run is handled
12
+ under the hood, :mod:`biotite.interface` only covers the object conversion, allowing
13
+ for more flexibility.
14
+ """
15
+
16
+ __name__ = "biotite.interface"
17
+ __author__ = "Patrick Kunzmann"
18
+
19
+ from .warning import *
@@ -0,0 +1,16 @@
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
+ """
6
+ This subpackage provides an interface to the `OpenMM <https://openmm.org/>`_
7
+ molecular simulation toolkit.
8
+ It allows conversion between :class:`.AtomArray`/:class:`.AtomArrayStack` and
9
+ structure-related objects from *OpenMM*.
10
+ """
11
+
12
+ __name__ = "biotite.interface.openmm"
13
+ __author__ = "Patrick Kunzmann"
14
+
15
+ from .state import *
16
+ from .system import *
@@ -0,0 +1,93 @@
1
+ __name__ = "biotite.interface.openmm"
2
+ __author__ = "Patrick Kunzmann"
3
+ __all__ = ["from_context", "from_state", "from_states"]
4
+
5
+ import numpy as np
6
+ import openmm
7
+ import biotite.structure as struc
8
+
9
+
10
+ def from_context(template, context):
11
+ """
12
+ Parse the coordinates and box of the current state of an
13
+ :class:`openmm.openmm.Context` into an :class:`AtomArray`.
14
+
15
+ Parameters
16
+ ----------
17
+ template : AtomArray
18
+ This structure is used as template.
19
+ The output :class:`AtomArray` is equal to this template with the
20
+ exception of the coordinates and the box vectors.
21
+ context : Context
22
+ The coordinates are parsed from the current state of this
23
+ :class:`openmm.openmm.Context`.
24
+
25
+ Returns
26
+ -------
27
+ atoms : AtomArray
28
+ The created :class:`AtomArray`.
29
+ """
30
+ state = context.getState(getPositions=True)
31
+ return from_state(template, state)
32
+
33
+
34
+ def from_state(template, state):
35
+ """
36
+ Parse the coordinates and box of the given :class:`openmm.openmm.State`
37
+ into an :class:`AtomArray`.
38
+
39
+ Parameters
40
+ ----------
41
+ template : AtomArray
42
+ This structure is used as template.
43
+ The output :class:`AtomArray` is equal to this template with the
44
+ exception of the coordinates and the box vectors.
45
+ state : State
46
+ The coordinates are parsed from this state.
47
+ Must be created with ``getPositions=True``.
48
+
49
+ Returns
50
+ -------
51
+ atoms : AtomArray
52
+ The created :class:`AtomArray`.
53
+ """
54
+ coord, box = _parse_state(state)
55
+ atoms = template.copy()
56
+ atoms.coord = coord
57
+ atoms.box = box
58
+ return atoms
59
+
60
+
61
+ def from_states(template, states):
62
+ """
63
+ Parse the coordinates and box vectors of multiple :class:`openmm.openmm.State`
64
+ objects into an :class:`AtomArrayStack`.
65
+
66
+ Parameters
67
+ ----------
68
+ template : AtomArray
69
+ This structure is used as template.
70
+ The output :class:`AtomArray` is equal to this template with the
71
+ exception of the coordinates and the box vectors.
72
+ states : iterable of State
73
+ The coordinates are parsed from these states.
74
+ Must be created with ``getPositions=True``.
75
+
76
+ Returns
77
+ -------
78
+ atoms : AtomArrayStack
79
+ The created :class:`AtomArrayStack`.
80
+ """
81
+ coords = []
82
+ boxes = []
83
+ for state in states:
84
+ coord, box = _parse_state(state)
85
+ coords.append(coord)
86
+ boxes.append(box)
87
+ return struc.from_template(template, np.stack(coords), np.stack(boxes))
88
+
89
+
90
+ def _parse_state(state):
91
+ coord = state.getPositions(asNumpy=True).value_in_unit(openmm.unit.angstrom)
92
+ box = state.getPeriodicBoxVectors(asNumpy=True).value_in_unit(openmm.unit.angstrom)
93
+ return coord, box
@@ -0,0 +1,227 @@
1
+ __name__ = "biotite.interface.openmm"
2
+ __author__ = "Patrick Kunzmann"
3
+ __all__ = ["to_system", "to_topology", "from_topology"]
4
+
5
+ import numpy as np
6
+ import openmm
7
+ import openmm.app as app
8
+ import openmm.unit as unit
9
+ import biotite.structure as struc
10
+ import biotite.structure.info as info
11
+
12
+ _BOND_TYPE_TO_ORDER = {
13
+ struc.BondType.SINGLE: 1,
14
+ struc.BondType.DOUBLE: 2,
15
+ struc.BondType.TRIPLE: 3,
16
+ struc.BondType.QUADRUPLE: 4,
17
+ struc.BondType.AROMATIC_SINGLE: 1,
18
+ struc.BondType.AROMATIC_DOUBLE: 2,
19
+ struc.BondType.AROMATIC_TRIPLE: 3,
20
+ }
21
+
22
+
23
+ def to_system(atoms):
24
+ """
25
+ Create a :class:`openmm.openmm.System` from an :class:`AtomArray` or
26
+ :class:`AtomArrayStack`.
27
+
28
+ Parameters
29
+ ----------
30
+ atoms : AtomArray or AtomArrayStack
31
+ The structure to be converted.
32
+ The box vectors are set from the ``box`` attribute.
33
+ If multiple models are given the box of the first model is selected.
34
+
35
+ Returns
36
+ -------
37
+ system : System
38
+ The created :class:`openmm.openmm.System`.
39
+ """
40
+ system = openmm.System()
41
+
42
+ for element in atoms.element:
43
+ system.addParticle(info.mass(element))
44
+
45
+ if atoms.box is not None:
46
+ if atoms.box.ndim == 3:
47
+ # If an `AtomArrayStack`, the first box is chosen
48
+ box = atoms.box[0]
49
+ else:
50
+ box = atoms.box
51
+ if not _check_box_requirements(box):
52
+ raise struc.BadStructureError(
53
+ "Box does not fulfill OpenMM's requirements for periodic boxes"
54
+ )
55
+ system.setDefaultPeriodicBoxVectors(*(box * unit.angstrom))
56
+
57
+ return system
58
+
59
+
60
+ def to_topology(atoms):
61
+ """
62
+ Create a :class:`openmm.app.topology.Topology` from an :class:`AtomArray` or
63
+ :class:`AtomArrayStack`.
64
+
65
+ Parameters
66
+ ----------
67
+ atoms : AtomArray or AtomArrayStack
68
+ The structure to be converted.
69
+ An associated :class:`BondList` is required.
70
+
71
+ Returns
72
+ -------
73
+ topology : Topology
74
+ The created :class:`openmm.app.topology.Topology`.
75
+ """
76
+ if "atom_id" in atoms.get_annotation_categories():
77
+ atom_id = atoms.atom_id
78
+ else:
79
+ atom_id = np.arange(atoms.array_length()) + 1
80
+
81
+ chain_starts = struc.get_chain_starts(atoms)
82
+ res_starts = struc.get_residue_starts(atoms)
83
+
84
+ # Lists of chain, residue and atom objects that will be filled later
85
+ chain_list = []
86
+ residue_list = []
87
+ atom_list = []
88
+ # Each atom's index in the chain and residue list
89
+ chain_idx = _generate_idx(chain_starts, atoms.array_length())
90
+ res_idx = _generate_idx(res_starts, atoms.array_length())
91
+
92
+ topology = app.Topology()
93
+
94
+ ## Add atoms
95
+ for start_i in chain_starts:
96
+ chain_list.append(topology.addChain(id=atoms.chain_id[start_i]))
97
+ for start_i in res_starts:
98
+ residue_list.append(
99
+ topology.addResidue(
100
+ name=atoms.res_name[start_i],
101
+ chain=chain_list[chain_idx[start_i]],
102
+ insertionCode=atoms.ins_code[start_i],
103
+ id=str(atoms.res_id[start_i]),
104
+ )
105
+ )
106
+ for i in np.arange(atoms.array_length()):
107
+ atom_list.append(
108
+ topology.addAtom(
109
+ name=atoms.atom_name[i],
110
+ element=app.Element.getBySymbol(atoms.element[i]),
111
+ residue=residue_list[res_idx[i]],
112
+ id=str(atom_id[start_i]),
113
+ )
114
+ )
115
+
116
+ ## Add bonds
117
+ if atoms.bonds is None:
118
+ raise struc.BadStructureError("Input structure misses an associated BondList")
119
+ for atom_i, atom_j, bond_type in atoms.bonds.as_array():
120
+ topology.addBond(
121
+ atom_list[atom_i],
122
+ atom_list[atom_j],
123
+ order=_BOND_TYPE_TO_ORDER.get(bond_type),
124
+ )
125
+
126
+ ## Add box
127
+ if atoms.box is not None:
128
+ if atoms.box.ndim == 3:
129
+ # If an `AtomArrayStack`, the first box is chosen
130
+ box = atoms.box[0]
131
+ else:
132
+ box = atoms.box
133
+ if not _check_box_requirements(box):
134
+ raise struc.BadStructureError(
135
+ "Box does not fulfill OpenMM's requirements for periodic boxes"
136
+ )
137
+ topology.setPeriodicBoxVectors(box * unit.angstrom)
138
+
139
+ return topology
140
+
141
+
142
+ def from_topology(topology):
143
+ """
144
+ Create a :class:`AtomArray` from a :class:`openmm.app.topology.Topology`.
145
+
146
+ Parameters
147
+ ----------
148
+ topology : Topology
149
+ The topology to be converted.
150
+
151
+ Returns
152
+ -------
153
+ atoms : AtomArray
154
+ The created :class:`AtomArray`.
155
+ As the :class:`openmm.app.topology.Topology` does not contain atom
156
+ coordinates, the values of the :class:`AtomArray` ``coord``
157
+ are set to *NaN*.
158
+
159
+ Notes
160
+ -----
161
+ This function is especially useful for obtaining an updated
162
+ template, if the original topology was modified
163
+ (e.g. via :class:`openmm.app.modeller.Modeller`).
164
+ """
165
+ atoms = struc.AtomArray(topology.getNumAtoms())
166
+
167
+ chain_ids = []
168
+ res_ids = []
169
+ ins_codes = []
170
+ res_names = []
171
+ atom_names = []
172
+ elements = []
173
+ for chain in topology.chains():
174
+ chain_id = chain.id
175
+ for residue in chain.residues():
176
+ res_name = residue.name
177
+ res_id = int(residue.id)
178
+ ins_code = residue.insertionCode
179
+ for atom in residue.atoms():
180
+ chain_ids.append(chain_id)
181
+ res_ids.append(res_id)
182
+ ins_codes.append(ins_code)
183
+ res_names.append(res_name)
184
+ atom_names.append(atom.name.upper())
185
+ elements.append(atom.element.symbol.upper())
186
+ atoms.chain_id = chain_ids
187
+ atoms.res_id = res_ids
188
+ atoms.ins_code = ins_codes
189
+ atoms.res_name = res_names
190
+ atoms.atom_name = atom_names
191
+ atoms.element = elements
192
+ atoms.hetero = ~(struc.filter_amino_acids(atoms) | struc.filter_nucleotides(atoms))
193
+
194
+ bonds = []
195
+ atom_to_index = {atom: i for i, atom in enumerate(topology.atoms())}
196
+ for bond in topology.bonds():
197
+ order = bond.order if bond.order is not None else struc.BondType.ANY
198
+ bonds.append([atom_to_index[bond.atom1], atom_to_index[bond.atom2], order])
199
+ atoms.bonds = struc.BondList(atoms.array_length(), np.array(bonds))
200
+
201
+ box = topology.getPeriodicBoxVectors()
202
+ if box is None:
203
+ atoms.box = None
204
+ else:
205
+ atoms.box = np.asarray(box.value_in_unit(openmm.unit.angstrom))
206
+
207
+ return atoms
208
+
209
+
210
+ def _generate_idx(starts, length):
211
+ # An array that is 1, at start positions and 0 everywhere else
212
+ start_counter = np.zeros(length, dtype=int)
213
+ start_counter[starts] = 1
214
+ # The first index should be zero -> the first start is not counted
215
+ start_counter[0] = 0
216
+ return np.cumsum(start_counter)
217
+
218
+
219
+ def _check_box_requirements(box):
220
+ """
221
+ Return True, if the given box fulfills *OpenMM*'s requirements for
222
+ boxes, else otherwise.
223
+
224
+ The first vector must be on the x-axis
225
+ and the second vector must be on the xy-plane.
226
+ """
227
+ return np.all(np.triu(box, k=1) == 0)
@@ -0,0 +1,198 @@
1
+ # ruff: noqa: F401
2
+
3
+ # This source code is part of the Biotite package and is distributed
4
+ # under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
5
+ # information.
6
+
7
+ """
8
+ This package enables the transfer of structures from *Biotite* to
9
+ `PyMOL <https://pymol.org/>`_ for visualization and vice versa,
10
+ via *PyMOL*'s Python API:
11
+
12
+ - Import :class:`AtomArray` and :class:`AtomArrayStack` objects into *PyMOL* -
13
+ without intermediate structure files.
14
+ - Convert *PyMOL* objects into :class:`AtomArray` and :class:`AtomArrayStack`
15
+ instances.
16
+ - Use *Biotite*'s boolean masks for atom selection in *PyMOL*.
17
+ - Display images rendered with *PyMOL* in *Jupyter* notebooks.
18
+
19
+ Launching PyMOL
20
+ ---------------
21
+
22
+ Library mode
23
+ ^^^^^^^^^^^^
24
+ The recommended way to invoke *PyMOL* in a Python script depends on whether a GUI should
25
+ be displayed.
26
+ If no GUI is required, we recommend launching a *PyMOL* session in library mode.
27
+
28
+ .. code-block:: python
29
+
30
+ import biotite.interface.pymol as pymol_interface
31
+
32
+ pymol_interface.launch_pymol()
33
+
34
+ Usually launching *PyMOL* manually via :func:`launch_pymol()` is not even necessary:
35
+ When *Biotite* requires a *PyMOL* session, e.g. for creating a *PyMOL* object or
36
+ invoking a command, and none is already running, *PyMOL* is automatically started in
37
+ library mode.
38
+
39
+ GUI mode
40
+ ^^^^^^^^
41
+ When the *PyMOL* GUI is necessary, the *PyMOL* library mode is not available.
42
+ Instead *PyMOL* can be launched in interactive (GUI) mode:
43
+
44
+ .. code-block:: python
45
+
46
+ import biotite.interface.pymol as pymol_interface
47
+
48
+ pymol_interface.launch_interactive_pymol("-qixkF", "-W", "400", "-H", "400")
49
+
50
+ :func:`launch_interactive_pymol()` starts *PyMOL* using the given command line options,
51
+ reinitializes it and sets necessary parameters.
52
+
53
+ After that, the usual *PyMOL* commands and the other functions from
54
+ *Biotite* are available.
55
+
56
+ Note that the *PyMOL* window will stay open after the end of the script.
57
+ This can lead to issues when using interactive Python (e.g. *IPython*):
58
+ The *PyMOL* window could not be closed by normal means and a forced termination might be
59
+ necessary.
60
+ This can be solved by using *PyMOL*'s integrated command line for executing Python.
61
+
62
+ Launching PyMOL directly
63
+ ^^^^^^^^^^^^^^^^^^^^^^^^
64
+
65
+ .. note::
66
+
67
+ This is not the recommended way to use *PyMOL* in the context of
68
+ :mod:`biotite.interface.pymol`.
69
+ Usage is at your own risk.
70
+
71
+ You can also launch *PyMOL* directly using the *PyMOL* Python API, that
72
+ :func:`launch_pymol()` and :func:`launch_interactive_pymol()` use internally.
73
+ In this case, it is important to call :func:`setup_parameters()` for setting
74
+ parameters that are necessary for *Biotite* to interact properly with *PyMOL*.
75
+ Furthermore, the ``pymol_instance`` parameter must be set the first time
76
+ a :class:`PyMOLObject` is created to inform *Biotite* about the *PyMOL* session.
77
+
78
+ .. code-block:: python
79
+
80
+ from pymol2 import PyMOL
81
+ import biotite.interface.pymol as pymol_interface
82
+
83
+ pymol_app = PyMOL()
84
+ pymol_app.start()
85
+ pymol_interface.setup_parameters(pymol_instance=pymol_app)
86
+ cmd = pymol_app.cmd
87
+
88
+ pymol_object = pymol_interface.PyMOLObject.from_structure(
89
+ atom_array, pymol_instance=pymol_app
90
+ )
91
+
92
+ Common issues
93
+ -------------
94
+ As *PyMOL* is a quite complex software with a lot of its functionality written
95
+ in *C++*, sometimes unexpected results or crashes may occur under certain
96
+ circumstances.
97
+ This page should provide help in such and similar cases.
98
+
99
+ Interactive PyMOL crashes when launched on MacOS
100
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101
+ Unfortunately, the *PyMOL* GUI is not supported on MacOS, as described in
102
+ `this issue <https://github.com/schrodinger/pymol-open-source/issues/97>`_.
103
+ The library mode launched by default should still work.
104
+
105
+ Interactive PyMOL crashes when launched after usage of Matplotlib
106
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107
+ Interactive *PyMOL* will crash, if it is launched after a *Matplotlib* figure
108
+ is created. This does not happen in the object-oriented library mode of
109
+ *PyMOL*.
110
+ Presumably the reason is a conflict in the *OpenGL* contexts.
111
+
112
+ Example code that leads to crash:
113
+
114
+ .. code-block:: python
115
+
116
+ import matplotlib.pyplot as plt
117
+ import biotite.interface.pymol as pymol_interface
118
+
119
+ figure = plt.figure()
120
+ pymol_interface.launch_interactive_pymol()
121
+
122
+ 'cmd.png()' command crashes in pytest function
123
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
124
+ ``pytest`` executes the test functions via ``exec()``, which might lead to the crash.
125
+ Up to now the only way to prevent this, is not to test the ``png()`` command
126
+ in pytest.
127
+
128
+ Launching PyMOL for the first time raises DuplicatePyMOLError
129
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
130
+ For example the code snippet
131
+
132
+ .. code-block:: python
133
+
134
+ import biotite.interface.pymol import cmd, launch_pymol
135
+
136
+ launch_pymol()
137
+
138
+ raises
139
+
140
+ .. code-block:: python
141
+
142
+ biotite.interface.pymol.DuplicatePyMOLError: A PyMOL instance is already running
143
+
144
+ The reason:
145
+
146
+ If ``from biotite.interface.pymol import pymol``
147
+ or ``from biotite.interface.pymol import cmd`` is called, *PyMOL* is already launched
148
+ upon import in order to make the ``pymol`` or ``cmd`` attribute available.
149
+ Subsequent calls of :func:`launch_pymol()` or
150
+ :func:`launch_interactive_pymol()` would start a second *PyMOL* session,
151
+ which is forbidden.
152
+
153
+ To circumvent this problem do not import ``pymol`` or ``cmd`` from
154
+ ``biotite.interface.pymol``, but access these attributes via ``pymol_interface.pymol``
155
+ or ``pymol_interface.cmd`` at the required places in your code.
156
+
157
+ |
158
+
159
+ *PyMOL is a trademark of Schrodinger, LLC.*
160
+ """
161
+
162
+ __name__ = "biotite.interface.pymol"
163
+ __author__ = "Patrick Kunzmann"
164
+
165
+
166
+ from .cgo import *
167
+ from .convert import *
168
+ from .display import *
169
+ from .object import *
170
+ from .shapes import *
171
+
172
+ # Do not import expose the internally used 'get_and_set_pymol_instance()'
173
+ from .startup import (
174
+ DuplicatePyMOLError,
175
+ launch_interactive_pymol,
176
+ launch_pymol,
177
+ reset,
178
+ setup_parameters,
179
+ )
180
+
181
+
182
+ # Make the PyMOL instance accessible via `biotite.interface.pymol.pymol`
183
+ # analogous to a '@property' of a class, but on module level instead
184
+ def __getattr__(name):
185
+ from .startup import get_and_set_pymol_instance
186
+
187
+ if name == "pymol":
188
+ return get_and_set_pymol_instance()
189
+ elif name == "cmd":
190
+ return __getattr__("pymol").cmd
191
+ elif name in list(globals().keys()):
192
+ return globals()["name"]
193
+ else:
194
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
195
+
196
+
197
+ def __dir__():
198
+ return list(globals().keys()) + ["pymol", "cmd"]