ecallistolib 0.2.1__py3-none-any.whl → 0.2.3__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.
ecallistolib/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  """
3
3
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
4
- Version 0.2.1
4
+ Version 0.2.3
5
5
  Sahan S Liyanage (sahanslst@gmail.com)
6
6
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
7
7
  """
@@ -14,6 +14,7 @@ from .exceptions import (
14
14
  CropError,
15
15
  DownloadError,
16
16
  ECallistoError,
17
+ FrequencyOutOfRangeError,
17
18
  InvalidFilenameError,
18
19
  InvalidFITSError,
19
20
  )
@@ -50,6 +51,7 @@ __all__ = [
50
51
  "DownloadError",
51
52
  "CombineError",
52
53
  "CropError",
54
+ "FrequencyOutOfRangeError",
53
55
  ]
54
56
 
55
57
 
@@ -86,12 +88,14 @@ def __getattr__(name: str):
86
88
  "plot_dynamic_spectrum",
87
89
  "plot_raw_spectrum",
88
90
  "plot_background_subtracted",
91
+ "plot_light_curve",
89
92
  "TimeAxisConverter",
90
93
  }:
91
94
  from .plotting import (
92
95
  TimeAxisConverter,
93
96
  plot_background_subtracted,
94
97
  plot_dynamic_spectrum,
98
+ plot_light_curve,
95
99
  plot_raw_spectrum,
96
100
  )
97
101
 
@@ -99,6 +103,7 @@ def __getattr__(name: str):
99
103
  "plot_dynamic_spectrum": plot_dynamic_spectrum,
100
104
  "plot_raw_spectrum": plot_raw_spectrum,
101
105
  "plot_background_subtracted": plot_background_subtracted,
106
+ "plot_light_curve": plot_light_curve,
102
107
  "TimeAxisConverter": TimeAxisConverter,
103
108
  }[name]
104
109
 
ecallistolib/combine.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
ecallistolib/crop.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
ecallistolib/download.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
@@ -36,3 +36,8 @@ class CombineError(ECallistoError):
36
36
  class CropError(ECallistoError):
37
37
  """Raised when cropping parameters are invalid."""
38
38
  pass
39
+
40
+
41
+ class FrequencyOutOfRangeError(ECallistoError):
42
+ """Raised when the requested frequency is outside the spectrum's frequency range."""
43
+ pass
ecallistolib/io.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
ecallistolib/models.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
ecallistolib/plotting.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
@@ -155,39 +155,60 @@ def _get_filename_title(ds: DynamicSpectrum, suffix: str) -> str:
155
155
  """Generate plot title from DynamicSpectrum source filename."""
156
156
  if ds.source is not None:
157
157
  filename = ds.source.stem # Get filename without extension
158
+ # Also strip .fit if it's a double extension like .fit.gz
159
+ if filename.endswith(".fit"):
160
+ filename = filename[:-4]
158
161
  return f"{filename}_{suffix}"
159
162
  return suffix
160
163
 
161
164
 
162
- def plot_raw_spectrum(
165
+ # Conversion factor for Digits to dB (pseudo-calibration)
166
+ # dB = Digits * 2500 / 256 / 25.4 = Digits * 0.384
167
+ DIGITS_TO_DB_FACTOR = 2500.0 / 256.0 / 25.4 # ~0.384
168
+
169
+
170
+ def plot_dynamic_spectrum(
163
171
  ds: DynamicSpectrum,
172
+ process: Literal["raw", "background_subtracted", "noise_reduced"] = "raw",
173
+ clip_low: float | None = None,
174
+ clip_high: float | None = None,
164
175
  title: str | None = None,
165
- cmap: str = "viridis",
176
+ cmap: str = "inferno",
166
177
  figsize: tuple[float, float] | None = None,
167
- vmin: float | None = None,
168
- vmax: float | None = None,
169
178
  ax: Optional[plt.Axes] = None,
170
179
  show_colorbar: bool = True,
171
180
  time_format: Literal["seconds", "ut"] = "seconds",
181
+ intensity_units: Literal["digits", "dB"] = "digits",
172
182
  **imshow_kwargs,
173
183
  ) -> tuple["Figure", "Axes", "AxesImage"]:
174
184
  """
175
- Plot a raw DynamicSpectrum without any processing.
185
+ Plot a DynamicSpectrum with selectable processing mode.
186
+
187
+ This is the main plotting function that supports raw, background-subtracted,
188
+ and noise-reduced visualization modes with full matplotlib customization.
176
189
 
177
190
  Parameters
178
191
  ----------
179
192
  ds : DynamicSpectrum
180
193
  The dynamic spectrum to plot.
181
- title : str
182
- Plot title.
194
+ process : {"raw", "background_subtracted", "noise_reduced"}
195
+ Processing mode to apply before plotting:
196
+ - "raw": Plot the original data without any processing.
197
+ - "background_subtracted": Subtract mean over time for each frequency.
198
+ - "noise_reduced": Apply background subtraction and clipping (requires
199
+ clip_low and clip_high).
200
+ clip_low : float | None
201
+ Lower clipping threshold. Required when process="noise_reduced".
202
+ Also used for colormap normalization in all modes if provided.
203
+ clip_high : float | None
204
+ Upper clipping threshold. Required when process="noise_reduced".
205
+ Also used for colormap normalization in all modes if provided.
206
+ title : str | None
207
+ Plot title. If None, auto-generates from filename and process mode.
183
208
  cmap : str
184
- Matplotlib colormap name.
209
+ Matplotlib colormap name (e.g., "inferno", "viridis", "jet").
185
210
  figsize : tuple[float, float] | None
186
211
  Figure size as (width, height) in inches. Ignored if ax is provided.
187
- vmin : float | None
188
- Minimum value for colormap normalization.
189
- vmax : float | None
190
- Maximum value for colormap normalization.
191
212
  ax : plt.Axes | None
192
213
  Existing axes to plot on. If None, creates a new figure.
193
214
  show_colorbar : bool
@@ -195,19 +216,60 @@ def plot_raw_spectrum(
195
216
  time_format : {"seconds", "ut"}
196
217
  Format for the time axis. "seconds" shows elapsed seconds,
197
218
  "ut" shows Universal Time (requires ut_start_sec in metadata).
219
+ intensity_units : {"digits", "dB"}
220
+ Units for the intensity axis. "digits" shows raw ADU values,
221
+ "dB" converts using dB = Digits * 0.384 (pseudo-calibration).
198
222
  **imshow_kwargs
199
223
  Additional keyword arguments passed to matplotlib's imshow().
224
+ Common options include:
225
+ - interpolation: str ("nearest", "bilinear", "bicubic", etc.)
226
+ - origin: str ("upper", "lower")
227
+ - alpha: float (transparency)
200
228
 
201
229
  Returns
202
230
  -------
203
231
  tuple[Figure, Axes, AxesImage]
204
232
  The figure, axes, and image objects.
205
233
 
234
+ Raises
235
+ ------
236
+ ValueError
237
+ If process="noise_reduced" but clip_low or clip_high is not provided.
238
+
206
239
  Example
207
240
  -------
208
241
  >>> ds = read_fits("spectrum.fit.gz")
209
- >>> fig, ax, im = plot_raw_spectrum(ds, figsize=(12, 6), cmap="plasma")
242
+ >>> # Plot raw spectrum
243
+ >>> fig, ax, im = plot_dynamic_spectrum(ds, process="raw")
244
+ >>> # Plot noise-reduced spectrum
245
+ >>> fig, ax, im = plot_dynamic_spectrum(
246
+ ... ds, process="noise_reduced",
247
+ ... clip_low=-5, clip_high=20,
248
+ ... cmap="jet"
249
+ ... )
210
250
  """
251
+ from .processing import background_subtract, noise_reduce_mean_clip
252
+
253
+ # Validate parameters for noise_reduced mode
254
+ if process == "noise_reduced":
255
+ if clip_low is None or clip_high is None:
256
+ raise ValueError(
257
+ "When process='noise_reduced', both clip_low and clip_high must be provided."
258
+ )
259
+
260
+ # Apply processing
261
+ if process == "background_subtracted":
262
+ ds_plot = background_subtract(ds)
263
+ title_suffix = "background_subtracted"
264
+ elif process == "noise_reduced":
265
+ ds_plot = noise_reduce_mean_clip(
266
+ ds, clip_low=clip_low, clip_high=clip_high, scale=None
267
+ )
268
+ title_suffix = "noise_clipped"
269
+ else: # raw
270
+ ds_plot = ds
271
+ title_suffix = "raw"
272
+
211
273
  if ax is None:
212
274
  fig, ax = plt.subplots(figsize=figsize)
213
275
  else:
@@ -215,8 +277,18 @@ def plot_raw_spectrum(
215
277
 
216
278
  extent, converter = _compute_extent(ds, time_format)
217
279
 
280
+ # Convert to dB if requested
281
+ plot_data = ds_plot.data
282
+ vmin, vmax = clip_low, clip_high
283
+ if intensity_units == "dB":
284
+ plot_data = plot_data * DIGITS_TO_DB_FACTOR
285
+ if vmin is not None:
286
+ vmin = vmin * DIGITS_TO_DB_FACTOR
287
+ if vmax is not None:
288
+ vmax = vmax * DIGITS_TO_DB_FACTOR
289
+
218
290
  im = ax.imshow(
219
- ds.data,
291
+ plot_data,
220
292
  aspect="auto",
221
293
  extent=extent,
222
294
  cmap=cmap,
@@ -226,65 +298,64 @@ def plot_raw_spectrum(
226
298
  )
227
299
  # Use filename-based title if not provided
228
300
  if title is None:
229
- title = _get_filename_title(ds, "raw")
301
+ title = _get_filename_title(ds, title_suffix)
230
302
  ax.set_title(title)
231
303
  _format_time_axis(ax, converter, time_format)
232
304
  ax.set_ylabel("Frequency [MHz]")
233
305
 
234
306
  if show_colorbar:
235
307
  cbar = fig.colorbar(im, ax=ax)
236
- cbar.set_label("Intensity [DN]")
308
+ if intensity_units == "dB":
309
+ cbar.set_label("Intensity [dB]")
310
+ else:
311
+ cbar.set_label("Intensity [Digits]")
237
312
 
238
313
  return fig, ax, im
239
314
 
240
315
 
241
- def plot_dynamic_spectrum(
316
+ def plot_raw_spectrum(
242
317
  ds: DynamicSpectrum,
243
318
  title: str | None = None,
244
- cmap: str = "inferno",
319
+ cmap: str = "viridis",
245
320
  figsize: tuple[float, float] | None = None,
246
- vmin: float | None = None,
247
- vmax: float | None = None,
321
+ clip_low: float | None = None,
322
+ clip_high: float | None = None,
248
323
  ax: Optional[plt.Axes] = None,
249
324
  show_colorbar: bool = True,
250
325
  time_format: Literal["seconds", "ut"] = "seconds",
326
+ intensity_units: Literal["digits", "dB"] = "digits",
251
327
  **imshow_kwargs,
252
328
  ) -> tuple["Figure", "Axes", "AxesImage"]:
253
329
  """
254
- Plot a DynamicSpectrum using matplotlib with full customization.
330
+ Plot a raw DynamicSpectrum without any processing.
255
331
 
256
- This is the main plotting function with support for all matplotlib
257
- imshow parameters including colormap clipping (vmin/vmax), figure size,
258
- and custom time axis formats.
332
+ This is a convenience function that calls plot_dynamic_spectrum with
333
+ process="raw" and a default colormap suitable for raw data.
259
334
 
260
335
  Parameters
261
336
  ----------
262
337
  ds : DynamicSpectrum
263
338
  The dynamic spectrum to plot.
264
- title : str
339
+ title : str | None
265
340
  Plot title.
266
341
  cmap : str
267
- Matplotlib colormap name (e.g., "inferno", "viridis", "magma", "plasma").
342
+ Matplotlib colormap name. Default is "viridis".
268
343
  figsize : tuple[float, float] | None
269
- Figure size as (width, height) in inches. Ignored if ax is provided.
270
- vmin : float | None
271
- Minimum value for colormap normalization (clipping lower bound).
272
- vmax : float | None
273
- Maximum value for colormap normalization (clipping upper bound).
344
+ Figure size as (width, height) in inches.
345
+ clip_low : float | None
346
+ Minimum value for colormap normalization.
347
+ clip_high : float | None
348
+ Maximum value for colormap normalization.
274
349
  ax : plt.Axes | None
275
350
  Existing axes to plot on. If None, creates a new figure.
276
351
  show_colorbar : bool
277
352
  Whether to show a colorbar.
278
353
  time_format : {"seconds", "ut"}
279
- Format for the time axis. "seconds" shows elapsed seconds,
280
- "ut" shows Universal Time (requires ut_start_sec in metadata).
354
+ Format for the time axis.
355
+ intensity_units : {"digits", "dB"}
356
+ Units for the intensity axis.
281
357
  **imshow_kwargs
282
358
  Additional keyword arguments passed to matplotlib's imshow().
283
- Common options include:
284
- - interpolation: str ("nearest", "bilinear", "bicubic", etc.)
285
- - origin: str ("upper", "lower")
286
- - alpha: float (transparency)
287
- - norm: matplotlib.colors.Normalize (custom normalization)
288
359
 
289
360
  Returns
290
361
  -------
@@ -294,43 +365,22 @@ def plot_dynamic_spectrum(
294
365
  Example
295
366
  -------
296
367
  >>> ds = read_fits("spectrum.fit.gz")
297
- >>> ds_reduced = noise_reduce_mean_clip(ds)
298
- >>> fig, ax, im = plot_dynamic_spectrum(
299
- ... ds_reduced,
300
- ... title="Noise Reduced",
301
- ... vmin=-5, vmax=20,
302
- ... figsize=(12, 6),
303
- ... cmap="magma"
304
- ... )
368
+ >>> fig, ax, im = plot_raw_spectrum(ds, figsize=(12, 6), cmap="plasma")
305
369
  """
306
- if ax is None:
307
- fig, ax = plt.subplots(figsize=figsize)
308
- else:
309
- fig = ax.figure
310
-
311
- extent, converter = _compute_extent(ds, time_format)
312
-
313
- im = ax.imshow(
314
- ds.data,
315
- aspect="auto",
316
- extent=extent,
370
+ return plot_dynamic_spectrum(
371
+ ds,
372
+ process="raw",
373
+ clip_low=clip_low,
374
+ clip_high=clip_high,
375
+ title=title,
317
376
  cmap=cmap,
318
- vmin=vmin,
319
- vmax=vmax,
377
+ figsize=figsize,
378
+ ax=ax,
379
+ show_colorbar=show_colorbar,
380
+ time_format=time_format,
381
+ intensity_units=intensity_units,
320
382
  **imshow_kwargs,
321
383
  )
322
- # Use filename-based title if not provided
323
- if title is None:
324
- title = _get_filename_title(ds, "dynamic_spectrum")
325
- ax.set_title(title)
326
- _format_time_axis(ax, converter, time_format)
327
- ax.set_ylabel("Frequency [MHz]")
328
-
329
- if show_colorbar:
330
- cbar = fig.colorbar(im, ax=ax)
331
- cbar.set_label("Intensity [DN]")
332
-
333
- return fig, ax, im
334
384
 
335
385
 
336
386
  def plot_background_subtracted(
@@ -338,34 +388,34 @@ def plot_background_subtracted(
338
388
  title: str | None = None,
339
389
  cmap: str = "jet",
340
390
  figsize: tuple[float, float] | None = None,
341
- vmin: float | None = None,
342
- vmax: float | None = None,
391
+ clip_low: float | None = None,
392
+ clip_high: float | None = None,
343
393
  ax: Optional[plt.Axes] = None,
344
394
  show_colorbar: bool = True,
345
395
  time_format: Literal["seconds", "ut"] = "seconds",
396
+ intensity_units: Literal["digits", "dB"] = "digits",
346
397
  **imshow_kwargs,
347
398
  ) -> tuple["Figure", "Axes", "AxesImage"]:
348
399
  """
349
400
  Plot a DynamicSpectrum after background subtraction (before clipping).
350
401
 
351
- This is a convenience function that applies background subtraction
352
- (mean removal per frequency channel) and plots the result. This shows
353
- the intermediate step before clipping is applied in noise reduction.
402
+ This is a convenience function that calls plot_dynamic_spectrum with
403
+ process="background_subtracted".
354
404
 
355
405
  Parameters
356
406
  ----------
357
407
  ds : DynamicSpectrum
358
408
  The raw dynamic spectrum (will be background-subtracted internally).
359
- title : str
409
+ title : str | None
360
410
  Plot title.
361
411
  cmap : str
362
- Matplotlib colormap name. Default is "RdBu_r" (diverging colormap)
363
- which works well for showing positive/negative deviations.
412
+ Matplotlib colormap name. Default is "jet" which works well for
413
+ showing positive/negative deviations.
364
414
  figsize : tuple[float, float] | None
365
415
  Figure size as (width, height) in inches.
366
- vmin : float | None
416
+ clip_low : float | None
367
417
  Minimum value for colormap normalization.
368
- vmax : float | None
418
+ clip_high : float | None
369
419
  Maximum value for colormap normalization.
370
420
  ax : plt.Axes | None
371
421
  Existing axes to plot on. If None, creates a new figure.
@@ -373,6 +423,8 @@ def plot_background_subtracted(
373
423
  Whether to show a colorbar.
374
424
  time_format : {"seconds", "ut"}
375
425
  Format for the time axis.
426
+ intensity_units : {"digits", "dB"}
427
+ Units for the intensity axis.
376
428
  **imshow_kwargs
377
429
  Additional keyword arguments passed to matplotlib's imshow().
378
430
 
@@ -384,23 +436,183 @@ def plot_background_subtracted(
384
436
  Example
385
437
  -------
386
438
  >>> ds = read_fits("spectrum.fit.gz")
387
- >>> fig, ax, im = plot_background_subtracted(ds, vmin=-10, vmax=30)
439
+ >>> fig, ax, im = plot_background_subtracted(ds, clip_low=-10, clip_high=30)
388
440
  """
389
- from .processing import background_subtract
390
-
391
- ds_bg = background_subtract(ds)
392
- # Use filename-based title if not provided
393
- if title is None:
394
- title = _get_filename_title(ds, "background_subtracted")
395
441
  return plot_dynamic_spectrum(
396
- ds_bg,
442
+ ds,
443
+ process="background_subtracted",
444
+ clip_low=clip_low,
445
+ clip_high=clip_high,
397
446
  title=title,
398
447
  cmap=cmap,
399
448
  figsize=figsize,
400
- vmin=vmin,
401
- vmax=vmax,
402
449
  ax=ax,
403
450
  show_colorbar=show_colorbar,
404
451
  time_format=time_format,
452
+ intensity_units=intensity_units,
405
453
  **imshow_kwargs,
406
454
  )
455
+
456
+
457
+ def plot_light_curve(
458
+ ds: DynamicSpectrum,
459
+ frequency_mhz: float,
460
+ process: Literal["raw", "background_subtracted", "noise_reduced"] = "raw",
461
+ title: str | None = None,
462
+ figsize: tuple[float, float] | None = None,
463
+ ax: Optional[plt.Axes] = None,
464
+ time_format: Literal["seconds", "ut"] = "seconds",
465
+ clip_low: float | None = None,
466
+ clip_high: float | None = None,
467
+ intensity_units: Literal["digits", "dB"] = "digits",
468
+ **plot_kwargs,
469
+ ) -> tuple["Figure", "Axes", "plt.Line2D"]:
470
+ """
471
+ Plot a light curve (intensity vs time) at a specific frequency.
472
+
473
+ This function extracts the intensity values at the frequency channel closest
474
+ to the specified frequency and plots them against time. The data can be
475
+ plotted raw, after background subtraction, or after full noise reduction.
476
+
477
+ Parameters
478
+ ----------
479
+ ds : DynamicSpectrum
480
+ The dynamic spectrum to extract the light curve from.
481
+ frequency_mhz : float
482
+ The target frequency in MHz. The function will use the closest
483
+ available frequency channel in the spectrum.
484
+ process : {"raw", "background_subtracted", "noise_reduced"}
485
+ Processing to apply before plotting:
486
+ - "raw": Use the original data without any processing.
487
+ - "background_subtracted": Subtract mean over time for each frequency.
488
+ - "noise_reduced": Apply full noise reduction (requires clip_low/clip_high).
489
+ title : str | None
490
+ Plot title. If None, generates title from filename and frequency.
491
+ figsize : tuple[float, float] | None
492
+ Figure size as (width, height) in inches. Ignored if ax is provided.
493
+ ax : plt.Axes | None
494
+ Existing axes to plot on. If None, creates a new figure.
495
+ time_format : {"seconds", "ut"}
496
+ Format for the time axis. "seconds" shows elapsed seconds,
497
+ "ut" shows Universal Time (requires ut_start_sec in metadata).
498
+ clip_low : float | None
499
+ Lower clipping threshold for noise reduction. Required if process="noise_reduced".
500
+ clip_high : float | None
501
+ Upper clipping threshold for noise reduction. Required if process="noise_reduced".
502
+ intensity_units : {"digits", "dB"}
503
+ Units for the intensity axis. "digits" shows raw ADU values,
504
+ "dB" converts using dB = Digits * 0.384 (pseudo-calibration).
505
+ **plot_kwargs
506
+ Additional keyword arguments passed to matplotlib's plot().
507
+
508
+ Returns
509
+ -------
510
+ tuple[Figure, Axes, Line2D]
511
+ The figure, axes, and line objects.
512
+
513
+ Raises
514
+ ------
515
+ FrequencyOutOfRangeError
516
+ If the requested frequency is outside the spectrum's frequency range.
517
+ ValueError
518
+ If process="noise_reduced" but clip_low or clip_high is not provided.
519
+
520
+ Example
521
+ -------
522
+ >>> ds = read_fits("spectrum.fit.gz")
523
+ >>> # Plot raw light curve at 60 MHz
524
+ >>> fig, ax, line = plot_light_curve(ds, frequency_mhz=60, process="raw")
525
+ >>> # Plot noise-reduced light curve with custom clipping
526
+ >>> fig, ax, line = plot_light_curve(
527
+ ... ds, frequency_mhz=60, process="noise_reduced",
528
+ ... clip_low=-5, clip_high=20
529
+ ... )
530
+ """
531
+ from .exceptions import FrequencyOutOfRangeError
532
+ from .processing import background_subtract, noise_reduce_mean_clip
533
+
534
+ # Validate frequency is within range
535
+ freq_min = float(ds.freqs_mhz.min())
536
+ freq_max = float(ds.freqs_mhz.max())
537
+
538
+ if frequency_mhz < freq_min or frequency_mhz > freq_max:
539
+ raise FrequencyOutOfRangeError(
540
+ f"Requested frequency {frequency_mhz} MHz is outside the spectrum's "
541
+ f"frequency range [{freq_min:.2f}, {freq_max:.2f}] MHz."
542
+ )
543
+
544
+ # Validate clip parameters for noise_reduced
545
+ if process == "noise_reduced":
546
+ if clip_low is None or clip_high is None:
547
+ raise ValueError(
548
+ "When process='noise_reduced', both clip_low and clip_high must be provided."
549
+ )
550
+
551
+ # Find the closest frequency channel
552
+ freq_idx = int(np.argmin(np.abs(ds.freqs_mhz - frequency_mhz)))
553
+ actual_freq = float(ds.freqs_mhz[freq_idx])
554
+
555
+ # Apply processing
556
+ if process == "background_subtracted":
557
+ ds_processed = background_subtract(ds)
558
+ elif process == "noise_reduced":
559
+ ds_processed = noise_reduce_mean_clip(
560
+ ds, clip_low=clip_low, clip_high=clip_high, scale=None
561
+ )
562
+ else: # raw
563
+ ds_processed = ds
564
+
565
+ # Extract light curve data
566
+ light_curve = ds_processed.data[freq_idx, :]
567
+
568
+ # Convert to dB if requested
569
+ if intensity_units == "dB":
570
+ light_curve = light_curve * DIGITS_TO_DB_FACTOR
571
+
572
+ # Create figure and axes
573
+ if ax is None:
574
+ fig, ax = plt.subplots(figsize=figsize)
575
+ else:
576
+ fig = ax.figure
577
+
578
+ # Prepare time axis
579
+ if time_format == "ut":
580
+ converter = TimeAxisConverter.from_dynamic_spectrum(ds)
581
+ time_values = ds.time_s + converter.ut_start_sec
582
+ ax.set_xlabel("Time [UT]")
583
+ # Format x-tick labels as UT times
584
+ from matplotlib.ticker import FuncFormatter
585
+
586
+ def fmt(x, pos):
587
+ return converter.seconds_to_ut(x - converter.ut_start_sec)
588
+
589
+ ax.xaxis.set_major_formatter(FuncFormatter(fmt))
590
+ else:
591
+ time_values = ds.time_s
592
+ ax.set_xlabel("Time [s]")
593
+
594
+ # Plot the light curve
595
+ (line,) = ax.plot(time_values, light_curve, **plot_kwargs)
596
+
597
+ # Set title
598
+ if title is None:
599
+ # Map process name to title suffix
600
+ title_suffix = "noise_clipped" if process == "noise_reduced" else process
601
+ if ds.source is not None:
602
+ filename = ds.source.stem
603
+ # Strip .fit if it's a double extension like .fit.gz
604
+ if filename.endswith(".fit"):
605
+ filename = filename[:-4]
606
+ title = f"{filename}_light_curve_{actual_freq:.1f}MHz_{title_suffix}"
607
+ else:
608
+ title = f"Light Curve @ {actual_freq:.1f} MHz ({title_suffix})"
609
+
610
+ ax.set_title(title)
611
+
612
+ if intensity_units == "dB":
613
+ ax.set_ylabel("Intensity [dB]")
614
+ else:
615
+ ax.set_ylabel("Intensity [Digits]")
616
+
617
+ return fig, ax, line
618
+
@@ -1,6 +1,6 @@
1
1
  """
2
2
  e-callistolib: Tools for e-CALLISTO FITS dynamic spectra.
3
- Version 0.2.1
3
+ Version 0.2.3
4
4
  Sahan S Liyanage (sahanslst@gmail.com)
5
5
  Astronomical and Space Science Unit, University of Colombo, Sri Lanka.
6
6
  """
@@ -14,8 +14,8 @@ from .models import DynamicSpectrum
14
14
 
15
15
  def noise_reduce_mean_clip(
16
16
  ds: DynamicSpectrum,
17
- clip_low: float = -5.0,
18
- clip_high: float = 20.0,
17
+ clip_low: float,
18
+ clip_high: float,
19
19
  scale: float | None = (2500.0 / 255.0 / 25.4),
20
20
  ) -> DynamicSpectrum:
21
21
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ecallistolib
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Tools to download, read, process, and plot e-CALLISTO FITS dynamic spectra.
5
5
  Author: Sahan S. Liyanage
6
6
  License: MIT
@@ -70,6 +70,20 @@ A Python library to **download**, **read**, **process**, and **plot** e-CALLISTO
70
70
 
71
71
  ## Installation
72
72
 
73
+
74
+ ### From PyPI (Stable)
75
+
76
+ ```bash
77
+ pip install ecallistolib
78
+ ```
79
+
80
+ ### Optional Dependencies
81
+
82
+ Install optional features as needed:
83
+
84
+ ```bash
85
+ pip install ecallistolib"[download,plot]"
86
+ ```
73
87
  ### From Source (Development)
74
88
 
75
89
  ```bash
@@ -103,11 +117,14 @@ import ecallistolib as ecl
103
117
  # Read a FITS file
104
118
  spectrum = ecl.read_fits("ALASKA_20230101_120000_01.fit.gz")
105
119
 
106
- # Apply noise reduction
107
- cleaned = ecl.noise_reduce_mean_clip(spectrum)
108
-
109
- # Plot the result
110
- fig, ax, im = ecl.plot_dynamic_spectrum(cleaned, title="Solar Radio Burst")
120
+ # Plot with different processing modes
121
+ fig, ax, im = ecl.plot_dynamic_spectrum(
122
+ spectrum,
123
+ process="noise_reduced",
124
+ clip_low=-5,
125
+ clip_high=20,
126
+ title="Solar Radio Burst"
127
+ )
111
128
  ```
112
129
 
113
130
  ---
@@ -186,14 +203,11 @@ import ecallistolib as ecl
186
203
 
187
204
  spectrum = ecl.read_fits("my_spectrum.fit.gz")
188
205
 
189
- # Apply noise reduction with default parameters
190
- cleaned = ecl.noise_reduce_mean_clip(spectrum)
191
-
192
- # Or customize the parameters
206
+ # Apply noise reduction with required clipping values
193
207
  cleaned = ecl.noise_reduce_mean_clip(
194
208
  spectrum,
195
- clip_low=-5.0, # Lower clipping threshold
196
- clip_high=20.0, # Upper clipping threshold
209
+ clip_low=-5.0, # Lower clipping threshold (required)
210
+ clip_high=20.0, # Upper clipping threshold (required)
197
211
  scale=2500.0 / 255.0 / 25.4 # Scaling factor (None to disable)
198
212
  )
199
213
 
@@ -240,7 +254,7 @@ spectrum = ecl.read_fits("my_spectrum.fit.gz")
240
254
  cropped = ecl.crop_frequency(spectrum, freq_min=100, freq_max=300)
241
255
 
242
256
  # Crop to specific time range (in seconds)
243
- cropped = ecf.crop_time(spectrum, time_min=10, time_max=60)
257
+ cropped = ecl.crop_time(spectrum, time_min=10, time_max=60)
244
258
 
245
259
  # Crop both axes at once
246
260
  cropped = ecl.crop(spectrum, freq_range=(100, 300), time_range=(10, 60))
@@ -319,28 +333,28 @@ if ecl.can_combine_time(files):
319
333
 
320
334
  ### Plotting
321
335
 
322
- Create dynamic spectrum visualizations with full customization:
336
+ Create dynamic spectrum visualizations with selectable processing modes:
323
337
 
324
338
  ```python
325
339
  import ecallistolib as ecl
326
340
  import matplotlib.pyplot as plt
327
341
 
328
- spectrum = ecf.read_fits("my_spectrum.fit.gz")
329
- cleaned = ecf.noise_reduce_mean_clip(spectrum)
342
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
330
343
 
331
- # Basic plot
332
- fig, ax, im = ecf.plot_dynamic_spectrum(cleaned, title="Solar Radio Observation")
344
+ # Plot raw spectrum
345
+ fig, ax, im = ecl.plot_dynamic_spectrum(spectrum, process="raw")
333
346
  plt.show()
334
347
 
335
- # Customized plot with clipping values, colormap, and figure size
336
- fig, ax, im = ecf.plot_dynamic_spectrum(
337
- cleaned,
348
+ # Plot noise-reduced spectrum with required clipping values
349
+ fig, ax, im = ecl.plot_dynamic_spectrum(
350
+ spectrum,
351
+ process="noise_reduced", # Apply noise reduction
352
+ clip_low=-5, # Lower clipping bound (required)
353
+ clip_high=20, # Upper clipping bound (required)
338
354
  title="Type III Solar Burst",
339
- cmap="magma", # Matplotlib colormap
340
- vmin=-5, # Colormap lower bound
341
- vmax=20, # Colormap upper bound
342
- figsize=(12, 6), # Figure size in inches
343
- interpolation="bilinear" # Any matplotlib imshow kwarg
355
+ cmap="magma",
356
+ figsize=(12, 6),
357
+ interpolation="bilinear"
344
358
  )
345
359
  plt.savefig("spectrum.png", dpi=150, bbox_inches="tight")
346
360
  ```
@@ -348,12 +362,12 @@ plt.savefig("spectrum.png", dpi=150, bbox_inches="tight")
348
362
  #### Plotting Raw Data
349
363
 
350
364
  ```python
351
- import ecallistolib as ecf
365
+ import ecallistolib as ecl
352
366
 
353
- spectrum = ecf.read_fits("my_spectrum.fit.gz")
367
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
354
368
 
355
369
  # Plot raw spectrum without any processing
356
- fig, ax, im = ecf.plot_raw_spectrum(
370
+ fig, ax, im = ecl.plot_raw_spectrum(
357
371
  spectrum,
358
372
  title="Raw Spectrum",
359
373
  cmap="viridis",
@@ -364,15 +378,15 @@ fig, ax, im = ecf.plot_raw_spectrum(
364
378
  #### Plotting Background Subtracted (Before Clipping)
365
379
 
366
380
  ```python
367
- import ecallistolib as ecf
381
+ import ecallistolib as ecl
368
382
 
369
- spectrum = ecf.read_fits("my_spectrum.fit.gz")
383
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
370
384
 
371
385
  # Plot after background subtraction but before clipping
372
- fig, ax, im = ecf.plot_background_subtracted(
386
+ fig, ax, im = ecl.plot_background_subtracted(
373
387
  spectrum,
374
- vmin=-10,
375
- vmax=30,
388
+ clip_low=-10,
389
+ clip_high=30,
376
390
  cmap="RdBu_r" # Diverging colormap for +/- values
377
391
  )
378
392
  ```
@@ -382,28 +396,46 @@ fig, ax, im = ecf.plot_background_subtracted(
382
396
  Display time in seconds or Universal Time (UT):
383
397
 
384
398
  ```python
385
- import ecallistolib as ecf
399
+ import ecallistolib as ecl
386
400
 
387
- spectrum = ecf.read_fits("my_spectrum.fit.gz")
401
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
388
402
 
389
403
  # Default: time in seconds
390
- ecf.plot_dynamic_spectrum(spectrum, time_format="seconds")
404
+ ecl.plot_dynamic_spectrum(spectrum, time_format="seconds")
391
405
 
392
406
  # Time in UT format (HH:MM:SS)
393
- ecf.plot_dynamic_spectrum(spectrum, time_format="ut")
407
+ ecl.plot_dynamic_spectrum(spectrum, time_format="ut")
408
+ ```
409
+
410
+ #### Intensity Units
411
+
412
+ Choose between raw digital values (Digits/ADU) or pseudo-calibrated dB:
413
+
414
+ ```python
415
+ import ecallistolib as ecl
416
+
417
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
418
+
419
+ # Default: intensity in Digits (raw ADU values)
420
+ ecl.plot_dynamic_spectrum(spectrum, intensity_units="digits")
421
+
422
+ # Convert to dB using: dB = Digits * 0.384 (pseudo-calibration)
423
+ ecl.plot_dynamic_spectrum(spectrum, intensity_units="dB")
394
424
  ```
395
425
 
426
+ > **Note:** The dB conversion uses the formula: dB = Digits × 2500 / 256 / 25.4 ≈ Digits × 0.384
427
+
396
428
  #### Time Axis Converter
397
429
 
398
430
  Convert between elapsed seconds and UT time programmatically:
399
431
 
400
432
  ```python
401
- import ecallistolib as ecf
433
+ import ecallistolib as ecl
402
434
 
403
- spectrum = ecf.read_fits("my_spectrum.fit.gz")
435
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
404
436
 
405
437
  # Create converter from spectrum metadata
406
- converter = ecf.TimeAxisConverter.from_dynamic_spectrum(spectrum)
438
+ converter = ecl.TimeAxisConverter.from_dynamic_spectrum(spectrum)
407
439
 
408
440
  # Convert seconds to UT
409
441
  print(converter.seconds_to_ut(100)) # "12:01:40"
@@ -418,19 +450,72 @@ print(converter.ut_to_seconds("13:00:00")) # 3600.0
418
450
 
419
451
  ```python
420
452
  import matplotlib.pyplot as plt
421
- import ecallistolib as ecf
453
+ import ecallistolib as ecl
422
454
 
423
455
  fig, axes = plt.subplots(1, 2, figsize=(14, 5))
424
456
 
425
- spectrum1 = ecf.read_fits("file1.fit.gz")
426
- spectrum2 = ecf.read_fits("file2.fit.gz")
457
+ spectrum1 = ecl.read_fits("file1.fit.gz")
458
+ spectrum2 = ecl.read_fits("file2.fit.gz")
427
459
 
428
- ecf.plot_raw_spectrum(spectrum1, ax=axes[0], title="Raw")
429
- ecf.plot_dynamic_spectrum(
430
- ecf.noise_reduce_mean_clip(spectrum2),
460
+ ecl.plot_dynamic_spectrum(spectrum1, process="raw", ax=axes[0], title="Raw")
461
+ ecl.plot_dynamic_spectrum(
462
+ spectrum2,
463
+ process="noise_reduced",
431
464
  ax=axes[1],
432
465
  title="Noise Reduced",
433
- vmin=-5, vmax=20
466
+ clip_low=-5, clip_high=20
467
+ )
468
+
469
+ plt.tight_layout()
470
+ plt.show()
471
+ ```
472
+
473
+ #### Light Curve Plotting
474
+
475
+ Plot intensity vs time at a specific frequency:
476
+
477
+ ```python
478
+ import ecallistolib as ecl
479
+ import matplotlib.pyplot as plt
480
+
481
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
482
+
483
+ # Plot raw light curve at 60 MHz
484
+ fig, ax, line = ecl.plot_light_curve(spectrum, frequency_mhz=60, process="raw")
485
+ plt.show()
486
+
487
+ # Plot background-subtracted light curve
488
+ fig, ax, line = ecl.plot_light_curve(
489
+ spectrum, frequency_mhz=60, process="background_subtracted"
490
+ )
491
+ plt.show()
492
+
493
+ # Plot noise-reduced light curve (must provide clip values)
494
+ fig, ax, line = ecl.plot_light_curve(
495
+ spectrum,
496
+ frequency_mhz=60,
497
+ process="noise_reduced",
498
+ clip_low=-5,
499
+ clip_high=20
500
+ )
501
+ plt.show()
502
+ ```
503
+
504
+ Compare all three processing modes:
505
+
506
+ ```python
507
+ import ecallistolib as ecl
508
+ import matplotlib.pyplot as plt
509
+
510
+ spectrum = ecl.read_fits("my_spectrum.fit.gz")
511
+
512
+ fig, axes = plt.subplots(3, 1, figsize=(12, 10))
513
+
514
+ ecl.plot_light_curve(spectrum, 60, process="raw", ax=axes[0], title="Raw")
515
+ ecl.plot_light_curve(spectrum, 60, process="background_subtracted", ax=axes[1], title="BG Sub")
516
+ ecl.plot_light_curve(
517
+ spectrum, 60, process="noise_reduced", ax=axes[2], title="Noise Reduced",
518
+ clip_low=-5, clip_high=20
434
519
  )
435
520
 
436
521
  plt.tight_layout()
@@ -638,36 +723,65 @@ Concatenate spectra horizontally (time concatenation).
638
723
 
639
724
  ### Plotting Functions
640
725
 
641
- #### `plot_dynamic_spectrum(ds, title="...", cmap="inferno", figsize=None, vmin=None, vmax=None, ax=None, show_colorbar=True, time_format="seconds", **imshow_kwargs)`
726
+ #### `plot_dynamic_spectrum(ds, process="raw", clip_low=None, clip_high=None, title=None, cmap="inferno", figsize=None, ax=None, show_colorbar=True, time_format="seconds", intensity_units="digits", **imshow_kwargs)`
642
727
 
643
- Plot a dynamic spectrum with full customization.
728
+ Plot a dynamic spectrum with selectable processing mode.
644
729
 
645
730
  | Parameter | Type | Default | Description |
646
731
  |-----------|------|---------|-------------|
647
732
  | `ds` | `DynamicSpectrum` | — | Spectrum to plot |
648
- | `title` | `str` | `"Dynamic Spectrum"` | Plot title |
733
+ | `process` | `str` | `"raw"` | Processing mode: `"raw"`, `"background_subtracted"`, or `"noise_reduced"` |
734
+ | `clip_low` | `float \| None` | `None` | Lower clipping bound (required for `"noise_reduced"`) |
735
+ | `clip_high` | `float \| None` | `None` | Upper clipping bound (required for `"noise_reduced"`) |
736
+ | `title` | `str \| None` | `None` | Plot title (auto-generated if `None`) |
649
737
  | `cmap` | `str` | `"inferno"` | Matplotlib colormap |
650
738
  | `figsize` | `tuple \| None` | `None` | Figure size as `(width, height)` in inches |
651
- | `vmin` | `float \| None` | `None` | Colormap lower bound (clipping) |
652
- | `vmax` | `float \| None` | `None` | Colormap upper bound (clipping) |
653
739
  | `ax` | `Axes \| None` | `None` | Existing axes (creates new if `None`) |
654
740
  | `show_colorbar` | `bool` | `True` | Whether to display colorbar |
655
741
  | `time_format` | `str` | `"seconds"` | `"seconds"` or `"ut"` for time axis format |
742
+ | `intensity_units` | `str` | `"digits"` | `"digits"` (raw ADU) or `"dB"` (pseudo-calibrated) |
656
743
  | `**imshow_kwargs` | — | — | Additional kwargs passed to `matplotlib.imshow()` |
657
744
 
658
745
  **Returns:** Tuple of `(fig, ax, im)`.
659
746
 
747
+ **Raises:** `ValueError` if `process="noise_reduced"` without `clip_low` and `clip_high`.
748
+
660
749
  ---
661
750
 
662
- #### `plot_raw_spectrum(ds, title="Raw Spectrum", cmap="viridis", ...)`
751
+ #### `plot_raw_spectrum(ds, clip_low=None, clip_high=None, title=None, cmap="viridis", ...)`
663
752
 
664
- Plot raw spectrum data without any processing. Accepts the same parameters as `plot_dynamic_spectrum`.
753
+ Convenience function that calls `plot_dynamic_spectrum` with `process="raw"`.
665
754
 
666
755
  ---
667
756
 
668
- #### `plot_background_subtracted(ds, title="Background Subtracted", cmap="RdBu_r", ...)`
757
+ #### `plot_background_subtracted(ds, clip_low=None, clip_high=None, title=None, cmap="jet", ...)`
758
+
759
+ Convenience function that calls `plot_dynamic_spectrum` with `process="background_subtracted"`.
760
+
761
+ ---
762
+
763
+ #### `plot_light_curve(ds, frequency_mhz, process="raw", title=None, figsize=None, ax=None, time_format="seconds", clip_low=None, clip_high=None, **plot_kwargs)`
764
+
765
+ Plot a light curve (intensity vs time) at a specific frequency.
669
766
 
670
- Plot spectrum after background subtraction (before clipping). Automatically applies `background_subtract()` and plots the result. Accepts the same parameters as `plot_dynamic_spectrum`.
767
+ | Parameter | Type | Default | Description |
768
+ |-----------|------|---------|-------------|
769
+ | `ds` | `DynamicSpectrum` | — | Spectrum to extract light curve from |
770
+ | `frequency_mhz` | `float` | — | Target frequency in MHz |
771
+ | `process` | `str` | `"raw"` | Processing mode: `"raw"`, `"background_subtracted"`, or `"noise_reduced"` |
772
+ | `title` | `str \| None` | `None` | Plot title (auto-generated if `None`) |
773
+ | `figsize` | `tuple \| None` | `None` | Figure size as `(width, height)` in inches |
774
+ | `ax` | `Axes \| None` | `None` | Existing axes (creates new if `None`) |
775
+ | `time_format` | `str` | `"seconds"` | `"seconds"` or `"ut"` for time axis format |
776
+ | `clip_low` | `float \| None` | `None` | Lower clip threshold (required for `"noise_reduced"`) |
777
+ | `clip_high` | `float \| None` | `None` | Upper clip threshold (required for `"noise_reduced"`) |
778
+ | `**plot_kwargs` | — | — | Additional kwargs passed to `matplotlib.plot()` |
779
+
780
+ **Returns:** Tuple of `(fig, ax, line)`.
781
+
782
+ **Raises:**
783
+ - `FrequencyOutOfRangeError` if frequency is outside spectrum's range.
784
+ - `ValueError` if `process="noise_reduced"` without `clip_low` and `clip_high`.
671
785
 
672
786
  ---
673
787
 
@@ -701,22 +815,23 @@ The library provides a hierarchy of custom exceptions for robust error handling:
701
815
  | `DownloadError` | Raised when downloading files from the archive fails |
702
816
  | `CombineError` | Raised when spectra cannot be combined |
703
817
  | `CropError` | Raised when cropping parameters are invalid |
818
+ | `FrequencyOutOfRangeError` | Raised when the requested frequency is outside the spectrum's range |
704
819
 
705
820
  #### Error Handling Example
706
821
 
707
822
  ```python
708
- import ecallistolib as ecf
823
+ import ecallistolib as ecl
709
824
  from ecallistolib import InvalidFITSError, CropError
710
825
 
711
826
  try:
712
- spectrum = ecf.read_fits("corrupted_file.fit")
827
+ spectrum = ecl.read_fits("corrupted_file.fit")
713
828
  except FileNotFoundError:
714
829
  print("File not found")
715
830
  except InvalidFITSError as e:
716
831
  print(f"Invalid FITS file: {e}")
717
832
 
718
833
  try:
719
- cropped = ecf.crop(spectrum, freq_range=(1000, 2000)) # Out of range
834
+ cropped = ecl.crop(spectrum, freq_range=(1000, 2000)) # Out of range
720
835
  except CropError as e:
721
836
  print(f"Cropping failed: {e}")
722
837
  ```
@@ -729,24 +844,24 @@ except CropError as e:
729
844
 
730
845
  ```python
731
846
  from datetime import date
732
- import ecallistolib as ecf
847
+ import ecallistolib as ecl
733
848
  import matplotlib.pyplot as plt
734
849
 
735
850
  # 1. Download data
736
- remote = ecf.list_remote_fits(date(2023, 6, 15), hour=12, station_substring="alaska")
737
- paths = ecf.download_files(remote[:2], out_dir="./data")
851
+ remote = ecl.list_remote_fits(date(2023, 6, 15), hour=12, station_substring="alaska")
852
+ paths = ecl.download_files(remote[:2], out_dir="./data")
738
853
 
739
854
  # 2. Read and combine
740
- if ecf.can_combine_time(paths):
741
- spectrum = ecf.combine_time(paths)
855
+ if ecl.can_combine_time(paths):
856
+ spectrum = ecl.combine_time(paths)
742
857
  else:
743
- spectrum = ecf.read_fits(paths[0])
858
+ spectrum = ecl.read_fits(paths[0])
744
859
 
745
860
  # 3. Process
746
- cleaned = ecf.noise_reduce_mean_clip(spectrum)
861
+ cleaned = ecl.noise_reduce_mean_clip(spectrum)
747
862
 
748
863
  # 4. Plot
749
- fig, ax, im = ecf.plot_dynamic_spectrum(
864
+ fig, ax, im = ecl.plot_dynamic_spectrum(
750
865
  cleaned,
751
866
  title=f"e-CALLISTO Observation - {spectrum.meta.get('station', 'Unknown')}",
752
867
  cmap="plasma"
@@ -758,9 +873,9 @@ plt.show()
758
873
  ### Working with Metadata
759
874
 
760
875
  ```python
761
- import ecallistolib as ecf
876
+ import ecallistolib as ecl
762
877
 
763
- spectrum = ecf.read_fits("my_file.fit.gz")
878
+ spectrum = ecl.read_fits("my_file.fit.gz")
764
879
 
765
880
  # Access metadata
766
881
  print(f"Station: {spectrum.meta.get('station')}")
@@ -768,7 +883,7 @@ print(f"Date: {spectrum.meta.get('date')}")
768
883
  print(f"UT Start: {spectrum.meta.get('ut_start_sec')} seconds")
769
884
 
770
885
  # After processing, metadata is preserved and extended
771
- processed = ecf.noise_reduce_mean_clip(spectrum)
886
+ processed = ecl.noise_reduce_mean_clip(spectrum)
772
887
  print(f"Processing applied: {processed.meta.get('noise_reduction')}")
773
888
  ```
774
889
 
@@ -0,0 +1,14 @@
1
+ ecallistolib/__init__.py,sha256=MOEjuYi132aHYdFNN8ReRcu95eXOVWFsyRvX2zPb6Os,3003
2
+ ecallistolib/combine.py,sha256=wYDh1pzh4DMZTLD2KRQOCtRbtt2y-PC8xmQvC5xl1LA,3315
3
+ ecallistolib/crop.py,sha256=DactJZ9DtZ50zj7Cp6Ii0F6sCieVloGyzWqMY7HmJ9I,6383
4
+ ecallistolib/download.py,sha256=XbqcLqptKS16D8MP9bWZZprFviQdw1hbt9ctsW1N91s,4114
5
+ ecallistolib/exceptions.py,sha256=e993ColPiVOyOP7Dh7RY4GlRoClwFCPABLiWaS5cLuk,1027
6
+ ecallistolib/io.py,sha256=_uSw6L6Bm1t5GjpVMGtdoF_5NmgEVVDzCXW2nRVFbV8,3686
7
+ ecallistolib/models.py,sha256=Mv8fRWKsbNlMQi20_6oxUz9UX6wkckZAcS9Tj0kH-b4,1299
8
+ ecallistolib/plotting.py,sha256=rEItUrxAXfMj76_MPmoycgfxcbsuWztc3cduWKppkSU,20616
9
+ ecallistolib/processing.py,sha256=enwu8KSome09u4Iv5zjhY80t1HbnGFz3xXf2Wr3Lp7k,1962
10
+ ecallistolib-0.2.3.dist-info/licenses/LICENSE,sha256=WunjkzsBGyy9vIQxfNe_GDV1yKBQJ-0WbFt4AXZ5Rvc,1073
11
+ ecallistolib-0.2.3.dist-info/METADATA,sha256=vqzLuqmPGXxIKwF2HABGorRI6YusKD15p_XAQ3kQEmg,26290
12
+ ecallistolib-0.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ ecallistolib-0.2.3.dist-info/top_level.txt,sha256=DmLjR5jlE2i2mQXou5gyCpaHOOlNs4DIQyCPoGXhsbc,13
14
+ ecallistolib-0.2.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,14 +0,0 @@
1
- ecallistolib/__init__.py,sha256=9O277WBX99gg3MqWcv-tiaQxB6IKeMfHM91uDJP_9O0,2833
2
- ecallistolib/combine.py,sha256=79LuR2HngpTbaM2xBg7aqUGK_1xkK3RomKmomWG2FpE,3315
3
- ecallistolib/crop.py,sha256=zcAsd5XP-_lG9exBPUFYt4PJslzxLabjSLvbdSADhDk,6383
4
- ecallistolib/download.py,sha256=gUmDLZDjyVIElzqZnGoAREkpOaxYNsAUDeujlGwd_o4,4114
5
- ecallistolib/exceptions.py,sha256=F0EdRCi54ut8qQDtDVZxhGn3P_JbsoQ8hNVxKCFpO5s,879
6
- ecallistolib/io.py,sha256=e-BMtWvILsqs2ua89Ysa2vwZ9s4mDukDGVPYDA3ed-E,3686
7
- ecallistolib/models.py,sha256=v8bl1fN3jKHVbQmpfVSv3ZusFrkWZJ1ciZkuufygmjE,1299
8
- ecallistolib/plotting.py,sha256=RhTJK5qGwCcBRRJP-mDNyGoWzd5diHCbx1IyXK8PraU,12296
9
- ecallistolib/processing.py,sha256=eBH3uGt3RmGM1NRdH_wJ7AAcVeadk9te-pHc9pWy2Lo,1976
10
- ecallistolib-0.2.1.dist-info/licenses/LICENSE,sha256=WunjkzsBGyy9vIQxfNe_GDV1yKBQJ-0WbFt4AXZ5Rvc,1073
11
- ecallistolib-0.2.1.dist-info/METADATA,sha256=LPysk03p7kqiyr311C2R-CKwYWnq_yVgyK4n8eLSlMM,22583
12
- ecallistolib-0.2.1.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
13
- ecallistolib-0.2.1.dist-info/top_level.txt,sha256=DmLjR5jlE2i2mQXou5gyCpaHOOlNs4DIQyCPoGXhsbc,13
14
- ecallistolib-0.2.1.dist-info/RECORD,,