waferthin
waferthin

Reputation: 1602

How to create dynamic table of key-value pairs with d3

I would like to dynamically generate a table of key-value pairs for a selectable data point using d3.

For example, for the data.csv file pasted below, I have d3 code that will plot the x,y values of the 4 data points as circles in an svg. I would like to be able to generate a table of key-value pairs when each circle is clicked. So, for point1 (row 1) the table would be:

<table>
<thead>
<tr> <th>Key</th>  <th>Value</th>  </tr>
</thead>
<tbody>
<tr> <td>name</td> <td>point1</td> </tr>
<tr> <td>x</td>    <td>50</td>     </tr>
<tr> <td>y</td>    <td>200</td>    </tr>
<tr> <td>f</td>    <td>1</td>      </tr>
</tbody>
</table>

This table is to be updated depending on the data point that is selected - note the headers stay the same, but the content of the table should change. Example data and my d3 + html code so far are below. Any help much appreciated.

data.csv

name,x,y,f
point1,50,170,1
point2,100,75,2
point3,150,125,3
point4,35,25,4

example.js

var svg = d3.select("body")
   .append("svg")
   .attr("width", 400)
   .attr("height", 200);

var mktable = function(dat) {
   console.log(dat)  // data is available!

   var tr = d3.select("tbody").selectAll("tr")
      .data(d3.keys(dat)).enter().append("tr")  

   var td = tr.selectAll("td")
      .data(function(d){return d})
      .enter().append("td")
      .text(function(d) {return d})
};

d3.text("data.csv", function(text) {
   var data = d3.csv.parse(text);

   svg.selectAll("circle")
      .data(data)
      .enter()
      .append("svg:circle")
      .attr("cx", function(d) {
         return parseFloat(d.x);
      })
      .attr("cy", function(d) {
         return parseFloat(d.y);
      })
      .attr("r", function(d) {
         return 3;
      })
      .on("mouseover", function() {
         d3.select(this)
            .attr("r", function(d) { return 7 });
      })
      .on("mouseout", function() {
         d3.select(this)
            .attr("r", function(d) { return 3 });
      })
      .on("click", mktable)
});

example.html

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>D3 Test</title>
     <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
 </head>
 <body>
   <script type="text/javascript" src="example.js"></script>
<table>
   <thead>
      <tr><th>Key</th><th>Value</th></tr>
   </thead>
   <tbody>
   </tbody>
</table>
 </body>
</html>

Upvotes: 0

Views: 2234

Answers (2)

waferthin
waferthin

Reputation: 1602

Progress - this mktable function generates the correct table for the first click, but clicking on a second point adds extra td elements rather than replacing them.

var mktable = function(dat, i) {
    var tr = d3.select("tbody").selectAll("tr")
        .data(d3.entries(dat));

     tr.enter().append("tr");

    tr.append("td")
        .text(function(d) { return d.key });

    tr.append("td")
        .text(function(d) { return d.value });

    tr.exit().remove();
 };

Upvotes: 2

danza
danza

Reputation: 12241

As you write attributes, you can also read them, handling the click event. So you can read any attribute you set in the vectorial circle element, and use them to generate the table.

If you need extra values, you can save them in a data- attribute in the circle, for example data-name. The data- attributes are structured this way in order to be complient with the w3c specifications.

In your case i think the table alignment would be hard to implement in an easy way, because the table is an HTML element and it cannot be appended to SVG elements. You could overlay the table with a z-index, probably, but i suggest you other techniques to show the value, like setting title or appending and SVG element.

Upvotes: 0

Related Questions