4

I'm trying to understand how jqplot calculates the width of bars when the width is not specified. Say I have the following chart:

$.jqplot(chartDiv.attr("id"), [
    [
        ['2013-02-15', 0],
        ['2013-03-01', 2],
        ['2013-03-15', 4],
        ['2013-03-29', 6],
        ['2013-04-12', 8],
        ['2013-04-26', 10],
        ['2013-05-10', 12],
        ['2013-05-24', 14],
        ['2013-06-07', 16],
        ['2013-06-21', 18],
        ['2013-07-05', 20],
        ['2013-07-19', 22],
        ['2013-08-02', 24],
        ['2013-08-16', 26],
        ['2013-08-30', 28],
        ['2013-09-13', 30],
        ['2013-09-27', 32],
        ['2013-10-11', 34],
        ['2013-10-25', 36],
        ['2013-11-08', 38], , ], ], {


    axes: {
        xaxis: {
            renderer: $.jqplot.DateAxisRenderer,
            min: '2013-1-20',
            max: '2013-12-1',
            tickRenderer: $.jqplot.CanvasAxisTickRenderer,
            tickInterval: '14 days',
            tickOptions: {
                angle: 45,
                formatString: '%d/%m/%Y',
            },
        }
    },
    series: [{
        xaxis: 'xaxis',
        yaxis: 'yaxis',
        renderer: $.jqplot.BarRenderer,
    }],
    seriesDefaults: {
        shadow: false,
    },
    axesDefaults: {
       useSeriesColor: true,
        rendererOptions: {
            alignTicks: true
        }
    },
});

When I change tickInterval between 7 days and 14 days, the width of the bars alters, despite there being the same number of bars on the same physical area. How is tickInterval used in the calculation of bar widths? Or failing that, how can I alter this example such that tickInterval can vary (it will be calculated from data eventually) but the width of the bars be set to something sensible?

elo96
  • 341
  • 1
  • 5
  • 16

2 Answers2

9

In jqplot.barRenderer.js there is a property called barWidth:

// prop: barWidth
// Width of the bar in pixels (auto by devaul).  null = calculated automatically.
this.barWidth = null;

When setting the series options, you can also supply rendererOptions. Adding this:

rendererOptions: { barWidth: 10 }

So the series becomes:

series: [{
    xaxis: 'xaxis',
    yaxis: 'yaxis',
    renderer: $.jqplot.BarRenderer,
    rendererOptions: { barWidth: 10 }
}],

Will force all bars to be 10 pixels wide, regardless of the tickInterval.

Edit:

The details for determining bar widths are in the setBarWidth function in jqplot.barRenderer.js.

To give you an example, calculating the bar widths for an unstacked x-axis (it's very similar for the y-axis) is as follows:

var nticks = paxis.numberTicks;
var nbins = (nticks-1)/2;

this.barWidth = ((paxis._offsets.max - paxis._offsets.min) / nbins -
    this.barPadding * (nseries - 1) - this.barMargin * 2) / nseries;

Essentially, we first take the width (or height) of the axis, and divide it by the maximum number of bins (in this case bars). From this we subtract the total padding between series (in this case it is zero as there is only one series) and then subtract the margin around the outside of the bar. After that the total bar width is divided by the number of series in the plot.

As you can see from that code, the important bit is really establishing the number of ticks to display. In your particular case, this happens in the DateAxisRenderer, where it essentially finds the number of days between the max and min date ('2013-1-20' and '2013-12-1') - 315 - before dividing by the number of days in the interval, which from yoru question was either 7 or 14, giving 46 and 24 respectively.

nick_w
  • 14,758
  • 3
  • 51
  • 71
  • Thanks for that nick_w. My confusion is more for when barWidth is not specified and is 'calculated automatically'. I don't see what that calculation is based on. – elo96 Feb 04 '13 at 08:36
  • 1
    nick_w: thanks for the very clear explanation. It looks like automatic bar-width calculation is not useful when using DateAxisRenderer since it depends on the number of ticks rather than the number of bars. – elo96 Feb 05 '13 at 08:42
0

Thanks a lot for the answer. This is old, but here is what i did to solve the problem in my case

$.jqplot.DateBarRenderer = function(){
    $.jqplot.BarRenderer.call(this);
};
$.jqplot.DateBarRenderer.prototype = new $.jqplot.BarRenderer();

  $.jqplot.DateBarRenderer.prototype.setBarWidth = function() {
  // need to know how many data values we have on the approprate axis and figure it out.
  var i;
  var nvals = 0;
  var nseries = 0;
  var paxis = this[this._primaryAxis];
  var s, series, pos;
  var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
  nvals = temp[0];
  nseries = temp[1];
  var nticks = paxis.numberTicks;
  var nbins = (nticks-1)/2;
  // so, now we have total number of axis values.
  if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
      if (this._stack) {
          this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
      }
      else {
          this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/ (nvals + 1 )  - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
          //this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins  - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
          // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
      }
  }
  else {
      if (this._stack) {
          this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
      }
      else {
          this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins  - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
          // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
      }
  }
  return [nvals, nseries];
};

I simply replaced the setBarWidth of the BarRenderer to use the number of values instead of the number of ticks. The rest of the code is from the BarRenderer object, keeping it unchanged in case of an update.

To use it, just use:

var plot = $.jqplot('graphID', [graphData], {
    axes:{
      xaxis:{
        renderer:$.jqplot.DateAxisRenderer
      }
    },
    seriesDefaults:{
      renderer:$.jqplot.DateBarRenderer
    }
  });
jaudette
  • 2,305
  • 1
  • 20
  • 20