Your problem is with the offset of the bars from each other; if you hard-code a value, e.g. using translate(0,29)
, you are going to be in trouble when the chart data changes, and that makes the bars change size, too. To prevent that happening, set the translate value relative to the size of the bar:
//Appends first bar var bars = categoryGroup.append("rect") .attr("width", function(d) { return xScale(d.num); }) .attr("height", y0.rangeBand()/2.5 ) .attr("class", "g-num")var bars2 = categoryGroup.append("rect") .attr("width", function(d) { return xScale(d.num2); }) .attr("height", y0.rangeBand()/2.5 ) .attr("class", "g-num2") .attr("transform", "translate(0,"+ ( y0.rangeBand()/2.5 ) +")");
This way, no matter how many or how few bars you have in the chart, the offset of bars2
will always be the same size as the height of the bars, i.e. y0.rangeBand()/2.5
.
I'd advise you to standardise the bar label position in a similar manner, but add in a fixed y
offset using the dy
attribute:
//Appends first bar labels var barLabels = labelGroup.append("text") .text(function(d) {return d.num;}) .attr("x", function(d) { return xScale(d.num) - 20; }) .attr("y", y0.rangeBand()/2.5 ) // note: use 2.5, rather than 2.65 .attr('dy', '-0.35em') // fixed y offset, set relative to the text size .attr("class", "g-labels"); //Appends second bar labels var barLabels2 = labelGroup.append("text") .text(function(d) {return d.num2;}) .attr("x", function(d) { return xScale(d.num2) - 20; }) .attr("y", y0.rangeBand()/1.25 ) .attr('dy', '-0.35em') // fixed y offset .attr("class", "g-labels");
Here's your full example:
/* ----- Data ----- */var json_data = {"headers":["Month","Country","Number"],"rows":[["2018-05-01 00:00:00.0","Germany",19],["2018-05-01 00:00:00.0","United Kingdom",23],["2018-04-01 00:00:00.0","Germany",21],["2018-04-01 00:00:00.0","United Kingdom",129] ]};var dataRows = json_data.rows;/* ----- !Data ----- *//* ----- Functions ----- *///Create dictionary function (transformed JSON)createDict = (data) => { let groups = data.reduce((acc, arr) => { if (acc.hasOwnProperty(arr[1])) { acc[arr[1]].push(arr); } else { acc[arr[1]] = [arr]; } return acc; }, {}); let results = []; for (let g in groups) { let obj = {Value: g}; let a = groups[g][0]; let b = groups[g][1]; if (a[0] <= b[0]) { obj.num = a[2]; obj.num2 = b[2]; } else { obj.num = b[2]; obj.num2 = a[2]; } results.push(obj); } return results;}//Returns unique values of a specific object of a JSON stringuniqueValues = (data,objectNum) => {var uniqueValues = [];data.forEach(function(item) { var value = item[objectNum]; if (uniqueValues.indexOf(value) !== -1) return false; uniqueValues.push(value);});return uniqueValues;}//Chart creation functioncreateChart = (data) => { //Margin conventions console.log(data) var margin = {top: 10, right: 50, bottom: 20, left: 70}; var widther = window.outerWidth; var width = widther - margin.left - margin.right, height = 400 - margin.top - margin.bottom; //Appends the svg to the chart-container div var svg = d3.select(".g-chart").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 +")"); //Creates the xScale var xScale = d3.scale.linear() .range([0,width]); //Creates the yScale var y0 = d3.scale.ordinal() .rangeBands([height, 0], 0.2) .domain(uniqueValues); console.log(d3.scale.ordinal().rangeBands([height, 0], 0.2) ); //.domain(["Spain", "UK", "Germany", "France", "Italy"]); //Defines the y axis styles var yAxis = d3.svg.axis() .scale(y0) .orient("left"); //Defines the y axis styles var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom") .tickFormat(function(d) {return d; }) //Change axis values for percentage //.tickFormat(function(d) {return d +"%"; }) .tickSize(height) .ticks(numTicks(width)); //FORMAT data data.forEach(function(d) { d.num = +d.num; }); //Sets the max for the xScale var maxX = d3.max(data, function(d) { return d.num; }); //Defines the xScale max xScale.domain([0, maxX ]); //Appends the y axis var yAxisGroup = svg.append("g") .attr("class", "y axis") .call(yAxis); //Appends the x axis var xAxisGroup = svg.append("g") .attr("class", "x axis") .call(xAxis); //Binds the data to the bars var categoryGroup = svg.selectAll(".g-category-group") .data(data) .enter() .append("g") .attr("class", "g-category-group") .attr("transform", function(d) { return "translate(0,"+ y0(d.Value) +")"; }); //Appends first bar var bars = categoryGroup.append("rect") .attr("width", function(d) { return xScale(d.num); }) .attr("height", y0.rangeBand()/2.5 ) .attr("class", "g-num")// .attr("transform", "translate(0,4)"); //Appends second bar var bars2 = categoryGroup.append("rect") .attr("width", function(d) { return xScale(d.num2); }) .attr("height", y0.rangeBand()/2.5 ) .attr("class", "g-num2") .attr("transform", "translate(0,"+ ( y0.rangeBand()/2.5 ) +")"); //Binds data to labels var labelGroup = svg.selectAll("g-num") .data(data) .enter() .append("g") .attr("class", "g-label-group") .attr("transform", function(d) { return "translate(0,"+ y0(d.Value) +")"; }); //Appends first bar labels var barLabels = labelGroup.append("text") .text(function(d) {return d.num;}) .attr("x", function(d) { return xScale(d.num) - 20; }) .attr("y", y0.rangeBand()/2.5 ) .attr('dy', '-0.35em') .attr("class", "g-labels"); //Appends second bar labels var barLabels2 = labelGroup.append("text") .text(function(d) {return d.num2;}) .attr("x", function(d) { return xScale(d.num2) - 20; }) .attr("y", y0.rangeBand()/1.25 ) .attr('dy', '-0.35em') .attr("class", "g-labels"); //Appends chart source d3.select(".g-source-bold") .text("SOURCE: ") .attr("class", "g-source-bold"); d3.select(".g-source-reg") .text("Chart source info goes here") .attr("class", "g-source-reg"); //RESPONSIVENESS d3.select(window).on("resize", resized); function resized() { //new margin var newMargin = {top: 10, right: 80, bottom: 20, left: 50}; //Get the width of the window var w = d3.select(".g-chart").node().clientWidth; console.log("resized", w); //Change the width of the svg d3.select("svg") .attr("width", w); //Change the xScale xScale .range([0, w - newMargin.right]); //Update the bars bars .attr("width", function(d) { return xScale(d.num); }); //Update the second bars bars2 .attr("width", function(d) { return xScale(d.num2); }); //Updates bar labels barLabels .attr("x", function(d) { return xScale(d.num) - 20; }) .attr("y", y0.rangeBand()/2.65 ) //Updates second bar labels barLabels2 .attr("x", function(d) { return xScale(d.num2) - 20; }) .attr("y", y0.rangeBand()/1.25 ) //Updates xAxis xAxisGroup .call(xAxis); //Updates ticks xAxis .scale(xScale) .ticks(numTicks(w)); }; //} //Determines number of ticks base on width function numTicks(widther) { if (widther <= 400) { return 4 console.log("return 4") } else { return 10 console.log("return 5") } }}/* ----- !Functions ----- */ /* ----- Main ----- */var data = createDict(dataRows);//Calculate unique Values var uniqueValues = uniqueValues(dataRows,1);createChart(data);/* ----- !Main ----- */
/*css to go here*/ @import url(https://fonts.googleapis.com/css?family=Karla); body { font-family: 'Karla', sans-serif; font-size: 12px; } .g-hed { text-align: left; text-transform: uppercase; font-weight: bold; font-size:22px; margin: 3px 0; } .g-source-bold { text-align: left; font-size:10px; font-weight: bold; } .g-source { margin: 10px 0; } .g-source-bold { text-align: left; font-size:10px; } .g-intro { font-size: 16px; margin: 0px 0px 10px 0px; } .g-num { fill:#124; } .g-num2 { fill:#ccc; } .g-labels { fill: white; font-weight: bold; font-size: 13px; } .axis line { fill: none; stroke: #ccc; stroke-dasharray: 2px 3px; shape-rendering: crispEdges; stroke-width: 1px; } .axis text { font-size: 13px; pointer-events: none; fill: #7e7e7e; } .domain { display: none; } .y.axis text { text-anchor: end !important; font-size:14px; fill: #000000; } .y.axis line { display: none; } .g-baseline line { stroke:#000; stroke-width: 1px; stroke-dasharray:none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script><body><h5 class="g-hed"></h5><p class="g-intro"></p><div class="g-chart"></div><div class="g-source"><span class="g-source-bold"></span><span class="g-source-reg"></span></div></div></body>