Ngdon-Visualization
Number of Rents and Returns during Weekdays and Weekends
Interesting observations:
- There are two peaks (8 am and 5 pm) during week days, probably people going to work and going back from work.
- Bikes are used more to go home than to go to work.
- People wake up late during weekends.
- Nobody try to rent bikes when its 3-4 am. There are only returns.
Top Ten Most Ridden Bikes
The most popular bike of the quarter is Bike #70145, which has been ridden for almost 300 hours! The least popular bike is Bike #70008, which has been ridden only for about 10 minutes during the quarter.
Rents and Returns at Stations
Interesting observations:
- There’s more traffic near city center.
- People tend to rent their bikes at small stations and return them at larger ones.
I really enjoyed making this assignment. There seemed to be so much interesting information that I can extract from the data, and I kept thinking of possible visualizations I can do.
d3 felt strange at first, but soon I got used to it and started to admire its beauty. However for some of the features (for example one bar on top of another in the first chart) I couldn’t figure out how to make them using the idiomatic d3 way, so I used some hackish processing-like method to achieve them.
/* HIDDEN INITIALIZATION BLOCK */
// Select the DOM element
var parent = d3.select("#visualization");
// Set up the margins
var bbox = parent.node().getBoundingClientRect();
var margin = {top: 50, right: 50, bottom: 50, left: 50};
var width = +bbox.width - margin.left - margin.right;
var height = +bbox.height - margin.top - margin.bottom;
// Define svg as a group within the base SVG.
var svg = parent.select("svg").append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
/* END HIDDEN INITIALIZATION BLOCK */
var data1 = []
var data2 = []
for (var i = 0; i < 49; i++){
data1.push(0)
data2.push(0)
}
var datat = []
var mapdata = null;
var stations = null;
var rentals = null;
function isweekday(t){
var dt = t.split(" ")[0].split("/")
var date = new Date(dt[2],dt[0]-1,dt[1])
var fmt = d3.timeFormat("%a")
return ["Mon","Tue","Wed","Thur","Fri"].indexOf(fmt(date)) != -1
}
d3.json('http://d3.workergnome.com/examples/basic_map/data.geojson', function(loaded_data1) {
d3.csv('db/HealthyRideStations2016.csv', function(loaded_data2) {
d3.csv('db/HealthyRideRentals2016Q3.csv', function(loaded_data3) {
mapdata = loaded_data1;
stations = loaded_data2;
rentals = loaded_data3;
var s1 = 1
var s2 = 1
for (var i = 0; i < rentals.length; i++){
var shr = +rentals[i]["Starttime"].split(" ")[1].split(":")[0]
var ehr = +rentals[i]["Stoptime"].split(" ")[1].split(":")[0]
if (isweekday(rentals[i]["Starttime"])){
data1[shr]+=1
data2[ehr]+=1
//s1++
}else{
data1[shr+25]+=1
data2[ehr+25]+=1
//s2++
}
}
console.log([s1,s2])
for (var i = 0; i < 24; i++){
datat.push((data1[i]+data2[i])/s1)
}
for (var i = 24; i < data1.length; i++){
datat.push((data1[i]+data2[i])/s2)
}
var x = d3.scaleLinear().domain([0, d3.max(datat)]).range([0, height]);
var x2 = d3.scaleLinear().domain([0, d3.max(datat)]).range([height, 0]);
var d1s = []
var d2s = []
for (var i = 0; i < 24; i++){
d1s.push(x(data1[i]/s1));
d2s.push(x(data2[i]/s1));
}
for (var i = 24; i < data1.length; i++){
d1s.push(x(data1[i]/s2));
d2s.push(x(data2[i]/s2));
}
// define the bar width
var barWidth = width/data1.length;
// set up the x scale
var col1 = d3.rgb(190,195,195)
var col2 = d3.rgb(200,190,190)
var col3 = d3.rgb(170,175,175)
var col4 = d3.rgb(180,170,170)
console.log(data1)
console.log(data2)
// Create each bar, select the enter selection, and append a svg group.
svg.append("g")
.attr("transform", "translate(-4,-2)")
.call(d3.axisLeft(x2).ticks(10))
.attr("font-family", "sans-serif")
.attr("font-size", 8)
.attr("opacity",.3)
svg.selectAll("rect.i")
.data(d1s).enter()
.append("rect")
.attr("class", "i")
.attr("x",function(d,i){return i*barWidth})
.attr("y",function(d,i){return height-d-d2s[i]})
.attr("width",barWidth*0.9)
.attr("height",function(d){return d})
.attr("fill", function(d,i){if (i < 25){return col1}else{return col2}})
svg.selectAll("rect.ii")
.data(d2s).enter()
.append("rect")
.attr("class", "ii")
.attr("x",function(d,i){return i*barWidth})
.attr("y",function(d,i){return height-d-1})
.attr("width",barWidth*0.9)
.attr("height",function(d){return d})
.attr("fill", function(d,i){if (i < 25){return col3}else{return col4}})
var ts = 8
svg.selectAll("text.i")
.data(d2s).enter()
.append("text")
.attr("class", "i")
.attr("x",function(d,i){return (i+0.45)*barWidth-ts/2})
.attr("y",function(d,i){return height+8})
.attr("fill", function(d,i){if (i < 25){return d3.rgb(170,175,175)}else{return d3.rgb(180,170,170)}})
.attr("font-family", "sans-serif")
.attr("font-size", ts)
.text(function(d,i){if ((i%25)%2 == 1 && (i%25) != 24){return i%25}else{return ""}})
var ww = ["Weekdays","Weekends"]
svg.selectAll("text.ii")
.data(ww).enter()
.append("text")
.attr("class", "ii")
.attr("x",function(d,i){return (i*barWidth*25+10)})
.attr("y",function(d,i){return 10})
.attr("fill", function(d,i){if (i < 1){return d3.rgb(170,175,175)}else{return d3.rgb(180,170,170)}})
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.text(function(d,i){return d})
//drawing the legend
var t1 = svg.append("text").attr("x", barWidth*data1.length+8).attr("y", height+8)
.attr("font-family", "sans-serif").attr("fill","silver").attr("font-size", 8).text("O'Clock");
var bx = svg.append("rect").attr("x", width-20).attr("y", 50)
.attr("width", 50).attr("height",50).attr("fill","none").attr("stroke","Gainsboro")
var l1 = svg.append("rect").attr("x", width-15).attr("y", 60).attr("width", 10).attr("height",10).attr("fill",col1)
var l2 = svg.append("rect").attr("x", width-15).attr("y", 80).attr("width", 10).attr("height",10).attr("fill",col3)
var lt1 = svg.append("text").attr("x", width-2).attr("y", 67)
.attr("font-family", "sans-serif").attr("fill","silver").attr("font-size", 7).text("Rents");
var lt2 = svg.append("text").attr("x", width-2).attr("y", 87)
.attr("font-family", "sans-serif").attr("fill","silver").attr("font-size", 7).text("Returns");
});
});
});