Imo
Imo

Reputation: 1475

How to move d3 ticks on y-axis

I have a bar chart see plunker the problem is that I would like to move the y-axis ticks to be at the middle left side of the rects but they appear on the top and end. and I cannot seem to move them without destroying the chart.

my code

var info = [{
        name: "Walnuts",
        value: 546546
      }, {
        name: "Almonds",
        value: 456455
      }

    ];

    /* Set chart dimensions */
    var width = 960,
      height = 500,
      margin = {
        top: 10,
        right: 10,
        bottom: 20,
        left: 60
      };

    //subtract margins
    width = width - margin.left - margin.right;
    height = height - margin.top - margin.bottom;

    //sort data from highest to lowest
    info = info.sort(function(a, b) {
      return b.value - a.value;
    });

    //Sets the y scale from 0 to the maximum data element


    var max_n = 0;
    var category = []
    for (var d in info) {
      max_n = Math.max(info[d].value, max_n);
      category.push(info[d].name)
    }

    var dx = width / max_n;
    var dy = height / info.length;

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

    var yAxis = d3.svg.axis()
      .scale(y)
      .orient('left')

    var svg = d3.select("#chart")
      .append("svg")
      .attr("width", "100%")
      .attr("height", "100%")
      .attr('preserveAspectRatio', 'xMidYMin')
      .attr("viewBox", '0 0 ' + parseInt(width + margin.left + margin.right) + ' ' + parseInt(height + margin.top + margin.bottom))
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.selectAll(".bar")
      .data(info)
      .enter()
      .append("rect")
      .attr("class", function(d, i) {
        return "bar" + d.name;
      })
      .attr("x", function(d, i) {
        return 0;
      })
      .attr("y", function(d, i) {
        return dy * i;
      })
      .attr("width", function(d, i) {
        return dx * d.value
      })
      .attr("height", dy)
      .attr("fill", function(d, i) {
        if (d.name == 'Walnuts') {
          return 'red'
        } else {
          return 'green'
        }
      });

    var y_xis = svg.append('g')
      .attr('id', 'yaxis')
      .call(yAxis);

Upvotes: 1

Views: 1662

Answers (3)

Nikolai
Nikolai

Reputation: 692

Recently I needed something very very similar and I solved this with a call with selecting all text elements in the selection and moving their dy upwards. I will give an example with OP's code:

   var y_xis = svg.append('g')
                      .attr('id','yaxis')
                      .call(yAxis)
                      .call(selection => selection
                          .selectAll('text')
                          .attr('dy', '-110') // this moves the text labels upwards
                          .attr('x', '110')); // this does the same job but horizontally

Upvotes: 0

juanesarango
juanesarango

Reputation: 569

For d3 versions like v4/v5.

Defining height as the graph/plot height, and max as the maximum value of y.

import { parseSvg } from 'd3-interpolate/src/transform/parse'

const yScale = d3
    .scaleLinear()
    .domain([0, max])
    .rangeRound([height, 0])

const yAxis = d3.axisLeft(yScale)

svg
    .append('g')
    .call(yAxis)
    .selectAll('.tick')
    .each(function(data) {
      const tick = d3.select(this)
      const { translateX, translateY } = parseSvg(tick.attr('transform'))
      tick.attr(
        'transform',
        translate(translateX, translateY + height / (2 * max))
      )
    })

Upvotes: 0

Cyril Cherian
Cyril Cherian

Reputation: 32327

You are using range in y axis like this:

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

You should be using 'rangeRoundBands' since the y scale is ordinal

   var y =   d3.scale.ordinal()
                        .domain(category)
                .rangeRoundBands([0, height], .1);

working code here

Upvotes: 2

Related Questions