Skip to content

Cross

The "cross" transform forms the Cartesian product of its primary input and a finite eager foreign data source. It emits one flat row for every pair of primary and foreign rows.

For example, crossing:

x
1
2

with:

y
A
B
C

produces:

x y
1 A
1 B
1 C
2 A
2 B
2 C

Primary-input order is the outer order, and foreign-input order is the inner order. An empty input on either side produces no rows.

Parameters

description
Type: string

A description of the transform step. Can be used for documentation and agent context.

from Required
Type: CrossInput

The finite eager foreign data and its optional preprocessing transforms.

Foreign Data

from.data accepts finite eager data, including inline values, URLs, named data, and generated sequences. Lazy data sources are not supported because the complete foreign relation must be available before primary rows are crossed.

Optional transforms in from.transform preprocess the foreign data. This pipeline supports ordinary unary transforms. Transforms that require another side input are not supported there.

{
  "type": "cross",
  "from": {
    "data": {
      "sequence": { "start": 0, "stop": 3, "as": "y" }
    },
    "transform": [
      {
        "type": "formula",
        "expr": "datum.y * 10",
        "as": "scaledY"
      }
    ]
  }
}

Fields

Each output row is a new shallow object containing all primary fields followed by all foreign fields. A field name must occur on only one side. The transform throws an error when primary and foreign data contain a duplicate field name.

Use project before crossing to select or rename primary fields. Use project in from.transform to select or rename foreign fields.

The transform preserves primary batch boundaries. All foreign rows are treated as one finite relation; partition-aware foreign matching is not supported.

Example

The following example crosses two generated sequences and derives a value for each heatmap cell:

{
  "description": "Cross two generated sequences to form a heatmap grid.",

  "data": {
    "sequence": { "start": 0, "stop": 6, "as": "x" }
  },

  "transform": [
    {
      "type": "cross",
      "from": {
        "data": {
          "sequence": { "start": 0, "stop": 4, "as": "y" }
        }
      }
    },
    {
      "type": "formula",
      "expr": "datum.x + 1",
      "as": "x2"
    },
    {
      "type": "formula",
      "expr": "datum.y + 1",
      "as": "y2"
    },
    {
      "type": "formula",
      "expr": "(datum.x + 1) * (datum.y + 1)",
      "as": "value"
    }
  ],

  "width": 300,
  "height": 180,

  "mark": "rect",

  "encoding": {
    "x": {
      "field": "x",
      "type": "quantitative",
      "axis": { "title": "Primary sequence", "tickMinStep": 1 }
    },
    "x2": { "field": "x2" },
    "y": {
      "field": "y",
      "type": "quantitative",
      "axis": { "title": "Foreign sequence", "tickMinStep": 1 }
    },
    "y2": { "field": "y2" },
    "color": {
      "field": "value",
      "type": "quantitative",
      "scale": { "scheme": "viridis" }
    }
  }
}