Public
Edited
Mar 10, 2023
Paused
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
// set the selection interactions to be able to select either an offense type, an offense category, or a time interval
const selectTimeBrush = vl.selectInterval().encodings("x");
// Use an OR operator on which time scrubber to use

const selectType = vl
.selectPoint("selected_pt")
.on("click") // select on click
.fields("Offense") // select all crimes of the same type
.bind("legend") // also bind to the legend
.clear("dblclick") // double click to clear selection
.toggle(true); // allow for multi-select (on by default) with shift-click
//draw the charts

const crimeTrends = vl
.markLine({ strokeWidth: 2 })
.data(vanCrime2)
// .transform(vl.filter(selectType))
//.transform(vl.filter(selectTimeBrushCat))
//.width(600)
.params(selectTimeBrush)
.title("VNon-Violent Crime Trends by Type Summer 2016")
.encode(
vl.x().fieldT("Date"),
vl.detail().fieldN("Offense"),
vl
.y()
.fieldQ("*")
.count()
.scale({ domain: [0, 60] }),
vl.color().fieldN("Offense Category").scale({ range: OffenseCatColors }),
vl.opacity().if(selectType, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.99, otherwise 0.1
);

const crimeBars = vl
.markBar()
//.width(600)
.data(vanCrime2)
.params(selectType)
.title("Vancouver Non-Violent Crime Total Offenses Summer 2016")
.transform(vl.filter(selectTimeBrush))
.encode(
vl.y().fieldN("Offense").scale({ domain: OffenseTypes }),
vl
.x()
.fieldQ("*")
.aggregate("count")
.scale({ domain: [0, 4400] }),
vl
.color()
.fieldN("Offense Category")
.scale({ range: OffenseCatColors })
.legend({ orient: "bottom", offset: -70 }),
// .if(selectedBar, vl.fieldN("Offense Category"))
// .value("grey"), // if point selected, use default color, otherwise grey
vl.opacity().if(selectType, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);
// const base = crimeBars.transform(vl.filter(timeSelector));
return vl.hconcat(crimeBars, crimeTrends).render();
}
Insert cell
Insert cell
viewof crimeViews = {
// set the selection interactions to be able to select either an offense type, an offense category, or a time interval
const selectTimeBrushCat = vl.selectInterval("tbrush").encodings("x");

const selectCat = vl
.selectPoint("selectedCat")
.on("click") // select on click
// .bind("legend")
.fields("Offense Category") // select all crimes of the same category
.toggle(true); // allow for multi-select (on by default) with shift-click

const selectType = vl
.selectPoint("selected_pt")
.on("click") // select on click
.fields("Offense", "Offense Category") // select all crimes of the same type
.toggle(true); // allow for multi-select (on by default) with shift-click

// mutable SelectedCategory = this.data("selectCat_store");

const crimeTrendsCat = vl
.markLine({ strokeWidth: 2 })
.data(vanCrime2)
.transform(vl.filter(selectType))
.params(selectTimeBrushCat)
.height(250)
.width(350)
.title("Non-Violent Crime Trends by Category Summer 2016")
.encode(
vl.x().fieldT("Date"),
vl
.y()
.fieldQ("*")
.count()
.scale({ domain: [0, 120] }),
vl.color().fieldN("Offense Category").scale({ range: OffenseCatColors }),
vl.opacity().if(selectCat, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.99, otherwise 0.1
);

const crimeBars = vl
.markBar()
.width(200)
.data(vanCrime2)
.params(selectType, selectCat)
.title("Vancouver Non-Violent Crime Offense Totals Summer 2016")
.transform(vl.filter(selectTimeBrushCat))
.encode(
vl.y().fieldN("Offense").scale({ domain: OffenseTypes }),
vl
.x()
.fieldQ("*")
.aggregate("count")
.scale({ domain: [0, 4400] }),
vl
.color()
.fieldN("Offense Category")
.scale({ range: OffenseCatColors })
.legend({ orient: "bottom", offset: -60 }),
// .if(selectedBar, vl.fieldN("Offense Category"))
// .value("grey"), // if point selected, use default color, otherwise grey
vl.opacity().if(selectType, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);
return vl.hconcat(crimeBars, crimeTrendsCat).render();
}
Insert cell
SelectedCategory = crimeViews.data("selectedCat_store")
Insert cell
SelectedType = crimeViews.data("selected_pt_store")
Insert cell
SelectedTime = crimeViews.data("tbrush_store")
Insert cell
Insert cell
Insert cell
clicked = Generators.observe((notify) => {
const clicked = (event, { datum }) => notify(datum);
cBars.addEventListener("click", clicked);
return () => cBars.removeEventListener("click", clicked);
})
Insert cell
Insert cell
Insert cell
{
// set the selection interactions to be able to select either an offense type, an offense category, or a time interval
const selectTimeBrush = vl.selectInterval().encodings("x").resolve('intersect');
const selectTimeBrushCat = vl.selectInterval().encodings("x").resolve('intersect');

// Use an OR operator on which time scrubber to use

const timeSelector = vl.or(
selectTimeBrush.empty(false), // If false, empty predicate will not select all values
selectTimeBrushCat.empty(false) // If false, empty predicate will not select all values
);

//console.log(tBrush);

const selectType = vl
.selectPoint("selected_pt")
.on("click") // select on click
.fields("Offense") // select all crimes of the same type
//.bind("legend") // also bind to the legend
.clear("dblclick") // double click to clear selection
.toggle(true); // allow for multi-select (on by default) with shift-click

const selectCat = vl
.selectPoint("selected_cat")
.on("click") // select on click
.fields("Offense Category") // select all crimes of the same category
.bind("legend") // also bind to the legend
.clear("dblclick") // double click to clear selection
.toggle(true); // allow for multi-select (on by default) with shift-click

//draw the charts

const crimeTrends = vl
.markLine({ strokeWidth: 2 })
.data(vanCrime2)
.transform(vl.filter(selectType || selectTimeBrushCat))
//.transform(vl.filter(selectTimeBrushCat))
//.width(600)
.params(selectTimeBrush)
.title("VNon-Violent Crime Trends by Type Summer 2016")
.encode(
vl.x().fieldT("Date"),
vl.detail().fieldN("Offense"),
vl
.y()
.fieldQ("*")
.count()
.scale({ domain: [0, 120] }),
vl.color().fieldN("Offense Category").scale({ range: OffenseCatColors }),
vl.opacity().if(selectType, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.99, otherwise 0.1
);

const crimeTrendsCat = vl
.markLine({ strokeWidth: 2 })
.data(vanCrime2)
// .transform(vl.filter(selectTimeBrush))
.transform(vl.filter(selectType || selectTimeBrush))
.params(selectTimeBrushCat)
.title("Non-Violent Crime Trends by Category Summer 2016")
.encode(
vl.x().fieldT("Date"),
vl
.y()
.fieldQ("*")
.count()
.scale({ domain: [0, 120] }),
vl.color().fieldN("Offense Category").scale({ range: OffenseCatColors }),
vl.opacity().if(selectCat, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);

const crimeBars = vl
.markBar()
//.width(600)
.data(vanCrime2)
.params(selectCat, selectType)
.title("Vancouver Non-Violent Crime Total Offenses Summer 2016")
.transform(vl.filter(selectTimeBrush))
.encode(
vl.y().fieldN("Offense").scale({ domain: OffenseTypes }),
vl
.x()
.fieldQ("*")
.aggregate("count")
.scale({ domain: [0, 4400] }),
vl.color().fieldN("Offense Category").scale({ range: OffenseCatColors }),
// .if(selectedBar, vl.fieldN("Offense Category"))
// .value("grey"), // if point selected, use default color, otherwise grey
vl.opacity().if(selectType, vl.value(0.99)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);
// const base = crimeBars.transform(vl.filter(timeSelector));
return vl
.vconcat(crimeBars, vl.hconcat(crimeTrends, crimeTrendsCat))
.render();
}
Insert cell
Tbrush = vl.selectInterval().encodings("x").name("Timebrush") //This name is the one you use in the signal listener
Insert cell
Bselect = vl
.selectPoint()
.on("click") // select on click
.fields("Offense Category") // select all crimes of the same type
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md `### Functions`
Insert cell
Insert cell
Insert cell
timeParse = d3.timeParse("%m/%d/%y")
Insert cell
dateFormat = d3.timeFormat("%m/%d/%y")
Insert cell
Insert cell
crimeCharts.addSignalListener("offenseSelect", function (name, value) {
if (value == null) mutable otype = null;
else mutable otype = value.Offense;
})
Insert cell
Insert cell
Insert cell
bSelection = {
if (isEmpty(otype)) {
return Array.from(new Set(vanCrime2.map((d) => d.Offense)));
} else {
return otype;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
//We are writing the event listener function for each feature in our geojson layer
function areaClick(feature, layer) {
layer.on({
click:whenClicked //callback function
});
}
Insert cell
//We update our data in the function using mutable. This overrides observables defaults so we can push data from within //function scope globally
whenClicked = (event) => {
mutable nHood = event.target.feature.properties.NAME
}
Insert cell
mutable nHood = null
Insert cell
mapSelection = {
if(nHood == null ){
return Array.from(new Set(vanCrime2.map(d => d.NEIGHBOURHOOD))) //Set is a new datastructure in ES6 -> only unique values
} else {
return [nHood]
}
}
Insert cell
Insert cell
Insert cell
Insert cell
vanCrimeFiltered = vanCrime.features
.filter((d) => bSelection.includes(d.properties.Offense))
.filter(
(d) =>
timeParse(d.properties.Date) >= timeParse(TSelection[0]) &&
timeParse(d.properties.Date) <= timeParse(TSelection[1])
)
.filter((d) => mapSelection.includes(d.properties.NEIGHBOURHOOD))
Insert cell
FilteredGeoCrimes = {
return new Object({type: "FeatureCollection", features: vanCrimeFiltered})
}
Insert cell
GeoCrimes = {
let k = FilteredGeoCrimes.features.length;
let i = 0;
let crimes = new Object({
type: "FeatureCollection",
features: vanCrimeFiltered
});
for (i = 0; i++; i < k) {
crimes.features[k].ID = k;
}
return crimes;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
heatLayer = L, require('leaflet.heat').catch(() => L.heatLayer)
Insert cell
embed = require("vega-embed@6")
Insert cell
mutable selectedMap = ["warmgreys"]
Insert cell
Insert cell
vanCrime = FileAttachment("vanCrime.json").json()
Insert cell
vanCrimeID = {
let i = vanCrime.features.length;
let j = 0;
let k = 0;
let temp = {};
let newCrimeArray = vanCrime.slice();
// for (k = 0; k < i; k++) {
// newCrimeArray.features[k] = vanCrime.features[k];
// }
return newCrimeArray;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vanAreas = FileAttachment("VanAreas.json").json()
Insert cell
vanAreaValues2 = d3.json("https://www.sfu.ca/~lyn/data/Urban/VancouverAreaSizeTopo.json")
Insert cell
Insert cell
Insert cell
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