# Thread: X-axis using logorithm scale

1. Member
Join Date
Jul 2013
Posts
31

## X-axis using logorithm scale

Hi All,

I am wondering if there is a way to change the scale of the x-axis to be logarithm instead of linear, it appear to be doable in protovis
var yScale = pv.Scale.log(0,popCountArray.length).range(0,height);
I have a dot chart that would like the x-axis ticks to be 0, 100, 10000, 1000000, 10000000,

If it is doable, where and how can I do it?

Thanks.

2. Senior Member
Join Date
Mar 2012
Posts
645
Not doable solely with simple configuration, in CCC, whether for the X or the Y axis.

The workaround is to simulate the log scale, by providing pre-log'ed values to the chart.
Provide the X-values as the logarithm of base 10 of the real value:
• -1 <- 10^-1 = 0.1
• 0 <- 10^0 = 1
• 1 <- 10^1 = 10
• 2 <- 10^2 = 100
• 3 <- 10^3 = 1000
• ...

Assuming we're using a metric chart, the X-axis dimension is named "x", by default (if not a metric chart, note that, in most other charts, the X-axis is fed with a dimension named "category").

The conversion can be done by specifying a "converter" for the "x" dimension.
Then, format the dimension so that the original value is always shown to the user, instead of the exponent.
The "x" dimension's "formatter" handles the value that is shown in the tooltip.
For when the value is shown in the X-axis' ticks, specify the "baseAxisTickFormatter" property.

In the component's "postFetch" handler specify:
Code:
```function() {
// Protovis formatter for the original values (you may need to adjust the number of decimal places)
var rawFormatter = pv.Format.createFormatter(pv.Format.number().fractionDigits(0, 2));

var cd = this.chartDefinition;
cd.dimensions = {
"x": {
// Convert X Values to its log_10.
// Original value, v, remains accessible in datum.rawValue .
// Negative values are converted to null (they're not representable with log scale).
converter: function(v) {
if(v != null) { v = +v; } // Convert non-null to number
return (v == null || isNaN(v) || v <= 0) ? null : (Math.log(v)/Math.LN10);
},

// The original/raw value is shown, formatted:
formatter: function(value, rawValue) {
return value == null ? "-" : rawFormatter(+rawValue);
}
}
};

// Calculate the corresponding original value and format it.
// You could also show it as 10^-1, 10^0, 10^1, ... or some variation of this.
cd.baseAxisTickFormatter = function(v) {
return rawFormatter(Math.pow(10, v));
};

// You may want to provide an adequate axis title. Something like:
cd.baseAxisTitle = "Frequency (log 10)";

// Show grid lines
cd.baseAxisGrid = true;

// Force tick and grid step to be 1.
//   Hack 1. Ensure only 1x, 2x, 5x ticks steps are generated:
cd.baseAxisTickExponentMin = 0;
cd.baseAxisTickExponentMax = 0;

//   Hack 2. Exclude 2x and 5x steps unless it gets really clobbered.
cd.baseAxisLabelSpacingMin = 0.1; // em.s

//   Hack 3. Force ticks to align with plot ends.
cd.baseAxisDomainRoundMode = 'tick';

// Hide minor ticks, cause these are drawn midway between major ticks, and not at the correct 5*10^n position...
cd.baseAxisMinorTicks = false;
}```
If you really wan't to show only the ticks and grid-lines of 1, 100, 10000, etc, you'll need to hide every other tick and grid-line, by specifying the following extension points:
• orthoAxisTicksPanel_visible --> function() { return !(this.index % 2); }
• orthoAxisGrid_visible --> function() { return !(this.index % 2); }

Last but not the least, if you wan't to show gridlines in the 2*10^n, 3*10^n, ... between the major grid-lines, you'll have a little more work.
Place the following in the "orthoAxisGrid_add" extension point:
Code:
```function() {
return new pv.Rule()
.data(function() {
var data = this.delegate();
var minorsRange = pv.range(2, 10, 1); // 2, 3, ..., 9
var minorScenes = [];
data.forEach(function(majorScene, i) {
// Skip last major tick. Don't draw outside the plot.
if(i === data.length - 1) { return; }

var v_major = majorScene.vars.tick.value;
var v_origMajor = Math.pow(10, v_major);
minorsRange.forEach(function(m) {
var orig_m = m * v_origMajor;
var v_minor = Math.log(orig_m) / Math.LN10;
var minorScene = new pvc.visual.CartesianAxisTickScene(majorScene, {
tick:      v_minor,
tickRaw:   v_minor,
tickLabel: v_minor.toFixed(2) // not really relevant
});
minorScenes.push(minorScene);
});
});
return minorScenes;
})
.zOrder(-12); // Not inherited from major grid-rule. Must repeat.
}```
I've set a up a jsFiddle showing this technique, here.
Hope it helps! In a not so distant future, we'll surely add support for log scales, in a more yes/no fashion...