lime-stable 2.0.dev3__tar.gz → 2.0.dev6__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.
- {lime_stable-2.0.dev3/src/lime_stable.egg-info → lime_stable-2.0.dev6}/PKG-INFO +2 -2
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/pyproject.toml +2 -2
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/__init__.py +1 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/archives/read_fits.py +1 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/archives/tables.py +3 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/changelog.txt +6 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/fitting/lines.py +8 -6
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/fitting/redshift.py +3 -0
- lime_stable-2.0.dev6/src/lime/inference/intensity_threshold.py +137 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/io.py +18 -20
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/lime.toml +1 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/observations.py +3 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/bokeh_plots.py +22 -15
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/format.py +5 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/plots.py +101 -92
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/plots_interactive.py +53 -34
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/theme_lime.toml +3 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/tools.py +7 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/transitions.py +146 -107
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/workflow.py +283 -190
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6/src/lime_stable.egg-info}/PKG-INFO +2 -2
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime_stable.egg-info/requires.txt +1 -1
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_cube.py +2 -2
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_io.py +46 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_line.py +19 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_spectrum.py +49 -5
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_tools.py +102 -4
- lime_stable-2.0.dev3/src/lime/inference/intensity_threshold.py +0 -205
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/LICENSE.rst +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/MANIFEST.in +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/README.rst +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/setup.cfg +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/archives/__init__.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/fitting/__init__.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/inference/detection.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/__init__.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/plotting/utils.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/resources/__init__.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/resources/lines_database_formatting.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/resources/lines_database_v2.0.0.txt +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/resources/logo.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/resources/types_params.txt +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/retrieve/__init__.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime/retrieve/peaks.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime_stable.egg-info/SOURCES.txt +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime_stable.egg-info/dependency_links.txt +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/src/lime_stable.egg-info/top_level.txt +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_astro.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_model.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_read_fits.py +0 -0
- {lime_stable-2.0.dev3 → lime_stable-2.0.dev6}/tests/test_sample.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lime-stable
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.dev6
|
|
4
4
|
Summary: Line measuring algorithm for astronomical spectra
|
|
5
5
|
Author-email: Vital Fernández <vgf@umich.edu>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -19,7 +19,7 @@ Requires-Dist: aspect-stable~=0.3.1
|
|
|
19
19
|
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
|
|
20
20
|
Provides-Extra: full
|
|
21
21
|
Requires-Dist: asdf~=4.1; extra == "full"
|
|
22
|
-
Requires-Dist: bokeh~=3.
|
|
22
|
+
Requires-Dist: bokeh~=3.7; extra == "full"
|
|
23
23
|
Requires-Dist: mplcursors~=0.6; extra == "full"
|
|
24
24
|
Requires-Dist: openpyxl~=3.1; extra == "full"
|
|
25
25
|
Requires-Dist: PyLaTeX~=1.4; extra == "full"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lime-stable"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.dev6"
|
|
8
8
|
readme = "README.rst"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
license = "GPL-3.0-or-later"
|
|
@@ -25,7 +25,7 @@ classifiers = ["Programming Language :: Python :: 3",
|
|
|
25
25
|
|
|
26
26
|
[project.optional-dependencies]
|
|
27
27
|
full = ["asdf~=4.1",
|
|
28
|
-
"bokeh~=3.
|
|
28
|
+
"bokeh~=3.7",
|
|
29
29
|
"mplcursors~=0.6",
|
|
30
30
|
"openpyxl~=3.1",
|
|
31
31
|
"PyLaTeX~=1.4",
|
|
@@ -42,7 +42,7 @@ _logger.debug(f'Launching LiMe {__version__} in Python {__python_version__}')
|
|
|
42
42
|
from lime.observations import Spectrum, Sample, Cube
|
|
43
43
|
from lime.io import *
|
|
44
44
|
from lime.tools import *
|
|
45
|
-
from lime.transitions import Line, label_decomposition,
|
|
45
|
+
from lime.transitions import Line, label_decomposition, bands_from_measurements
|
|
46
46
|
from lime.archives.read_fits import OpenFits, show_instrument_cfg
|
|
47
47
|
from lime.plotting.plots import theme
|
|
48
48
|
from lime.workflow import line_bands
|
|
@@ -154,7 +154,7 @@ def check_fits_source(fits_source, lime_object=None, load_function=None):
|
|
|
154
154
|
else:
|
|
155
155
|
|
|
156
156
|
if load_function is None:
|
|
157
|
-
|
|
157
|
+
_logger.warning(f'Please introduce fits file instrument or a load function to import the fits file as a '
|
|
158
158
|
f'LiMe observation')
|
|
159
159
|
|
|
160
160
|
return fits_source, spectrum_type
|
|
@@ -105,4 +105,9 @@ LiMe Mayor update - 2.0.0 - XX/XX/XXXX
|
|
|
105
105
|
- The central wavelenght bands are now calculated assuming a bands_vsigma=70 and n_sigma=4
|
|
106
106
|
- The function lime.Spectrum.retrieve.spectrum() returns the spectrum axes as a recarray or saves it into a text file if the user provides a file address.
|
|
107
107
|
- lime.Spectrum.from_file("fname", instrument='text') can now read the file from a text file following the format from the lime.Spectrum.retrieve.spectrum() function.
|
|
108
|
-
- Bug the .plot.spectrum(include_fittings) does not show the combined profile
|
|
108
|
+
- Bug the .plot.spectrum(include_fittings) does not show the combined profile
|
|
109
|
+
- Rename term "_conf" to "_cfg" across function names and arguments for uniformity
|
|
110
|
+
- Fitting functions now have the update_default=True argument. In the default behaviour the default configuration updates the default one. If set to update_default=False only the obj_cfg is used if available else the default one.
|
|
111
|
+
- Creating a spectrum object where all the entries are masked now produces a critical warning instead of raising an error.
|
|
112
|
+
- By default line_bands.
|
|
113
|
+
- Added bands_from_log function
|
|
@@ -180,7 +180,6 @@ def pp_FWHM(line, idx):
|
|
|
180
180
|
|
|
181
181
|
|
|
182
182
|
def gaussian_area(line, idx, n_steps):
|
|
183
|
-
|
|
184
183
|
amp = np.random.normal(line.amp[idx], line.amp_err[idx], n_steps)
|
|
185
184
|
sigma = np.random.normal(line.sigma[idx], line.sigma_err[idx], n_steps)
|
|
186
185
|
|
|
@@ -418,7 +417,9 @@ def sigma_corrections(line, idcs_line, wave_arr, R_arr, temperature):
|
|
|
418
417
|
if np.isscalar(R_arr):
|
|
419
418
|
line.sigma_instr = np.mean(wave_arr.compressed() / (R_arr * k_gFWHM))
|
|
420
419
|
else:
|
|
421
|
-
|
|
420
|
+
mask_data = ~wave_arr.mask
|
|
421
|
+
line.sigma_instr = np.mean(wave_arr[mask_data] / (R_arr[idcs_line][mask_data] * k_gFWHM))
|
|
422
|
+
wave_arr[mask_data] / (R_arr[idcs_line][mask_data] * k_gFWHM)
|
|
422
423
|
else:
|
|
423
424
|
line.sigma_instr = np.nan
|
|
424
425
|
|
|
@@ -468,8 +469,6 @@ class ProfileModelCompiler:
|
|
|
468
469
|
self.model.prefix = f'line0_'
|
|
469
470
|
|
|
470
471
|
# Fix or not the continuum
|
|
471
|
-
# m_cont_conf = _SLOPE_FIX_PAR if line._cont_from_adjacent else _SLOPE_FREE_PAR
|
|
472
|
-
# n_cont_conf = _INTER_FIX_PAR if line._cont_from_adjacent else _INTER_FREE_PAR
|
|
473
472
|
self.define_param(0, line, 'm_cont', line.m_cont, _SLOPE_FIX_PAR, user_conf)
|
|
474
473
|
self.define_param(0, line, 'n_cont', line.n_cont, _INTER_FIX_PAR, user_conf)
|
|
475
474
|
|
|
@@ -614,8 +613,11 @@ class ProfileModelCompiler:
|
|
|
614
613
|
# Check for negative -0.0 # TODO this needs a better place # FIXME -0.0 error
|
|
615
614
|
if np.signbit(line.sigma_err[i]):
|
|
616
615
|
line.sigma_err[i] = np.nan
|
|
617
|
-
|
|
618
|
-
|
|
616
|
+
_logger.warning(f'Negative scale value for amplitude at {comp_label}')
|
|
617
|
+
|
|
618
|
+
if np.signbit(line.amp_err[i]):
|
|
619
|
+
line.amp_err[i] = np.nan
|
|
620
|
+
_logger.warning(f'Negative scale value for amplitude at {comp_label}')
|
|
619
621
|
|
|
620
622
|
# Compute the profile areas
|
|
621
623
|
profile_flux_dist = AREA_FUNCTIONS[line._p_shape[i]](line, i, 1000)
|
|
@@ -283,6 +283,9 @@ class RedshiftFitting:
|
|
|
283
283
|
else:
|
|
284
284
|
pred_arr, conf_arr = self._spec.infer.pred_arr, self._spec.infer.conf_arr
|
|
285
285
|
|
|
286
|
+
# Resolving power # TODO this should be read at another point...
|
|
287
|
+
res_power = self._spec.res_power if res_power is None else res_power
|
|
288
|
+
|
|
286
289
|
# Set the type of fitting and the components to use
|
|
287
290
|
if mode == 'key':
|
|
288
291
|
components = components if components is not None else ['emission', 'doublet']
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from scipy import signal
|
|
7
|
+
from lime.io import check_file_dataframe
|
|
8
|
+
from lime.transitions import label_decomposition
|
|
9
|
+
from lime.plotting.plots import plot_peaks_troughs
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
import joblib
|
|
13
|
+
joblib_check = True
|
|
14
|
+
except ImportError:
|
|
15
|
+
joblib_check = False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_logger = logging.getLogger('LiMe')
|
|
19
|
+
|
|
20
|
+
MACHINE_PATH = None
|
|
21
|
+
FLUX_PIXEL_CONV = np.linspace(0,1,33)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def compute_line_width(idx_peak, spec_flux, delta_i, min_delta=2, emission_check=True):
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
Algororithm to measure emision line width given its peak location
|
|
28
|
+
:param idx_peak:
|
|
29
|
+
:param spec_flux:
|
|
30
|
+
:param delta_i:
|
|
31
|
+
:param min_delta:
|
|
32
|
+
:return:
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
i = idx_peak
|
|
36
|
+
|
|
37
|
+
if emission_check:
|
|
38
|
+
while (spec_flux[i] > spec_flux[i + delta_i]) or (np.abs(idx_peak - (i + delta_i)) <= min_delta):
|
|
39
|
+
i += delta_i
|
|
40
|
+
else:
|
|
41
|
+
while (spec_flux[i] < spec_flux[i + delta_i]) or (np.abs(idx_peak - (i + delta_i)) <= min_delta):
|
|
42
|
+
i += delta_i
|
|
43
|
+
|
|
44
|
+
return i
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LineFinder:
|
|
50
|
+
|
|
51
|
+
def __init__(self):
|
|
52
|
+
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
def peaks_troughs(self, bands, sigma_threshold=3, emission_type=True, width_tol=5,
|
|
56
|
+
continuum_array=None, continuum_std=None, plot_steps=False, **kwargs):
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
This function compares the input lines bands in the observation spectrum to confirm the presence of lines.
|
|
61
|
+
|
|
62
|
+
The input bands can be specified as a pandas dataframe or the path to its file via the ``bands_df`` argument.
|
|
63
|
+
|
|
64
|
+
The continuum needs to be fit a priori with the Spectrum.fit.continuum function or assigning a ``continuum_array``
|
|
65
|
+
and a ``continuum_std``.
|
|
66
|
+
|
|
67
|
+
The ``sigma_threshold`` establishes the standard deviation factor beyond which a positive line detection is assumed.
|
|
68
|
+
|
|
69
|
+
By default the algorithm seeks for emission lines, set ``emission_type`` equal to False for absorption lines.
|
|
70
|
+
|
|
71
|
+
The additional arguments provide additional utils to adjust the line detection and show the steps/results.
|
|
72
|
+
|
|
73
|
+
:param bands: Input bands dataframe or the address to its file.
|
|
74
|
+
:type bands: pandas.Dataframe, str, pathlib.Path
|
|
75
|
+
|
|
76
|
+
:param sigma_threshold: Continuum standard deviation factor for line detection. The default value is 3.
|
|
77
|
+
:type sigma_threshold: float, optional
|
|
78
|
+
|
|
79
|
+
:param emission_type: Line type. The default value is "True" for emission lines.
|
|
80
|
+
:type emission_type: str, optional
|
|
81
|
+
|
|
82
|
+
:param width_tol: Minimum number of pixels between peaks/troughs. The default value is 5.
|
|
83
|
+
:type width_tol: float, optional
|
|
84
|
+
|
|
85
|
+
:param ml_detection: Machine learning algorithm to detect lines. The default value is None.
|
|
86
|
+
:type ml_detection: str, optional
|
|
87
|
+
|
|
88
|
+
:param plot_steps: Plot the detected peaks/troughs. The default value is False
|
|
89
|
+
:type plot_steps: bool, optional
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
# TODO Lime2.0 replace by warning with new retrieve line bands
|
|
94
|
+
# Check for the peaks of the emission lines
|
|
95
|
+
continuum_array = self._spec.cont if continuum_array is None else continuum_array
|
|
96
|
+
continuum_std = self._spec.cont_std if continuum_std is None else continuum_std
|
|
97
|
+
|
|
98
|
+
# Get indeces of peaks
|
|
99
|
+
limit_threshold = sigma_threshold * continuum_std
|
|
100
|
+
limit_threshold = continuum_array + limit_threshold if emission_type else continuum_array + limit_threshold
|
|
101
|
+
idcs_peaks, _ = signal.find_peaks(self._spec.flux, height=limit_threshold, distance=width_tol)
|
|
102
|
+
|
|
103
|
+
# Match peaks with theoretical lines
|
|
104
|
+
bands = check_file_dataframe(bands)
|
|
105
|
+
matched_DF = self.label_peaks(idcs_peaks, bands, width_tol=width_tol, line_type=emission_type)
|
|
106
|
+
|
|
107
|
+
# Plot the results
|
|
108
|
+
if plot_steps:
|
|
109
|
+
plot_peaks_troughs(self._spec, idcs_peaks, limit_threshold, continuum_array, matched_DF, **kwargs)
|
|
110
|
+
|
|
111
|
+
return matched_DF
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def label_peaks(self, idcs_peaks, matched_DF, line_type='emission', width_tol=5):
|
|
115
|
+
|
|
116
|
+
# Security check in case no lines detected
|
|
117
|
+
if len(idcs_peaks) == 0:
|
|
118
|
+
return pd.DataFrame(columns=matched_DF.columns)
|
|
119
|
+
|
|
120
|
+
# Add theoretical wavelength values if necessary
|
|
121
|
+
if 'wavelength' not in matched_DF.columns:
|
|
122
|
+
matched_DF['wavelength'] = label_decomposition(matched_DF.index.values, params_list=['wavelength'])[0]
|
|
123
|
+
|
|
124
|
+
# Get bands limits indexes
|
|
125
|
+
idcs_w3 = np.searchsorted(self._spec.wave_rest, matched_DF.w3)
|
|
126
|
+
idcs_w4 = np.searchsorted(self._spec.wave_rest, matched_DF.w4)
|
|
127
|
+
|
|
128
|
+
# Get the bands matching
|
|
129
|
+
band_contains_peak = (idcs_peaks[None, :] > idcs_w3[:, None]) & (idcs_peaks[None, :] < idcs_w4[:, None])
|
|
130
|
+
idcs_matched_bands = band_contains_peak.any(axis=1)
|
|
131
|
+
idcs_matched_peaks = idcs_peaks[band_contains_peak.argmax(axis=1)[idcs_matched_bands]]
|
|
132
|
+
|
|
133
|
+
# Crop the bands to the detection
|
|
134
|
+
matched_DF.loc[idcs_matched_bands, 'observation'] = 'detected'
|
|
135
|
+
matched_DF.loc[idcs_matched_bands, 'signal_peak'] = idcs_matched_peaks
|
|
136
|
+
|
|
137
|
+
return matched_DF.loc[idcs_matched_bands]
|
|
@@ -446,8 +446,8 @@ def save_frame(fname, dataframe, page='FRAME', parameters='all', header=None, co
|
|
|
446
446
|
output_file.write(string_DF.encode('UTF-8'))
|
|
447
447
|
|
|
448
448
|
# Pdf fluxes table
|
|
449
|
-
elif file_type == '.pdf':
|
|
450
|
-
table_fluxes(lines_log, log_path.parent / log_path.stem, header_format_latex=_LOG_COLUMNS_LATEX,
|
|
449
|
+
elif file_type == '.pdf' or file_type == '.tex':
|
|
450
|
+
table_fluxes(lines_log, log_path.parent / log_path.stem, table_type=file_type[1:], header_format_latex=_LOG_COLUMNS_LATEX,
|
|
451
451
|
lines_notation=log.latex_label.values, **kwargs)
|
|
452
452
|
|
|
453
453
|
# Log in a fits format
|
|
@@ -601,7 +601,8 @@ def check_file_dataframe(df_variable, variable_type=pd.DataFrame, ext='FRAME', s
|
|
|
601
601
|
return output
|
|
602
602
|
|
|
603
603
|
|
|
604
|
-
def check_fit_conf(fit_conf, default_key,
|
|
604
|
+
def check_fit_conf(fit_conf, default_key, obj_key, update_default=True, group_list=None, fit_cfg_suffix='_line_fitting',
|
|
605
|
+
line_detection=False):
|
|
605
606
|
|
|
606
607
|
# Check that there is an input configuration
|
|
607
608
|
if fit_conf is not None:
|
|
@@ -634,33 +635,30 @@ def check_fit_conf(fit_conf, default_key, group_key, group_list=None, fit_cfg_su
|
|
|
634
635
|
|
|
635
636
|
# Recover the configuration expected for the object
|
|
636
637
|
default_cfg = input_cfg.get(f'{default_key}_line_fitting') if default_key is not None else None
|
|
637
|
-
|
|
638
|
+
custom_cfg = input_cfg.get(f'{obj_key}_line_fitting') if obj_key is not None else None
|
|
638
639
|
|
|
639
|
-
# Case there are not
|
|
640
|
-
if (default_cfg is None) and (
|
|
640
|
+
# Case there are not level entries
|
|
641
|
+
if (default_cfg is None) and (custom_cfg is None):
|
|
641
642
|
output_cfg = input_cfg
|
|
642
643
|
|
|
643
644
|
# Proceed to update the levels
|
|
644
645
|
else:
|
|
645
646
|
|
|
646
647
|
# Default configuration
|
|
647
|
-
|
|
648
|
-
default_detect =
|
|
648
|
+
default_cfg = {} if default_cfg is None else default_cfg
|
|
649
|
+
default_detect = default_cfg.get('line_detection', {})
|
|
649
650
|
|
|
650
|
-
#
|
|
651
|
-
|
|
652
|
-
|
|
651
|
+
# Custom configuration
|
|
652
|
+
custom_cfg = {} if custom_cfg is None else custom_cfg
|
|
653
|
+
custom_detect = custom_cfg.get('line_detection', {})
|
|
653
654
|
|
|
654
|
-
# Update
|
|
655
|
-
output_cfg = {**
|
|
655
|
+
# Update default configuration if requested else use only custom
|
|
656
|
+
output_cfg = {**default_cfg, **custom_cfg} if update_default else (custom_cfg if custom_cfg else default_cfg)
|
|
656
657
|
|
|
657
|
-
#
|
|
658
|
-
if
|
|
659
|
-
output_cfg['line_detection'] =
|
|
660
|
-
|
|
661
|
-
output_cfg['line_detection'] = default_detect
|
|
662
|
-
else:
|
|
663
|
-
pass
|
|
658
|
+
# Update default detection if requested else use only custom
|
|
659
|
+
if line_detection:
|
|
660
|
+
output_cfg['line_detection'] = default_detect.update(custom_detect) if update_default else\
|
|
661
|
+
(custom_detect if custom_detect else default_detect)
|
|
664
662
|
|
|
665
663
|
else:
|
|
666
664
|
output_cfg = {}
|
|
@@ -142,7 +142,7 @@ def check_inputs_arrays(wave, flux, err_flux, pixel_mask, lime_object):
|
|
|
142
142
|
# Check not all the pixels are masked
|
|
143
143
|
if mask_check:
|
|
144
144
|
if np.all(output_pixel_mask):
|
|
145
|
-
|
|
145
|
+
_logger.critical(f'All the input observation pixels are masked. Please check that only bad pixels entries'
|
|
146
146
|
f' are masked (in numpy arrays flux_arr[pixel_mask] = bad_entries)')
|
|
147
147
|
|
|
148
148
|
return output_pixel_mask
|
|
@@ -1347,6 +1347,8 @@ class Sample(UserDict, OpenFits):
|
|
|
1347
1347
|
else:
|
|
1348
1348
|
obs = load_function_output
|
|
1349
1349
|
|
|
1350
|
+
|
|
1351
|
+
|
|
1350
1352
|
return obs
|
|
1351
1353
|
|
|
1352
1354
|
def __getitem__(self, id_key):
|
|
@@ -102,14 +102,7 @@ def bokeh_bands(fig, bands, x, y, z_corr, redshift):
|
|
|
102
102
|
|
|
103
103
|
# Loop through the detections and plot the names
|
|
104
104
|
for i in np.arange(latex.size):
|
|
105
|
-
if idcs_band_limits[0, i] != idcs_band_limits[0, i]: # Y limit for the label check if same pixel
|
|
106
|
-
max_region = np.max(y[idcs_band_limits[0, i]:idcs_band_limits[0, i]])
|
|
107
|
-
else:
|
|
108
|
-
max_region = y[idcs_band_limits[0, i]]
|
|
109
|
-
|
|
110
|
-
label = 'Matched line' if i == 0 else '_'
|
|
111
105
|
fig.add_layout(BoxAnnotation(left=w3_obs[i]/z_corr, right=w4_obs[i]/z_corr, fill_alpha=0.3, fill_color=theme.colors['match_line']))
|
|
112
|
-
# axis.text(wave_array[i] * (1 + redshift) / z_corr, max_region * 0.9 * z_corr, latex[i], rotation=270)
|
|
113
106
|
|
|
114
107
|
return
|
|
115
108
|
|
|
@@ -193,8 +186,8 @@ class BokehFigures:
|
|
|
193
186
|
|
|
194
187
|
return
|
|
195
188
|
|
|
196
|
-
def bands(self, label, output_address=None, ref_bands=None, include_fits=True, rest_frame=False, log_scale=True,
|
|
197
|
-
ax_cfg=None, return_fig=False):
|
|
189
|
+
def bands(self, label, output_address=None, ref_bands=None, include_fits=True, rest_frame=False, log_scale=True,
|
|
190
|
+
exclude_continua=True, fig_cfg=None, ax_cfg=None, return_fig=False):
|
|
198
191
|
|
|
199
192
|
|
|
200
193
|
# Unpack variables
|
|
@@ -232,16 +225,13 @@ class BokehFigures:
|
|
|
232
225
|
# Create figure with default utils if not provided
|
|
233
226
|
fig = figure(tools=PLT_CONF.get('tools', "pan,wheel_zoom,box_zoom,reset,save"), y_axis_type=scale_str)
|
|
234
227
|
|
|
235
|
-
# # Create figure with default utils if not provided
|
|
236
|
-
# fig = figure(tools=PLT_CONF.get('tools', "pan,wheel_zoom,box_zoom,reset,save"))
|
|
237
|
-
|
|
238
228
|
# Spectrum data source
|
|
239
229
|
source = ColumnDataSource(data={"x": wave_plot[idcs_bands[0]:idcs_bands[5]] / z_corr,
|
|
240
230
|
"y": flux_plot[idcs_bands[0]:idcs_bands[5]] * z_corr})
|
|
241
231
|
fig.step("x", "y", source=source, color=theme.colors['fg'], line_width=1, mode='center')
|
|
242
232
|
|
|
243
233
|
# Fille the bands
|
|
244
|
-
bands_filling_bokeh(fig, wave_plot, flux_plot, z_corr, idcs_bands, line)
|
|
234
|
+
bands_filling_bokeh(fig, wave_plot, flux_plot, z_corr, idcs_bands, line, exclude_continua=exclude_continua)
|
|
245
235
|
|
|
246
236
|
# Plot labels
|
|
247
237
|
fig.xaxis.axis_label = AXES_CONF['xlabel']
|
|
@@ -250,6 +240,9 @@ class BokehFigures:
|
|
|
250
240
|
# Adjust the format of the plot
|
|
251
241
|
update_bokeh_figure(fig, PLT_CONF)
|
|
252
242
|
|
|
243
|
+
# Hide the legend if there are line profiles
|
|
244
|
+
fig.legend.visible = legend_check
|
|
245
|
+
|
|
253
246
|
# Save or display the plot
|
|
254
247
|
if return_fig:
|
|
255
248
|
return fig
|
|
@@ -258,11 +251,14 @@ class BokehFigures:
|
|
|
258
251
|
save(fig, filename=output_address)
|
|
259
252
|
|
|
260
253
|
else:
|
|
261
|
-
# output_notebook()
|
|
262
254
|
show(fig)
|
|
263
255
|
|
|
256
|
+
else:
|
|
257
|
+
_logger.info(f'The input line {label} could not be found')
|
|
258
|
+
|
|
264
259
|
return
|
|
265
260
|
|
|
261
|
+
|
|
266
262
|
def grid(self, output_address=None, rest_frame=True, log_scale=False, n_cols=6, n_rows=None, col_row_scale=(2, 1.5),
|
|
267
263
|
include_fits=True, in_fig=None, fig_cfg=None, ax_cfg=None, maximize=False):
|
|
268
264
|
|
|
@@ -270,7 +266,7 @@ class BokehFigures:
|
|
|
270
266
|
|
|
271
267
|
def spectrum(self, output_address=None, label=None, bands=None, rest_frame=False, log_scale=False,
|
|
272
268
|
include_fits=True, include_cont=False, include_components=False, return_fig=False, fig_cfg=None, ax_cfg=None, maximize=False,
|
|
273
|
-
detection_band=None, show_masks=True, show_categories=False):
|
|
269
|
+
detection_band=None, show_masks=True, show_categories=False, show_err=False):
|
|
274
270
|
|
|
275
271
|
|
|
276
272
|
# Set figure format with the user inputs overwriting the default conf
|
|
@@ -298,6 +294,14 @@ class BokehFigures:
|
|
|
298
294
|
if bands is not None:
|
|
299
295
|
bokeh_bands(fig, bands, wave_plot, flux_plot, z_corr, self._spec.redshift)
|
|
300
296
|
|
|
297
|
+
# Show uncertainty
|
|
298
|
+
if show_err and (self._spec.err_flux is not None):
|
|
299
|
+
err_plot = self._spec.err_flux.data
|
|
300
|
+
fig.varea_step(x=wave_plot / z_corr,
|
|
301
|
+
y1=(flux_plot - err_plot) * z_corr,
|
|
302
|
+
y2=(flux_plot + err_plot) * z_corr,
|
|
303
|
+
step_mode="center", fill_alpha=0.2, color=theme.colors['err_area'])
|
|
304
|
+
|
|
301
305
|
# Include the continuum
|
|
302
306
|
if include_cont and self._spec.cont is not None:
|
|
303
307
|
fig.line(wave_plot/z_corr, self._spec.cont*z_corr, legend_label="Continuum.",
|
|
@@ -402,6 +406,9 @@ class BokehFigures:
|
|
|
402
406
|
# Adjust the format of the plot
|
|
403
407
|
update_bokeh_figure(fig, PLT_CONF)
|
|
404
408
|
|
|
409
|
+
# Hide the legend if there are line profiles
|
|
410
|
+
fig.legend.visible = legend_check
|
|
411
|
+
|
|
405
412
|
# Save or display the plot
|
|
406
413
|
if return_fig:
|
|
407
414
|
return fig
|
|
@@ -54,6 +54,7 @@ class Themer:
|
|
|
54
54
|
self.conf = None # All the formating data
|
|
55
55
|
self.style = None # Label of the active style
|
|
56
56
|
self.active_conf = None # Dictionary with the active figure configuration and library
|
|
57
|
+
self.default_lib = 'matplotlib'
|
|
57
58
|
|
|
58
59
|
# LiMe plots personalization
|
|
59
60
|
self.colors = None # Features individual colors
|
|
@@ -67,6 +68,8 @@ class Themer:
|
|
|
67
68
|
self.conf = conf.copy()
|
|
68
69
|
self.set_style(style)
|
|
69
70
|
|
|
71
|
+
|
|
72
|
+
|
|
70
73
|
return
|
|
71
74
|
|
|
72
75
|
|
|
@@ -163,7 +166,7 @@ class Themer:
|
|
|
163
166
|
return ax_cfg
|
|
164
167
|
|
|
165
168
|
|
|
166
|
-
def set_style(self, style=None, scale=None, colors_conf=None, library=
|
|
169
|
+
def set_style(self, style=None, scale=None, colors_conf=None, library='matplotlib'):
|
|
167
170
|
|
|
168
171
|
# Set the default style
|
|
169
172
|
# self.style = ['default']
|
|
@@ -173,6 +176,7 @@ class Themer:
|
|
|
173
176
|
# self.style += [style] if isinstance(style, str) else style
|
|
174
177
|
self.style = 'default' if style is None else style
|
|
175
178
|
self.scale = ['default'] if style is None else [scale]
|
|
179
|
+
self.default_lib = library
|
|
176
180
|
|
|
177
181
|
# Set the library defaults
|
|
178
182
|
self.active_conf = {'matplotlib': self.conf['matplotlib']['default'].copy(),
|