dgpost 2.1.2__tar.gz → 2.2.1__tar.gz

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.
Files changed (65) hide show
  1. {dgpost-2.1.2/src/dgpost.egg-info → dgpost-2.2.1}/PKG-INFO +20 -34
  2. dgpost-2.2.1/pyproject.toml +69 -0
  3. dgpost-2.2.1/setup.cfg +4 -0
  4. dgpost-2.2.1/src/dgpost/__init__.py +8 -0
  5. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/main.py +4 -30
  6. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/catalysis.py +3 -4
  7. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/chromatography.py +2 -2
  8. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/circuit_utils/circuit_components.py +1 -0
  9. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/circuit_utils/circuit_parser.py +5 -4
  10. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/electrochemistry.py +8 -7
  11. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/impedance.py +1 -0
  12. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/rates.py +1 -0
  13. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/reflection.py +37 -33
  14. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/table.py +1 -0
  15. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/__init__.py +2 -0
  16. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/extract.py +13 -9
  17. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/helpers.py +16 -21
  18. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/load.py +3 -2
  19. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/parse.py +19 -3
  20. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/pivot.py +1 -0
  21. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/plot.py +1 -0
  22. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/save.py +2 -1
  23. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/utils/transform.py +1 -0
  24. {dgpost-2.1.2 → dgpost-2.2.1/src/dgpost.egg-info}/PKG-INFO +20 -34
  25. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost.egg-info/SOURCES.txt +1 -5
  26. dgpost-2.2.1/src/dgpost.egg-info/requires.txt +20 -0
  27. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_catalysis_conversion.py +1 -1
  28. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_extract.py +15 -3
  29. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_impedance.py +1 -1
  30. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_load.py +2 -2
  31. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_main.py +2 -4
  32. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_parse.py +7 -11
  33. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_reflection.py +0 -1
  34. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_roundtrip.py +4 -4
  35. dgpost-2.1.2/MANIFEST.in +0 -2
  36. dgpost-2.1.2/setup.cfg +0 -12
  37. dgpost-2.1.2/setup.py +0 -65
  38. dgpost-2.1.2/src/dgpost/__init__.py +0 -8
  39. dgpost-2.1.2/src/dgpost/_version.py +0 -21
  40. dgpost-2.1.2/src/dgpost.egg-info/requires.txt +0 -29
  41. dgpost-2.1.2/versioneer.py +0 -2189
  42. {dgpost-2.1.2 → dgpost-2.2.1}/LICENSE +0 -0
  43. {dgpost-2.1.2 → dgpost-2.2.1}/README.md +0 -0
  44. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/__init__.py +0 -0
  45. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost/transform/circuit_utils/__init__.py +0 -0
  46. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost.egg-info/dependency_links.txt +0 -0
  47. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost.egg-info/entry_points.txt +0 -0
  48. {dgpost-2.1.2 → dgpost-2.2.1}/src/dgpost.egg-info/top_level.txt +0 -0
  49. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_catalysis_atbal.py +0 -0
  50. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_catalysis_selectivity.py +0 -0
  51. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_catalysis_yield.py +0 -0
  52. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_chromatography.py +0 -0
  53. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_electrochemistry_charge.py +0 -0
  54. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_electrochemistry_current.py +0 -0
  55. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_electrochemistry_fe.py +0 -0
  56. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_electrochemistry_nernst.py +0 -0
  57. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_pivot.py +0 -0
  58. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_plot.py +0 -0
  59. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_rates_batchtomolar.py +0 -0
  60. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_rates_flowtomolar.py +0 -0
  61. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_realworld.py +0 -0
  62. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_save.py +0 -0
  63. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_table_combine_columns.py +0 -0
  64. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_table_combine_namespaces.py +0 -0
  65. {dgpost-2.1.2 → dgpost-2.2.1}/tests/test_table_set_uncertainty.py +0 -0
@@ -1,56 +1,42 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: dgpost
3
- Version: 2.1.2
3
+ Version: 2.2.1
4
4
  Summary: datagram post-processing toolkit
5
- Home-page: https://github.com/dgbowl/dgpost
6
- Author: Peter Kraus
7
- Author-email: peter@tondon.de
8
- Project-URL: Bug Tracker, https://github.com/dgbowl/dgpost/issues
9
- Project-URL: Documentation, https://dgbowl.github.io/dgpost/
10
- Classifier: Programming Language :: Python :: 3.9
5
+ Author: Ueli Sauter
6
+ Author-email: Peter Kraus <peter.kraus@tu-berlin.de>
7
+ Maintainer-email: Peter Kraus <peter.kraus@tu-berlin.de>
8
+ Project-URL: Documentation, https://dgbowl.github.io/dgpost/master
9
+ Project-URL: Issues, https://github.com/dgbowl/dgpost/issues
10
+ Project-URL: Repository, https://github.com/dgbowl/dgpost/
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
13
  Classifier: Programming Language :: Python :: 3.10
12
14
  Classifier: Programming Language :: Python :: 3.11
13
15
  Classifier: Programming Language :: Python :: 3.12
14
16
  Classifier: Programming Language :: Python :: 3.13
15
- Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
16
17
  Classifier: Operating System :: OS Independent
17
- Requires-Python: >=3.9
18
+ Requires-Python: >=3.10
18
19
  Description-Content-Type: text/markdown
19
20
  License-File: LICENSE
20
- Requires-Dist: numpy<2.0,>=1.2.0; python_version < "3.10"
21
- Requires-Dist: numpy>=1.2.0; python_version >= "3.10"
21
+ Requires-Dist: numpy>=1.20
22
22
  Requires-Dist: uncertainties<3.2
23
- Requires-Dist: pandas<2.1; python_version < "3.10"
24
- Requires-Dist: pandas>=2.1; python_version >= "3.10"
23
+ Requires-Dist: pandas
25
24
  Requires-Dist: openpyxl
26
- Requires-Dist: pint>=0.22
25
+ Requires-Dist: pint>=0.24.1
27
26
  Requires-Dist: chemicals>=1.0.0
28
27
  Requires-Dist: rdkit>=2022.3
29
28
  Requires-Dist: h5netcdf>=1.0
30
- Requires-Dist: xarray<2024.10.0
31
- Requires-Dist: xarray-datatree>=0.0.12
32
- Requires-Dist: dgbowl-schemas>=116
29
+ Requires-Dist: xarray>=2024.10.0
30
+ Requires-Dist: dgbowl-schemas>=122
33
31
  Requires-Dist: matplotlib>=3.5.0
34
- Requires-Dist: requests
35
32
  Provides-Extra: testing
36
33
  Requires-Dist: pytest; extra == "testing"
37
- Requires-Dist: Pillow; extra == "testing"
34
+ Requires-Dist: ruff; extra == "testing"
38
35
  Provides-Extra: docs
39
36
  Requires-Dist: sphinx~=7.2; extra == "docs"
40
- Requires-Dist: sphinx-rtd-theme; extra == "docs"
41
- Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
42
- Requires-Dist: autodoc-pydantic>=2.0.0; extra == "docs"
43
- Dynamic: author
44
- Dynamic: author-email
45
- Dynamic: classifier
46
- Dynamic: description
47
- Dynamic: description-content-type
48
- Dynamic: home-page
49
- Dynamic: project-url
50
- Dynamic: provides-extra
51
- Dynamic: requires-dist
52
- Dynamic: requires-python
53
- Dynamic: summary
37
+ Requires-Dist: sphinx-rtd-theme~=1.3.0; extra == "docs"
38
+ Requires-Dist: autodoc-pydantic~=2.1.0; extra == "docs"
39
+ Dynamic: license-file
54
40
 
55
41
  # dgpost: datagram post-processing toolkit
56
42
 
@@ -0,0 +1,69 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 61.0", "setuptools-git-versioning"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ dynamic = ["version"]
7
+ name = "dgpost"
8
+ authors = [
9
+ {name = "Peter Kraus", email = "peter.kraus@tu-berlin.de"},
10
+ {name = "Ueli Sauter"},
11
+ ]
12
+ maintainers = [
13
+ {name = "Peter Kraus", email = "peter.kraus@tu-berlin.de"},
14
+ ]
15
+ description = "datagram post-processing toolkit"
16
+ readme = "README.md"
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+ requires-python = ">= 3.10"
27
+ dependencies = [
28
+ "numpy >= 1.20",
29
+ "uncertainties < 3.2",
30
+ "pandas",
31
+ "openpyxl",
32
+ "pint >= 0.24.1",
33
+ "chemicals >= 1.0.0",
34
+ "rdkit >= 2022.3",
35
+ "h5netcdf >= 1.0",
36
+ "xarray >= 2024.10.0",
37
+ "dgbowl-schemas >= 122",
38
+ "matplotlib >= 3.5.0",
39
+ ]
40
+
41
+ [project.optional-dependencies]
42
+ testing = [
43
+ "pytest",
44
+ "ruff",
45
+ ]
46
+ docs = [
47
+ "sphinx ~= 7.2",
48
+ "sphinx-rtd-theme ~= 1.3.0",
49
+ "autodoc-pydantic ~= 2.1.0",
50
+ ]
51
+
52
+ [project.urls]
53
+ Documentation = "https://dgbowl.github.io/dgpost/master"
54
+ Issues = "https://github.com/dgbowl/dgpost/issues"
55
+ Repository = "https://github.com/dgbowl/dgpost/"
56
+
57
+ [project.scripts]
58
+ dgpost = "dgpost:run_with_arguments"
59
+
60
+ [tool.setuptools-git-versioning]
61
+ enabled = true
62
+ dev_template = "{tag}.dev{ccount}"
63
+ dirty_template = "{tag}.dev{ccount}"
64
+
65
+ [tool.ruff]
66
+
67
+ [tool.pytest.ini_options]
68
+ log_cli = false
69
+ log_cli_level = "DEBUG"
dgpost-2.2.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,8 @@
1
+ import sys
2
+ from importlib.metadata import version
3
+ from .main import run_with_arguments, run
4
+
5
+ __all__ = ["run_with_arguments", "run"]
6
+ __version__ = version("dgpost")
7
+
8
+ sys.path += sys.modules["dgpost"].__path__
@@ -5,13 +5,11 @@ dgpost.main
5
5
  Module containing the execution functions for dgpost.
6
6
 
7
7
  """
8
+
8
9
  import argparse
9
10
  import logging
10
11
  from importlib import metadata
11
12
  import copy
12
- import requests
13
- import json
14
- from packaging import version
15
13
 
16
14
  from dgpost.utils import parse, load, extract, transform, save, plot, pivot
17
15
  from dgpost.utils.helpers import combine_tables
@@ -19,29 +17,6 @@ from dgpost.utils.helpers import combine_tables
19
17
  logger = logging.getLogger(__name__)
20
18
 
21
19
 
22
- def version_check(project="dgpost"):
23
- url = f"https://pypi.org/pypi/{project}/json"
24
- try:
25
- res = requests.get(url, timeout=1)
26
- except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
27
- logger.debug(f"Version check could not proceed due to Exception={e}.")
28
- return
29
- jsdata = json.loads(res.text)
30
- versions = sorted([version.parse(i) for i in jsdata["releases"].keys()])
31
- latest = versions[-1]
32
- current = version.parse(metadata.version(project))
33
- if latest > current:
34
- logger.warning("You are using an out-of-date version of '%s'. ", project)
35
- logger.info(
36
- "The latest version is '%s', the current version is '%s'.", latest, current
37
- )
38
- logger.info(
39
- "Consider updating using: pip install --upgrade %s==%s", project, latest
40
- )
41
- else:
42
- logger.debug("Your version of '%s' is up-to-date.", project)
43
-
44
-
45
20
  def run(path: str, patch: str = None) -> tuple[dict, dict]:
46
21
  """
47
22
  Main API execution function. Loads the `recipe` from the provided ``path``,
@@ -83,8 +58,8 @@ def run(path: str, patch: str = None) -> tuple[dict, dict]:
83
58
  tables = {}
84
59
 
85
60
  logger.info("Processing 'load'.")
86
- l = spec.pop("load")
87
- for el in l:
61
+ ldict = spec.pop("load")
62
+ for el in ldict:
88
63
  if patch is None:
89
64
  fp = el["path"]
90
65
  else:
@@ -187,7 +162,7 @@ def run_with_arguments():
187
162
  parser.add_argument(
188
163
  "--version",
189
164
  action="version",
190
- version=f'%(prog)s version {metadata.version("dgpost")}',
165
+ version=f"%(prog)s version {metadata.version('dgpost')}",
191
166
  )
192
167
 
193
168
  parser.add_argument(
@@ -225,5 +200,4 @@ def run_with_arguments():
225
200
  logging.basicConfig(level=loglevel)
226
201
  logging.debug(f"loglevel set to '{logging._levelToName[loglevel]}'")
227
202
 
228
- version_check()
229
203
  run(args.infile, patch=args.patch)
@@ -36,9 +36,6 @@ import pint
36
36
  import logging
37
37
  import numpy as np
38
38
  from typing import Iterable
39
-
40
- logger = logging.getLogger(__name__)
41
-
42
39
  from dgpost.utils.helpers import (
43
40
  name_to_chem,
44
41
  columns_to_smiles,
@@ -48,6 +45,8 @@ from dgpost.utils.helpers import (
48
45
  separate_data,
49
46
  )
50
47
 
48
+ logger = logging.getLogger(__name__)
49
+
51
50
 
52
51
  @load_data(
53
52
  ("xin", None, dict),
@@ -182,7 +181,7 @@ def conversion(
182
181
  if product is not None:
183
182
  logger.warning(
184
183
  "Specifying reactant- and product-based conversion using "
185
- f"'product' is deprecated and will stop working in dgpost-2.0. "
184
+ "'product' is deprecated and will stop working in dgpost-2.0. "
186
185
  "Use 'type={product,reactant,mixed}' instead."
187
186
  )
188
187
  type = "product" if product else "reactant"
@@ -61,7 +61,7 @@ def integrate_trace(
61
61
  and interpolating between the ends of all matched peaks. If consecutive
62
62
  peaks are found, the interpolation spans the whole domain.
63
63
  #) The baseline is subtracted from the signal and the peak areas are
64
- integrated using the :func:`numpy.trapz` function.
64
+ integrated using the :func:`numpy.trapezoid` function.
65
65
  #) The peak height is taken from the original ``signal`` data.
66
66
 
67
67
  The format of the ``species`` specification, used for peak matching, is as follows:
@@ -227,7 +227,7 @@ def integrate_trace(
227
227
  e = v["rlim"] + 1
228
228
  py = signal[s:e] - baseline[s:e]
229
229
  px = time[s:e]
230
- A = np.trapz(py, px)
230
+ A = np.trapezoid(py, px)
231
231
  retval[f"{output}->area->{k}"] = A
232
232
  retval[f"{output}->height->{k}"] = py[v["max"] - s]
233
233
 
@@ -2,6 +2,7 @@
2
2
  dgpost.transform.circuit_utils.circuit_components
3
3
  =================================================
4
4
  """
5
+
5
6
  from typing import Type
6
7
 
7
8
  import numpy as np
@@ -2,6 +2,7 @@
2
2
  dgpost.transform.circuit_utils.circuit_parser
3
3
  =============================================
4
4
  """
5
+
5
6
  import re
6
7
  import warnings
7
8
  import logging
@@ -156,7 +157,7 @@ def fit_routine(
156
157
  with warnings.catch_warnings():
157
158
  warnings.filterwarnings("ignore", message="overflow encountered in tanh")
158
159
 
159
- logger.debug(f"Started fitting routine")
160
+ logger.debug("Started fitting routine")
160
161
  for i in range(repeat):
161
162
  logger.debug(f"Fitting routine pass {i}")
162
163
  opt_result = least_squares(
@@ -168,7 +169,7 @@ def fit_routine(
168
169
  ftol=1e-9,
169
170
  )
170
171
  initial_value = opt_result.x
171
- logger.debug(f"Finished least squares")
172
+ logger.debug("Finished least squares")
172
173
  opt_result = minimize(
173
174
  opt_func,
174
175
  initial_value,
@@ -178,6 +179,6 @@ def fit_routine(
178
179
  method="Nelder-Mead",
179
180
  )
180
181
  initial_value = opt_result.x
181
- logger.debug(f"Finished Nelder-Mead")
182
- logger.debug(f"Finished fitting routine")
182
+ logger.debug("Finished Nelder-Mead")
183
+ logger.debug("Finished fitting routine")
183
184
  return opt_result
@@ -19,6 +19,7 @@ charge and timestamps.
19
19
  nernst
20
20
 
21
21
  """
22
+
22
23
  import pint
23
24
  import numpy as np
24
25
  import pandas as pd
@@ -48,7 +49,7 @@ ureg = pint.get_application_registry()
48
49
  def nernst(
49
50
  Ewe: pint.Quantity,
50
51
  R: pint.Quantity = pint.Quantity(0.0, "Ω"),
51
- I: pint.Quantity = pint.Quantity(0.0, "A"),
52
+ I: pint.Quantity = pint.Quantity(0.0, "A"), # noqa: E741
52
53
  Eref: pint.Quantity = pint.Quantity(0.0, "V"),
53
54
  T: pint.Quantity = pint.Quantity(298.15, "K"),
54
55
  n: int = None,
@@ -148,7 +149,7 @@ def nernst(
148
149
  )
149
150
  def fe(
150
151
  rate: dict[str, pint.Quantity],
151
- I: pint.Quantity,
152
+ I: pint.Quantity, # noqa: E741
152
153
  charges: dict[str, int],
153
154
  output: str = None,
154
155
  ) -> dict[str, pint.Quantity]:
@@ -214,7 +215,7 @@ def fe(
214
215
  )
215
216
  def charge(
216
217
  time: pint.Quantity,
217
- I: pint.Quantity,
218
+ I: pint.Quantity, # noqa: E741
218
219
  t0: pint.Quantity = None,
219
220
  output: str = "Q",
220
221
  ) -> dict[str, pint.Quantity]:
@@ -327,10 +328,10 @@ def average_current(
327
328
  dt = np.diff(time)
328
329
  dQ = np.diff(Q)
329
330
 
330
- I = dQ / dt
331
+ current = dQ / dt
331
332
 
332
- if len(I) != nts:
333
- I = np.insert(I, 0, ureg.Quantity(0, "A"))
333
+ if len(current) != nts:
334
+ current = np.insert(current, 0, ureg.Quantity(0, "A"))
334
335
 
335
- ret = {output: I}
336
+ ret = {output: current}
336
337
  return ret
@@ -26,6 +26,7 @@ to find the :func:`~dgpost.transform.impedance.lowest_real_impedance` in the dat
26
26
  in this module have to be called on each timestep individually.
27
27
 
28
28
  """
29
+
29
30
  import logging
30
31
  from typing import Union
31
32
  import numpy as np
@@ -17,6 +17,7 @@ rates from the concentration profile of a batch mixture.
17
17
  flow_to_molar
18
18
 
19
19
  """
20
+
20
21
  import pint
21
22
  import pandas as pd
22
23
  import numpy as np
@@ -27,25 +27,28 @@ factors to the reflection trace data. The use of the peak-height based pruning v
27
27
 
28
28
 
29
29
  """
30
+
30
31
  import pint
31
32
  import numpy as np
32
33
  import uncertainties as uc
33
34
  from scipy.optimize import curve_fit
35
+ from scipy.signal import find_peaks
34
36
 
35
37
  from dgpost.utils.helpers import separate_data, load_data
36
38
 
37
39
 
38
- def _find_peak(near, absgamma, freq) -> int:
40
+ def _find_peak(near, absgamma, freq, height=0.2) -> int:
39
41
  if near is None:
40
- logmag = -10 * np.log10(absgamma)
41
- return np.argmax(logmag)
42
+ return np.argmax((1 - absgamma))
42
43
  else:
43
- dp = len(freq) // 10
44
- idx = np.argmax(freq > near)
45
- s = max(0, idx - dp)
46
- e = min(len(freq), idx + dp)
47
- logmag = -10 * np.log10(absgamma[s:e])
48
- return s + np.argmax(logmag)
44
+ peaks, _ = find_peaks((1 - absgamma), height=height)
45
+ nearest = None
46
+ for pi in peaks:
47
+ if nearest is None:
48
+ nearest = pi
49
+ elif abs(freq[pi] - near) < abs(freq[nearest] - near):
50
+ nearest = pi
51
+ return nearest
49
52
 
50
53
 
51
54
  @load_data(
@@ -60,6 +63,7 @@ def prune_cutoff(
60
63
  freq: pint.Quantity,
61
64
  near: pint.Quantity = None,
62
65
  cutoff: float = 0.4,
66
+ height: float = 0.2,
63
67
  output: str = "pruned",
64
68
  ) -> dict[str, pint.Quantity]:
65
69
  """
@@ -87,17 +91,18 @@ def prune_cutoff(
87
91
 
88
92
  near
89
93
  A frequency used to select the point around which to prune. By default, pruning
90
- is performed around the highest peak in :math:`\\text{log}|\\Gamma|`. When set,
91
- pruning will be perfomed around any maximum in :math:`\\text{log}|\\Gamma|` that
92
- exists within 10% of the trace size on either side of the selected point. This
93
- means that for a trace size of 20001 points, 2000 points below and 2000 points
94
- above the point corresponding to the selected frequency will be used to find a
95
- local maximum.
94
+ is performed around the highest peak in :math:`(1 - \\Gamma)`. When ``near`` is
95
+ set, the peak nearest in frequency as identified using :func:`~scipy.signal.find_peaks`
96
+ will be used for pruning.
96
97
 
97
98
  cutoff
98
99
  Relative peak height below which the reflection trace should be pruned.
99
100
  Uses a fraction of normalised :math:`|\\Gamma|`. Defaults to ``0.4``.
100
101
 
102
+ height
103
+ Peak height in :math:`(1 - \\Gamma)` passed to :func:`~scipy.signal.find_peaks`,
104
+ defaults to ``0.2``.
105
+
101
106
  output
102
107
  Name for the output namespace. Defaults to ``"pruned"``.
103
108
 
@@ -111,18 +116,20 @@ def prune_cutoff(
111
116
  re, _, _ = separate_data(real)
112
117
  im, _, _ = separate_data(imag)
113
118
  absgamma = np.abs(re + 1j * im)
114
- pi = _find_peak(near, absgamma, freq)
119
+
120
+ pi = _find_peak(near, absgamma, freq, height=height)
121
+
115
122
  max_v = absgamma.max()
116
123
  min_v = absgamma[pi]
117
124
  norm = (absgamma - min_v) / (max_v - min_v)
118
- for l in range(pi - 1):
119
- li = pi - l
125
+ for left in range(pi - 1):
126
+ li = pi - left
120
127
  if norm[li] <= cutoff:
121
128
  pass
122
129
  else:
123
130
  break
124
- for r in range(len(absgamma) - pi):
125
- ri = pi + r
131
+ for rght in range(len(absgamma) - pi):
132
+ ri = pi + rght
126
133
  if norm[ri] <= cutoff:
127
134
  pass
128
135
  else:
@@ -169,13 +176,10 @@ def prune_gradient(
169
176
  corresponding to the reflection coefficient data. Defaults to ``Hz``.
170
177
 
171
178
  near
172
- A frequency used to select around which peak to prune. By default, pruning
173
- is performed around the highest peak in :math:`\\text{log}|\\Gamma|`. When set,
174
- pruning will be perfomed around any maximum in :math:`\\text{log}|\\Gamma|` that
175
- exists within 10% of the trace size on either side of the selected point. This
176
- means that for a trace size of 20001 points, 2000 points below and 2000 points
177
- above the point corresponding to the selected frequency will be used to find a
178
- local maximum.
179
+ A frequency used to select the point around which to prune. By default, pruning
180
+ is performed around the highest peak in :math:`(1 - \\Gamma)`. When ``near`` is
181
+ set, the peak nearest in frequency as identified using :func:`~scipy.signal.find_peaks`
182
+ will be used for pruning.
179
183
 
180
184
  threshold
181
185
  Threshold for the gradient in the :math:`\\text{abs}(\\Gamma)` below which the
@@ -199,15 +203,15 @@ def prune_gradient(
199
203
 
200
204
  pi = _find_peak(near, absgamma, freq)
201
205
 
202
- for l in range(pi - 1):
203
- li = pi - l
204
- if abs(grad[li]) > threshold or l < 100:
206
+ for left in range(pi - 1):
207
+ li = pi - left
208
+ if abs(grad[li]) > threshold or left < 100:
205
209
  pass
206
210
  else:
207
211
  break
208
- for r in range(absgamma.size - pi):
209
- ri = pi + r
210
- if abs(grad[ri]) > threshold or r < 100:
212
+ for rght in range(absgamma.size - pi):
213
+ ri = pi + rght
214
+ if abs(grad[ri]) > threshold or rght < 100:
211
215
  pass
212
216
  else:
213
217
  break
@@ -19,6 +19,7 @@ stripping or replacing uncertainties from data.
19
19
 
20
20
 
21
21
  """
22
+
22
23
  import pint
23
24
  import pandas as pd
24
25
  import numpy as np
@@ -5,3 +5,5 @@ from .parse import parse
5
5
  from .save import save
6
6
  from .plot import plot
7
7
  from .pivot import pivot
8
+
9
+ __all__ = ["extract", "transform", "load", "parse", "save", "plot", "pivot"]
@@ -61,10 +61,10 @@ The data pulled out of the datagram in the second step using the prescription in
61
61
  are interpolated onto the index of the existing :class:`pd.DataFrame`.
62
62
 
63
63
  """
64
+
64
65
  import numpy as np
65
66
  import pandas as pd
66
- import datatree
67
- import xarray as xr
67
+ from xarray import DataTree
68
68
  import uncertainties as uc
69
69
  import uncertainties.unumpy as unp
70
70
  from typing import Union, Any, Optional
@@ -83,14 +83,14 @@ logger = logging.getLogger(__name__)
83
83
 
84
84
 
85
85
  def get_step(
86
- obj: Union[pd.DataFrame, datatree.DataTree, dict, None],
86
+ obj: Union[pd.DataFrame, DataTree, dict, None],
87
87
  at: Optional[dict] = None,
88
- ) -> Union[pd.DataFrame, datatree.DataTree, list[dict], None]:
88
+ ) -> Union[pd.DataFrame, DataTree, list[dict], None]:
89
89
  if obj is None:
90
90
  return None
91
91
  elif isinstance(obj, pd.DataFrame):
92
92
  return obj
93
- elif isinstance(obj, datatree.DataTree):
93
+ elif isinstance(obj, DataTree):
94
94
  if at is not None and "step" in at:
95
95
  return obj[at["step"]]
96
96
  elif at is not None and "steps" in at:
@@ -115,7 +115,7 @@ def get_step(
115
115
  if isinstance(step, int):
116
116
  assert step < len(obj["steps"]), (
117
117
  f"extract: specified step index {step} is out of bounds "
118
- f"of the supplied datagtam with {len(obj['steps'])} steps."
118
+ f"of the supplied datagram with {len(obj['steps'])} steps."
119
119
  )
120
120
  ret += obj["steps"][step]["data"]
121
121
  elif isinstance(step, str):
@@ -148,7 +148,7 @@ def get_constant(spec: dict, ts: pd.Index):
148
148
 
149
149
 
150
150
  def extract(
151
- obj: Union[dict, pd.DataFrame, datatree.DataTree, None],
151
+ obj: Union[dict, pd.DataFrame, DataTree, None],
152
152
  spec: dict,
153
153
  index: pd.Index = None,
154
154
  ) -> pd.DataFrame:
@@ -229,8 +229,8 @@ def _(obj: pd.DataFrame, columns: list[dict]) -> list[pd.Series]:
229
229
  return series
230
230
 
231
231
 
232
- @extract_obj.register(datatree.DataTree)
233
- def _(obj: datatree.DataTree, columns: list[dict]) -> list[pd.Series]:
232
+ @extract_obj.register(DataTree)
233
+ def _(obj: DataTree, columns: list[dict]) -> list[pd.Series]:
234
234
  def get_key_recurse(dt, keys):
235
235
  key = keys.pop(0)
236
236
  if len(keys) == 0:
@@ -259,6 +259,8 @@ def _(obj: datatree.DataTree, columns: list[dict]) -> list[pd.Series]:
259
259
  if vals.coords.dtypes[coord].kind in {"O", "U"}:
260
260
  splits = vals[coord].values
261
261
  break
262
+ else:
263
+ splits = [None]
262
264
  else:
263
265
  coord = None
264
266
  splits = [None]
@@ -276,6 +278,8 @@ def _(obj: datatree.DataTree, columns: list[dict]) -> list[pd.Series]:
276
278
  if sigs is None:
277
279
  if coord is None:
278
280
  data = vals
281
+ elif split is None:
282
+ data = vals.values
279
283
  else:
280
284
  data = vals.loc[{coord: split}]
281
285
  name.append(split)