Related to figure 4 g, Ifng and Ifngr1 log2 fold change of gene expression in CD8+ T-cell subsets within the TME 4 and 8 days post-adoptive T-cell transfer. Statistically significant expression levels are colored to indicate their upregulation in Pmel1.IL15 (red) or Pmel1.IL21.IL15 (blue) groups.
Bayesian Poisson DGE contrast¶
This notebook documents (briefly) how the Fig. 4g table is produced:
- Prepared long-form count table (from
report_16_tcell_macrophage_enrichment_analysis.ipynb) - Bayesian Poisson GLM fit (script:
xenium_possion_dge_model_tcell_skin.py) — run offline / HPC - Posterior summarization into a final results table (script:
posterior_analysis_dge_poisson.py)
Key point: the contrast reported for Fig. 4g is a posterior median ln fold-change (log rate ratio) computed as
( \Delta = \beta_{Both} - \beta_{IL-15} ),
with uncertainty summarized by the 95% HDI and a two-sided posterior tail probability analogue.
0) Imports + paths¶
Update the PATH_MODEL and filenames to match where you store the prepared long table and saved traces (.pkl).
import os
import pandas as pd
# Large input files for this notebook are hosted on Zenodo; download and unpack the Zenodo bundle locally and set the base data path below to your local folder.
DATA_ROOT = "data_external/nguyenlab-il15act-dataset-v1"
PATH_MODEL = DATA_ROOT
# Long-form input table (created in the preparation notebook)
INFILE_LONG = "02_tables_inputs/skin_tcell_long_counts.csv"
# Trace pickle produced by the model script
TRACE_PKL = "06_models/possion_dge/trace_cd8subsets_day4.pkl"
# Where to write outputs
OUTDIR = "./outputs"
os.makedirs(OUTDIR, exist_ok=True)
1) Data preparation (what happens upstream)¶
The preparation notebook report_16_tcell_macrophage_enrichment_analysis.ipynb produces a long-form table with (at least) these columns:
expr: gene-level counts per observation (cell / spot / aggregated unit)size: library size / exposure (used as log-offset)gene_namecondition(TCR / IL-15 / IL-21 / Both)batchannotation(cell subtype label; used to filter to the CD8⁺ subset of interest)day(e.g., 4 or 8)
This notebook assumes INFILE_LONG already exists.
df_long = pd.read_csv(os.path.join(PATH_MODEL, INFILE_LONG))
df_long.head()
2) Model fitting (run offline / HPC)¶
The Bayesian Poisson GLM is fit by xenium_possion_dge_model_tcell_skin.py.
The script filters to a specific day and cell subtype annotation and fits:
- Poisson likelihood with log link
- log-offset:
log(size) - gene- and condition-specific effects (
beta[gene, condition]) - batch effect (
rho[batch]) - additional gene and condition terms (
lam,delta)
Typical command:
python xenium_possion_dge_model_tcell_skin.py \
--infile skin_tcell_long_counts.csv \
--outfile trace_cd8subsets_day4.pkl \
--day 4 \
--celltype "CD8_T_subtype_name"
This notebook starts from the saved trace (TRACE_PKL).
3) Posterior summarization → final table for Fig. 4g¶
We use the helper class in posterior_analysis_dge_poisson.py to:
- load the long table + trace
- compute the posterior contrast Both − IL-15 for each gene:
FC: posterior median of (\beta_{Both} - \beta_{IL-15}) (ln fold-change / log rate ratio)hdi_lower,hdi_upper: 95% HDIpv: two-sided posterior tail probability analogue
import sys
# If this notebook lives next to posterior_analysis_dge_poisson.py, this will work.
# Otherwise, add the directory containing that file to sys.path.
sys.path.append(".")
from posterior_analysis_dge_poisson import analysis_skin
ana = analysis_skin(path_data=PATH_MODEL, trace_name=TRACE_PKL, data_name=INFILE_LONG)
table_all = ana.table_skin
table_all.head()
3a) Extract the Fig. 4g subset (Ifng / Ifngr1; Both vs IL-15)¶
Adjust the CELLTYPE, DAY, and gene list as needed to exactly match the panel.
GENES_OF_INTEREST = ["Ifng", "Ifngr1"]
COMPARISON = "Both_vs_IL-15" # matches analysis_skin output 'comparison' column
# Subset to the comparison + genes
table_fig4g = table_all.query("comparison == @COMPARISON and gene_name in @GENES_OF_INTEREST").copy()
table_fig4g
4) Save the final table¶
This file is the final tabular output used for Fig. 4g.
out_csv = os.path.join(OUTDIR, "fig4g_ifng_ifngr1_posterior_lnFC.csv")
table_fig4g.to_csv(out_csv, index=False)
out_csv
Notes on interpretation (caption-ready)¶
FCis posterior median ln fold-change (log rate ratio) for Both vs IL-15.- Effects are considered credibly non-zero when the 95% HDI excludes 0.
- If you ever want log2FC, convert as:
log2FC = FC / ln(2).