Show the code
from IPython.display import Markdown
from tabulate import tabulate
from astropy.table import Table
from types import MethodType
from format_multiple_errors import format_multiple_errors
from numbers import Real
import numpy as np
import math
def format_cell(x,
exponential=False,
digits=2):
"""
Render a single table cell in latex depending on the type of x:
- scalar -> single value
- 1-tuple/list/np.array (value,) -> treat like scalar
- 2-tuple/list/np.array (value, err) -> value ± err
- 3-tuple/list/np.array (value, err_minus, err_plus) -> value_{-err_minus}^{+err_plus}
Formatted as exponential if exponential = True, with the indicated number of digits.
Format overrides may also be specified in a dictionary at the end of the tuple.
Non-numerical values are returned as string unchanged.
"""
# TODO: improve automatic choice of exponential and digits value when unspecified
# Missing value
if x is None:
return "—"
list_formats = (list, tuple, np.ndarray)
numeric_formats = (Real, np.floating, np.integer)
# Scalar number
fmt = f".{digits}{'e' if exponential else 'f'}" # Format
if isinstance(x, np.ndarray) and x.ndim == 0: # Regularize potential ndarray 0D (e.g. np.array(value)) to python scalars
x = x.item()
if isinstance(x, numeric_formats): # Plain scalar value
return fr"${x:{fmt}}$"
if isinstance(x, list_formats) and len(x) == 1: # Or 1-tuple -> treat like scalar
value = x[0]
if isinstance(value, numeric_formats):
return fr"${value:{fmt}}$"
# Significant figures given digits
def sigfig(digits, value):
e = 0 if value == 0 else int(math.floor(math.log10(abs(value))))
return max(1, digits + e + 1) if not exponential else digits + 1
# 2-tuple symmetric uncertainty
if isinstance(x, list_formats) and len(x) == 2 and all(isinstance(v, numeric_formats) for v in x):
value, err = x
return rf"${format_multiple_errors(value, err, exponential=exponential, significant_figures=sigfig(digits, value), length_control='central', latex=True)}$"
# 3-tuple asymmetric uncertainty
if isinstance(x, list_formats) and len(x) == 3 and all(isinstance(v, numeric_formats) for v in x):
value, err_lower, err_upper, = x
return rf"${format_multiple_errors(value, (err_upper, err_lower), exponential=exponential, significant_figures=sigfig(digits, value), length_control='central', latex=True)}$"
# Special case: entry includes explicit format overrides as a dictionary in the last element of the tuple
if isinstance(x, list_formats) and isinstance(x[-1], dict):
*values, fmt_overrides = x
note = fmt_overrides.pop("note", "") # Return value associated to the key and remove entry from dictionary (otherwise format_cell() produces an error)
fmt_merged = {
"exponential": exponential,
"digits": digits,
**fmt_overrides
} # Shallow merge: if duplicate key in dictionary, take the last one, effectively overriding the specified format parameters
values_unpacked = values[0] if len(values) == 1 else tuple(values)
return format_cell(values_unpacked, **fmt_merged) + note
# Fallback: try to convert to string, or raise exception
try:
return str(x)
except:
raise ValueError(f"Unrecognized cell format for entry {x}")
def table_to_markdown(tbl,
exponential=False,
digits=2,
col_fmt_overrides=None,
headers=None,
**kwargs):
"""
Convert an Astropy Table into a Markdown table, formatting every cell through the format_cell() function.
Formatting instructions passed to format_cell() can be overridden for specific columns through the col_fmt_overrides field
"""
default_fmt = {
"exponential": exponential,
"digits": digits
}
rows = []
for r in tbl:
row = []
for c in tbl.colnames:
if col_fmt_overrides is None:
fmt = default_fmt # Default format
else:
fmt = {**default_fmt, **col_fmt_overrides.get(c, {})} # Shallow merge: if duplicate key, take the last one, overriding the specified format parameters for current column
row.append(format_cell(r[c], **fmt))
rows.append(row)
if headers is None:
headers = tbl.colnames
md = tabulate(
rows,
headers,
**kwargs
)
return md
# ---------------- Example usage ----------------
# Map column name --> (header, units); TODO: units using astropy.units and converting when formatting header
colmap = {
"ID": ("Name", None),
"redshift": ("Redshift", None),
"OtoH": ("12 + log(O/H)", None),
"metallicity": ("Metallicity", r"Z$_\odot$"),
"MIII": (r"$M_\mathrm{III}$", r"M$_\odot$"),
"Mstar": (r"$M_\star$", r"M$_\odot$"),
"SFR": ("SFR", r"M$_\odot$yr$^{-1}$"),
"magnification": ("Lensed", None),
"MUV": (r"$M_{\rm UV}$", None),
"beta": (r"$\beta$-slope", None),
"HeII1640_flux": ("HeII1640 flux", r"erg s$^{-1}$ cm$^{-2}$"),
"HeII1640_EW": ("HeII1640 EW", "Å"),
"HeII1640_FWHM": ("HeII1640 FWHM", r"km s$^{-1}$"),
"HeII4686_flux": ("HeII4686 flux", r"erg s$^{-1}$ cm$^{-2}$"),
"HeII4686_EW": ("HeII4686 EW", "Å"),
"HeII4686_FWMH": ("HeII4686 FWHM", r"km s$^{-1}$"),
"OIII5007_flux": ("[OIII]5007 flux", r"erg s$^{-1}$ cm$^{-2}$"),
"OIII5007_EW": ("[OIII]5007 EW", "Å"),
"OIII5007_FWHM": ("[OIII]5007 FWHM", r"km s$^{-1}$"),
"OIIItoHb": (r"[OIII]/H$\beta$", None),
"Lya_flux": (r"Ly$\alpha$ flux", r"erg s$^{-1}$ cm$^{-2}$"),
"Lya_EW": (r"Ly$\alpha$ EW", "Å"),
"Lya_FWHM": (r"Ly$\alpha$ FWHM", r"km s$^{-1}$"),
"Ha_flux": (r"H$\alpha$ flux", r"erg s$^{-1}$ cm$^{-2}$"),
"Ha_EW": (r"H$\alpha$ EW", "Å"),
"Ha_FWHM": (r"H$\alpha$ FWHM", r"km s$^{-1}$"),
"Hb_flux": (r"H$\beta$ flux", r"erg s$^{-1}$ cm$^{-2}$"),
"Hb_EW": (r"H$\beta$ EW", "Å"),
"Hb_FWHM": (r"H$\beta$ FWHM", r"km s$^{-1}$"),
"Hg_flux": (r"H$\gamma$ flux", r"erg s$^{-1}$ cm$^{-2}$"),
"Hg_EW": (r"H$\gamma$ EW", "Å"),
"reference": ("References", None),
}
names = tuple(colmap.keys())
headers = tuple(
(fr"{label}<br>[{unit}]" if unit else f"{label}<br> ")
for (label, unit) in colmap.values()
)
# Setup table
table = Table(
names=names,
dtype=("object",)*len(names),
masked=True
)
# Minor patch of astropy table add_row method, so that missing values are set to None by default instead of 0
defaults = {c: None for c in table.colnames}
def add_row_with_defaults(self, row=None, *args, **kwargs):
if isinstance(row, dict):
row = {**defaults, **row}
return Table.add_row(self, row, *args, **kwargs)
table.add_row = MethodType(add_row_with_defaults, table)
# Column format overrides
col_fmt_overrides = {
"Mstar": {"exponential": True},
"MIII": {"exponential": True},
"Lya_flux": {"exponential": True},
"Ha_flux": {"exponential": True},
"Hb_flux": {"exponential": True},
"Hg_flux": {"exponential": True},
"HeII1640_flux": {"exponential": True},
"HeII4686_flux": {"exponential": True},
"OIII5007_flux": {"exponential": True},
}
# Notes style
class NoteManager:
def __init__(self):
self.map = {}
self.notes = []
def _label(self, i):
label = ""
while True:
label = chr(ord('a') + i % 26) + label
i = i // 26 - 1
if i < 0:
break
return label
def get_index(self, text):
if text not in self.map:
idx = len(self.notes)
self.map[text] = idx
self.notes.append(text)
return self.map[text]
def mark(self, text, color="red"):
idx = self.get_index(text)
label = self._label(idx)
return (
f'<a href="#note-{idx}" id="ref-{idx}">'
f'$^{{\\textcolor{{{color}}}{{({label})}}}}$'
f'</a>'
)
def render_notes_markdown(self):
blocks = []
for i, text in enumerate(self.notes):
label = self._label(i)
blocks.append(
f'<span id="note-{i}" style="font-size:75%">\n'
f'<a href="#ref-{i}">$^{{({label})}}$</a> {text}\n'
f'</span>\n'
)
return "\n".join(blocks)
nm = NoteManager()
def note(text):
return nm.mark(text)
# Fill table
table.add_row(dict(
ID="GNHeII J1236+6215",
redshift=(2.9803, 0.0010, {"digits": 4}),
magnification="No",
MUV=(-22.09, 0.02, {"digits": 2}),
beta=(-2.18, 0.06, {"digits": 2}),
Lya_flux=(23.0e-18, 5.4e-18, {"digits": 2}),
Lya_EW=(19.2),
Lya_FWHM=(758, 90, {"digits": 0}), # Note that values for the FWHMs are also given in A in Tab. 4
Ha_flux=(16.46e-18, 0.32e-18, {"digits": 3}),
Ha_EW=166.5,
Ha_FWHM=(268, 41, {"digits": 0}),
Hb_flux=(5.44e-18, 0.37e-18, {"digits": 2}),
Hb_EW=(26.6),
Hb_FWHM=(320, 137, {"digits": 0}),
HeII1640_flux=(8.8e-18, 1.8e-18),
HeII1640_EW=8.3,
HeII1640_FWHM=(573, 191, {"digits": 0}),
Mstar=(7.8e8, 3.1e8),
SFR=(12.2, 2.0, {"note": note(r"From photometric analysis, averaged over the last 10 Myr; from spectroscopic analysis: $\mathrm{SFR}_\mathrm{UV} = (9.8 \pm 0.1) ~\mathrm{M_\odot yr^{-1}}$, $\mathrm{SFR}_\mathrm{H\beta} = (7.6 \pm 0.4) ~\mathrm{M_\odot yr^{-1}}$, $\mathrm{SFR}_\mathrm{H\alpha} = (7.5 \pm 0.1) ~\mathrm{M_\odot yr^{-1}}$, $\mathrm{SFR}_\mathrm{Pa\beta} = (6.40 \pm 0.03) ~\mathrm{M_\odot yr^{-1}}$.")}), # From SED, i.e. the value reported in the abstract
OIII5007_flux=(59.6e-18, 2.2e-18, {"digits": 2}),
OIII5007_EW=248.8,
OIIItoHb=(5.45, 0.32, {"digits": 2}), # They also give HeII/Hbeta = 1.96 \pm 0.30, and HeII/Halpha = 0.69, 0.10, reported to closely match with the candidate from Wang+24
OtoH=(7.85, 0.22, {"digits": 2}),
metallicity=(0.003, 0.002, {"digits": 3}),
reference="@mondal2025"
))
table.add_row(dict(
ID="MPG-CR3",
redshift=(3.193, 0.016, {"digits": 3}),
magnification="No",
Lya_flux=(5.8e-17, 0.7e-17),
Lya_EW=(822, 101, {"digits": 0}),
Ha_flux=(4.2e-18, 0.6e-18, {"note": note("Includes a rescaling to account for potential flux losses, as the source lies near the edge of the MSA shutter.")}),
Ha_EW=(2814, 327, {"digits": 0}),
Hb_flux=(6.3e-19, 0.7e-19),
HeII1640_flux=(None, {"note": note("HeII1640 line coinciding with strong OH skyline for this object.")}),
MIII=6.1e5,
OIII5007_flux=r"$< 5.6 \times 10^{-19}$", # At 2sigma
OtoH=r"$< 6.52$",
metallicity=r"$< 8 \times 10^{-3}$",
reference="@cai2025"
))
table.add_row(dict(
ID="LAP2",
redshift=(4.189, 0.003, {"digits": 3}),
magnification=("Yes", {"note": note(r"The UV magnitude at 1700 Å for this source is de-lensed, while fluxes are not corrected for lensing. De-lensed fluxes were obtained by dividing by $\mu_\mathrm{tot}$, assuming a total magnification factor of $\mu_\mathrm{tot} = 50 \pm 5$.")}), # mu_tot = 50 \pm 5, mu_tang = 20 \pm 3
MUV=(r"$\approx -12.2$"), # M_1700
Mstar=r"$\approx (1.2 - 5.0) \times 10^4$",
Ha_flux=(1.68e-19, 0.30e-19, {"digits": 2}),
OIII5007_flux=r"$< 5 \times 10^{-20}$", # 2sigma upper limit
Hb_flux=(0.72e-19, 0.26e-19, {"digits": 1}),
Lya_flux=(26.4e-19, 3.8e-19, 3.7e-19, {"digits": 2, "note": note(r"From independent VLT/MUSE measure, $f_\mathrm{Ly\alpha} = (5.50 \pm 0.58) \times 10^{-18} ~\mathrm{erg \, s^{-1} \, cm^{-1}}$.")}),
Ha_EW=(647, 220, 302, {"digits": 0}),
metallicity=r"$< 0.006$",
OtoH=r"$< 6.5$",
HeII1640_EW=r"$< 80$", # 2sigma upper limit
reference="@vanzella2026"
))
table.add_row(dict(
ID=("CAPERS-UDS-32520", {"note": note(r"The authors also examined a companion that serendipitously lies across the slit mask (therefore dubbing the whole system \"banana and blueberry\" due to its morphology, possibly hinting to a disturbed, merger-like origin), finding clear signatures of H$\alpha$ emission, as well as potential HeI and HeII emission lines; however, they caution that photometric data for the \"blueberry\" system from the Minerva survey (@muzzin2025) strongly favor a lower-redshift solution at $z \sim 0.7$ (Willot, priv. comm.).")}),
redshift=(5.1240, 0.0002, {"digits": 4}),
magnification="No",
MUV=(-20.95, 0.05, {"digits": 2}),
beta=(-1.68, 0.05, {"digits": 2}),
Hg_flux=(2.8e-18, 0.3e-18, {"digits": 1}),
Hg_EW=(35, 4, {"digits": 0}),
Hb_flux=(4.3e-18, 0.3e-18, {"digits": 1}),
Hb_EW=(137, 13, {"digits": 0}),
OIII5007_flux=(29.6e-18, 0.4e-18, {"digits": 2}),
OIII5007_EW=(946, 46, {"digits": 0}),
Ha_flux=(13.8e-18, 0.2e-18, {"digits": 2}),
Ha_EW=(734, 33, {"digits": 0}),
OtoH=(7.88, 0.07, {"digits": 2}),
metallicity=r"$< 0.15$",
Mstar=r"$\sim 10^9$",
reference="@reumert2026"
))
table.add_row(dict(
ID="AMORE6",
redshift=(5.7253, 0.00005, {"digits": 4}),
magnification=("Yes", {"note": note("Properties for the stacked spectrum of the two images in the doubly lensed system, normalizing by the magnification factor of each image.")}), # $\mu = 39.32_{-3.48}^{+3.73}$ for AMORE6-A, vs $\mu = 77.69_{-5.92}^{+8.37}$ for AMORE6-B
MUV=(-14.52, 0.08, 0.07, {"digits": 2, "note": note(r"The absolute UV magnitude and the physical properties of AMORE6 from SED fitting are reported for only one of the two images (AMORE6-B), as the other one (AMORE6-A) suffers from large uncertainties, likely due to its location near bright galaxies as well as its smaller magnification factor ($\mu = 39.32_{-3.48}^{+3.73}$, vs $\mu = 77.69_{-5.92}^{+8.37}$ for AMORE6-B).")}),
beta=(-2.77, 0.09, 0.07, {"digits": 2}),
Lya_flux= (4.95e-19, 0.92e-19, {"digits": 2}), # From Lyalpha-to-Hbeta ratio = 10.01 \pm 1.4, propagating uncertainties
Hb_flux=(0.49e-19, 0.06e-19),
Hb_EW=(1594.7, 206.9),
Mstar=(4.37e5, 0.73e5, 2.24e5, {"digits": 2}),
SFR=(0.35, 0.06, {"digits": 2, "note": note(r"SFR inferred from H$\beta$, larger than the value inferred from rest-frame UV luminosity -- $(0.0186_{-0.0035}^{+0.0033}) ~\mathrm{M_\odot yr^{-1}}$ -- or from averaging over the last 100 Myr of the best-fit star-formation history -- $(0.0038_{-0.0007}^{+0.0017}) ~\mathrm{M_\odot yr^{-1}}$ --, suporting the presence of a very young burst.")}), # From Hbeta, converting from log to linear
OIII5007_flux=r"$< 1.1 \times 10^{-20}$", # Upper limits at 2sigma
OtoH=r"$< 5.78$",
metallicity=r"$< 0.0012$",
reference="@morishita2025"
))
'''
# Originally proposed by https://ui.adsabs.harvard.edu/abs/2025ApJ...989...46F/abstract, but fails two of the three updated color–color criteria of https://ui.adsabs.harvard.edu/abs/2025arXiv251211790F/abstract
table.add_row(dict(
ID="JOF-21739",
redshift=(6.17, 0.19, 0.06, {"digits": 2}),
magnification="Yes", # Value of magnification not indicated
MUV=(-17.62, 0.15, 0.17, {"digits": 2}),
beta=(-2.79, 0.05, {"digits": 2}),
Ha_EW=(3600, 430, {"digits": 0}),
MIII=r"$\sim 10^5 - 10^6$",
OIIItoHb=r"$< 0.32$",
OtoH=r"$< 6.2$",
metallicity=r"$< 0.003$",
reference="@fujimoto2025"
))
'''
'''
# Originally proposed by https://ui.adsabs.harvard.edu/abs/2025ApJ...989...46F/abstract, but rejected due to [OIII] detection in the spectrum (https://ui.adsabs.harvard.edu/abs/2025arXiv251211790F/abstract)
table.add_row(dict(
ID="GLIMPSE-1604",
redshift=(6.50, 0.24, 0.03, {"digits": 2}),
magnification="Yes", # mu = (2.9, 0.2, 0.1),
MUV=(-15.89, 0.14, 0.12, {"digits": 2}),
beta=(-2.34, 0.36, {"digits": 2}),
Ha_EW=(2810, 550, {"digits": 0}),
MIII=r"$\sim 10^5$",
OIIItoHb=r"$< 0.44$",
OtoH=r"$< 6.4$",
metallicity=r"$< 0.005$",
reference="@fujimoto2025"
))
'''
table.add_row(dict(
ID="LAP1",
redshift=(6.625, 0.001, {"digits": 3}),
magnification="Yes", # mu = 98
MUV=r"$> -10.4$",
Mstar=r"$\lesssim 2700$",
Lya_flux=(6.08e-19, 1.70e-19, {"digits": 2}), # All fluxes from tab. 1
Lya_EW=r"$> 250$",
Ha_flux=(2.07e-19, 0.25e-19, {"digits": 2}),
Ha_EW=r"$> 1800$", # at 3sigma, 880 at 5sigma
Hb_flux=(0.73e-19, 0.20e-19, {"digits": 1}),
Hb_EW=r"$> 340$", # at 3sigma, 170 at 5sigma
HeII1640_flux=(r"$\lesssim 1.85 \times 10^{-19}$", {"note": note(r"@vanzella2023 previously estimated a line flux for HeII1640 of $(7.96 \pm 2.07) \times 10^{-19} ~\mathrm{erg \, s^{-1} \, cm^{-2}}$; however, the reliability of the HeII line detection was hampered by the presence of a small blueshift relative to the Balmer lines, and by the extreme required EW ($\gtrsim 200$ Å), therefore the authors safely considered the line undetected, placing a $1\sigma$ upper limit of $2.7 \times 10^{-19} ~\mathrm{erg \, s^{-1} \, cm^{-2}}$. While @nakajima2025 also report no clear detection of the line, they provide an upper limit that remains within the range expected for zero-metallicity stellar populations. Also note that the stellar continuum is undetected for this source.")}),
OIII5007_flux=(0.50e-19, 0.15e-19, {"digits": 1}), # I could not find a constraint on the EW for the [OIII]5007 line
OIIItoHb=(0.69, 0.28, {"digits": 2}),
OtoH=(6.31, 0.23, 0.15, {"digits": 2}),
metallicity=(4.2e-3, 1.8e-3, {"exponential": True, "digits": 1}),
reference="@nakajima2025"
))
'''
# LAP1 properties from previous measure of Vanzella+23 (https://ui.adsabs.harvard.edu/abs/2023A%26A...678A.173V/abstract)
table.add_row(dict(
ID="LAP1",
redshift=(6.639, 0.004, {"digits": 3}),
magnification="Yes", # mu_tot(median) = (120, 9), mu_tang(median) = (55, 6, 2), mu_tot > 500 for images A1,A2, mu_tot=98,99 for B1,B2
MUV=r"$> -11.2$",
Mstar=r"$\lesssim 10^4$",
Lya_flux=(369.2e-20, 29.3e-20, {"digits": 3}),
Lya_EW=r"$> 370$",
Ha_flux=(69.4e-20, 5.5e-20, {"digits": 2}),
Ha_EW=r"$> 2020$",
Hb_flux=(26.3e-20, 2.7e-20, {"digits": 2}),
Hb_EW=r"$> 420$",
HeII1640_flux=(79.6e-20, 20.7e-20, {"digits": 2, "note": note("g")}),
OIII5007_flux=(14.5e-20, 3.4e-20, {"digits": 2}),
OIII5007_EW=r"$> 246$",
OIIItoHb=(0.55, 0.14, 0.15, {"digits": 2}),
OtoH=r"$< 6.3$",
metallicity=r"$< 0.004$",
reference="@vanzella2023"
))
'''
table.add_row(dict(
ID="RX J2129-z8HeII",
redshift=(8.1623, 0.0007, {"digits": 4}),
magnification="Yes", # mu = (2.26, 0.14),
MUV=(-19.58, 0.02, 0.03, {"digits": 2}),
beta=(-2.53, 0.07, 0.06, {"digits": 2}),
Mstar=(5.6e7, 0.7e7, 0.8e7), # Tot. stellar mass of the system LogM*/Msun = 7.75 \pm 0.06 from Tab. 1
MIII=(7.8e5, 1.4e5), # Mass of the putative Pop III component estimated from the HeII luminosity
SFR=(9.56, 1.70, 4.51, {"digits": 2}),
Hb_flux=(71e-20, 10e-20, {"note": note("Intrinsic line fluxes and upper limits are reported after applying corrections for lensing magnification and dust extinction, adopting $A_\mathrm{V} = 0.12 \pm 0.04$ from their spectro-photometric analysis.")}),
Hb_EW=(202, 34, {"digits": 0}),
HeII1640_flux=(120e-20, 22e-20, {"digits": 2}),
HeII1640_EW=(21, 4, {"digits": 0}),
HeII4686_flux=r"$< 1.6 \times 10^{-19}$", # 2sigma upper limits
HeII4686_EW=r"$< 49$",
OIII5007_flux=(390e-20, 10e-20, {"digits": 2}),
OIII5007_EW=(1015, 83, {"digits": 0}),
OIIItoHb=(5.5, 0.8),
OtoH=(7.63, 0.09, 0.14, {"digits": 2}),
metallicity=r"$\sim 0.1$", # Log(Zstar/Zsun) ~ -0.9
reference="@wang2024"
))
table.add_row(dict(
ID="EXCELS-63107",
redshift=(8.271, {"digits": 3}),
magnification="No",
MUV=(-19.9, 0.1),
beta=(-3.3, 0.3),
Mstar=(3.72e8, 3.36e8, 4.05e8, {"digits": 2, "note": note(r"Assuming an extended star-formation history in which the stellar mass is built up steadily, but with a recent ~3 Myr burst of star formation, forming a mass of $(2.24_{-2.13}^{+1.48}) \times 10^7 ~\mathrm{M_\odot}$.")}), # Assuming extended SF + recent burst model and converting from log to linear --> LogMstar/Msun = 8.57 -1.03 +0.32 to linear, with mass of the burst LogMburst/Msun = 7.35 -1.30 +0.22 (see Sec. 3.3 and Tab. 3)
SFR=(7.8, 0.6), # From Hbeta
Hb_flux=(10.69e-19, 0.84e-19, {"digits": 3}),
OIII5007_flux=(38.54e-19, 1.20e-19, {"digits": 3}),
OIIItoHb=(3.61, 0.30, {"digits": 2}),
OtoH=(6.89, 0.21, 0.26, {"digits": 2, "note": note("Though this system is not metal-free, the authors suggest that an effective temperature $\gtrsim 80000$ K for the ionizing source is necessary (with no obvious sign of AGN heating), hardly explained with a standard IMF, and that exotic scenarios such as Pop III star formation within a mildly enriched halo would be consistent with the observation.")}), # The authors report that this is one of the lowest directly constrained oxygen abundances measured in any galaxy to date, and $\sim 10 \times$ lower than is typical for $z \simeq 8$ galaxies with the same stellar mass
metallicity=(0.016, {"digits": 3}),
reference="@cullen2025"
))
table.add_row(dict(
ID="Hebe (GN-z11)",
redshift=(10.5862, 0.003, {"digits": 4}), # From Ubler+26
magnification=("No", {"note": note("Although measured fluxes need to be corrected for a small magnification factor of 1.42, which is not accounted for in the reported line fluxes; see table 1 of @maiolino2026 for the corresponding de-lensed line luminosities.")}),
MIII=r"$\sim 2 \times 10^4 - 6 \times 10^5$", # From Rusta+26
OtoH=r"$< 6.96$", # 3sigma upper limits on 12+log(O/H) and Zgas from Ubler+26
metallicity=(r"$< 0.0019$", {"digits": 4}),
HeII1640_flux=(1.11e-19, 0.17e-19, {"digits": 2}), # Total fluxes and EWs from Tab. 1 of Maiolino+26
HeII1640_EW=r"$> 47$",
Lya_flux=r"$< 1.5 \times 10^{-18}$", # 3sigma upper limit from Sec. 8 of Maiolino+26
Hg_flux=(4.1e-20, 0.7e-20, {"digits": 1}), # Hg flux and EW from Ubler+26
Hg_EW=r"$> 350$",
reference="@maiolino2026, @ubler2026, @rusta2026"
))
'''
TODO:
- add Balmer jump to the table, where available
- check objects from Tiger's table https://docs.google.com/spreadsheets/d/1fUcRK6AGNtIf2qHyW31bLb2BuDMquJHNq7YIJ3zk8yc/edit?gid=0#gid=0 --> other page with possible Pop III descendants?
'''
# Markdown table
md = table_to_markdown(table, tablefmt="github", headers=headers, exponential=False, digits=1, col_fmt_overrides=col_fmt_overrides)
# Rendering including footnotes (we create two separate div for table and notes, so that the scrollable bar is immediately after the table instead of after the note list)
html = f"""
<div style="overflow-x: auto; width: 100%;">
{md}
</div>
{nm.render_notes_markdown()}
"""
Markdown(html)| Name |
Redshift |
12 + log(O/H) |
Metallicity [Z\(_\odot\)] |
\(M_\mathrm{III}\) [M\(_\odot\)] |
\(M_\star\) [M\(_\odot\)] |
SFR [M\(_\odot\)yr\(^{-1}\)] |
Lensed |
\(M_{\rm UV}\) |
\(\beta\)-slope |
HeII1640 flux [erg s\(^{-1}\) cm\(^{-2}\)] |
HeII1640 EW [Å] |
HeII1640 FWHM [km s\(^{-1}\)] |
HeII4686 flux [erg s\(^{-1}\) cm\(^{-2}\)] |
HeII4686 EW [Å] |
HeII4686 FWHM [km s\(^{-1}\)] |
[OIII]5007 flux [erg s\(^{-1}\) cm\(^{-2}\)] |
[OIII]5007 EW [Å] |
[OIII]5007 FWHM [km s\(^{-1}\)] |
[OIII]/H\(\beta\) |
Ly\(\alpha\) flux [erg s\(^{-1}\) cm\(^{-2}\)] |
Ly\(\alpha\) EW [Å] |
Ly\(\alpha\) FWHM [km s\(^{-1}\)] |
H\(\alpha\) flux [erg s\(^{-1}\) cm\(^{-2}\)] |
H\(\alpha\) EW [Å] |
H\(\alpha\) FWHM [km s\(^{-1}\)] |
H\(\beta\) flux [erg s\(^{-1}\) cm\(^{-2}\)] |
H\(\beta\) EW [Å] |
H\(\beta\) FWHM [km s\(^{-1}\)] |
H\(\gamma\) flux [erg s\(^{-1}\) cm\(^{-2}\)] |
H\(\gamma\) EW [Å] |
References |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| GNHeII J1236+6215 | \(2.9803 \pm 0.0010\) | \(7.85 \pm 0.22\) | \(0.003 \pm 0.002\) | — | \((7.8 \pm 3.1) \times 10^{8}\) | \(12.2 \pm 2.0\)\(^{\textcolor{red}{(a)}}\) | No | \(-22.09 \pm 0.02\) | \(-2.18 \pm 0.06\) | \((8.8 \pm 1.8) \times 10^{-18}\) | \(8.3\) | \(573 \pm 191\) | — | — | — | \((5.96 \pm 0.22) \times 10^{-17}\) | \(248.8\) | — | \(5.45 \pm 0.32\) | \((2.30 \pm 0.54) \times 10^{-17}\) | \(19.2\) | \(758 \pm 90\) | \((1.646 \pm 0.032) \times 10^{-17}\) | \(166.5\) | \(268 \pm 41\) | \((5.44 \pm 0.37) \times 10^{-18}\) | \(26.6\) | \(320 \pm 137\) | — | — | Mondal et al. (2025) |
| MPG-CR3 | \(3.193 \pm 0.016\) | \(< 6.52\) | \(< 8 \times 10^{-3}\) | \(6.1e+05\) | — | — | No | — | — | —\(^{\textcolor{red}{(c)}}\) | — | — | — | — | — | \(< 5.6 \times 10^{-19}\) | — | — | — | \((5.8 \pm 0.7) \times 10^{-17}\) | \(822 \pm 101\) | — | \((4.2 \pm 0.6) \times 10^{-18}\)\(^{\textcolor{red}{(b)}}\) | \(2814 \pm 327\) | — | \((6.3 \pm 0.7) \times 10^{-19}\) | — | — | — | — | Cai et al. (2025) |
| LAP2 | \(4.189 \pm 0.003\) | \(< 6.5\) | \(< 0.006\) | — | \(\approx (1.2 - 5.0) \times 10^4\) | — | Yes\(^{\textcolor{red}{(d)}}\) | \(\approx -12.2\) | — | — | \(< 80\) | — | — | — | — | \(< 5 \times 10^{-20}\) | — | — | — | \((2.64 {}^{+0.37}_{-0.38}) \times 10^{-18}\)\(^{\textcolor{red}{(e)}}\) | — | — | \((1.68 \pm 0.30) \times 10^{-19}\) | \(647 {}^{+302}_{-220}\) | — | \((7.2 \pm 2.6) \times 10^{-20}\) | — | — | — | — | Vanzella et al. (2026) |
| CAPERS-UDS-32520\(^{\textcolor{red}{(f)}}\) | \(5.1240 \pm 0.0002\) | \(7.88 \pm 0.07\) | \(< 0.15\) | — | \(\sim 10^9\) | — | No | \(-20.95 \pm 0.05\) | \(-1.68 \pm 0.05\) | — | — | — | — | — | — | \((2.96 \pm 0.04) \times 10^{-17}\) | \(946 \pm 46\) | — | — | — | — | — | \((1.38 \pm 0.02) \times 10^{-17}\) | \(734 \pm 33\) | — | \((4.3 \pm 0.3) \times 10^{-18}\) | \(137 \pm 13\) | — | \((2.8 \pm 0.3) \times 10^{-18}\) | \(35 \pm 4\) | Reumert et al. (2026) |
| AMORE6 | \(5.7253 \pm 0.0001\) | \(< 5.78\) | \(< 0.0012\) | — | \((4.37 {}^{+2.24}_{-0.73}) \times 10^{5}\) | \(0.35 \pm 0.06\)\(^{\textcolor{red}{(i)}}\) | Yes\(^{\textcolor{red}{(g)}}\) | \(-14.52 {}^{+0.07}_{-0.08}\)\(^{\textcolor{red}{(h)}}\) | \(-2.77 {}^{+0.07}_{-0.09}\) | — | — | — | — | — | — | \(< 1.1 \times 10^{-20}\) | — | — | — | \((4.95 \pm 0.92) \times 10^{-19}\) | — | — | — | — | — | \((4.9 \pm 0.6) \times 10^{-20}\) | \(1594.7 \pm 206.9\) | — | — | — | Morishita et al. (2025) |
| LAP1 | \(6.625 \pm 0.001\) | \(6.31 {}^{+0.15}_{-0.23}\) | \((4.2 \pm 1.8) \times 10^{-3}\) | — | \(\lesssim 2700\) | — | Yes | \(> -10.4\) | — | \(\lesssim 1.85 \times 10^{-19}\)\(^{\textcolor{red}{(j)}}\) | — | — | — | — | — | \((5.0 \pm 1.5) \times 10^{-20}\) | — | — | \(0.69 \pm 0.28\) | \((6.08 \pm 1.70) \times 10^{-19}\) | \(> 250\) | — | \((2.07 \pm 0.25) \times 10^{-19}\) | \(> 1800\) | — | \((7.3 \pm 2.0) \times 10^{-20}\) | \(> 340\) | — | — | — | Nakajima et al. (2025) |
| RX J2129-z8HeII | \(8.1623 \pm 0.0007\) | \(7.63 {}^{+0.14}_{-0.09}\) | \(\sim 0.1\) | \((7.8 \pm 1.4) \times 10^{5}\) | \((5.6 {}^{+0.8}_{-0.7}) \times 10^{7}\) | \(9.56 {}^{+4.51}_{-1.70}\) | Yes | \(-19.58 {}^{+0.03}_{-0.02}\) | \(-2.53 {}^{+0.06}_{-0.07}\) | \((1.20 \pm 0.22) \times 10^{-18}\) | \(21 \pm 4\) | — | \(< 1.6 \times 10^{-19}\) | \(< 49\) | — | \((3.90 \pm 0.10) \times 10^{-18}\) | \(1015 \pm 83\) | — | \(5.5 \pm 0.8\) | — | — | — | — | — | — | \((7.1 \pm 1.0) \times 10^{-19}\)\(^{\textcolor{red}{(k)}}\) | \(202 \pm 34\) | — | — | — | Wang et al. (2024) |
| EXCELS-63107 | \(8.271\) | \(6.89 {}^{+0.26}_{-0.21}\)\(^{\textcolor{red}{(m)}}\) | \(0.016\) | — | \((3.72 {}^{+4.05}_{-3.36}) \times 10^{8}\)\(^{\textcolor{red}{(l)}}\) | \(7.8 \pm 0.6\) | No | \(-19.9 \pm 0.1\) | \(-3.3 \pm 0.3\) | — | — | — | — | — | — | \((3.854 \pm 0.120) \times 10^{-18}\) | — | — | \(3.61 \pm 0.30\) | — | — | — | — | — | — | \((1.069 \pm 0.084) \times 10^{-18}\) | — | — | — | — | Cullen et al. (2025) |
| Hebe (GN-z11) | \(10.5862 \pm 0.0030\) | \(< 6.96\) | \(< 0.0019\) | \(\sim 2 \times 10^4 - 6 \times 10^5\) | — | — | No\(^{\textcolor{red}{(n)}}\) | — | — | \((1.11 \pm 0.17) \times 10^{-19}\) | \(> 47\) | — | — | — | — | — | — | — | — | \(< 1.5 \times 10^{-18}\) | — | — | — | — | — | — | — | — | \((4.1 \pm 0.7) \times 10^{-20}\) | \(> 350\) | Maiolino et al. (2026), Übler et al. (2026), Rusta et al. (2026) |
\(^{(a)}\) From photometric analysis, averaged over the last 10 Myr; from spectroscopic analysis: \(\mathrm{SFR}_\mathrm{UV} = (9.8 \pm 0.1) ~\mathrm{M_\odot yr^{-1}}\), \(\mathrm{SFR}_\mathrm{H\beta} = (7.6 \pm 0.4) ~\mathrm{M_\odot yr^{-1}}\), \(\mathrm{SFR}_\mathrm{H\alpha} = (7.5 \pm 0.1) ~\mathrm{M_\odot yr^{-1}}\), \(\mathrm{SFR}_\mathrm{Pa\beta} = (6.40 \pm 0.03) ~\mathrm{M_\odot yr^{-1}}\).
\(^{(b)}\) Includes a rescaling to account for potential flux losses, as the source lies near the edge of the MSA shutter.
\(^{(c)}\) HeII1640 line coinciding with strong OH skyline for this object.
\(^{(d)}\) The UV magnitude at 1700 Å for this source is de-lensed, while fluxes are not corrected for lensing. De-lensed fluxes were obtained by dividing by \(\mu_\mathrm{tot}\), assuming a total magnification factor of \(\mu_\mathrm{tot} = 50 \pm 5\).
\(^{(e)}\) From independent VLT/MUSE measure, \(f_\mathrm{Ly\alpha} = (5.50 \pm 0.58) \times 10^{-18} ~\mathrm{erg \, s^{-1} \, cm^{-1}}\).
\(^{(f)}\) The authors also examined a companion that serendipitously lies across the slit mask (therefore dubbing the whole system "banana and blueberry" due to its morphology, possibly hinting to a disturbed, merger-like origin), finding clear signatures of H\(\alpha\) emission, as well as potential HeI and HeII emission lines; however, they caution that photometric data for the "blueberry" system from the Minerva survey (Muzzin et al. (2025)) strongly favor a lower-redshift solution at \(z \sim 0.7\) (Willot, priv. comm.).
\(^{(g)}\) Properties for the stacked spectrum of the two images in the doubly lensed system, normalizing by the magnification factor of each image.
\(^{(h)}\) The absolute UV magnitude and the physical properties of AMORE6 from SED fitting are reported for only one of the two images (AMORE6-B), as the other one (AMORE6-A) suffers from large uncertainties, likely due to its location near bright galaxies as well as its smaller magnification factor (\(\mu = 39.32_{-3.48}^{+3.73}\), vs \(\mu = 77.69_{-5.92}^{+8.37}\) for AMORE6-B).
\(^{(i)}\) SFR inferred from H\(\beta\), larger than the value inferred from rest-frame UV luminosity – \((0.0186_{-0.0035}^{+0.0033}) ~\mathrm{M_\odot yr^{-1}}\) – or from averaging over the last 100 Myr of the best-fit star-formation history – \((0.0038_{-0.0007}^{+0.0017}) ~\mathrm{M_\odot yr^{-1}}\) –, suporting the presence of a very young burst.
\(^{(j)}\) Vanzella et al. (2023) previously estimated a line flux for HeII1640 of \((7.96 \pm 2.07) \times 10^{-19} ~\mathrm{erg \, s^{-1} \, cm^{-2}}\); however, the reliability of the HeII line detection was hampered by the presence of a small blueshift relative to the Balmer lines, and by the extreme required EW (\(\gtrsim 200\) Å), therefore the authors safely considered the line undetected, placing a \(1\sigma\) upper limit of \(2.7 \times 10^{-19} ~\mathrm{erg \, s^{-1} \, cm^{-2}}\). While Nakajima et al. (2025) also report no clear detection of the line, they provide an upper limit that remains within the range expected for zero-metallicity stellar populations. Also note that the stellar continuum is undetected for this source.
\(^{(k)}\) Intrinsic line fluxes and upper limits are reported after applying corrections for lensing magnification and dust extinction, adopting \(A_\mathrm{V} = 0.12 \pm 0.04\) from their spectro-photometric analysis.
\(^{(l)}\) Assuming an extended star-formation history in which the stellar mass is built up steadily, but with a recent ~3 Myr burst of star formation, forming a mass of \((2.24_{-2.13}^{+1.48}) \times 10^7 ~\mathrm{M_\odot}\).
\(^{(m)}\) Though this system is not metal-free, the authors suggest that an effective temperature \(\gtrsim 80000\) K for the ionizing source is necessary (with no obvious sign of AGN heating), hardly explained with a standard IMF, and that exotic scenarios such as Pop III star formation within a mildly enriched halo would be consistent with the observation.
\(^{(n)}\) Although measured fluxes need to be corrected for a small magnification factor of 1.42, which is not accounted for in the reported line fluxes; see table 1 of Maiolino et al. (2026) for the corresponding de-lensed line luminosities.