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
@@ -15,13 +15,10 @@ from spectre_core.spectrograms import TimeType
15
15
  from spectre_core.config import TimeFormat, get_batches_dir_path
16
16
  from ._base import BasePanel, XAxisType
17
17
  from ._format import PanelFormat
18
- from ._panels import (
19
- PanelName, SpectrogramPanel, TimeCutsPanel, FrequencyCutsPanel
20
- )
18
+ from ._panels import PanelName, SpectrogramPanel, TimeCutsPanel, FrequencyCutsPanel
21
19
 
22
- def _is_cuts_panel(
23
- panel: BasePanel
24
- ) -> bool:
20
+
21
+ def _is_cuts_panel(panel: BasePanel) -> bool:
25
22
  """Check if a panel contains spectrogram cuts.
26
23
 
27
24
  :param panel: The panel to check.
@@ -30,9 +27,7 @@ def _is_cuts_panel(
30
27
  return panel.name in {PanelName.FREQUENCY_CUTS, PanelName.TIME_CUTS}
31
28
 
32
29
 
33
- def _is_spectrogram_panel(
34
- panel: BasePanel
35
- ) -> bool:
30
+ def _is_spectrogram_panel(panel: BasePanel) -> bool:
36
31
  """Check if a panel is a spectrogram panel.
37
32
 
38
33
  :param panel: The panel to check.
@@ -43,12 +38,13 @@ def _is_spectrogram_panel(
43
38
 
44
39
  class PanelStack:
45
40
  """Visualise spectrogram data in a stack of panels."""
41
+
46
42
  def __init__(
47
- self,
43
+ self,
48
44
  panel_format: PanelFormat = PanelFormat(),
49
45
  time_type: TimeType = TimeType.RELATIVE,
50
46
  figsize: Tuple[int, int] = (15, 8),
51
- non_interactive: bool = False
47
+ non_interactive: bool = False,
52
48
  ) -> None:
53
49
  """Initialize an instance of `PanelStack`.
54
50
 
@@ -59,92 +55,79 @@ class PanelStack:
59
55
  self._panel_format = panel_format
60
56
  self._time_type = time_type
61
57
  self._figsize = figsize
62
-
58
+
63
59
  if non_interactive:
64
60
  # Use a non-interactive matplotlib backend, which can only write files.
65
- use('agg')
61
+ use("agg")
66
62
 
67
- self._panels : list[BasePanel] = []
63
+ self._panels: list[BasePanel] = []
68
64
  self._superimposed_panels: list[BasePanel] = []
69
-
65
+
70
66
  self._fig: Optional[Figure] = None
71
67
  self._axs: Optional[np.ndarray] = None
72
68
 
73
-
74
69
  @property
75
- def time_type(
76
- self
77
- ) -> TimeType:
70
+ def time_type(self) -> TimeType:
78
71
  """The type of time we assign to the spectrograms"""
79
72
  return self._time_type
80
73
 
81
-
82
74
  @property
83
- def panels(
84
- self
85
- ) -> list[BasePanel]:
75
+ def panels(self) -> list[BasePanel]:
86
76
  """Get the panels in the stack, sorted by their `XAxisType`."""
87
77
  return list(sorted(self._panels, key=lambda panel: panel.xaxis_type.value))
88
78
 
89
-
90
79
  @property
91
- def fig(
92
- self
93
- ) -> Figure:
80
+ def fig(self) -> Figure:
94
81
  """Get the shared `matplotlib` figure for the panel stack.
95
82
 
96
83
  :raises ValueError: If the axes have not been initialized.
97
84
  """
98
85
  if self._fig is None:
99
- raise ValueError(f"An unexpected error has occured, `fig` must be set for the panel stack.")
86
+ raise ValueError(
87
+ f"An unexpected error has occured, `fig` must be set for the panel stack."
88
+ )
100
89
  return self._fig
101
90
 
102
-
103
91
  @property
104
- def axs(
105
- self
106
- ) -> np.ndarray:
92
+ def axs(self) -> np.ndarray:
107
93
  """Get the `matplotlib` axes in the stack.
108
94
 
109
95
  :return: An array of `matplotlib.axes.Axes`, one for each panel in the stack.
110
96
  :raises ValueError: If the axes have not been initialized.
111
97
  """
112
98
  if self._axs is None:
113
- raise ValueError(f"An unexpected error has occured, `axs` must be set for the panel stack.")
99
+ raise ValueError(
100
+ f"An unexpected error has occured, `axs` must be set for the panel stack."
101
+ )
114
102
  return np.atleast_1d(self._axs)
115
103
 
116
-
117
104
  @property
118
- def num_panels(
119
- self
120
- ) -> int:
105
+ def num_panels(self) -> int:
121
106
  """Get the number of panels in the stack."""
122
107
  return len(self._panels)
123
108
 
124
-
125
109
  def add_panel(
126
- self,
110
+ self,
127
111
  panel: BasePanel,
128
112
  identifier: Optional[str] = None,
129
- panel_format: Optional[PanelFormat] = None
113
+ panel_format: Optional[PanelFormat] = None,
130
114
  ) -> None:
131
115
  """Add a panel to the stack.
132
116
 
133
117
  :param panel: An instance of a `BasePanel` subclass to be added to the stack.
134
118
  :param identifier: An optional string to link the panel with others for superimposing.
135
119
  """
136
- panel.panel_format = panel_format or self._panel_format
137
- panel.time_type = self._time_type
138
- if identifier:
120
+ panel.panel_format = panel_format or self._panel_format
121
+ panel.time_type = self._time_type
122
+ if identifier:
139
123
  panel.identifier = identifier
140
124
  self._panels.append(panel)
141
125
 
142
-
143
126
  def superimpose_panel(
144
- self,
127
+ self,
145
128
  panel: BasePanel,
146
129
  identifier: Optional[str] = None,
147
- panel_format: Optional[PanelFormat] = None
130
+ panel_format: Optional[PanelFormat] = None,
148
131
  ) -> None:
149
132
  """Superimpose a panel onto an existing panel in the stack.
150
133
 
@@ -154,49 +137,42 @@ class PanelStack:
154
137
  if identifier:
155
138
  panel.identifier = identifier
156
139
  panel.panel_format = panel_format or self._panel_format
157
- panel.time_type = self._time_type
140
+ panel.time_type = self._time_type
158
141
  self._superimposed_panels.append(panel)
159
142
 
160
-
161
- def _init_plot_style(
162
- self
163
- ) -> None:
143
+ def _init_plot_style(self) -> None:
164
144
  """Initialize the global plot style for the stack.
165
145
 
166
146
  This method sets `matplotlib` styles and font sizes based on the `panel_format`.
167
147
  """
168
148
  plt.style.use(self._panel_format.style)
169
-
170
- plt.rc('font', size=self._panel_format.small_size)
171
-
172
- plt.rc('axes', titlesize=self._panel_format.medium_size,
173
- labelsize=self._panel_format.medium_size)
174
-
175
- plt.rc('xtick', labelsize=self._panel_format.small_size)
176
- plt.rc('ytick', labelsize=self._panel_format.small_size)
177
-
178
- plt.rc('legend', fontsize=self._panel_format.small_size)
179
- plt.rc('figure', titlesize=self._panel_format.large_size)
180
-
181
-
182
- def _create_figure_and_axes(
183
- self
184
- ) -> None:
149
+
150
+ plt.rc("font", size=self._panel_format.small_size)
151
+
152
+ plt.rc(
153
+ "axes",
154
+ titlesize=self._panel_format.medium_size,
155
+ labelsize=self._panel_format.medium_size,
156
+ )
157
+
158
+ plt.rc("xtick", labelsize=self._panel_format.small_size)
159
+ plt.rc("ytick", labelsize=self._panel_format.small_size)
160
+
161
+ plt.rc("legend", fontsize=self._panel_format.small_size)
162
+ plt.rc("figure", titlesize=self._panel_format.large_size)
163
+
164
+ def _create_figure_and_axes(self) -> None:
185
165
  """Create the `matplotlib` figure and axes for the panel stack.
186
166
 
187
167
  This initializes a figure with a specified number of vertically stacked axes.
188
168
  """
189
- self._fig, self._axs = plt.subplots(self.num_panels,
190
- 1,
191
- figsize=self._figsize,
192
- layout="constrained")
193
-
169
+ self._fig, self._axs = plt.subplots(
170
+ self.num_panels, 1, figsize=self._figsize, layout="constrained"
171
+ )
194
172
 
195
- def _assign_axes(
196
- self
197
- ) -> None:
173
+ def _assign_axes(self) -> None:
198
174
  """Assign each axes in the figure to some panel in the stack.
199
-
175
+
200
176
  Axes are shared between panels with common `xaxis_type`.
201
177
  """
202
178
  shared_axes: dict[XAxisType, Axes] = {}
@@ -204,15 +180,11 @@ class PanelStack:
204
180
  panel.ax = self.axs[i]
205
181
  panel.fig = self._fig
206
182
  if panel.xaxis_type in shared_axes:
207
- panel.ax.sharex( shared_axes[panel.xaxis_type] )
183
+ panel.ax.sharex(shared_axes[panel.xaxis_type])
208
184
  else:
209
185
  shared_axes[panel.xaxis_type] = panel.ax
210
186
 
211
-
212
- def _overlay_cuts(
213
- self,
214
- cuts_panel: BasePanel
215
- ) -> None:
187
+ def _overlay_cuts(self, cuts_panel: BasePanel) -> None:
216
188
  """Overlay cuts onto corresponding spectrogram panels.
217
189
 
218
190
  For a given cuts panel, locate any spectrogram panels in the stack with a matching tag
@@ -224,82 +196,77 @@ class PanelStack:
224
196
  if _is_spectrogram_panel(panel) and panel.tag == cuts_panel.tag:
225
197
  panel = cast(SpectrogramPanel, panel)
226
198
  if cuts_panel.name == PanelName.FREQUENCY_CUTS:
227
- panel.overlay_frequency_cuts( cast(FrequencyCutsPanel, cuts_panel) )
199
+ panel.overlay_frequency_cuts(cast(FrequencyCutsPanel, cuts_panel))
228
200
  elif cuts_panel.name == PanelName.TIME_CUTS:
229
- panel.overlay_time_cuts( cast(TimeCutsPanel, cuts_panel) )
230
-
201
+ panel.overlay_time_cuts(cast(TimeCutsPanel, cuts_panel))
231
202
 
232
- def _overlay_superimposed_panels(
233
- self
234
- ) -> None:
203
+ def _overlay_superimposed_panels(self) -> None:
235
204
  """Superimpose panels onto matching panels in the stack.
236
205
 
237
- For each superimposed panel, find a matching panel in the stack with the same name
238
- and identifier. Share the axes and figure, then draw the superimposed panel. If the
206
+ For each superimposed panel, find a matching panel in the stack with the same name
207
+ and identifier. Share the axes and figure, then draw the superimposed panel. If the
239
208
  panel contains cuts, overlay those cuts onto the corresponding spectrogram panels.
240
209
  """
241
210
  for super_panel in self._superimposed_panels:
242
211
  for panel in self._panels:
243
- if panel.name == super_panel.name and (panel.identifier == super_panel.identifier):
212
+ if panel.name == super_panel.name and (
213
+ panel.identifier == super_panel.identifier
214
+ ):
244
215
  super_panel.ax, super_panel.fig = panel.ax, self._fig
245
216
  super_panel.draw()
246
217
  if _is_cuts_panel(super_panel):
247
218
  self._overlay_cuts(super_panel)
248
219
 
249
- def _make_figure(
250
- self
251
- ) -> None:
220
+ def _make_figure(self) -> None:
252
221
  """Make the panel stack figure."""
253
222
  if self.num_panels < 1:
254
223
  raise ValueError(f"There must be at least one panel in the stack.")
255
-
224
+
256
225
  self._init_plot_style()
257
226
  self._create_figure_and_axes()
258
227
  self._assign_axes()
259
-
228
+
260
229
  last_panel_per_axis = {panel.xaxis_type: panel for panel in self.panels}
261
-
230
+
262
231
  for panel in self.panels:
263
232
  panel.draw()
264
233
  panel.annotate_yaxis()
265
-
234
+
266
235
  if panel == last_panel_per_axis[panel.xaxis_type]:
267
236
  panel.annotate_xaxis()
268
237
  else:
269
238
  panel.hide_xaxis_labels()
270
-
239
+
271
240
  if _is_cuts_panel(panel):
272
241
  self._overlay_cuts(panel)
273
-
242
+
274
243
  self._overlay_superimposed_panels()
275
244
 
276
- def show(
277
- self
278
- ) -> None:
245
+ def show(self) -> None:
279
246
  """Display the panel stack figure."""
280
247
  self._make_figure()
281
248
  plt.show()
282
-
283
-
249
+
284
250
  def save(
285
251
  self,
286
252
  ) -> str:
287
- """Save the panel stack figure as a batch file under the tag of the first
288
- panel in the stack. The file format is `png`.
289
-
253
+ """Save the panel stack figure as a batch file under the tag of the first
254
+ panel in the stack. The file format is `png`.
255
+
290
256
  :return: The file path of the newly created batch file containing the figure.
291
257
  """
292
258
  self._make_figure()
293
259
  first_panel = self._panels[0]
294
-
295
- start_dt = cast(datetime, first_panel.spectrogram.start_datetime.astype(datetime))
296
- batch_name = f"{start_dt.strftime(TimeFormat.DATETIME)}_{first_panel.spectrogram.tag}"
260
+
261
+ start_dt = cast(
262
+ datetime, first_panel.spectrogram.start_datetime.astype(datetime)
263
+ )
264
+ batch_name = (
265
+ f"{start_dt.strftime(TimeFormat.DATETIME)}_{first_panel.spectrogram.tag}"
266
+ )
297
267
  batch_file_path = os.path.join(
298
268
  get_batches_dir_path(start_dt.year, start_dt.month, start_dt.day),
299
- f"{batch_name}.png"
269
+ f"{batch_name}.png",
300
270
  )
301
271
  plt.savefig(batch_file_path)
302
272
  return batch_file_path
303
-
304
-
305
-