Removing y-axis end ticks with tickSizeOuter(0) is not working

Viewed 563

enter image description here

(i) I am trying to remove y-axis end ticks but tickSizeOuter(0) is not helping me in that case.

(ii) Also I would like to have some padding after y-axis end-tick value(60), similar to as in x-axis. I tried padding and paddingOuter but that doesn't help me.

Here is the stackblitz.

And this is my code:

maxAllowed = 60;
  graphData = [
    {
      hrCount: 4,
      resCount: 2
    },
    {
      hrCount: 8,
      resCount: 5
    },
    {
      hrCount: 12,
      resCount: 10
    },
    ...
const margin = { top: 25, right: 25, bottom: 25, left: 25 };
    const width =
      document.getElementById("svgcontainer").parentElement.offsetWidth -
      (margin.left + margin.right);
    const height =
      document.getElementById("svgcontainer").parentElement.offsetHeight -
      (margin.top + margin.bottom);

    // Remove any existing SVG
    d3.select("#svgcontainer")
      .selectAll("svg > *")
      .remove();

    // Group
    const g = d3
      .select("#svgcontainer")
      .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 + ")");

    // Scale
    // x-scale
    const xScale = d3
      .scaleBand()
      .domain(this.graphData.map((d: any) => d.hrCount))
      .range([0, width]);
    // y-scale
    const yScale = d3
      .scaleLinear()
      .domain([0, this.maxAllowed])
      .range([height, 0]);

    // y-axis gridline
    g.append("g")
      .attr("class", "y-axis-grid")
      .call(
        d3
          .axisLeft(yScale)
          .tickSize(-width)
          .tickFormat("")
          .ticks(5)
      );

    // Axis
    // x-axis
    const xAxis = d3.axisBottom(xScale).tickSizeOuter(0);
    g.append("g")
      .attr("transform", "translate(0, " + height + ")")
      .attr("class", "graph-axis")
      .call(xAxis.scale(xScale))
      .append("text")
      .attr("x", width)
      .attr("y", -6)
      .attr("text-anchor", "end")
      .attr("font", "10px sans-serif")
      .attr("letter-spacing", "1px")
      .attr("fill", "#8997b1")
      .text("Hours");
    // y-axis
    const yAxis = d3
      .axisLeft(yScale)
      .ticks(5)
      .tickSizeOuter(0);
    g.append("g")
      .attr("class", "graph-axis")
      .call(yAxis.scale(yScale))
      .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .attr("font", "10px sans-serif")
      .attr("letter-spacing", "1px")
      .attr("fill", "#8997b1")
      .text("Resources");

    // Data line
    const line = d3
      .line()
      .x((d: any) => xScale(d.hrCount))
      .y((d: any) => yScale(d.resCount));
    const path = g
      .append("path")
      .attr("fill", "none")
      .attr("stroke", "#088dda")
      .attr("stroke-width", "2px")
      .attr("d", line(this.graphData));
    // Transition
    const totalLength = path.node().getTotalLength();
    path
      .attr("stroke-dasharray", totalLength + " " + totalLength)
      .attr("stroke-dashoffset", totalLength);
    path
      .transition()
      .duration(4000)
      .attr("stroke-dashoffset", 0);

    // Data dots
    g.selectAll("line-circle")
      .data(this.graphData)
      .enter()
      .append("circle")
      .attr("r", 4)
      .attr("fill", "#088dda")
      .attr("cx", (d: any) => xScale(d.hrCount))
      .attr("cy", (d: any) => yScale(d.resCount));
  }
2 Answers

I have checked your code and came up with the following approach to resolve your issue.

You can add the top padding to your chart by mapping your y axis domain to largest values present in data + some padding height (I have taken 5). Changes Required to do so:

maxAllowed = 0;

this.maxAllowed = d3.max(this.graphData, d => d.hrCount) + 5; // max value + padding

// y-scale
const yScale = d3
  .scaleLinear()
  .domain([0, this.maxAllowed])
  .range([height, 0]);

For the second change where you want to remove the outermost tickSize, you can easily accomplish it using .tickSizeOuter(0); The issue is you are not able to see this change because tickSizeOuter makes zero value for those tick line which does not have corresponding y-tick value as well (The end point of y axis has some tick y value).

But if you mark the value of this.maxAllowed = 65 and remove the tickSizeOuter(0) then you will be able to see that the end of y axis which has no y-tick value but its tick line is extended outwards. In these cases we uses tickSizeOuter(0) to remove the tick line.

And IMO you should only use this and should not remove the tick line for 0 value. It can lead to unnecessary results. But if you still want to remove tick line for 0 value. You can use the below code and remove it from the svg:

d3.selectAll(".y-axes-tick .tick line").each(function(d, i) {
  debugger;
  if (i === 0) {
    this.remove();
  }
});

Please find here the working stackblitz

You customize your axis on the call. It should look something like this:

.call(d3.axisLeft(yScale).tickSizeOuter(0)

Right now, you are trying to customize it when creating the scale for the visual. As far as padding, I think the function you are looking for is tickPadding().

Here's some documentation from d3.js on customizing the axis.

Related