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
          }
        }
      ]
    }
  ]
}
py
import vgplot as vg

athletes = vg.parquet("data/athletes.parquet")

category = vg.selection.intersect()
query = vg.selection.intersect(include=[category])
hover = vg.selection.intersect(empty=True)

view = vg.hconcat(
    vg.vconcat(
        vg.hconcat(
            vg.menu(label="Sport", bind=category, source=athletes, column="sport"),
            vg.menu(label="Sex", bind=category, source=athletes, column="sex"),
            vg.search(
                label="Name",
                filter_by=category,
                bind=query,
                source=athletes,
                column="name",
                type="contains",
            ),
        ),
        vg.vspace(10),
        vg.plot(
            vg.dot(
                data=athletes,
                filter_by=query,
                x="weight",
                y="height",
                fill="sex",
                r=2,
                opacity=0.1,
            ),
            vg.regression_y(
                data=athletes, filter_by=query, x="weight", y="height", stroke="sex"
            ),
            vg.interval_xy(bind=query, brush=vg.brush(fill_opacity=0, stroke="black")),
            vg.dot(
                data=athletes,
                filter_by=hover,
                x="weight",
                y="height",
                fill="sex",
                stroke="currentColor",
                stroke_width=1,
                r=3,
            ),
            vg.xy_domain("Fixed"),
            vg.color_domain("Fixed"),
            vg.margins(left=35, top=20, right=1),
            vg.width(570),
            vg.height(350),
        ),
        vg.vspace(5),
        vg.table_input(
            source=athletes,
            max_width=570,
            height=250,
            filter_by=query,
            bind=hover,
            columns=["name", "nationality", "sex", "height", "weight", "sport"],
            width={
                "name": 180,
                "nationality": 100,
                "sex": 50,
                "height": 50,
                "weight": 50,
                "sport": 100,
            },
        ),
    ),
)