Skip to content

Commit

Permalink
continue lines off the edge toward invalid log values
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcjohnson committed Sep 1, 2018
1 parent 2fde3dc commit 68b489d
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 18 deletions.
6 changes: 6 additions & 0 deletions src/constants/numerical.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ module.exports = {
*/
ALMOST_EQUAL: 1 - 1e-6,

/*
* If we're asked to clip a non-positive log value, how far off-screen
* do we put it?
*/
LOG_CLIP: 10,

/*
* not a number, but for displaying numbers: the "minus sign" symbol is
* wider than the regular ascii dash "-"
Expand Down
10 changes: 3 additions & 7 deletions src/plots/cartesian/set_convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var ensureNumber = Lib.ensureNumber;
var numConstants = require('../../constants/numerical');
var FP_SAFE = numConstants.FP_SAFE;
var BADNUM = numConstants.BADNUM;
var LOG_CLIP = numConstants.LOG_CLIP;

var constants = require('./constants');
var axisIds = require('./axis_ids');
Expand Down Expand Up @@ -59,20 +60,15 @@ module.exports = function setConvert(ax, fullLayout) {

var axLetter = (ax._id || 'x').charAt(0);

// clipMult: how many axis lengths past the edge do we render?
// for panning, 1-2 would suffice, but for zooming more is nice.
// also, clipping can affect the direction of lines off the edge...
var clipMult = 10;

function toLog(v, clip) {
if(v > 0) return Math.log(v) / Math.LN10;

else if(v <= 0 && clip && ax.range && ax.range.length === 2) {
// clip NaN (ie past negative infinity) to clipMult axis
// clip NaN (ie past negative infinity) to LOG_CLIP axis
// length past the negative edge
var r0 = ax.range[0],
r1 = ax.range[1];
return 0.5 * (r0 + r1 - 3 * clipMult * Math.abs(r0 - r1));
return 0.5 * (r0 + r1 - 2 * LOG_CLIP * Math.abs(r0 - r1));
}

else return BADNUM;
Expand Down
48 changes: 37 additions & 11 deletions src/traces/scatter/line_points.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@

'use strict';

var BADNUM = require('../../constants/numerical').BADNUM;
var numConstants = require('../../constants/numerical');
var BADNUM = numConstants.BADNUM;
var LOG_CLIP = numConstants.LOG_CLIP;
var LOG_CLIP_PLUS = LOG_CLIP + 0.5;
var LOG_CLIP_MINUS = LOG_CLIP - 0.5;
var Lib = require('../../lib');
var segmentsIntersect = Lib.segmentsIntersect;
var constrain = Lib.constrain;
Expand All @@ -19,6 +23,10 @@ var constants = require('./constants');
module.exports = function linePoints(d, opts) {
var xa = opts.xaxis;
var ya = opts.yaxis;
var xLog = xa.type === 'log';
var yLog = ya.type === 'log';
var xLen = xa._length;
var yLen = ya._length;
var connectGaps = opts.connectGaps;
var baseTolerance = opts.baseTolerance;
var shape = opts.shape;
Expand Down Expand Up @@ -59,7 +67,25 @@ module.exports = function linePoints(d, opts) {
if(!di) return false;
var x = xa.c2p(di.x);
var y = ya.c2p(di.y);
if(x === BADNUM || y === BADNUM) return false;

// if non-positive log values, set them VERY far off-screen
// so the line looks essentially straight from the previous point.
if(x === BADNUM) {
if(xLog) x = xa.c2p(di.x, true);
if(x === BADNUM) return false;
// If BOTH were bad log values, make the line follow a constant
// exponent rather than a constant slope
if(yLog && y === BADNUM) {
x *= Math.abs(xa._m * yLen * (xa._m > 0 ? LOG_CLIP_PLUS : LOG_CLIP_MINUS) /
(ya._m * xLen * (ya._m > 0 ? LOG_CLIP_PLUS : LOG_CLIP_MINUS)));
}
x *= 1000;
}
if(y === BADNUM) {
if(yLog) y = ya.c2p(di.y, true);
if(y === BADNUM) return false;
y *= 1000;
}
return [x, y];
}

Expand All @@ -79,16 +105,16 @@ module.exports = function linePoints(d, opts) {
var latestXFrac, latestYFrac;
// if we're off-screen, increase tolerance over baseTolerance
function getTolerance(pt, nextPt) {
var xFrac = pt[0] / xa._length;
var yFrac = pt[1] / ya._length;
var xFrac = pt[0] / xLen;
var yFrac = pt[1] / yLen;
var offScreenFraction = Math.max(0, -xFrac, xFrac - 1, -yFrac, yFrac - 1);
if(offScreenFraction && (latestXFrac !== undefined) &&
crossesViewport(xFrac, yFrac, latestXFrac, latestYFrac)
) {
offScreenFraction = 0;
}
if(offScreenFraction && nextPt &&
crossesViewport(xFrac, yFrac, nextPt[0] / xa._length, nextPt[1] / ya._length)
crossesViewport(xFrac, yFrac, nextPt[0] / xLen, nextPt[1] / yLen)
) {
offScreenFraction = 0;
}
Expand All @@ -114,10 +140,10 @@ module.exports = function linePoints(d, opts) {
// if both are outside there will be 0 or 2 intersections
// (or 1 if it's right at a corner - we'll treat that like 0)
// returns an array of intersection pts
var xEdge0 = -xa._length * maxScreensAway;
var xEdge1 = xa._length * (1 + maxScreensAway);
var yEdge0 = -ya._length * maxScreensAway;
var yEdge1 = ya._length * (1 + maxScreensAway);
var xEdge0 = -xLen * maxScreensAway;
var xEdge1 = xLen * (1 + maxScreensAway);
var yEdge0 = -yLen * maxScreensAway;
var yEdge1 = yLen * (1 + maxScreensAway);
var edges = [
[xEdge0, yEdge0, xEdge1, yEdge0],
[xEdge1, yEdge0, xEdge1, yEdge1],
Expand Down Expand Up @@ -261,8 +287,8 @@ module.exports = function linePoints(d, opts) {
}

function addPt(pt) {
latestXFrac = pt[0] / xa._length;
latestYFrac = pt[1] / ya._length;
latestXFrac = pt[0] / xLen;
latestYFrac = pt[1] / yLen;
// Are we more than maxScreensAway off-screen any direction?
// if so, clip to this box, but in such a way that on-screen
// drawing is unchanged
Expand Down
Binary file added test/image/baselines/log_lines_fills.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions test/image/mocks/log_lines_fills.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"data": [{
"x": [-1, 1.5, 2, 0, 1, 3, 4, 5, 6, 1, -1, -1, 3, 3, 0, 7, 7, -1, -1],
"y": [-1, 1.5, 1, -1, -1, 1, 1, 0, 2, 2, 0, 2, 3, 4, 5, 6, -2, -2, -1],
"mode": "markers+lines", "fill": "toself"
}, {
"x": [-1, 1.5, 2, 0, 1, 3, 4, 5, 6, 1, -1, -1, 3, 3, 0, 7, 7, -1, -1],
"y": [-1, 1.5, 1, -1, -1, 1, 1, 0, 2, 2, 0, 2, 3, 4, 5, 6, -2, -2, -1],
"mode": "markers+lines", "fill": "toself", "xaxis": "x2"
}, {
"x": [-1, 1.5, 2, 0, 1, 3, 4, 5, 6, 1, -1, -1, 3, 3, 0, 7, 7, -1, -1],
"y": [-1, 1.5, 1, -1, -1, 1, 1, 0, 2, 2, 0, 2, 3, 4, 5, 6, -2, -2, -1],
"mode": "markers+lines", "fill": "toself", "yaxis": "y2"
}, {
"x": [-1, 1.5, 2, 0, 1, 3, 4, 5, 6, 1, -1, -1, 3, 3, 0, 7, 7, -1, -1],
"y": [-1, 1.5, 1, -1, -1, 1, 1, 0, 2, 2, 0, 2, 3, 4, 5, 6, -2, -2, -1],
"mode": "markers+lines", "fill": "toself", "xaxis": "x2", "yaxis": "y2"
}, {
"x": [0.01, 0.1], "y": [0.01, 0.1],
"mode": "markers", "xaxis": "x2", "yaxis": "y2"
}],
"layout": {
"width": 800,
"height": 600,
"xaxis": {"title": "linear"},
"xaxis2": {"title": "log", "type": "log"},
"yaxis": {"title": "linear"},
"yaxis2": {"title": "log", "type": "log"},
"grid": {"columns": 2, "rows": 2},
"showlegend": false,
"title": "Lines to invalid log values"
}
}

0 comments on commit 68b489d

Please sign in to comment.