Skip to content

Olympic Athletes

An interactive dashboard of athlete statistics. The menus and searchbox filter the display and are automatically populated by backing data columns.

Loading Example...

Specification

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

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

const $category = vg.Selection.intersect();
const $query = vg.Selection.intersect({include: [$category]});
const $hover = vg.Selection.intersect({empty: true});

export default vg.hconcat(
  vg.vconcat(
    vg.hconcat(
      vg.menu({label: "Sport", as: $category, from: "athletes", column: "sport"}),
      vg.menu({label: "Sex", as: $category, from: "athletes", column: "sex"}),
      vg.search({
        label: "Name",
        filterBy: $category,
        as: $query,
        from: "athletes",
        column: "name",
        type: "contains"
      })
    ),
    vg.vspace(10),
    vg.plot(
      vg.dot(
        vg.from("athletes", {filterBy: $query}),
        {x: "weight", y: "height", fill: "sex", r: 2, opacity: 0.1}
      ),
      vg.regressionY(
        vg.from("athletes", {filterBy: $query}),
        {x: "weight", y: "height", stroke: "sex"}
      ),
      vg.intervalXY({as: $query, brush: {fillOpacity: 0, stroke: "black"}}),
      vg.dot(
        vg.from("athletes", {filterBy: $hover}),
        {
          x: "weight",
          y: "height",
          fill: "sex",
          stroke: "currentColor",
          strokeWidth: 1,
          r: 3
        }
      ),
      vg.xyDomain(vg.Fixed),
      vg.colorDomain(vg.Fixed),
      vg.margins({left: 35, top: 20, right: 1}),
      vg.width(570),
      vg.height(350)
    ),
    vg.vspace(5),
    vg.table({
      from: "athletes",
      maxWidth: 570,
      height: 250,
      filterBy: $query,
      as: $hover,
      columns: ["name", "nationality", "sex", "height", "weight", "sport"],
      width: {name: 180, nationality: 100, sex: 50, height: 50, weight: 50, sport: 100}
    })
  )
);
yaml
meta:
  title: Olympic Athletes
  description: >
    An interactive dashboard of athlete statistics. The menus and searchbox
    filter the display and are automatically populated by backing data columns.
data:
  athletes: { file: data/athletes.parquet }
params:
  category: { select: intersect }
  query: { select: intersect, include: $category }
  hover: { select: intersect, empty: true } # select nothing when empty
hconcat:
- vconcat:
  - hconcat:
    - input: menu
      label: Sport
      as: $category
      from: athletes
      column: sport
    - input: menu
      label: Sex
      as: $category
      from: athletes
      column: sex
    - input: search
      label: Name
      filterBy: $category
      as: $query
      from: athletes
      column: name
      type: contains
  - vspace: 10
  - plot:
    - mark: dot
      data: { from: athletes, filterBy: $query }
      x: weight
      y: height
      fill: sex
      r: 2
      opacity: 0.1
    - mark: regressionY
      data: { from: athletes, filterBy: $query }
      x: weight
      y: height
      stroke: sex
    - select: intervalXY
      as: $query
      brush: { fillOpacity: 0, stroke: black }
    - mark: dot
      data: { from: athletes, filterBy: $hover }
      x: weight
      y: height
      fill: sex
      stroke: currentColor
      strokeWidth: 1
      r: 3
    xyDomain: Fixed
    colorDomain: Fixed
    margins: { left: 35, top: 20, right: 1 }
    width: 570
    height: 350
  - vspace: 5
  - input: table
    from: athletes
    maxWidth: 570
    height: 250
    filterBy: $query
    as: $hover
    columns: [name, nationality, sex, height, weight, sport]
    width: { name: 180, nationality: 100, sex: 50, height: 50, weight: 50, sport: 100 }
json
{
  "meta": {
    "title": "Olympic Athletes",
    "description": "An interactive dashboard of athlete statistics. The menus and searchbox filter the display and are automatically populated by backing data columns.\n"
  },
  "data": {
    "athletes": {
      "file": "data/athletes.parquet"
    }
  },
  "params": {
    "category": {
      "select": "intersect"
    },
    "query": {
      "select": "intersect",
      "include": "$category"
    },
    "hover": {
      "select": "intersect",
      "empty": true
    }
  },
  "hconcat": [
    {
      "vconcat": [
        {
          "hconcat": [
            {
              "input": "menu",
              "label": "Sport",
              "as": "$category",
              "from": "athletes",
              "column": "sport"
            },
            {
              "input": "menu",
              "label": "Sex",
              "as": "$category",
              "from": "athletes",
              "column": "sex"
            },
            {
              "input": "search",
              "label": "Name",
              "filterBy": "$category",
              "as": "$query",
              "from": "athletes",
              "column": "name",
              "type": "contains"
            }
          ]
        },
        {
          "vspace": 10
        },
        {
          "plot": [
            {
              "mark": "dot",
              "data": {
                "from": "athletes",
                "filterBy": "$query"
              },
              "x": "weight",
              "y": "height",
              "fill": "sex",
              "r": 2,
              "opacity": 0.1
            },
            {
              "mark": "regressionY",
              "data": {
                "from": "athletes",
                "filterBy": "$query"
              },
              "x": "weight",
              "y": "height",
              "stroke": "sex"
            },
            {
              "select": "intervalXY",
              "as": "$query",
              "brush": {
                "fillOpacity": 0,
                "stroke": "black"
              }
            },
            {
              "mark": "dot",
              "data": {
                "from": "athletes",
                "filterBy": "$hover"
              },
              "x": "weight",
              "y": "height",
              "fill": "sex",
              "stroke": "currentColor",
              "strokeWidth": 1,
              "r": 3
            }
          ],
          "xyDomain": "Fixed",
          "colorDomain": "Fixed",
          "margins": {
            "left": 35,
            "top": 20,
            "right": 1
          },
          "width": 570,
          "height": 350
        },
        {
          "vspace": 5
        },
        {
          "input": "table",
          "from": "athletes",
          "maxWidth": 570,
          "height": 250,
          "filterBy": "$query",
          "as": "$hover",
          "columns": [
            "name",
            "nationality",
            "sex",
            "height",
            "weight",
            "sport"
          ],
          "width": {
            "name": 180,
            "nationality": 100,
            "sex": 50,
            "height": 50,
            "weight": 50,
            "sport": 100
          }
        }
      ]
    }
  ]
}