reciprocalspaceship 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.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 reciprocalspaceship might be problematic. Click here for more details.
- reciprocalspaceship/VERSION +1 -1
- reciprocalspaceship/algorithms/scale_merged_intensities.py +8 -7
- reciprocalspaceship/dataset.py +5 -0
- reciprocalspaceship/decorators.py +2 -2
- reciprocalspaceship/dtypes/floating.py +24 -28
- reciprocalspaceship/dtypes/integer.py +38 -37
- reciprocalspaceship/dtypes/internals.py +243 -49
- reciprocalspaceship/io/crystfel.py +568 -234
- reciprocalspaceship/utils/__init__.py +6 -1
- reciprocalspaceship/utils/cell.py +5 -0
- reciprocalspaceship/utils/stats.py +5 -7
- reciprocalspaceship/utils/structurefactors.py +5 -0
- reciprocalspaceship/utils/units.py +14 -4
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/METADATA +26 -28
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/RECORD +20 -20
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/WHEEL +1 -1
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/entry_points.txt +0 -1
- tests/test_dataseries.py +1 -1
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/LICENSE +0 -0
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.2.dist-info}/top_level.txt +0 -0
reciprocalspaceship/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.2
|
|
@@ -185,6 +185,7 @@ def scale_merged_intensities(
|
|
|
185
185
|
mean_intensity_method="isotropic",
|
|
186
186
|
bins=100,
|
|
187
187
|
bw=2.0,
|
|
188
|
+
minimum_sigma=-np.inf,
|
|
188
189
|
):
|
|
189
190
|
"""
|
|
190
191
|
Scales merged intensities using Bayesian statistics in order to
|
|
@@ -240,6 +241,9 @@ def scale_merged_intensities(
|
|
|
240
241
|
parameter controls the distance that each reflection impacts in
|
|
241
242
|
reciprocal space. Only affects output if mean_intensity_method is
|
|
242
243
|
\"anisotropic\".
|
|
244
|
+
minimum_sigma : float
|
|
245
|
+
Minimum value imposed on Sigma (default: -np.inf, that is: no minimum).
|
|
246
|
+
|
|
243
247
|
|
|
244
248
|
Returns
|
|
245
249
|
-------
|
|
@@ -281,14 +285,11 @@ def scale_merged_intensities(
|
|
|
281
285
|
I, Sig = ds[intensity_key].to_numpy(), ds[sigma_key].to_numpy()
|
|
282
286
|
if mean_intensity_method == "isotropic":
|
|
283
287
|
dHKL = ds["dHKL"].to_numpy(dtype=np.float64)
|
|
284
|
-
Sigma = (
|
|
285
|
-
mean_intensity_by_resolution(I / multiplicity, dHKL, bins) * multiplicity
|
|
286
|
-
)
|
|
288
|
+
Sigma = mean_intensity_by_resolution(I / multiplicity, dHKL, bins)
|
|
287
289
|
elif mean_intensity_method == "anisotropic":
|
|
288
|
-
Sigma = (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
)
|
|
290
|
+
Sigma = mean_intensity_by_miller_index(I / multiplicity, ds.get_hkls(), bw)
|
|
291
|
+
Sigma = np.clip(Sigma, a_min=minimum_sigma, a_max=np.inf)
|
|
292
|
+
Sigma = Sigma * multiplicity
|
|
292
293
|
|
|
293
294
|
# Initialize outputs
|
|
294
295
|
ds[outputI] = 0.0
|
reciprocalspaceship/dataset.py
CHANGED
|
@@ -1234,6 +1234,11 @@ class DataSet(pd.DataFrame):
|
|
|
1234
1234
|
# Compute new HKLs and phase shifts
|
|
1235
1235
|
hkls = dataset.get_hkls()
|
|
1236
1236
|
compressed_hkls, inverse = np.unique(hkls, axis=0, return_inverse=True)
|
|
1237
|
+
|
|
1238
|
+
# The behavior of np.unique changed with v2.0. This block maintains v1 compatibility
|
|
1239
|
+
if inverse.shape[-1] == 1:
|
|
1240
|
+
inverse = inverse.squeeze(-1)
|
|
1241
|
+
|
|
1237
1242
|
asu_hkls, isym, phi_coeff, phi_shift = hkl_to_asu(
|
|
1238
1243
|
compressed_hkls, dataset.spacegroup, return_phase_shifts=True
|
|
1239
1244
|
)
|
|
@@ -100,7 +100,7 @@ def spacegroupify(func=None, *sg_args):
|
|
|
100
100
|
for arg in sg_args:
|
|
101
101
|
if arg in bargs.arguments:
|
|
102
102
|
bargs.arguments[arg] = _convert_spacegroup(bargs.arguments[arg])
|
|
103
|
-
return f(**bargs.
|
|
103
|
+
return f(*bargs.args, **bargs.kwargs)
|
|
104
104
|
|
|
105
105
|
return wrapped
|
|
106
106
|
|
|
@@ -155,7 +155,7 @@ def cellify(func=None, *cell_args):
|
|
|
155
155
|
for arg in cell_args:
|
|
156
156
|
if arg in bargs.arguments:
|
|
157
157
|
bargs.arguments[arg] = _convert_unitcell(bargs.arguments[arg])
|
|
158
|
-
return f(**bargs.
|
|
158
|
+
return f(*bargs.args, **bargs.kwargs)
|
|
159
159
|
|
|
160
160
|
return wrapped
|
|
161
161
|
|
|
@@ -34,7 +34,6 @@ from __future__ import annotations
|
|
|
34
34
|
|
|
35
35
|
import numpy as np
|
|
36
36
|
from pandas._libs import lib
|
|
37
|
-
from pandas._libs import missing as libmissing
|
|
38
37
|
from pandas._typing import ArrayLike, DtypeObj
|
|
39
38
|
from pandas.util._decorators import cache_readonly
|
|
40
39
|
|
|
@@ -45,6 +44,7 @@ except:
|
|
|
45
44
|
|
|
46
45
|
from pandas import Float32Dtype, Float64Dtype
|
|
47
46
|
from pandas.core.arrays import ExtensionArray
|
|
47
|
+
from pandas.core.dtypes.cast import np_find_common_type
|
|
48
48
|
from pandas.core.dtypes.common import (
|
|
49
49
|
is_bool_dtype,
|
|
50
50
|
is_float,
|
|
@@ -58,7 +58,7 @@ from pandas.core.dtypes.dtypes import ExtensionDtype, register_extension_dtype
|
|
|
58
58
|
from pandas.core.tools.numeric import to_numeric
|
|
59
59
|
|
|
60
60
|
from reciprocalspaceship.dtypes.base import MTZDtype
|
|
61
|
-
from reciprocalspaceship.dtypes.internals import NumericArray
|
|
61
|
+
from reciprocalspaceship.dtypes.internals import NumericArray, is_numeric_na
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
class MTZFloat32Dtype(MTZDtype):
|
|
@@ -80,14 +80,14 @@ class MTZFloat32Dtype(MTZDtype):
|
|
|
80
80
|
return self
|
|
81
81
|
if not all(isinstance(t, MTZFloat32Dtype) for t in dtypes):
|
|
82
82
|
return None
|
|
83
|
-
np_dtype =
|
|
83
|
+
np_dtype = np_find_common_type(
|
|
84
84
|
# error: Item "ExtensionDtype" of "Union[Any, ExtensionDtype]" has no
|
|
85
85
|
# attribute "numpy_dtype"
|
|
86
86
|
[t.numpy_dtype for t in dtypes], # type: ignore[union-attr]
|
|
87
87
|
[],
|
|
88
88
|
)
|
|
89
89
|
if np.issubdtype(np_dtype, np.floating):
|
|
90
|
-
return
|
|
90
|
+
return Float32Dtype()
|
|
91
91
|
return None
|
|
92
92
|
|
|
93
93
|
|
|
@@ -136,7 +136,11 @@ def coerce_to_array(
|
|
|
136
136
|
mask = mask.copy()
|
|
137
137
|
return values, mask
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
if copy:
|
|
140
|
+
values = np.array(values, copy=copy)
|
|
141
|
+
else:
|
|
142
|
+
values = np.asarray(values)
|
|
143
|
+
|
|
140
144
|
if is_object_dtype(values.dtype):
|
|
141
145
|
inferred_type = lib.infer_dtype(values, skipna=True)
|
|
142
146
|
if inferred_type == "empty":
|
|
@@ -160,7 +164,7 @@ def coerce_to_array(
|
|
|
160
164
|
raise TypeError("values must be a 1D list-like")
|
|
161
165
|
|
|
162
166
|
if mask is None:
|
|
163
|
-
mask =
|
|
167
|
+
mask = is_numeric_na(values)
|
|
164
168
|
|
|
165
169
|
else:
|
|
166
170
|
assert len(mask) == len(values)
|
|
@@ -286,6 +290,20 @@ class MTZFloatArray(NumericArray):
|
|
|
286
290
|
def _coerce_to_array(self, value) -> tuple[np.ndarray, np.ndarray]:
|
|
287
291
|
return coerce_to_array(value, dtype=self.dtype)
|
|
288
292
|
|
|
293
|
+
def _maybe_mask_result(self, result, mask):
|
|
294
|
+
"""
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
result : array-like
|
|
298
|
+
mask : array-like bool
|
|
299
|
+
"""
|
|
300
|
+
# if we have a float operand we are by-definition
|
|
301
|
+
# a float result
|
|
302
|
+
# or our op is a divide
|
|
303
|
+
if result.dtype.kind == "f":
|
|
304
|
+
return type(self)(result, mask, copy=False)
|
|
305
|
+
return super()._maybe_mask_result(result=result, mask=mask)
|
|
306
|
+
|
|
289
307
|
def astype(self, dtype, copy: bool = True) -> ArrayLike:
|
|
290
308
|
"""
|
|
291
309
|
Cast to a NumPy array or ExtensionArray with 'dtype'.
|
|
@@ -328,28 +346,6 @@ class MTZFloatArray(NumericArray):
|
|
|
328
346
|
data = self.to_numpy(dtype=dtype, **kwargs) # type: ignore[arg-type]
|
|
329
347
|
return astype_nansafe(data, dtype, copy=False)
|
|
330
348
|
|
|
331
|
-
def _maybe_mask_result(self, result, mask, other, op_name: str):
|
|
332
|
-
"""
|
|
333
|
-
Parameters
|
|
334
|
-
----------
|
|
335
|
-
result : array-like
|
|
336
|
-
mask : array-like bool
|
|
337
|
-
other : scalar or array-like
|
|
338
|
-
op_name : str
|
|
339
|
-
"""
|
|
340
|
-
# if we have a float operand we are by-definition
|
|
341
|
-
# a float result
|
|
342
|
-
# or our op is a divide
|
|
343
|
-
if (
|
|
344
|
-
(is_float_dtype(other) or is_float(other))
|
|
345
|
-
or (op_name in ["rtruediv", "truediv"])
|
|
346
|
-
or (is_float_dtype(self.dtype) and is_numeric_dtype(result.dtype))
|
|
347
|
-
):
|
|
348
|
-
return type(self)(result, mask, copy=False)
|
|
349
|
-
return super()._maybe_mask_result(
|
|
350
|
-
result=result, mask=mask, other=other, op_name=op_name
|
|
351
|
-
)
|
|
352
|
-
|
|
353
349
|
def _values_for_argsort(self) -> np.ndarray:
|
|
354
350
|
return self._data
|
|
355
351
|
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
from __future__ import annotations
|
|
34
34
|
|
|
35
35
|
import numpy as np
|
|
36
|
-
from pandas import Int32Dtype, Int64Dtype
|
|
36
|
+
from pandas import Float32Dtype, Int32Dtype, Int64Dtype
|
|
37
37
|
from pandas._libs import lib
|
|
38
|
-
from pandas._libs import missing as libmissing
|
|
39
38
|
from pandas._typing import ArrayLike, Dtype, DtypeObj
|
|
40
39
|
from pandas.core.arrays import ExtensionArray
|
|
41
40
|
from pandas.core.dtypes.base import ExtensionDtype, register_extension_dtype
|
|
41
|
+
from pandas.core.dtypes.cast import np_find_common_type
|
|
42
42
|
from pandas.core.dtypes.common import (
|
|
43
43
|
is_bool_dtype,
|
|
44
44
|
is_float_dtype,
|
|
@@ -51,7 +51,11 @@ from pandas.core.tools.numeric import to_numeric
|
|
|
51
51
|
from pandas.util._decorators import cache_readonly
|
|
52
52
|
|
|
53
53
|
from reciprocalspaceship.dtypes.base import MTZDtype
|
|
54
|
-
from reciprocalspaceship.dtypes.internals import
|
|
54
|
+
from reciprocalspaceship.dtypes.internals import (
|
|
55
|
+
BaseMaskedDtype,
|
|
56
|
+
NumericArray,
|
|
57
|
+
is_numeric_na,
|
|
58
|
+
)
|
|
55
59
|
|
|
56
60
|
|
|
57
61
|
class MTZInt32Dtype(MTZDtype):
|
|
@@ -88,25 +92,25 @@ class MTZInt32Dtype(MTZDtype):
|
|
|
88
92
|
for t in dtypes
|
|
89
93
|
):
|
|
90
94
|
return None
|
|
91
|
-
np_dtype =
|
|
95
|
+
np_dtype = np_find_common_type(
|
|
92
96
|
# error: List comprehension has incompatible type List[Union[Any,
|
|
93
97
|
# dtype, ExtensionDtype]]; expected List[Union[dtype, None, type,
|
|
94
98
|
# _SupportsDtype, str, Tuple[Any, Union[int, Sequence[int]]],
|
|
95
99
|
# List[Any], _DtypeDict, Tuple[Any, Any]]]
|
|
96
100
|
[
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
(
|
|
102
|
+
t.numpy_dtype # type: ignore[misc]
|
|
103
|
+
if isinstance(t, BaseMaskedDtype)
|
|
104
|
+
else t
|
|
105
|
+
)
|
|
100
106
|
for t in dtypes
|
|
101
107
|
],
|
|
102
108
|
[],
|
|
103
109
|
)
|
|
104
110
|
if np.issubdtype(np_dtype, np.integer):
|
|
105
|
-
return
|
|
111
|
+
return Int32Dtype()
|
|
106
112
|
elif np.issubdtype(np_dtype, np.floating):
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return FLOAT_STR_TO_DTYPE[str(np_dtype)]
|
|
113
|
+
return Float32Dtype()
|
|
110
114
|
return None
|
|
111
115
|
|
|
112
116
|
|
|
@@ -175,7 +179,11 @@ def coerce_to_array(
|
|
|
175
179
|
mask = mask.copy()
|
|
176
180
|
return values, mask
|
|
177
181
|
|
|
178
|
-
|
|
182
|
+
if copy:
|
|
183
|
+
values = np.array(values, copy=copy)
|
|
184
|
+
else:
|
|
185
|
+
values = np.asarray(values)
|
|
186
|
+
|
|
179
187
|
inferred_type = None
|
|
180
188
|
if is_object_dtype(values.dtype) or is_string_dtype(values.dtype):
|
|
181
189
|
inferred_type = lib.infer_dtype(values, skipna=True)
|
|
@@ -202,7 +210,7 @@ def coerce_to_array(
|
|
|
202
210
|
raise TypeError("values must be a 1D list-like")
|
|
203
211
|
|
|
204
212
|
if mask is None:
|
|
205
|
-
mask =
|
|
213
|
+
mask = is_numeric_na(values)
|
|
206
214
|
else:
|
|
207
215
|
assert len(mask) == len(values)
|
|
208
216
|
|
|
@@ -227,7 +235,12 @@ def coerce_to_array(
|
|
|
227
235
|
# a ValueError if the str cannot be parsed into an int
|
|
228
236
|
values = values.astype(dtype, copy=copy)
|
|
229
237
|
else:
|
|
230
|
-
|
|
238
|
+
try:
|
|
239
|
+
values = safe_cast(values, dtype, copy=False)
|
|
240
|
+
except:
|
|
241
|
+
# certain outputs cannot be coerced to int32
|
|
242
|
+
dtype = np.dtype("float64")
|
|
243
|
+
values = safe_cast(values, dtype, copy=False)
|
|
231
244
|
|
|
232
245
|
return values, mask
|
|
233
246
|
|
|
@@ -310,14 +323,6 @@ class MTZIntegerArray(NumericArray):
|
|
|
310
323
|
def dtype(self) -> MTZInt32Dtype:
|
|
311
324
|
return self._dtype
|
|
312
325
|
|
|
313
|
-
def __init__(self, values: np.ndarray, mask: np.ndarray, copy: bool = False):
|
|
314
|
-
if not (isinstance(values, np.ndarray) and values.dtype.kind in ["i", "u"]):
|
|
315
|
-
raise TypeError(
|
|
316
|
-
"values should be integer numpy array. Use "
|
|
317
|
-
"the 'pd.array' function instead"
|
|
318
|
-
)
|
|
319
|
-
super().__init__(values, mask, copy=copy)
|
|
320
|
-
|
|
321
326
|
@classmethod
|
|
322
327
|
def _from_sequence(
|
|
323
328
|
cls, scalars, *, dtype: Dtype | None = None, copy: bool = False
|
|
@@ -335,6 +340,17 @@ class MTZIntegerArray(NumericArray):
|
|
|
335
340
|
def _coerce_to_array(self, value) -> tuple[np.ndarray, np.ndarray]:
|
|
336
341
|
return coerce_to_array(value, dtype=self.dtype)
|
|
337
342
|
|
|
343
|
+
def _maybe_mask_result(self, result, mask):
|
|
344
|
+
"""
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
result : array-like
|
|
348
|
+
mask : array-like bool
|
|
349
|
+
"""
|
|
350
|
+
if result.dtype.kind in "iu":
|
|
351
|
+
return type(self)(result, mask, copy=False)
|
|
352
|
+
return super()._maybe_mask_result(result=result, mask=mask)
|
|
353
|
+
|
|
338
354
|
def astype(self, dtype, copy: bool = True) -> ArrayLike:
|
|
339
355
|
"""
|
|
340
356
|
Cast to a NumPy array or ExtensionArray with 'dtype'.
|
|
@@ -375,21 +391,6 @@ class MTZIntegerArray(NumericArray):
|
|
|
375
391
|
|
|
376
392
|
return self.to_numpy(dtype=dtype, na_value=na_value, copy=False)
|
|
377
393
|
|
|
378
|
-
def _maybe_mask_result(self, result, mask, other, op_name: str):
|
|
379
|
-
"""
|
|
380
|
-
Parameters
|
|
381
|
-
----------
|
|
382
|
-
result : array-like
|
|
383
|
-
mask : array-like bool
|
|
384
|
-
other : scalar or array-like
|
|
385
|
-
op_name : str
|
|
386
|
-
"""
|
|
387
|
-
if is_integer_dtype(result):
|
|
388
|
-
return type(self)(result, mask, copy=False)
|
|
389
|
-
return super()._maybe_mask_result(
|
|
390
|
-
result=result, mask=mask, other=other, op_name=op_name
|
|
391
|
-
)
|
|
392
|
-
|
|
393
394
|
def _values_for_argsort(self) -> np.ndarray:
|
|
394
395
|
"""
|
|
395
396
|
Return values for sorting.
|