Ngdon-Visualization

Number of Rents and Returns during Weekdays and Weekends

snip20161102_1

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

snip20161102_3

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

snip20161104_10

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"); 

    });
  });


});