Published
Edited
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more