spectre-core 0.0.8__py3-none-any.whl → 0.0.10__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.
Files changed (109) hide show
  1. spectre_core/__init__.py +0 -3
  2. spectre_core/_file_io/__init__.py +15 -0
  3. spectre_core/_file_io/file_handlers.py +128 -0
  4. spectre_core/capture_configs/__init__.py +29 -0
  5. spectre_core/capture_configs/_capture_config.py +85 -0
  6. spectre_core/capture_configs/_capture_templates.py +222 -0
  7. spectre_core/capture_configs/_parameters.py +110 -0
  8. spectre_core/capture_configs/_pconstraints.py +82 -0
  9. spectre_core/capture_configs/_ptemplates.py +450 -0
  10. spectre_core/capture_configs/_pvalidators.py +173 -0
  11. spectre_core/chunks/__init__.py +17 -201
  12. spectre_core/chunks/{base.py → _base.py} +15 -60
  13. spectre_core/chunks/_chunks.py +200 -0
  14. spectre_core/chunks/{factory.py → _factory.py} +6 -7
  15. spectre_core/chunks/library/{callisto/chunk.py → _callisto.py} +4 -7
  16. spectre_core/chunks/library/{fixed/chunk.py → _fixed_center_frequency.py} +7 -64
  17. spectre_core/chunks/library/_swept_center_frequency.py +103 -0
  18. spectre_core/config/__init__.py +20 -0
  19. spectre_core/config/_paths.py +77 -0
  20. spectre_core/config/_time_formats.py +15 -0
  21. spectre_core/exceptions.py +4 -5
  22. spectre_core/logging/__init__.py +11 -0
  23. spectre_core/logging/_configure.py +35 -0
  24. spectre_core/logging/_decorators.py +19 -0
  25. spectre_core/{logging.py → logging/_log_handlers.py} +13 -58
  26. spectre_core/plotting/__init__.py +7 -1
  27. spectre_core/plotting/{base.py → _base.py} +40 -20
  28. spectre_core/plotting/_format.py +18 -0
  29. spectre_core/plotting/{panel_stack.py → _panel_stack.py} +50 -48
  30. spectre_core/plotting/_panels.py +234 -0
  31. spectre_core/post_processing/__init__.py +14 -0
  32. spectre_core/post_processing/_base.py +119 -0
  33. spectre_core/post_processing/_factory.py +23 -0
  34. spectre_core/post_processing/_post_processor.py +40 -0
  35. spectre_core/post_processing/library/_fixed_center_frequency.py +115 -0
  36. spectre_core/post_processing/library/_swept_center_frequency.py +382 -0
  37. spectre_core/receivers/__init__.py +12 -2
  38. spectre_core/receivers/_base.py +352 -0
  39. spectre_core/receivers/{factory.py → _factory.py} +2 -2
  40. spectre_core/receivers/_spec_names.py +20 -0
  41. spectre_core/receivers/gr/__init__.py +3 -0
  42. spectre_core/receivers/gr/_base.py +33 -0
  43. spectre_core/receivers/gr/_rsp1a.py +158 -0
  44. spectre_core/receivers/gr/_test.py +123 -0
  45. spectre_core/receivers/library/_rsp1a.py +61 -0
  46. spectre_core/receivers/library/_test.py +221 -0
  47. spectre_core/spectrograms/__init__.py +18 -0
  48. spectre_core/spectrograms/{analytical.py → _analytical.py} +29 -27
  49. spectre_core/spectrograms/{array_operations.py → _array_operations.py} +47 -1
  50. spectre_core/spectrograms/{spectrogram.py → _spectrogram.py} +62 -35
  51. spectre_core/spectrograms/{transform.py → _transform.py} +76 -89
  52. spectre_core/{receivers/library → wgetting}/__init__.py +4 -2
  53. spectre_core/wgetting/_callisto.py +155 -0
  54. {spectre_core-0.0.8.dist-info → spectre_core-0.0.10.dist-info}/METADATA +1 -1
  55. spectre_core-0.0.10.dist-info/RECORD +63 -0
  56. spectre_core/cfg.py +0 -116
  57. spectre_core/chunks/library/__init__.py +0 -8
  58. spectre_core/chunks/library/sweep/__init__.py +0 -0
  59. spectre_core/chunks/library/sweep/chunk.py +0 -400
  60. spectre_core/dynamic_imports.py +0 -22
  61. spectre_core/file_handlers/base.py +0 -68
  62. spectre_core/file_handlers/configs.py +0 -271
  63. spectre_core/file_handlers/json.py +0 -40
  64. spectre_core/file_handlers/text.py +0 -21
  65. spectre_core/plotting/factory.py +0 -26
  66. spectre_core/plotting/format.py +0 -19
  67. spectre_core/plotting/library/__init__.py +0 -7
  68. spectre_core/plotting/library/frequency_cuts/panel.py +0 -74
  69. spectre_core/plotting/library/integral_over_frequency/panel.py +0 -34
  70. spectre_core/plotting/library/spectrogram/panel.py +0 -92
  71. spectre_core/plotting/library/time_cuts/panel.py +0 -77
  72. spectre_core/plotting/panel_register.py +0 -13
  73. spectre_core/receivers/base.py +0 -415
  74. spectre_core/receivers/library/rsp1a/__init__.py +0 -0
  75. spectre_core/receivers/library/rsp1a/gr/__init__.py +0 -0
  76. spectre_core/receivers/library/rsp1a/gr/fixed.py +0 -104
  77. spectre_core/receivers/library/rsp1a/gr/sweep.py +0 -129
  78. spectre_core/receivers/library/rsp1a/receiver.py +0 -68
  79. spectre_core/receivers/library/rspduo/__init__.py +0 -0
  80. spectre_core/receivers/library/rspduo/gr/__init__.py +0 -0
  81. spectre_core/receivers/library/rspduo/gr/tuner_1_fixed.py +0 -114
  82. spectre_core/receivers/library/rspduo/gr/tuner_1_sweep.py +0 -131
  83. spectre_core/receivers/library/rspduo/gr/tuner_2_fixed.py +0 -120
  84. spectre_core/receivers/library/rspduo/gr/tuner_2_sweep.py +0 -119
  85. spectre_core/receivers/library/rspduo/receiver.py +0 -97
  86. spectre_core/receivers/library/test/__init__.py +0 -0
  87. spectre_core/receivers/library/test/gr/__init__.py +0 -0
  88. spectre_core/receivers/library/test/gr/cosine_signal_1.py +0 -83
  89. spectre_core/receivers/library/test/gr/tagged_staircase.py +0 -93
  90. spectre_core/receivers/library/test/receiver.py +0 -178
  91. spectre_core/receivers/validators.py +0 -193
  92. spectre_core/watchdog/__init__.py +0 -6
  93. spectre_core/watchdog/base.py +0 -105
  94. spectre_core/watchdog/factory.py +0 -22
  95. spectre_core/watchdog/library/__init__.py +0 -10
  96. spectre_core/watchdog/library/fixed/__init__.py +0 -0
  97. spectre_core/watchdog/library/fixed/event_handler.py +0 -41
  98. spectre_core/watchdog/library/sweep/event_handler.py +0 -55
  99. spectre_core/watchdog/post_processor.py +0 -50
  100. spectre_core/web_fetch/callisto.py +0 -101
  101. spectre_core-0.0.8.dist-info/RECORD +0 -74
  102. /spectre_core/chunks/{chunk_register.py → _register.py} +0 -0
  103. /spectre_core/{watchdog/event_handler_register.py → post_processing/_register.py} +0 -0
  104. /spectre_core/receivers/{receiver_register.py → _register.py} +0 -0
  105. /spectre_core/{chunks/library/callisto/__init__.py → receivers/gr/_rspduo.py} +0 -0
  106. /spectre_core/{chunks/library/fixed/__init__.py → receivers/library/_rspduo.py} +0 -0
  107. {spectre_core-0.0.8.dist-info → spectre_core-0.0.10.dist-info}/LICENSE +0 -0
  108. {spectre_core-0.0.8.dist-info → spectre_core-0.0.10.dist-info}/WHEEL +0 -0
  109. {spectre_core-0.0.8.dist-info → spectre_core-0.0.10.dist-info}/top_level.txt +0 -0
@@ -1,68 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- import os
6
- from abc import ABC, abstractmethod
7
- from typing import Any, Optional
8
- from warnings import warn
9
-
10
- class BaseFileHandler(ABC):
11
- def __init__(self,
12
- parent_path: str,
13
- base_file_name: str,
14
- extension: Optional[str] = None):
15
- self._parent_path = parent_path
16
- self._base_file_name = base_file_name
17
- self._extension = extension
18
-
19
-
20
- @abstractmethod
21
- def read(self) -> Any:
22
- pass
23
-
24
-
25
- @property
26
- def parent_path(self) -> str:
27
- return self._parent_path
28
-
29
-
30
- @property
31
- def base_file_name(self) -> str:
32
- return self._base_file_name
33
-
34
-
35
- @property
36
- def extension(self) -> Optional[str]:
37
- return self._extension
38
-
39
-
40
- @property
41
- def file_name(self) -> str:
42
- return self._base_file_name if (self._extension is None) else f"{self._base_file_name}.{self._extension}"
43
-
44
-
45
- @property
46
- def file_path(self) -> str:
47
- return os.path.join(self._parent_path, self.file_name)
48
-
49
-
50
- @property
51
- def exists(self) -> bool:
52
- return os.path.exists(self.file_path)
53
-
54
-
55
- def make_parent_path(self) -> None:
56
- os.makedirs(self.parent_path, exist_ok=True)
57
-
58
-
59
- def delete(self,
60
- ignore_if_missing: bool = False) -> None:
61
- if not self.exists and not ignore_if_missing:
62
- raise FileNotFoundError(f"{self.file_name} does not exist, and so cannot be deleted")
63
- else:
64
- os.remove(self.file_path)
65
-
66
-
67
- def cat(self) -> None:
68
- print(self.read())
@@ -1,271 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from typing import Any, Optional, Type, Tuple
6
- from abc import ABC
7
- import ast
8
-
9
- from spectre_core.file_handlers.json import JsonHandler
10
- from spectre_core.cfg import CONFIGS_DIR_PATH
11
- from spectre_core.exceptions import InvalidTagError
12
-
13
-
14
- def _unpack_param(param: str) -> list[str, str]:
15
- """Seperate a string of the form "a=b" into a list [a,b]."""
16
- if not param or '=' not in param:
17
- raise ValueError(f'Invalid format: "{param}". Expected "KEY=VALUE".')
18
- if param.startswith('=') or param.endswith('='):
19
- raise ValueError(f'Invalid format: "{param}". Expected "KEY=VALUE".')
20
- # remove leading and trailing whitespace.
21
- param = param.strip()
22
- return param.split('=', 1)
23
-
24
-
25
- def _params_to_string_dict(params: list[str]) -> dict[str, str]:
26
- """Converts a list with string elements of the form "a=b" into a dictionary where the key value pairs are "a": "b"."""
27
- d = {}
28
- for param in params:
29
- key, value = _unpack_param(param)
30
- d[key] = value
31
- return d
32
-
33
-
34
- def _convert_to_dict(v: str) -> dict:
35
- """Evaluate literally a string containing a Python dictionary expression."""
36
- return ast.literal_eval(v)
37
-
38
-
39
- def _convert_to_bool(v: str) -> bool:
40
- """Evaluate literally a string representation of a boolean as a boolean"""
41
- v = v.lower()
42
- if v in ('true', '1', 't', 'y', 'yes'):
43
- return True
44
- if v in ('false', '0', 'f', 'n', 'no'):
45
- return False
46
- raise ValueError(f'Cannot convert {v} to bool.')
47
-
48
-
49
- def _convert_string_to_type(value: str,
50
- target_type: Type) -> Any:
51
- """Cast a string as the target type."""
52
- if target_type == bool:
53
- return _convert_to_bool(value)
54
- elif target_type == dict:
55
- return _convert_to_dict(value)
56
- return target_type(value)
57
-
58
-
59
- def _type_cast_string_dict(d: dict[str, str],
60
- type_template: dict[str, Type]) -> dict[str, Any]:
61
- """Cast the values of the input dictionary according to a type template."""
62
- casted_d = {}
63
- for key, value in d.items():
64
- target_type = type_template.get(key)
65
- if target_type is None:
66
- raise KeyError(f'Key "{key}" not found in type template. Expected keys: {list(type_template.keys())}')
67
- try:
68
- casted_d[key] = _convert_string_to_type(value, target_type)
69
- except ValueError:
70
- raise ValueError(f'Failed to convert key "{key}" with value "{value}" to {target_type.__name__}.')
71
- return casted_d
72
-
73
-
74
- def _validate_keys(d: dict[str, Any],
75
- type_template: dict[str, type],
76
- ignore_keys: Optional[list] = None) -> None:
77
- """Validate that the keys in the input dictionary map one-to-one to the input type template."""
78
- if ignore_keys is None:
79
- ignore_keys = []
80
-
81
- type_template_keys = set(type_template.keys())
82
- input_keys = set(d.keys())
83
- ignore_keys = set(ignore_keys)
84
-
85
- missing_keys = type_template_keys - input_keys
86
- invalid_keys = input_keys - type_template_keys - ignore_keys
87
-
88
- errors = []
89
-
90
- if missing_keys:
91
- errors.append(f"Missing keys: {', '.join(missing_keys)}")
92
-
93
- if invalid_keys:
94
- errors.append(f"Invalid keys: {', '.join(invalid_keys)}")
95
-
96
- if errors:
97
- raise KeyError("Key errors found! " + " ".join(errors))
98
-
99
-
100
- def _validate_types(d: dict[str, Any],
101
- type_template: dict[str, type],
102
- ignore_keys: Optional[list] = None) -> None:
103
- """Validate the types in the input dictionary are consistent with the input type template."""
104
-
105
- if ignore_keys is None:
106
- ignore_keys = []
107
-
108
- for k, v in d.items():
109
- if k in ignore_keys:
110
- continue
111
- expected_type = type_template[k]
112
- if expected_type is None:
113
- raise KeyError(f'Type not found for key "{k}" in the type template.')
114
-
115
- if not isinstance(v, expected_type):
116
- raise TypeError(f'Expected {expected_type} for "{k}", but got {type(v)}.')
117
-
118
-
119
- def validate_against_type_template(d: dict[str, Any],
120
- type_template: dict[str, type],
121
- ignore_keys: Optional[list] = None) -> None:
122
- """Validates the keys and values of the input dictionary, according to the input type template."""
123
- _validate_keys(d,
124
- type_template,
125
- ignore_keys = ignore_keys)
126
- _validate_types(d,
127
- type_template,
128
- ignore_keys = ignore_keys)
129
-
130
-
131
- def type_cast_params(params: list[str],
132
- type_template: dict[str, type]) -> dict[str, Any]:
133
- d = _params_to_string_dict(params)
134
- return _type_cast_string_dict(d,
135
- type_template)
136
-
137
-
138
-
139
- class SPECTREConfig(JsonHandler, ABC):
140
- def __init__(self,
141
- tag: str,
142
- config_type: str,
143
- **kwargs):
144
- self._validate_tag(tag)
145
- self._tag = tag
146
- self._config_type = config_type
147
-
148
- self._dict = None # cache
149
- super().__init__(CONFIGS_DIR_PATH,
150
- f"{config_type}_{tag}",
151
- **kwargs)
152
-
153
-
154
- @property
155
- def tag(self) -> str:
156
- return self._tag
157
-
158
-
159
- @property
160
- def config_type(self) -> str:
161
- return self._config_type
162
-
163
-
164
- @property
165
- def dict(self) -> dict[str, Any]:
166
- if self._dict is None:
167
- self._dict = self.read()
168
- return self._dict
169
-
170
-
171
- def _validate_tag(self, tag: str) -> None:
172
- if "_" in tag:
173
- raise InvalidTagError(f"Tags cannot contain an underscore. Received {tag}")
174
- if "callisto" in tag:
175
- raise InvalidTagError(f'"callisto" cannot be a substring in a native tag. Received "{tag}"')
176
-
177
-
178
- def __getitem__(self,
179
- key: str) -> Any:
180
- return self.dict[key]
181
-
182
-
183
- def get(self,
184
- *args,
185
- **kwargs) -> Any:
186
- return self.dict.get(*args,
187
- **kwargs)
188
-
189
-
190
- def update(self,
191
- *args,
192
- **kwargs) -> None:
193
- self.dict.update(*args, **kwargs)
194
-
195
-
196
- def items(self):
197
- return self.dict.items()
198
-
199
-
200
- def keys(self):
201
- return self.dict.keys()
202
-
203
-
204
- def values(self):
205
- return self.dict.values()
206
-
207
-
208
- class FitsConfig(SPECTREConfig):
209
-
210
- type_template = {
211
- "ORIGIN": str,
212
- "TELESCOP": str,
213
- "INSTRUME": str,
214
- "OBJECT": str,
215
- "OBS_LAT": float,
216
- "OBS_LONG": float,
217
- "OBS_ALT": float
218
- }
219
-
220
- def __init__(self,
221
- tag: str,
222
- **kwargs):
223
- super().__init__(tag,
224
- "fits",
225
- **kwargs)
226
-
227
- def get_create_fits_config_cmd(self,
228
- tag: str,
229
- as_string: bool = False) -> list[str] | str:
230
- command_as_list = ["spectre", "create", "fits-config", "-t", tag]
231
- for key, value in self.type_template.items():
232
- command_as_list += ["-p"]
233
- command_as_list += [f"{key}={value.__name__}"]
234
- if as_string:
235
- return " ".join(command_as_list)
236
- else:
237
- return command_as_list
238
-
239
-
240
- def save_params(self,
241
- params: list[str],
242
- force: bool = False
243
- ) -> None:
244
- d = type_cast_params(params,
245
- self.type_template)
246
- validate_against_type_template(d,
247
- self.type_template)
248
- self.save(d,
249
- force = force)
250
-
251
-
252
- class CaptureConfig(SPECTREConfig):
253
- def __init__(self,
254
- tag: str,
255
- **kwargs):
256
- super().__init__(tag,
257
- "capture",
258
- **kwargs)
259
-
260
-
261
- def get_receiver_metadata(self) -> Tuple[str, str]:
262
-
263
- receiver_name, mode = self.get("receiver"), self.get("mode")
264
-
265
- if receiver_name is None:
266
- raise ValueError("Invalid capture config! Receiver name is not specified.")
267
-
268
- if mode is None:
269
- raise ValueError("Invalid capture config! Receiver mode is not specified.")
270
-
271
- return receiver_name, mode
@@ -1,40 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from typing import Any
6
- import json
7
-
8
- from spectre_core.file_handlers.base import BaseFileHandler
9
-
10
- class JsonHandler(BaseFileHandler):
11
- def __init__(self,
12
- parent_path: str,
13
- base_file_name: str,
14
- extension: str = "json",
15
- **kwargs):
16
- super().__init__(parent_path,
17
- base_file_name,
18
- extension,
19
- **kwargs)
20
-
21
-
22
- def read(self) -> dict[str, Any]:
23
- with open(self.file_path, 'r') as f:
24
- return json.load(f)
25
-
26
-
27
- def save(self,
28
- d: dict,
29
- force: bool = False) -> None:
30
- self.make_parent_path()
31
-
32
- if self.exists:
33
- if force:
34
- pass
35
- else:
36
- raise RuntimeError((f"{self.file_name} already exists, write has been abandoned. "
37
- f"You can override this functionality with `force`"))
38
-
39
- with open(self.file_path, 'w') as file:
40
- json.dump(d, file, indent=4)
@@ -1,21 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from spectre_core.file_handlers.base import BaseFileHandler
6
-
7
- class TextHandler(BaseFileHandler):
8
- def __init__(self,
9
- parent_path: str,
10
- base_file_name: str,
11
- extension: str = "txt",
12
- **kwargs):
13
- super().__init__(parent_path,
14
- base_file_name,
15
- extension,
16
- **kwargs)
17
-
18
-
19
- def read(self) -> dict:
20
- with open(self.file_path, 'r') as f:
21
- return f.read()
@@ -1,26 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from spectre_core.spectrograms.spectrogram import Spectrogram
6
- from spectre_core.plotting.base import BasePanel
7
- from spectre_core.plotting.panel_register import panels
8
- from spectre_core.exceptions import PanelNotFoundError
9
-
10
- def get_panel(panel_name: str,
11
- spectrogram: Spectrogram,
12
- time_type: str,
13
- *args,
14
- **kwargs) -> BasePanel:
15
-
16
- Panel = panels.get(panel_name)
17
- if Panel is None:
18
- valid_panels = list(panels.keys())
19
- raise PanelNotFoundError(f"Could not find panel with name {panel_name}. "
20
- f"Expected one of {valid_panels}")
21
-
22
- return Panel(panel_name,
23
- spectrogram,
24
- time_type,
25
- *args,
26
- **kwargs)
@@ -1,19 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from dataclasses import dataclass
6
-
7
- @dataclass
8
- class DefaultFormats:
9
- small_size: int = 18
10
- medium_size: int = 21
11
- large_size: int = 24
12
- line_width: int = 3
13
- style: str = "dark_background"
14
- spectrogram_cmap: str = "gnuplot2"
15
- cuts_cmap: str = "winter"
16
- integral_over_frequency_color: str = "lime"
17
-
18
-
19
- DEFAULT_FORMATS = DefaultFormats()
@@ -1,7 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from spectre_core.dynamic_imports import import_target_modules
6
-
7
- import_target_modules(__file__, __name__, "panel")
@@ -1,74 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from typing import Optional
6
- from datetime import datetime
7
-
8
- from spectre_core.spectrograms.spectrogram import FrequencyCut
9
- from spectre_core.spectrograms.spectrogram import Spectrogram
10
- from spectre_core.plotting.base import BaseSpectrumPanel, CutsPanel
11
- from spectre_core.plotting.panel_register import register_panel
12
- from spectre_core.plotting.format import DEFAULT_FORMATS
13
-
14
- FREQUENCY_CUTS_PANEL_NAME = "frequency_cuts"
15
-
16
- @register_panel(FREQUENCY_CUTS_PANEL_NAME)
17
- class Panel(BaseSpectrumPanel, CutsPanel):
18
- def __init__(self,
19
- name: str,
20
- spectrogram: Spectrogram,
21
- time_type: str = "seconds",
22
- *times: list[float | str],
23
- dBb: bool = False,
24
- peak_normalise: bool = False,
25
- cmap: str = DEFAULT_FORMATS.cuts_cmap,
26
- **kwargs):
27
- super().__init__(name,
28
- spectrogram,
29
- time_type,
30
- **kwargs)
31
- self._times = times
32
- self._cmap = cmap
33
- self._dBb = dBb
34
- self._peak_normalise = peak_normalise
35
- # map each time cut to the corresponding FrequencyCut dataclass
36
- self._frequency_cuts: Optional[dict[float | datetime, FrequencyCut]] = {}
37
-
38
-
39
- @property
40
- def frequency_cuts(self) -> dict[float | str, FrequencyCut]:
41
- if not self._frequency_cuts:
42
- for time in self._times:
43
- frequency_cut = self._spectrogram.get_frequency_cut(time,
44
- dBb = self._dBb,
45
- peak_normalise = self._peak_normalise)
46
- self._frequency_cuts[frequency_cut.time] = frequency_cut
47
- return self._frequency_cuts
48
-
49
-
50
- @property
51
- def times(self) -> list[float | datetime]:
52
- return list(self.frequency_cuts.keys())
53
-
54
-
55
- def draw(self):
56
- for time, color in self.bind_to_colors():
57
- frequency_cut = self.frequency_cuts[time]
58
- self.ax.step(self.frequencies*1e-6, # convert to MHz
59
- frequency_cut.cut,
60
- where='mid',
61
- color = color)
62
-
63
-
64
- def annotate_y_axis(self) -> None:
65
- if self._dBb:
66
- self.ax.set_ylabel('dBb')
67
- elif self._peak_normalise:
68
- return # no y-axis label
69
- else:
70
- self.ax.set_ylabel(f'{self._spectrogram.spectrum_type.capitalize()}')
71
-
72
-
73
- def bind_to_colors(self):
74
- return super().bind_to_colors(self.times, cmap = self._cmap)
@@ -1,34 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- from spectre_core.plotting.base import BaseTimeSeriesPanel
6
- from spectre_core.plotting.panel_register import register_panel
7
- from spectre_core.plotting.format import DEFAULT_FORMATS
8
-
9
- INTEGRAL_OVER_FREQUENCY_PANEL_NAME = "integral_over_frequency"
10
-
11
- @register_panel(INTEGRAL_OVER_FREQUENCY_PANEL_NAME)
12
- class Panel(BaseTimeSeriesPanel):
13
- def __init__(self,
14
- *args,
15
- peak_normalise: bool = False,
16
- background_subtract: bool = False,
17
- color: str = DEFAULT_FORMATS.integral_over_frequency_color,
18
- **kwargs):
19
- super().__init__(*args, **kwargs)
20
- self._peak_normalise = peak_normalise
21
- self._background_subtract = background_subtract
22
- self._color = color
23
-
24
-
25
- def draw(self):
26
- I = self._spectrogram.integrate_over_frequency(correct_background = self._background_subtract,
27
- peak_normalise = self._peak_normalise)
28
- self.ax.step(self.times, I, where="mid", color = self._color)
29
-
30
-
31
- def annotate_y_axis(self):
32
- return # no y-axis label
33
-
34
-
@@ -1,92 +0,0 @@
1
- # SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
- # This file is part of SPECTRE
3
- # SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- import numpy as np
6
- from matplotlib.colors import LogNorm
7
- from matplotlib.figure import Figure
8
- from matplotlib.axes import Axes
9
- from warnings import warn
10
-
11
- from spectre_core.plotting.base import BaseTimeSeriesPanel
12
- from spectre_core.plotting.panel_register import register_panel
13
- from spectre_core.plotting.base import CutsPanel
14
- from spectre_core.plotting.library.time_cuts.panel import Panel as TimeCutsPanel
15
- from spectre_core.plotting.library.frequency_cuts.panel import Panel as FrequencyCutsPanel
16
- from spectre_core.plotting.format import DEFAULT_FORMATS
17
-
18
- SPECTROGRAM_PANEL_NAME = "spectrogram"
19
-
20
- @register_panel(SPECTROGRAM_PANEL_NAME)
21
- class Panel(BaseTimeSeriesPanel):
22
- def __init__(self,
23
- *args,
24
- log_norm: bool = False,
25
- dBb: bool = False,
26
- vmin: float | None = -1,
27
- vmax: float | None = 2,
28
- cmap: str = DEFAULT_FORMATS.spectrogram_cmap,
29
- **kwargs):
30
- super().__init__(*args, **kwargs)
31
- self._log_norm = log_norm
32
- self._dBb = dBb
33
- self._vmin = vmin
34
- self._vmax = vmax
35
- self._cmap = cmap
36
-
37
-
38
- def draw(self):
39
- dynamic_spectra = self._spectrogram.dynamic_spectra_as_dBb if self._dBb else self._spectrogram.dynamic_spectra
40
-
41
- norm = LogNorm(vmin=np.nanmin(dynamic_spectra[dynamic_spectra > 0]),
42
- vmax=np.nanmax(dynamic_spectra)) if self._log_norm else None
43
-
44
-
45
- if self._log_norm and (self._vmin or self._vmax):
46
- warn("vmin/vmax will be ignored while using log_norm.")
47
- self._vmin = None
48
- self._vmax = None
49
-
50
- # Plot the spectrogram with kwargs
51
- pcm = self.ax.pcolormesh(self.times,
52
- self._spectrogram.frequencies * 1e-6,
53
- dynamic_spectra,
54
- vmin=self._vmin,
55
- vmax=self._vmax,
56
- norm=norm,
57
- cmap=self._cmap)
58
-
59
- # Add colorbar if dBb is used
60
- if self._dBb:
61
- cbar = self.fig.colorbar(pcm,
62
- ax=self.ax,
63
- ticks=np.linspace(self._vmin, self._vmax, 6, dtype=int))
64
- cbar.set_label('dBb')
65
-
66
-
67
- def annotate_y_axis(self) -> None:
68
- self.ax.set_ylabel('Frequency [MHz]')
69
- return
70
-
71
-
72
- def overlay_cuts(self, cuts_panel: CutsPanel) -> None:
73
- if isinstance(cuts_panel, TimeCutsPanel):
74
- self._overlay_time_cuts(cuts_panel)
75
- elif isinstance(cuts_panel, FrequencyCutsPanel):
76
- self._overlay_frequency_cuts(cuts_panel)
77
-
78
-
79
- def _overlay_time_cuts(self, time_cuts_panel: TimeCutsPanel) -> None:
80
- for frequency, color in time_cuts_panel.bind_to_colors():
81
- self.ax.axhline(frequency*1e-6, # convert to MHz
82
- color = color,
83
- linewidth=DEFAULT_FORMATS.line_width
84
- )
85
-
86
-
87
- def _overlay_frequency_cuts(self, frequency_cuts_panel: FrequencyCutsPanel) -> None:
88
- for time, color in frequency_cuts_panel.bind_to_colors():
89
- self.ax.axvline(time,
90
- color = color,
91
- linewidth=DEFAULT_FORMATS.line_width
92
- )