lime-stable 2.0.dev3__py3-none-any.whl → 2.0.dev4__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.
- lime/archives/tables.py +3 -0
- lime/changelog.txt +5 -1
- lime/fitting/lines.py +3 -1
- lime/fitting/redshift.py +3 -0
- lime/io.py +18 -20
- lime/lime.toml +1 -1
- lime/observations.py +3 -1
- lime/plotting/bokeh_plots.py +9 -1
- lime/plotting/plots.py +22 -7
- lime/plotting/plots_interactive.py +53 -34
- lime/plotting/theme_lime.toml +3 -1
- lime/transitions.py +77 -70
- lime/workflow.py +250 -184
- {lime_stable-2.0.dev3.dist-info → lime_stable-2.0.dev4.dist-info}/METADATA +1 -1
- {lime_stable-2.0.dev3.dist-info → lime_stable-2.0.dev4.dist-info}/RECORD +18 -18
- {lime_stable-2.0.dev3.dist-info → lime_stable-2.0.dev4.dist-info}/WHEEL +1 -1
- {lime_stable-2.0.dev3.dist-info → lime_stable-2.0.dev4.dist-info}/licenses/LICENSE.rst +0 -0
- {lime_stable-2.0.dev3.dist-info → lime_stable-2.0.dev4.dist-info}/top_level.txt +0 -0
lime/archives/tables.py
CHANGED
lime/changelog.txt
CHANGED
|
@@ -105,4 +105,8 @@ 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
|
lime/fitting/lines.py
CHANGED
|
@@ -418,7 +418,9 @@ def sigma_corrections(line, idcs_line, wave_arr, R_arr, temperature):
|
|
|
418
418
|
if np.isscalar(R_arr):
|
|
419
419
|
line.sigma_instr = np.mean(wave_arr.compressed() / (R_arr * k_gFWHM))
|
|
420
420
|
else:
|
|
421
|
-
|
|
421
|
+
mask_data = ~wave_arr.mask
|
|
422
|
+
line.sigma_instr = np.mean(wave_arr[mask_data] / (R_arr[idcs_line][mask_data] * k_gFWHM))
|
|
423
|
+
wave_arr[mask_data] / (R_arr[idcs_line][mask_data] * k_gFWHM)
|
|
422
424
|
else:
|
|
423
425
|
line.sigma_instr = np.nan
|
|
424
426
|
|
lime/fitting/redshift.py
CHANGED
|
@@ -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']
|
lime/io.py
CHANGED
|
@@ -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 = {}
|
lime/lime.toml
CHANGED
lime/observations.py
CHANGED
|
@@ -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):
|
lime/plotting/bokeh_plots.py
CHANGED
|
@@ -270,7 +270,7 @@ class BokehFigures:
|
|
|
270
270
|
|
|
271
271
|
def spectrum(self, output_address=None, label=None, bands=None, rest_frame=False, log_scale=False,
|
|
272
272
|
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):
|
|
273
|
+
detection_band=None, show_masks=True, show_categories=False, show_err=False):
|
|
274
274
|
|
|
275
275
|
|
|
276
276
|
# Set figure format with the user inputs overwriting the default conf
|
|
@@ -298,6 +298,14 @@ class BokehFigures:
|
|
|
298
298
|
if bands is not None:
|
|
299
299
|
bokeh_bands(fig, bands, wave_plot, flux_plot, z_corr, self._spec.redshift)
|
|
300
300
|
|
|
301
|
+
# Show uncertainty
|
|
302
|
+
if show_err and (self._spec.err_flux is not None):
|
|
303
|
+
err_plot = self._spec.err_flux.data
|
|
304
|
+
fig.varea_step(x=wave_plot / z_corr,
|
|
305
|
+
y1=(flux_plot - err_plot) * z_corr,
|
|
306
|
+
y2=(flux_plot + err_plot) * z_corr,
|
|
307
|
+
step_mode="center", fill_alpha=0.2, color=theme.colors['err_area'])
|
|
308
|
+
|
|
301
309
|
# Include the continuum
|
|
302
310
|
if include_cont and self._spec.cont is not None:
|
|
303
311
|
fig.line(wave_plot/z_corr, self._spec.cont*z_corr, legend_label="Continuum.",
|
lime/plotting/plots.py
CHANGED
|
@@ -654,7 +654,7 @@ def redshift_permu_evaluation(spectrum, z_infered, obs_wave_arr, theo_wave_arr,
|
|
|
654
654
|
return
|
|
655
655
|
|
|
656
656
|
|
|
657
|
-
def bands_filling_plot(axis, x, y, z_corr, idcs_mask, label, exclude_continua=False, color_dict=theme.colors):
|
|
657
|
+
def bands_filling_plot(axis, x, y, z_corr, idcs_mask, label, exclude_continua=False, color_dict=theme.colors, show_central=True):
|
|
658
658
|
|
|
659
659
|
# Security check for low selection
|
|
660
660
|
if len(x[idcs_mask[2]:idcs_mask[3]]) > 1:
|
|
@@ -673,8 +673,9 @@ def bands_filling_plot(axis, x, y, z_corr, idcs_mask, label, exclude_continua=Fa
|
|
|
673
673
|
low_lim = m * x_interval + n
|
|
674
674
|
|
|
675
675
|
# Central bands
|
|
676
|
-
|
|
677
|
-
|
|
676
|
+
if show_central:
|
|
677
|
+
axis.fill_between(x_interval/z_corr, low_lim*z_corr, y_interval*z_corr,
|
|
678
|
+
facecolor=color_dict['line_band'], step='mid', alpha=0.25)
|
|
678
679
|
|
|
679
680
|
# Continua bands exclusion
|
|
680
681
|
if exclude_continua is False:
|
|
@@ -767,8 +768,8 @@ class Plotter:
|
|
|
767
768
|
def _line_matching_plot(self, axis, bands, x, y, z_corr, redshift):
|
|
768
769
|
|
|
769
770
|
# Open the bands file the bands
|
|
770
|
-
match_log = self._spec.retrieve.line_bands(ref_bands=bands,
|
|
771
|
-
|
|
771
|
+
match_log = self._spec.retrieve.line_bands(ref_bands=bands, fit_cfg=None, instrumental_correction=False,
|
|
772
|
+
adjust_central_band=False)
|
|
772
773
|
# Compute bands limits
|
|
773
774
|
w3 = match_log.w3.values * (1 + redshift)
|
|
774
775
|
w4 = match_log.w4.values * (1 + redshift)
|
|
@@ -782,6 +783,7 @@ class Plotter:
|
|
|
782
783
|
|
|
783
784
|
# Loop through the detections and plot the names
|
|
784
785
|
for i, line_label in enumerate(match_log.index):
|
|
786
|
+
print(line_label)
|
|
785
787
|
line = Line(line_label, match_log)
|
|
786
788
|
|
|
787
789
|
# Get the max flux on the region making the exception for 1 pixel bands
|
|
@@ -1274,7 +1276,7 @@ class SpectrumFigures(Plotter):
|
|
|
1274
1276
|
return in_fig
|
|
1275
1277
|
|
|
1276
1278
|
def bands(self, label=None, output_address=None, ref_bands=None, include_fits=True, rest_frame=False, y_scale='auto', fig_cfg=None,
|
|
1277
|
-
ax_cfg=None, in_fig=None, maximize=False):
|
|
1279
|
+
ax_cfg=None, in_fig=None, maximize=False, show_err=True):
|
|
1278
1280
|
|
|
1279
1281
|
"""
|
|
1280
1282
|
|
|
@@ -1333,6 +1335,12 @@ class SpectrumFigures(Plotter):
|
|
|
1333
1335
|
# Check which line should be plotted
|
|
1334
1336
|
line = parse_bands_arguments(label, log, ref_bands, norm_flux)
|
|
1335
1337
|
|
|
1338
|
+
# Check the observation has uncertainty to display
|
|
1339
|
+
if show_err and (self._spec.err_flux is None):
|
|
1340
|
+
if self._spec.err_flux is None:
|
|
1341
|
+
_logger.info('Input observation does not include uncertainty to display')
|
|
1342
|
+
show_err = False
|
|
1343
|
+
|
|
1336
1344
|
# Proceed to plot
|
|
1337
1345
|
if line is not None:
|
|
1338
1346
|
|
|
@@ -1375,7 +1383,14 @@ class SpectrumFigures(Plotter):
|
|
|
1375
1383
|
where='mid', color=theme.colors['fg'], label=label_leg, linewidth=theme.plt['spectrum_width'])
|
|
1376
1384
|
|
|
1377
1385
|
# Continuum bands
|
|
1378
|
-
bands_filling_plot(in_ax[0], wave_plot, flux_plot, z_corr, idcs_bands, line, color_dict=theme.colors
|
|
1386
|
+
bands_filling_plot(in_ax[0], wave_plot, flux_plot, z_corr, idcs_bands, line, color_dict=theme.colors,
|
|
1387
|
+
show_central=not show_err)
|
|
1388
|
+
|
|
1389
|
+
if show_err:
|
|
1390
|
+
err_plot = self._spec.err_flux.data
|
|
1391
|
+
in_ax[0].fill_between(x=wave_plot[idcs_bands[2]:idcs_bands[3]] / z_corr, y1=(flux_plot[idcs_bands[2]:idcs_bands[3]] - err_plot[idcs_bands[2]:idcs_bands[3]]) * z_corr,
|
|
1392
|
+
y2=(flux_plot[idcs_bands[2]:idcs_bands[3]] + err_plot[idcs_bands[2]:idcs_bands[3]]) * z_corr,
|
|
1393
|
+
step='mid', alpha=1, color=theme.colors['line_band'], ec=None)
|
|
1379
1394
|
|
|
1380
1395
|
# Add the fitting results
|
|
1381
1396
|
if include_fits:
|
|
@@ -20,23 +20,31 @@ from ..transitions import label_decomposition, Line
|
|
|
20
20
|
_logger = logging.getLogger('LiMe')
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def establish_selection_lines(spec, input_log, band_vsigma
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
update_latex=False):
|
|
23
|
+
def establish_selection_lines(spec, input_log, band_vsigma, n_sigma, adjust_central_band, instrumental_correction,
|
|
24
|
+
components_detection, composite_lines, fit_cfg, default_cfg_prefix, obj_cfg_prefix,
|
|
25
|
+
update_default, line_list, particle_list, decimals, vacuum_waves, ref_bands, update_labels,
|
|
26
|
+
update_latex, vacuum_label):
|
|
28
27
|
|
|
29
28
|
# Use the default database crop for the observation if none provided
|
|
30
|
-
ref_bands = spec.retrieve.line_bands(band_vsigma, n_sigma,
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
ref_bands = spec.retrieve.line_bands(band_vsigma=band_vsigma, n_sigma=n_sigma, adjust_central_band=adjust_central_band,
|
|
30
|
+
instrumental_correction=instrumental_correction, components_detection=False,
|
|
31
|
+
composite_lines=None, fit_cfg=None, default_cfg_prefix=None,
|
|
32
|
+
obj_cfg_prefix=None, update_default=True,
|
|
33
|
+
line_list=line_list, particle_list=particle_list, decimals=decimals,
|
|
34
|
+
vacuum_waves=vacuum_waves, ref_bands=ref_bands, update_labels=update_labels,
|
|
35
|
+
update_latex=update_latex, vacuum_label=vacuum_label)
|
|
36
|
+
|
|
33
37
|
|
|
34
38
|
# Load input log or copy the reference one
|
|
35
39
|
in_bands = check_file_dataframe(input_log, verbose=False)
|
|
36
40
|
if in_bands is None:
|
|
37
|
-
in_bands = spec.retrieve.line_bands(band_vsigma, n_sigma,
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
in_bands = spec.retrieve.line_bands(band_vsigma=band_vsigma, n_sigma=n_sigma, adjust_central_band=adjust_central_band,
|
|
42
|
+
instrumental_correction=instrumental_correction, components_detection=components_detection,
|
|
43
|
+
composite_lines=composite_lines, fit_cfg=fit_cfg, default_cfg_prefix=default_cfg_prefix,
|
|
44
|
+
obj_cfg_prefix=obj_cfg_prefix, update_default=update_default,
|
|
45
|
+
line_list=line_list, particle_list=particle_list, decimals=decimals,
|
|
46
|
+
vacuum_waves=vacuum_waves, ref_bands=ref_bands, update_labels=update_labels,
|
|
47
|
+
update_latex=update_latex, vacuum_label=vacuum_label)
|
|
40
48
|
default_status = 1 if components_detection else 0
|
|
41
49
|
else:
|
|
42
50
|
default_status = 1
|
|
@@ -78,6 +86,11 @@ def establish_selection_lines(spec, input_log, band_vsigma=70, n_sigma=4, fit_co
|
|
|
78
86
|
active_lines = active_lines[sorted_indexes].astype(bool)
|
|
79
87
|
labels_arr = labels_arr[sorted_indexes]
|
|
80
88
|
|
|
89
|
+
# Set NaN entries in dataframe as None
|
|
90
|
+
if 'group_label' in log.columns:
|
|
91
|
+
idcs_nan = log.group_label.isnull()
|
|
92
|
+
log.loc[idcs_nan, 'group_label'] = 'none'
|
|
93
|
+
|
|
81
94
|
return log, labels_arr, active_lines
|
|
82
95
|
|
|
83
96
|
|
|
@@ -180,17 +193,20 @@ class BandsInspection:
|
|
|
180
193
|
self._color_bg = {True: theme.colors['inspection_positive'],
|
|
181
194
|
False: theme.colors['inspection_negative']}
|
|
182
195
|
|
|
196
|
+
self._out_params = ["wavelength", "wave_vac", "w1", "w2", "w3", "w4", "w5", "w6",
|
|
197
|
+
"units_wave", "particle", "transition", "rel_int"]
|
|
198
|
+
|
|
183
199
|
return
|
|
184
200
|
|
|
185
|
-
def bands(self, bands_file, band_vsigma=70, n_sigma=4,
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
201
|
+
def bands(self, bands_file, band_vsigma=70, n_sigma=4, adjust_central_band=True, instrumental_correction=True,
|
|
202
|
+
components_detection=False, composite_lines=None, fit_cfg=None, default_cfg_prefix='default',
|
|
203
|
+
obj_cfg_prefix=None, update_default=True, line_list=None, particle_list=None, decimals=None,
|
|
204
|
+
vacuum_waves=False, ref_bands=None, update_labels=False, update_latex=False, vacuum_label=False,
|
|
205
|
+
y_scale='auto', n_cols=6, n_rows=None, col_row_scale=(1, 0.5),
|
|
206
|
+
exclude_continua=False, n_pixels=10, fig_cfg=None, in_fig=None, maximize=False):
|
|
190
207
|
|
|
191
208
|
|
|
192
209
|
"""
|
|
193
|
-
|
|
194
210
|
This function launches an interactive plot from which to select the line bands on the observed spectrum. If this
|
|
195
211
|
function is run a second time, the user selections won't be overwritten.
|
|
196
212
|
|
|
@@ -266,10 +282,11 @@ class BandsInspection:
|
|
|
266
282
|
raise LiMe_Error(f'Input bands file directory does not exist ({self._log_address.parent.as_posix()})')
|
|
267
283
|
|
|
268
284
|
# Establish the reference lines log to inspect the mask
|
|
269
|
-
self.log, self.line_list, self.active_lines = establish_selection_lines(self._spec, self._log_address,
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
285
|
+
self.log, self.line_list, self.active_lines = establish_selection_lines(self._spec, self._log_address,
|
|
286
|
+
band_vsigma, n_sigma, adjust_central_band, instrumental_correction,
|
|
287
|
+
components_detection, composite_lines, fit_cfg, default_cfg_prefix,
|
|
288
|
+
obj_cfg_prefix, update_default, line_list, particle_list, decimals,
|
|
289
|
+
vacuum_waves, ref_bands, update_labels, update_latex, vacuum_label)
|
|
273
290
|
|
|
274
291
|
# Proceed if there are lines in the mask for the object spectrum wavelength range
|
|
275
292
|
if len(self.log.index) > 0:
|
|
@@ -430,7 +447,7 @@ class BandsInspection:
|
|
|
430
447
|
_logger.info(f'Unsuccessful line selection: {self.line}: w_low: {w_low}, w_high: {w_high}')
|
|
431
448
|
|
|
432
449
|
# Save the log to the file
|
|
433
|
-
save_or_clear_log(self.log, self._log_address, self.active_lines)
|
|
450
|
+
save_or_clear_log(self.log, self._log_address, self.active_lines, self._out_params)
|
|
434
451
|
|
|
435
452
|
# Redraw the line measurement
|
|
436
453
|
self._ax.clear()
|
|
@@ -470,7 +487,7 @@ class BandsInspection:
|
|
|
470
487
|
self.active_lines[idx] = np.invert(self.active_lines[idx])
|
|
471
488
|
|
|
472
489
|
# Save the log to the file
|
|
473
|
-
save_or_clear_log(self.log, self._log_address, self.active_lines)
|
|
490
|
+
save_or_clear_log(self.log, self._log_address, self.active_lines, self._out_params)
|
|
474
491
|
|
|
475
492
|
# Plot the line selection with the new Background
|
|
476
493
|
self._ax.clear()
|
|
@@ -516,7 +533,7 @@ class BandsInspection:
|
|
|
516
533
|
self._fig.canvas.draw()
|
|
517
534
|
|
|
518
535
|
# Save the log to the file
|
|
519
|
-
save_or_clear_log(self.log, self._log_address, self.active_lines)
|
|
536
|
+
save_or_clear_log(self.log, self._log_address, self.active_lines, self._out_params)
|
|
520
537
|
|
|
521
538
|
return
|
|
522
539
|
|
|
@@ -821,8 +838,12 @@ class RedshiftInspection:
|
|
|
821
838
|
|
|
822
839
|
def redshift(self, obj_idcs, reference_lines, output_file_log=None, output_idcs=None, redshift_column='redshift',
|
|
823
840
|
initial_z=None, none_value=np.nan, unknown_value=0.0, legend_handle='levels', maximize=False, title=None,
|
|
824
|
-
output_address=None, n_pixels=10, fig_cfg={}, ax_cfg={}, in_fig=None):
|
|
841
|
+
output_address=None, n_pixels=10, fig_cfg={}, ax_cfg={}, in_fig=None, **kwargs):
|
|
842
|
+
|
|
825
843
|
|
|
844
|
+
# Check if input tuple
|
|
845
|
+
if isinstance(obj_idcs, tuple):
|
|
846
|
+
obj_idcs = pd.MultiIndex.from_tuples([obj_idcs], names=self._sample.index.names)
|
|
826
847
|
|
|
827
848
|
# Assign the attributes
|
|
828
849
|
self._obj_idcs = obj_idcs if isinstance(obj_idcs, pd.MultiIndex) else self._sample.loc[obj_idcs].index
|
|
@@ -833,6 +854,10 @@ class RedshiftInspection:
|
|
|
833
854
|
self._legend_handle = legend_handle
|
|
834
855
|
self._user_point = None
|
|
835
856
|
|
|
857
|
+
# Parameters for the load function
|
|
858
|
+
self._load_params = {**self._sample.load_params, **kwargs}
|
|
859
|
+
self._load_params['redshift'] = 0
|
|
860
|
+
|
|
836
861
|
# Output Log params
|
|
837
862
|
self._log_address = output_file_log
|
|
838
863
|
|
|
@@ -904,9 +929,6 @@ class RedshiftInspection:
|
|
|
904
929
|
# Plot on screen unless an output address is provided
|
|
905
930
|
save_close_fig_swicth(output_address, 'tight', self._fig, maximise=maximize)
|
|
906
931
|
|
|
907
|
-
# else:
|
|
908
|
-
# _logger.warning(f'The sample does not have objects. The redshift check could not be done')
|
|
909
|
-
|
|
910
932
|
return
|
|
911
933
|
|
|
912
934
|
def _launch_plots_ZI(self):
|
|
@@ -944,8 +966,7 @@ class RedshiftInspection:
|
|
|
944
966
|
for i, obj_idx in enumerate(self._obj_idcs):
|
|
945
967
|
|
|
946
968
|
# Load the spectrum with a zero redshift
|
|
947
|
-
|
|
948
|
-
spec = self._sample.load_function(self._sample.frame, obj_idx, self._sample.file_address, **load_params)
|
|
969
|
+
spec = self._sample.load_function(self._sample.frame, obj_idx, self._sample.file_address, **self._load_params)
|
|
949
970
|
|
|
950
971
|
# Plot on the observed frame with reshift = 0
|
|
951
972
|
wave_plot, flux_plot, z_corr, idcs_mask = frame_mask_switch(spec.wave, spec.flux, spec.redshift, 'observed')
|
|
@@ -966,8 +987,7 @@ class RedshiftInspection:
|
|
|
966
987
|
for obj_idx in self._obj_idcs:
|
|
967
988
|
|
|
968
989
|
# Load the spectrum
|
|
969
|
-
|
|
970
|
-
spec = self._sample.load_function(self._sample.frame, obj_idx, self._sample.file_address, **load_params)
|
|
990
|
+
spec = self._sample.load_function(self._sample.frame, obj_idx, self._sample.file_address, **self._load_params)
|
|
971
991
|
|
|
972
992
|
wavelength = spec.wave.data
|
|
973
993
|
wavelength = wavelength[~np.isnan(wavelength)]
|
|
@@ -1042,13 +1062,12 @@ class RedshiftInspection:
|
|
|
1042
1062
|
_redshift_pred = redshift_output
|
|
1043
1063
|
|
|
1044
1064
|
# Store the new redshift
|
|
1045
|
-
|
|
1065
|
+
|
|
1046
1066
|
self._sample.loc[self._output_idcs, self._column_log] = _redshift_pred
|
|
1047
1067
|
|
|
1048
1068
|
# Save to file if provided
|
|
1049
1069
|
if self._log_address is not None:
|
|
1050
1070
|
save_frame(self._log_address, self._sample.frame)
|
|
1051
|
-
|
|
1052
1071
|
return
|
|
1053
1072
|
|
|
1054
1073
|
def _button_ZI(self, line_selection):
|
lime/plotting/theme_lime.toml
CHANGED
|
@@ -109,6 +109,7 @@ mask_marker = '#FF0000'
|
|
|
109
109
|
inspection_positive = '#FFFFFF'
|
|
110
110
|
inspection_negative = '#ff796c' # 'xkcd:salmon'
|
|
111
111
|
fade_fg = "#FFE5B4"
|
|
112
|
+
err_area = "#00FF00"
|
|
112
113
|
|
|
113
114
|
[colors.dark] # Dark theme
|
|
114
115
|
bg = "#2B2B2B"
|
|
@@ -128,4 +129,5 @@ comps_map = 'PuRd'
|
|
|
128
129
|
mask_marker = '#FF0000'
|
|
129
130
|
inspection_positive = "#2B2B2B"
|
|
130
131
|
inspection_negative = '#840000'
|
|
131
|
-
fade_fg = "#73879B"
|
|
132
|
+
fade_fg = "#73879B"
|
|
133
|
+
err_area = "#00FF00"
|
lime/transitions.py
CHANGED
|
@@ -749,6 +749,7 @@ class Line:
|
|
|
749
749
|
self.kinem = None
|
|
750
750
|
self.profile_comp = profile
|
|
751
751
|
self.transition_comp = None
|
|
752
|
+
self.core = None
|
|
752
753
|
|
|
753
754
|
self._ref_idx = None
|
|
754
755
|
self._p_type = None
|
|
@@ -843,9 +844,11 @@ class Line:
|
|
|
843
844
|
else:
|
|
844
845
|
self._ref_idx = 0
|
|
845
846
|
|
|
847
|
+
# Core component definition
|
|
848
|
+
self.core = f'{comps_list[0]}_{comps_list[1]}'
|
|
849
|
+
|
|
846
850
|
# Provide a bands from the log if possible
|
|
847
|
-
|
|
848
|
-
self.mask = label_mask_assigning(self.label, band, self.blended_check, self.merged_check, core_comp)
|
|
851
|
+
self.mask = label_mask_assigning(self.label, band, self.blended_check, self.merged_check, self.core)
|
|
849
852
|
|
|
850
853
|
# Check if there are masked pixels in the line
|
|
851
854
|
self.pixel_mask = 'no' if fit_conf is None else fit_conf.get(f'{self.label}_mask', 'no')
|
|
@@ -1039,89 +1042,93 @@ class Line:
|
|
|
1039
1042
|
else:
|
|
1040
1043
|
return idcs_bands
|
|
1041
1044
|
|
|
1042
|
-
def index_bands_orig(self, wavelength_array, redshift, merge_continua=True, just_band_edges=False):
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1045
|
+
# def index_bands_orig(self, wavelength_array, redshift, merge_continua=True, just_band_edges=False):
|
|
1046
|
+
#
|
|
1047
|
+
# if self.mask is None:
|
|
1048
|
+
# raise LiMe_Error(f'The line {self.label} does include bands. Please select another line or update the database.')
|
|
1049
|
+
#
|
|
1050
|
+
# # Make sure it is a matrix
|
|
1051
|
+
# bands_arr = np.atleast_2d(self.mask) * (1 + redshift)
|
|
1052
|
+
#
|
|
1053
|
+
# # if np.any(bands_arr[:, 0] < wavelength_array[0]) or np.any(bands_arr[:, 5] > wavelength_array[-1]):
|
|
1054
|
+
# # _logger.warning(f'The {self.label} bands do not match the spectrum wavelength range (observed):')
|
|
1055
|
+
# # _logger.warning( f'-- The spectrum wavelength range is: ({wavelength_array[0]:0.2f}, {wavelength_array[-1]:0.2f}) (observed frame)')
|
|
1056
|
+
# # _logger.warning(f'-- The {self.label} bands are: {bands_arr} (rest frame * (1 + z))')
|
|
1057
|
+
#
|
|
1058
|
+
# # Check if it is a masked array
|
|
1059
|
+
# wave_arr = wavelength_array.data
|
|
1060
|
+
#
|
|
1061
|
+
# # Remove masked pixels from this function wavelength array
|
|
1062
|
+
# if self.pixel_mask != 'no':
|
|
1063
|
+
#
|
|
1064
|
+
# # Convert cfg mask string to limits
|
|
1065
|
+
# line_mask_limits = format_line_mask_option(self.pixel_mask, wave_arr)
|
|
1066
|
+
#
|
|
1067
|
+
# # Get masked indeces
|
|
1068
|
+
# idcsMask = (wave_arr[:, None] >= line_mask_limits[:, 0]) & (wave_arr[:, None] <= line_mask_limits[:, 1])
|
|
1069
|
+
# idcsValid = ~idcsMask.sum(axis=1).astype(bool)[:, None]
|
|
1070
|
+
#
|
|
1071
|
+
# else:
|
|
1072
|
+
# idcsValid = np.ones(wave_arr.size).astype(bool)[:, None]
|
|
1073
|
+
#
|
|
1074
|
+
# # Find indeces for six points in spectrum
|
|
1075
|
+
# idcsW = np.searchsorted(wave_arr, bands_arr)
|
|
1076
|
+
#
|
|
1077
|
+
# # Return just the edges of the bands
|
|
1078
|
+
# if just_band_edges:
|
|
1079
|
+
# outputs = idcsW[0]
|
|
1080
|
+
#
|
|
1081
|
+
# # Return the indeces of all the pixels within the bands
|
|
1082
|
+
# else:
|
|
1083
|
+
#
|
|
1084
|
+
# # Emission region
|
|
1085
|
+
# idcsLineRegion = ((wave_arr[idcsW[:, 2]] <= wave_arr[:, None]) & (
|
|
1086
|
+
# wave_arr[:, None] <= wave_arr[idcsW[:, 3]]) & idcsValid).squeeze()
|
|
1087
|
+
#
|
|
1088
|
+
# # Return left and right continua merged in one array
|
|
1089
|
+
# if merge_continua:
|
|
1090
|
+
# idcsContRegion = (((wave_arr[idcsW[:, 0]] <= wave_arr[:, None]) &
|
|
1091
|
+
# (wave_arr[:, None] <= wave_arr[idcsW[:, 1]])) |
|
|
1092
|
+
# ((wave_arr[idcsW[:, 4]] <= wave_arr[:, None]) & (
|
|
1093
|
+
# wave_arr[:, None] <= wave_arr[idcsW[:, 5]])) & idcsValid).squeeze()
|
|
1094
|
+
#
|
|
1095
|
+
# outputs = idcsLineRegion, idcsContRegion
|
|
1096
|
+
#
|
|
1097
|
+
# # Return left and right continua in separated arrays
|
|
1098
|
+
# else:
|
|
1099
|
+
# idcsContLeft = ((wave_arr[idcsW[:, 0]] <= wave_arr[:, None]) & (
|
|
1100
|
+
# wave_arr[:, None] <= wave_arr[idcsW[:, 1]]) & idcsValid).squeeze()
|
|
1101
|
+
# idcsContRight = ((wave_arr[idcsW[:, 4]] <= wave_arr[:, None]) & (
|
|
1102
|
+
# wave_arr[:, None] <= wave_arr[idcsW[:, 5]]) & idcsValid).squeeze()
|
|
1103
|
+
#
|
|
1104
|
+
# outputs = idcsLineRegion, idcsContLeft, idcsContRight
|
|
1105
|
+
#
|
|
1106
|
+
# return outputs
|
|
1073
1107
|
|
|
1074
|
-
|
|
1075
|
-
if just_band_edges:
|
|
1076
|
-
outputs = idcsW[0]
|
|
1108
|
+
def update_label(self, decimals=None, update_latex=True, bands_df=None, vacuum_label=False):
|
|
1077
1109
|
|
|
1078
|
-
#
|
|
1110
|
+
# Reference wavelength
|
|
1111
|
+
if (vacuum_label is True) and (bands_df is not None):
|
|
1112
|
+
wave_ref = pd_get(bands_df, self.label, 'wave_vac')
|
|
1079
1113
|
else:
|
|
1114
|
+
wave_ref = self.wavelength[self._ref_idx]
|
|
1080
1115
|
|
|
1081
|
-
|
|
1082
|
-
idcsLineRegion = ((wave_arr[idcsW[:, 2]] <= wave_arr[:, None]) & (
|
|
1083
|
-
wave_arr[:, None] <= wave_arr[idcsW[:, 3]]) & idcsValid).squeeze()
|
|
1084
|
-
|
|
1085
|
-
# Return left and right continua merged in one array
|
|
1086
|
-
if merge_continua:
|
|
1087
|
-
idcsContRegion = (((wave_arr[idcsW[:, 0]] <= wave_arr[:, None]) &
|
|
1088
|
-
(wave_arr[:, None] <= wave_arr[idcsW[:, 1]])) |
|
|
1089
|
-
((wave_arr[idcsW[:, 4]] <= wave_arr[:, None]) & (
|
|
1090
|
-
wave_arr[:, None] <= wave_arr[idcsW[:, 5]])) & idcsValid).squeeze()
|
|
1091
|
-
|
|
1092
|
-
outputs = idcsLineRegion, idcsContRegion
|
|
1093
|
-
|
|
1094
|
-
# Return left and right continua in separated arrays
|
|
1095
|
-
else:
|
|
1096
|
-
idcsContLeft = ((wave_arr[idcsW[:, 0]] <= wave_arr[:, None]) & (
|
|
1097
|
-
wave_arr[:, None] <= wave_arr[idcsW[:, 1]]) & idcsValid).squeeze()
|
|
1098
|
-
idcsContRight = ((wave_arr[idcsW[:, 4]] <= wave_arr[:, None]) & (
|
|
1099
|
-
wave_arr[:, None] <= wave_arr[idcsW[:, 5]]) & idcsValid).squeeze()
|
|
1100
|
-
|
|
1101
|
-
outputs = idcsLineRegion, idcsContLeft, idcsContRight
|
|
1102
|
-
|
|
1103
|
-
return outputs
|
|
1104
|
-
|
|
1105
|
-
def update_label(self, decimals=None, update_latex=True, bands_df=None):
|
|
1106
|
-
|
|
1107
|
-
# Convert core transition particle
|
|
1116
|
+
# Core transition particle
|
|
1108
1117
|
part_str = self.particle[self._ref_idx]
|
|
1109
|
-
wave_str = np.round(
|
|
1118
|
+
wave_str = np.round(wave_ref, 0).astype(int) if decimals is None else np.round(wave_ref, decimals)
|
|
1110
1119
|
units_str = f'{self.units_wave[self._ref_idx]}' if self.units_wave[self._ref_idx] != 'Angstrom' else 'A'
|
|
1111
1120
|
module_str = "_b" if self.blended_check else "_m" if self.merged_check else ""
|
|
1121
|
+
|
|
1122
|
+
# Optional components
|
|
1112
1123
|
kinem_str = f'_k-{self.kinem[self._ref_idx]}' if self.kinem[self._ref_idx] != 0 else ''
|
|
1113
1124
|
profile_str = f'_p-{self.profile_comp[self._ref_idx]}' if self.profile_comp[self._ref_idx] != 'g-emi' else ''
|
|
1114
1125
|
trans_str = f'_t-{self.kinem[self._ref_idx]}' if not self.profile_comp[self._ref_idx] not in ['rec', 'col'] else ''
|
|
1115
1126
|
|
|
1116
|
-
#
|
|
1127
|
+
# Set label
|
|
1117
1128
|
self.label = f'{part_str}_{wave_str}{units_str}{module_str}{kinem_str}{profile_str}{trans_str}'
|
|
1118
1129
|
|
|
1119
1130
|
# Update latex notation
|
|
1120
1131
|
if update_latex:
|
|
1121
1132
|
self.latex_label = self._review_science_notation(bands_df, update_latex, decimals=decimals)
|
|
1122
1133
|
|
|
1123
|
-
return
|
|
1124
|
-
|
|
1125
|
-
def get_latex_label(self):
|
|
1126
|
-
|
|
1127
1134
|
return
|