1
votes

I am trying to create a line graph with that shows the average amount of people at certain hours of the day. I also wan to format the x axis to reflect and read midnight, 8am, Noon, 5pm, 8pm, and 11 pm. My chart keeps coming up blank and my axis is starting at 7pm for some reason. Any help is appreciated.

I have partially answered my own question and can get the data count using the following:

ok, I have partially answered my own question. To get the count, I needed to change the following:
  var volumeByHour = crossfilterData.dimension(function(d) { 
        return d.datetime ? (d.datetime.getHours()):null;

});

var volumeByHourGroup = volumeByHour.group();

This gives me the raw number of visitors and I need the average....

The data looks like this

[
   {
      "id":1,
      "sex":0,
      "age":65,
      "income":201428,
      "ethnicity":0,
      "datetime":"2009-04-26T00:00:00.000Z"
   },
   {
      "id":2,
      "sex":0,
      "age":75,
      "income":22851,
      "ethnicity":1,
      "datetime":"2009-04-26T01:00:00.000Z"
   },
   {
      "id":3,
      "sex":1,
      "age":27,
      "income":15672,
      "ethnicity":2,
      "datetime":"2009-04-26T02:00:00.000Z"
   },
   {
      "id":4,
      "sex":1,
      "age":69,
      "income":60719,
      "ethnicity":3,
      "datetime":"2009-04-26T03:00:00.000Z"
   },
   {
      "id":5,
      "sex":1,
      "age":18,
      "income":217262,
      "ethnicity":4,
      "datetime":"2009-04-26T04:00:00.000Z"
   },
   {
      "id":6,
      "sex":1,
      "age":76,
      "income":73308,
      "ethnicity":5,
      "datetime":"2009-04-26T05:00:00.000Z"
   },
   {
      "id":7,
      "sex":0,
      "age":51,
      "income":259663,
      "ethnicity":6,
      "datetime":"2009-04-26T06:00:00.000Z"
   },
   {
      "id":8,
      "sex":1,
      "age":42,
      "income":271168,
      "ethnicity":7,
      "datetime":"2009-04-26T07:00:00.000Z"
   },
   {
      "id":9,
      "sex":0,
      "age":42,
      "income":318753,
      "ethnicity":8,
      "datetime":"2009-04-26T08:00:00.000Z"
   },
   {
      "id":10,
      "sex":1,
      "age":94,
      "income":302247,
      "ethnicity":9,
      "datetime":"2009-04-26T09:00:00.000Z"
   },
   {
      "id":11,
      "sex":1,
      "age":94,
      "income":221124,
      "ethnicity":10,
      "datetime":"2009-04-26T10:00:00.000Z"
   },
   {
      "id":12,
      "sex":1,
      "age":56,
      "income":311643,
      "ethnicity":11,
      "datetime":"2009-04-26T11:00:00.000Z"
   },
   {
      "id":13,
      "sex":1,
      "age":79,
      "income":204746,
      "ethnicity":12,
      "datetime":"2009-04-26T12:00:00.000Z"
   },
   {
      "id":14,
      "sex":1,
      "age":54,
      "income":2451,
      "ethnicity":13,
      "datetime":"2009-04-26T13:00:00.000Z"
   },
   {
      "id":15,
      "sex":1,
      "age":100,
      "income":25213,
      "ethnicity":14,
      "datetime":"2009-04-26T14:00:00.000Z"
   },
   {
      "id":16,
      "sex":1,
      "age":71,
      "income":299937,
      "ethnicity":15,
      "datetime":"2009-04-26T15:00:00.000Z"
   },
   {
      "id":17,
      "sex":0,
      "age":91,
      "income":217957,
      "ethnicity":16,
      "datetime":"2009-04-26T16:00:00.000Z"
   },
   {
      "id":18,
      "sex":1,
      "age":98,
      "income":157079,
      "ethnicity":17,
      "datetime":"2009-04-26T17:00:00.000Z"
   },
   {
      "id":19,
      "sex":0,
      "age":57,
      "income":60152,
      "ethnicity":0,
      "datetime":"2009-04-26T18:00:00.000Z"
   },
   {
      "id":20,
      "sex":1,
      "age":94,
      "income":148961,
      "ethnicity":1,
      "datetime":"2009-04-26T19:00:00.000Z"
   },
   {
      "id":21,
      "sex":1,
      "age":29,
      "income":40591,
      "ethnicity":1,
      "datetime":"2009-04-26T20:00:00.000Z"
   }
]

and is being loaded and parsed like this:

/*createCrossfilter() - constructs a new crossfilter
 *  @data: our data returned by the loadData callback
 */
function createCrossfilter(data, callback) {
    crossfilterData = crossfilter(data);
    crossfilterDataAll = crossfilterData.groupAll();
    if (callback !== undefined) {
        callback();
    }
}

/* loadData() - loads our dataset. a callback with our data when our data is ready to  be used.
 *  @pathToData: path to the dataset on the file system.
 */
function loadData(pathToData) {
    d3.json(pathToData, function (data) {
        globalData = data;

        // parse JSON Strings - convert to real javascript objects
        data.forEach(function (e) {
            var parseDateTime = d3.time.format("%Y-%m%dT%I:%M:%S.%LZ");
                    e.datetime = parseDateTime.parse(e.datetime);
                e.hour = d3.time.hour(e.datetime);
                e.day = d3.time.day(e.datetime);
                e.month = d3.time.month(e.datetime);
            });

and the code I have looks like this:

function createTimeOfDayChart() {
// define an anchor point for the createTimeOfDayChart
charts.timeOfDayChart = dc.lineChart("#dc-timeofday-chart");

// create any dimensions
var volumeByHour = crossfilterData.dimension(function(d) { 
            return d.datetime ? (d.datetime.getHours()):null;
});

// number of visitors per hour Chart
var volumeByHourGroup = volumeByHour.group().reduceCount(function(d) {  
            return d.datetime ? (d.datetime.getHours()):null;
  });

var timeExtent = d3.extent(globalData, function(d){

    return d.hour;
});


charts.timeOfDayChart
            .width(350)
            .height(225)
            .margins({ top: 0, left: 35, right: 45, bottom: 40 }) 
            .transitionDuration(500) 
            .dimension(volumeByHour) 
            .group(volumeByHourGroup)
          //.group(crossfilterData.groupAll()) 
            .valueAccessor(function(d){
                return d.value.avg;
            })
            .elasticY(true)
            .elasticX(true)
            .x(d3.time.scale().domain(timeExtent.map(function(d) { return new Date(d);        }))
            .round(d3.time.hour.round)
            .xUnits(d3.time.hours)
            .renderHorizontalGridLines(true)
            .renderVerticalGridLines(true)
            .renderLabel(true)
            .renderArea(false)
            .brushOn(true)
            .renderLabel(true)
            .dotRadius(10)

            .renderlet(function(chart){
                var colors =d3.scale.ordinal().domain(timeExtent)
                    .range(["steelblue", "brown", "red", "green", "yellow", "grey"]);
                chart.selectAll('path.line').each(function(d){
                     d3.select(this).attr("style", "fill: " + colors(d.key)); 
                });
            })
            .xAxis().ticks(6);
1
I notice that you're using dc charts and I'm not familiar with that library but if you wanted to specify tick values in d3 you'd use axis.tickValues. You might have to edit the source code of dc to achieve this or code your line graph using using d3. - user1614080
Yeah, I am trying to customize that now. I want the y axis to read 5%, 10%, 15%, 20%, 25%, 30% and am trying to make the line segments different colors like in a dimple.js chart here it is proving to be very challenging!! - user3057785

1 Answers

1
votes

Updated based on comments

First you will want to create your dimension based on the hour of the day (as you did above):

 var volumeByHour = crossfilterData.dimension(function (d) {
        return d.datetime ? (d.datetime.getHours()):null;
    });

Next you will want to create a custom reduce method to keep track of the total and average visits per hour. I used the difference between the min and max dates as the dividend in the average.

    var volumeByHourGroup = volumeByHour.group().reduce(
        function (p, v) {
            ++p.count;
            p.avgCount = p.count / numberOfDays;
            return p;
        },

        function (p, v) {
            --p.count;
            p.avgCount = p.count / numberOfDays;
            return p;
        },

        function () {
            return {
                count: 0,
                avgCount: 0
            };
        });

Finally you can adapt the chart to show the ticks that you want:

        timeOfDayChart.width(350)
        .height(225)
        .dimension(volumeByHour)
        .group(volumeByHourGroup)
        .x(d3.scale.linear().domain([0, 24]))       
        .valueAccessor(function(d){return d.value.avgCount})
        .xAxis().tickValues([7, 11, 16, 19, 22]);

You will probably want to also use a tickFormatter to change how each tick is displayed.

Here is an updated jsfiddle: http://jsfiddle.net/djmartin_umich/G2nqh/