Solution 1 :

The usual trick for spacing is to just add a little fudge factor:

.attr("x", function(d) { return x(d.data.race) + 2; }) //<-- move right two pixels to stay centered
.attr("y", function(d) { return y(d[0] + d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
.attr("width", x.bandwidth() - 4) //<-- shorten width by 4

For your tooltip you are using a code snippet from an older version of d3. For d3.js version 6, the callback was modified to pass the event object where you can get the cursor position:

.on("mousemove", function(e,d) {
    var xPosition = e.offsetX - margin.left + 10;
    var yPosition = e.offsetY - margin.top - 10;
    tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
    tooltip.select("text").text(d[1]);
});

Working code:

<!DOCTYPE html>
<html lang="en">

<head>

<meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>Communities Fighting Covid</title>

  <!-- Bootstrap core CSS -->
  <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

  <!-- Custom styles for this template -->
  <link href="css/modern-business.css" rel="stylesheet">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>

</head>

<body>
<script>
        var margin = {top: 20, right: 160, bottom: 35, left: 30};

        var width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

        var svg = d3.select("body")
        .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 + ")");


        /* Data in strings like it would be if imported from a csv */

        var data = [
        { race: "A", positive: "60", total: "600"},
        { race: "C", positive: "58", total: "500"},
        { race: "D", positive: "85", total: "600"},
        { race: "E", positive: "56", total: "500"},
        { race: "F", positive: "89", total: "700"},
        { race: "G", positive: "62", total: "400"}
        ];


        // Transpose the data into layers
        var keys= ["positive", "total"];
        var dataset = d3.stack().keys(keys)(data);

        // Set x, y and colors
        var x = d3.scaleBand()
        .domain(data.map(function(d) { return d.race; }))
        .range([10, width-10], 0.02);

        var y = d3.scaleLinear()
        .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d[0] + d[1]; });  })])
        .range([height, 0]);

        var colors = ["b33040", "#d25c4d"];


        // Define and draw axes
        var yAxis = d3.axisLeft()
        .scale(y)
        .ticks(5)
        .tickSize(-width, 0, 0)
        .tickFormat( function(d) { return d } );

        var xAxis = d3.axisBottom()
        .scale(x)
        .tickFormat(data.race); // change this to get x values to reflect new

        svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

        svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);


        // Create groups for each series, rects for each segment 
        var groups = svg.selectAll("g.cost")
        .data(dataset)
        .enter().append("g")
        .attr("class", "cost")
        .style("fill", function(d, i) { return colors[i]; })


        var rect = groups.selectAll("rect")
        .data(function(d) { return d; })
        .enter()
        .append("rect")
        .attr("x", function(d) { return x(d.data.race) + 2; })
        .attr("y", function(d) { return y(d[0] + d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
        .attr("width", x.bandwidth() - 4)
        .on("mouseover", function() { tooltip.style("display", null); })
        .on("mouseout", function() { tooltip.style("display", "none"); })
        .on("mousemove", function(e,d) {
            var xPosition = e.offsetX - margin.left + 10;
            var yPosition = e.offsetY - margin.top - 10;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d[1]);
        });


        // Draw legend
        var legend = svg.selectAll(".legend")
        .data(colors)
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
        
        legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", function(d, i) {return colors.slice().reverse()[i];});
        
        legend.append("text")
        .attr("x", width + 5)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d, i) { 
            switch (i) {
            case 0: return "Total Cases";
            case 1: return "Positive Cases";
            }
        });


        // Prep the tooltip bits, initial display is hidden
        var tooltip = svg.append("g")
        .attr("class", "tooltip")
        .style("display", "none");
            
        tooltip.append("rect")
        .attr("width", 30)
        .attr("height", 20)
        .attr("fill", "white")
        .style("opacity", 0.5);

        tooltip.append("text")
        .attr("x", 15)
        .attr("dy", "1.2em")
        .style("text-anchor", "middle")
        .attr("font-size", "12px")
        .attr("font-weight", "bold")
        .attr("fill", "black")

        </script>

</body>

Problem :

I noticed that my bar chart doesn’t have the spacing between the bars that I was aiming to achieve. I also can’t seem to get the interactive tooltip to show up when I hover over the bars. I might need some help with this. The point of this is to get the value of the certain color to show up when an arrow is hovering over it.

Codepen link: codepen.io/irwinmier96/pen/qBaKmma

Here is my code.

<!DOCTYPE html>
<html lang="en">

<head>

<meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>Communities Fighting Covid</title>

  <!-- Bootstrap core CSS -->
  <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

  <!-- Custom styles for this template -->
  <link href="css/modern-business.css" rel="stylesheet">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>

</head>

<body>
<script>
        var margin = {top: 20, right: 160, bottom: 35, left: 30};

        var width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

        var svg = d3.select("body")
        .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 + ")");


        /* Data in strings like it would be if imported from a csv */

        var data = [
        { race: "A", positive: "60", total: "600"},
        { race: "C", positive: "58", total: "500"},
        { race: "D", positive: "85", total: "600"},
        { race: "E", positive: "56", total: "500"},
        { race: "F", positive: "89", total: "700"},
        { race: "G", positive: "62", total: "400"}
        ];


        // Transpose the data into layers
        var keys= ["positive", "total"];
        var dataset = d3.stack().keys(keys)(data);

        // Set x, y and colors
        var x = d3.scaleBand()
        .domain(data.map(function(d) { return d.race; }))
        .range([10, width-10], 0.02);

        var y = d3.scaleLinear()
        .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d[0] + d[1]; });  })])
        .range([height, 0]);

        var colors = ["b33040", "#d25c4d"];


        // Define and draw axes
        var yAxis = d3.axisLeft()
        .scale(y)
        .ticks(5)
        .tickSize(-width, 0, 0)
        .tickFormat( function(d) { return d } );

        var xAxis = d3.axisBottom()
        .scale(x)
        .tickFormat(data.race); // change this to get x values to reflect new

        svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

        svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);


        // Create groups for each series, rects for each segment 
        var groups = svg.selectAll("g.cost")
        .data(dataset)
        .enter().append("g")
        .attr("class", "cost")
        .style("fill", function(d, i) { return colors[i]; })


        var rect = groups.selectAll("rect")
        .data(function(d) { return d; })
        .enter()
        .append("rect")
        .attr("x", function(d) { return x(d.data.race); })
        .attr("y", function(d) { return y(d[0] + d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
        .attr("width", x.bandwidth())
        .on("mouseover", function() { tooltip.style("display", null); })
        .on("mouseout", function() { tooltip.style("display", "none"); })
        .on("mousemove", function(d) {
            var xPosition = d3.pointer(this)[0] - 15;
            var yPosition = d3.pointer(this)[1] - 25;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d.y);
        });


        // Draw legend
        var legend = svg.selectAll(".legend")
        .data(colors)
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
        
        legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", function(d, i) {return colors.slice().reverse()[i];});
        
        legend.append("text")
        .attr("x", width + 5)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d, i) { 
            switch (i) {
            case 0: return "Total Cases";
            case 1: return "Positive Cases";
            }
        });


        // Prep the tooltip bits, initial display is hidden
        var tooltip = svg.append("g")
        .attr("class", "tooltip")
        .style("display", "none");
            
        tooltip.append("rect")
        .attr("width", 30)
        .attr("height", 20)
        .attr("fill", "white")
        .style("opacity", 0.5);

        tooltip.append("text")
        .attr("x", 15)
        .attr("dy", "1.2em")
        .style("text-anchor", "middle")
        .attr("font-size", "12px")
        .attr("font-weight", "bold");

        </script>

</body>

Comments

Comment posted by CodePen

Could you make a

Comment posted by codepen.io/irwinmier96/pen/qBaKmma

codepen.io/irwinmier96/pen/qBaKmma

Comment posted by Irwin Mier

Hello thanks for your answer, I was able to create the spaces but the tooltip still does not work on my end. Is there other alternatives, since the number isn’t hovering over when I am hovering on the bars. I am using the same code.

Comment posted by Mark

@IrwinMier, which version of

Comment posted by cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js

I think whatever this version is, but it should be version 6

By