d3 stacked bar with unusual data

40 views
Skip to first unread message

peter Flow

unread,
Jan 12, 2017, 12:55:56 PM1/12/17
to d3-js

i want to create a stacked bar chart, but not the usual way with series, who get stacked.

exact data example:


[  
{"issue":19,"created_at":"2017-01-06T14:24:04.247Z","time":"00:30:00"},
{"issue":18,"created_at":"2017-01-06T14:24:04.247Z","time":"02:00:00"},
{"issue":18,"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
{"issue":19,"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
{"issue":17,"created_at":"2017-01-07T14:24:04.247Z","time":"02:00:00"},
{"issue":17,"created_at":"2017-01-07T14:24:04.247Z","time":"06:00:00"},
{"issue":17,"created_at":"2017-01-08T14:24:04.247Z","time":"06:00:00"},
{"issue":17,"created_at":"2017-01-09T14:24:04.247Z","time":"06:00:00"},
{"issue":17,"created_at":"2017-01-09T14:24:04.247Z","time":"00:30:00"},
{"issue":18,"created_at":"2017-01-10T14:24:04.247Z","time":"00:10:00"},
{"issue":19,"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
{"issue":17,"created_at":"2017-01-10T14:24:04.247Z","time":"06:00:00"},
{"issue":19,"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
{"issue":19,"created_at":"2017-01-11T14:24:04.247Z","time":"00:10:00"}
]


I want to create now a stacked-bar chart for the last seven days, where values(time field) are stacked for each day and coloured by id(issue).


The Problem is all examples i found are doing series stacking

I have different amounts of values per day: 0 <= #values(day)


can someone show me a short example (http://jsfiddle.net/qbmy76on/3/) of getting a stacked bar out of this data with d3(value could also be a simple integer value, like in the following example)


with Charts.js i realized a Prototype(with minutes), but i want to switch to d3 for future Features.

http://i.imgur.com/LdtsusH.png

Vlado Z

unread,
Jan 13, 2017, 6:17:50 AM1/13/17
to d3-js
I would first process the data and shape it into a form suitable for drawing bar chart. So you would have json with all times grouped by the issue id. Something like this:

{
   
{
       
"issue": 17,
        times
: [
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-08T14:24:04.247Z","time":"06:00:00"},
           
{"created_at":"2017-01-09T14:24:04.247Z","time":"06:00:00"},
           
{"created_at":"2017-01-09T14:24:04.247Z","time":"00:30:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"06:00:00"}
       
]
   
},

   
{
       
"issue": 18,
        times
: [
           
{"created_at":"2017-01-06T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"00:10:00"}
       
]
   
},

   
{
       
"issue": 19,
        times
:[
           
{"created_at":"2017-01-06T14:24:04.247Z","time":"00:30:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-11T14:24:04.247Z","time":"00:10:00"}
       
]
   
}
}

So you would need a script to first process the data then draw the bar chart as you expect.

Vlado Z

unread,
Jan 13, 2017, 6:21:11 AM1/13/17
to d3-js
Or maybe like an array:

[
   
{
       
"issue": 17,
       
"times": [
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-08T14:24:04.247Z","time":"06:00:00"},
           
{"created_at":"2017-01-09T14:24:04.247Z","time":"06:00:00"},
           
{"created_at":"2017-01-09T14:24:04.247Z","time":"00:30:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"06:00:00"}
       
]
   
},

   
{
       
"issue": 18,
       
"times": [
           
{"created_at":"2017-01-06T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"00:10:00"}
       
]
   
},

   
{
       
"issue": 19,
       
"times":[
           
{"created_at":"2017-01-06T14:24:04.247Z","time":"00:30:00"},
           
{"created_at":"2017-01-07T14:24:04.247Z","time":"00:10:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-10T14:24:04.247Z","time":"02:00:00"},
           
{"created_at":"2017-01-11T14:24:04.247Z","time":"00:10:00"}
       
]
   
}
]


But you can also create sequential array with issue being array indexes if issues have incremental order with difference of 1.

peter Flow

unread,
Jan 13, 2017, 6:22:29 AM1/13/17
to d3-js
with your data format i can create a bar chart looking like this: https://imgur.com/LdtsusH ?
 
i'm a little bit confused, i thought i would have to group the date by date.

Vlado Z

unread,
Jan 13, 2017, 6:38:05 AM1/13/17
to d3-js
Something like this and sorted by earlier time? But I think you should also remove the time from the date field. Because there could be differences in milliseconds :)

[
   
{

       
"created_at":"2017-01-06T14:24:04.247Z",

       
"entries": [
           
{"issue":19, "time":"00:30:00"},
           
{"issue":18, "time":"02:00:00"}
       
]
   
},

   
{

       
"created_at": "2017-01-07T14:24:04.247Z",

       
"entries": [
           
{"issue":18, "time":"00:10:00"},
           
{"issue":19, "time":"00:10:00"},
           
{"issue":17, "time":"02:00:00"},
           
{"issue":17, "time":"06:00:00"},
       
]
   
},

   
{

       
"created_at":"2017-01-08T14:24:04.247Z",

       
"entries": [
           
{"issue":17, "time":"06:00:00"}
       
]
   
},

   
{

       
"created_at":"2017-01-09T14:24:04.247Z",

       
"entries": [
           
{"issue":17, "time":"00:30:00"},
           
{"issue":17, "time":"06:00:00"}
       
]
   
},

   
{

       
"created_at":"2017-01-10T14:24:04.247Z",

       
"entries": [
           
{"issue":18, "time":"00:10:00"},
           
{"issue":19, "time":"02:00:00"},
           
{"issue":19, "time":"02:00:00"},
           
{"issue":17, "time":"06:00:00"}
       
]
   
},

   
{

       
"created_at":"2017-01-11T14:24:04.247Z",

       
"entries": {
           
{"issue":19, "time":"00:10:00"}
       
}
   
}
]


Vlado Z

unread,
Jan 13, 2017, 6:41:10 AM1/13/17
to d3-js
Perhaps you should also pay attention to whether it is with 24 hour time format or is it with AM/PM time format.
It seems it is with 24 hour format.

peter Flow

unread,
Jan 13, 2017, 6:42:13 AM1/13/17
to d3-js
Yeah something like that i had in mind. The time i'll remove from the date of course.
but how do i pass this data now to d3 drawing a stacked bar?
like i said the issue id is just for giving the stacked entries same colour for same issue id.

peter Flow

unread,
Jan 13, 2017, 6:44:14 AM1/13/17
to d3-js
can i pass this structure now do d3.stack() ?

peter Flow

unread,
Jan 13, 2017, 6:46:10 AM1/13/17
to d3-js
i also need to add an entry in this array for the dates in the last seven days where i have no data i think, or?

Vlado Z

unread,
Jan 13, 2017, 6:56:30 AM1/13/17
to d3-js
I reworked the code with cleaner JavaScript of Stacked Bar Chart here: https://github.com/bluePlayer/practices/tree/master/D3js%20Exercises/StackedBarChart
You can also check some D3 examples in action which I reworked here: https://blueplayer.github.io/

The problem is, the example uses CSV and it sends a type() function to add a total field inside the data object so when drawing the bars, D3js knows the size of each bar.

I would use d3.json(jsonFileUrl, callbackFunction) instead. But its not just simple to pass the data file. It will not work. You must think how to process the data further.
I would try to help you but will need some time.

Vlado Z

unread,
Jan 13, 2017, 7:02:24 AM1/13/17
to d3-js
It actually might work with d3.stack() function if you create an array of keys, each key would be the date of the issues being created.

And then pass this key array of date to the d3.stack() function

Vlado Z

unread,
Jan 13, 2017, 7:09:47 AM1/13/17
to d3-js
It would be something like this:

stack = d3.stack()
   
.keys(["2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10", "2017-01-11"])
   
.order(d3.stackOrderNone)
   
.offset(d3.stackOffsetNone);

series
= stack(data);

console
.dir(series);

But when I print the series I get NaNs so I make mistake somewhere.

Vlado Z

unread,
Jan 13, 2017, 9:21:53 AM1/13/17
to d3-js
Can you give more information about the data itself?
Does the data looks exactly like in the main post above or you did something to it?

Give more details about the data.

peter Flow

unread,
Jan 13, 2017, 9:22:11 AM1/13/17
to d3-js
yeah, meee too
i converted the time field to minutes and get the following data structure:
var grouped_by_date=[
 
{"key":"2017-01-07",

 
"values":

 
[ {"user":1,"issue":18,"created_at":"2017-01-07","time":10},

 
{"user":1,"issue":19,"created_at":"2017-01-07","time":10},

 
{"user":1,"issue":17,"created_at":"2017-01-07","time":120},

 
{"user":1,"issue":17,"created_at":"2017-01-07","time":360}

 
]

},

{“key":"2017-01-08",

 "
values":

 [

 {"
user":1,"issue":17,"created_at":"2017-01-08","time":360}

 ]

},

{"
key":"2017-01-09",

 "
values":

 [

 {"
user":1,"issue":17,"created_at":"2017-01-09","time":360},

 {"
user":1,"issue":17,"created_at":"2017-01-09","time":30}

 ]

},

{"
key":"2017-01-10",

 "
values":

 [

 {"
user":1,"issue":18,"created_at":"2017-01-10","time":10},

 {"
user":1,"issue":19,"created_at":"2017-01-10","time":120},

 {"
user":1,"issue":17,"created_at":"2017-01-10","time":360},

 {"
user":1,"issue":19,"created_at":"2017-01-10","time":120}

 ]

},

{"
key":"2017-01-11","values":

 [

 {"
user":1,"issue":19,"created_at":"2017-01-11","time":10}

 ]

}

]


then i do

    var stack = d3.stack()


   
.keys("2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10", "2017-01-11"])
   
.value(function(d, key) { return d.values.time; })
   
.order(d3.stackOrderNone)
   
.offset(d3.stackOffsetNone);


    series
= stack(grouped_by_date);
   
 console.dir(JSON.stringify(series));



gives me for series:


[[[0,null],[0,null],[0,null],[0,null],[0,null]],[[0,null],[0,null],[0,null],[0,null],[0,null]],[[0,null],[0,null],[0,null],[0,null],[0,null]],[[0,null],[0,null],[0,null],[0,null],[0,null]],[[0,null],[0,null],[0,null],[0,null],[0,null]],[[0,null],[0,null],[0,null],[0,null],[0,null]]]



peter Flow

unread,
Jan 13, 2017, 9:27:24 AM1/13/17
to d3-js
i get it from a json api in django

the data looks like:

{  
      "model":"timelog.timelog",
      "pk":15979,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-07T14:24:12.216Z",

         "time":"00:10:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15980,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-07T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15974,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-08T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15975,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-08T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15976,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-08T14:24:12.216Z",

         "time":"00:10:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15977,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-08T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15978,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-08T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15971,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-09T14:24:12.216Z",

         "time":"02:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15972,
      "fields":{  
         "user":1,
         "issue":22,
         "created_at":"2017-01-09T14:24:12.216Z",

         "time":"02:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15973,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-09T14:24:12.216Z",

         "time":"00:30:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15969,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-10T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15970,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-10T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15968,
      "fields":{  
         "user":1,
         "issue":21,
         "created_at":"2017-01-11T14:24:12.216Z",

         "time":"06:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15967,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-12T14:24:12.216Z",

         "time":"02:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15964,
      "fields":{  
         "user":1,
         "issue":22,
         "created_at":"2017-01-13T14:24:12.216Z",

         "time":"00:30:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15965,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-13T14:24:12.216Z",
         "time":"01:00:00"
      }
   },
   {  
      "model":"timelog.timelog",
      "pk":15966,
      "fields":{  
         "user":1,
         "issue":20,
         "created_at":"2017-01-13T14:24:12.216Z",
         "time":"00:10:00"
      }
   }
]



this is my js code till now:

d3.json("{% url "timelog:api_last_7_days"  %}", function(error, data) {
        data.forEach(function(d) {
           d.fields.created_at = parseDate(d.fields.created_at)
           d.fields.created_at = formatDate(d.fields.created_at)
           d.fields.time = parseTime(d.fields.time)
           d.fields.time = d.fields.time.getHours()*60 + d.fields.time.getMinutes()
        });
    console.log(data)
    var js = JSON.stringify(data, ['issue', 'created_at', 'time'])
    var res = [];
    data.forEach(function(entry) {
        res.push(entry.fields)
    });
    var js = JSON.stringify(res, ['issue', 'created_at', 'time'])
    var grouped_by_date = d3.nest()
    .key(function(d) { return d.created_at; })
    .entries(res);
    console.dir(JSON.stringify(grouped_by_date));

    var stack = d3.stack()
    .keys(["2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10", "2017-01-11", "2017-01-12", "2017-01-13"])

peter Flow

unread,
Jan 13, 2017, 9:31:26 AM1/13/17
to d3-js
should be looking like that with the updated data: http://i.imgur.com/xZ5oMAo.png

peter Flow

unread,
Jan 13, 2017, 9:45:08 AM1/13/17
to d3-js
created a fiddle with the uptodate data: https://jsfiddle.net/vt3990yr/6/

peter Flow

unread,
Jan 13, 2017, 10:11:07 AM1/13/17
to d3-js
https://jsfiddle.net/vt3990yr/18/

showing the x and y axis(with minutes)

peter Flow

unread,
Jan 13, 2017, 12:15:37 PM1/13/17
to d3-js

peter Flow

unread,
Jan 13, 2017, 2:54:51 PM1/13/17
to d3-js
Reply all
Reply to author
Forward
0 new messages