Public
Edited
Dec 2, 2022
Insert cell
Insert cell
<Chenhao Jin>, <cj2234>
Insert cell
Insert cell
Insert cell
Insert cell
data = (await FileAttachment('film_permits_reduced.csv').csv())
.map(permit => {
// create a function to parese strings into Dates
const parser = d3.timeParse('%Y-%m-%d %H:%M:%S');
permit['StartDateTime'] = parser(permit['StartDateTime']);
permit['EndDateTime'] = parser(permit['EndDateTime']);
// a permit can be for multiple zip codes
permit['ZipCodes'] = permit['ZipCode(s)'].split(', ');
// remove columns that we are not using it
delete permit['SubCategoryName'];
delete permit['ZipCode(s)'];
return permit;
})
Insert cell
Insert cell
Insert cell
// calculate diff of end and start time for each row.
diff = data.map(cur => ({
"hour" : d3.timeHour.count(cur.StartDateTime,cur.EndDateTime),
"Category": cur.Category
}))
Insert cell
// sum by each category
total = Array.from(d3.rollup(diff, v=> d3.sum(v,d=>d.hour) , d=>d.Category)).sort((a, b) => d3.descending(a[1], b[1]));
Insert cell
margin = ({top: 10, bottom: 70, left: 140, right: 10})
Insert cell
visWidth = width - margin.left - margin.right
Insert cell
visHeight = 500 - margin.top - margin.bottom
Insert cell
Category = total.map(a=>a[0])
Insert cell
x = d3.scaleBand()
.domain(Category)
.range([0, visWidth])
.padding(0.2)
Insert cell
//
maxh = d3.max(total, d => d[1])
Insert cell
y = d3.scaleLinear()
.domain([0, maxh])
.range([visHeight,0])
Insert cell
xAxis = d3.axisBottom(x)
Insert cell
yAxis = d3.axisLeft(y)
Insert cell
{
// create and select an svg element that is the size of the bars plus margins
const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);
// append a group element and move it left and down to create space
// for the left and top margins
const g = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// bind our data to rectangles
g.selectAll('rect')
.data(total)
.join('rect')
// set attributes for each bar
.attr('x', d => x(d[0]))
.attr('y', d => y(d[1]))
.attr('width', x.bandwidth)
.attr('height', d=>(visHeight - y(d[1])))
.attr('fill', 'steelblue');
// add a group for the y-axis
g.append('g')
.call(yAxis);
// add a group for the x-axis
g.append('g')
// we have to move this group down to the bottom of the vis
.attr('transform', `translate(0, ${visHeight})`)
.call(xAxis)
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth / 2)
.attr('y', 40)
.text("Category");
g.append('g')
.attr('transform', `translate(-10, 0)`)
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', -100)
.attr('y', visHeight/2)
.style("font-size", "10px")
.text("Total Duration");
return svg.node();
}
Insert cell
total

Insert cell
Insert cell
// add cells
zip = data.map(d=>{return d['ZipCodes']})
Insert cell
zips = d3.merge(zip)
Insert cell
// cpunt for each zip
countzip = Array.from(d3.rollup(zips, v => v.length, d => d))
.sort((a, b) => d3.descending(a[1], b[1])).splice(0,25)
Insert cell
Zipcodes = countzip.map(d=>d[0])
Insert cell
za = data.map(d=> [d["ZipCodes"],[d.Borough]])
Insert cell
zanda = za.flatMap(d=> d[0].map(v=> ({'zip':v,'borough':d[1][0]})))
Insert cell
s = za.filter(function( a ) {return a[0].length < 2;})
Insert cell
ma = s.map(a=>a)
Insert cell
b = Array.from(new Set(zanda.map(a => a.borough)))
Insert cell
function getb(z) {
return ma.filter(a=>a[0] == z)[0]
}
Insert cell
//
margin1 = ({top: 10, bottom: 70, left: 140, right: 10})
Insert cell
visWidth1 = width - margin1.left - margin1.right
Insert cell
visHeight1 = 500 - margin1.top - margin1.bottom
Insert cell
maxc= d3.max(countzip,d=>d[1])
Insert cell
x1 = d3.scaleBand()
.domain(Zipcodes)
.range([0, visWidth1])
.padding(0.2)
Insert cell
y1 = d3.scaleLinear()
.domain([0, maxc])
.range([visHeight1,0])
Insert cell
xAxis1 = d3.axisBottom(x1)
Insert cell
yAxis1 = d3.axisLeft(y1)
Insert cell
{
// create and select an svg element that is the size of the bars plus margins
const svg = d3.create('svg')
.attr('width', visWidth1 + margin1.left + margin1.right)
.attr('height', visHeight1 + margin1.top + margin1.bottom);
// append a group element and move it left and down to create space
// for the left and top margins
const g = svg.append("g")
.attr('transform', `translate(${margin1.left}, ${margin1.top})`);
// bind our data to rectangles
g.selectAll('rect')
.data(countzip)
.join('rect')
// set attributes for each bar
.attr('x', d => x1(d[0]))
.attr('y', d => y1(d[1]))
.attr('width', x1.bandwidth)
.attr('height', d=>(visHeight1 - y1(d[1])))
.attr('fill', 'steelblue');
// add a group for the y-axis
g.append('g')
.call(yAxis1);
// add a group for the x-axis
g.append('g')
// we have to move this group down to the bottom of the vis
.attr('transform', `translate(0, ${visHeight1})`)
.call(xAxis1)
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth1 / 2)
.attr('y', 40)
.text("zip");
g.append('g')
.attr('transform', `translate(-10, 0)`)
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', -100)
.attr('y', visHeight1/2)
.style("font-size", "10px")
.text("Total");
return svg.node();
}
Insert cell
Insert cell
//each category
total1 = Array.from(d3.rollup(data,a => a.length, b =>b.Category)).sort((c, d) => d3.descending(c[1],d[1])).splice(0, 5)
Insert cell
// each boro each cate
bc = Array.from(d3.rollup(data, a => d3.rollup(a, b => b.length, c => c.Category),b => b.Borough)).sort((e, f) => d3.descending(e[1],f[1]))
Insert cell
bc1 = Array.from(bc,(([boro,ct]) => {const map = Object.fromEntries(ct);map["Total"] = d3.sum(ct.values());map["Borough"] = boro; return map;}))
Insert cell
boros = Array.from(new Set(bc.map( a => a[0])))
Insert cell
cate = Array.from(new Set(total1.map( a => a[0])))
Insert cell
re = d3.stack().keys(cate).order(d3.stackOrderDescending)
Insert cell
sta = re(bc1)
Insert cell
margin2 = ({top: 10, bottom: 70, left: 140, right: 10})
Insert cell
visWidth2 = width - margin2.left - margin2.right
Insert cell
visHeight2 = 500 - margin2.top - margin2.bottom
Insert cell
x2 = d3.scaleBand()
.domain(boros)
.range([0, visWidth2])
.padding(0.2)
Insert cell
y2 = d3.scaleLinear()
.domain([0, 1])
.range([visHeight2,0])
Insert cell
r = d3.stack().keys(cate).offset(d3.stackOffsetExpand)(bc1)
Insert cell
c = d3.scaleOrdinal().domain(cate).range(d3.schemeAccent)
Insert cell
{
// create and select an svg element that is the size of the bars plus margins
const svg = d3.create('svg')
.attr('width', visWidth2 + margin2.left + margin2.right)
.attr('height', visHeight2 + margin2.top + margin2.bottom);
// append a group element and move it left and down to create space
// for the left and top margins
const g = svg.append("g")
.attr('transform', `translate(${margin2.left}, ${margin2.top})`);
const xAxis = d3.axisBottom(x2);
const yAxis = d3.axisLeft(y2).tickFormat(d3.format(".0%"));


g.append('g')
.attr('transform', `translate(0, ${visHeight2})`)
.call(xAxis)
.call(g => g.selectAll('.domain').remove())
.append('text')
.attr('fill', 'black')
.attr('x', visWidth2 / 2)
.attr('y', visHeight2)
.text("Categories");

g.append('g')
.call(yAxis)
.call(g => g.selectAll('.domain').remove())
.append('text')
.attr('fill', 'black')
.attr('x', -35)
.attr('y', visHeight2 / 2)
.text("count");
g.append('g')
.selectAll("g")
.data(r)
.join("g")
.attr("fill" , d => c(d.key))
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d=>x2(d.data.Borough))
.attr("y", d => y2(d[1]))
.attr("height", d => y2(d[0]) - y2(d[1]))
.attr("width", x2.bandwidth());
return svg.node();
}
Insert cell
Insert cell
// add cells here
Insert cell
Insert cell
// add cells here
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