spectre-core 0.0.22__py3-none-any.whl → 0.0.23__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 (77) hide show
  1. spectre_core/_file_io/__init__.py +4 -4
  2. spectre_core/_file_io/file_handlers.py +60 -106
  3. spectre_core/batches/__init__.py +20 -3
  4. spectre_core/batches/_base.py +85 -134
  5. spectre_core/batches/_batches.py +55 -99
  6. spectre_core/batches/_factory.py +21 -20
  7. spectre_core/batches/_register.py +8 -8
  8. spectre_core/batches/plugins/_batch_keys.py +7 -6
  9. spectre_core/batches/plugins/_callisto.py +65 -97
  10. spectre_core/batches/plugins/_iq_stream.py +105 -169
  11. spectre_core/capture_configs/__init__.py +46 -17
  12. spectre_core/capture_configs/_capture_config.py +25 -52
  13. spectre_core/capture_configs/_capture_modes.py +8 -6
  14. spectre_core/capture_configs/_capture_templates.py +50 -110
  15. spectre_core/capture_configs/_parameters.py +37 -74
  16. spectre_core/capture_configs/_pconstraints.py +40 -40
  17. spectre_core/capture_configs/_pnames.py +36 -34
  18. spectre_core/capture_configs/_ptemplates.py +260 -347
  19. spectre_core/capture_configs/_pvalidators.py +99 -102
  20. spectre_core/config/__init__.py +13 -8
  21. spectre_core/config/_paths.py +18 -35
  22. spectre_core/config/_time_formats.py +6 -5
  23. spectre_core/exceptions.py +38 -0
  24. spectre_core/jobs/__init__.py +3 -6
  25. spectre_core/jobs/_duration.py +12 -0
  26. spectre_core/jobs/_jobs.py +72 -43
  27. spectre_core/jobs/_workers.py +55 -105
  28. spectre_core/logs/__init__.py +7 -2
  29. spectre_core/logs/_configure.py +13 -17
  30. spectre_core/logs/_decorators.py +6 -4
  31. spectre_core/logs/_logs.py +37 -89
  32. spectre_core/logs/_process_types.py +5 -3
  33. spectre_core/plotting/__init__.py +13 -3
  34. spectre_core/plotting/_base.py +64 -138
  35. spectre_core/plotting/_format.py +10 -8
  36. spectre_core/plotting/_panel_names.py +7 -5
  37. spectre_core/plotting/_panel_stack.py +82 -115
  38. spectre_core/plotting/_panels.py +120 -155
  39. spectre_core/post_processing/__init__.py +6 -3
  40. spectre_core/post_processing/_base.py +41 -55
  41. spectre_core/post_processing/_factory.py +14 -11
  42. spectre_core/post_processing/_post_processor.py +16 -12
  43. spectre_core/post_processing/_register.py +10 -7
  44. spectre_core/post_processing/plugins/_event_handler_keys.py +4 -3
  45. spectre_core/post_processing/plugins/_fixed_center_frequency.py +54 -47
  46. spectre_core/post_processing/plugins/_swept_center_frequency.py +199 -174
  47. spectre_core/receivers/__init__.py +9 -2
  48. spectre_core/receivers/_base.py +82 -148
  49. spectre_core/receivers/_factory.py +20 -30
  50. spectre_core/receivers/_register.py +7 -10
  51. spectre_core/receivers/_spec_names.py +17 -15
  52. spectre_core/receivers/plugins/_b200mini.py +47 -60
  53. spectre_core/receivers/plugins/_receiver_names.py +8 -6
  54. spectre_core/receivers/plugins/_rsp1a.py +44 -40
  55. spectre_core/receivers/plugins/_rspduo.py +59 -44
  56. spectre_core/receivers/plugins/_sdrplay_receiver.py +67 -83
  57. spectre_core/receivers/plugins/_test.py +136 -129
  58. spectre_core/receivers/plugins/_usrp.py +93 -85
  59. spectre_core/receivers/plugins/gr/__init__.py +1 -1
  60. spectre_core/receivers/plugins/gr/_base.py +14 -22
  61. spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
  62. spectre_core/receivers/plugins/gr/_rspduo.py +77 -89
  63. spectre_core/receivers/plugins/gr/_test.py +49 -57
  64. spectre_core/receivers/plugins/gr/_usrp.py +61 -59
  65. spectre_core/spectrograms/__init__.py +21 -13
  66. spectre_core/spectrograms/_analytical.py +108 -99
  67. spectre_core/spectrograms/_array_operations.py +39 -46
  68. spectre_core/spectrograms/_spectrogram.py +289 -322
  69. spectre_core/spectrograms/_transform.py +106 -73
  70. spectre_core/wgetting/__init__.py +1 -3
  71. spectre_core/wgetting/_callisto.py +87 -93
  72. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/METADATA +9 -23
  73. spectre_core-0.0.23.dist-info/RECORD +79 -0
  74. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/WHEEL +1 -1
  75. spectre_core-0.0.22.dist-info/RECORD +0 -78
  76. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/licenses/LICENSE +0 -0
  77. {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
 
5
5
  from logging import getLogger
6
+
6
7
  _LOGGER = getLogger(__name__)
7
8
 
8
9
  import os
@@ -15,11 +16,8 @@ from spectre_core.config import get_logs_dir_path, TimeFormat
15
16
  from ._process_types import ProcessType
16
17
 
17
18
 
18
- def parse_log_base_file_name(
19
- base_file_name: str
20
- ) -> Tuple[str, str, str]:
21
- """Parse the base file name of a log into a start time, process ID and process type.
22
- """
19
+ def parse_log_base_file_name(base_file_name: str) -> Tuple[str, str, str]:
20
+ """Parse the base file name of a log into a start time, process ID and process type."""
23
21
  file_name, _ = os.path.splitext(base_file_name)
24
22
  log_start_time, pid, process_type = file_name.split("_")
25
23
  return log_start_time, pid, process_type
@@ -27,12 +25,8 @@ def parse_log_base_file_name(
27
25
 
28
26
  class Log(TextHandler):
29
27
  """Interface to read log files generated by `spectre`."""
30
- def __init__(
31
- self,
32
- start_time: str,
33
- pid: str,
34
- process_type: ProcessType
35
- ) -> None:
28
+
29
+ def __init__(self, start_time: str, pid: str, process_type: ProcessType) -> None:
36
30
  """Initialise a `Log` instance.
37
31
 
38
32
  :param start_time: The timestamp when the log file was created.
@@ -48,40 +42,32 @@ class Log(TextHandler):
48
42
  base_file_name = f"{start_time}_{pid}_{process_type.value}"
49
43
 
50
44
  super().__init__(parent_path, base_file_name, "log")
51
-
52
45
 
53
46
  @property
54
- def start_time(
55
- self
56
- ) -> str:
47
+ def start_time(self) -> str:
57
48
  """The system time when the log was created."""
58
49
  return self._start_time
59
-
60
50
 
61
51
  @property
62
- def pid(
63
- self
64
- ) -> str:
52
+ def pid(self) -> str:
65
53
  """The ID of the process writing to the log file."""
66
54
  return self._pid
67
-
68
55
 
69
56
  @property
70
- def process_type(
71
- self
72
- ) -> str:
57
+ def process_type(self) -> str:
73
58
  """Indicates the type of process, as defined by `ProcessType`."""
74
59
  return self._process_type
75
60
 
76
61
 
77
62
  class Logs:
78
63
  """Filter and read a collection of logs generated by `spectre`."""
64
+
79
65
  def __init__(
80
- self,
81
- process_type: Optional[ProcessType] = None,
82
- year: Optional[int] = None,
83
- month: Optional[int] = None,
84
- day: Optional[int] = None
66
+ self,
67
+ process_type: Optional[ProcessType] = None,
68
+ year: Optional[int] = None,
69
+ month: Optional[int] = None,
70
+ day: Optional[int] = None,
85
71
  ) -> None:
86
72
  """Initialise a `Logs` instance.
87
73
 
@@ -91,81 +77,53 @@ class Logs:
91
77
  :param day: Filter by the numeric day. Defaults to None.
92
78
  """
93
79
  self._process_type = process_type.value if process_type is not None else None
94
-
80
+
95
81
  self._log_map: dict[str, Log] = OrderedDict()
96
82
  self.set_date(year, month, day)
97
83
 
98
-
99
84
  @property
100
- def process_type(
101
- self
102
- ) -> Optional[str]:
85
+ def process_type(self) -> Optional[str]:
103
86
  """Indicates the type of process, as defined by `ProcessType`."""
104
87
  return self._process_type
105
-
106
88
 
107
89
  @property
108
- def year(
109
- self
110
- ) -> Optional[int]:
90
+ def year(self) -> Optional[int]:
111
91
  """Filter by the numeric year."""
112
92
  return self._year
113
93
 
114
-
115
- @property
116
- def month(
117
- self
118
- ) -> Optional[int]:
94
+ @property
95
+ def month(self) -> Optional[int]:
119
96
  """Filter by the numeric month."""
120
97
  return self._month
121
-
122
98
 
123
99
  @property
124
- def day(
125
- self
126
- ) -> Optional[int]:
100
+ def day(self) -> Optional[int]:
127
101
  """Filter by the numeric day."""
128
102
  return self._day
129
103
 
130
-
131
104
  @property
132
- def logs_dir_path(
133
- self
134
- ) -> str:
105
+ def logs_dir_path(self) -> str:
135
106
  """The shared ancestral path for all the log files. `Logs` recursively searches
136
107
  this directory to find all log files according to the date and process type."""
137
108
  return get_logs_dir_path(self.year, self.month, self.day)
138
-
139
109
 
140
110
  @property
141
- def log_list(
142
- self
143
- ) -> list[Log]:
111
+ def log_list(self) -> list[Log]:
144
112
  """A list of all log handlers representing files found within `logs_dir_path`."""
145
113
  return list(self._log_map.values())
146
114
 
147
-
148
115
  @property
149
- def num_logs(
150
- self
151
- ) -> int:
116
+ def num_logs(self) -> int:
152
117
  """The number of log files found within `logs_dir_path`."""
153
- return len(self.log_list)
154
-
118
+ return len(self.log_list)
155
119
 
156
120
  @property
157
- def file_names(
158
- self
159
- ) -> list[str]:
121
+ def file_names(self) -> list[str]:
160
122
  """A list of all log file names found within `logs_dir_path`."""
161
123
  return list(self._log_map.keys())
162
124
 
163
-
164
125
  def set_date(
165
- self,
166
- year: Optional[int],
167
- month: Optional[int],
168
- day: Optional[int]
126
+ self, year: Optional[int], month: Optional[int], day: Optional[int]
169
127
  ) -> None:
170
128
  """Reset `logs_dir_path` according to the numeric date, and refresh the list
171
129
  of available log files.
@@ -179,36 +137,28 @@ class Logs:
179
137
  self._day = day
180
138
  self.update()
181
139
 
182
-
183
- def update(
184
- self
185
- ) -> None:
140
+ def update(self) -> None:
186
141
  """Perform a fresh search of all files in `logs_dir_path` for log files
187
142
  according to the date and process type."""
188
143
  log_files = [f for (_, _, files) in os.walk(self.logs_dir_path) for f in files]
189
144
 
190
145
  for log_file in log_files:
191
-
146
+
192
147
  log_start_time, pid, process_type = parse_log_base_file_name(log_file)
193
148
 
194
149
  if self.process_type and process_type != self.process_type:
195
150
  continue
196
151
 
197
- self._log_map[log_file] = Log(log_start_time, pid, ProcessType(process_type))
152
+ self._log_map[log_file] = Log(
153
+ log_start_time, pid, ProcessType(process_type)
154
+ )
198
155
 
199
156
  self._log_map = OrderedDict(sorted(self._log_map.items()))
200
157
 
201
-
202
- def __iter__(
203
- self
204
- ) -> Iterator[Log]:
158
+ def __iter__(self) -> Iterator[Log]:
205
159
  yield from self.log_list
206
160
 
207
-
208
- def get_from_file_name(
209
- self,
210
- file_name: str
211
- ) -> Log:
161
+ def get_from_file_name(self, file_name: str) -> Log:
212
162
  """Retrieve a `Log` instance based on the log file name.
213
163
 
214
164
  :param file_name: The name of the log file (with or without extension).
@@ -220,13 +170,11 @@ class Logs:
220
170
  try:
221
171
  return self._log_map[file_name]
222
172
  except KeyError:
223
- raise FileNotFoundError(f"Log handler for file name '{file_name}' not found in log map")
224
-
173
+ raise FileNotFoundError(
174
+ f"Log handler for file name '{file_name}' not found in log map"
175
+ )
225
176
 
226
- def get_from_pid(
227
- self,
228
- pid: str
229
- ) -> Log:
177
+ def get_from_pid(self, pid: str) -> Log:
230
178
  """Retrieve a `Log` instance based on the process ID.
231
179
 
232
180
  :param pid: The process ID to search for.
@@ -4,11 +4,13 @@
4
4
 
5
5
  from enum import Enum
6
6
 
7
+
7
8
  class ProcessType(Enum):
8
9
  """The origin of a `spectre` process.
9
-
10
+
10
11
  :ivar USER: A process is one initiated directly by the user, or part of the main user session.
11
12
  :ivar WORKER: A process is one which is created and managed internally by `spectre`.
12
13
  """
13
- USER = "user"
14
- WORKER = "worker"
14
+
15
+ USER = "user"
16
+ WORKER = "worker"
@@ -5,9 +5,19 @@
5
5
  """An intuitive API for plotting spectrogram data."""
6
6
 
7
7
  from ._format import PanelFormat
8
- from ._panels import SpectrogramPanel, FrequencyCutsPanel, TimeCutsPanel, IntegralOverFrequencyPanel
8
+ from ._panels import (
9
+ SpectrogramPanel,
10
+ FrequencyCutsPanel,
11
+ TimeCutsPanel,
12
+ IntegralOverFrequencyPanel,
13
+ )
9
14
  from ._panel_stack import PanelStack
10
15
 
11
16
  __all__ = [
12
- "PanelFormat", "PanelStack", "SpectrogramPanel", "FrequencyCutsPanel", "TimeCutsPanel", "IntegralOverFrequencyPanel"
13
- ]
17
+ "PanelFormat",
18
+ "PanelStack",
19
+ "SpectrogramPanel",
20
+ "FrequencyCutsPanel",
21
+ "TimeCutsPanel",
22
+ "IntegralOverFrequencyPanel",
23
+ ]
@@ -21,13 +21,14 @@ from ._panel_names import PanelName
21
21
 
22
22
  class XAxisType(Enum):
23
23
  """The x-axis type for a panel.
24
-
24
+
25
25
  Axes are shared in a stack between panels with common `XAxisType`.
26
-
26
+
27
27
  :ivar TIME: The xaxis has units of time.
28
28
  :ivar FREQUENCY: The xaxis has units of frequency.
29
29
  """
30
- TIME = "time"
30
+
31
+ TIME = "time"
31
32
  FREQUENCY = "frequency"
32
33
 
33
34
 
@@ -38,11 +39,8 @@ class BasePanel(ABC):
38
39
  panels contribute to a composite plot. Subclasses must implement methods to define
39
40
  how the panel is drawn and annotated, and specify its x-axis type.
40
41
  """
41
- def __init__(
42
- self,
43
- name: PanelName,
44
- spectrogram: Spectrogram
45
- ) -> None:
42
+
43
+ def __init__(self, name: PanelName, spectrogram: Spectrogram) -> None:
46
44
  """Initialize an instance of `BasePanel`.
47
45
 
48
46
  :param name: The name of the panel.
@@ -53,61 +51,40 @@ class BasePanel(ABC):
53
51
 
54
52
  # internal attributes set by `PanelStack` during stacking.
55
53
  self._panel_format: Optional[PanelFormat] = None
56
- self._time_type : Optional[TimeType] = None
57
- self._ax : Optional[Axes] = None
58
- self._fig : Optional[Figure] = None
59
- self._identifier : Optional[str] = None
60
-
54
+ self._time_type: Optional[TimeType] = None
55
+ self._ax: Optional[Axes] = None
56
+ self._fig: Optional[Figure] = None
57
+ self._identifier: Optional[str] = None
61
58
 
62
59
  @abstractmethod
63
- def draw(
64
- self
65
- ) -> None:
60
+ def draw(self) -> None:
66
61
  """Modify the `ax` attribute to draw the panel contents."""
67
62
 
68
-
69
63
  @abstractmethod
70
- def annotate_xaxis(
71
- self
72
- ) -> None:
64
+ def annotate_xaxis(self) -> None:
73
65
  """Modify the `ax` attribute to annotate the x-axis of the panel."""
74
66
 
75
-
76
67
  @abstractmethod
77
- def annotate_yaxis(
78
- self
79
- ) -> None:
68
+ def annotate_yaxis(self) -> None:
80
69
  """Modify the `ax` attribute to annotate the y-axis of the panel."""
81
70
 
82
-
83
71
  @property
84
72
  @abstractmethod
85
- def xaxis_type(
86
- self
87
- ) -> XAxisType:
88
- """Specify the x-axis type for the panel."""
89
-
73
+ def xaxis_type(self) -> XAxisType:
74
+ """Specify the x-axis type for the panel."""
90
75
 
91
76
  @property
92
- def spectrogram(
93
- self
94
- ) -> Spectrogram:
77
+ def spectrogram(self) -> Spectrogram:
95
78
  """The spectrogram being visualised on this panel."""
96
79
  return self._spectrogram
97
-
98
80
 
99
81
  @property
100
- def tag(
101
- self
102
- ) -> str:
82
+ def tag(self) -> str:
103
83
  """The tag of the spectrogram being visualised."""
104
84
  return self._spectrogram.tag
105
-
106
85
 
107
86
  @property
108
- def time_type(
109
- self
110
- ) -> TimeType:
87
+ def time_type(self) -> TimeType:
111
88
  """The time type of the spectrogram.
112
89
 
113
90
  :raises ValueError: If the `time_type` has not been set.
@@ -115,13 +92,9 @@ class BasePanel(ABC):
115
92
  if self._time_type is None:
116
93
  raise ValueError(f"`time_type` for the panel '{self.name}' must be set.")
117
94
  return self._time_type
118
-
119
95
 
120
96
  @time_type.setter
121
- def time_type(
122
- self,
123
- value: TimeType
124
- ) -> None:
97
+ def time_type(self, value: TimeType) -> None:
125
98
  """Set the `TimeType` for the spectrogram.
126
99
 
127
100
  This controls how time is represented and annotated on the panel.
@@ -129,20 +102,14 @@ class BasePanel(ABC):
129
102
  :param value: The `TimeType` to assign to the spectrogram.
130
103
  """
131
104
  self._time_type = value
132
-
133
105
 
134
106
  @property
135
- def name(
136
- self
137
- ) -> PanelName:
107
+ def name(self) -> PanelName:
138
108
  """The name of the panel."""
139
109
  return self._name
140
-
141
-
110
+
142
111
  @property
143
- def panel_format(
144
- self
145
- ) -> PanelFormat:
112
+ def panel_format(self) -> PanelFormat:
146
113
  """Retrieve the panel format, which controls the style of the panel.
147
114
 
148
115
  :raises ValueError: If the `panel_format` has not been set.
@@ -151,23 +118,16 @@ class BasePanel(ABC):
151
118
  raise ValueError(f"`panel_format` for the panel '{self.name}' must be set.")
152
119
  return self._panel_format
153
120
 
154
-
155
121
  @panel_format.setter
156
- def panel_format(
157
- self,
158
- value: PanelFormat
159
- ) -> None:
122
+ def panel_format(self, value: PanelFormat) -> None:
160
123
  """Set the panel format to control the style of the panel.
161
-
124
+
162
125
  :param value: The `PanelFormat` to assign to the panel.
163
126
  """
164
127
  self._panel_format = value
165
128
 
166
-
167
129
  @property
168
- def ax(
169
- self
170
- ) -> Axes:
130
+ def ax(self) -> Axes:
171
131
  """The `Axes` object bound to this panel.
172
132
 
173
133
  :raises AttributeError: If the `Axes` object has not been set.
@@ -175,13 +135,9 @@ class BasePanel(ABC):
175
135
  if self._ax is None:
176
136
  raise AttributeError(f"`ax` must be set for the panel `{self.name}`")
177
137
  return self._ax
178
-
179
138
 
180
139
  @ax.setter
181
- def ax(
182
- self,
183
- value: Axes
184
- ) -> None:
140
+ def ax(self, value: Axes) -> None:
185
141
  """Assign a Matplotlib `Axes` object to this panel.
186
142
 
187
143
  This `Axes` will be used for drawing and annotations.
@@ -190,11 +146,8 @@ class BasePanel(ABC):
190
146
  """
191
147
  self._ax = value
192
148
 
193
-
194
149
  @property
195
- def fig(
196
- self
197
- ) -> Figure:
150
+ def fig(self) -> Figure:
198
151
  """
199
152
  The `Figure` object bound to this panel.
200
153
 
@@ -203,13 +156,9 @@ class BasePanel(ABC):
203
156
  if self._fig is None:
204
157
  raise AttributeError(f"`fig` must be set for the panel `{self.name}`")
205
158
  return self._fig
206
-
207
159
 
208
160
  @fig.setter
209
- def fig(
210
- self,
211
- value: Figure
212
- ) -> None:
161
+ def fig(self, value: Figure) -> None:
213
162
  """
214
163
  Assign a Matplotlib `Figure` object to this panel.
215
164
 
@@ -218,104 +167,81 @@ class BasePanel(ABC):
218
167
  :param value: The Matplotlib `Figure` to assign to the panel.
219
168
  """
220
169
  self._fig = value
221
-
222
-
170
+
223
171
  @property
224
- def identifier(
225
- self
226
- ) -> Optional[str]:
172
+ def identifier(self) -> Optional[str]:
227
173
  """Optional identifier for the panel.
228
174
 
229
- This identifier can be used to distinguish panels or aid in superimposing
175
+ This identifier can be used to distinguish panels or aid in superimposing
230
176
  panels in a stack.
231
177
  """
232
178
  return self._identifier
233
-
234
-
179
+
235
180
  @identifier.setter
236
- def identifier(
237
- self,
238
- value: str
239
- ) -> None:
181
+ def identifier(self, value: str) -> None:
240
182
  """Set the optional identifier for the panel.
241
-
183
+
242
184
  This can be used to distinguish panels or aid in superimposing panels.
243
185
  """
244
186
  self._identifier = value
245
-
246
187
 
247
- def hide_xaxis_labels(
248
- self
249
- ) -> None:
188
+ def hide_xaxis_labels(self) -> None:
250
189
  """Hide the x-axis labels for this panel."""
251
- self.ax.tick_params(axis='x', labelbottom=False)
252
-
190
+ self.ax.tick_params(axis="x", labelbottom=False)
253
191
 
254
- def hide_yaxis_labels(
255
- self
256
- ) -> None:
192
+ def hide_yaxis_labels(self) -> None:
257
193
  """Hide the y-axis labels for this panel."""
258
- self.ax.tick_params(axis='y', labelbottom=False)
259
-
194
+ self.ax.tick_params(axis="y", labelbottom=False)
195
+
260
196
 
261
197
  class BaseTimeSeriesPanel(BasePanel):
262
198
  """
263
199
  Abstract subclass of `BasePanel` designed for visualising time series data.
264
200
 
265
201
  Subclasses must implement any remaining abstract methods from `BasePanel`.
266
- """
202
+ """
203
+
267
204
  @property
268
- def xaxis_type(
269
- self
270
- ) -> Literal[XAxisType.TIME]:
205
+ def xaxis_type(self) -> Literal[XAxisType.TIME]:
271
206
  return XAxisType.TIME
272
-
273
-
207
+
274
208
  @property
275
- def times(
276
- self
277
- ) -> npt.NDArray[np.float32 | np.datetime64]:
209
+ def times(self) -> npt.NDArray[np.float32 | np.datetime64]:
278
210
  """The times assigned to each spectrum according to the `TimeType`."""
279
- return self.spectrogram.times if self.time_type == TimeType.RELATIVE else self.spectrogram.datetimes
280
-
211
+ return (
212
+ self.spectrogram.times
213
+ if self.time_type == TimeType.RELATIVE
214
+ else self.spectrogram.datetimes
215
+ )
281
216
 
282
- def annotate_xaxis(
283
- self
284
- ) -> None:
217
+ def annotate_xaxis(self) -> None:
285
218
  """Annotate the x-axis according to the specified `TimeType`."""
286
219
  if self.time_type == TimeType.RELATIVE:
287
- self.ax.set_xlabel('Time [s]')
220
+ self.ax.set_xlabel("Time [s]")
288
221
  else:
289
- #TODO: Adapt for time ranges greater than one day
290
- start_date = datetime.strftime(self.spectrogram.start_datetime.astype(datetime),
291
- TimeFormat.DATE)
292
- self.ax.set_xlabel(f'Time [UTC] (Start Date: {start_date})')
222
+ # TODO: Adapt for time ranges greater than one day
223
+ start_date = datetime.strftime(
224
+ self.spectrogram.start_datetime.astype(datetime), TimeFormat.DATE
225
+ )
226
+ self.ax.set_xlabel(f"Time [UTC] (Start Date: {start_date})")
293
227
  self.ax.xaxis.set_major_formatter(mdates.DateFormatter(TimeFormat.TIME))
294
228
 
295
229
 
296
-
297
230
  class BaseSpectrumPanel(BasePanel):
298
231
  """An abstract subclass of `BasePanel` tailored for visualising spectrum data.
299
-
232
+
300
233
  Subclasses must implement any remaining abstract methods as described by `BasePanel`.
301
- """
234
+ """
235
+
302
236
  @property
303
- def xaxis_type(
304
- self
305
- ) -> Literal[XAxisType.FREQUENCY]:
237
+ def xaxis_type(self) -> Literal[XAxisType.FREQUENCY]:
306
238
  return XAxisType.FREQUENCY
307
-
308
-
239
+
309
240
  @property
310
- def frequencies(
311
- self
312
- ) -> npt.NDArray[np.float32]:
241
+ def frequencies(self) -> npt.NDArray[np.float32]:
313
242
  """The physical frequencies assigned to each spectral component."""
314
243
  return self._spectrogram.frequencies
315
244
 
316
-
317
- def annotate_xaxis(
318
- self
319
- ) -> None:
245
+ def annotate_xaxis(self) -> None:
320
246
  """Annotate the x-axis assuming frequency in units of Hz."""
321
- self.ax.set_xlabel('Frequency [Hz]')
247
+ self.ax.set_xlabel("Frequency [Hz]")
@@ -4,9 +4,10 @@
4
4
 
5
5
  from dataclasses import dataclass
6
6
 
7
+
7
8
  @dataclass
8
9
  class PanelFormat:
9
- """Specifies formatting options for a panel, including font sizes, line styles,
10
+ """Specifies formatting options for a panel, including font sizes, line styles,
10
11
  colour maps, and general visual settings.
11
12
 
12
13
  These formatting values can be applied consistently across all panels within a `PanelStack`,
@@ -21,11 +22,12 @@ class PanelFormat:
21
22
  :ivar style: Matplotlib style applied to the panel, defaults to "dark_background".
22
23
  :ivar spectrogram_cmap: Colormap applied to spectrogram plots, defaults to "gnuplot2".
23
24
  """
24
- small_size : int = 18
25
- medium_size : int = 21
26
- large_size : int = 24
27
- line_width : int = 3
28
- line_color : str = "lime"
29
- line_cmap : str = "winter"
30
- style : str = "dark_background"
25
+
26
+ small_size: int = 18
27
+ medium_size: int = 21
28
+ large_size: int = 24
29
+ line_width: int = 3
30
+ line_color: str = "lime"
31
+ line_cmap: str = "winter"
32
+ style: str = "dark_background"
31
33
  spectrogram_cmap: str = "gnuplot2"
@@ -4,15 +4,17 @@
4
4
 
5
5
  from enum import Enum
6
6
 
7
+
7
8
  class PanelName(Enum):
8
9
  """Literal corresponding to a fully implemented `BasePanel` subclass.
9
-
10
+
10
11
  :ivar SPECTROGRAM: Panel for visualising the full spectrogram.
11
12
  :ivar FREQUENCY_CUTS: Panel for visualising individual spectrums in a spectrogram.
12
13
  :ivar TIME_CUTS: Panel for visualising spectrogram data as time series of spectral components.
13
14
  :ivar INTEGRAL_OVER_FREQUENCY: Panel for visualising the spectrogram integrated over frequency.
14
15
  """
15
- SPECTROGRAM = "spectrogram"
16
- FREQUENCY_CUTS = "frequency_cuts"
17
- TIME_CUTS = "time_cuts"
18
- INTEGRAL_OVER_FREQUENCY = "integral_over_frequency"
16
+
17
+ SPECTROGRAM = "spectrogram"
18
+ FREQUENCY_CUTS = "frequency_cuts"
19
+ TIME_CUTS = "time_cuts"
20
+ INTEGRAL_OVER_FREQUENCY = "integral_over_frequency"