Lucas03
Lucas03

Reputation: 2347

nvd3 multibarchart last bar is hidden not visible

Based on this stackoverflow answer I was trying to copy essential parts to get proper scale for timeline. I use multibarcharts for multible graphs, from few records to hundreds with X-axis having data from 1930 to today.

I've copied it like this, but I have two issues:

  1. Last bar is always outside of graph
  2. bars overlap, which I can partly fix by altering numTicks, but isn't there a better way?

    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.js"></script>
    <script type="text/javascript">
        nv.addGraph(function() {
          var data = [{
            "values": [
    
                    { x: new Date("1999-12-01"), y: 42.27 } , 
    
                    { x: new Date("2000-12-01"), y: 41.73 } , 
    
                    { x: new Date("2001-12-01"), y: 41.34 } , 
    
                    { x: new Date("2002-12-01"), y: 41.84 } , 
    
                    { x: new Date("2003-12-01"), y: 43.93 } , 
    
                    { x: new Date("2004-12-01"), y: 42.18 } , 
    
                    { x: new Date("2005-12-01"), y: 42.31 } , 
    
                    { x: new Date("2006-12-01"), y: 43.14 } , 
    
                    { x: new Date("2007-12-01"), y: 43.24 } , 
    
                    { x: new Date("2008-12-01"), y: 39.30 } , 
    
                    { x: new Date("2009-12-01"), y: 43.80 } , 
    
                    { x: new Date("2010-12-01"), y: 44.10 } , 
    
                    { x: new Date("2011-12-01"), y: 54.10 } , 
    
                    { x: new Date("2012-12-01"), y: 62.10 } , 
    
                    { x: new Date("2013-12-01"), y: 56.70 } , 
    
                    { x: new Date("2014-12-01"), y: 45 } , 
    
                    { x: new Date("2015-12-01"), y: 55.60 } , 
    
                    { x: new Date("2026-12-01"), y: 54.40 } , 
    
                    { x: new Date("2027-12-01"), y: 57 } 
    
            ],
            "bar": true,
            "key": "Payout Ratio"
          }];
    
          var chart = nv.models.multiBarChart(),
              container = d3.select('#payout_ratio_chart svg'),
              availableWidth,
              numTicks = data[0].values.length,
              xScale = d3.time.scale();
    
          function updateAvailableWidth() {
              availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
          }
          updateAvailableWidth();
          nv.utils.windowResize(updateAvailableWidth);
    
          xScale.rangeBands = xScale.range;
          xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * availableWidth / numTicks; };
    
          chart.multibar.xScale(xScale);
    
          var last_date = data[0].values[data[0].values.length-1].x;
          last_date.setMonth(last_date.getMonth() + 10);
          chart.xDomain([data[0].values[0].x, last_date]);
    
          chart.xAxis.tickFormat(function(d){ return d3.time.format('%b %Y')(new Date(d)); });
          chart.yAxis.tickFormat(d3.format(',f'));
    
    
          chart.showControls(false);
    
          container.datum(data).transition().duration(500).call(chart);
    
          nv.utils.windowResize(chart.update);
    
          return chart;
      });
    </script>
    

https://jsfiddle.net/lucas03/poamvfke/4/

Upvotes: 0

Views: 265

Answers (2)

Dipen Shah
Dipen Shah

Reputation: 26075

Checkout the code below which was derived from your posted code:

nv.addGraph(function() {
  var data = [{
    "values": [

      {
        x: new Date("1999-12-01"),
        y: 42.27
      },

      {
        x: new Date("2000-12-01"),
        y: 41.73
      },

      {
        x: new Date("2001-12-01"),
        y: 41.34
      },

      {
        x: new Date("2002-12-01"),
        y: 41.84
      },

      {
        x: new Date("2003-12-01"),
        y: 43.93
      },

      {
        x: new Date("2004-12-01"),
        y: 42.18
      },

      {
        x: new Date("2005-12-01"),
        y: 42.31
      },

      {
        x: new Date("2006-12-01"),
        y: 43.14
      },

      {
        x: new Date("2007-12-01"),
        y: 43.24
      },

      {
        x: new Date("2008-12-01"),
        y: 39.30
      },

      {
        x: new Date("2009-12-01"),
        y: 43.80
      },

      {
        x: new Date("2010-12-01"),
        y: 44.10
      },

      {
        x: new Date("2011-12-01"),
        y: 54.10
      },

      {
        x: new Date("2012-12-01"),
        y: 62.10
      },

      {
        x: new Date("2013-12-01"),
        y: 56.70
      },

      {
        x: new Date("2014-12-01"),
        y: 45
      },

      {
        x: new Date("2015-12-01"),
        y: 55.60
      },

      {
        x: new Date("2026-12-01"),
        y: 54.40
      },

      {
        x: new Date("2027-12-01"),
        y: 57
      }

    ],
    "bar": true,
    "key": "Payout Ratio"
  }];


  var fDate = data[0].values[0].x,
  lDate = new Date(data[0].values[data[0].values.length - 1].x);
  lDate.setFullYear(lDate.getFullYear() + 1);
  
  var chart = nv.models.multiBarChart()
    .showControls(false)
    .reduceXTicks(false)
    .rotateLabels(-45),
    container = d3.select('#payout_ratio_chart svg'),
    availableWidth,
    numTicks = (lDate.getFullYear() - fDate.getFullYear()) + 1,
    xScale = d3.time.scale();

  function updateAvailableWidth() {
    availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
  }
  updateAvailableWidth();

  xScale.rangeBands = xScale.range;
  xScale.rangeBand = function() {
    return (1 - chart.groupSpacing()) * availableWidth / numTicks;
  };

  chart.multibar.xScale(xScale);

  chart.xDomain([fDate, lDate]);

  chart.xAxis.tickFormat(function(d) {
    return d3.time.format('%b %Y')(new Date(d));
  });
  chart.yAxis.tickFormat(d3.format(',f'));

  container.datum(data).transition().duration(500).call(chart);

  nv.utils.windowResize(function() {
    updateAvailableWidth();
    chart.update();
  });

  return chart;
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.css" rel="stylesheet"/>
<div id="payout_ratio_chart">
  <svg style="width:100%;height:400px" />
</div>

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.js"></script>

Fixes:

Only difference between your code and fixed code is how fDate, lDate and numTicks are calculated.

fDate is your start date while lDate is last date in data for the following year. Lastly, numTicks is difference between years in fDate and lDate.

Find jsfiddle here.

Upvotes: 1

rioV8
rioV8

Reputation: 28643

You have a bar chart so you have to insert data points for not existing dates.

Here I have hard coded but you can write some logic to add missing dates. For some other data serie you can have values for the missing dates of this serie.

nvd3 draws these bars with a minimal height of 1px, so add a style to hide these small bars

.nvd3 .nv-groups rect[height="1"] {
    opacity: 0;
}

nv.addGraph(function() {
  var data = [{
    "values": [
      { x: new Date("1999-12-01"), y: 42.27 },
      { x: new Date("2000-12-01"), y: 41.73 },
      { x: new Date("2001-12-01"), y: 41.34 },
      { x: new Date("2002-12-01"), y: 41.84 },
      { x: new Date("2003-12-01"), y: 43.93 },
      { x: new Date("2004-12-01"), y: 42.18 },
      { x: new Date("2005-12-01"), y: 42.31 },
      { x: new Date("2006-12-01"), y: 43.14 },
      { x: new Date("2007-12-01"), y: 43.24 },
      { x: new Date("2008-12-01"), y: 39.30 },
      { x: new Date("2009-12-01"), y: 43.80 },
      { x: new Date("2010-12-01"), y: 44.10 },
      { x: new Date("2011-12-01"), y: 54.10 },
      { x: new Date("2012-12-01"), y: 62.10 },
      { x: new Date("2013-12-01"), y: 56.70 },
      { x: new Date("2014-12-01"), y: 45 },
      { x: new Date("2015-12-01"), y: 55.60 },
      { x: new Date("2016-12-01"), y: 0 },
      { x: new Date("2017-12-01"), y: 0 },
      { x: new Date("2018-12-01"), y: 0 },
      { x: new Date("2019-12-01"), y: 0 },
      { x: new Date("2020-12-01"), y: 0 },
      { x: new Date("2021-12-01"), y: 0 },
      { x: new Date("2022-12-01"), y: 0 },
      { x: new Date("2023-12-01"), y: 0 },
      { x: new Date("2024-12-01"), y: 0 },
      { x: new Date("2025-12-01"), y: 0 },
      { x: new Date("2026-12-01"), y: 54.40 },
      { x: new Date("2027-12-01"), y: 57 }
    ],
    "bar": true,
    "key": "Payout Ratio"
  }];

  var chart = nv.models.multiBarChart(),
    container = d3.select('#payout_ratio_chart svg');

  chart.xAxis.tickFormat(function(d) {
    return d3.time.format('%b %Y')(new Date(d));
  });
  chart.yAxis.tickFormat(d3.format(',f'));

  chart.showControls(false);

  container.datum(data).transition().duration(500).call(chart);

  nv.utils.windowResize(chart.update);

  return chart;
});
.nvd3 .nv-groups rect[height="1"] {
    opacity: 0;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.css" rel="stylesheet"/>
<div id="payout_ratio_chart">
  <svg style="width:100%;height:400px" />
</div>

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.js"></script>

Upvotes: 0

Related Questions