Published
Edited
May 6, 2021
1 fork
1 star
Insert cell
md`# Heatmap`
Insert cell
d3 = require("d3@6")
Insert cell
file = FileAttachment("new_data3.csv")
Insert cell
data = d3.csvParse(await file.text())
Insert cell
groupBy = keys => array =>
array.reduce((objectsByKeyValue, obj) => {
const value = keys.map(key => obj[key]).join('-');
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
return objectsByKeyValue;
}, {});
Insert cell
{
var new_data = groupBy(['Occur_date']);
return new_data
}
Insert cell
function groupArrayOfObjects(list, key) {
return list.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
Insert cell
new_array1 = {
var date_array = []
var countObject = groupArrayOfObjects(data,"Occur_date")
Object.keys(countObject).forEach(function(key,index) {
var new_object = {
"Occur_date": new Date(key),
"count": countObject[key].length
}
date_array.push(new_object)
// key: the name of the object key
// index: the ordinal position of the key within the object
})
return date_array
}
Insert cell
// Group data by year
years = d3.groups(new_array, d => d.Occur_date.getUTCFullYear()).reverse()
Insert cell
chart = {
//create a svg tag
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height*3])
.attr("font-family", "sans-serif")
.attr("font-size", 10);
svg.append("text")
.attr("x", (width / 2))
.attr("y", 20)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Value vs Date Graph");
//Add year label on the top left corner
const year = svg.selectAll("g")
.data(years)
.join("g")
.attr("transform", (d, i) => `translate(40.5,${height * i + cellSize * 1.5})`);

year.append("text")
.attr("x", -5)
.attr("y", -5)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(([key]) => key);
// Add small rectangle for each day whose color represents the count of crime
year.append("g")
.selectAll("rect")
.data(weekday === "weekday"
? ([, values]) => values.filter(d => ![0, 6].includes(d.Occur_date.getUTCDay()))
: ([, values]) => values)
.join("rect")
.attr("width", cellSize - 1)
.attr("height", cellSize - 1)
.attr("x", d => timeWeek.count(d3.utcYear(d.Occur_date), d.Occur_date) * cellSize + 0.5)
.attr("y", d => countDay(d.Occur_date.getUTCDay()) * cellSize + 0.5)
.attr("fill", d => color_ord(d.absolute))
.append("title")
.text(d => `${formatDate(d.Occur_date)}
${d.absolute.toLocaleString("en")} crime`);
// Add weekday text to the left of heatmap
year.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(weekday === "weekday" ? d3.range(1, 6) : d3.range(7))
.join("text")
.attr("x", -5)
.attr("y", i => (countDay(i) + 0.5) * cellSize)
.attr("dy", "0.31em")
.text(formatDayNew);
// Add month text on the top of heatmap
const month = year.append("g")
.selectAll("g")
.data(([, values]) => d3.utcMonths(d3.utcMonth(new Date(2020, 1, 1)), new Date(2020, 12, 1)))
.join("g");
// Change stroke color and width to distinguish month
month.filter((d, i) => i).append("path")
.attr("fill", "none")
.attr("stroke", "#fff")
.attr("stroke-width", 3)
.attr("d", pathMonth);

month.append("text")
.attr("x", d => timeWeek.count(d3.utcYear(d), timeWeek.ceil(d)) * cellSize + 2)
.attr("y", -5)
.text(formatMonth);
return svg.node();
}
Insert cell
chart_2019 = {
//create a svg tag
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height+9.5])
.attr("font-family", "sans-serif")
.attr("font-size", 10);
svg.append("text")
.attr("x", (width / 2))
.attr("y", 15)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Crime heatmap in 2019");
//Add year label on the top left corner
const year = svg.selectAll("g")
.data([years[0]])
.join("g")
.attr("transform", (d, i) => `translate(40.5,${height * i + cellSize * 1.5 + 5})`);

year.append("text")
.attr("x", -5)
.attr("y", 0)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(([key]) => key);
// Add small rectangle for each day whose color represents the count of crime
year.append("g")
.selectAll("rect")
.data(weekday === "weekday"
? ([, values]) => values.filter(d => ![0, 6].includes(d.Occur_date.getUTCDay()))
: ([, values]) => values)
.join("rect")
.attr("width", cellSize - 1)
.attr("height", cellSize - 1)
.attr("x", d => timeWeek.count(d3.utcYear(d.Occur_date), d.Occur_date) * cellSize + 0.5)
.attr("y", d => countDay(d.Occur_date.getUTCDay()) * cellSize + 10)
.attr("fill", d => color_ord(d.absolute))
.append("title")
.text(d => `${formatDate(d.Occur_date)}
${d.absolute.toLocaleString("en")} crime`);
// Add weekday text to the left of heatmap
year.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(weekday === "weekday" ? d3.range(1, 6) : d3.range(7))
.join("text")
.attr("x", -5)
.attr("y", i => (countDay(i) + 0.5) * cellSize + 9.5)
.attr("dy", "0.31em")
.text(formatDayNew);
// Add month text on the top of heatmap
const month = year.append("g")
.selectAll("g")
.data(([, values]) => d3.utcMonths(d3.utcMonth(new Date(2020, 1, 1)), new Date(2020, 12, 1)))
.join("g");
// Change stroke color and width to distinguish month
// month.filter((d, i) => i).append("path")
// .attr("fill", "none")
// .attr("stroke", "#fff")
// .attr("stroke-width", 3)
// .attr("d", pathMonth);

month.append("text")
.attr("x", d => timeWeek.count(d3.utcYear(d), timeWeek.ceil(d)) * cellSize + 2)
.attr("y", 4.5)
.text(formatMonth);
return svg.node();
}
Insert cell
chart_2020 = {
//create a svg tag
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height+9.5])
.attr("font-family", "sans-serif")
.attr("font-size", 10);
svg.append("text")
.attr("x", (width / 2))
.attr("y", 15)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Crime heatmap in 2020");
//Add year label on the top left corner
const year = svg.selectAll("g")
.data([years[1]])
.join("g")
.attr("transform", (d, i) => `translate(40.5,${height * i + cellSize * 1.5 + 5})`);

year.append("text")
.attr("x", -5)
.attr("y", 0)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(([key]) => key);
// Add small rectangle for each day whose color represents the count of crime
year.append("g")
.selectAll("rect")
.data(weekday === "weekday"
? ([, values]) => values.filter(d => ![0, 6].includes(d.Occur_date.getUTCDay()))
: ([, values]) => values)
.join("rect")
.attr("width", cellSize - 1)
.attr("height", cellSize - 1)
.attr("x", d => timeWeek.count(d3.utcYear(d.Occur_date), d.Occur_date) * cellSize + 0.5)
.attr("y", d => countDay(d.Occur_date.getUTCDay()) * cellSize + 10)
.attr("fill", d => color_ord(d.absolute))
.append("title")
.text(d => `${formatDate(d.Occur_date)}
${d.absolute.toLocaleString("en")} crime`);
// Add weekday text to the left of heatmap
year.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(weekday === "weekday" ? d3.range(1, 6) : d3.range(7))
.join("text")
.attr("x", -5)
.attr("y", i => (countDay(i) + 0.5) * cellSize + 9.5)
.attr("dy", "0.31em")
.text(formatDayNew);
// Add month text on the top of heatmap
const month = year.append("g")
.selectAll("g")
.data(([, values]) => d3.utcMonths(d3.utcMonth(new Date(2020, 1, 1)), new Date(2020, 12, 1)))
.join("g");
// Change stroke color and width to distinguish month
// month.filter((d, i) => i).append("path")
// .attr("fill", "none")
// .attr("stroke", "#fff")
// .attr("stroke-width", 3)
// .attr("d", pathMonth);

month.append("text")
.attr("x", d => timeWeek.count(d3.utcYear(d), timeWeek.ceil(d)) * cellSize + 2)
.attr("y", 4.5)
.text(formatMonth);
return svg.node();
}
Insert cell
chart_2021 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-family", "sans-serif")
.attr("font-size", 10);
//Add year label on the top left corner
const year = svg.selectAll("g")
.data([years[2]])
.join("g")
.attr("transform", (d, i) => `translate(40.5,${height * i + cellSize * 1.5})`);

year.append("text")
.attr("x", -5)
.attr("y", -5)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(([key]) => key);
// Add small rectangle for each day whose color represents the count of crime
year.append("g")
.selectAll("rect")
.data(weekday === "weekday"
? ([, values]) => values.filter(d => ![0, 6].includes(d.Occur_date.getUTCDay()))
: ([, values]) => values)
.join("rect")
.attr("width", cellSize - 1)
.attr("height", cellSize - 1)
.attr("x", d => timeWeek.count(d3.utcYear(d.Occur_date), d.Occur_date) * cellSize + 0.5)
.attr("y", d => countDay(d.Occur_date.getUTCDay()) * cellSize + 0.5)
.attr("fill", d => color_ord(d.absolute))
.append("title")
.text(d => `${formatDate(d.Occur_date)}
${d.absolute.toLocaleString("en")} crime`);
// Add weekday text to the left of heatmap
year.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(weekday === "weekday" ? d3.range(1, 6) : d3.range(7))
.join("text")
.attr("x", -5)
.attr("y", i => (countDay(i) + 0.5) * cellSize)
.attr("dy", "0.31em")
.text(formatDayNew);
// Add month text on the top of heatmap
const month = year.append("g")
.selectAll("g")
.data(([, values]) => d3.utcMonths(d3.utcMonth(new Date(2020, 1, 1)), new Date(2020, 12, 1)))
.join("g");
// Change stroke color and width to distinguish month
month.filter((d, i) => i).append("path")
.attr("fill", "none")
.attr("stroke", "#fff")
.attr("stroke-width", 3)
.attr("d", pathMonth);

month.append("text")
.attr("x", d => timeWeek.count(d3.utcYear(d), timeWeek.ceil(d)) * cellSize + 2)
.attr("y", -5)
.text(formatMonth);
return svg.node();
}
Insert cell
cellSize = 17
Insert cell
width = 954
Insert cell
height = cellSize * (weekday === "weekday" ? 7 : 9)
Insert cell
weekday = "monday"
Insert cell
timeWeek = weekday === "sunday" ? d3.utcSunday : d3.utcMonday
Insert cell
countDay = weekday === "sunday" ? i => i : i => (i + 6) % 7
Insert cell
formatDay = i => "SMTWTFS"[i]
Insert cell
formatDayNew = i => ["Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][i]
Insert cell
formatMonth = d3.utcFormat("%b")
Insert cell
formatValue = x => `${Math.exp(x).toFixed(2)}×`
Insert cell
formatDate = d3.utcFormat("%x")
Insert cell
function pathMonth(t) {
const n = weekday === "weekday" ? 5 : 7;
const d = Math.max(0, Math.min(n, countDay(t.getUTCDay())));
const w = timeWeek.count(d3.utcYear(t), t);
return `${d === 0 ? `M${w * cellSize},0`
: d === n ? `M${(w + 1) * cellSize},0`
: `M${(w + 1) * cellSize},0V${d * cellSize}H${w * cellSize}`}V${n * cellSize}`;
}
Insert cell
// color = d3.scaleDiverging([d3.min(new_array, d => d.count), d3.max(new_array, d => d.count)], d3.interpolateSpectral)
Insert cell
// Set the color based on crime counts
color_ord = d3.scaleOrdinal()
.domain(["1","2","3","4","5","6","7","8","9","10"])
.range(d3.schemeGreys[9])
.unknown("#eee");
Insert cell
// calculate the relative intensity compared to the year average

new_array = {
var abc = d3.groups(new_array1, d => d.Occur_date.getUTCFullYear())
.flatMap(([year, yeardata]) => {
const base = Math.log(d3.mean(yeardata, d => d.count));
return yeardata.map(({Occur_date, count}) => ({Occur_date, absolute: count, count: Math.log(count) - base}))})
return abc
}
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