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.
- biotite/application/application.py +3 -3
- biotite/application/autodock/app.py +1 -1
- biotite/application/blast/webapp.py +1 -1
- biotite/application/clustalo/app.py +1 -1
- biotite/application/dssp/app.py +13 -3
- biotite/application/localapp.py +36 -2
- biotite/application/msaapp.py +10 -10
- biotite/application/muscle/app3.py +5 -18
- biotite/application/muscle/app5.py +5 -5
- biotite/application/sra/app.py +0 -5
- biotite/application/util.py +22 -2
- biotite/application/viennarna/rnaalifold.py +8 -8
- biotite/application/viennarna/rnaplot.py +9 -3
- biotite/application/viennarna/util.py +1 -1
- biotite/application/webapp.py +1 -1
- biotite/database/afdb/__init__.py +12 -0
- biotite/database/afdb/download.py +191 -0
- biotite/database/entrez/dbnames.py +10 -0
- biotite/database/entrez/download.py +9 -10
- biotite/database/entrez/key.py +1 -1
- biotite/database/entrez/query.py +5 -4
- biotite/database/pubchem/download.py +6 -6
- biotite/database/pubchem/error.py +10 -0
- biotite/database/pubchem/query.py +12 -23
- biotite/database/rcsb/download.py +3 -2
- biotite/database/rcsb/query.py +8 -9
- biotite/database/uniprot/check.py +22 -17
- biotite/database/uniprot/download.py +3 -6
- biotite/database/uniprot/query.py +4 -5
- biotite/file.py +14 -2
- biotite/interface/__init__.py +19 -0
- biotite/interface/openmm/__init__.py +16 -0
- biotite/interface/openmm/state.py +93 -0
- biotite/interface/openmm/system.py +227 -0
- biotite/interface/pymol/__init__.py +198 -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 +1226 -0
- biotite/interface/pymol/shapes.py +178 -0
- biotite/interface/pymol/startup.py +169 -0
- biotite/interface/rdkit/__init__.py +15 -0
- biotite/interface/rdkit/mol.py +490 -0
- biotite/interface/version.py +71 -0
- biotite/interface/warning.py +19 -0
- biotite/sequence/align/__init__.py +0 -4
- biotite/sequence/align/alignment.py +49 -14
- biotite/sequence/align/banded.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/banded.pyx +26 -26
- biotite/sequence/align/cigar.py +2 -2
- biotite/sequence/align/kmeralphabet.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/kmeralphabet.pyx +19 -2
- biotite/sequence/align/kmersimilarity.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/kmertable.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/kmertable.pyx +58 -48
- biotite/sequence/align/localgapped.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/localgapped.pyx +47 -47
- biotite/sequence/align/localungapped.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/localungapped.pyx +10 -10
- biotite/sequence/align/matrix.py +284 -57
- biotite/sequence/align/matrix_data/3Di.mat +24 -0
- biotite/sequence/align/matrix_data/PB.license +21 -0
- biotite/sequence/align/matrix_data/PB.mat +18 -0
- biotite/sequence/align/multiple.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/pairwise.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/pairwise.pyx +35 -35
- biotite/sequence/align/permutation.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/selector.cp311-win_amd64.pyd +0 -0
- biotite/sequence/align/selector.pyx +2 -2
- biotite/sequence/align/statistics.py +1 -1
- biotite/sequence/align/tracetable.cp311-win_amd64.pyd +0 -0
- biotite/sequence/alphabet.py +5 -2
- biotite/sequence/annotation.py +19 -13
- biotite/sequence/codec.cp311-win_amd64.pyd +0 -0
- biotite/sequence/codon.py +1 -2
- biotite/sequence/graphics/alignment.py +25 -39
- biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
- biotite/sequence/graphics/color_schemes/pb_flower.json +2 -1
- biotite/sequence/graphics/colorschemes.py +44 -11
- biotite/sequence/graphics/dendrogram.py +4 -2
- biotite/sequence/graphics/features.py +2 -2
- biotite/sequence/graphics/logo.py +10 -12
- biotite/sequence/io/fasta/convert.py +1 -2
- biotite/sequence/io/fasta/file.py +1 -1
- biotite/sequence/io/fastq/file.py +3 -3
- biotite/sequence/io/genbank/file.py +3 -3
- biotite/sequence/io/genbank/sequence.py +2 -0
- biotite/sequence/io/gff/convert.py +1 -1
- biotite/sequence/io/gff/file.py +1 -2
- biotite/sequence/phylo/nj.cp311-win_amd64.pyd +0 -0
- biotite/sequence/phylo/tree.cp311-win_amd64.pyd +0 -0
- biotite/sequence/phylo/upgma.cp311-win_amd64.pyd +0 -0
- biotite/sequence/profile.py +105 -29
- biotite/sequence/search.py +0 -1
- biotite/sequence/seqtypes.py +136 -8
- biotite/sequence/sequence.py +1 -2
- biotite/setup_ccd.py +197 -0
- biotite/structure/__init__.py +6 -3
- 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 +163 -66
- biotite/structure/basepairs.py +26 -26
- biotite/structure/bonds.cp311-win_amd64.pyd +0 -0
- biotite/structure/bonds.pyx +79 -25
- biotite/structure/box.py +19 -21
- biotite/structure/celllist.cp311-win_amd64.pyd +0 -0
- biotite/structure/celllist.pyx +83 -67
- biotite/structure/chains.py +5 -37
- biotite/structure/charges.cp311-win_amd64.pyd +0 -0
- biotite/structure/compare.py +420 -13
- biotite/structure/density.py +1 -1
- biotite/structure/dotbracket.py +27 -28
- biotite/structure/filter.py +8 -8
- biotite/structure/geometry.py +74 -127
- biotite/structure/hbond.py +17 -19
- biotite/structure/info/__init__.py +1 -0
- biotite/structure/info/atoms.py +24 -15
- biotite/structure/info/bonds.py +12 -6
- biotite/structure/info/ccd.py +125 -34
- biotite/structure/info/{ccd/components.bcif → components.bcif} +0 -0
- biotite/structure/info/groups.py +62 -19
- biotite/structure/info/masses.py +9 -6
- biotite/structure/info/misc.py +15 -22
- biotite/structure/info/radii.py +92 -22
- biotite/structure/info/standardize.py +4 -4
- biotite/structure/integrity.py +4 -6
- biotite/structure/io/general.py +2 -2
- biotite/structure/io/gro/file.py +8 -9
- biotite/structure/io/mol/convert.py +1 -1
- biotite/structure/io/mol/ctab.py +33 -28
- biotite/structure/io/mol/mol.py +1 -1
- biotite/structure/io/mol/sdf.py +80 -53
- biotite/structure/io/pdb/convert.py +4 -3
- biotite/structure/io/pdb/file.py +85 -25
- biotite/structure/io/pdb/hybrid36.cp311-win_amd64.pyd +0 -0
- biotite/structure/io/pdbqt/file.py +36 -36
- biotite/structure/io/pdbx/__init__.py +1 -0
- biotite/structure/io/pdbx/bcif.py +54 -15
- biotite/structure/io/pdbx/cif.py +92 -66
- biotite/structure/io/pdbx/component.py +15 -4
- biotite/structure/io/pdbx/compress.py +321 -0
- biotite/structure/io/pdbx/convert.py +410 -75
- biotite/structure/io/pdbx/encoding.cp311-win_amd64.pyd +0 -0
- biotite/structure/io/pdbx/encoding.pyx +98 -17
- biotite/structure/io/trajfile.py +9 -6
- biotite/structure/io/util.py +38 -0
- biotite/structure/mechanics.py +0 -1
- biotite/structure/molecules.py +141 -156
- biotite/structure/pseudoknots.py +7 -13
- biotite/structure/repair.py +2 -4
- biotite/structure/residues.py +13 -24
- biotite/structure/rings.py +335 -0
- biotite/structure/sasa.cp311-win_amd64.pyd +0 -0
- biotite/structure/sasa.pyx +2 -1
- biotite/structure/segments.py +69 -11
- biotite/structure/sequence.py +0 -1
- biotite/structure/sse.py +0 -2
- biotite/structure/superimpose.py +74 -62
- biotite/structure/tm.py +581 -0
- biotite/structure/transform.py +12 -25
- biotite/structure/util.py +76 -4
- biotite/version.py +9 -4
- biotite/visualize.py +111 -1
- {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/METADATA +6 -2
- {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/RECORD +173 -143
- biotite/structure/info/ccd/README.rst +0 -8
- biotite/structure/info/ccd/amino_acids.txt +0 -1663
- biotite/structure/info/ccd/carbohydrates.txt +0 -1135
- biotite/structure/info/ccd/nucleotides.txt +0 -798
- {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
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
|
-
|
|
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"]
|