"""
Module with utility functions for plotting data.
"""
import warnings
from string import ascii_lowercase
from typing import Dict, List, Optional, Tuple
import numpy as np
from typeguard import typechecked
from species.core import constants
from species.util.model_util import convert_model_name
[docs]
@typechecked
def sptype_to_index(
field_range: Tuple[str, str], spec_types: np.ndarray, check_subclass: bool
) -> np.ndarray:
"""
Function for mapping the spectral types of stellar and
substellar objects to indices that corresponds with the
discrete colorbar of a color-magnitude or color-color
diagram.
Parameters
----------
field_range : tuple(str, str)
Range of the discrete colorbar for the field objects. The tuple
should contain the lower and upper value ('early M', 'late M',
'early L', 'late L', 'early T', 'late T', 'early Y). Also
stellar spectral types can be specified.
spec_types : np.ndarray
Array with the spectral types.
check_subclass : bool
Set to ``True`` if the discrete colorbar should distinguish
early and late spectral types with different colors or set
to ``False`` if subclasses should not be distinguished.
Returns
-------
np.ndarray
Array with spectral types mapped to indices. Spectral types
that are not within the range specified with ``field_range``
will be set to NaN.
"""
spt_discrete = np.zeros(spec_types.size)
if check_subclass:
spt_check = [
("early O", "late O"),
("early B", "late B"),
("early A", "late A"),
("early F", "late F"),
("early G", "late G"),
("early K", "late K"),
("early M", "late M"),
("early L", "late L"),
("early T", "late T"),
("early Y", "late Y"),
]
for i, item in enumerate(spec_types):
if item[0:2] in ["O0", "O1", "O2", "O3", "O4"]:
spt_discrete[i] = 0.5
elif item[0:2] in ["O5", "O6", "O7", "O8", "O9"]:
spt_discrete[i] = 1.5
elif item[0:2] in ["B0", "B1", "B2", "B3", "B4"]:
spt_discrete[i] = 2.5
elif item[0:2] in ["B5", "B6", "B7", "B8", "B9"]:
spt_discrete[i] = 3.5
elif item[0:2] in ["A0", "A1", "A2", "A3", "A4"]:
spt_discrete[i] = 4.5
elif item[0:2] in ["A5", "A6", "A7", "A8", "A9"]:
spt_discrete[i] = 5.5
elif item[0:2] in ["F0", "F1", "F2", "F3", "F4"]:
spt_discrete[i] = 6.5
elif item[0:2] in ["F5", "F6", "F7", "F8", "F9"]:
spt_discrete[i] = 7.5
elif item[0:2] in ["G0", "G1", "G2", "G3", "G4"]:
spt_discrete[i] = 8.5
elif item[0:2] in ["G5", "G6", "G7", "G8", "G9"]:
spt_discrete[i] = 9.5
elif item[0:2] in ["K0", "K1", "K2", "K3", "K4"]:
spt_discrete[i] = 10.5
elif item[0:2] in ["K5", "K6", "K7", "K8", "K9"]:
spt_discrete[i] = 11.5
elif item[0:2] in ["M0", "M1", "M2", "M3", "M4"]:
spt_discrete[i] = 12.5
elif item[0:2] in ["M5", "M6", "M7", "M8", "M9"]:
spt_discrete[i] = 13.5
elif item[0:2] in ["L0", "L1", "L2", "L3", "L4"]:
spt_discrete[i] = 14.5
elif item[0:2] in ["L5", "L6", "L7", "L8", "L9"]:
spt_discrete[i] = 15.5
elif item[0:2] in ["T0", "T1", "T2", "T3", "T4"]:
spt_discrete[i] = 16.5
elif item[0:2] in ["T5", "T6", "T7", "T8", "T9"]:
spt_discrete[i] = 17.5
elif "Y" in item:
spt_discrete[i] = 18.5
else:
spt_discrete[i] = np.nan
count = 0
for i, item in enumerate(spt_check):
for j in range(2):
if field_range[0] == item[j]:
spt_discrete -= float(count)
break
count += 1
else:
spt_check = ["O", "B", "A", "F", "G", "K", "M", "L", "T", "Y"]
for i, item in enumerate(spec_types):
if item[0] == "O":
spt_discrete[i] = 0.5
elif item[0] == "B":
spt_discrete[i] = 1.5
elif item[0] == "A":
spt_discrete[i] = 2.5
elif item[0] == "F":
spt_discrete[i] = 3.5
elif item[0] == "G":
spt_discrete[i] = 4.5
elif item[0] == "K":
spt_discrete[i] = 5.5
elif item[0] == "M":
spt_discrete[i] = 6.5
elif item[0] == "L":
spt_discrete[i] = 7.5
elif item[0] == "T":
spt_discrete[i] = 8.5
elif item[0] == "Y":
spt_discrete[i] = 9.5
else:
spt_discrete[i] = np.nan
for i, item in enumerate(spt_check):
if field_range[0] == item:
spt_discrete -= float(i)
break
set_to_nan = spt_discrete < 0.0
spt_discrete[set_to_nan] = np.nan
return spt_discrete
[docs]
@typechecked
def update_labels(param: List[str], object_type: str = "planet") -> List[str]:
"""
Function for formatting the model parameters to use them
as labels in the posterior plot.
Parameters
----------
param : list
List with names of the model parameters.
object_type : str
Object type ('planet' or 'star'). With 'planet', the radius
and mass are expressed in Jupiter units. With 'star', the
radius and mass are expressed in solar units.
Returns
-------
list
List with parameter labels for plots.
"""
cloud_species = ["Fe", "MgSiO3", "Al2O3", "Na2S", "KCl"]
cloud_labels = ["Fe", r"MgSiO_{3}", r"Al_{2}O_{3}", r"Na_{2}S", "KCl"]
abund_species = [
"CO_all_iso",
"CO_all_iso_HITEMP",
"H2O",
"H2O_HITEMP",
"H2O_main_iso",
"CH4",
"CH4_main_iso",
"NH3",
"NH3_main_iso",
"CO2",
"CO2_main_iso",
"H2S",
"H2S_main_iso",
"Na",
"Na_allard",
"Na_burrows",
"Na_lor_cur",
"K",
"K_allard",
"K_burrows",
"K_lor_cur",
"PH3",
"PH3_main_iso",
"VO",
"VO_Plez",
"TiO",
"TiO_all_Exomol",
"TiO_all_iso_Plez",
"FeH",
"FeH_main_iso",
"MgSiO3(c)",
"Fe(c)",
"Al2O3(c)",
"Na2S(c)",
"KCL(c)",
]
abund_labels = [
"CO",
"CO",
"H_{2}O",
"H_{2}O",
"H_{2}O",
"CH_{4}",
"CH_{4}",
"NH_{3}",
"NH_{3}",
"CO_{2}",
"CO_{2}",
"H_{2}S",
"H_{2}S",
"Na",
"Na",
"Na",
"Na",
"K",
"K",
"K",
"K",
"PH_{3}",
"PH_{3}",
"VO",
"VO",
"TiO",
"TiO",
"TiO",
"FeH",
"FeH",
"MgSiO_{3}",
"Fe",
"Al_{2}O_{3}",
"Na_{2}S",
"KCl",
]
if "teff" in param:
index = param.index("teff")
param[index] = r"$T_\mathrm{eff}$ (K)"
if "teff_0" in param:
index = param.index("teff_0")
param[index] = r"$T_\mathrm{eff,1}$ (K)"
if "teff_1" in param:
index = param.index("teff_1")
param[index] = r"$T_\mathrm{eff,2}$ (K)"
if "logg" in param:
index = param.index("logg")
param[index] = r"$\log\,g$"
if "logg_0" in param:
index = param.index("logg_0")
param[index] = r"$\log\,g_\mathrm{1}$"
if "logg_1" in param:
index = param.index("logg_1")
param[index] = r"$\log\,g_\mathrm{2}$"
if "metallicity" in param:
index = param.index("metallicity")
param[index] = "[Fe/H]"
if "feh" in param:
index = param.index("feh")
param[index] = "[Fe/H]"
if "feh_0" in param:
index = param.index("feh_0")
param[index] = r"[Fe/H]$_\mathrm{1}$"
if "feh_1" in param:
index = param.index("feh_1")
param[index] = r"[Fe/H]$_\mathrm{2}$"
if "fsed" in param:
index = param.index("fsed")
param[index] = r"$f_\mathrm{sed}$"
if "fsed_1" in param:
index = param.index("fsed_1")
param[index] = r"$f_\mathrm{sed,1}$"
if "fsed_2" in param:
index = param.index("fsed_2")
param[index] = r"$f_\mathrm{sed,2}$"
if "f_clouds" in param:
index = param.index("f_clouds")
param[index] = r"$w_\mathrm{clouds}$"
if "c_o_ratio" in param:
index = param.index("c_o_ratio")
param[index] = r"C/O"
if "radius" in param:
index = param.index("radius")
if object_type == "planet":
param[index] = r"$R$ ($R_\mathrm{J}$)"
elif object_type == "star":
param[index] = r"$R_\ast$ ($R_\mathrm{\odot}$)"
if "distance" in param:
index = param.index("distance")
param[index] = "$d$ (pc)"
if "parallax" in param:
index = param.index("parallax")
param[index] = r"$\varpi$ (mas)"
if "vsini" in param:
index = param.index("vsini")
param[index] = r"$v\,\sin\,i$ (km s$^{-1}$)"
if "mass" in param:
index = param.index("mass")
if object_type == "planet":
param[index] = r"$M$ ($M_\mathrm{J}$)"
elif object_type == "star":
param[index] = r"$M_\ast$ ($M_\mathrm{\odot}$)"
for i, item in enumerate(ascii_lowercase[1:]):
if f"mass_{i}" in param:
index = param.index(f"mass_{i}")
param[index] = rf"$M_\mathrm{{{item}}}$ ($M_\mathrm{{J}}$)"
else:
break
if "log_mass" in param:
index = param.index("log_mass")
if object_type == "planet":
param[index] = r"$\log\,M/M_\mathrm{J}$"
elif object_type == "star":
param[index] = r"$\log\,M_\ast/M_\mathrm{\odot}$"
if "age" in param:
index = param.index("age")
param[index] = "Age (Myr)"
if "mass_1" in param:
index = param.index("mass_1")
param[index] = r"$M_\mathrm{b}$ ($M_\mathrm{J}$)"
if "mass_2" in param:
index = param.index("mass_2")
param[index] = r"$M_\mathrm{c}$ ($M_\mathrm{J}$)"
if "entropy" in param:
index = param.index("entropy")
param[index] = r"$S_\mathrm{i}$ ($k_\mathrm{B}/\mathrm{baryon}$)"
if "entropy_1" in param:
index = param.index("entropy_1")
param[index] = r"$S_\mathrm{i,b}$ ($k_\mathrm{B}/\mathrm{baryon}$)"
if "entropy_2" in param:
index = param.index("entropy_2")
param[index] = r"$S_\mathrm{i,c}$ ($k_\mathrm{B}/\mathrm{baryon}$)"
if "dfrac_1" in param:
index = param.index("dfrac_1")
param[index] = r"$\log\,D_\mathrm{i,b}$"
if "dfrac_2" in param:
index = param.index("dfrac_2")
param[index] = r"$\log\,D_\mathrm{i,c}$"
if "y_frac" in param:
index = param.index("y_frac")
param[index] = r"$Y$"
if "yfrac_1" in param:
index = param.index("yfrac_1")
param[index] = r"$Y_\mathrm{b}$"
if "yfrac_2" in param:
index = param.index("yfrac_2")
param[index] = r"$Y_\mathrm{c}$"
if "mcore_1" in param:
index = param.index("mcore_1")
param[index] = r"$M_\mathrm{core,b}$ ($M_\mathrm{E}$)"
if "mcore_2" in param:
index = param.index("mcore_2")
param[index] = r"$M_\mathrm{core,c}$ ($M_\mathrm{E}$)"
for i, item in enumerate(ascii_lowercase[1:]):
if f"teff_evol_{i}" in param:
index = param.index(f"teff_evol_{i}")
param[index] = rf"$T_\mathrm{{eff, {item}}}$ (K)"
else:
break
for i, item in enumerate(ascii_lowercase[1:]):
if f"radius_evol_{i}" in param:
index = param.index(f"radius_evol_{i}")
param[index] = rf"$R_\mathrm{{{item}}}$ ($R_\mathrm{{J}}$)"
else:
break
for i, item in enumerate(ascii_lowercase[1:]):
if f"logg_evol_{i}" in param:
index = param.index(f"logg_evol_{i}")
param[index] = rf"$\log\,g_\mathrm{{{item}}}$"
else:
break
for i, item in enumerate(ascii_lowercase[1:]):
if f"inflate_lbol{i}" in param:
index = param.index(f"inflate_lbol{i}")
param[index] = rf"$\sigma_{{L,{{{item}}}}}$ (dex)"
else:
break
for i, item in enumerate(ascii_lowercase[1:]):
if f"inflate_mass{i}" in param:
index = param.index(f"inflate_mass{i}")
param[index] = rf"$\sigma_{{M,{{{item}}}}}$ ($M_\mathrm{{J}}$)"
else:
break
if "luminosity" in param:
index = param.index("luminosity")
if object_type == "planet":
param[index] = r"$\log\,L/L_\mathrm{\odot}$"
elif object_type == "star":
param[index] = r"$\log\,L_\ast/L_\mathrm{\odot}$"
if "luminosity_ratio" in param:
index = param.index("luminosity_ratio")
param[index] = r"$\log\,L_\mathrm{1}/L_\mathrm{2}$"
if "luminosity_disk_planet" in param:
index = param.index("luminosity_disk_planet")
if object_type == "planet":
param[index] = r"$L_\mathrm{disk}/L_\mathrm{atm}$"
elif object_type == "star":
param[index] = r"$L_\mathrm{disk}/L_\ast$"
if "lognorm_radius" in param:
index = param.index("lognorm_radius")
param[index] = r"$\log\,r_\mathrm{g}$"
if "lognorm_sigma" in param:
index = param.index("lognorm_sigma")
param[index] = r"$\sigma_\mathrm{g}$"
if "lognorm_ext" in param:
index = param.index("lognorm_ext")
param[index] = r"$A_V$"
if "powerlaw_min" in param:
index = param.index("powerlaw_min")
param[index] = r"$\log\,a_\mathrm{min}/\mathrm{µm}$"
if "powerlaw_max" in param:
index = param.index("powerlaw_max")
param[index] = r"$\log\,a_\mathrm{max}/\mathrm{µm}$"
if "powerlaw_exp" in param:
index = param.index("powerlaw_exp")
param[index] = r"$\beta$"
if "powerlaw_ext" in param:
index = param.index("powerlaw_ext")
param[index] = r"$A_V$"
if "ism_ext" in param:
index = param.index("ism_ext")
param[index] = r"$A_V$"
if "ism_red" in param:
index = param.index("ism_red")
param[index] = r"$R_V$"
for item in param:
if item.startswith("phot_ext_"):
index = param.index(item)
filter_name = item[9:].split("/")[1]
param[index] = rf"$A_\mathrm{{{filter_name}}}$"
break
if "tint" in param:
index = param.index("tint")
param[index] = r"$T_\mathrm{int}$ (K)"
for i in range(15):
if f"t{i}" in param:
index = param.index(f"t{i}")
param[index] = rf"$T_\mathrm{{{i}}}$ (K)"
if "alpha" in param:
index = param.index("alpha")
param[index] = r"$\alpha$"
if "log_sigma_alpha" in param:
index = param.index("log_sigma_alpha")
param[index] = r"$\log\,\sigma_\alpha$"
if "log_delta" in param:
index = param.index("log_delta")
param[index] = r"$\log\,\delta$"
if "T_bottom" in param:
index = param.index("T_bottom")
param[index] = r"$T_\mathrm{bottom}$ (K)"
num_layer = 6 # could make a variable in the future
for i in range(num_layer):
if f"PTslope_{num_layer - i}" in param:
index = param.index(f"PTslope_{num_layer - i}")
param[index] = rf"$(dlnT/dlnP)_\mathrm{{P={i}bar}}$ (K)"
if "log_p_quench" in param:
index = param.index("log_p_quench")
param[index] = r"$\log\,P_\mathrm{quench}$"
if "sigma_lnorm" in param:
index = param.index("sigma_lnorm")
param[index] = r"$\sigma_\mathrm{g}$"
if "log_kzz" in param:
index = param.index("log_kzz")
param[index] = r"$\log\,K_\mathrm{zz}$"
if "kzz" in param:
# Backward compatibility
index = param.index("kzz")
param[index] = r"$\log\,K_\mathrm{zz}$"
for i, item in enumerate(cloud_species):
if f"{item.lower()}_fraction" in param:
index = param.index(f"{item.lower()}_fraction")
param[
index
] = rf"$\log\,\tilde{{\mathrm{{X}}}}_\mathrm{{{cloud_labels[i]}}}$"
if f"{item.lower()}_tau" in param:
index = param.index(f"{item.lower()}_tau")
param[index] = rf"$\bar{{\tau}}_\mathrm{{{cloud_labels[i]}}}$"
if f"log_p_base_{item}(c)" in param:
index = param.index(f"log_p_base_{item}(c)")
param[index] = rf"$\log\,P_\mathrm{{{cloud_labels[i]}}}$"
if f"fsed_{item}(c)" in param:
index = param.index(f"fsed_{item}(c)")
param[index] = rf"$\log\,P_\mathrm{{{cloud_labels[i]}}}$"
for i, item_i in enumerate(cloud_species):
for j, item_j in enumerate(cloud_species):
if f"{item_i.lower()}_{item_j.lower()}_ratio" in param:
index = param.index(f"{item_i.lower()}_{item_j.lower()}_ratio")
param[index] = (
rf"$\log\,\tilde{{\mathrm{{X}}}}"
rf"_\mathrm{{{cloud_labels[i]}}}/"
rf"\mathrm{{\tilde{{X}}}}_\mathrm{{{cloud_labels[j]}}}$"
)
for i, item in enumerate(abund_species):
if item in param:
index = param.index(item)
param[index] = rf"$\log\,\mathrm{{{abund_labels[i]}}}$"
for i, item in enumerate(param):
if item[0:8] == "scaling_":
item_name = item[8:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$a_\mathrm{{{item_name}}}$"
elif item[0:6] == "error_":
item_name = item[6:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$b_\mathrm{{{item_name}}}$"
elif item[0:7] == "radvel_":
item_name = item[7:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"RV$_\mathrm{{{item_name}}}$ (km s$^{{-1}}$)"
elif item[0:11] == "wavelength_":
item_name = item[11:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$c_\mathrm{{{item_name}}}$ (nm)"
elif item[-6:] == "_error":
item_name = item[:-6]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$f_\mathrm{{{item_name}}}$"
elif item[0:9] == "corr_len_":
item_name = item[9:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$\log\,\ell_\mathrm{{{item_name}}}$"
elif item[0:9] == "corr_amp_":
item_name = item[9:]
if item_name.find("\\_") == -1 and item_name.find("_") > 0:
item_name = item_name.replace("_", "\\_")
param[i] = rf"$f_\mathrm{{{item_name}}}$"
if "c_h_ratio" in param:
index = param.index("c_h_ratio")
param[index] = r"[C/H]"
if "o_h_ratio" in param:
index = param.index("o_h_ratio")
param[index] = r"[O/H]"
for i in range(100):
if f"teff_{i}" in param:
index = param.index(f"teff_{i}")
param[index] = rf"$T_\mathrm{{{i+1}}}$ (K)"
else:
break
for i in range(100):
if f"radius_{i}" in param:
index = param.index(f"radius_{i}")
param[index] = rf"$R_\mathrm{{{i+1}}}$ ($R_\mathrm{{J}}$)"
else:
break
for i in range(100):
if f"luminosity_{i}" in param:
index = param.index(f"luminosity_{i}")
param[index] = rf"$\log\,L_\mathregular{{{i+1}}}/L_\mathregular{{\odot}}$"
else:
break
if "disk_teff" in param:
index = param.index("disk_teff")
param[index] = r"$T_\mathrm{disk}$ (K)"
for i in range(100):
if f"disk_teff_{i}" in param:
index = param.index(f"disk_teff_{i}")
param[index] = r"$T_\mathrm{disk,}$" + rf"$_\mathrm{{{i+1}}}$ (K)"
else:
break
if "disk_radius" in param:
index = param.index("disk_radius")
if object_type == "planet":
param[index] = r"$R_\mathrm{disk}$ ($R_\mathrm{J}$)"
elif object_type == "star":
param[index] = r"$R_\mathrm{disk}$ (au)"
for i in range(100):
if f"disk_radius_{i}" in param:
index = param.index(f"disk_radius_{i}")
if object_type == "planet":
param[index] = (
r"$R_\mathrm{disk,}$" + rf"$_{{{i+1}}}$ ($R_\mathrm{{J}}$)"
)
elif object_type == "star":
param[index] = r"$R_\mathrm{disk,}$" + rf"$_\mathrm{{{i+1}}}$ (au)"
else:
break
if "radius_bb" in param:
index = param.index("radius_bb")
if object_type == "planet":
param[index] = r"$R_\mathrm{bb}$ ($R_\mathrm{J}$)"
elif object_type == "star":
param[index] = r"$R_\mathrm{bb}$ (au)"
for i in range(100):
if f"radius_bb_{i}" in param:
index = param.index(f"radius_bb_{i}")
if object_type == "planet":
param[index] = (
r"$R_\mathrm{bb,}$" + rf"$_{{{i+1}}}$ ($R_\mathrm{{J}}$)"
)
elif object_type == "star":
param[index] = r"$R_\mathrm{bb,}$" + rf"$_\mathrm{{{i+1}}}$ (au)"
else:
break
if "log_powerlaw_a" in param:
index = param.index("log_powerlaw_a")
param[index] = r"$a_\mathrm{powerlaw}$"
if "log_powerlaw_b" in param:
index = param.index("log_powerlaw_b")
param[index] = r"$b_\mathrm{powerlaw}$"
if "log_powerlaw_c" in param:
index = param.index("log_powerlaw_c")
param[index] = r"$c_\mathrm{powerlaw}$"
if "pt_smooth" in param:
index = param.index("pt_smooth")
param[index] = r"$\sigma_\mathrm{P-T}$"
if "abund_smooth" in param:
index = param.index("abund_smooth")
param[index] = r"$\sigma_\mathrm{abund}$"
if "log_prob" in param:
index = param.index("log_prob")
param[index] = r"$\log\,\mathcal{L}$"
if "log_tau_cloud" in param:
index = param.index("log_tau_cloud")
param[index] = r"$\log\,\tau_\mathrm{cloud}$"
if "veil_a" in param:
index = param.index("veil_a")
param[index] = r"$a_\mathrm{veil}$"
if "veil_b" in param:
index = param.index("veil_b")
param[index] = r"$b_\mathrm{veil}$"
if "veil_ref" in param:
index = param.index("veil_ref")
param[index] = r"$F_\mathrm{ref, veil}$"
if "gauss_amplitude" in param:
index = param.index("gauss_amplitude")
param[index] = r"$a$ (W m$^{-2}$ µm$^{-1}$)"
if "gauss_mean" in param:
index = param.index("gauss_mean")
param[index] = r"$\lambda$ (nm)"
if "gauss_sigma" in param:
index = param.index("gauss_sigma")
param[index] = r"$\sigma$ (nm)"
if "gauss_amplitude_2" in param:
index = param.index("gauss_amplitude_2")
param[index] = r"$a_2$ (W m$^{-2}$ µm$^{-1}$)"
if "gauss_mean_2" in param:
index = param.index("gauss_mean_2")
param[index] = r"$\lambda_2$ (nm)"
if "gauss_sigma_2" in param:
index = param.index("gauss_sigma_2")
param[index] = r"$\sigma_2$ (nm)"
if "gauss_fwhm" in param:
index = param.index("gauss_fwhm")
param[index] = r"FWHM (km s$^{-1}$)"
if "line_flux" in param:
index = param.index("line_flux")
param[index] = r"$F_\mathrm{line}$ (W m$^{-2}$)"
if "line_luminosity" in param:
index = param.index("line_luminosity")
param[index] = r"$L_\mathrm{line}$ ($L_\mathrm{\odot}$)"
if "log_line_lum" in param:
index = param.index("log_line_lum")
param[index] = r"$\log\,L_\mathrm{line}/L_\mathrm{\odot}$"
if "log_acc_lum" in param:
index = param.index("log_acc_lum")
param[index] = r"$\log\,L_\mathrm{acc}/L_\mathrm{\odot}$"
if "line_eq_width" in param:
index = param.index("line_eq_width")
param[index] = r"EW ($\AA$)"
if "line_vrad" in param:
index = param.index("line_vrad")
param[index] = r"RV (km s$^{-1}$)"
if "log_kappa_0" in param:
index = param.index("log_kappa_0")
param[index] = r"$\log\,\kappa_0$"
if "log_kappa_abs" in param:
index = param.index("log_kappa_abs")
param[index] = r"$\log\,\kappa_\mathrm{abs}$"
if "log_kappa_sca" in param:
index = param.index("log_kappa_sca")
param[index] = r"$\log\,\kappa_\mathrm{sca}$"
if "opa_index" in param:
index = param.index("opa_index")
param[index] = r"$\xi$"
if "opa_abs_index" in param:
index = param.index("opa_abs_index")
param[index] = r"$\xi_\mathrm{abs}$"
if "opa_sca_index" in param:
index = param.index("opa_sca_index")
param[index] = r"$\xi_\mathrm{sca}$"
if "log_p_base" in param:
index = param.index("log_p_base")
param[index] = r"$\log\,P_\mathrm{cloud}$"
if "albedo" in param:
index = param.index("albedo")
param[index] = r"$\omega$"
if "opa_knee" in param:
index = param.index("opa_knee")
param[index] = r"$\lambda_\mathrm{R}$ (µm)"
if "lambda_ray" in param:
index = param.index("lambda_ray")
param[index] = r"$\lambda_\mathrm{R}$ (µm)"
if "mix_length" in param:
index = param.index("mix_length")
param[index] = r"$\ell_\mathrm{m}$ ($H_\mathrm{p}$)"
if "spec_weight" in param:
index = param.index("spec_weight")
param[index] = r"w$_\mathrm{spec}$"
if "log_beta_r" in param:
index = param.index("log_beta_r")
param[index] = r"$\log\,\beta_\mathrm{r}$"
if "log_gamma_r" in param:
index = param.index("log_gamma_r")
param[index] = r"$\log\,\gamma_\mathrm{r}$"
if "gamma_r" in param:
index = param.index("gamma_r")
param[index] = r"$\gamma_\mathrm{r}$"
if "log_kappa_gray" in param:
index = param.index("log_kappa_gray")
param[index] = r"$\log\,\kappa_\mathrm{gray}$"
if "log_cloud_top" in param:
index = param.index("log_cloud_top")
param[index] = r"$\log\,P_\mathrm{top}$"
if "flux_scaling" in param:
index = param.index("flux_scaling")
param[index] = r"$a_\mathrm{flux}$"
if "log_flux_scaling" in param:
index = param.index("log_flux_scaling")
param[index] = r"$\log\,a_\mathrm{flux}$"
if "flux_offset" in param:
index = param.index("flux_offset")
param[index] = r"$b_\mathrm{flux}$ (W m$^{-2}$ µm$^{-1}$)"
return param
[docs]
@typechecked
def quantity_unit(
param: List[str], object_type: str
) -> Tuple[List[str], List[Optional[str]], List[str]]:
"""
Function for creating lists with quantities, units, and labels
for fitted parameter.
Parameters
----------
param : list
List with parameter names.
object_type : str
Object type (``'planet'`` or ``'star'``).
Returns
-------
list
List with the quantities.
list
List with the units.
list
List with the parameter labels for plots.
"""
quantity = []
unit = []
label = []
for item in param:
if item == "teff":
quantity.append("teff")
unit.append("K")
label.append(r"$T_\mathrm{eff}$")
if item == "logg":
quantity.append("logg")
unit.append(None)
label.append(r"$\log g$")
if item == "metallicity":
quantity.append("metallicity")
unit.append(None)
label.append("[Fe/H]")
if item == "feh":
quantity.append("feh")
unit.append(None)
label.append("[Fe/H]")
if item == "fsed":
quantity.append("fsed")
unit.append(None)
label.append(r"$f_\mathrm{sed}$")
if item == "c_o_ratio":
quantity.append("c_o_ratio")
unit.append(None)
label.append("C/O")
if item == "log_kzz":
quantity.append("log_kzz")
unit.append(None)
label.append(r"$\log\,K_\mathrm{zz}$")
if item == "ad_index":
quantity.append("ad_index")
unit.append(None)
label.append(r"$\gamma_\mathrm{ad}$")
if item == "radius":
quantity.append("radius")
if object_type == "planet":
unit.append(r"$R_\mathrm{J}$")
label.append(r"$R$")
elif object_type == "star":
unit.append(r"$R_\mathrm{\odot}$")
label.append(r"$R_\ast$")
for i in range(100):
if item == f"teff_{i}":
quantity.append(f"teff_{i}")
unit.append("K")
label.append(rf"$T_\mathrm{{{i+1}}}$")
else:
break
for i in range(100):
if item == f"radius_{i}":
quantity.append(f"radius_{i}")
if object_type == "planet":
unit.append(r"$R_\mathrm{J}$")
elif object_type == "star":
unit.append(r"$R_\mathrm{\odot}$")
label.append(rf"$R_\mathrm{{{i+1}}}$")
else:
break
if item == "distance":
quantity.append("distance")
unit.append("pc")
label.append(r"$d$")
if item == "parallax":
quantity.append("parallax")
unit.append("mas")
label.append(r"$\varpi$")
if item == "mass":
quantity.append("mass")
if object_type == "planet":
unit.append(r"$M_\mathrm{J}$")
label.append(r"$M$")
elif object_type == "star":
unit.append(r"$M_\mathrm{\odot}$")
label.append(r"$M_\ast$")
if item == "luminosity":
quantity.append("luminosity")
unit.append(None)
label.append(r"$\log\,L/L_\mathrm{\odot}$")
if item == "ism_ext":
quantity.append("ism_ext")
unit.append(None)
label.append(r"$A_V$")
if item == "lognorm_ext":
quantity.append("lognorm_ext")
unit.append(None)
label.append(r"$A_V$")
if item == "powerlaw_ext":
quantity.append("powerlaw_ext")
unit.append(None)
label.append(r"$A_V$")
if item.startswith("phot_ext_"):
quantity.append(item)
unit.append(None)
filter_name = item[9:].split("/")[1]
label.append(rf"$A_\mathrm{{{filter_name}}}$")
if item == "pt_smooth":
quantity.append("pt_smooth")
unit.append(None)
label.append(r"$\sigma_\mathrm{P-T}$")
if item == "abund_smooth":
quantity.append("abund_smooth")
unit.append(None)
label.append(r"$\sigma_\mathrm{abund}$")
if item == "disk_teff":
quantity.append("disk_teff")
unit.append("K")
label.append(r"$T_\mathrm{disk}$")
for i in range(100):
if item == f"disk_teff_{i}":
quantity.append(f"disk_teff_{i}")
unit.append("K")
label.append(r"$T_\mathrm{disk,}$" + rf"$_\mathrm{{{i+1}}}$")
else:
break
if item == "disk_radius":
quantity.append("disk_radius")
if object_type == "planet":
unit.append(r"$R_\mathrm{J}$")
elif object_type == "star":
unit.append("au")
label.append(r"$R_\mathrm{disk}$")
for i in range(100):
if item == f"disk_radius_{i}":
quantity.append(f"disk_radius_{i}")
if object_type == "planet":
unit.append(r"$R_\mathrm{J}$")
elif object_type == "star":
unit.append("au")
label.append(r"$R_\mathrm{disk,}$" + rf"$_\mathrm{{{i+1}}}$")
else:
break
if item == "flux_scaling":
quantity.append("flux_scaling")
unit.append(None)
label.append(r"$a_\mathrm{flux}$")
if item == "log_flux_scaling":
quantity.append("log_flux_scaling")
unit.append(None)
label.append(r"$\log\,a_\mathrm{flux}$")
if item == "flux_offset":
quantity.append("flux_offset")
unit.append(r"W m$^{-2}$ µm$^{-1}$")
label.append(r"$b_\mathrm{flux}$")
return quantity, unit, label
[docs]
@typechecked
def field_bounds_ticks(
field_range: Tuple[str, str],
check_subclass: bool,
) -> Tuple[np.ndarray, np.ndarray, List[str]]:
"""
Function for converting the specified field range into boundaries
and labels for the discrete colorbar that is plotted with a
color-magnitude or color-color diagram.
Parameters
----------
field_range : tuple(str, str)
Range of the discrete colorbar for the field objects. The tuple
should contain the lower and upper value ('early M', 'late M',
'early L', 'late L', 'early T', 'late T', 'early Y). Also
stellar spectral types can be specified.
check_subclass : bool
Set to ``True`` if the discrete colorbar should distinguish
early and late spectral types with different colors or set
to ``False`` if subclasses should not be distinguished.
Returns
-------
np.ndarray
Array with the boundaries for the discrete colorbar.
np.ndarray
Array with the midpoints for the discrete colorbar.
list(str)
List with the tick labels for the discrete colorbar.
"""
if check_subclass:
spectral_ranges = [
"O0-O4",
"O5-O9",
"B0-B4",
"B5-B9",
"A0-A4",
"A5-A9",
"F0-F4",
"F5-F9",
"G0-G4",
"G5-G9",
"K0-K4",
"K5-K9",
"M0-M4",
"M5-M9",
"L0-L4",
"L5-L9",
"T0-T4",
"T5-T9",
"Y1-Y2",
]
if field_range[0] == "early O":
index_start = 0
elif field_range[0] == "late O":
index_start = 1
elif field_range[0] == "early B":
index_start = 2
elif field_range[0] == "late B":
index_start = 3
elif field_range[0] == "early A":
index_start = 4
elif field_range[0] == "late A":
index_start = 5
elif field_range[0] == "early F":
index_start = 6
elif field_range[0] == "late F":
index_start = 7
elif field_range[0] == "early G":
index_start = 8
elif field_range[0] == "late G":
index_start = 9
elif field_range[0] == "early K":
index_start = 10
elif field_range[0] == "late K":
index_start = 11
elif field_range[0] == "early M":
index_start = 12
elif field_range[0] == "late M":
index_start = 13
elif field_range[0] == "early L":
index_start = 14
elif field_range[0] == "late L":
index_start = 15
elif field_range[0] == "early T":
index_start = 16
elif field_range[0] == "late T":
index_start = 17
elif field_range[0] == "early Y":
index_start = 18
if field_range[1] == "early O":
index_end = 1
elif field_range[1] == "late O":
index_end = 2
elif field_range[1] == "early B":
index_end = 3
elif field_range[1] == "late B":
index_end = 4
elif field_range[1] == "early A":
index_end = 5
elif field_range[1] == "late A":
index_end = 6
elif field_range[1] == "early F":
index_end = 7
elif field_range[1] == "late F":
index_end = 8
elif field_range[1] == "early G":
index_end = 9
elif field_range[1] == "late G":
index_end = 10
elif field_range[1] == "early K":
index_end = 11
elif field_range[1] == "late K":
index_end = 12
elif field_range[1] == "early M":
index_end = 13
elif field_range[1] == "late M":
index_end = 14
elif field_range[1] == "early L":
index_end = 15
elif field_range[1] == "late L":
index_end = 16
elif field_range[1] == "early T":
index_end = 17
elif field_range[1] == "late T":
index_end = 18
elif field_range[1] == "early Y":
index_end = 19
else:
spectral_ranges = ["O", "B", "A", "F", "G", "K", "M", "L", "T", "Y"]
if field_range[0] == "O":
index_start = 0
elif field_range[0] == "B":
index_start = 1
elif field_range[0] == "A":
index_start = 2
elif field_range[0] == "F":
index_start = 3
elif field_range[0] == "G":
index_start = 4
elif field_range[0] == "K":
index_start = 5
elif field_range[0] == "M":
index_start = 6
elif field_range[0] == "L":
index_start = 7
elif field_range[0] == "T":
index_start = 8
elif field_range[0] == "Y":
index_start = 9
if field_range[1] == "O":
index_end = 1
elif field_range[1] == "B":
index_end = 2
elif field_range[1] == "A":
index_end = 3
elif field_range[1] == "F":
index_end = 4
elif field_range[1] == "G":
index_end = 5
elif field_range[1] == "K":
index_end = 6
elif field_range[1] == "M":
index_end = 7
elif field_range[1] == "L":
index_end = 8
elif field_range[1] == "T":
index_end = 9
elif field_range[1] == "Y":
index_end = 10
index_range = index_end - index_start + 1
bounds = np.linspace(index_start, index_end, index_range)
ticks = np.linspace(index_start + 0.5, index_end - 0.5, index_range - 1)
labels = spectral_ranges[index_start:index_end]
ticks -= bounds[0]
bounds -= bounds[0]
return bounds, ticks, labels
[docs]
@typechecked
def remove_color_duplicates(
object_names: List[str], empirical_names: np.ndarray
) -> List[int]:
""" "
Function for deselecting young/low-gravity objects that will
already be plotted individually as directly imaged objects.
Parameters
----------
object_names : list(str)
List with names of directly imaged planets and brown dwarfs.
empirical_names : np.ndarray
Array with names of young/low-gravity objects.
Returns
-------
list
List with selected indices of the young/low-gravity objects.
"""
indices = []
for i, item in enumerate(empirical_names):
if item == "beta_Pic_b" and "beta Pic b" in object_names:
continue
if item == "HR8799b" and "HR 8799 b" in object_names:
continue
if item == "HR8799c" and "HR 8799 c" in object_names:
continue
if item == "HR8799d" and "HR 8799 d" in object_names:
continue
if item == "HR8799e" and "HR 8799 e" in object_names:
continue
if item == "kappa_And_B" and "kappa And b" in object_names:
continue
if item == "HD1160B" and "HD 1160 B" in object_names:
continue
indices.append(i)
return indices
[docs]
@typechecked
def create_model_label(
model_param: Dict[str, float],
object_type: str,
model_name: str,
inc_model_name: bool,
leg_param: List[str],
param_fmt: Dict[str, str],
) -> str:
""" "
Function for creating a label that includes the parameters of a
model spectrum. The label is used in the legend of a SED plot.
Parameters
----------
model_param : dict
Dictionary with model parameters.
model_name : str
Name of the atmospheric model.
inc_model_name : bool
Include the model name in the label.
object_type : str
Object type ('planet' or 'star') that determines if
Jupiter or solar units are used.
leg_param : list(str)
List with the parameters to include. Apart from atmospheric
parameters (e.g. 'teff', 'logg', 'radius') also parameters
such as 'mass' and 'luminosity' can be included. The default
atmospheric parameters are included in the legend if the
argument is an empty list.
param_fmt : dict(str, str)
Dictionary with formats that will be used for the model
parameter. The parameters are included in the ``legend``
when plotting the model spectra. Default formats are
used if the argument of ``param_fmt`` is set to ``None``.
Returns
-------
str
Text label that includes the selected parameter names,
the model values, and the parameter units.
"""
# data_file = Path(__file__).parents[1].resolve() / "data/model_data/model_data.json"
# with open(data_file, "r", encoding="utf-8") as json_file:
# model_data = json.load(json_file)
# model_list = list(model_data.keys())
# Do not include these parameters by default in the legend
not_default = ["distance", "parallax", "mass", "luminosity"]
# Use the model parameters if leg_param is empty
if len(leg_param) == 0:
leg_param = list(model_param.keys())
for param_item in not_default:
if param_item in leg_param:
# Do not include the not_default parameters
leg_param.remove(param_item)
# Remove parameters from the model_param dictionary
# if they are not included in the leg_param list
del_keys = []
for param_item in model_param.keys():
if param_item not in leg_param:
del_keys.append(param_item)
for param_item in del_keys:
del model_param[param_item]
# Get parameters keys, units, and labels
par_key, par_unit, par_label = quantity_unit(
param=list(model_param.keys()), object_type=object_type
)
# Initiate an empty label that will be returned
label = ""
# newline = False
# Optionally include the model name into the label
if model_name is not None and inc_model_name:
label += convert_model_name(model_name)
if len(par_key) > 0:
label += ": "
for item in leg_param:
if item in par_key:
param_idx = par_key.index(item)
else:
continue
if item[:4] == "teff":
value = f"{model_param[item]:{param_fmt['teff']}}"
elif item[:6] == "radius":
if object_type == "planet":
value = f"{model_param[item]:{param_fmt['radius']}}"
elif object_type == "star":
value = f"{model_param[item]*constants.R_JUP/constants.R_SUN:{param_fmt['radius']}}"
elif item[:11] == "disk_radius":
if object_type == "planet":
value = f"{model_param[item]:{param_fmt['disk_radius']}}"
elif object_type == "star":
radius_au = model_param[item] * constants.R_JUP / constants.AU
value = f"{radius_au:{param_fmt['disk_radius']}}"
elif item == "mass" and item in leg_param:
if object_type == "planet":
value = f"{model_param[item]:{param_fmt['mass']}}"
elif object_type == "star":
value = f"{model_param[item]*constants.M_JUP/constants.M_SUN:{param_fmt['mass']}}"
elif item == "luminosity" and item in leg_param:
value = f"{np.log10(model_param[item]):{param_fmt['luminosity']}}"
elif item in leg_param and item in param_fmt:
value = f"{model_param[item]:{param_fmt[item]}}"
elif item in leg_param and item not in param_fmt:
warnings.warn(
f"The '{item}' parameter is not found in "
"the dictionary of 'param_fmt'."
)
value = f"{model_param[item]:{param_fmt[item]:.2f}}"
else:
continue
# if len(label) > 80 and newline == False:
# label += '\n'
# newline = True
if par_unit[param_idx] is None:
if len(label) > 0 and label[-2] != ":":
label += ", "
label += f"{par_label[param_idx]} = {value}"
else:
if len(label) > 0 and label[-2] != ":":
label += ", "
label += f"{par_label[param_idx]} = {value} {par_unit[param_idx]}"
return label