ofey
ofey

Reputation: 3337

d3.js label bars of bar chart

I am trying to add labels to the bars of a bar chart with somethingA, somethingB, somethingC, somethingD.

Trying to get it to look like this,

enter image description here

The data is in the form,

data = [
          {name : 'somethingA', yVal : 1},
          {name : 'somethingB', yVal : 4},
          {name : 'somethingC', yVal : 2},
          {name : 'somethingD', yVal : 3}
      ];

I tried using,

.attr('text', function(d){
                  return xScale(d.name);
                })

This is being run in an angular4 component.

The code in app.component.ts file,

  ngOnInit() {
            let self = this;
            let d3 = this.d3;
            let d3ParentElement: any;
            let svg: any;
            let name: string;
            let xVal: number
            let yVal: number;
            let data: {name: string, yVal: number}[] = [];
            let padding: number = 25;
            let width: number = 500;
            let height: number = 150;
            let xScale: any;
            let yScale: any;
            let xAxis: any;
            let yAxis: any;

    if (this.parentNativeElement !== null) {
      svg = d3.select(this.parentNativeElement)
          .append('svg')        // create an <svg> element
          .attr('width', width) // set its dimensions
          .attr('height', height);

      data = [
          {name : 'A', yVal : 1},
          {name : 'B', yVal : 4},
          {name : 'C', yVal : 2},
          {name : 'D', yVal : 3}
      ];

      xScale = d3.scaleLinear()
          .domain([0,d3.max(data, function(d,i) {return i+1})])
          .range([0, 200]);

      yScale = d3.scaleLinear()
          .domain([0,d3.max(data, function(d) {return d.yVal})])
          .range([100, 0]);

      xAxis = d3.axisBottom(xScale) // d3.js v.4
          .ticks(5)
          .scale(xScale);

      yAxis = d3.axisLeft(xScale) // d3.js v.4
          .scale(yScale)
          .ticks(7);

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

           svg.append('g')            // create a <g> element
         .attr('class', 'axis')   // specify classes
           .attr("transform", "translate(" + padding + "," + (height - padding) + ")")
         .call(xAxis);            // let the axis do its thing

      var rects = svg.selectAll('rect')
          .data(data);
          rects.size();

      var newRects = rects.enter();

      newRects.append('rect')
          // .attr('x', function(d, i) {
          //     return xScale(i+1);
          // })
          .attr("x", function(d,i) {
            return xScale(i+1);
          })
          .attr('y', function(d) {
              return yScale(d.yVal);
            })
          .attr('text', function(d){
              return xScale(d.name);
            })
            .attr("transform","translate(" + (padding -5) + "," + (padding - 5) + ")")
          .attr('height', function(d) {
              return height - yScale(d.yVal) - (2*padding) + 5})
          .attr('width', 10);
     }
   }

EDIT: As suggested by Gerard Furtado I am using scaleBand(). Here's the code and output.

  ngOnInit() {
            let self = this;
            let d3 = this.d3;
            let d3ParentElement: any;
            let svg: any;
            let name: string;
            let xVal: number
            let yVal: number;
            let data: {name: string, yVal: number}[] = [];
            let padding: number = 25;
            let width: number = 500;
            let height: number = 150;
            let xScale: any;
            let yScale: any;
            let xAxis: any;
            let yAxis: any;

    if (this.parentNativeElement !== null) {
      svg = d3.select(this.parentNativeElement)
          .append('svg')        // create an <svg> element
          .attr('width', width) // set its dimensions
          .attr('height', height);

      data = [
          {name : 'A', yVal : 1},
          {name : 'B', yVal : 4},
          {name : 'C', yVal : 2},
          {name : 'D', yVal : 3}
      ];

      xScale = d3.scaleBand()
          .domain(data.map(function(d){ return d.name; }))
          .range([0, 200]);

      yScale = d3.scaleLinear()
          .domain([0,d3.max(data, function(d) {return d.yVal})])
          .range([100, 0]);

      xAxis = d3.axisBottom(xScale) // d3.js v.4
          .ticks(5)
          .scale(xScale);

      yAxis = d3.axisLeft(xScale) // d3.js v.4
          .scale(yScale)
          .ticks(7);

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

           svg.append('g')            // create a <g> element
         .attr('class', 'axis')   // specify classes
           .attr("transform", "translate(" + padding + "," + (height - padding) + ")")
         .call(xAxis);            // let the axis do its thing

      var rects = svg.selectAll('rect')
          .data(data);
          rects.size();

      var newRects = rects.enter();

      newRects.append('rect')
          // .attr('x', function(d, i) {
          //     return xScale(i+1);
          // })
          .attr("x", function(d,i) {
            return xScale(d.name);
          })
          .attr('y', function(d) {
              return yScale(d.yVal);
            })
            .attr("transform","translate(" + (padding -5) + "," + (padding - 5) + ")")
          .attr('height', function(d) {
              return height - yScale(d.yVal) - (2*padding) + 5})
          .attr('width', 10);
     }
   }

Unfortunately the bars are not centering on the A, B, C and D.enter image description here

This results in the bars not being centred on the A, B, C, D. I used translate() to shift it right a little like this,

.attr("transform","translate(" + (padding -5  + 25) + "," + (padding - 5) + ")")

enter image description here

Upvotes: 0

Views: 1158

Answers (1)

ofey
ofey

Reputation: 3337

Here is the component class,

Full project code and Demo

export class D3graphComponent implements OnInit {
  private d3: D3;
  private parentNativeElement: any;
  private d3Svg: Selection<SVGSVGElement, any, null, undefined>;

  constructor(element: ElementRef, private ngZone: NgZone, d3Service: D3Service) {
    this.d3 = d3Service.getD3();
    this.parentNativeElement = element.nativeElement;
  }

  ngOnInit() {
            let self = this;
            let d3 = this.d3;
            let d3ParentElement: any;
            let svg: any;
            let name: string;
            let yVal: number;
            let colors: any = [];
            let data: {name: string, yVal: number}[] = [];
            let padding: number = 25;
            let width: number = 500;
            let height: number = 150;
            let xScale: any;
            let yScale: any;
            let xColor: any;
            let xAxis: any;
            let yAxis: any;

    if (this.parentNativeElement !== null) {
      svg = d3.select(this.parentNativeElement)
          .append('svg')        // create an <svg> element
          .attr('width', width) // set its dimensions
          .attr('height', height);

      colors = ['red', 'yellow', 'green', 'blue'];

      data = [
          {name : 'A', yVal : 1},
          {name : 'B', yVal : 4},
          {name : 'C', yVal : 2},
          {name : 'D', yVal : 3}
      ];

      xScale = d3.scaleBand()
          .domain(data.map(function(d){ return d.name; }))
          .range([0, 200]);

      yScale = d3.scaleLinear()
          .domain([0,d3.max(data, function(d) {return d.yVal})])
          .range([100, 0]);

      xAxis = d3.axisBottom(xScale) // d3.js v.4
          .ticks(5)
          .scale(xScale);

      yAxis = d3.axisLeft(xScale) // d3.js v.4
          .scale(yScale)
          .ticks(7);

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

           svg.append('g')            // create a <g> element
         .attr('class', 'axis')   // specify classes
           .attr("transform", "translate(" + padding + "," + (height - padding) + ")")
         .call(xAxis);            // let the axis do its thing

      var rects = svg.selectAll('rect')
          .data(data);
          rects.size();

      var newRects = rects.enter();

      newRects.append('rect')
          .attr('x', function(d,i) {
            return xScale(d.name );
          })
          .attr('y', function(d) {
              return yScale(d.yVal);
            })
            .attr("transform","translate(" + (padding -5  + 25) + "," + (padding - 5) + ")")
          .attr('height', function(d) {
              return height - yScale(d.yVal) - (2*padding) + 5})
          .attr('width', 10)
          .attr('fill', function(d, i) {
            return colors[i];
          });
     }
   }
 }

Upvotes: 1

Related Questions