Home > Software design >  d3.js Bar Chart - No Y Axis scale
d3.js Bar Chart - No Y Axis scale

Time:08-14

I have a d3.js bar chart, but the X axis columns have no height, presumably because there is no data/scale for the Y axis. The last column should display.

enter image description here

The JSON:

[{"Domain":"Knowledge","Knowledge":0},{"Domain":"Problem Solving","problem_solving":0},{"Domain":"Skill","skill":0},{"Domain":"Transferable","transferable":100}]

The chart:

var margin = {top: 50, right: 135, bottom: 70, left: 80},
    width = 1050 - margin.left - margin.right,
    height = 540 - margin.top - margin.bottom;  

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

// load the data
d3.json("json/domains.json", function(error, data) {



// Transpose the data into layers
var dataset = d3.layout.stack()(["Knowledge", "Problem Solving, Skill, Transferable"].map(function(lvl) {
  return data.map(function(d) {
    return {
      x: d.Domain,
      y: d[lvl]
    };
  });
}));

  var disciplines = d3.nest()
    .key(function(d){return d.Domain})
    .rollup(function(leaves){
      return d3.sum(leaves, function(d) {return d3.sum(d3.values(d))});
    })
    .entries(data);

  // Set x, y and colors
  var x = d3.scale.ordinal()
    .domain(dataset[0].map(function(d) { return d.x; }))
    .rangeRoundBands([10, width-10], 0.35, 0);

  var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0   d.y; });  })])
    .range([height, 0]);

  var colors = ["#83d1c4", "#f17950", "#838BD1", "#F150BE"];

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

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .outerTickSize(0)
  
  
  d3.select('.y axis .tick:first-child').remove();
  
  var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-0, 0])
  .html(function(d) {
    return d.y   '%';
  })
    
svg.call(tip);

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


  svg.append("g")
    .call(xAxis)
    .attr("class", "x axis")
    .attr("transform", "translate(0,"   height   ")")
    .call(xAxis);
    
    svg.append("text")
  .attr("x", 390 )
  .attr("y",  480 )
  .style("text-anchor", "middle")
  .text("Disciplines");
    
svg.append("text")
   .attr("x", -200 )
   .attr("y",  -40 )
   .attr("transform", "rotate(-90)" )
   .attr('style', 'font-size:12px')
   .style("text-anchor", "middle")
   .text("Percentage of Learning Events");

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

//  var svg = d3.select("svg");
  var bar = groups.selectAll("g")
    .data(function(d) { return d; })
    .enter().append("g")
    .attr("transform", function(d, i) {
      return "translate("   x(d.x)   ", 0)";
    });

  var sum=0;
  bar.append("rect")
    .attr("y", function(d) { return y(d.y0   d.y); })
    .attr("height", function(d) { return y(d.y0) - y(d.y0   d.y); })
    .attr('class', 'segment')
    .attr("width", x.rangeBand())
    .on('mouseover', tip.show)
    .on('mouseout', tip.hide);


  columns = svg.append("g")
    .selectAll("text").data(disciplines)
    .enter().append("text")
    .attr("x", function(d){
      return x(d.key)   x.rangeBand()/2
    })
    .attr("y", function (d) {
      return y(d.values);
    })
    .attr("dy", "-0.7em")
    .attr('style', 'font-size:11px')
    .text( function (d){
      return d3.format(".2f")(d.values)   '%';
    })
    .style({fill: 'black', "text-anchor": "middle"});



  // Draw legend
var legend = svg.selectAll(".legend")
  .data(colors)
  .enter().append("g")
  .attr("class", "legend")
    .attr('style', 'font-size:12px')
  .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 "Knowledge";
      case 1:
        return "Problem Solving";
      case 2:
        return "Skill";
      case 3:
        return "Transferable";
      }
    });
    
    });

I have another d3.js chart, which uses practically the same chart code as above and JSON format, just the data is different, columns and Y axis graduations show OK:

enter image description here

UPDATE

Changed 'Domain' key in the JSON to 'Dom' so as not to cause any conflict with the d3.js function .domain (makes no difference to the chart though...):

JSON:

[{"Dom":"Knowledge","Knowledge":0},{"Dom":"Problem Solving","problem_solving":0},{"Dom":"Skill","skill":0},{"Dom":"Transferable","transferable":100}]

Chart:

var margin = {top: 50, right: 135, bottom: 70, left: 80},
    width = 1050 - margin.left - margin.right,
    height = 540 - margin.top - margin.bottom;  

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

// load the data
d3.json("json/domains.json", function(error, data) {



// Transpose the data into layers
var dataset = d3.layout.stack()(["Knowledge", "Problem Solving", "Skill", "Transferable"].map(function(lvl) {
  return data.map(function(d) {
    return {
      x: d.Dom,
      y: d[lvl]
    };
  });
}));

  var domains = d3.nest()
    .key(function(d){return d.Dom})
    .rollup(function(leaves){
      return d3.sum(leaves, function(d) {return d3.sum(d3.values(d))});
    })
    .entries(data);

  // Set x, y and colors
  var x = d3.scale.ordinal()
    .domain(dataset[0].map(function(d) { return d.x; }))
    .rangeRoundBands([10, width-10], 0.35, 0);

  var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0   d.y; });  })])
    .range([height, 0]);

  var colors = ["#50E0C8", "#f17950", "#C283D1", "#50BCF1"];

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

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .outerTickSize(0)
  
  
  d3.select('.y axis .tick:first-child').remove();
  
  var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-0, 0])
  .html(function(d) {
    return d.y   '%';
  })
    
svg.call(tip);

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


  svg.append("g")
    .call(xAxis)
    .attr("class", "x axis")
    .attr("transform", "translate(0,"   height   ")")
    .call(xAxis);
    
    svg.append("text")
  .attr("x", 390 )
  .attr("y",  480 )
  .style("text-anchor", "middle")
  .text("Domains");
    
svg.append("text")
   .attr("x", -200 )
   .attr("y",  -40 )
   .attr("transform", "rotate(-90)" )
   .style("text-anchor", "middle")
   .text("Percentage of Learning Events");

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

//  var svg = d3.select("svg");
  var bar = groups.selectAll("g")
    .data(function(d) { return d; })
    .enter().append("g")
    .attr("transform", function(d, i) {
      return "translate("   x(d.x)   ", 0)";
    });

  var sum=0;
  bar.append("rect")
    .attr("y", function(d) { return y(d.y0   d.y); })
    .attr("height", function(d) { return y(d.y0) - y(d.y0   d.y); })
    .attr('class', 'segment')
    .attr("width", x.rangeBand())
    .on('mouseover', tip.show)
    .on('mouseout', tip.hide);


  columns = svg.append("g")
    .selectAll("text").data(domains)
    .enter().append("text")
    .attr("x", function(d){
      return x(d.key)   x.rangeBand()/2
    })
    .attr("y", function (d) {
      return y(d.values);
    })
    .attr("dy", "-0.7em")
    .attr('style', 'font-size:11px')
    .text( function (d){
      return d3.format(".2f")(d.values)   '%';
    })
    .style({fill: 'black', "text-anchor": "middle"});


    
    });

CodePudding user response:

Fixed some errors and simplified your code. See it working in the fiddle:

var margin = {top: 50, right: 135, bottom: 70, left: 80},
    width = 1050 - margin.left - margin.right,
    height = 540 - margin.top - margin.bottom;  

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

// load the data
const data = [{"Domain":"Knowledge","knowledge":0},{"Domain":"Problem Solving","problem_solving":0},{"Domain":"Skill","skill":0},{"Domain":"Transferable","transferable":100}];

const normalized = data.map(item => {
  const name = item['Domain'];
  const attr = name.toLowerCase().replace(' ', '_');
  const value = item[attr];
  return {name, value};
});

console.log('N: ', normalized);
/*
// Transpose the data into layers
var dataset = d3.layout.stack()(["Knowledge", "Problem Solving, Skill, Transferable"].map(function(lvl) {
  return data.map(function(d) {
    return {
      x: d.Domain,
      y: d[lvl]
    };
  });
}));

  var disciplines = d3.nest()
    .key(function(d){return d.Domain})
    .rollup(function(leaves){
      return d3.sum(leaves, function(d) {return d3.sum(d3.values(d))});
    })
    .entries(data);
*/

  // Set x, y and colors
  var x = d3.scale.ordinal()
    .domain(normalized.map(item => item.name))
    .rangeRoundBands([10, width-10], 0.35, 0);

    const maxValue = normalized.reduce((max, item) => Math.max(max, item.value), 0);

  var y = d3.scale.linear()
    .domain([0, maxValue])
    .range([height, 0]);

  var colors = ["#83d1c4", "#f17950", "#838BD1", "#F150BE"];

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

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .outerTickSize(0)
  
  
  d3.select('.y axis .tick:first-child').remove();
  
/*
  var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-0, 0])
  .html(function(d) {
    return d.y   '%';
  })
    
svg.call(tip);
*/

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


  svg.append("g")
    .call(xAxis)
    .attr("class", "x axis")
    .attr("transform", "translate(0,"   height   ")")
    .call(xAxis);
    
    svg.append("text")
  .attr("x", 390 )
  .attr("y",  480 )
  .style("text-anchor", "middle")
  .text("Disciplines");
    
svg.append("text")
   .attr("x", -200 )
   .attr("y",  -40 )
   .attr("transform", "rotate(-90)" )
   .attr('style', 'font-size:12px')
   .style("text-anchor", "middle")
   .text("Percentage of Learning Events");

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

  groups.append("rect")
    .attr("y", function(d) { return y(d.value); })
    .attr("x", d => x(d.name))
    .attr("height", function(d) { return y(0) - y(d.value); })
    .attr('class', 'segment')
    .attr("width", x.rangeBand())
    // .on('mouseover', tip.show)
    // .on('mouseout', tip.hide);


  columns = svg.append("g")
    .selectAll("text")
    .data(normalized)
    .enter().append("text")
    .attr("x", function(d){
      return x(d.name)   x.rangeBand()/2
    })
    .attr("y", function (d) {
      return y(d.value);
    })
    .attr("dy", "-0.7em")
    .attr('style', 'font-size:11px')
    .text( function (d){
      return d3.format(".2f")(d.value)   '%';
    })
    .style({fill: 'black', "text-anchor": "middle"});



  // Draw legend
var legend = svg.selectAll(".legend")
  .data(colors)
  .enter().append("g")
  .attr("class", "legend")
    .attr('style', 'font-size:12px')
  .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 "Knowledge";
      case 1:
        return "Problem Solving";
      case 2:
        return "Skill";
      case 3:
        return "Transferable";
      }
    });
    
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>


<div id="domains" />

  • Related