Skip to content

Scatter Plot Matrix (SPLOM)

A scatter plot matrix enables inspection of pairwise bivariate distributions. Do points cluster or separate in some dimensions but not others? Select a region to highlight corresponding points across all plots.

Loading Example...

Specification

js
import * as vg from "@uwdata/vgplot";

await vg.coordinator().exec([
  vg.loadParquet("penguins", "data/penguins.parquet")
]);

const $brush = vg.Selection.single();

const defaultAttributes = [
  vg.xTicks(3),
  vg.yTicks(4),
  vg.xDomain(vg.Fixed),
  vg.yDomain(vg.Fixed),
  vg.colorDomain(vg.Fixed),
  vg.marginTop(5),
  vg.marginBottom(10),
  vg.marginLeft(10),
  vg.marginRight(5),
  vg.xAxis(null),
  vg.yAxis(null),
  vg.xLabelAnchor("center"),
  vg.yLabelAnchor("center"),
  vg.xTickFormat("s"),
  vg.yTickFormat("s"),
  vg.width(150),
  vg.height(150)
];

export default vg.vconcat(
  vg.hconcat(
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_length", y: "body_mass", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.yAxis("left"),
      vg.marginLeft(45),
      vg.width(185)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_depth", y: "body_mass", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "flipper_length", y: "body_mass", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "body_mass", y: "body_mass", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    )
  ),
  vg.hconcat(
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_length", y: "flipper_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.yAxis("left"),
      vg.marginLeft(45),
      vg.width(185)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_depth", y: "flipper_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "flipper_length", y: "flipper_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "body_mass", y: "flipper_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    )
  ),
  vg.hconcat(
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_length", y: "bill_depth", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.yAxis("left"),
      vg.marginLeft(45),
      vg.width(185)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_depth", y: "bill_depth", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "flipper_length", y: "bill_depth", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "body_mass", y: "bill_depth", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes
    )
  ),
  vg.hconcat(
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_length", y: "bill_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.yAxis("left"),
      vg.xAxis("bottom"),
      vg.marginLeft(45),
      vg.marginBottom(35),
      vg.width(185),
      vg.height(175)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "bill_depth", y: "bill_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.xAxis("bottom"),
      vg.height(175),
      vg.marginBottom(35)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "flipper_length", y: "bill_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.xAxis("bottom"),
      vg.height(175),
      vg.marginBottom(35)
    ),
    vg.plot(
      vg.frame({stroke: "#ccc"}),
      vg.dot(
        vg.from("penguins"),
        {x: "body_mass", y: "bill_length", fill: "species", r: 2}
      ),
      vg.intervalXY({as: $brush}),
      vg.highlight({by: $brush, opacity: 0.1}),
      ...defaultAttributes,
      vg.xAxis("bottom"),
      vg.height(175),
      vg.marginBottom(35)
    )
  )
);
yaml
meta:
  title: Scatter Plot Matrix (SPLOM)
  description: >
    A scatter plot matrix enables inspection of pairwise bivariate distributions.
    Do points cluster or separate in some dimensions but not others?
    Select a region to highlight corresponding points across all plots.
data:
  penguins: { file: data/penguins.parquet }
params:
  brush: { select: single }
plotDefaults:
  xTicks: 3
  yTicks: 4
  xDomain: Fixed
  yDomain: Fixed
  colorDomain: Fixed
  marginTop: 5
  marginBottom: 10
  marginLeft: 10
  marginRight: 5
  xAxis: null
  yAxis: null
  xLabelAnchor: center
  yLabelAnchor: center
  xTickFormat: s
  yTickFormat: s
  width: 150
  height: 150

# Below we explicitly enumerate every chart in the SPLOM.
# Such repetitions are easy to generate from a host language!
vconcat:
- hconcat:
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_length, y: body_mass, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    yAxis: left
    marginLeft: 45
    width: 185
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_depth, y: body_mass, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: flipper_length, y: body_mass, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: body_mass, y: body_mass, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }

- hconcat:
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_length, y: flipper_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    yAxis: left
    marginLeft: 45
    width: 185
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_depth, y: flipper_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: flipper_length, y: flipper_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: body_mass, y: flipper_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }

- hconcat:
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_length, y: bill_depth, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    yAxis: left
    marginLeft: 45
    width: 185
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_depth, y: bill_depth, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: flipper_length, y: bill_depth, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: body_mass, y: bill_depth, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }

- hconcat:
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_length, y: bill_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    yAxis: left
    xAxis: bottom
    marginLeft: 45
    marginBottom: 35
    width: 185
    height: 175
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: bill_depth, y: bill_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    xAxis: bottom
    height: 175
    marginBottom: 35
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: flipper_length, y: bill_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    xAxis: bottom
    height: 175
    marginBottom: 35
  - plot:
    - { mark: frame, stroke: "#ccc" }
    - { mark: dot, data: { from: penguins }, x: body_mass, y: bill_length, fill: species, r: 2 }
    - { select: intervalXY, as: $brush }
    - { select: highlight, by: $brush, opacity: 0.1 }
    xAxis: bottom
    height: 175
    marginBottom: 35
json
{
  "meta": {
    "title": "Scatter Plot Matrix (SPLOM)",
    "description": "A scatter plot matrix enables inspection of pairwise bivariate distributions. Do points cluster or separate in some dimensions but not others? Select a region to highlight corresponding points across all plots.\n"
  },
  "data": {
    "penguins": {
      "file": "data/penguins.parquet"
    }
  },
  "params": {
    "brush": {
      "select": "single"
    }
  },
  "plotDefaults": {
    "xTicks": 3,
    "yTicks": 4,
    "xDomain": "Fixed",
    "yDomain": "Fixed",
    "colorDomain": "Fixed",
    "marginTop": 5,
    "marginBottom": 10,
    "marginLeft": 10,
    "marginRight": 5,
    "xAxis": null,
    "yAxis": null,
    "xLabelAnchor": "center",
    "yLabelAnchor": "center",
    "xTickFormat": "s",
    "yTickFormat": "s",
    "width": 150,
    "height": 150
  },
  "vconcat": [
    {
      "hconcat": [
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_length",
              "y": "body_mass",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "yAxis": "left",
          "marginLeft": 45,
          "width": 185
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_depth",
              "y": "body_mass",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "flipper_length",
              "y": "body_mass",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "body_mass",
              "y": "body_mass",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        }
      ]
    },
    {
      "hconcat": [
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_length",
              "y": "flipper_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "yAxis": "left",
          "marginLeft": 45,
          "width": 185
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_depth",
              "y": "flipper_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "flipper_length",
              "y": "flipper_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "body_mass",
              "y": "flipper_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        }
      ]
    },
    {
      "hconcat": [
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_length",
              "y": "bill_depth",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "yAxis": "left",
          "marginLeft": 45,
          "width": 185
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_depth",
              "y": "bill_depth",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "flipper_length",
              "y": "bill_depth",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "body_mass",
              "y": "bill_depth",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ]
        }
      ]
    },
    {
      "hconcat": [
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_length",
              "y": "bill_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "yAxis": "left",
          "xAxis": "bottom",
          "marginLeft": 45,
          "marginBottom": 35,
          "width": 185,
          "height": 175
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "bill_depth",
              "y": "bill_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "xAxis": "bottom",
          "height": 175,
          "marginBottom": 35
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "flipper_length",
              "y": "bill_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "xAxis": "bottom",
          "height": 175,
          "marginBottom": 35
        },
        {
          "plot": [
            {
              "mark": "frame",
              "stroke": "#ccc"
            },
            {
              "mark": "dot",
              "data": {
                "from": "penguins"
              },
              "x": "body_mass",
              "y": "bill_length",
              "fill": "species",
              "r": 2
            },
            {
              "select": "intervalXY",
              "as": "$brush"
            },
            {
              "select": "highlight",
              "by": "$brush",
              "opacity": 0.1
            }
          ],
          "xAxis": "bottom",
          "height": 175,
          "marginBottom": 35
        }
      ]
    }
  ]
}