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,
},
),
),
)