Extracting data from the DOM (Html Table)

1,401 views
Skip to first unread message

Daniel Bodart

unread,
Dec 21, 2012, 7:52:41 AM12/21/12
to d3-js
Hi there,

I'm trying to extract data from a pre-existing table, where the text
content is the data value for that cell:

<table>
<thead>
<tr>
<td></td> <th>A</th> <th>B</th> <th>C</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th> <td>A1</td> <td>B1</td> <td>C1</td>
</tr>
<tr>
<th>2</th> <td>A2</td> <td>B2</td> <td>C2</td>
</tr>
</tbody>
</table>
.
I have managed to get out the header values by doing the following
(which is ok but a little weird)

var table = d3.select('table');
function text() {return this.textContent; }
var keys = table.selectAll('thead th').datum(text).data();

Ideally you wouldn't have overridden 'Array.prototype.map' as then I
could have done:

var keys = table.selectAll('thead th').map(text);

Then I really like the fact that you support keeping the structure, so
I can then do

var values = table.selectAll('tbody
tr').selectAll('td').datum(text)

And I will get back an array of arrays, but I can't find any way to
get the values out. If I call 'data()' you throw away the structure
and only return the first array. You have the same problem with
'text()' which would been ideal but this only returns the first
element.

Any advice appreciated...

Dan






Daniel Bodart

unread,
Dec 21, 2012, 8:08:53 AM12/21/12
to d3-js
In fact is there a simple way of just returning a vanilla javascript
array from d3 array?

Tore Nauta

unread,
Dec 21, 2012, 11:14:19 AM12/21/12
to d3...@googlegroups.com
I've also had to do something like that in the past and what I ended up with was adding my own map method to the d3.selection prototype, like this:

// Return a new array by collecting the results of the specified function
// for each element in the current selection, passing in the current datum d
// and index i, with the this context of the current DOM element.
d3.selection.prototype.map_flat = function(f) {
  var arr = [];
  this.each(function(d, i) {
    arr[arr.length] = f.call(this, d, i);
  });
  return arr;
};

However, this creates a flat array based on the current selection. In your, and the more general, case you'd like a nested version like this:

// Return a new nested array by collecting the results of the specified function
// for each element in the current selection, passing in the current datum d
// and indexes i and j with the this context of the current DOM element.
d3.selection.prototype.map_nested = function(f) {
  var arr = d3.range(this.length).map(function() { return []; });
  this.each(function(d, i, j) {
    arr[j].push(f.call(this, d, i, j));
  });
  return arr;
};

You can use this as follows:
// make nested selection
var tds = d3.select("tbody").selectAll("tr").selectAll("td");

// obtain nested array containing the text of each table cell
var vals = tds.map_nested(function(d, i, j) { return d3.select(this).text(); });

See also https://github.com/mbostock/d3/issues/878, where Mike and Shawn were discussing alternative methods of doing something like this.

Tore

Chris Viau

unread,
Dec 21, 2012, 12:01:09 PM12/21/12
to d3...@googlegroups.com
d3.selectAll('div')[0]

Daniel Worthington-Bodart

unread,
Dec 21, 2012, 5:30:21 PM12/21/12
to d3...@googlegroups.com
I noticed in the new version 3, selection.map has been removed so I can now map as usual yay!

Marc Fawzi

unread,
Dec 22, 2012, 1:04:38 PM12/22/12
to d3...@googlegroups.com, d3...@googlegroups.com
Didn't know Array.prototype.map was overriden in v2. I imagined it was just a map method on the selection function. 

Just curious: in v3 does D3 override any native prototype method?  

(I wouldnt think so but asking just in case...)

Sent from my iPhone
Reply all
Reply to author
Forward
0 new messages