Plot nodes in d3.js Heatmap - Need Guidance - javascript
I'm new to d3.js implementation. Need some help d3.js heatmap
I have a Requirement :
A heat map which shows the difference between each record. based on records Severity and Probability types:
Desired Image :
Data:
In the Above output picture , You can see the circles :
Assume those as records being displayed on a graph .
Code for that starts after Comment " //Add dots or circles " .
Record data example :
{
"group":"Likely",
"variable":"Significant",
"value":79,
"record":"Retention of environmental safety records",
"color":"red"
}
Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping .
I have worked on a Heatmap Design .
Combining :
Heatmap : https://www.d3-graph-gallery.com/graph/heatmap_style.html
Connected scatter plot : https://www.d3-graph-gallery.com/graph/connectedscatter_tooltip.html
For now , I have just updated the data :
I have 2 Issues :
Overlapping dots issue
Tooltip not showing after Updating to svg
Detail:
1. Overlapping dots issue
Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping .
The desired Output is something like this : Circles should not be Overlapped .
If two records with same data , It should display 2 records. I need help in implenting that . Any suggestion is appreciated .
** 2. ToolTip Issue :**
I had an Issue with Tooltip (It was working with div tag ) previously it was as shown below :
Due to Some requirement i had to go with svg tag in the Html rather than Div tag . since This has to be implemented in Lwc in Salesforce.
Html Updated from div to Svg as shown below :
After Updating ,
Entire Heatmap is working except the Tooltip part .
Updated the Tooltip part to Svg as shown below :
Now the Tooltip is not working .
code :
<!-- Code from d3-graph-gallery.com -->
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v5.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz">
<svg
class="d3"
width={svgWidth}
height={svgHeight}
lwc:dom="manual"
></svg></div>
<!-- Load color palettes -->
<script>
// set the dimensions and margins of the graph
var margin = {top: 80, right: 25, bottom: 30, left: 100},
width = 550 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select(this.template.querySelector('svg.d3'))
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
var data = [{"group":"Rare","variable":"Insignificant","value":45,"color":"purple"},{"group":"Rare","variable":"Minimal","value":95,"color":"purple"},{"group":"Rare","variable":"Moderate","value":22,"color":"green"},{"group":"Rare","variable":"Significant","value":14,"color":"green"},{"group":"Rare","variable":"Catastrophic","value":59,"color":"yellow"},{"group":"Unlikely","variable":"Minimal","value":37,"color":"purple"},{"group":"Unlikely","variable":"Insignificant","value":37,"color":"purple"},{"group":"Unlikely","variable":"Moderate","value":81,"color":"green"},{"group":"Unlikely","variable":"Significant","value":79,"color":"yellow"},{"group":"Unlikely","variable":"Catastrophic","value":84,"color":"orange"},{"group":"Probable","variable":"Insignificant","value":96,"color":"purple"},{"group":"Probable","variable":"Minimal","value":37,"color":"green"},{"group":"Probable","variable":"Moderate","value":98,"color":"yellow"},{"group":"Probable","variable":"Significant","value":10,"color":"orange"},{"group":"Probable","variable":"Catastrophic","value":86,"color":"red"},{"group":"Likely","variable":"Insignificant","value":75,"color":"green"},{"group":"Likely","variable":"Minimal","value":18,"color":"yellow"},{"group":"Likely","variable":"Moderate","value":92,"color":"orange"},{"group":"Likely","variable":"Significant","value":43,"color":"red"},{"group":"Likely","variable":"Catastrophic","value":16,"color":"red"},{"group":"Almost Certain","variable":"Insignificant","value":44,"color":"green"},{"group":"Almost Certain","variable":"Minimal","value":29,"color":"yellow"},{"group":"Almost Certain","variable":"Moderate","value":58,"color":"orange"},{"group":"Almost Certain","variable":"Significant","value":55,"color":"red"},{"group":"Almost Certain","variable":"Catastrophic","value":65,"color":"red"}]; // Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
var myGroups = d3.map(data, function(d){return d.group;}).keys()
var myVars = d3.map(data, function(d){return d.variable;}).keys()
// Build X scales and axis:
var x = d3.scaleBand()
.range([ 0, width ])
.domain(myGroups)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickSize(0))
.select(".domain").remove()
// Build Y scales and axis:
var y = d3.scaleBand()
.range([ height, 0 ])
.domain(myVars)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.call(d3.axisLeft(y).tickSize(0))
.select(".domain").remove()
// Build color scale
var myColor = d3.scaleSequential()
.interpolator(d3.interpolateInferno)
.domain([1,100])
// create a tooltip
var tooltip = d3.select("#my_dataviz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
.style("position","fixed")
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover = function(d) {
tooltip
.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
}
var mousemove = function(d) {
tooltip
.html("The exact value of<br>this cell is: " + d.value)
.style("left", (d3.mouse(this)[0]+70) + "px")
.style("top", (d3.mouse(this)[1]) + "px")
}
var mouseleave = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
// add the squares
svg.selectAll()
.data(data, function(d) {return d.group+':'+d.variable;})
.enter()
.append("rect")
.attr("x", function(d) { return x(d.group) })
.attr("y", function(d) { return y(d.variable) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", x.bandwidth() )
.attr("height", y.bandwidth() )
.style("fill", function(d) { return d.color } )
.style("stroke-width", 4)
.style("stroke", "none")
.style("opacity", 0.8)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover1 = function(d) {
tooltip
.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
}
var mousemove1 = function(d) {
tooltip
.html("4. " + d.record)
.style("left", (d3.mouse(this)[0]+90) + "px")
.style("top", (d3.mouse(this)[1]) + "px")
}
var mouseleave1 = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
//Add dots or circles
var dots =
[{"group":"Likely","variable":"Significant","value":79,"record":"Retention of environmental safety records","color":"red"},
{"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk of Fines from European Union GDPR due to data breach","color":"orange"},
{"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk Management Case record","color":"green"}];
// Add the points
svg
.append("g")
.selectAll("dot")
.data(dots)
.enter()
.append("circle")
.attr("class", "myCircle")
.attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )
.attr("cy", function(d) { return y(d.variable)+ y.bandwidth()/2 } )
.attr("r", 8)
.attr("stroke", "#69b3a2")
.attr("stroke-width", 3)
.attr("fill", function(d) { return d.color })
.on("mouseover", mouseover1)
.on("mousemove", mousemove1)
.on("mouseleave", mouseleave1)
//})
// Add title to graph
svg.append("text")
.attr("x", 0)
.attr("y", -50)
.attr("text-anchor", "left")
.style("font-size", "22px")
.text("A heatmap");
// Add subtitle to graph
svg.append("text")
.attr("x", 0)
.attr("y", -20)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("fill", "grey")
.style("max-width", 400)
.text("A short description of the take-away message of this chart.");
</script>
Output (Updated) :
Can someone help me in resolving these issues.
I need to display the multiple dots inside the same squares, each dot as a seperate element . when you hover over it It should display the record it represents.
Any suggestion is appreciated . Thankyou
Give your tooltip a position of fixed:
.style("position","fixed")
This will allow the top and left attributes to impact its positioning.
To make the dots appear within the boxes, change your cx attribute to:
.attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )
That should center the dots within each box.
To give the dots their own positioning, the dots need to have their own y and x scales. Just make sure it has the same width and height.
Do you have another dataset for this? If not, I wonder if a different scale would give you the outcome you are looking for.
Related
Using d3.js to create a heatmap, having issues with color
Hi i have a heatmap here that im trying to give color to. Right now its all over red but I want to use the d3.interpolateRdYlBu, i want my values that are lower to be the blue and the higher be the red so i would like it to gel nicely. I know that its reading correctly since i get the red and no other errors in my console but Im not doing something right that it doesnt take my value into account and do accordingly. Any help would be appreciated! <!DOCTYPE html> <meta charset="utf-8"> <!-- Load d3.js --> <script src="https://d3js.org/d3.v4.js"></script> <!-- Create a div where the graph will take place --> <div id="my_dataviz"></div> <!-- Load color palettes --> <script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script> <script> // set the dimensions and margins of the graph var margin = {top: 80, right: 25, bottom: 30, left: 40}, width = 1000 - margin.left - margin.right, height = 1000 - margin.top - margin.bottom; // append the svg object to the body of the page var svg = d3.select("#my_dataviz") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //Read the data d3.csv("https://raw.githubusercontent.com/Nataliemcg18/Data/master/NASA_Surface_Temperature.csv", function(data) { // Labels of row and columns -> unique identifier of the column called 'group' and 'variable' var myGroups = d3.map(data, function(d){return d.group;}).keys() var myVars = d3.map(data, function(d){return d.variable;}).keys() // Build X scales and axis: var x = d3.scaleBand() .range([ 0, width ]) .domain(myGroups) .padding(0.05); svg.append("g") .style("font-size", 15) .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).tickSize(0)) .select(".domain").remove() // Build Y scales and axis: var y = d3.scaleBand() .range([ height, 0 ]) .domain(myVars) .padding(0.05); svg.append("g") .style("font-size", 15) .call(d3.axisLeft(y).tickSize(0)) .select(".domain").remove() // Build color scale var myColor = d3.scaleSequential() .interpolator( d3.interpolateRdYlBu) .domain([1,100]) // create a tooltip var tooltip = d3.select("#my_dataviz") .append("div") .style("opacity", 0) .attr("class", "tooltip") .style("background-color", "white") .style("border", "solid") .style("border-width", "2px") .style("border-radius", "5px") .style("padding", "5px") // Three function that change the tooltip when user hover / move / leave a cell var mouseover = function(d) { tooltip .style("opacity", 1) d3.select(this) .style("stroke", "green") .style("opacity", 1) } var mousemove = function(d) { tooltip .html("The exact value of this cell is: " + d.value, ) .style("left", (d3.mouse(this)[0]+70) + "px") .style("top", (d3.mouse(this)[1]) + "px") } var mouseleave = function(d) { tooltip .style("opacity", 0) d3.select(this) .style("stroke", "none") .style("opacity", 0.8) } // add the squares svg.selectAll() .data(data, function(d) {return d.group+':'+d.variable;}) .enter() .append("rect") .attr("x", function(d) { return x(d.group) }) .attr("y", function(d) { return y(d.variable) }) .attr("rx", 4) .attr("ry", 4) .attr("width", x.bandwidth() ) .attr("height", y.bandwidth() ) .style("fill", function(d) { return myColor(d.value)} ) .style("stroke-width", 4) .style("stroke", "none") .style("opacity", 0.8) .on("mouseover", mouseover) .on("mousemove", mousemove) .on("mouseleave", mouseleave) }) // Add title to graph svg.append("text") .attr("x", 0) .attr("y", -50) .attr("text-anchor", "left") .style("font-size", "22px") .text("A d3.js heatmap"); // Add subtitle to graph svg.append("text") .attr("x", 0) .attr("y", -20) .attr("text-anchor", "left") .style("font-size", "14px") .style("fill", "grey") .style("max-width", 400) .text("A short description of the take-away message of this chart."); </script>
In your colour scale, you've set the domain as [0,100]. Your values however are between 0 and 1.5, and you want them reversed so, this should fix it: // Build color scale var myColor = d3.scaleSequential() .interpolator( d3.interpolateRdYlBu) .domain([1.3,0]) To be even more thorough, you can use the d3.max and d3.min functions to work out the max in min for you: var myColor = d3.scaleSequential() .interpolator( d3.interpolateRdYlBu) .domain([d3.max(data, d=>d.value),d3.min(data, d=>d.value)]) Heres a jsFiddle with this working: https://jsfiddle.net/x8zyud5t/
d3.event.pageX & d3.mouse(this)[0]
I tried to figure out the difference between 'd3.event.pageX' & 'd3.mouse(this)[0]'. I guessed both are same but, when I console.log both, the value was different by '8' in my code. var height=600; var width=600; var graphgap=60; d3.csv('./details.csv').then(function(data){ var svg =d3.select('section').append('svg') .attr('width',600).attr('height',600) .on('mousemove',mousemove) drawrect(data); }) function drawrect(data){ let bars=d3.select('svg').selectAll('rect').data(data); bars.enter().append('rect').classed('bargraph',true) .attr('x',function(d,i){return (i+1)*graphgap}) .attr('y',function(d){return height-(d.Age)*5}) .attr('width',55) .attr('height',function(d){return (d.Age)*(5)}) } function mousemove(){ let mouselocation =[]; d3.select('svg').append('text') .text(d3.event.pageX) .attr('x',d3.event.pageX) .attr('y',d3.event.pageY) console.log(d3.event.pageX) console.log(d3.mouse(this)[0]) } So, I think these two are two different things. Can anyone let me know why it makes a difference? The reason why I tried to figure this out is because I was re-writing the code below. <script> // set the dimensions and margins of the graph var margin = {top: 10, right: 30, bottom: 30, left: 60}, width = 460 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; // append the svg object to the body of the page var svg = d3.select("#my_dataviz") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //Read the data d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_IC.csv",function(data) { // Add X axis --> it is a date format var x = d3.scaleLinear() .domain([1,100]) .range([ 0, width ]); svg.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); // Add Y axis var y = d3.scaleLinear() .domain([0, 13]) .range([ height, 0 ]); svg.append("g") .call(d3.axisLeft(y)); // This allows to find the closest X index of the mouse: var bisect = d3.bisector(function(d) { return d.x; }).left; // Create the circle that travels along the curve of chart var focus = svg .append('g') .append('circle') .style("fill", "none") .attr("stroke", "black") .attr('r', 8.5) .style("opacity", 0) // Create the text that travels along the curve of chart var focusText = svg .append('g') .append('text') .style("opacity", 0) .attr("text-anchor", "left") .attr("alignment-baseline", "middle") // Create a rect on top of the svg area: this rectangle recovers mouse position svg .append('rect') .style("fill", "none") .style("pointer-events", "all") .attr('width', width) .attr('height', height) .on('mouseover', mouseover) .on('mousemove', mousemove) .on('mouseout', mouseout); // Add the line svg .append("path") .datum(data) .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-width", 1.5) .attr("d", d3.line() .x(function(d) { return x(d.x) }) .y(function(d) { return y(d.y) }) ) // What happens when the mouse move -> show the annotations at the right positions. function mouseover() { focus.style("opacity", 1) focusText.style("opacity",1) } function mousemove() { // recover coordinate we need var x0 = x.invert(d3.mouse(this)[0]); var i = bisect(data, x0, 1); selectedData = data[i] focus .attr("cx", x(selectedData.x)) .attr("cy", y(selectedData.y)) focusText .html("x:" + selectedData.x + " - " + "y:" + selectedData.y) .attr("x", x(selectedData.x)+15) .attr("y", y(selectedData.y)) } function mouseout() { focus.style("opacity", 0) focusText.style("opacity", 0) } }) </script>
In documentation is written: While you can use the native event.pageX and event.pageY, it is often more convenient to transform the event position to the local coordinate system of the container that received the event using d3.mouse, d3.touch or d3.touches. d3.event d3.mouse - uses local coordinate (without margin (60px)) d3.event.pageX - uses global coordinate (with margin (60px)) But local cordinate start on 68px. I guess 8 pixels is used to describe the y-axis.
D3.js Mouseover text inside donut chart
possible duplicates: D3 text on mouseover D3 donut chart text centering but unsure what is happening in respect to my problem and quite stuck. Im building a data visualization with many layouts. I am currently trying to make a piechart with text centered in the middle and whenever someone mouse overs the arcs, it displays the text of it in the center. function GUP_PieRender() { var svg = d3.select(targetDOMelement).append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var g = svg.selectAll(".arc") .data(pie(dataset)) .enter().append("g") .attr("class", "arc") .on("mouseover", function(d) { d3.select("text").text(d.data.ResearchArea)}); //Problem area g.append("path") .attr("d", arc) .style("fill", function(d) { return color(d.data.ResearchArea); }); g.append("text") .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) .attr("dy", ".35em") .style("text-anchor", "middle"); } What it is doing instead is displaying the text in another D3 barchart layout that has text. So I must be calling the mouseover event too early and appending it to the last text element in that? Can I get a remedy? Thanks.
The problem here (inside your "mouseover" handler) is simply this: d3.select("text") When you do this, D3 selects the first text element it finds in that page. You don't want that, obviously. Therefore, just do: g.select("text") That way, you only select text elements inside your g selection. Alternatively, you can also do: d3.select(this).select("text") Since this in this context is the group element. Here is a demo (I'm trying to imitate your code): var data = ["foo", "bar", "baz"]; data.forEach(function(d) { render(d); }) function render(data) { var svg = d3.select("body") .append("svg") .attr("width", 100) .attr("height", 100); var g = svg.selectAll(null) .data([data]) .enter() .append("g") .on("mouseover", function(d) { g.select("text").text(String) }) .on("mouseout", function(d) { g.select("text").text(null) }) g.append("circle") .attr("cx", 50) .attr("cy", 50) .attr("r", 20); g.append("text") .attr("x", 25) .attr("y", 20); } svg { background-color: tan; border: 1px solid darkgray; margin-right: 10px; } circle { fill: teal; } <script src="https://d3js.org/d3.v4.min.js"></script>
How to get second bars to show on grouped bar chart?
I'm trying to get a second bar into my graph. The elements are correctly getting appended but not in the correct location and not the correct height. What I want from the data to be at the 1 position in the x-axis to have 2 bars one with a height of 2 and the other height of 3 and so on. http://jsfiddle.net/626uesbh/4/ var svg2 = d3.select("#histogram").append("svg2") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg2.selectAll(".rect") .data(data) .enter().append("g") .attr("transform", "translate(0, 100)") .append("rect") .attr("class", "rect") .attr("width", 10) .attr("height", function(d) { return height - y2Map(d); }) .attr("x", xMap) .attr("y", yMap) .style("fill", "blue"); I suspect svg2 transform is the problem but after trying fiddling with it for an hour I can seem to get what I want. I looked at this question and tried to implement it into my problem. D3.js grouped bar chart
Since each element in your data contains the values for both bars, you have to add them as a group. That is, add a 'g' element to the chart for each element in the array, then add a bar for inner_array[1] and inner_array[2]. Hopefully this gets you on the right path, essentially all I changed was the stuff after your //bar comment. http://jsfiddle.net/626uesbh/6/ // bar var bar_groups = svg.selectAll('.bar-group') .data(data) .enter().append('g') .attr('class', 'bar-group'); bar_groups.append('rect') .attr("class", "rect") .attr("width", 10) .attr("height", function(d) { return height - yScale(d[1]); }) .attr("x", function(d) { return xScale(d[0]) - 5; }) .attr("y", function(d) { return yScale(d[1]); }) .style("fill", "green"); bar_groups.append('rect') .attr("class", "rect") .attr("width", 10) .attr("height", function(d) { return height - yScale(d[2]); }) .attr("x", function(d) { return xScale(d[0]) + 5; }) .attr("y", function(d) { return yScale(d[2]); }) .style("fill", "blue"); Note: there are much more elegant ways to do this. I am only showing you how to add the bars to your existing code. Please take a look at http://bl.ocks.org/mbostock/3887051 for further guidance.
Appending lines to D3 bar chart - absolutely nothing happens
I have an otherwise fine working grouped bar chart script to which I'm trying to add simple reference lines. The relevant code: //Set up margins and dimensions according to http://bl.ocks.org/3019563 var margin = {top: 20, right: 10, bottom: 20, left: 30}, width = 810 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* Set up the primary x scale */ var x0 = d3.scale.ordinal() .rangeRoundBands([0, width], .1) .domain(data.map(function (d) { return options.xPrimaryScaleAccessor(d); })); /* Set up the secondary x scale */ var x1 = d3.scale.ordinal() .domain(xSecondaryScaleValues) .rangeRoundBands([0, x0.rangeBand()]); /* Set up the y scale as a linear (continous) scale with a total range of 0 - full height and a domain of 0-100 */ var y = d3.scale.linear() .range([height, 0]) .domain([0, 100]); /* Set up a color space of 20 colors */ var color = d3.scale.category20(); /* Set up the x axis using the primary x scale and align it to the bottom */ var xAxis = d3.svg.axis() .scale(x0) .orient("bottom"); /* Set up the y axis using the y scale and align it to the left */ var yAxis = d3.svg.axis() .scale(y) .orient("left"); /* Create an SVG element and append it to the body, set its dimensions, append a <g> element to * it and apply a transform translating all coordinates according to the margins set up. */ var svg = d3.select(options.target).append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //Create a space for definitions var defs = svg.append("defs"); setupDropShadowFilter(defs, 3, 3, 3); //Sets up a gaussian blur filter with id 'drop-shadow' /* Append a <g> element to the chart and turn it into a representation of the x axis */ svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); /* Append a <g> element to the chart and turn it into a representation of the y axis */ svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text(options.yLabel); var dataArr = y.ticks(yAxis.ticks()); /* Draw the reference lines */ svg.selectAll("line") .data(dataArr) .enter().append("line") .attr("x1", 0) .attr("x2", width) .attr("y1", y) .attr("y2", y) .style("stroke", "#ccc"); /* Set up the bar groups */ var group = svg.selectAll(".group") .data(data) .enter().append("g") .attr("class", "g") .attr("transform", function(d) { return "translate(" + x0(options.xPrimaryScaleAccessor(d)) + ",0)"; }); /* Draw the bars */ group.selectAll("rect") .data(options.valueAccessor) .enter().append("rect") .attr("width", x1.rangeBand()) .attr("x", function(d) { return x1(d.label); }) .attr("y", function(d) { return y(d.value); }) .attr('rx', options.barCornerRadius) .attr('ry', options.barCornerRadius) .attr("height", function(d) { return height - y(d.value); }) .style("fill", function(d) { return getStripedPattern(defs, color(d.label)); //Sets up a pattern and returns its ID })//Todo: fill with pattern instead. see http://tributary.io/tributary/2929255 .style("filter", "url(#drop-shadow)"); /* Draw a legend */ var legend = svg.selectAll(".legend") .data(xSecondaryScaleValues) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + (xSecondaryScaleValues.length-i-.25) * (height/xSecondaryScaleValues.length) + ")"; }); legend.append("rect") .attr("x", width - 9) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("y", 9) //.attr("dy", ".35em") .attr("transform", "translate(" + (width - 6) + ",-8)rotate(-90)" ) .style("text-anchor", "start") .text(function(d) { return d; }); EDIT: I have also tried to append rect elements instead with hardcoded coordinates and dimensions, but those also didn't make it to the DOM. EDIT 2: More or less full code now included. Basically, nothing happens. No lines are appended and there are no errors in the console. The dataArr is a plain array of numbers and y(number) is confirmed to return good values in the output range. I think (and debug suggests) that the chain dies at the append() stage, possibly because .enter() return something useless. Console log after .data(): Console log after .enter(): Console log after .append(): I've been stuck on this for a good while now, so grateful for any ideas about what may go wrong. I'm sure I'm overlooking something obvious...
The problem is that the code that generates the axes appends line elements to the SVG. As it is run before appending the reference lines, calling svg.selectAll("line").data(...) matches the existing lines with the data. There are more lines than data elements, so no new elements need to be added and the .enter() selection is empty. There are a few ways to fix this. You could move the code that generates the reference lines further up. You add a g element that contains these lines. You could have a special class for these lines and adjust the selector accordingly. Or you could provide a custom matching function to .data().