How to align x axis with bars respectively in Combo Chart (Bars and Lines)?










1















I have a combo/ bars & lines chart based on D3.js. The x axis domain contains min and max dates, and bars are based on values. But the last bar (rect) is outside the chart. I can bring it in by forcing it (manually) but it won't reflect the data.






var data = [

fcst_valid_local: "2018-11-13T14:00:00-0600",
pop: 20,
rh: 67,
temp: 38,
wspd: 7
,

fcst_valid_local: "2018-11-14T15:00:00-0600",
pop: 15,
rh: 50,
temp: 39,
wspd: 8
,

fcst_valid_local: "2018-11-15T16:00:00-0600",
pop: 10,
rh: 90,
temp: 40,
wspd: 9

];

// Margins, width and height.
var margin = top: 20, right: 20, bottom: 30, left: 50,
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;

// Date parsing.
const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
data.forEach(function (d)
d.date = parseDate(d.fcst_valid_local);
);

// Set scale domains.
var x = d3.scaleTime().range([0, width])
.domain(d3.extent(data, function (d)
return d.date;
));

var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
const y1 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, (d) => d.pop)]);

// Construct our SVG object.
const svg = d3.select('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g').attr('class', 'container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");

// Set x, y-left and y-right axis.
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
// .tickFormat(d3.timeFormat('%b %d, %H:%M'))
.tickSize(0).tickPadding(10);
var y0Axis = d3.axisLeft(y0)
.ticks(5).tickSize(0);
var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

svg.append("g")
.attr("class", "x-axis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + 0 + ", 0)")
.call(y0Axis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + width + ", 0)")
.call(y1Axis);

// Draw bars.
var bars = svg.selectAll(".precips")
.data(data);

bars.exit().remove();

bars.enter().append("rect")
.attr("class", "precip")
.attr("width", width / data.length - 50)
.attr("x", function (d)
return x(d.date);
)
.attr("y", height)
.transition().duration(1000)
.attr("y", function (d)
return y0(d.pop);
)
.attr("height", function (d)
return height - y0(d.pop);
);

const lineRH = d3.line()
.x((d) => x(d['date']))
.y(d => y0(d['rh']));

svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('stroke-width', 1.5)
.attr('d', lineRH);

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>












share|improve this question


























    1















    I have a combo/ bars & lines chart based on D3.js. The x axis domain contains min and max dates, and bars are based on values. But the last bar (rect) is outside the chart. I can bring it in by forcing it (manually) but it won't reflect the data.






    var data = [

    fcst_valid_local: "2018-11-13T14:00:00-0600",
    pop: 20,
    rh: 67,
    temp: 38,
    wspd: 7
    ,

    fcst_valid_local: "2018-11-14T15:00:00-0600",
    pop: 15,
    rh: 50,
    temp: 39,
    wspd: 8
    ,

    fcst_valid_local: "2018-11-15T16:00:00-0600",
    pop: 10,
    rh: 90,
    temp: 40,
    wspd: 9

    ];

    // Margins, width and height.
    var margin = top: 20, right: 20, bottom: 30, left: 50,
    width = 500 - margin.left - margin.right,
    height = 200 - margin.top - margin.bottom;

    // Date parsing.
    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
    data.forEach(function (d)
    d.date = parseDate(d.fcst_valid_local);
    );

    // Set scale domains.
    var x = d3.scaleTime().range([0, width])
    .domain(d3.extent(data, function (d)
    return d.date;
    ));

    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
    const y1 = d3.scaleLinear()
    .range([height, 0])
    .domain([0, d3.max(data, (d) => d.pop)]);

    // Construct our SVG object.
    const svg = d3.select('svg')
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append('g').attr('class', 'container')
    .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

    // Set x, y-left and y-right axis.
    var xAxis = d3.axisBottom(x)
    .ticks(d3.timeDay.every(1))
    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
    .tickSize(0).tickPadding(10);
    var y0Axis = d3.axisLeft(y0)
    .ticks(5).tickSize(0);
    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

    svg.append("g")
    .attr("class", "x-axis axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
    svg.append("g")
    .attr("class", "y-axis axis")
    .attr("transform", "translate(" + 0 + ", 0)")
    .call(y0Axis);
    svg.append("g")
    .attr("class", "y-axis axis")
    .attr("transform", "translate(" + width + ", 0)")
    .call(y1Axis);

    // Draw bars.
    var bars = svg.selectAll(".precips")
    .data(data);

    bars.exit().remove();

    bars.enter().append("rect")
    .attr("class", "precip")
    .attr("width", width / data.length - 50)
    .attr("x", function (d)
    return x(d.date);
    )
    .attr("y", height)
    .transition().duration(1000)
    .attr("y", function (d)
    return y0(d.pop);
    )
    .attr("height", function (d)
    return height - y0(d.pop);
    );

    const lineRH = d3.line()
    .x((d) => x(d['date']))
    .y(d => y0(d['rh']));

    svg.append('path')
    .datum(data)
    .attr('class', 'line')
    .attr('fill', 'none')
    .attr('stroke', 'red')
    .attr('stroke-linejoin', 'round')
    .attr('stroke-linecap', 'round')
    .attr('stroke-width', 1.5)
    .attr('d', lineRH);

    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg></svg>












    share|improve this question
























      1












      1








      1








      I have a combo/ bars & lines chart based on D3.js. The x axis domain contains min and max dates, and bars are based on values. But the last bar (rect) is outside the chart. I can bring it in by forcing it (manually) but it won't reflect the data.






      var data = [

      fcst_valid_local: "2018-11-13T14:00:00-0600",
      pop: 20,
      rh: 67,
      temp: 38,
      wspd: 7
      ,

      fcst_valid_local: "2018-11-14T15:00:00-0600",
      pop: 15,
      rh: 50,
      temp: 39,
      wspd: 8
      ,

      fcst_valid_local: "2018-11-15T16:00:00-0600",
      pop: 10,
      rh: 90,
      temp: 40,
      wspd: 9

      ];

      // Margins, width and height.
      var margin = top: 20, right: 20, bottom: 30, left: 50,
      width = 500 - margin.left - margin.right,
      height = 200 - margin.top - margin.bottom;

      // Date parsing.
      const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
      data.forEach(function (d)
      d.date = parseDate(d.fcst_valid_local);
      );

      // Set scale domains.
      var x = d3.scaleTime().range([0, width])
      .domain(d3.extent(data, function (d)
      return d.date;
      ));

      var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
      const y1 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(data, (d) => d.pop)]);

      // Construct our SVG object.
      const svg = d3.select('svg')
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append('g').attr('class', 'container')
      .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")");

      // Set x, y-left and y-right axis.
      var xAxis = d3.axisBottom(x)
      .ticks(d3.timeDay.every(1))
      // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
      .tickSize(0).tickPadding(10);
      var y0Axis = d3.axisLeft(y0)
      .ticks(5).tickSize(0);
      var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

      svg.append("g")
      .attr("class", "x-axis axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + 0 + ", 0)")
      .call(y0Axis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + width + ", 0)")
      .call(y1Axis);

      // Draw bars.
      var bars = svg.selectAll(".precips")
      .data(data);

      bars.exit().remove();

      bars.enter().append("rect")
      .attr("class", "precip")
      .attr("width", width / data.length - 50)
      .attr("x", function (d)
      return x(d.date);
      )
      .attr("y", height)
      .transition().duration(1000)
      .attr("y", function (d)
      return y0(d.pop);
      )
      .attr("height", function (d)
      return height - y0(d.pop);
      );

      const lineRH = d3.line()
      .x((d) => x(d['date']))
      .y(d => y0(d['rh']));

      svg.append('path')
      .datum(data)
      .attr('class', 'line')
      .attr('fill', 'none')
      .attr('stroke', 'red')
      .attr('stroke-linejoin', 'round')
      .attr('stroke-linecap', 'round')
      .attr('stroke-width', 1.5)
      .attr('d', lineRH);

      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
      <svg></svg>












      share|improve this question














      I have a combo/ bars & lines chart based on D3.js. The x axis domain contains min and max dates, and bars are based on values. But the last bar (rect) is outside the chart. I can bring it in by forcing it (manually) but it won't reflect the data.






      var data = [

      fcst_valid_local: "2018-11-13T14:00:00-0600",
      pop: 20,
      rh: 67,
      temp: 38,
      wspd: 7
      ,

      fcst_valid_local: "2018-11-14T15:00:00-0600",
      pop: 15,
      rh: 50,
      temp: 39,
      wspd: 8
      ,

      fcst_valid_local: "2018-11-15T16:00:00-0600",
      pop: 10,
      rh: 90,
      temp: 40,
      wspd: 9

      ];

      // Margins, width and height.
      var margin = top: 20, right: 20, bottom: 30, left: 50,
      width = 500 - margin.left - margin.right,
      height = 200 - margin.top - margin.bottom;

      // Date parsing.
      const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
      data.forEach(function (d)
      d.date = parseDate(d.fcst_valid_local);
      );

      // Set scale domains.
      var x = d3.scaleTime().range([0, width])
      .domain(d3.extent(data, function (d)
      return d.date;
      ));

      var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
      const y1 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(data, (d) => d.pop)]);

      // Construct our SVG object.
      const svg = d3.select('svg')
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append('g').attr('class', 'container')
      .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")");

      // Set x, y-left and y-right axis.
      var xAxis = d3.axisBottom(x)
      .ticks(d3.timeDay.every(1))
      // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
      .tickSize(0).tickPadding(10);
      var y0Axis = d3.axisLeft(y0)
      .ticks(5).tickSize(0);
      var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

      svg.append("g")
      .attr("class", "x-axis axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + 0 + ", 0)")
      .call(y0Axis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + width + ", 0)")
      .call(y1Axis);

      // Draw bars.
      var bars = svg.selectAll(".precips")
      .data(data);

      bars.exit().remove();

      bars.enter().append("rect")
      .attr("class", "precip")
      .attr("width", width / data.length - 50)
      .attr("x", function (d)
      return x(d.date);
      )
      .attr("y", height)
      .transition().duration(1000)
      .attr("y", function (d)
      return y0(d.pop);
      )
      .attr("height", function (d)
      return height - y0(d.pop);
      );

      const lineRH = d3.line()
      .x((d) => x(d['date']))
      .y(d => y0(d['rh']));

      svg.append('path')
      .datum(data)
      .attr('class', 'line')
      .attr('fill', 'none')
      .attr('stroke', 'red')
      .attr('stroke-linejoin', 'round')
      .attr('stroke-linecap', 'round')
      .attr('stroke-width', 1.5)
      .attr('d', lineRH);

      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
      <svg></svg>








      var data = [

      fcst_valid_local: "2018-11-13T14:00:00-0600",
      pop: 20,
      rh: 67,
      temp: 38,
      wspd: 7
      ,

      fcst_valid_local: "2018-11-14T15:00:00-0600",
      pop: 15,
      rh: 50,
      temp: 39,
      wspd: 8
      ,

      fcst_valid_local: "2018-11-15T16:00:00-0600",
      pop: 10,
      rh: 90,
      temp: 40,
      wspd: 9

      ];

      // Margins, width and height.
      var margin = top: 20, right: 20, bottom: 30, left: 50,
      width = 500 - margin.left - margin.right,
      height = 200 - margin.top - margin.bottom;

      // Date parsing.
      const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
      data.forEach(function (d)
      d.date = parseDate(d.fcst_valid_local);
      );

      // Set scale domains.
      var x = d3.scaleTime().range([0, width])
      .domain(d3.extent(data, function (d)
      return d.date;
      ));

      var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
      const y1 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(data, (d) => d.pop)]);

      // Construct our SVG object.
      const svg = d3.select('svg')
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append('g').attr('class', 'container')
      .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")");

      // Set x, y-left and y-right axis.
      var xAxis = d3.axisBottom(x)
      .ticks(d3.timeDay.every(1))
      // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
      .tickSize(0).tickPadding(10);
      var y0Axis = d3.axisLeft(y0)
      .ticks(5).tickSize(0);
      var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

      svg.append("g")
      .attr("class", "x-axis axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + 0 + ", 0)")
      .call(y0Axis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + width + ", 0)")
      .call(y1Axis);

      // Draw bars.
      var bars = svg.selectAll(".precips")
      .data(data);

      bars.exit().remove();

      bars.enter().append("rect")
      .attr("class", "precip")
      .attr("width", width / data.length - 50)
      .attr("x", function (d)
      return x(d.date);
      )
      .attr("y", height)
      .transition().duration(1000)
      .attr("y", function (d)
      return y0(d.pop);
      )
      .attr("height", function (d)
      return height - y0(d.pop);
      );

      const lineRH = d3.line()
      .x((d) => x(d['date']))
      .y(d => y0(d['rh']));

      svg.append('path')
      .datum(data)
      .attr('class', 'line')
      .attr('fill', 'none')
      .attr('stroke', 'red')
      .attr('stroke-linejoin', 'round')
      .attr('stroke-linecap', 'round')
      .attr('stroke-width', 1.5)
      .attr('d', lineRH);

      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
      <svg></svg>





      var data = [

      fcst_valid_local: "2018-11-13T14:00:00-0600",
      pop: 20,
      rh: 67,
      temp: 38,
      wspd: 7
      ,

      fcst_valid_local: "2018-11-14T15:00:00-0600",
      pop: 15,
      rh: 50,
      temp: 39,
      wspd: 8
      ,

      fcst_valid_local: "2018-11-15T16:00:00-0600",
      pop: 10,
      rh: 90,
      temp: 40,
      wspd: 9

      ];

      // Margins, width and height.
      var margin = top: 20, right: 20, bottom: 30, left: 50,
      width = 500 - margin.left - margin.right,
      height = 200 - margin.top - margin.bottom;

      // Date parsing.
      const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
      data.forEach(function (d)
      d.date = parseDate(d.fcst_valid_local);
      );

      // Set scale domains.
      var x = d3.scaleTime().range([0, width])
      .domain(d3.extent(data, function (d)
      return d.date;
      ));

      var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
      const y1 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(data, (d) => d.pop)]);

      // Construct our SVG object.
      const svg = d3.select('svg')
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append('g').attr('class', 'container')
      .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")");

      // Set x, y-left and y-right axis.
      var xAxis = d3.axisBottom(x)
      .ticks(d3.timeDay.every(1))
      // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
      .tickSize(0).tickPadding(10);
      var y0Axis = d3.axisLeft(y0)
      .ticks(5).tickSize(0);
      var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

      svg.append("g")
      .attr("class", "x-axis axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + 0 + ", 0)")
      .call(y0Axis);
      svg.append("g")
      .attr("class", "y-axis axis")
      .attr("transform", "translate(" + width + ", 0)")
      .call(y1Axis);

      // Draw bars.
      var bars = svg.selectAll(".precips")
      .data(data);

      bars.exit().remove();

      bars.enter().append("rect")
      .attr("class", "precip")
      .attr("width", width / data.length - 50)
      .attr("x", function (d)
      return x(d.date);
      )
      .attr("y", height)
      .transition().duration(1000)
      .attr("y", function (d)
      return y0(d.pop);
      )
      .attr("height", function (d)
      return height - y0(d.pop);
      );

      const lineRH = d3.line()
      .x((d) => x(d['date']))
      .y(d => y0(d['rh']));

      svg.append('path')
      .datum(data)
      .attr('class', 'line')
      .attr('fill', 'none')
      .attr('stroke', 'red')
      .attr('stroke-linejoin', 'round')
      .attr('stroke-linecap', 'round')
      .attr('stroke-width', 1.5)
      .attr('d', lineRH);

      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
      <svg></svg>






      javascript d3.js






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 15 '18 at 17:39









      Maihan NijatMaihan Nijat

      2,94822448




      2,94822448






















          2 Answers
          2






          active

          oldest

          votes


















          1














          Although an answer has been accepted, I'd like to let you know that you don't have to manipulate the data (as it might be fetched from an API as well) but you can play around the x.domain() as it's all about setting the right domain here.



          1. Try using d3 time_nice to round off the time scale domains

          2. Play around with d3 time methods to change the dates (there are a lot here)

          Here's an example of using the second approach from above and setting the x domain:



          var x = d3.scaleTime().range([0, width])
          .domain([d3.min(data, function (d)
          return d.date;
          ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);


          Explanation: This is offsetting the max date from the data by 1 day and so the new x.domain() would come out as:



          (2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]


          which results in a chart as follows:






          var data = [

          fcst_valid_local: "2018-11-13T14:00:00-0600",
          pop: 20,
          rh: 67,
          temp: 38,
          wspd: 7
          ,

          fcst_valid_local: "2018-11-14T15:00:00-0600",
          pop: 15,
          rh: 50,
          temp: 39,
          wspd: 8
          ,

          fcst_valid_local: "2018-11-15T16:00:00-0600",
          pop: 10,
          rh: 90,
          temp: 40,
          wspd: 9

          ];

          // Margins, width and height.
          var margin = top: 20, right: 20, bottom: 30, left: 50,
          width = 500 - margin.left - margin.right,
          height = 200 - margin.top - margin.bottom;

          // Date parsing.
          const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
          data.forEach(function (d)
          d.date = parseDate(d.fcst_valid_local);
          );

          // Set scale domains.
          var x = d3.scaleTime().range([0, width])
          .domain([d3.min(data, function (d)
          return d.date;
          ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

          var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
          const y1 = d3.scaleLinear()
          .range([height, 0])
          .domain([0, d3.max(data, (d) => d.pop)]);
          //console.log(x.domain());
          // Construct our SVG object.
          const svg = d3.select('svg')
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
          .append('g').attr('class', 'container')
          .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

          // Set x, y-left and y-right axis.
          var xAxis = d3.axisBottom(x)
          .ticks(d3.timeDay.every(1))
          // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
          .tickSize(0).tickPadding(10);
          var y0Axis = d3.axisLeft(y0)
          .ticks(5).tickSize(0);
          var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

          svg.append("g")
          .attr("class", "x-axis axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis);
          svg.append("g")
          .attr("class", "y-axis axis")
          .attr("transform", "translate(" + 0 + ", 0)")
          .call(y0Axis);
          svg.append("g")
          .attr("class", "y-axis axis")
          .attr("transform", "translate(" + width + ", 0)")
          .call(y1Axis);

          // Draw bars.
          var bars = svg.selectAll(".precips")
          .data(data);

          bars.exit().remove();

          bars.enter().append("rect")
          .attr("class", "precip")
          .attr("width", width / data.length - 50)
          .attr("x", function (d)
          return x(d.date);
          )
          .attr("y", height)
          .transition().duration(1000)
          .attr("y", function (d)
          return y0(d.pop);
          )
          .attr("height", function (d)
          return height - y0(d.pop);
          );

          const lineRH = d3.line()
          .x((d) => x(d['date']) + (width / data.length - 50)/2)
          .y(d => y0(d['rh']));

          svg.append('path')
          .datum(data)
          .attr('class', 'line')
          .attr('fill', 'none')
          .attr('stroke', 'red')
          .attr('stroke-linejoin', 'round')
          .attr('stroke-linecap', 'round')
          .attr('stroke-width', 1.5)
          .attr('d', lineRH);

          <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
          <svg></svg>





          I also tried with .nice() and a fun part would be to use the d3 time intervals within .nice(). Feel free to play around with those and let me know if you have any questions.



          Also, I'm offsetting the line (path) by the barwidth/2 in the line generator fn.



          d3.line()
          .x((d) => x(d['date']) + (width / data.length - 50)/2)


          Hope this helps as well.






          share|improve this answer






























            1














            Add a dummy data item that is a bit later then the last item



            Here it is done hard coded but you can add it dynamic based on the date of the last item






            var data = [

            fcst_valid_local: "2018-11-13T14:00:00-0600",
            pop: 20,
            rh: 67,
            temp: 38,
            wspd: 7
            ,

            fcst_valid_local: "2018-11-14T15:00:00-0600",
            pop: 15,
            rh: 50,
            temp: 39,
            wspd: 8
            ,

            fcst_valid_local: "2018-11-15T16:00:00-0600",
            pop: 10,
            rh: 90,
            temp: 40,
            wspd: 9
            ,

            fcst_valid_local: "2018-11-16T01:00:00-0600"

            ];

            // Margins, width and height.
            var margin = top: 20, right: 20, bottom: 30, left: 50,
            width = 500 - margin.left - margin.right,
            height = 200 - margin.top - margin.bottom;

            // Date parsing.
            const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
            data.forEach(function (d)
            d.date = parseDate(d.fcst_valid_local);
            );

            // Set scale domains.
            var x = d3.scaleTime().range([0, width])
            .domain(d3.extent(data, function (d)
            return d.date;
            ));

            var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
            const y1 = d3.scaleLinear()
            .range([height, 0])
            .domain([0, d3.max(data, (d) => d.pop)]);

            // Construct our SVG object.
            const svg = d3.select('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append('g').attr('class', 'container')
            .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");

            // Set x, y-left and y-right axis.
            var xAxis = d3.axisBottom(x)
            .ticks(d3.timeDay.every(1))
            // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
            .tickSize(0).tickPadding(10);
            var y0Axis = d3.axisLeft(y0)
            .ticks(5).tickSize(0);
            var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

            svg.append("g")
            .attr("class", "x-axis axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);
            svg.append("g")
            .attr("class", "y-axis axis")
            .attr("transform", "translate(" + 0 + ", 0)")
            .call(y0Axis);
            svg.append("g")
            .attr("class", "y-axis axis")
            .attr("transform", "translate(" + width + ", 0)")
            .call(y1Axis);

            // Draw bars.
            var bars = svg.selectAll(".precips")
            .data(data);

            bars.exit().remove();

            bars.enter().append("rect")
            .attr("class", "precip")
            .attr("width", width / data.length - 50)
            .attr("x", function (d)
            return x(d.date);
            )
            .attr("y", height)
            .transition().duration(1000)
            .attr("y", function (d)
            return y0(d.pop);
            )
            .attr("height", function (d)
            return height - y0(d.pop);
            );

            const lineRH = d3.line()
            .x((d) => x(d['date']))
            .y(d => y0(d['rh']));

            svg.append('path')
            .datum(data)
            .attr('class', 'line')
            .attr('fill', 'none')
            .attr('stroke', 'red')
            .attr('stroke-linejoin', 'round')
            .attr('stroke-linecap', 'round')
            .attr('stroke-width', 1.5)
            .attr('d', lineRH);

            <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
            <svg></svg>








            share|improve this answer























            • It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

              – Maihan Nijat
              Nov 15 '18 at 18:32











            • @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

              – rioV8
              Nov 15 '18 at 18:45











            • Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

              – Maihan Nijat
              Nov 15 '18 at 18:53











            • @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

              – rioV8
              Nov 15 '18 at 18:56










            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325104%2fhow-to-align-x-axis-with-bars-respectively-in-combo-chart-bars-and-lines%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            Although an answer has been accepted, I'd like to let you know that you don't have to manipulate the data (as it might be fetched from an API as well) but you can play around the x.domain() as it's all about setting the right domain here.



            1. Try using d3 time_nice to round off the time scale domains

            2. Play around with d3 time methods to change the dates (there are a lot here)

            Here's an example of using the second approach from above and setting the x domain:



            var x = d3.scaleTime().range([0, width])
            .domain([d3.min(data, function (d)
            return d.date;
            ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);


            Explanation: This is offsetting the max date from the data by 1 day and so the new x.domain() would come out as:



            (2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]


            which results in a chart as follows:






            var data = [

            fcst_valid_local: "2018-11-13T14:00:00-0600",
            pop: 20,
            rh: 67,
            temp: 38,
            wspd: 7
            ,

            fcst_valid_local: "2018-11-14T15:00:00-0600",
            pop: 15,
            rh: 50,
            temp: 39,
            wspd: 8
            ,

            fcst_valid_local: "2018-11-15T16:00:00-0600",
            pop: 10,
            rh: 90,
            temp: 40,
            wspd: 9

            ];

            // Margins, width and height.
            var margin = top: 20, right: 20, bottom: 30, left: 50,
            width = 500 - margin.left - margin.right,
            height = 200 - margin.top - margin.bottom;

            // Date parsing.
            const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
            data.forEach(function (d)
            d.date = parseDate(d.fcst_valid_local);
            );

            // Set scale domains.
            var x = d3.scaleTime().range([0, width])
            .domain([d3.min(data, function (d)
            return d.date;
            ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

            var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
            const y1 = d3.scaleLinear()
            .range([height, 0])
            .domain([0, d3.max(data, (d) => d.pop)]);
            //console.log(x.domain());
            // Construct our SVG object.
            const svg = d3.select('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append('g').attr('class', 'container')
            .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");

            // Set x, y-left and y-right axis.
            var xAxis = d3.axisBottom(x)
            .ticks(d3.timeDay.every(1))
            // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
            .tickSize(0).tickPadding(10);
            var y0Axis = d3.axisLeft(y0)
            .ticks(5).tickSize(0);
            var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

            svg.append("g")
            .attr("class", "x-axis axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);
            svg.append("g")
            .attr("class", "y-axis axis")
            .attr("transform", "translate(" + 0 + ", 0)")
            .call(y0Axis);
            svg.append("g")
            .attr("class", "y-axis axis")
            .attr("transform", "translate(" + width + ", 0)")
            .call(y1Axis);

            // Draw bars.
            var bars = svg.selectAll(".precips")
            .data(data);

            bars.exit().remove();

            bars.enter().append("rect")
            .attr("class", "precip")
            .attr("width", width / data.length - 50)
            .attr("x", function (d)
            return x(d.date);
            )
            .attr("y", height)
            .transition().duration(1000)
            .attr("y", function (d)
            return y0(d.pop);
            )
            .attr("height", function (d)
            return height - y0(d.pop);
            );

            const lineRH = d3.line()
            .x((d) => x(d['date']) + (width / data.length - 50)/2)
            .y(d => y0(d['rh']));

            svg.append('path')
            .datum(data)
            .attr('class', 'line')
            .attr('fill', 'none')
            .attr('stroke', 'red')
            .attr('stroke-linejoin', 'round')
            .attr('stroke-linecap', 'round')
            .attr('stroke-width', 1.5)
            .attr('d', lineRH);

            <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
            <svg></svg>





            I also tried with .nice() and a fun part would be to use the d3 time intervals within .nice(). Feel free to play around with those and let me know if you have any questions.



            Also, I'm offsetting the line (path) by the barwidth/2 in the line generator fn.



            d3.line()
            .x((d) => x(d['date']) + (width / data.length - 50)/2)


            Hope this helps as well.






            share|improve this answer



























              1














              Although an answer has been accepted, I'd like to let you know that you don't have to manipulate the data (as it might be fetched from an API as well) but you can play around the x.domain() as it's all about setting the right domain here.



              1. Try using d3 time_nice to round off the time scale domains

              2. Play around with d3 time methods to change the dates (there are a lot here)

              Here's an example of using the second approach from above and setting the x domain:



              var x = d3.scaleTime().range([0, width])
              .domain([d3.min(data, function (d)
              return d.date;
              ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);


              Explanation: This is offsetting the max date from the data by 1 day and so the new x.domain() would come out as:



              (2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]


              which results in a chart as follows:






              var data = [

              fcst_valid_local: "2018-11-13T14:00:00-0600",
              pop: 20,
              rh: 67,
              temp: 38,
              wspd: 7
              ,

              fcst_valid_local: "2018-11-14T15:00:00-0600",
              pop: 15,
              rh: 50,
              temp: 39,
              wspd: 8
              ,

              fcst_valid_local: "2018-11-15T16:00:00-0600",
              pop: 10,
              rh: 90,
              temp: 40,
              wspd: 9

              ];

              // Margins, width and height.
              var margin = top: 20, right: 20, bottom: 30, left: 50,
              width = 500 - margin.left - margin.right,
              height = 200 - margin.top - margin.bottom;

              // Date parsing.
              const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
              data.forEach(function (d)
              d.date = parseDate(d.fcst_valid_local);
              );

              // Set scale domains.
              var x = d3.scaleTime().range([0, width])
              .domain([d3.min(data, function (d)
              return d.date;
              ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

              var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
              const y1 = d3.scaleLinear()
              .range([height, 0])
              .domain([0, d3.max(data, (d) => d.pop)]);
              //console.log(x.domain());
              // Construct our SVG object.
              const svg = d3.select('svg')
              .attr("width", width + margin.left + margin.right)
              .attr("height", height + margin.top + margin.bottom)
              .append('g').attr('class', 'container')
              .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");

              // Set x, y-left and y-right axis.
              var xAxis = d3.axisBottom(x)
              .ticks(d3.timeDay.every(1))
              // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
              .tickSize(0).tickPadding(10);
              var y0Axis = d3.axisLeft(y0)
              .ticks(5).tickSize(0);
              var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

              svg.append("g")
              .attr("class", "x-axis axis")
              .attr("transform", "translate(0," + height + ")")
              .call(xAxis);
              svg.append("g")
              .attr("class", "y-axis axis")
              .attr("transform", "translate(" + 0 + ", 0)")
              .call(y0Axis);
              svg.append("g")
              .attr("class", "y-axis axis")
              .attr("transform", "translate(" + width + ", 0)")
              .call(y1Axis);

              // Draw bars.
              var bars = svg.selectAll(".precips")
              .data(data);

              bars.exit().remove();

              bars.enter().append("rect")
              .attr("class", "precip")
              .attr("width", width / data.length - 50)
              .attr("x", function (d)
              return x(d.date);
              )
              .attr("y", height)
              .transition().duration(1000)
              .attr("y", function (d)
              return y0(d.pop);
              )
              .attr("height", function (d)
              return height - y0(d.pop);
              );

              const lineRH = d3.line()
              .x((d) => x(d['date']) + (width / data.length - 50)/2)
              .y(d => y0(d['rh']));

              svg.append('path')
              .datum(data)
              .attr('class', 'line')
              .attr('fill', 'none')
              .attr('stroke', 'red')
              .attr('stroke-linejoin', 'round')
              .attr('stroke-linecap', 'round')
              .attr('stroke-width', 1.5)
              .attr('d', lineRH);

              <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
              <svg></svg>





              I also tried with .nice() and a fun part would be to use the d3 time intervals within .nice(). Feel free to play around with those and let me know if you have any questions.



              Also, I'm offsetting the line (path) by the barwidth/2 in the line generator fn.



              d3.line()
              .x((d) => x(d['date']) + (width / data.length - 50)/2)


              Hope this helps as well.






              share|improve this answer

























                1












                1








                1







                Although an answer has been accepted, I'd like to let you know that you don't have to manipulate the data (as it might be fetched from an API as well) but you can play around the x.domain() as it's all about setting the right domain here.



                1. Try using d3 time_nice to round off the time scale domains

                2. Play around with d3 time methods to change the dates (there are a lot here)

                Here's an example of using the second approach from above and setting the x domain:



                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);


                Explanation: This is offsetting the max date from the data by 1 day and so the new x.domain() would come out as:



                (2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]


                which results in a chart as follows:






                var data = [

                fcst_valid_local: "2018-11-13T14:00:00-0600",
                pop: 20,
                rh: 67,
                temp: 38,
                wspd: 7
                ,

                fcst_valid_local: "2018-11-14T15:00:00-0600",
                pop: 15,
                rh: 50,
                temp: 39,
                wspd: 8
                ,

                fcst_valid_local: "2018-11-15T16:00:00-0600",
                pop: 10,
                rh: 90,
                temp: 40,
                wspd: 9

                ];

                // Margins, width and height.
                var margin = top: 20, right: 20, bottom: 30, left: 50,
                width = 500 - margin.left - margin.right,
                height = 200 - margin.top - margin.bottom;

                // Date parsing.
                const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                data.forEach(function (d)
                d.date = parseDate(d.fcst_valid_local);
                );

                // Set scale domains.
                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

                var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                const y1 = d3.scaleLinear()
                .range([height, 0])
                .domain([0, d3.max(data, (d) => d.pop)]);
                //console.log(x.domain());
                // Construct our SVG object.
                const svg = d3.select('svg')
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append('g').attr('class', 'container')
                .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

                // Set x, y-left and y-right axis.
                var xAxis = d3.axisBottom(x)
                .ticks(d3.timeDay.every(1))
                // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                .tickSize(0).tickPadding(10);
                var y0Axis = d3.axisLeft(y0)
                .ticks(5).tickSize(0);
                var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                svg.append("g")
                .attr("class", "x-axis axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + 0 + ", 0)")
                .call(y0Axis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + width + ", 0)")
                .call(y1Axis);

                // Draw bars.
                var bars = svg.selectAll(".precips")
                .data(data);

                bars.exit().remove();

                bars.enter().append("rect")
                .attr("class", "precip")
                .attr("width", width / data.length - 50)
                .attr("x", function (d)
                return x(d.date);
                )
                .attr("y", height)
                .transition().duration(1000)
                .attr("y", function (d)
                return y0(d.pop);
                )
                .attr("height", function (d)
                return height - y0(d.pop);
                );

                const lineRH = d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)
                .y(d => y0(d['rh']));

                svg.append('path')
                .datum(data)
                .attr('class', 'line')
                .attr('fill', 'none')
                .attr('stroke', 'red')
                .attr('stroke-linejoin', 'round')
                .attr('stroke-linecap', 'round')
                .attr('stroke-width', 1.5)
                .attr('d', lineRH);

                <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                <svg></svg>





                I also tried with .nice() and a fun part would be to use the d3 time intervals within .nice(). Feel free to play around with those and let me know if you have any questions.



                Also, I'm offsetting the line (path) by the barwidth/2 in the line generator fn.



                d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)


                Hope this helps as well.






                share|improve this answer













                Although an answer has been accepted, I'd like to let you know that you don't have to manipulate the data (as it might be fetched from an API as well) but you can play around the x.domain() as it's all about setting the right domain here.



                1. Try using d3 time_nice to round off the time scale domains

                2. Play around with d3 time methods to change the dates (there are a lot here)

                Here's an example of using the second approach from above and setting the x domain:



                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);


                Explanation: This is offsetting the max date from the data by 1 day and so the new x.domain() would come out as:



                (2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]


                which results in a chart as follows:






                var data = [

                fcst_valid_local: "2018-11-13T14:00:00-0600",
                pop: 20,
                rh: 67,
                temp: 38,
                wspd: 7
                ,

                fcst_valid_local: "2018-11-14T15:00:00-0600",
                pop: 15,
                rh: 50,
                temp: 39,
                wspd: 8
                ,

                fcst_valid_local: "2018-11-15T16:00:00-0600",
                pop: 10,
                rh: 90,
                temp: 40,
                wspd: 9

                ];

                // Margins, width and height.
                var margin = top: 20, right: 20, bottom: 30, left: 50,
                width = 500 - margin.left - margin.right,
                height = 200 - margin.top - margin.bottom;

                // Date parsing.
                const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                data.forEach(function (d)
                d.date = parseDate(d.fcst_valid_local);
                );

                // Set scale domains.
                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

                var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                const y1 = d3.scaleLinear()
                .range([height, 0])
                .domain([0, d3.max(data, (d) => d.pop)]);
                //console.log(x.domain());
                // Construct our SVG object.
                const svg = d3.select('svg')
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append('g').attr('class', 'container')
                .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

                // Set x, y-left and y-right axis.
                var xAxis = d3.axisBottom(x)
                .ticks(d3.timeDay.every(1))
                // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                .tickSize(0).tickPadding(10);
                var y0Axis = d3.axisLeft(y0)
                .ticks(5).tickSize(0);
                var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                svg.append("g")
                .attr("class", "x-axis axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + 0 + ", 0)")
                .call(y0Axis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + width + ", 0)")
                .call(y1Axis);

                // Draw bars.
                var bars = svg.selectAll(".precips")
                .data(data);

                bars.exit().remove();

                bars.enter().append("rect")
                .attr("class", "precip")
                .attr("width", width / data.length - 50)
                .attr("x", function (d)
                return x(d.date);
                )
                .attr("y", height)
                .transition().duration(1000)
                .attr("y", function (d)
                return y0(d.pop);
                )
                .attr("height", function (d)
                return height - y0(d.pop);
                );

                const lineRH = d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)
                .y(d => y0(d['rh']));

                svg.append('path')
                .datum(data)
                .attr('class', 'line')
                .attr('fill', 'none')
                .attr('stroke', 'red')
                .attr('stroke-linejoin', 'round')
                .attr('stroke-linecap', 'round')
                .attr('stroke-width', 1.5)
                .attr('d', lineRH);

                <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                <svg></svg>





                I also tried with .nice() and a fun part would be to use the d3 time intervals within .nice(). Feel free to play around with those and let me know if you have any questions.



                Also, I'm offsetting the line (path) by the barwidth/2 in the line generator fn.



                d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)


                Hope this helps as well.






                var data = [

                fcst_valid_local: "2018-11-13T14:00:00-0600",
                pop: 20,
                rh: 67,
                temp: 38,
                wspd: 7
                ,

                fcst_valid_local: "2018-11-14T15:00:00-0600",
                pop: 15,
                rh: 50,
                temp: 39,
                wspd: 8
                ,

                fcst_valid_local: "2018-11-15T16:00:00-0600",
                pop: 10,
                rh: 90,
                temp: 40,
                wspd: 9

                ];

                // Margins, width and height.
                var margin = top: 20, right: 20, bottom: 30, left: 50,
                width = 500 - margin.left - margin.right,
                height = 200 - margin.top - margin.bottom;

                // Date parsing.
                const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                data.forEach(function (d)
                d.date = parseDate(d.fcst_valid_local);
                );

                // Set scale domains.
                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

                var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                const y1 = d3.scaleLinear()
                .range([height, 0])
                .domain([0, d3.max(data, (d) => d.pop)]);
                //console.log(x.domain());
                // Construct our SVG object.
                const svg = d3.select('svg')
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append('g').attr('class', 'container')
                .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

                // Set x, y-left and y-right axis.
                var xAxis = d3.axisBottom(x)
                .ticks(d3.timeDay.every(1))
                // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                .tickSize(0).tickPadding(10);
                var y0Axis = d3.axisLeft(y0)
                .ticks(5).tickSize(0);
                var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                svg.append("g")
                .attr("class", "x-axis axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + 0 + ", 0)")
                .call(y0Axis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + width + ", 0)")
                .call(y1Axis);

                // Draw bars.
                var bars = svg.selectAll(".precips")
                .data(data);

                bars.exit().remove();

                bars.enter().append("rect")
                .attr("class", "precip")
                .attr("width", width / data.length - 50)
                .attr("x", function (d)
                return x(d.date);
                )
                .attr("y", height)
                .transition().duration(1000)
                .attr("y", function (d)
                return y0(d.pop);
                )
                .attr("height", function (d)
                return height - y0(d.pop);
                );

                const lineRH = d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)
                .y(d => y0(d['rh']));

                svg.append('path')
                .datum(data)
                .attr('class', 'line')
                .attr('fill', 'none')
                .attr('stroke', 'red')
                .attr('stroke-linejoin', 'round')
                .attr('stroke-linecap', 'round')
                .attr('stroke-width', 1.5)
                .attr('d', lineRH);

                <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                <svg></svg>





                var data = [

                fcst_valid_local: "2018-11-13T14:00:00-0600",
                pop: 20,
                rh: 67,
                temp: 38,
                wspd: 7
                ,

                fcst_valid_local: "2018-11-14T15:00:00-0600",
                pop: 15,
                rh: 50,
                temp: 39,
                wspd: 8
                ,

                fcst_valid_local: "2018-11-15T16:00:00-0600",
                pop: 10,
                rh: 90,
                temp: 40,
                wspd: 9

                ];

                // Margins, width and height.
                var margin = top: 20, right: 20, bottom: 30, left: 50,
                width = 500 - margin.left - margin.right,
                height = 200 - margin.top - margin.bottom;

                // Date parsing.
                const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                data.forEach(function (d)
                d.date = parseDate(d.fcst_valid_local);
                );

                // Set scale domains.
                var x = d3.scaleTime().range([0, width])
                .domain([d3.min(data, function (d)
                return d.date;
                ), d3.timeDay.offset(d3.max(data, function (d) return d.date; ), 1)]);

                var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                const y1 = d3.scaleLinear()
                .range([height, 0])
                .domain([0, d3.max(data, (d) => d.pop)]);
                //console.log(x.domain());
                // Construct our SVG object.
                const svg = d3.select('svg')
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append('g').attr('class', 'container')
                .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

                // Set x, y-left and y-right axis.
                var xAxis = d3.axisBottom(x)
                .ticks(d3.timeDay.every(1))
                // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                .tickSize(0).tickPadding(10);
                var y0Axis = d3.axisLeft(y0)
                .ticks(5).tickSize(0);
                var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                svg.append("g")
                .attr("class", "x-axis axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + 0 + ", 0)")
                .call(y0Axis);
                svg.append("g")
                .attr("class", "y-axis axis")
                .attr("transform", "translate(" + width + ", 0)")
                .call(y1Axis);

                // Draw bars.
                var bars = svg.selectAll(".precips")
                .data(data);

                bars.exit().remove();

                bars.enter().append("rect")
                .attr("class", "precip")
                .attr("width", width / data.length - 50)
                .attr("x", function (d)
                return x(d.date);
                )
                .attr("y", height)
                .transition().duration(1000)
                .attr("y", function (d)
                return y0(d.pop);
                )
                .attr("height", function (d)
                return height - y0(d.pop);
                );

                const lineRH = d3.line()
                .x((d) => x(d['date']) + (width / data.length - 50)/2)
                .y(d => y0(d['rh']));

                svg.append('path')
                .datum(data)
                .attr('class', 'line')
                .attr('fill', 'none')
                .attr('stroke', 'red')
                .attr('stroke-linejoin', 'round')
                .attr('stroke-linecap', 'round')
                .attr('stroke-width', 1.5)
                .attr('d', lineRH);

                <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                <svg></svg>






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 15 '18 at 19:25









                ShashankShashank

                4,6501513




                4,6501513























                    1














                    Add a dummy data item that is a bit later then the last item



                    Here it is done hard coded but you can add it dynamic based on the date of the last item






                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>








                    share|improve this answer























                    • It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                      – Maihan Nijat
                      Nov 15 '18 at 18:32











                    • @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                      – rioV8
                      Nov 15 '18 at 18:45











                    • Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                      – Maihan Nijat
                      Nov 15 '18 at 18:53











                    • @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                      – rioV8
                      Nov 15 '18 at 18:56















                    1














                    Add a dummy data item that is a bit later then the last item



                    Here it is done hard coded but you can add it dynamic based on the date of the last item






                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>








                    share|improve this answer























                    • It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                      – Maihan Nijat
                      Nov 15 '18 at 18:32











                    • @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                      – rioV8
                      Nov 15 '18 at 18:45











                    • Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                      – Maihan Nijat
                      Nov 15 '18 at 18:53











                    • @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                      – rioV8
                      Nov 15 '18 at 18:56













                    1












                    1








                    1







                    Add a dummy data item that is a bit later then the last item



                    Here it is done hard coded but you can add it dynamic based on the date of the last item






                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>








                    share|improve this answer













                    Add a dummy data item that is a bit later then the last item



                    Here it is done hard coded but you can add it dynamic based on the date of the last item






                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>








                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>





                    var data = [

                    fcst_valid_local: "2018-11-13T14:00:00-0600",
                    pop: 20,
                    rh: 67,
                    temp: 38,
                    wspd: 7
                    ,

                    fcst_valid_local: "2018-11-14T15:00:00-0600",
                    pop: 15,
                    rh: 50,
                    temp: 39,
                    wspd: 8
                    ,

                    fcst_valid_local: "2018-11-15T16:00:00-0600",
                    pop: 10,
                    rh: 90,
                    temp: 40,
                    wspd: 9
                    ,

                    fcst_valid_local: "2018-11-16T01:00:00-0600"

                    ];

                    // Margins, width and height.
                    var margin = top: 20, right: 20, bottom: 30, left: 50,
                    width = 500 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                    // Date parsing.
                    const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
                    data.forEach(function (d)
                    d.date = parseDate(d.fcst_valid_local);
                    );

                    // Set scale domains.
                    var x = d3.scaleTime().range([0, width])
                    .domain(d3.extent(data, function (d)
                    return d.date;
                    ));

                    var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
                    const y1 = d3.scaleLinear()
                    .range([height, 0])
                    .domain([0, d3.max(data, (d) => d.pop)]);

                    // Construct our SVG object.
                    const svg = d3.select('svg')
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append('g').attr('class', 'container')
                    .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

                    // Set x, y-left and y-right axis.
                    var xAxis = d3.axisBottom(x)
                    .ticks(d3.timeDay.every(1))
                    // .tickFormat(d3.timeFormat('%b %d, %H:%M'))
                    .tickSize(0).tickPadding(10);
                    var y0Axis = d3.axisLeft(y0)
                    .ticks(5).tickSize(0);
                    var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);

                    svg.append("g")
                    .attr("class", "x-axis axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(xAxis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + 0 + ", 0)")
                    .call(y0Axis);
                    svg.append("g")
                    .attr("class", "y-axis axis")
                    .attr("transform", "translate(" + width + ", 0)")
                    .call(y1Axis);

                    // Draw bars.
                    var bars = svg.selectAll(".precips")
                    .data(data);

                    bars.exit().remove();

                    bars.enter().append("rect")
                    .attr("class", "precip")
                    .attr("width", width / data.length - 50)
                    .attr("x", function (d)
                    return x(d.date);
                    )
                    .attr("y", height)
                    .transition().duration(1000)
                    .attr("y", function (d)
                    return y0(d.pop);
                    )
                    .attr("height", function (d)
                    return height - y0(d.pop);
                    );

                    const lineRH = d3.line()
                    .x((d) => x(d['date']))
                    .y(d => y0(d['rh']));

                    svg.append('path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr('fill', 'none')
                    .attr('stroke', 'red')
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', 1.5)
                    .attr('d', lineRH);

                    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
                    <svg></svg>






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 15 '18 at 18:12









                    rioV8rioV8

                    4,5142312




                    4,5142312












                    • It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                      – Maihan Nijat
                      Nov 15 '18 at 18:32











                    • @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                      – rioV8
                      Nov 15 '18 at 18:45











                    • Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                      – Maihan Nijat
                      Nov 15 '18 at 18:53











                    • @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                      – rioV8
                      Nov 15 '18 at 18:56

















                    • It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                      – Maihan Nijat
                      Nov 15 '18 at 18:32











                    • @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                      – rioV8
                      Nov 15 '18 at 18:45











                    • Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                      – Maihan Nijat
                      Nov 15 '18 at 18:53











                    • @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                      – rioV8
                      Nov 15 '18 at 18:56
















                    It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                    – Maihan Nijat
                    Nov 15 '18 at 18:32





                    It won't help if I have data from the API. it is a workaround but looking for practical solution. Thanks

                    – Maihan Nijat
                    Nov 15 '18 at 18:32













                    @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                    – rioV8
                    Nov 15 '18 at 18:45





                    @MaihanNijat: like I made the remark to add it dynamically based on the last value in the dataset

                    – rioV8
                    Nov 15 '18 at 18:45













                    Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                    – Maihan Nijat
                    Nov 15 '18 at 18:53





                    Thanks, It creates gap between line (red) and the right y axis. Also, the x-axis not aligned with rectangles. What is causing all this mess?

                    – Maihan Nijat
                    Nov 15 '18 at 18:53













                    @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                    – rioV8
                    Nov 15 '18 at 18:56





                    @MaihanNijat: you can't have the red line touch the right y-axis AND have a bar that starts at the last date and does not go beyond the right y-axis

                    – rioV8
                    Nov 15 '18 at 18:56

















                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325104%2fhow-to-align-x-axis-with-bars-respectively-in-combo-chart-bars-and-lines%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    How to read a connectionString WITH PROVIDER in .NET Core?

                    Node.js Script on GitHub Pages or Amazon S3

                    Museum of Modern and Contemporary Art of Trento and Rovereto