Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render rectangles in a D3 grouped bar chart using React Faux DOM?

I am achingly close to finishing a group bar chart in React using react-faux-dom package. Everything is set except for the actual rectangles. Been spinning my wheels for a few hours so I'm hoping someone can see what I'm missing. The example that I'm working from is here. My goal is to have a time scale x-axis with multi bar groups. The X and Y axes are currently rendering without issue.

Data structure currently looks like so:

[   {key: "oauths", values: [     { date: Tue Jul 26 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 3060},     { date: Tue Jul 27 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 2060},     { date: Tue Jul 28 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 3270},   ...]},   {key: "user_stats", values: [     { date: Tue Jul 26 2016 00:00:00 GMT-1000 (HST), key: "user_stats", value: 2976},     ...   ]} ] 

The React component's render method is below. It error on the final svg.append()...

render() {     const data = [ {}, {} ]; // see above      // Constants     const margin = {top: 30, right: 20, bottom: 30, left: 50},           width = 600 - margin.left - margin.right,           height = 400 - margin.top - margin.bottom,           n = this.props.dataQueryPeriod.length, // number of samples           m = 2; // number of series      // Parse the date / time     const parseDate = d3.time.format("%Y-%m-%d").parse;      // Set ranges     const yScale = d3.scale.linear()       .range([height, 0]);      const x0 = d3.scale.ordinal()       .domain(d3.range(n))       .rangeBands([0, width], .2);      const x1 = d3.scale.ordinal()       .domain(d3.range(m))       .rangeBands([0, x0.rangeBand()]);      const xScale = d3.time.scale().range([0, width]);      // Test colors     var z = d3.scale.category10();      // Define axes     const xAxis = d3.svg.axis()       .scale(xScale)       .orient("bottom")       .ticks(d3.time.days);      const yAxis = d3.svg.axis()       .scale(yScale)       .orient("left")       .tickFormat(d3.format("s"));      // Convert structured data to nested data     const nest = d3.nest()         .key(function(d) { return d.key; })         .sortKeys(d3.ascending);      // Create node     let node = ReactFauxDOM.createElement('svg');      let svg = d3.select(node)         .attr("width", width + margin.left + margin.right)         .attr("height", height + margin.top + margin.bottom+40)       .append("g")         .attr("transform", `translate(${margin.left},${margin.top})`);      data.forEach(function(d) {       d.date = parseDate(d.date);       d.value = +d.value;     });      const nestedData = nest.entries(data);     console.log("nested data", nestedData);     console.log("pre nest data", data);      // Define axes domains     xScale.domain(d3.extent(data, function(d) { return d.date; }));     yScale.domain([0, d3.max(data, function(d) { return d.value; })]);      svg.append("g")       .attr("class", "y axis")       .call(yAxis);      svg.append("g")       .attr("class", "x axis")       .attr("transform", `translate(0,${height})`)       .call(xAxis)       .selectAll("text")           .style("text-anchor", "end")           .attr("dx", "-.8em")           .attr("dy", ".15em")           .attr("transform", function(d) {             return "rotate(-65)";           });      svg.append("g").selectAll("g")         .data(nestedData)       .enter().append("g")         .style("fill", function(d, i) { return z(i); })         .attr("transform", function(d, i) { return `translate(${x1(i)},0)`; })       .selectAll("rect")         .data(function(d) { return d.value; })       .enter().append("rect")         .attr("width", x1.rangeBand())         .attr("height", yScale)         .attr("x", function(d, i) { return x0(i); })         .attr("y", function(d) { return height - yScale(d.value); });      return node.toReact();   } 
like image 237
Kwhitejr Avatar asked Jul 29 '16 02:07

Kwhitejr


1 Answers

If your data is starting out like the example you provided, it's already nested and d3.nest(). Assuming that the data from your example is nestedData, then your problem is that you need to bind values not value. See below:

svg.append("g").selectAll("g")     .data(nestedData)     .enter()     .append("g")     .style("fill", function(d, i) { return z(i); })     .attr("transform", function(d, i) { return `translate(${x1(i)},0)`; })     .selectAll("rect")     .data(function(d) { return d.values; }) // This needs to be values     .enter().append("rect")     .attr("width", x1.rangeBand())     .attr("height", yScale)     .attr("x", function(d, i) { return x0(i); })     .attr("y", function(d) { return height - yScale(d.value); }); 
like image 57
SmokeyShakers Avatar answered Sep 24 '22 10:09

SmokeyShakers