Skip to content

Cis and nominal mapping¤

jaxqtl supports cis-eQTL mapping by scanning variants within a window around each gene (or other molecular feature).

Modes¤

jaxqtl exposes two cis-related scanning modes:

  • cis: per gene, compute variant-level statistics in the cis window and return the lead SNP plus a gene-level adjusted p-value (e.g. via permutation/Beta approximation or ACAT).
  • nominal: per gene, return statistics for all variants in the cis window.

For score-test ACAT mapping, SPA is strongly recommended. Pair SpaTest with ACAT; see Gene-level aggregation for calibration and execution details.

The Python mapper consumes a ReadyDataState whose genotype, expression, covariates, and offsets have already been aligned on IID. The CLI constructs this state internally.

The mapping state is an advanced interface

ReadyDataState is not currently re-exported from jaxqtl.map. Import it from jaxqtl.map.data when using the mapping function directly.

jaxqtl.map.data.ReadyDataState [source] ¤

Inputs aligned to a shared sample order and ready for mapping.

Construct this state with ReadyDataState.from_data so genotype samples, expression, covariates, and offsets are intersected and ordered consistently.

Attributes:

  • genotype: Open genoio dataset.
  • sample_ids: Retained sample IDs in mapping order.
  • expression: Aligned expression values and feature metadata.
  • covar: Covariate matrix with shape (n, p).
  • offset: Offset array with shape (n,), or scalar zero when absent.
  • read_options: Options applied to genotype block reads.
  • variant_filter: Global genoio filter applied before mapping.
from_data(genotype: Dataset, expression: ExpressionData, covar: DataFrame, offset: polars.dataframe.frame.DataFrame | None = None, keep_samples: list[str] | None = None, drop_samples: list[str] | None = None, read_options: jaxqtl.io._geno_engine.GenotypeReadOptions | None = None, min_maf: float | None = None, chromosome: str | None = None) -> ReadyDataState classmethod ¤

Align genotype, expression, covariates, and offsets on IID.

The retained sample order follows the genotype dataset after applying the optional sample filter. Only samples present in every input are retained. Covariates are converted to a JAX array, and min_maf becomes part of the lazy global variant filter. An optional chromosome label restricts genotype reads to that exact label.

Arguments:

  • genotype: Open genoio dataset.
  • expression: Expression data with sample IDs in its pheno and libsize frames.
  • covar: Polars frame containing iid and numeric covariate columns.
  • offset: Optional Polars frame containing iid and one offset column.
  • keep_samples: Optional sample IDs to retain from the genotype source.
  • drop_samples: Optional sample IDs to remove from the genotype source.
  • read_options: Genotype read options. Defaults to GenotypeReadOptions().
  • min_maf: Optional minimum minor allele frequency.
  • chromosome: Optional exact chromosome label to retain.

Returns:

A ReadyDataState whose inputs share the same samples and order.

Raises:

  • ValueError: If keep and drop filters are both supplied, an input contains duplicate IIDs, or genotype sample metadata lack iid.
  • AssertionError: If offset does not have exactly two columns after alignment.
iter_cis(self, window: int, *, tss_centered: bool = False, host_genotypes: bool = False) -> collections.abc.Iterator[jaxqtl.map.data.CisData] ¤

Yield aligned data for each phenotype's cis window.

Regions are read lazily from the genotype dataset. By default, each region spans window bases before the TSS through window bases after the TES. When tss_centered is true, both bounds are relative to the TSS. The lower coordinate is clipped to 1.

Arguments:

  • window: Cis window size in base pairs.
  • host_genotypes: Keep the reader's host buffer for fixed-block packing, avoiding a full-window device round trip.
  • tss_centered: Center both window bounds on the TSS when true.

Returns:

An iterator of CisData objects in phenotype order.


jaxqtl.map.map_cis(data: ReadyDataState, snp_test: AbstractHypothesisTest, gene_test: AbstractAggregateTest, mode: typing.Literal['cis', 'nominal'] = 'cis', window: int = 500000, verbose: bool = True, log: logging.Logger | None = None, seed: int = 123, *, tss_centered: bool = False) ¤

Yield cis or nominal eQTL mapping results in bounded DataFrame chunks.

Arguments:

  • data: Genotype/expression/covariate bundle aligned on IID.
  • snp_test: Hypothesis test to apply per variant (score or Wald).
  • gene_test: Gene-level p-value aggregation for cis mode. It is ignored in nominal mode.
  • mode: "cis" (per-gene lead SNP with multiple testing adjustment) or "nominal" (all variant stats).
  • window: Cis window size in base pairs.
  • verbose: Whether to emit progress logging.
  • log: Optional logger to use; defaults to module logger.
  • seed: PRNG seed for permutation and tie-breaking.
  • tss_centered: Center the window on the TSS when true. Otherwise, extend the window upstream of the TSS and downstream of the TES.

Returns:

An iterator of pl.DataFrame chunks. Each chunk may contain one or more genes.

Failure Modes:

Genes with no variants in the requested window or no phenotype variance are skipped. If every gene is skipped, the iterator yields one empty frame with the mode-specific schema.

In cis mode, a tested gene with no finite SNP-level p-values is retained as an invalid result row. Its lead and association fields are null, result_valid is false, and failure_reason is "no_finite_pvalues".

Raises:

  • ValueError: If mode is not "cis" or "nominal".