ecallistolib 0.2.1__tar.gz → 0.2.3__tar.gz

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 (29) hide show
  1. {ecallistolib-0.2.1/src/ecallistolib.egg-info → ecallistolib-0.2.3}/PKG-INFO +186 -71
  2. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/README.md +185 -70
  3. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/pyproject.toml +1 -1
  4. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/__init__.py +6 -1
  5. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/combine.py +1 -1
  6. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/crop.py +1 -1
  7. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/download.py +1 -1
  8. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/exceptions.py +6 -1
  9. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/io.py +1 -1
  10. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/models.py +1 -1
  11. ecallistolib-0.2.3/src/ecallistolib/plotting.py +618 -0
  12. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib/processing.py +3 -3
  13. {ecallistolib-0.2.1 → ecallistolib-0.2.3/src/ecallistolib.egg-info}/PKG-INFO +186 -71
  14. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_crop.py +1 -1
  15. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_exceptions.py +6 -1
  16. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_imports.py +1 -1
  17. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_integration.py +3 -3
  18. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_io.py +1 -1
  19. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_models.py +1 -1
  20. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_plotting.py +150 -6
  21. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_processing.py +1 -1
  22. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/tests/test_smoke.py +1 -1
  23. ecallistolib-0.2.1/src/ecallistolib/plotting.py +0 -406
  24. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/LICENSE +0 -0
  25. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/setup.cfg +0 -0
  26. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib.egg-info/SOURCES.txt +0 -0
  27. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib.egg-info/dependency_links.txt +0 -0
  28. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib.egg-info/requires.txt +0 -0
  29. {ecallistolib-0.2.1 → ecallistolib-0.2.3}/src/ecallistolib.egg-info/top_level.txt +0 -0
@@ -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