Public
Edited
Apr 17, 2023
Insert cell
Insert cell
Data1@4.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
viewof crash_data = aq // viewof shows the table view, but assigns the table value
.fromCSV(await FileAttachment("Data1@4.csv").text())
.view()
Insert cell
viewof hist =
vl.markBar()
.data(crash_data)
.encode(
vl.x().fieldQ('AGE').bin({maxbins: 100, minstep: 0.5}).axis({format: 'd', titleAnchor: 'start'}),
vl.y().count().title(null)
)
.render()
Insert cell
viewof scatter_distraction =
vl.markCircle({tooltip: {"content": "AGE"}})
.data(crash_data)
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DISTRACTION').as('DISTRACTED'),
vl.sum('NO_DISTRACTION').as('NOT_DISTRACTED')
)
)
.encode(
vl.x().fieldQ('DISTRACTED').scale({domain: [0, 11000]}),
vl.y().fieldQ('NOT_DISTRACTED')
)
.render()
Insert cell
viewof scatter_drunk =
vl.markCircle({tooltip: {"content": "AGE"}})
.data(crash_data)
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DRUNK').as('DRINKING'),
vl.sum('NOT_DRUNK').as('NO_DRINKING')
)
)
.encode(
vl.x().fieldQ('DRINKING').scale({domain: [0, 12000]}),
vl.y().fieldQ('NO_DRINKING')
)
.render()
Insert cell
viewof scatter_drugs =
vl.markCircle({tooltip: {"content": "AGE"}})
.data(crash_data)
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DRUGS').as('DRUGS_USED'),
vl.sum('NO_DRUGS').as('NO_DRUGS_USED')
)
)
.encode(
vl.x().fieldQ('DRUGS_USED').scale({domain: [0, 12000]}),
vl.y().fieldQ('NO_DRUGS_USED')
)
.render()
Insert cell
viewof bar_dirstraction =
vl.markBar({tooltip:true})
.data(crash_data)
.transform(
vl.filter("datum.DISTRACTION_TYPE !== 'no distraction'")
)
.encode(
vl.x().count(),
vl.y().fieldN("DISTRACTION_TYPE").sort(vl.count("count()").order("descending")),
vl.color().fieldN("DISTRACTION_TYPE"),
)
.render()
Insert cell
viewof bar_drunk =
vl.markBar({tooltip:true})
.data(MODIFIED_DATA)
.transform(
vl.filter("datum.DRINKING_TYPE !== 'no drinking'")
)
.encode(
vl.x().count(),
vl.y().fieldN("DRINKING_TYPE").sort(vl.count("count()").order("descending")),
vl.color().fieldN("DRINKING_TYPE"),
)
.render()
Insert cell
viewof bar_drugs =
vl.markBar({tooltip:true})
.data(crash_data)
.transform(
vl.filter("datum.DRUG_USE !== 'no'")
)
.encode(
vl.x().count(),
vl.y().fieldN("DRUG_USE").sort(vl.count("count()").order("descending")),
vl.color().fieldN("DRUG_USE").legend(null)
)
.render()
Insert cell
viewof bar_severity =
vl.markBar({tooltip:true})
.data(crash_data)
.transform(
vl.filter("datum.DCRASH_SEVERITY !== 'no distraction'")
)
.encode(
vl.x().fieldN("CRASH_SEVERITY").sort(vl.count("count()").order("descending")),
vl.y().count(),
vl.color().fieldN("CRASH_SEVERITY"),
)
.render()
Insert cell
viewof pie_severity =
vl.markArc({tooltip:true})
.data(crash_data)
.transform(
vl.filter("datum.DCRASH_SEVERITY !== 'no distraction'"),
)
.encode(
vl.theta().count(),
vl.color().fieldN("CRASH_SEVERITY")
.scale({domain: ["fatal injury", "severe injury", "nonvisible injury", "visible injury", "property damage only"], range: ["red", "orange", "yellow", "green", "blue"]}),
vl.tooltip().fieldQ("count"),
)
.render()

Insert cell
viewof line_severity =
vl.markLine()
.data(crash_data)
.transform(
vl.groupby(["CRASH_YEAR"])
)
.encode(
vl.x().fieldT("CRASH_YEAR").timeUnit('year'),
vl.y().count(),
vl.color().fieldN("CRASH_SEVERITY"),
vl.tooltip([
vl.fieldN("CRASH_SEVERITY"),
vl.count()
])
)
.render()

Insert cell
Insert cell
Insert cell
Insert cell
{
const height = 750;
const width = 750;
const scatterWidth = width * 0.35;
const scatterHeight = height * 0.2;
const histwidth = 3.75 * scatterWidth;
const histHeight = (height - scatterHeight) / 3 - (6 * 4);
const severitywidth = width * 0.585;
const severityheight = height * 0.2;

const brush = vl.selectInterval().encodings('x').resolve('intersect');

const hist =
vl.markBar()
.encode(
vl.x().fieldQ('AGE').title('Age Groups')
.bin({maxbins: 100, minstep: 0.5})
.axis({format: 'd', titleAnchor: 'start'}),
vl.y().count().title(null)
);
const hist_layer = vl.layer(
hist.params(brush).encode(vl.color().value('lightgrey')), // turn all grey
hist.transform(vl.filter(brush)));
const scatter_distraction =
vl.markCircle()
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DISTRACTION').as('DISTRACTED'),
vl.sum('NO_DISTRACTION').as('NOT_DISTRACTED')
)
)
.encode(
vl.x().fieldQ('DISTRACTED').scale({domain: [0, 11000]}).title('Distracted Driving'),
vl.y().fieldQ('NOT_DISTRACTED').title('Undistracted Driving'),
vl.color().if(brush, vl.value('green')).value('grey').scale({scheme: 'tableau10'}),
vl.opacity().if(brush, vl.value(0.8)).value(0.1),
vl.tooltip([
{field: 'AGE', type: 'ordinal', title: 'Age'},
{field: 'DISTRACTED', type: 'quantitative', title: 'Distracted'},
{field: 'NOT_DISTRACTED', type: 'quantitative', title: 'Not Distracted'}
])
);
const scatter_drunk =
vl.markCircle()
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DRUNK').as('DRINKING'),
vl.sum('NOT_DRUNK').as('NO_DRINKING')
)
)
.encode(
vl.x().fieldQ('DRINKING').scale({domain: [0, 12000]}).title('Drunk'),
vl.y().fieldQ('NO_DRINKING').title('Not Drunk'),
vl.color().if(brush, vl.value('green')).value('grey').scale({scheme: 'tableau10'}),
vl.opacity().if(brush, vl.value(0.8)).value(0.1),
vl.tooltip([
{field: 'AGE', type: 'ordinal', title: 'Age'},
{field: 'DRINKING', type: 'quantitative', title: 'Drunk'},
{field: 'NO_DRINKING', type: 'quantitative', title: 'Not Drunk'}
])
);
const scatter_drugs =
vl.markCircle()
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DRUGS').as('DRUGS_USED'),
vl.sum('NO_DRUGS').as('NO_DRUGS_USED')
)
)
.encode(
vl.x().fieldQ('DRUGS_USED').scale({domain: [0, 12000]}).title('Drugs Used'),
vl.y().fieldQ('NO_DRUGS_USED').title('No Drugs Used'),
vl.color().if(brush, vl.value('green')).value('grey').scale({scheme: 'tableau10'}),
vl.opacity().if(brush, vl.value(0.8)).value(0.1),
vl.tooltip([
{field: 'AGE', type: 'ordinal', title: 'Age'},
{field: 'DRUGS_USED', type: 'quantitative', title: 'Drugs Used'},
{field: 'NO_DRUGS_USED', type: 'quantitative', title: 'No Drugs Used'}
])
);
const bar_distraction =
vl.markBar()
.transform(
vl.filter("datum.DISTRACTION_TYPE !== 'no distraction'"),
vl.filter(brush)
)
.encode(
vl.x().count().scale({domain: [0, 25000]}).title(null),
vl.y().fieldN("DISTRACTION_TYPE").sort(vl.count("count()").order("descending")).title(null),
vl.color().fieldN("DISTRACTION_TYPE").legend(null),
vl.tooltip([
{field: 'DISTRACTION_TYPE', type: 'nominal', title: 'Type of Distraction'},
vl.x().count().title ('Number of crashes')
])
)
.title("Distraction Types");
const bar_drunk =
vl.markBar()
.transform(
vl.filter("datum.DRINKING_TYPE !== 'no drinking'"),
vl.filter(brush)
)
.encode(
vl.x().count().scale({domain: [0, 15000]}).title(null),
vl.y().fieldN("DRINKING_TYPE").sort(vl.count("count()").order("descending")).title(null),
vl.color().fieldN("DRINKING_TYPE").legend(null),
vl.tooltip([{field: 'DRINKING_TYPE', type: 'nominal', title: 'Level of Drunkenness'}, vl.x().count().title('Number of crashes')])
)
.title("Alcohol Related Crash Types");
const bar_drugs =
vl.markBar()
.transform(
vl.filter("datum.DRUG_USE !== 'no'"),
vl.filter(brush)
)
.encode(
vl.x().count().scale({domain: [0, 50000]}).title(null),
vl.y().fieldN("DRUG_USE").sort(vl.count("count()").order("descending")).title(null),
vl.color().fieldN("DRUG_USE").legend(null),
vl.tooltip([{field: 'DRUG_USE', type: 'nominal', title: 'Drugs Used?'}, vl.x().count().title('Number of Crashes')])
)
.title("Drugs Related Crash Types");
const bar_severity =
vl.markBar()
.transform(
vl.filter("datum.DCRASH_SEVERITY !== 'no distraction'"),
vl.filter(brush)
)
.encode(
vl.x().count().title(null).scale({domain: [0, 300000]}),
vl.y().fieldN("CRASH_SEVERITY").sort(vl.count("count()").order("descending")).title(null),
vl.color().fieldN("CRASH_SEVERITY").scale({scheme: 'tableau10'}),
vl.tooltip([{field: 'CRASH_SEVERITY', type: 'nominal', title: 'Level of Severity'}, vl.x().count().title("Number of Crashes")])
)
.title("Level of Crash Severity");
const line_severity =
vl.markLine()
.data(crash_data)
.transform(
vl.groupby(["CRASH_YEAR"])
)
.encode(
vl.x().fieldT("CRASH_YEAR").timeUnit('year').title(null),
vl.y().count().title(null),
vl.color().fieldN("CRASH_SEVERITY").scale({scheme: 'tableau10'}),
vl.tooltip([
{field: 'CRASH_SEVERITY', type: 'Nominal', title: 'Level of Severity'},
vl.x().count().title('Number of Crashes')
])
)
.title("Crash Severity Over Time")

return vl.vconcat(
vl.hconcat(
hist_layer.width(histwidth).height(histHeight)
),
vl.hconcat(
scatter_distraction.width(scatterWidth).height(scatterHeight),
scatter_drunk.width(scatterWidth).height(scatterHeight),
scatter_drugs.width(scatterWidth).height(scatterHeight),
).spacing({row: 30, column: 35}),
vl.hconcat(
bar_distraction.width(scatterWidth).height(scatterHeight),
bar_drunk.width(scatterWidth).height(scatterHeight),
bar_drugs.width(scatterWidth).height(scatterHeight)
),
vl.hconcat(
line_severity.width(severitywidth).height(severityheight),
bar_severity.width(severitywidth).height(severityheight)
)
).spacing(10).padding(10).data(crash_data).render();
}
Insert cell
Insert cell
crash_years = [2019, 2020, 2021, 2022]
Insert cell
MODIFIED_DATA = crash_data.derive({
YEAR: d => op.year(op.parse_date(d.CRASH_YEAR)),
})
Insert cell
{
const width = 1000;
const height = 700;
const scatter_sq = width * 0.47;
const hist_width = width * 0.33;
const num_hist = 1; // set to 1 to display only one histogram
const hist_height = (scatter_sq/num_hist)-(6*num_hist);

const brush = vl.selectInterval().encodings('x').resolve('intersect');

const crash_years = ["2019", "2020", "2021", "2022"];
const selection = vl.selectPoint()
.fields('YEAR')
.init({YEAR: crash_years[0]})
.bind(vl.radio(crash_years));

const selected_year = selection.value.year;

const hist = vl.markBar()
.transform(brush)
.encode(
vl.x().fieldQ('AGE')
.bin({maxbins: 100, minstep: 0.5})
.axis({format: 'd', titleAnchor: 'start'}),
vl.y().count().title(null)
);
const hist_layer = vl.layer(
hist.params(brush).encode(vl.color().value('lightgrey')), // turn all grey
hist.transform(vl.filter(brush))) // layer selected values on top in default blue
.height(hist_height)
.width(hist_width);

const scatter_distraction =
vl.markCircle({tooltip: {"content": "AGE"}})
.params(selection)
.height(scatter_sq).width(scatter_sq)
.transform (
vl.groupby('AGE')
.aggregate(
vl.sum('DISTRACTION').as('DISTRACTED'),
vl.sum('NO_DISTRACTION').as('NOT_DISTRACTED')
),
vl.filter(d => d.YEAR = selected_year)
)
.encode(
vl.x().fieldQ('DISTRACTED').scale({domain: [0, 11000]}),
vl.y().fieldQ('NOT_DISTRACTED'),
vl.color().if(brush, vl.value('green')).value('grey').scale({scheme: 'tableau10'}),
vl.opacity().if(brush, vl.value(0.8)).value(0.1)
);
// place the histograms and scatterplot
return vl.hconcat(
vl.vconcat(hist_layer, scatter_distraction).spacing({row: 10, column: 20}),
)
.data(MODIFIED_DATA)
.render();
}

Insert cell
{
const crash_years = [2019, 2020, 2021, 2022];
const selection = vl.selectPoint()
.fields('YEAR')
.init({YEAR: crash_years[0]})
.bind(vl.radio(crash_years));

const selected_year = selection.value.YEAR;

return vl.markBar({tooltip:true})
.data(MODIFIED_DATA)
.params(selection)
.transform(
vl.filter(d => d.YEAR === selected_year),
vl.filter("datum.DISTRACTION_TYPE !== 'no distraction'"),
)
.encode(
vl.x().count().scale({domain: [0, 25000]}),
vl.y().fieldN("DISTRACTION_TYPE").sort(vl.count("count()").order("descending")),
vl.color().fieldN("DISTRACTION_TYPE")
)
.render();
}

Insert cell
Insert cell
import { vl } from "@vega/vega-lite-api-v5"
Insert cell
import { aq, op } from '@uwdata/arquero'
Insert cell
import {uniqueValid} from '@uwdata/data-utilities'
Insert cell
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