spectre-core 0.0.9__py3-none-any.whl → 0.0.11__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.
- spectre_core/__init__.py +0 -3
- spectre_core/_file_io/__init__.py +15 -0
- spectre_core/_file_io/file_handlers.py +128 -0
- spectre_core/capture_configs/__init__.py +29 -0
- spectre_core/capture_configs/_capture_config.py +85 -0
- spectre_core/capture_configs/_capture_templates.py +222 -0
- spectre_core/capture_configs/_parameters.py +110 -0
- spectre_core/capture_configs/_pconstraints.py +82 -0
- spectre_core/capture_configs/_ptemplates.py +450 -0
- spectre_core/capture_configs/_pvalidators.py +171 -0
- spectre_core/chunks/__init__.py +17 -201
- spectre_core/chunks/{base.py → _base.py} +15 -60
- spectre_core/chunks/_chunks.py +200 -0
- spectre_core/chunks/{factory.py → _factory.py} +6 -7
- spectre_core/chunks/library/{callisto/chunk.py → _callisto.py} +4 -7
- spectre_core/chunks/library/{fixed/chunk.py → _fixed_center_frequency.py} +7 -64
- spectre_core/chunks/library/_swept_center_frequency.py +103 -0
- spectre_core/config/__init__.py +20 -0
- spectre_core/config/_paths.py +77 -0
- spectre_core/config/_time_formats.py +15 -0
- spectre_core/exceptions.py +4 -5
- spectre_core/logging/__init__.py +11 -0
- spectre_core/logging/_configure.py +35 -0
- spectre_core/logging/_decorators.py +19 -0
- spectre_core/{logging.py → logging/_log_handlers.py} +13 -58
- spectre_core/plotting/__init__.py +7 -1
- spectre_core/plotting/{base.py → _base.py} +40 -20
- spectre_core/plotting/_format.py +18 -0
- spectre_core/plotting/{panel_stack.py → _panel_stack.py} +48 -48
- spectre_core/plotting/_panels.py +234 -0
- spectre_core/post_processing/__init__.py +10 -2
- spectre_core/post_processing/_base.py +119 -0
- spectre_core/post_processing/{factory.py → _factory.py} +7 -6
- spectre_core/post_processing/{post_processor.py → _post_processor.py} +3 -3
- spectre_core/post_processing/library/_fixed_center_frequency.py +115 -0
- spectre_core/post_processing/library/_swept_center_frequency.py +382 -0
- spectre_core/receivers/__init__.py +13 -2
- spectre_core/receivers/_base.py +180 -0
- spectre_core/receivers/{factory.py → _factory.py} +2 -2
- spectre_core/receivers/_spec_names.py +20 -0
- spectre_core/receivers/gr/__init__.py +3 -0
- spectre_core/receivers/gr/_base.py +33 -0
- spectre_core/receivers/gr/_rsp1a.py +158 -0
- spectre_core/receivers/gr/_rspduo.py +227 -0
- spectre_core/receivers/gr/_test.py +123 -0
- spectre_core/receivers/library/_rsp1a.py +61 -0
- spectre_core/receivers/library/_rspduo.py +69 -0
- spectre_core/receivers/library/_sdrplay_receiver.py +185 -0
- spectre_core/receivers/library/_test.py +221 -0
- spectre_core/spectrograms/__init__.py +18 -0
- spectre_core/spectrograms/{analytical.py → _analytical.py} +29 -27
- spectre_core/spectrograms/{array_operations.py → _array_operations.py} +47 -1
- spectre_core/spectrograms/{spectrogram.py → _spectrogram.py} +62 -35
- spectre_core/spectrograms/{transform.py → _transform.py} +76 -89
- spectre_core/{post_processing/library → wgetting}/__init__.py +4 -5
- spectre_core/wgetting/_callisto.py +155 -0
- {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/METADATA +1 -1
- spectre_core-0.0.11.dist-info/RECORD +64 -0
- spectre_core/cfg.py +0 -116
- spectre_core/chunks/library/__init__.py +0 -8
- spectre_core/chunks/library/callisto/__init__.py +0 -0
- spectre_core/chunks/library/fixed/__init__.py +0 -0
- spectre_core/chunks/library/sweep/__init__.py +0 -0
- spectre_core/chunks/library/sweep/chunk.py +0 -400
- spectre_core/dynamic_imports.py +0 -22
- spectre_core/file_handlers/base.py +0 -68
- spectre_core/file_handlers/configs.py +0 -271
- spectre_core/file_handlers/json.py +0 -40
- spectre_core/file_handlers/text.py +0 -21
- spectre_core/plotting/factory.py +0 -26
- spectre_core/plotting/format.py +0 -19
- spectre_core/plotting/library/__init__.py +0 -7
- spectre_core/plotting/library/frequency_cuts/panel.py +0 -74
- spectre_core/plotting/library/integral_over_frequency/panel.py +0 -34
- spectre_core/plotting/library/spectrogram/panel.py +0 -92
- spectre_core/plotting/library/time_cuts/panel.py +0 -77
- spectre_core/plotting/panel_register.py +0 -13
- spectre_core/post_processing/base.py +0 -132
- spectre_core/post_processing/library/fixed/__init__.py +0 -0
- spectre_core/post_processing/library/fixed/event_handler.py +0 -40
- spectre_core/post_processing/library/sweep/event_handler.py +0 -54
- spectre_core/receivers/base.py +0 -422
- spectre_core/receivers/library/__init__.py +0 -7
- spectre_core/receivers/library/rsp1a/__init__.py +0 -0
- spectre_core/receivers/library/rsp1a/gr/__init__.py +0 -0
- spectre_core/receivers/library/rsp1a/gr/fixed.py +0 -104
- spectre_core/receivers/library/rsp1a/gr/sweep.py +0 -129
- spectre_core/receivers/library/rsp1a/receiver.py +0 -68
- spectre_core/receivers/library/rspduo/__init__.py +0 -0
- spectre_core/receivers/library/rspduo/gr/__init__.py +0 -0
- spectre_core/receivers/library/rspduo/gr/tuner_1_fixed.py +0 -114
- spectre_core/receivers/library/rspduo/gr/tuner_1_sweep.py +0 -131
- spectre_core/receivers/library/rspduo/gr/tuner_2_fixed.py +0 -120
- spectre_core/receivers/library/rspduo/gr/tuner_2_sweep.py +0 -119
- spectre_core/receivers/library/rspduo/receiver.py +0 -97
- spectre_core/receivers/library/test/__init__.py +0 -0
- spectre_core/receivers/library/test/gr/__init__.py +0 -0
- spectre_core/receivers/library/test/gr/cosine_signal_1.py +0 -83
- spectre_core/receivers/library/test/gr/tagged_staircase.py +0 -93
- spectre_core/receivers/library/test/receiver.py +0 -203
- spectre_core/receivers/validators.py +0 -231
- spectre_core/web_fetch/callisto.py +0 -101
- spectre_core-0.0.9.dist-info/RECORD +0 -74
- /spectre_core/chunks/{chunk_register.py → _register.py} +0 -0
- /spectre_core/post_processing/{event_handler_register.py → _register.py} +0 -0
- /spectre_core/receivers/{receiver_register.py → _register.py} +0 -0
- {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/LICENSE +0 -0
- {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/WHEEL +0 -0
- {spectre_core-0.0.9.dist-info → spectre_core-0.0.11.dist-info}/top_level.txt +0 -0
@@ -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()
|
spectre_core/plotting/factory.py
DELETED
@@ -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)
|
spectre_core/plotting/format.py
DELETED
@@ -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
|
-
)
|
@@ -1,77 +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
|
-
|
7
|
-
from spectre_core.spectrograms.spectrogram import TimeCut
|
8
|
-
from spectre_core.spectrograms.spectrogram import Spectrogram
|
9
|
-
from spectre_core.plotting.base import BaseTimeSeriesPanel, CutsPanel
|
10
|
-
from spectre_core.plotting.format import DEFAULT_FORMATS
|
11
|
-
from spectre_core.plotting.panel_register import register_panel
|
12
|
-
|
13
|
-
TIME_CUTS_PANEL_NAME = "time_cuts"
|
14
|
-
|
15
|
-
@register_panel(TIME_CUTS_PANEL_NAME)
|
16
|
-
class Panel(BaseTimeSeriesPanel, CutsPanel):
|
17
|
-
def __init__(self,
|
18
|
-
name: str,
|
19
|
-
spectrogram: Spectrogram,
|
20
|
-
time_type: str = "seconds",
|
21
|
-
*frequencies: list[float],
|
22
|
-
dBb: bool = False,
|
23
|
-
peak_normalise: bool = False,
|
24
|
-
background_subtract: bool = False,
|
25
|
-
cmap: str = DEFAULT_FORMATS.cuts_cmap,
|
26
|
-
**kwargs):
|
27
|
-
super().__init__(name,
|
28
|
-
spectrogram,
|
29
|
-
time_type,
|
30
|
-
**kwargs)
|
31
|
-
self._frequencies = frequencies
|
32
|
-
self._cmap = cmap
|
33
|
-
self._dBb = dBb
|
34
|
-
self._peak_normalise = peak_normalise
|
35
|
-
self._background_subtract = background_subtract
|
36
|
-
# map each cut frequency to the corresponding TimeCut dataclass
|
37
|
-
self._time_cuts: Optional[dict[float, TimeCut]] = {}
|
38
|
-
|
39
|
-
|
40
|
-
@property
|
41
|
-
def time_cuts(self) -> dict[float, TimeCut]:
|
42
|
-
if not self._time_cuts:
|
43
|
-
for frequency in self._frequencies:
|
44
|
-
time_cut = self._spectrogram.get_time_cut(frequency,
|
45
|
-
dBb = self._dBb,
|
46
|
-
peak_normalise = self._peak_normalise,
|
47
|
-
correct_background = self._background_subtract,
|
48
|
-
return_time_type=self._time_type)
|
49
|
-
self._time_cuts[time_cut.frequency] = time_cut
|
50
|
-
return self._time_cuts
|
51
|
-
|
52
|
-
|
53
|
-
@property
|
54
|
-
def frequencies(self) -> list[float]:
|
55
|
-
return list(self.time_cuts.keys())
|
56
|
-
|
57
|
-
|
58
|
-
def draw(self):
|
59
|
-
for frequency, color in self.bind_to_colors():
|
60
|
-
time_cut = self.time_cuts[frequency]
|
61
|
-
self.ax.step(self.times,
|
62
|
-
time_cut.cut,
|
63
|
-
where='mid',
|
64
|
-
color = color)
|
65
|
-
|
66
|
-
|
67
|
-
def annotate_y_axis(self) -> None:
|
68
|
-
if self._dBb:
|
69
|
-
self.ax.set_ylabel('dBb')
|
70
|
-
elif self._peak_normalise:
|
71
|
-
return # no y-axis label
|
72
|
-
else:
|
73
|
-
self.ax.set_ylabel(f'{self._spectrogram.spectrum_type.capitalize()}')
|
74
|
-
|
75
|
-
|
76
|
-
def bind_to_colors(self):
|
77
|
-
return super().bind_to_colors(self.frequencies, cmap = self._cmap)
|
@@ -1,13 +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
|
-
|
6
|
-
# Global dictionaries to hold the mappings
|
7
|
-
panels = {}
|
8
|
-
|
9
|
-
def register_panel(panel_name: str):
|
10
|
-
def decorator(cls):
|
11
|
-
panels[panel_name] = cls
|
12
|
-
return cls
|
13
|
-
return decorator
|