Public
Edited
Feb 28, 2024
Insert cell
Insert cell
Insert cell
nbaLocations = FileAttachment("nba_team_locations-4.csv")
.csv({ typed: true })
.then((data) => data.map((d) => ({ ...d, Year: new Date(d['Opening Year'], 0) })))
Insert cell
usBoundaries = FileAttachment("us-10m.json").json()
Insert cell
nbaColorsAndLogos = FileAttachment("nba_color_codes-1.csv").csv({typed: true})
Insert cell
Insert cell
vl.markPoint()
.data(nbaLocations)
.encode(
vl.x().fieldQ('Long').scale({domain: [-125, -60]}),
vl.y().fieldQ('Lat').scale({domain: [24, 48]}),
vl.color().fieldN('Region')
)
.render()

Insert cell
{
const teamLocations = vl.markPoint()
.encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.color().fieldN('Region')
);
const teamLabel = vl.markText({align: 'left', dx:5, dy:5})
.encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.text().fieldN('Team')
);

const teamLogos = vl.markImage({width:'25', height:'20'})
.transform( //connect logos to team dataset
vl.lookup('Team').from(vl.data(nbaColorsAndLogos).key('Team').fields(['LogoSvgUrl']))
).encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.url().fieldN('LogoSvgUrl')
)

const usaOutline = vl.markGeoshape({fill: '#d3d3d3', stroke: '#a9a9a9'})
.data(vl.topojson(usBoundaries).feature('states'))
return vl.layer(usaOutline, teamLogos, teamLabel)
.data(nbaLocations)
.project(vl.projection('albersUsa'))
.width(700).height(700)
.render()
}
Insert cell
{
const regionSelector = vl.selectPoint('selected_region')
.fields('Region')
.on('mouseover')
.clear('mousehover')
.nearest('true');
const teamLocations = vl.markPoint()
.params(regionSelector)
.encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.color().fieldN('Region'),
vl.opacity().if(regionSelector, vl.value(0.9)).value(0.1),
vl.size().fieldQ('City Population')
);
const teamLabel = vl.markText({align: 'left', dx:5, dy:5})
.encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.text().fieldN('Team')
);

const teamLogos = vl.markImage({width:'25', height:'20'})
.transform( //connect logos to team dataset
vl.lookup('Team').from(vl.data(nbaColorsAndLogos).key('Team').fields(['LogoSvgUrl']))
).encode(
vl.longitude().fieldQ('Long'),
vl.latitude().fieldQ('AdjustedLat'),
vl.url().fieldN('LogoSvgUrl')
)

const usaOutline = vl.markGeoshape({fill: '#d3d3d3', stroke: '#a9a9a9'})
.data(vl.topojson(usBoundaries).feature('states'))
return vl.layer(usaOutline, teamLocations, teamLabel)
.data(nbaLocations)
.project(vl.projection('albersUsa'))
.width(700).height(700)
.render()
}
Insert cell
Insert cell
import {vl} from "@vega/vega-lite-api-v5"
Insert cell
import {toc} from "@jonfroehlich/collapsible-toc"
Insert cell
import {printVegaLiteJSON} from "@jonfroehlich/vega-lite-utilities"
Insert cell
import {printTable} from "@jonfroehlich/data-utilities"
Insert cell
import {printTableTypes} from "@jonfroehlich/data-utilities"
Insert cell
import {mean} from "@jonfroehlich/data-utilities"
Insert cell
import {median} from "@jonfroehlich/data-utilities"
Insert cell
import {standardDeviation} from "@jonfroehlich/data-utilities"
Insert cell
import {countOccurrencesMap} from "@jonfroehlich/data-utilities"
Insert cell
import {vegalite} from "@jonfroehlich/vega-lite-utilities"
Insert cell
// https://github.com/dcousens/haversine-distance
haversine = require('https://bundle.run/haversine-distance@1.2.1')
Insert cell
{
// FOR LATER - IGNORE FOR NOW :)
// Create an adjusted
for(let nbaLoc of nbaLocations){
nbaLoc.AdjustedLat = nbaLoc.Lat;
if(nbaLoc.Team.includes("Clippers")){
nbaLoc.AdjustedLat += -0.6;
}else if(nbaLoc.Team.includes("Nets")){
nbaLoc.AdjustedLat += -0.3;
}else if(nbaLoc.Team.includes("Knicks")){
nbaLoc.AdjustedLat += 0.2;
}else if(nbaLoc.Team.includes("Bucks")){
nbaLoc.AdjustedLat += 0.2;
}else if(nbaLoc.Team.includes("Pistons")){
nbaLoc.AdjustedLat -= 0.1;
}else if(nbaLoc.Team.includes("Spurs")){
nbaLoc.AdjustedLat -= 0.4;
}else if(nbaLoc.Team.includes("Thunder")){
nbaLoc.AdjustedLat += 0.2;
}
}
return nbaLocations; // an optional return (just makes it easier to see data)
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more