Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log along the x-axis (bug 189) #296

Merged
merged 4 commits into from May 29, 2014
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -30,3 +30,27 @@ DygraphOptionsTestCase.prototype.testGetSeriesNames = function() {
var o = new DygraphOptions(g);
assertEquals(["Y", "Y2", "Y3"], o.seriesNames());
};

/*
* Ensures that even if logscale is set globally, it doesn't impact the
* x axis.
*/
DygraphOptionsTestCase.prototype.getLogscaleForX = function() {
var opts = {
width: 480,
height: 320
};
var data = "X,Y,Y2,Y3\n" +
"1,-1,2,3";

// Kind of annoying that you need a DOM to test the object.
var graph = document.getElementById("graph");
var g = new Dygraph(graph, data, opts);

assertFalse(g.getOptionForAxis('logscale', 'x'));
assertFalse(g.getOptionForAxis('logscale', 'y'));

g.updateOptions({ logscale : true });
assertFalse(g.getOptionForAxis('logscale', 'x'));
assertTrue(g.getOptionForAxis('logscale', 'y'));
};
@@ -172,19 +172,25 @@ ToDomCoordsTestCase.prototype.testAxisTickSize = function() {
assertEquals([500, 386], g.toDomCoords(100, 0));
}

ToDomCoordsTestCase.prototype.testChartLogarithmic = function() {
ToDomCoordsTestCase.prototype.testChartLogarithmic_YAxis = function() {
var opts = {
drawXAxis: false,
drawYAxis: false,
drawXGrid: false,
drawYGrid: false,
logscale: true,
rightGap: 0,
valueRange: [1, 4],
dateWindow: [0, 10],
width: 400,
height: 400,
colors: ['#ff0000']
colors: ['#ff0000'],
axes: {
x: {
drawGrid: false,
drawAxis: false
},
y: {
drawGrid: false,
drawAxis: false,
logscale: true
}
}
}

var graph = document.getElementById("graph");
@@ -203,3 +209,64 @@ ToDomCoordsTestCase.prototype.testChartLogarithmic = function() {
assertEquals([400, 400], g.toDomCoords(10, 1));
assertEquals([400, 200], g.toDomCoords(10, 2));
}

ToDomCoordsTestCase.prototype.testChartLogarithmic_XAxis = function() {
var opts = {
rightGap: 0,
valueRange: [1, 1000],
dateWindow: [1, 1000],
width: 400,
height: 400,
colors: ['#ff0000'],
axes: {
x: {
drawGrid: false,
drawAxis: false,
logscale: true
},
y: {
drawGrid: false,
drawAxis: false
}
}
}

var graph = document.getElementById("graph");
g = new Dygraph(graph, [ [1,1], [10, 10], [100,100], [1000,1000] ], opts);

var epsilon = 1e-8;
assertEqualsDelta(1, g.toDataXCoord(0), epsilon);
assertEqualsDelta(5.623413251903489, g.toDataXCoord(100), epsilon);
assertEqualsDelta(31.62277660168378, g.toDataXCoord(200), epsilon);
assertEqualsDelta(177.8279410038921, g.toDataXCoord(300), epsilon);
assertEqualsDelta(1000, g.toDataXCoord(400), epsilon);

assertEqualsDelta(0, g.toDomXCoord(1), epsilon);
assertEqualsDelta(3.6036036036036037, g.toDomXCoord(10), epsilon);
assertEqualsDelta(39.63963963963964, g.toDomXCoord(100), epsilon);
assertEqualsDelta(400, g.toDomXCoord(1000), epsilon);

assertEqualsDelta(0, g.toPercentXCoord(1), epsilon);
assertEqualsDelta(0.3333333333, g.toPercentXCoord(10), epsilon);
assertEqualsDelta(0.6666666666, g.toPercentXCoord(100), epsilon);
assertEqualsDelta(1, g.toPercentXCoord(1000), epsilon);

// Now zoom in and ensure that the methods return reasonable values.
g.updateOptions({dateWindow: [ 10, 100 ]});

assertEqualsDelta(10, g.toDataXCoord(0), epsilon);
assertEqualsDelta(17.78279410038923, g.toDataXCoord(100), epsilon);
assertEqualsDelta(31.62277660168379, g.toDataXCoord(200), epsilon);
assertEqualsDelta(56.23413251903491, g.toDataXCoord(300), epsilon);
assertEqualsDelta(100, g.toDataXCoord(400), epsilon);

assertEqualsDelta(-40, g.toDomXCoord(1), epsilon);
assertEqualsDelta(0, g.toDomXCoord(10), epsilon);
assertEqualsDelta(400, g.toDomXCoord(100), epsilon);
assertEqualsDelta(4400, g.toDomXCoord(1000), epsilon);

assertEqualsDelta(-1, g.toPercentXCoord(1), epsilon);
assertEqualsDelta(0, g.toPercentXCoord(10), epsilon);
assertEqualsDelta(1, g.toPercentXCoord(100), epsilon);
assertEqualsDelta(2, g.toPercentXCoord(1000), epsilon);
}
@@ -38,8 +38,14 @@ Dygraph.Interaction.startPan = function(event, g, context) {
var i, axis;
context.isPanning = true;
var xRange = g.xAxisRange();
context.dateRange = xRange[1] - xRange[0];
context.initialLeftmostDate = xRange[0];

if (g.getOptionForAxis("logscale", "x")) {
context.initialLeftmostDate = Dygraph.log10(xRange[0]);
context.dateRange = Dygraph.log10(xRange[1]) - Dygraph.log10(xRange[0]);
} else {
context.initialLeftmostDate = xRange[0];
context.dateRange = xRange[1] - xRange[0];
}
context.xUnitsPerPixel = context.dateRange / (g.plotter_.area.w - 1);

if (g.getNumericOption("panEdgeFraction")) {
@@ -132,7 +138,12 @@ Dygraph.Interaction.movePan = function(event, g, context) {
}
}

g.dateWindow_ = [minDate, maxDate];
if (g.getOptionForAxis("logscale", "x")) {
g.dateWindow_ = [ Math.pow(Dygraph.LOG_SCALE, minDate),
Math.pow(Dygraph.LOG_SCALE, maxDate) ];
} else {
g.dateWindow_ = [minDate, maxDate];
}

// y-axis scaling is automatic unless this is a full 2D pan.
if (context.is2DPan) {
@@ -160,8 +171,7 @@ Dygraph.Interaction.movePan = function(event, g, context) {
minValue = maxValue - axis_data.dragValueRange;
}
}
var logscale = g.attributes_.getForAxis("logscale", i);
if (logscale) {
if (g.attributes_.getForAxis("logscale", i)) {
axis.valueWindow = [ Math.pow(Dygraph.LOG_SCALE, minValue),
Math.pow(Dygraph.LOG_SCALE, maxValue) ];
} else {
@@ -175,6 +175,7 @@ DygraphLayout.prototype.setYAxes = function (yAxes) {
};

DygraphLayout.prototype.evaluate = function() {
this._xAxis = {};

This comment has been minimized.

@danvk

danvk Apr 23, 2014
Owner

Looks like most member vars have trailing underscores. I should really clean this up sometime.

This comment has been minimized.

@kberg

kberg Apr 24, 2014
Author Collaborator

ack. Agreed, and, no-op.

this._evaluateLimits();
this._evaluateLineCharts();
this._evaluateLineTicks();
@@ -183,19 +184,23 @@ DygraphLayout.prototype.evaluate = function() {

DygraphLayout.prototype._evaluateLimits = function() {
var xlimits = this.dygraph_.xAxisRange();
this.minxval = xlimits[0];
this.maxxval = xlimits[1];
this._xAxis.minval = xlimits[0];
this._xAxis.maxval = xlimits[1];
var xrange = xlimits[1] - xlimits[0];
this.xscale = (xrange !== 0 ? 1 / xrange : 1.0);
this._xAxis.scale = (xrange !== 0 ? 1 / xrange : 1.0);

if (this.dygraph_.getOptionForAxis("logscale", 'x')) {
this._xAxis.xlogrange = Dygraph.log10(this._xAxis.maxval) - Dygraph.log10(this._xAxis.minval);
this._xAxis.xlogscale = (this._xAxis.xlogrange !== 0 ? 1.0 / this._xAxis.xlogrange : 1.0);
}
for (var i = 0; i < this.yAxes_.length; i++) {
var axis = this.yAxes_[i];
axis.minyval = axis.computedValueRange[0];
axis.maxyval = axis.computedValueRange[1];
axis.yrange = axis.maxyval - axis.minyval;
axis.yscale = (axis.yrange !== 0 ? 1.0 / axis.yrange : 1.0);

if (axis.g.getOption("logscale")) {
if (this.dygraph_.getOption("logscale")) {
axis.ylogrange = Dygraph.log10(axis.maxyval) - Dygraph.log10(axis.minyval);
axis.ylogscale = (axis.ylogrange !== 0 ? 1.0 / axis.ylogrange : 1.0);
if (!isFinite(axis.ylogrange) || isNaN(axis.ylogrange)) {
@@ -207,6 +212,14 @@ DygraphLayout.prototype._evaluateLimits = function() {
}
};

DygraphLayout.calcXNormal_ = function(value, xAxis, logscale) {
if (logscale) {
return ((Dygraph.log10(value) - Dygraph.log10(xAxis.minval)) * xAxis.xlogscale);
} else {
return (value - xAxis.minval) * xAxis.scale;
}
};

/**
* @param {DygraphAxisType} axis
* @param {number} value
@@ -224,6 +237,7 @@ DygraphLayout.calcYNormal_ = function(axis, value, logscale) {

DygraphLayout.prototype._evaluateLineCharts = function() {
var isStacked = this.dygraph_.getOption("stackedGraph");
var isLogscaleForX = this.dygraph_.getOptionForAxis("logscale", 'x');

for (var setIdx = 0; setIdx < this.points.length; setIdx++) {
var points = this.points[setIdx];
@@ -237,7 +251,7 @@ DygraphLayout.prototype._evaluateLineCharts = function() {
var point = points[j];

// Range from 0-1 where 0 represents left and 1 represents right.
point.x = (point.xval - this.minxval) * this.xscale;
point.x = DygraphLayout.calcXNormal_(point.xval, this._xAxis, isLogscaleForX);
// Range from 0-1 where 0 represents top and 1 represents bottom
var yval = point.yval;
if (isStacked) {
@@ -266,7 +280,7 @@ DygraphLayout.prototype._evaluateLineTicks = function() {
for (i = 0; i < this.xTicks_.length; i++) {
tick = this.xTicks_[i];
label = tick.label;
pos = this.xscale * (tick.v - this.minxval);
pos = this.dygraph_.toPercentXCoord(tick.v);
if ((pos >= 0.0) && (pos < 1.0)) {
this.xticks.push([pos, label]);
}
@@ -371,7 +371,7 @@ Dygraph.OPTIONS_REFERENCE = // <JSON>
"default": "false",
"labels": ["Axis display"],
"type": "boolean",
"description": "When set for a y-axis, the graph shows that axis in log scale. Any values less than or equal to zero are not displayed.\n\nNot compatible with showZero, and ignores connectSeparatedPoints. Also, showing log scale with valueRanges that are less than zero will result in an unviewable graph."
"description": "When set for the y-axis or x-axis, the graph shows that axis in log scale. Any values less than or equal to zero are not displayed. Showing log scale with ranges that go below zero will result in an unviewable graph.\n\n Not compatible with showZero. connectSeparatedPoints is ignored. This is ignored for date-based x-axes."
},
"strokeWidth": {
"default": "1.0",
@@ -290,11 +290,13 @@ DygraphOptions.prototype.getForAxis = function(name, axis) {
}

// User-specified global options second.
var result = this.getGlobalUser_(name);
if (result !== null) {
return result;
// But, hack, ignore globally-specified 'logscale' for 'x' axis declaration.
if (!(axis === 'x' && name === 'logscale')) {
var result = this.getGlobalUser_(name);
if (result !== null) {
return result;
}
}

// Default axis options third.
var defaultAxisOptions = Dygraph.DEFAULT_ATTRS.axes[axisString];
if (defaultAxisOptions.hasOwnProperty(name)) {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.