Y-Axis Woes - How to get January away from the X-Axis!? (D3.js)

Cannot find any great resource to help me accomplish the following:

Leave a space between the X-axis and the first month and a space between the last month and the top of the chart (current chart below)

Any tips??

  const svg = d3
    .select("svg")
    .attr("width", w)
    .attr("height", h)
    .attr("margin", margin);

  const xScale = d3
    .scaleTime()
    .domain([minX, maxX])
    .range([padding, w - padding])
    .nice();

  const yScale = d3
    .scaleTime()
    .range([h - padding, padding])
    .domain([minY, maxY])
    .nice();
    
  const myColor = d3
  .scaleSequential()
  .interpolator(d3.interpolateRdYlBu)
  .domain([minTemp,maxTemp])

  const xAxis = d3.axisBottom(xScale).ticks(3);
  const yAxis = d3.axisLeft(yScale)
  .tickFormat(d3.timeFormat("%B")).ticks(12);
  

  svg
    .append("g")
    .attr("id", "x-axis")
    .attr("transform", "translate(0," + (h - padding) + ")")
    .call(xAxis);

  svg
    .append("g")
    .attr("id", "y-axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);

Not that you can’t have a time scale y-axis, but it’s a lot easier with a band scale since ‘month’ is really a category and not a continuous variable and bands are discrete while time is continuous. If you kept the time axis, you would need to reverse the sense of the scale so that January was at the top (this part may very well be optional to the tests) and have 12 month intervals (instead of 11) because January is currently between 0 and -1.

If you are set on keeping the time scale, then your axis needs to be 12 rows high (you’ll have to calculate it, manually) and you’ll have to define the ticks and set their locations manually (by dividing the axis height into twelfths and positioning the tick somewhere in the appropriate interval to pass the tests). You can’t just add another tick at the origin because the tests will find it and fail if it does not correspond to a month.

That said, a band scale does all of this for you. Linear scales can also work, but you have to do the calculations just like a time scale.

Finally, these are easier to debug and you’ll get better help if you post a link to a codepen or similar project so we can edit all the code directly.

Hello,

Thanks for the suggestion. I implemented what you suggested but am now having trouble getting the height attr to work again. When I was using scaleTime I had used (h-padding)/12 to get the bars to layout properly. Now just having some trouble thinking through the way to do this with scaleBand. I really appreciate your help!

CodePen

Right now, all the rects were off the top of the graph. That’s because your band scale currently uses the month names as the items in its domain and you are calling it with Date() objects here:

      .attr("y", (d) => yScale(d3.timeParse("%m")(d.month)))

You need to change the argument to yScale() to be a month name (so, get the month name from the Date() object) to work with the current scale. You also need to un-reverse the month names in the scale definition, unless you want January on the bottom.

Once you address this issue and get your attributes right on the rects, all the alignment tests pass.

Thanks a bunch! Did the following:

function monthName(mon) {
   return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][mon - 1];
}

 .attr("y", (d) => yScale(monthName(d.month)))