Skip to content

Facet

The facet operator repeats a plot for each category in a dataset, making it easy to compare groups using the same marks and scales.

Basic Examples

Wrapped Plots

{
  "description": "Anscombe's Quartet",

  "data": { "url": "vega-datasets/anscombe.json" },

  "facet": { "field": "Series" },

  "columns": 2,

  "spec": {
    "view": { "stroke": "lightgray" },
    "mark": "point",
    "encoding": {
      "x": { "field": "X", "type": "quantitative" },
      "y": { "field": "Y", "type": "quantitative" }
    }
  }
}

Data: Anscombe's quartet, served unchanged from vega-datasets.

Genomic Tracks

A BigWig URL template adds a sample field to records from five files. The row facet groups by that field, with overlay-title labels inside the plots. A shared samples parameter supplies the URLs and facet domain, keeping all five tracks navigable over empty regions.

{
  "description": [
    "Five H3K27ac BigWigs",
    "Using the facet operator to create a multi-track view of the same region across multiple samples."
  ],

  "params": [
    {
      "name": "samples",
      "value": [
        "forebrain-e12-5-rep1",
        "forebrain-e12-5-rep2",
        "heart-e12-5-rep1",
        "heart-e12-5-rep2",
        "limb-e12-5-rep1"
      ]
    }
  ],

  "data": {
    "lazy": {
      "type": "bigwig",
      "url": {
        "template": "https://data.genomespy.app/datasets/encode-mouse-fetal-development-mm10/v4/bigwigs/{sample}.bigWig",
        "values": { "expr": "samples" },
        "field": "sample"
      }
    }
  },

  "scales": {
    "x": {
      "domain": [
        { "chrom": "chr10", "pos": 82400000 },
        { "chrom": "chr10", "pos": 92400000 }
      ],
      "assembly": "mm10"
    }
  },

  "facet": {
    "row": {
      "field": "sample",
      "domain": { "expr": "samples" },
      "header": { "style": "overlay-title", "offset": 0, "dx": 5 }
    }
  },
  "spec": {
    "mark": { "type": "rect", "color": "#4c78a8", "minWidth": 0.5 },
    "encoding": {
      "x": {
        "chrom": "chrom",
        "pos": "start",
        "type": "locus",
        "axis": { "grid": true, "chromGrid": true }
      },
      "x2": { "chrom": "chrom", "pos": "end" },
      "y": {
        "field": "score",
        "type": "quantitative",
        "scale": { "zero": true },
        "axis": { "title": null, "tickCount": 2, "labelFlush": true }
      }
    }
  }
}

These regional BigWigs retain H3K27ac values from five released ENCODE files produced by the Bing Ren laboratory for Gorkin et al. (2020). Only the displayed 10 Mb mm10 region was retained.

Sample Collections in GenomeSpy App

For very large datasets, GenomeSpy App's sample views provide more efficient rendering and interactions than facets. Each layer can partition its own data source using the sample channel; Core facets partition one shared input. The App displays sample metadata alongside tracks and supports interactive sorting, filtering, and grouping. The App BigWig example shows the same five signal tracks using a sample view.

Defining a Facet

The facet property specifies how to group the data, and spec defines the plot repeated for each group. Both properties are required. The facet can declare shared data alongside them or inherit it from a parent view.

Arrangement facet definition
Columns {"field": "group"} or {"column": {"field": "group"}}
Rows {"row": {"field": "group"}}
Matrix {"row": {"field": "Origin"}, "column": {"field": "Cylinders"}}

The repeated spec can be a single plot, a layered plot, or an import that resolves to a unit, layer, or multiscale plot. Concatenations and nested facets are not supported inside spec.

Other properties are covered in the common view reference.

Facet Fields

Row and column categories can be ordered independently.

description

Type: string

A description of the encoded field. Can be used for documentation and to explain the meaning of the channel mapping.

domain

Type: Scalar[] | ExprRef

Categories to display, including empty cells. An expression reference can supply a reactive category array. Values outside the domain have no cells.

Default value: Categories found in the input data.

field

Type: string

Required. A string defining the name of the field from which to pull a data value.

See also: field documentation.

Notes: 1) Dots (.) and brackets ([ and ]) can be used to access nested objects (e.g., "field": "foo.bar" and "field": "foo['bar']"). If field names contain dots or brackets but are not nested, you can use \\ to escape dots and brackets (e.g., "a\\.b" and "a\\[0\\]"). See more details about escaping in the Vega-Lite field documentation.

header

Type: FacetHeader | null

Category label options. null hides labels and the field title, reclaiming their space.

sort

Type: "ascending" | "descending" | Scalar[]

Category order. An array places listed values first, followed by unlisted values in domain or input order. Sorting does not add cells.

Default value: Domain order when domain is specified; otherwise "ascending".

title

Type: string | Title | null

A shared title for this facet dimension. A string uses the regular view title style; an object supports view-title placement and styling. Row titles default to the left, and column titles to the top. Set to null to hide the title.

Default value: The field name.

Layout

Wrapping

The single-field form, "facet": {"field": "group"}, places cells in one row by default. Set "columns": 2 to wrap into rows of at most two plots. columns cannot be combined with facet.row or facet.column.

Spacing

The spacing property sets gaps between cells: a number sets both directions, and an object such as {"row": 10, "column": 20} sets them separately. Zero removes the gap; hidden headers add no space.

column

Type: number

Horizontal gap in pixels. Default value: 10

row

Type: number

Vertical gap in pixels. Default value: 10

Sizing and Scrolling

The repeated plot's width and height determine each cell's size, using the same sizing rules as concatenated views. Without fixed cell dimensions, the facets share the available container space.

Set viewportWidth or viewportHeight on the facet container to scroll the grid. Headers and axes scroll and clip with it. Child viewports are not supported.

Headers

Headers combine a shared field title, such as “Origin”, with category labels, such as “Europe” and “Japan”. Both use view-title styling and placement. A title inside the repeated spec labels each plot instead.

labels

Type: boolean

Whether category labels are shown. Hidden labels reserve no space.

Default value: true

format

Type: string

D3 number format for numeric category labels, for example ".1f" or ",.0f". String and boolean categories retain their original labels.

Category Labels

Set header to null to hide both labels and the field title, or to {"labels": false} to preserve the title.

Labels default to centered above columns and rotated beside rows. For horizontal, right-aligned row labels, use:

"row": {
  "field": "group",
  "header": { "angle": 0, "align": "right" }
}

Named title styles include track-title for horizontal track labels and overlay-title for labels inside the plot.

Header Defaults

config.header supplies shared defaults; config.headerRow and config.headerColumn override them per channel. Named styles override config, and explicit header properties override styles.

Scales and Guides

Scales are shared across cells, with legends drawn once beside the grid. Axes appear along the outer edges: one horizontal axis per occupied column and one vertical axis per row. In incomplete wrapped rows, bottom axes follow the last occupied cell in each column. Grid lines remain in every cell.

Layers can retain separate non-positional scales, each shared across cells.

Transforms and Data Scope

Transforms on the facet specification run before grouping. Transforms inside spec run independently for each group. For example, an aggregate without groupby computes one mean per facet:

{
  "description": "Facet-local means",

  "data": {
    "values": [
      { "group": "A", "value": 1 },
      { "group": "B", "value": 10 },
      { "group": "A", "value": 3 },
      { "group": "B", "value": 20 }
    ]
  },

  "facet": { "field": "group" },
  "spec": {
    "name": "means",
    "transform": [
      {
        "type": "aggregate",
        "fields": ["value"],
        "ops": ["mean"],
        "as": ["mean"]
      }
    ],
    "mark": { "type": "text", "size": 32 },
    "encoding": {
      "x": { "value": 0.5 },
      "y": { "value": 0.5 },
      "text": { "field": "mean" }
    }
  }
}

Child transforms can drop facet fields without changing cell membership. Include those fields in aggregate or project output if later transforms need them. Child filters can leave empty cells; without an explicit domain, outer filters remove groups before cells are created.

A child or layer with its own data repeats its result in every cell. That dataset is not partitioned, even if it contains the facet fields.

Interactions

Picking and tooltips use the pointed cell's data. Pan and zoom update shared scales across all cells and also work in the gaps between them. Point and interval selections also share their state across cells.

Differences from Vega-Lite

Vega-Lite's facet encoding shortcuts, independent per-cell resolution, time formatting, and sorting by another field or aggregate are not supported. Header styling uses view-title names such as angle and align, rather than labelAngle and labelAlign.