Discrete timelines

51 views
Skip to first unread message

Oliver Smith

unread,
Apr 4, 2013, 8:09:14 PM4/4/13
to google-visua...@googlegroups.com
I've spent a while searching, and I see a number of possible ways to do this, but none of them feels right, and this seems like something that ought to be so common that perhaps myself and the folks who've previously touched on it aren't quite getting it.

I have an arbitrary number of series of [time, sample] datasets. I want to draw a line chart with each. While the time values will be within the same ranges, they will rarely have the same values, and the times are in miliseconds relative to the start of the sample.

A given series readily produces a nice, simple, line chart of it's own, what I want to do is draw N (between 1 and 255).

While I can see a few ways to do this, I'd kind of like to find the right way.

My instinct is to look for a "draw series" method, because creating rows with 255 columns where the chances of any given row having more than one entry ... feels so wrong.

I tried using join, but got very confused very quickly and it rapidly got really slow.

I looked at using addColumn/addRow/setCell; addRow would work if I knew how many series there were going to be at development time, setCell just feels like it's going to be insanely expensive.

Any points or advice appreciated.

(And after this, it's off to figure out if I should use a gannt style visualisation)

asgallant

unread,
Apr 4, 2013, 10:22:25 PM4/4/13
to google-visua...@googlegroups.com
So you have an arbitrary number of data series, which may or may not share common x-axis values, and you are trying to figure out how to add them to a DataTable so you can draw your chart; do I have that correct?  If so, then I think the answer is going to depend heavily on the form in which you obtain the data to begin with.  What is the structure of the raw data?

Oliver Smith

unread,
Apr 5, 2013, 2:59:22 AM4/5/13
to google-visua...@googlegroups.com

The data is benchmarking info, sampled per thread. So if there are three threads, maybe:

{ 3 : [ [ 100, 10 ], [ 175, 90 ], [ 231, 18 ], [ 400, 190 ] ], 7 : [ [50, 12 ], [75, 8], [105, 6], [123, 7], [133, 7], [174, 15], [250, 1] ], 11 : [ 33, 12 ], [ 66, 25 ], [ 99, 9 ], [ 120, 3 ], [ 130, 4 ], [ 180, 2 ], [ 211, 1], [ 231, 2 ], [ 245, 5 ] ]}

Where 3, 7 and 11 are threads that were tracking.

There will tend to be more data points as samples will tend to last between 30 seconds and 5 minutes.

If I feed any one of the threads data into draw, a nice graph results, although I should probably include the base timestamp so I can use dates :) I can merge them all into one big dataset with a lot of manipulation and a lot of empty cells. I'm perhaps balking at that because I'm working on optimization, ergo the dataset...

Oliver

--
You received this message because you are subscribed to a topic in the Google Groups "Google Visualization API" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-visualization-api/KJiyMccn9PI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to google-visualizati...@googlegroups.com.
To post to this group, send email to google-visua...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-visualization-api?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

asgallant

unread,
Apr 5, 2013, 9:59:51 AM4/5/13
to google-visua...@googlegroups.com
This problem is quite similar to one I have dealt with before.  This may not be the most efficient way to handle the problem, but it should work:

var rawData = {};
var parsedData = {};
var colMap = {};
var i = 1;
var data = new google.visualization.DataTable();
data.addColumn('number', 'seconds');
// build out the columns
for (var x in rawData) {
    data.addColumn('number', x);
    colMap[x] = i;
    i++;
}
// fill in the rows
for (var x in rawData) {
    i = colMap[x];
    for (var j = 0; j < rawData[x].length; j++) {
        var seconds = rawData[x][j][0];
        var value = rawData[x][j][1];
        // if we don't yet have data at this timestamp, add new data
        if (!(parsedData[seconds] instanceOf Array)) {
            parsedData[seconds] = [seconds];
            for (var y in colMap) {
                parsedData[seconds].push(null);
            }
        }
        parsedData[seconds][i] = value;
    }        
}
// populate DataTable
for (var x in parsedData) {
    data.addRow(parsedData[x]);
}
// sort the DataTable by time
data.sort(0);
To unsubscribe from this group and all its topics, send an email to google-visualization-api+unsub...@googlegroups.com.

Oliver Smith

unread,
Apr 5, 2013, 2:15:06 PM4/5/13
to google-visua...@googlegroups.com
Awesome - oddly one of my three implementations looked almost exactly like your code: I was using 'time in parsedData' and I wasn't pushing nulls - I was just creating a new Array(n).

Adding the nulls and using Date objects for the time line results in a nicely rendered multi-line graph.

Thank you :)

-Oliver

asgallant

unread,
Apr 5, 2013, 2:20:01 PM4/5/13
to google-visua...@googlegroups.com
You're welcome.

Oliver Smith

unread,
Apr 5, 2013, 3:01:39 PM4/5/13
to google-visua...@googlegroups.com

Spoke too soon:

Using "Date" seems to be losing me some portion of my millisecond fidelity, if I use "number" for the times, instead, I wind up with a blank chart. I can mouse over the chart and see that the data points are there, but the lines themselves aren't rendered.

Here's the code with a simple "useDate" switch. If you set useDate=1, and redraw the graph a few times, you'll see it clearly doesn't like millisecond-granularity dates; if you set it to useDate=0, no lines.

  var tickTimes = {
1 : { 'color':'#ff0000', 'ticks':[[-20025,384],[-19586,376],[-19122,392],[-18722,368],[-18287,360],[-17838,377],[-17434,368],[-17020,399],[-16573,381],[-16138,393],[-15735,341],[-15295,363],[-14886,337],[-14455,370],[-14006,401],[-13567,380],[-13162,337],[-12681,445],[-12277,359],[-11874,345],[-11448,360],[-11013,368],[-10600,317],[-10166,423],[-9736,359],[-9280,383],[-8808,425],[-8384,411],[-7934,375],[-7503,341],[-7071,358],[-6624,377],[-6177,362],[-5765,289],[-5359,381],[-4942,381],[-4378,480],[-3906,466],[-3493,394],[-3092,358],[-2642,409],[-2226,371],[-1803,323],[-1402,381],[-1000,368],[-527,414],[-79,422],]},
3 : { 'color':'#ff8000', 'ticks':[[-19930,21],[-19526,39],[-19121,23],[-18718,36],[-18316,17],[-17914,23],[-17514,19],[-17114,21],[-16711,26],[-16311,21],[-15909,21],[-15509,20],[-15108,39],[-14706,41],[-14304,22],[-13904,25],[-13502,43],[-13102,21],[-12702,34],[-12300,37],[-11896,42],[-11492,23],[-11091,19],[-10689,43],[-10287,26],[-9886,20],[-9486,68],[-9086,30],[-8686,55],[-8286,40],[-7886,18],[-7482,23],[-7081,23],[-6680,43],[-6280,22],[-5879,23],[-5479,36],[-5075,19],[-4675,26],[-4270,36],[-3866,21],[-3465,26],[-3064,53],[-2647,69],[-2247,23],[-1845,41],[-1445,37],[-1042,27],[-639,32],[-239,52],]},
7 : { 'color':'#ffff00', 'ticks':[[-19847,6],[-19447,7],[-19046,7],[-18642,2],[-18241,7],[-17840,4],[-17440,4],[-17038,4],[-16638,6],[-16234,4],[-15834,2],[-15434,3],[-15034,6],[-14633,21],[-14233,4],[-13833,9],[-13433,21],[-13032,6],[-12632,4],[-12232,10],[-11832,25],[-11431,5],[-11027,2],[-10627,21],[-10227,3],[-9827,2],[-9427,27],[-9027,7],[-8626,4],[-8225,22],[-7824,3],[-7423,3],[-7007,24],[-6607,1],[-6207,0],[-5807,5],[-5407,24],[-5007,5],[-4603,4],[-4202,25],[-3801,1],[-3401,2],[-2998,29],[-2598,7],[-2198,4],[-1798,1],[-1397,42],[-997,1],[-597,11],[-196,25],]},
  };
  var useDate = 1;
  
  function drawVisualization() {
  var now = useDate ? (new Date()).getTime() : 0;
  var rows = {};
  var colors = [];

  // Create a visualization dataset.  
  var data = new google.visualization.DataTable();
  data.addColumn(useDate ? 'datetime' : 'number', 'Time');
  for (var t in tickTimes) {
var entry = tickTimes[t];
entry.col = data.addColumn('number', t);
colors[entry.col] = entry.color;
  }

  // Merge the data into a single table indexed by time,
  // wasteful because the threads are independent so they
  // are unlikely to tick at the same milisecond, but
  // required by the charts api.
  var time;
  for (var t in tickTimes) {
var entry = tickTimes[t];
for (var i = 0; i < entry.ticks.length; ++i) {
 var ticks = entry.ticks[i];
 if (useDate) {
   time = new Date();
   time.setTime(now + ticks[0]);
 } else {
   time = now + ticks[0];
 }
 if (!(time in rows)) {
   rows[time] = [time];
   for(var t in tickTimes) { rows[time].push(null); }
 }
 rows[time][entry.col] = ticks[1];
}
  }

  // Add the resulting rows into the data table.
  for (var row in rows) {
    data.addRow(rows[row]);
  }
  rows = [];
  data.sort(0);
  new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {width: 640, height: 480}
);
  }

asgallant

unread,
Apr 5, 2013, 5:59:38 PM4/5/13
to google-visua...@googlegroups.com
Date objects have millisecond resolution, so you shouldn't have any problem using them.  The only issue I see is that the data arrays have errant commas at the end (",]"), which will cause problems in some browsers.  I hooked up your code in a jsfiddle and inserted a DateFormatter to format the dates: http://jsfiddle.net/asgallant/3WqzC/

The problem with using numbers is that you have to set the "interpolateNulls" option to true in order to get the lines to draw with empty data sets between points.

I think I may have a better solution, though: http://jsfiddle.net/asgallant/3WqzC/2/.  This avoids the problem with the interpolation, should have a much lower memory footprint, and requires less pre-processing of data.

Oliver Smith

unread,
Apr 5, 2013, 6:43:39 PM4/5/13
to google-visua...@googlegroups.com
Ah! Ok - with the date formatter, that looks to be great. Thanks!

Any thoughts on what's going on when you change 'useDate' to 0?

asgallant

unread,
Apr 5, 2013, 7:33:33 PM4/5/13
to google-visua...@googlegroups.com
I explained the previous problem with setting useDate = 0 in the previous post (the interpolateNulls issue).  The new method isn't susceptible to that problem, though, so you could use either one.
Reply all
Reply to author
Forward
0 new messages