biotite 0.41.2__cp312-cp312-macosx_11_0_arm64.whl → 1.0.1__cp312-cp312-macosx_11_0_arm64.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 (205) hide show
  1. biotite/__init__.py +2 -3
  2. biotite/application/__init__.py +1 -1
  3. biotite/application/application.py +20 -10
  4. biotite/application/autodock/__init__.py +1 -1
  5. biotite/application/autodock/app.py +74 -79
  6. biotite/application/blast/__init__.py +1 -1
  7. biotite/application/blast/alignment.py +19 -10
  8. biotite/application/blast/webapp.py +92 -85
  9. biotite/application/clustalo/__init__.py +1 -1
  10. biotite/application/clustalo/app.py +46 -61
  11. biotite/application/dssp/__init__.py +1 -1
  12. biotite/application/dssp/app.py +8 -11
  13. biotite/application/localapp.py +62 -60
  14. biotite/application/mafft/__init__.py +1 -1
  15. biotite/application/mafft/app.py +16 -22
  16. biotite/application/msaapp.py +78 -89
  17. biotite/application/muscle/__init__.py +1 -1
  18. biotite/application/muscle/app3.py +50 -64
  19. biotite/application/muscle/app5.py +23 -31
  20. biotite/application/sra/__init__.py +1 -1
  21. biotite/application/sra/app.py +64 -68
  22. biotite/application/tantan/__init__.py +1 -1
  23. biotite/application/tantan/app.py +22 -45
  24. biotite/application/util.py +7 -9
  25. biotite/application/viennarna/rnaalifold.py +34 -28
  26. biotite/application/viennarna/rnafold.py +24 -39
  27. biotite/application/viennarna/rnaplot.py +36 -21
  28. biotite/application/viennarna/util.py +17 -12
  29. biotite/application/webapp.py +13 -14
  30. biotite/copyable.py +13 -13
  31. biotite/database/__init__.py +1 -1
  32. biotite/database/entrez/__init__.py +1 -1
  33. biotite/database/entrez/check.py +2 -3
  34. biotite/database/entrez/dbnames.py +7 -5
  35. biotite/database/entrez/download.py +55 -49
  36. biotite/database/entrez/key.py +1 -1
  37. biotite/database/entrez/query.py +62 -23
  38. biotite/database/error.py +2 -1
  39. biotite/database/pubchem/__init__.py +1 -1
  40. biotite/database/pubchem/download.py +43 -45
  41. biotite/database/pubchem/error.py +2 -2
  42. biotite/database/pubchem/query.py +34 -31
  43. biotite/database/pubchem/throttle.py +3 -4
  44. biotite/database/rcsb/__init__.py +1 -1
  45. biotite/database/rcsb/download.py +44 -52
  46. biotite/database/rcsb/query.py +85 -80
  47. biotite/database/uniprot/check.py +6 -3
  48. biotite/database/uniprot/download.py +6 -11
  49. biotite/database/uniprot/query.py +115 -31
  50. biotite/file.py +12 -31
  51. biotite/sequence/__init__.py +3 -3
  52. biotite/sequence/align/__init__.py +2 -2
  53. biotite/sequence/align/alignment.py +99 -90
  54. biotite/sequence/align/banded.cpython-312-darwin.so +0 -0
  55. biotite/sequence/align/buckets.py +12 -10
  56. biotite/sequence/align/cigar.py +43 -52
  57. biotite/sequence/align/kmeralphabet.cpython-312-darwin.so +0 -0
  58. biotite/sequence/align/kmeralphabet.pyx +55 -51
  59. biotite/sequence/align/kmersimilarity.cpython-312-darwin.so +0 -0
  60. biotite/sequence/align/kmertable.cpython-312-darwin.so +0 -0
  61. biotite/sequence/align/kmertable.pyx +3 -2
  62. biotite/sequence/align/localgapped.cpython-312-darwin.so +0 -0
  63. biotite/sequence/align/localungapped.cpython-312-darwin.so +0 -0
  64. biotite/sequence/align/matrix.py +81 -82
  65. biotite/sequence/align/multiple.cpython-312-darwin.so +0 -0
  66. biotite/sequence/align/multiple.pyx +1 -1
  67. biotite/sequence/align/pairwise.cpython-312-darwin.so +0 -0
  68. biotite/sequence/align/permutation.cpython-312-darwin.so +0 -0
  69. biotite/sequence/align/permutation.pyx +12 -4
  70. biotite/sequence/align/selector.cpython-312-darwin.so +0 -0
  71. biotite/sequence/align/selector.pyx +52 -54
  72. biotite/sequence/align/statistics.py +32 -33
  73. biotite/sequence/align/tracetable.cpython-312-darwin.so +0 -0
  74. biotite/sequence/alphabet.py +51 -65
  75. biotite/sequence/annotation.py +78 -77
  76. biotite/sequence/codec.cpython-312-darwin.so +0 -0
  77. biotite/sequence/codon.py +90 -79
  78. biotite/sequence/graphics/__init__.py +1 -1
  79. biotite/sequence/graphics/alignment.py +184 -103
  80. biotite/sequence/graphics/colorschemes.py +10 -12
  81. biotite/sequence/graphics/dendrogram.py +79 -34
  82. biotite/sequence/graphics/features.py +133 -99
  83. biotite/sequence/graphics/logo.py +22 -28
  84. biotite/sequence/graphics/plasmid.py +229 -178
  85. biotite/sequence/io/fasta/__init__.py +1 -1
  86. biotite/sequence/io/fasta/convert.py +44 -33
  87. biotite/sequence/io/fasta/file.py +42 -55
  88. biotite/sequence/io/fastq/__init__.py +1 -1
  89. biotite/sequence/io/fastq/convert.py +11 -14
  90. biotite/sequence/io/fastq/file.py +68 -112
  91. biotite/sequence/io/genbank/__init__.py +2 -2
  92. biotite/sequence/io/genbank/annotation.py +12 -20
  93. biotite/sequence/io/genbank/file.py +74 -76
  94. biotite/sequence/io/genbank/metadata.py +74 -62
  95. biotite/sequence/io/genbank/sequence.py +13 -14
  96. biotite/sequence/io/general.py +39 -30
  97. biotite/sequence/io/gff/__init__.py +2 -2
  98. biotite/sequence/io/gff/convert.py +10 -15
  99. biotite/sequence/io/gff/file.py +81 -65
  100. biotite/sequence/phylo/__init__.py +1 -1
  101. biotite/sequence/phylo/nj.cpython-312-darwin.so +0 -0
  102. biotite/sequence/phylo/tree.cpython-312-darwin.so +0 -0
  103. biotite/sequence/phylo/upgma.cpython-312-darwin.so +0 -0
  104. biotite/sequence/profile.py +57 -28
  105. biotite/sequence/search.py +17 -15
  106. biotite/sequence/seqtypes.py +200 -164
  107. biotite/sequence/sequence.py +15 -17
  108. biotite/structure/__init__.py +3 -3
  109. biotite/structure/atoms.py +246 -236
  110. biotite/structure/basepairs.py +260 -271
  111. biotite/structure/bonds.cpython-312-darwin.so +0 -0
  112. biotite/structure/bonds.pyx +29 -32
  113. biotite/structure/box.py +67 -71
  114. biotite/structure/celllist.cpython-312-darwin.so +0 -0
  115. biotite/structure/chains.py +55 -39
  116. biotite/structure/charges.cpython-312-darwin.so +0 -0
  117. biotite/structure/compare.py +32 -32
  118. biotite/structure/density.py +13 -18
  119. biotite/structure/dotbracket.py +20 -22
  120. biotite/structure/error.py +10 -2
  121. biotite/structure/filter.py +83 -78
  122. biotite/structure/geometry.py +130 -119
  123. biotite/structure/graphics/atoms.py +60 -43
  124. biotite/structure/graphics/rna.py +81 -68
  125. biotite/structure/hbond.py +112 -93
  126. biotite/structure/info/__init__.py +0 -2
  127. biotite/structure/info/atoms.py +10 -11
  128. biotite/structure/info/bonds.py +41 -43
  129. biotite/structure/info/ccd.py +4 -5
  130. biotite/structure/info/groups.py +1 -3
  131. biotite/structure/info/masses.py +5 -10
  132. biotite/structure/info/misc.py +1 -1
  133. biotite/structure/info/radii.py +20 -20
  134. biotite/structure/info/standardize.py +15 -26
  135. biotite/structure/integrity.py +18 -71
  136. biotite/structure/io/__init__.py +3 -4
  137. biotite/structure/io/dcd/__init__.py +1 -1
  138. biotite/structure/io/dcd/file.py +22 -20
  139. biotite/structure/io/general.py +47 -61
  140. biotite/structure/io/gro/__init__.py +1 -1
  141. biotite/structure/io/gro/file.py +73 -72
  142. biotite/structure/io/mol/__init__.py +1 -1
  143. biotite/structure/io/mol/convert.py +8 -11
  144. biotite/structure/io/mol/ctab.py +37 -36
  145. biotite/structure/io/mol/header.py +14 -10
  146. biotite/structure/io/mol/mol.py +9 -53
  147. biotite/structure/io/mol/sdf.py +47 -50
  148. biotite/structure/io/netcdf/__init__.py +1 -1
  149. biotite/structure/io/netcdf/file.py +24 -23
  150. biotite/structure/io/pdb/__init__.py +1 -1
  151. biotite/structure/io/pdb/convert.py +32 -20
  152. biotite/structure/io/pdb/file.py +151 -172
  153. biotite/structure/io/pdb/hybrid36.cpython-312-darwin.so +0 -0
  154. biotite/structure/io/pdbqt/__init__.py +1 -1
  155. biotite/structure/io/pdbqt/convert.py +17 -11
  156. biotite/structure/io/pdbqt/file.py +128 -80
  157. biotite/structure/io/pdbx/__init__.py +1 -2
  158. biotite/structure/io/pdbx/bcif.py +36 -44
  159. biotite/structure/io/pdbx/cif.py +140 -110
  160. biotite/structure/io/pdbx/component.py +10 -16
  161. biotite/structure/io/pdbx/convert.py +260 -258
  162. biotite/structure/io/pdbx/encoding.cpython-312-darwin.so +0 -0
  163. biotite/structure/io/trajfile.py +90 -107
  164. biotite/structure/io/trr/__init__.py +1 -1
  165. biotite/structure/io/trr/file.py +12 -15
  166. biotite/structure/io/xtc/__init__.py +1 -1
  167. biotite/structure/io/xtc/file.py +11 -14
  168. biotite/structure/mechanics.py +9 -11
  169. biotite/structure/molecules.py +3 -4
  170. biotite/structure/pseudoknots.py +53 -67
  171. biotite/structure/rdf.py +23 -21
  172. biotite/structure/repair.py +137 -86
  173. biotite/structure/residues.py +26 -16
  174. biotite/structure/sasa.cpython-312-darwin.so +0 -0
  175. biotite/structure/{resutil.py → segments.py} +24 -23
  176. biotite/structure/sequence.py +10 -11
  177. biotite/structure/sse.py +100 -119
  178. biotite/structure/superimpose.py +39 -77
  179. biotite/structure/transform.py +97 -71
  180. biotite/structure/util.py +11 -13
  181. biotite/version.py +2 -2
  182. biotite/visualize.py +69 -55
  183. {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/METADATA +6 -5
  184. biotite-1.0.1.dist-info/RECORD +322 -0
  185. biotite/structure/io/ctab.py +0 -72
  186. biotite/structure/io/mmtf/__init__.py +0 -21
  187. biotite/structure/io/mmtf/assembly.py +0 -214
  188. biotite/structure/io/mmtf/convertarray.cpython-312-darwin.so +0 -0
  189. biotite/structure/io/mmtf/convertarray.pyx +0 -341
  190. biotite/structure/io/mmtf/convertfile.cpython-312-darwin.so +0 -0
  191. biotite/structure/io/mmtf/convertfile.pyx +0 -501
  192. biotite/structure/io/mmtf/decode.cpython-312-darwin.so +0 -0
  193. biotite/structure/io/mmtf/decode.pyx +0 -152
  194. biotite/structure/io/mmtf/encode.cpython-312-darwin.so +0 -0
  195. biotite/structure/io/mmtf/encode.pyx +0 -183
  196. biotite/structure/io/mmtf/file.py +0 -233
  197. biotite/structure/io/npz/__init__.py +0 -20
  198. biotite/structure/io/npz/file.py +0 -152
  199. biotite/structure/io/pdbx/legacy.py +0 -267
  200. biotite/structure/io/tng/__init__.py +0 -13
  201. biotite/structure/io/tng/file.py +0 -46
  202. biotite/temp.py +0 -86
  203. biotite-0.41.2.dist-info/RECORD +0 -340
  204. {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/WHEEL +0 -0
  205. {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/licenses/LICENSE.rst +0 -0
@@ -6,20 +6,29 @@ __name__ = "biotite.sequence.graphics"
6
6
  __author__ = "Patrick Kunzmann"
7
7
  __all__ = ["plot_plasmid_map"]
8
8
 
9
- import copy
9
+ import re
10
10
  import warnings
11
- import abc
12
11
  import numpy as np
13
- import re
14
- from ...visualize import colors
15
- from ..annotation import Annotation, Feature, Location
16
-
17
-
18
- def plot_plasmid_map(axes, annotation, plasmid_size, tick_length=0.02,
19
- tick_step=200, ring_width=0.01, feature_width=0.06,
20
- spacing=0.01, arrow_head_length=0.04, label=None,
21
- face_properties=None, label_properties=None,
22
- omit_oversized_labels=True, feature_formatter=None):
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
+ ):
23
32
  """
24
33
  Plot a plasmid map using the sequence features in the given
25
34
  :class:`Annotation`.
@@ -84,26 +93,26 @@ def plot_plasmid_map(axes, annotation, plasmid_size, tick_length=0.02,
84
93
  the following tuple:
85
94
 
86
95
  - *directional* : bool
87
-
96
+
88
97
  True, if the direction of the feature should be indicated by
89
98
  an arrow.
90
99
  Otherwise, the feature is plotted is arc.
91
-
100
+
92
101
  - *face_color* : tuple or str, optional
93
-
102
+
94
103
  A *Matplotlib* compatible color for the feature arrow/arc.
95
-
104
+
96
105
  - *label_color* : tuple or str, optional
97
-
106
+
98
107
  A *Matplotlib* compatible color for the feature label.
99
-
108
+
100
109
  - *label* : str or None
101
-
110
+
102
111
  The label to be displayed for this feature.
103
112
  None, if no label should be displayed.
104
113
  """
105
114
  from matplotlib.projections.polar import PolarAxes
106
-
115
+
107
116
  if not isinstance(axes, PolarAxes):
108
117
  raise TypeError("The given axes must be a 'PolarAxes'")
109
118
 
@@ -118,16 +127,13 @@ def plot_plasmid_map(axes, annotation, plasmid_size, tick_length=0.02,
118
127
  if feature_formatter is None:
119
128
  feature_formatter = _default_feature_formatter
120
129
 
121
-
122
130
  ### Setup matplotlib ###
123
131
  # The x-coordinate is given as angle (rad)
124
132
  # Full circle -> 2*pi
125
- axes.set_xlim(0, 2*np.pi)
133
+ axes.set_xlim(0, 2 * np.pi)
126
134
  axes.set_ylim(0, 1)
127
135
  axes.yaxis.set_visible(False)
128
- axes.xaxis.set_tick_params(
129
- bottom=False, labelbottom=True
130
- )
136
+ axes.xaxis.set_tick_params(bottom=False, labelbottom=True)
131
137
  axes.set_theta_zero_location("N")
132
138
  axes.set_theta_direction("clockwise")
133
139
  axes.spines["polar"].set_visible(False)
@@ -142,32 +148,39 @@ def plot_plasmid_map(axes, annotation, plasmid_size, tick_length=0.02,
142
148
  axes.xaxis.set_ticks([_loc_to_rad(tick, plasmid_size) for tick in ticks])
143
149
  axes.xaxis.set_ticklabels(tick_labels)
144
150
  ### Draw plasmid ring with ticks and central label ###
145
-
151
+
146
152
  # Plasmid ring
147
153
  # Use 'barh()' instead of a Rectangle patch to ensure that the axes
148
154
  # is properly initialized
149
155
  # Otherwise the feature rectangles are not curved, but straight
150
156
  axes.barh(
151
- 1-ring_width-tick_length, 2*np.pi, ring_width,
152
- align="edge", color="black"
157
+ 1 - ring_width - tick_length, 2 * np.pi, ring_width, align="edge", color="black"
153
158
  )
154
-
159
+
155
160
  # Ticks (ticks itself, not the tick labels)
156
161
  for tick in ticks:
157
162
  angle = _loc_to_rad(tick, plasmid_size)
158
163
  axes.plot(
159
- (angle, angle), (1-tick_length, 1),
160
- color="black", linewidth=1, linestyle="-"
164
+ (angle, angle),
165
+ (1 - tick_length, 1),
166
+ color="black",
167
+ linewidth=1,
168
+ linestyle="-",
161
169
  )
162
-
170
+
163
171
  # Central plasmid label
164
172
  if label is not None:
165
173
  axes.text(
166
- 0, 0, label, ha="center", va="center",
167
- color="black", size=32, fontweight="bold"
174
+ 0,
175
+ 0,
176
+ label,
177
+ ha="center",
178
+ va="center",
179
+ color="black",
180
+ size=32,
181
+ fontweight="bold",
168
182
  )
169
183
 
170
-
171
184
  ### Draw plasmid interior ###
172
185
  inner_radius = 1 - ring_width - tick_length
173
186
  features = sorted(
@@ -177,28 +190,51 @@ def plot_plasmid_map(axes, annotation, plasmid_size, tick_length=0.02,
177
190
  ],
178
191
  # Features are sorted by the length of their location range
179
192
  # The shortest come first
180
- key = lambda feature: np.diff(feature.get_location_range())[0],
181
- reverse = True
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
+ )
182
212
  )
183
- axes.add_artist(PlasmidMap(
184
- axes, 0, features, plasmid_size, inner_radius, feature_width, spacing,
185
- arrow_head_length, label, face_properties, label_properties,
186
- omit_oversized_labels, feature_formatter
187
- ))
188
213
 
189
214
 
190
215
  try:
191
216
  # Only create these classes when matplotlib is installed
192
217
  from matplotlib.artist import Artist
218
+ from matplotlib.patches import Polygon, Rectangle
193
219
  from matplotlib.transforms import Bbox
194
- from matplotlib.patches import Rectangle, Polygon
195
-
196
220
 
197
221
  class PlasmidMap(Artist):
198
- def __init__(self, axes, zorder, features, plasmid_size, radius,
199
- feature_width, spacing, arrow_head_length, label,
200
- face_properties, label_properties, omit_oversized_labels,
201
- feature_formatter):
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
+ ):
202
238
  super().__init__()
203
239
  self._axes = axes
204
240
  self.zorder = zorder
@@ -212,30 +248,36 @@ try:
212
248
  for feature in features:
213
249
  indicators_for_feature = []
214
250
  for loc in feature.locs:
215
- # Set proper positions in 'draw()' method
251
+ # Set proper positions in 'draw()' method
216
252
  bbox = Bbox.from_extents(0, 0, 0, 0)
217
253
  # Draw features as curved arrows (feature indicator)
218
- indicator = axes.add_artist(Feature_Indicator(
219
- axes, self.zorder + 1, feature, loc, bbox,
220
- arrow_head_length, face_properties, label_properties,
221
- omit_oversized_labels, feature_formatter
222
- ))
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
+ )
223
268
  indicators_for_feature.append(indicator)
224
269
  self._all_indicators.append(indicators_for_feature)
225
270
 
226
-
227
271
  def draw(self, renderer, *args, **kwargs):
228
272
  # Find the maximum amount of feature rows
229
273
  # (used for overlapping features)
230
- row_count = int(
231
- self._radius // (self._feature_width + self._spacing)
232
- )
274
+ row_count = int(self._radius // (self._feature_width + self._spacing))
233
275
  # Tracks the location ranges of feature that were added to
234
276
  # a row in order to check if that row is occupied
235
277
  ranges_in_row = [[] for i in range(row_count)]
236
278
  # Stores the bottom coordinate (radius) for each row
237
279
  row_bottoms = [
238
- self._radius - (row+1) * (self._feature_width + self._spacing)
280
+ self._radius - (row + 1) * (self._feature_width + self._spacing)
239
281
  for row in range(row_count)
240
282
  ]
241
283
 
@@ -258,11 +300,13 @@ try:
258
300
  # 'Normal feature'
259
301
  if first <= curr_last and last >= curr_first:
260
302
  is_occupied = True
261
- else: # first < 1
303
+ else: # first < 1
262
304
  # Location is over periodic boundary
263
- if first + self._plasmid_size <= curr_last \
264
- or last >= curr_first:
265
- is_occupied = True
305
+ if (
306
+ first + self._plasmid_size <= curr_last
307
+ or last >= curr_first
308
+ ):
309
+ is_occupied = True
266
310
  if not is_occupied:
267
311
  # Row is not occupied by another feature
268
312
  # in the location range of the new feature
@@ -273,12 +317,10 @@ try:
273
317
  else:
274
318
  # Location is over periodic boundary
275
319
  # Split into 'end' and 'start' part
276
- ranges_in_row[row_i].append((
277
- first + self._plasmid_size, self._plasmid_size
278
- ))
279
- ranges_in_row[row_i].append((
280
- 1, last
281
- ))
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))
282
324
  row_bottom = row_bottoms[row_i]
283
325
  break
284
326
  if row_bottom is None:
@@ -288,24 +330,30 @@ try:
288
330
  "radius or decrease the feature width or spacing"
289
331
  )
290
332
  else:
291
- for loc, indicator in zip(
292
- feature.locs, indicators_for_feature
293
- ):
333
+ for loc, indicator in zip(feature.locs, indicators_for_feature):
294
334
  # Calculate arrow shape parameters
295
- row_center = row_bottom + self._feature_width/2
296
335
  row_top = row_bottom + self._feature_width
297
336
  start_ang = _loc_to_rad(loc.first, self._plasmid_size)
298
- stop_ang = _loc_to_rad(loc.last, self._plasmid_size)
337
+ stop_ang = _loc_to_rad(loc.last, self._plasmid_size)
299
338
  bbox = Bbox.from_extents(
300
339
  start_ang, row_bottom, stop_ang, row_top
301
340
  )
302
341
  indicator.set_bbox(bbox)
303
342
 
304
-
305
- class Feature_Indicator(Artist):
306
- def __init__(self, axes, zorder, feature, loc, bbox, head_length,
307
- arrow_properties, label_properties, omit_oversized_labels,
308
- feature_formatter):
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
+ ):
309
357
  super().__init__()
310
358
  self._axes = axes
311
359
  self.zorder = zorder
@@ -313,44 +361,59 @@ try:
313
361
  self._bbox = bbox
314
362
  self._head_length = head_length
315
363
  self._omit_oversized_labels = omit_oversized_labels
316
-
364
+
317
365
  # Determine how to draw the feature
318
- directional, face_color, label_color, label \
319
- = feature_formatter(feature)
320
-
366
+ directional, face_color, label_color, label = feature_formatter(feature)
367
+
321
368
  # Draw arrow as composition of a rectangle and a triangle,
322
369
  # as FancyArrow does not properly work for polar plots
323
370
 
324
- self._arrow_tail = axes.add_patch(Rectangle(
325
- # Set positions in 'draw()' method
326
- (0, 0), 0, 0,
327
- # Line width is set to 1 to avoid strange artifact in
328
- # the transition from rectangle (tail) to polygon (head)
329
- color=face_color, linewidth=1, zorder = self.zorder + 1,
330
- **arrow_properties
331
- ))
332
-
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
+
333
386
  if directional:
334
387
  # Only draw any arrow head when feature has a direction,
335
388
  # otherwise simply draw the tail (rectangle)
336
- self._arrow_head = axes.add_patch(Polygon(
337
- # Set positions in 'draw()' method
338
- [(0, 0), (0, 0), (0, 0)],
339
- color=face_color, linewidth=1, zorder = self.zorder + 1,
340
- **arrow_properties
341
- ))
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
+ )
342
399
  else:
343
400
  self._arrow_head = None
344
401
 
345
402
  if label is not None:
346
403
  label_properties["color"] = label_color
347
- self._label = axes.add_artist(CurvedText(
348
- # Set positions in 'draw()' method
349
- axes, self.zorder + 1, 0, 0, label, label_properties
350
- ))
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
+ )
351
415
  else:
352
416
  self._label = None
353
-
354
417
 
355
418
  def set_bbox(self, bbox):
356
419
  self._bbox = bbox
@@ -359,17 +422,15 @@ try:
359
422
  if self._label is not None:
360
423
  self._label.set_position(center_x, center_y)
361
424
 
362
-
363
425
  def draw(self, renderer, *args, **kwargs):
364
426
  bbox = self._bbox
365
- center_x = (bbox.x0 + bbox.x1) / 2
366
427
  center_y = (bbox.y0 + bbox.y1) / 2
367
428
 
368
429
  # Constant absolute width for all arrows
369
430
  # irrespective of the radius in the polar plot
370
431
  # Calculate actual angle from given absolute width
371
432
  head_length = self._head_length / center_y
372
-
433
+
373
434
  # Check if the head should be drawn
374
435
  if self._arrow_head is None:
375
436
  head_length = 0
@@ -382,39 +443,38 @@ try:
382
443
  rect_pos = (bbox.x0, bbox.y0)
383
444
  # (x0, y0), (x1, y1), (x2, y2)
384
445
  triangle_coord = [
385
- (bbox.x1 - head_length, bbox.y0), # base 1
386
- (bbox.x1 - head_length, bbox.y1), # base 2
387
- (bbox.x1, center_y) # tip
446
+ (bbox.x1 - head_length, bbox.y0), # base 1
447
+ (bbox.x1 - head_length, bbox.y1), # base 2
448
+ (bbox.x1, center_y), # tip
388
449
  ]
389
450
  else:
390
- rect_pos = (bbox.x0+head_length, bbox.y0)
451
+ rect_pos = (bbox.x0 + head_length, bbox.y0)
391
452
  triangle_coord = [
392
- (bbox.x0 + head_length, bbox.y0), # base 1
393
- (bbox.x0 + head_length, bbox.y1), # base 2
394
- (bbox.x0, center_y) # tip
453
+ (bbox.x0 + head_length, bbox.y0), # base 1
454
+ (bbox.x0 + head_length, bbox.y1), # base 2
455
+ (bbox.x0, center_y), # tip
395
456
  ]
396
-
457
+
397
458
  # Update coordinates of sub-artists
398
459
  self._arrow_tail.set_xy(rect_pos)
399
- self._arrow_tail.set_width(bbox.width-head_length)
460
+ self._arrow_tail.set_width(bbox.width - head_length)
400
461
  self._arrow_tail.set_height(bbox.height)
401
462
  if self._arrow_head is not None:
402
463
  self._arrow_head.set_xy(triangle_coord)
403
-
464
+
404
465
  if self._label is not None:
405
466
  # Do not draw the labels if it is larger than the
406
467
  # indicator
407
- if self._omit_oversized_labels \
408
- and self._label.get_total_angle(renderer) > bbox.width:
409
- self._label.set_visible(False)
468
+ if (
469
+ self._omit_oversized_labels
470
+ and self._label.get_total_angle(renderer) > bbox.width
471
+ ):
472
+ self._label.set_visible(False)
410
473
  else:
411
474
  self._label.set_visible(True)
412
475
 
413
-
414
-
415
476
  class CurvedText(Artist):
416
- def __init__(self, axes, zorder, angle, radius, string,
417
- text_properties):
477
+ def __init__(self, axes, zorder, angle, radius, string, text_properties):
418
478
  super().__init__()
419
479
  self._axes = axes
420
480
  self.zorder = zorder
@@ -425,44 +485,35 @@ try:
425
485
  for word in _split_into_words(string):
426
486
  text = axes.text(
427
487
  # Set position in 'draw()' method
428
- 0, 0,
488
+ 0,
489
+ 0,
429
490
  word,
430
- ha="center", va="center",
491
+ ha="center",
492
+ va="center",
431
493
  zorder=self.zorder + 1,
432
494
  **text_properties,
433
495
  )
434
496
  self._texts.append(text)
435
-
436
497
 
437
498
  def set_visible(self, visible):
438
499
  super().set_visible(visible)
439
500
  for text in self._texts:
440
501
  text.set_visible(visible)
441
502
 
442
-
443
503
  def set_position(self, angle, radius):
444
504
  self._angle = angle
445
505
  self._radius = radius
446
-
447
506
 
448
507
  def get_total_angle(self, renderer):
449
508
  return np.sum(self.get_word_angles(renderer))
450
-
451
509
 
452
510
  def get_word_angles(self, renderer):
453
511
  ax_px_radius = self._axes.get_window_extent(renderer).width / 2
454
512
  ax_unit_radius = self._axes.get_ylim()[1]
455
- circle_px_circumference = ax_px_radius * 2*np.pi \
456
- * (self._radius / ax_unit_radius)
513
+ circle_px_circumference = (
514
+ ax_px_radius * 2 * np.pi * (self._radius / ax_unit_radius)
515
+ )
457
516
 
458
- rad_angle = 360 - np.rad2deg(self._angle)
459
- # Avoid to draw the text upside down, when drawn on the
460
- # bottom half of the map
461
- if rad_angle > 90 and rad_angle < 270:
462
- turn_around = True
463
- else:
464
- turn_around = False
465
-
466
517
  angles = []
467
518
  for text in self._texts:
468
519
  orig_rot = text.get_rotation()
@@ -477,14 +528,12 @@ try:
477
528
  # In this case, assign a fixed width
478
529
  if np.isnan(word_px_width):
479
530
  word_px_width = 5.0
480
- word_angle \
481
- = 2*np.pi * word_px_width / circle_px_circumference
531
+ word_angle = 2 * np.pi * word_px_width / circle_px_circumference
482
532
  angles.append(word_angle)
483
533
  # Restore
484
534
  text.set_rotation(orig_rot)
485
535
  text.set_visible(orig_visible)
486
536
  return angles
487
-
488
537
 
489
538
  def draw(self, renderer, *args, **kwargs):
490
539
  angles = self.get_word_angles(renderer)
@@ -497,7 +546,7 @@ try:
497
546
  turn_around = True
498
547
  else:
499
548
  turn_around = False
500
-
549
+
501
550
  # Now that the angle for each word is known,
502
551
  # the appropriate position and rotation can be set
503
552
  if turn_around:
@@ -526,20 +575,18 @@ except ImportError:
526
575
  pass
527
576
 
528
577
 
529
-
530
-
531
578
  def _loc_to_rad(loc, plasmid_size):
532
579
  if loc > plasmid_size:
533
580
  raise ValueError(
534
581
  f"Location {loc} is larger then the plasmid size of {plasmid_size}"
535
582
  )
536
583
  # Location starts at 1 -> (loc-1)
537
- return ((loc-1) / plasmid_size) * 2*np.pi
584
+ return ((loc - 1) / plasmid_size) * 2 * np.pi
538
585
 
539
586
 
540
587
  def _rad_to_loc(rad, plasmid_size):
541
588
  # Location starts at 1 -> + 1
542
- return rad / (2*np.pi) * plasmid_size + 1
589
+ return rad / (2 * np.pi) * plasmid_size + 1
543
590
 
544
591
 
545
592
  def _merge_over_periodic_boundary(feature, plasmid_size):
@@ -547,7 +594,7 @@ def _merge_over_periodic_boundary(feature, plasmid_size):
547
594
  # Only one location -> no merge possible
548
595
  return feature
549
596
  first_loc = None
550
- last_loc = None
597
+ last_loc = None
551
598
  # Find total first location of the feature
552
599
  for loc in feature.locs:
553
600
  if first_loc is None or loc.first < first_loc.first:
@@ -558,38 +605,43 @@ def _merge_over_periodic_boundary(feature, plasmid_size):
558
605
  last_loc = loc
559
606
  # If the first and last location meet at the periodic boundary of
560
607
  # the plasmid -> merge them
561
- if first_loc.first == 1 and last_loc.last == plasmid_size \
562
- and first_loc.strand == last_loc.strand:
563
- new_locs = set(feature.locs)
564
- new_locs.remove(first_loc)
565
- new_locs.remove(last_loc)
566
- new_locs.add(Location(
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(
567
618
  # the fist base is now at negative location
568
619
  # by shifting by one plasmid 'period'
569
- first = last_loc.first - plasmid_size,
570
- last = first_loc.last,
571
- strand = first_loc.strand,
572
- defect = first_loc.defect | last_loc.defect
573
- ))
574
- return Feature(feature.key, new_locs, feature.qual)
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)
575
627
  else:
576
628
  return feature
577
629
 
578
630
 
579
631
  # ' ', '-' and '_' are word delimiters
580
632
  separators = re.compile(r"\s|_|-")
633
+
634
+
581
635
  def _split_into_words(string):
582
- match_indices = sorted(
583
- [match.start() for match in separators.finditer(string)]
584
- )
636
+ match_indices = sorted([match.start() for match in separators.finditer(string)])
585
637
  current_index = 0
586
638
  words = []
587
639
  for i in match_indices:
588
640
  # Add word up to delimiter
589
- words.append(string[current_index : i])
641
+ words.append(string[current_index:i])
590
642
  # Add delimiter
591
- words.append(string[i : i+1])
592
- current_index = i+1
643
+ words.append(string[i : i + 1])
644
+ current_index = i + 1
593
645
  # If there is a word after the last delimiter, add it too
594
646
  if current_index < len(string):
595
647
  words.append(string[current_index:])
@@ -618,44 +670,43 @@ def _default_feature_formatter(f):
618
670
  else:
619
671
  label = None
620
672
  return False, "black", "white", label
621
-
673
+
622
674
  # Origin of Replication
623
675
  elif f.key == "rep_origin":
624
- return False, "indigo", "white", \
625
- f.qual.get("standard_name", "ori")
626
-
676
+ return False, "indigo", "white", f.qual.get("standard_name", "ori")
677
+
627
678
  # Coding sequences
628
679
  elif f.key in ["gene", "CDS", "rRNA"]:
629
680
  label = f.qual.get("product")
630
681
  if label is None:
631
682
  label = f.qual.get("gene")
632
683
  return True, colors["orange"], "black", label
633
-
684
+
634
685
  elif f.key == "regulatory":
635
686
  # Promoters
636
687
  if f.qual.get("regulatory_class") in [
637
688
  "promoter",
638
689
  "TATA_box",
639
690
  "minus_35_signal",
640
- "minus_10_signal"
691
+ "minus_10_signal",
641
692
  ]:
642
693
  return True, colors["dimgreen"], "black", f.qual.get("note")
643
-
694
+
644
695
  # Terminators
645
696
  elif f.qual.get("regulatory_class") in "terminator":
646
697
  return False, "firebrick", "white", f.qual.get("note")
647
-
698
+
648
699
  # RBS
649
700
  elif f.qual.get("regulatory_class") == "ribosome_binding_site":
650
701
  return False, colors["brightorange"], "white", None
651
-
702
+
652
703
  # Primers
653
704
  elif f.key == "primer_bind":
654
705
  return True, "royalblue", "black", f.qual.get("note")
655
-
706
+
656
707
  # Binding proteins
657
708
  elif f.key == "protein_bind":
658
709
  return False, colors["lightgreen"], "black", f.qual.get("note")
659
-
710
+
660
711
  # Misc
661
- return True, "dimgray", "white", f.qual.get("note")
712
+ return True, "dimgray", "white", f.qual.get("note")