Public
Edited
Jul 1
Insert cell
Insert cell
Insert cell
housesales = FileAttachment("housesales-1.csv").csv()
Insert cell
parsedOne = await FileAttachment("housesales-1.csv").csv({typed:true})
.then(data =>
data
.map(d => ({
date: new Date(d.per_name),
value: +d.val,
dt_desc: d.dt_desc
}))
.filter(d => d.dt_desc === "Median Sales Price" && !isNaN(d.value))
);

Insert cell
Insert cell
import {vl} from "@vega/vega-lite-api-v5"
Insert cell
import {printTable} from "@uwdata/data-utilities"
Insert cell
import {Inputs} from "@observablehq/inputs"

Insert cell
Insert cell
# How have average sale prices of new single-family homes in the U.S. changed from 1963 through 2016, and which years exhibit the largest departures from the overall trend?
Insert cell
detailStatic = vl.markCircle()
.data(housesales)
.transform(
vl.filter("datum.dt_desc === 'Average Sales Price'")
)
.encode({
x: {
field: "per_name",
type: "temporal",
title: "Date"
},
y: {
field: "val",
type: "quantitative",
title: "Average Sales Price"
},
color: {
field: "val",
type: "quantitative",
scale: { range: ["green", "orange"] },
legend: { title: "Average Sales Price" }
},
tooltip: [
{ field: "per_name", type: "temporal", title: "Date" },
{ field: "val", type: "quantitative", title: "Average Price" }
]
})
.width(800)
.height(450)
.render()


Insert cell
Insert cell
{
const medianData = parsedOne.filter(d => d.dt_desc === "Median Sales Price");
const monthly = medianData.map(d => ({
...d,
monthName: d3.timeFormat("%b")(d.date)
}));

return vl.markBoxplot({ extent: 1.5 })
.data(monthly)
.encode({
x: {
field: "monthName", type: "ordinal",
sort: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
title: "Month"
},
y: {
field: "value", type: "quantitative",
title: "Median Sales Price"
},
color: {
field: "monthName", type: "ordinal",
scale: { scheme: "tableau10" },
legend: { title: "Month" }
}
})
.config({
boxplot: {
rule: { strokeWidth: 3 },
box: { strokeWidth: 1 },
median: { strokeWidth: 2 },
ticks: { strokeWidth: 2 }
}
})
.width(1000)
.height(300)
.title("Seasonal Distribution of Median Home Prices (All Years)")
.render();
}

Insert cell
parsed = (await FileAttachment("housesales-1.csv").csv({typed:true}))
.map(d => {
const date = new Date(d.per_name);
return {
year: date.getFullYear(),
monthName: date.toLocaleString("en", { month: "short" }),
value: +d.val,
dt_desc: d.dt_desc?.trim()
};
})
// keep only the two metrics
.filter(d =>
(d.dt_desc === "Median Sales Price" || d.dt_desc === "Average Sales Price") &&
!isNaN(d.value)
);

Insert cell
years = Array.from(new Set(parsed.map(d => d.year))).sort()

Insert cell

// 1. Dropdown for metric
viewof selectedMetric = Inputs.select(
["Median Sales Price","Average Sales Price"],
{ label: "Metric", value: "Median Sales Price" }
)



Insert cell
viewof selectedYear = Inputs.range(
[years[0], years[years.length - 1]],
{ step: 1, label: "Year" }
)

Insert cell
Insert cell

{

const monthly = parsed.filter(
d => d.dt_desc === selectedMetric && d.year === selectedYear
);


return vl.markBar({ cornerRadius: 3 })
.data(monthly)
.encode({
x: {
field: "monthName",
type: "ordinal",
sort: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
title: "Month"
},
y: {
field: "value",
type: "quantitative",
title: selectedMetric
},
color: {
field: "monthName",
type: "ordinal",
scale: { scheme: "tableau10" },
legend: { title: "Month" }
},
tooltip: [
{ field: "monthName", type: "ordinal", title: "Month" },
{ field: "value", type: "quantitative", title: selectedMetric }
]
})
.width(800)
.height(400)
.render();
}

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