Skip to content

remove cached trace._interpz from heatmaps/contour maps with gaps #2657

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

Merged
merged 1 commit into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/traces/contourcarpet/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function heatmappishCalc(gd, trace) {
z = trace._z = clean2dArray(trace._z || trace.z, trace.transpose);

trace._emptypoints = findEmpties(z);
trace._interpz = interp2d(z, trace._emptypoints, trace._interpz);
interp2d(z, trace._emptypoints);

// create arrays of brick boundaries, to be used by autorange and heatmap.plot
var xlen = maxRowLength(z),
Expand Down
2 changes: 1 addition & 1 deletion src/traces/heatmap/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ module.exports = function calc(gd, trace) {

if(isContour || trace.connectgaps) {
trace._emptypoints = findEmpties(z);
trace._interpz = interp2d(z, trace._emptypoints, trace._interpz);
interp2d(z, trace._emptypoints);
}
}

Expand Down
45 changes: 24 additions & 21 deletions src/traces/heatmap/interp2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,37 @@

var Lib = require('../../lib');

var INTERPTHRESHOLD = 1e-2,
NEIGHBORSHIFTS = [[-1, 0], [1, 0], [0, -1], [0, 1]];
var INTERPTHRESHOLD = 1e-2;
var NEIGHBORSHIFTS = [[-1, 0], [1, 0], [0, -1], [0, 1]];

function correctionOvershoot(maxFractionalChange) {
// start with less overshoot, until we know it's converging,
// then ramp up the overshoot for faster convergence
return 0.5 - 0.25 * Math.min(1, maxFractionalChange * 0.5);
}

module.exports = function interp2d(z, emptyPoints, savedInterpZ) {
// fill in any missing data in 2D array z using an iterative
// poisson equation solver with zero-derivative BC at edges
// amazingly, this just amounts to repeatedly averaging all the existing
// nearest neighbors (at least if we don't take x/y scaling into account)
var maxFractionalChange = 1,
i,
thisPt;

if(Array.isArray(savedInterpZ)) {
for(i = 0; i < emptyPoints.length; i++) {
thisPt = emptyPoints[i];
z[thisPt[0]][thisPt[1]] = savedInterpZ[thisPt[0]][thisPt[1]];
}
}
else {
// one pass to fill in a starting value for all the empties
iterateInterp2d(z, emptyPoints);
}
/*
* interp2d: Fill in missing data from a 2D array using an iterative
* poisson equation solver with zero-derivative BC at edges.
* Amazingly, this just amounts to repeatedly averaging all the existing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazingly

* nearest neighbors, at least if we don't take x/y scaling into account,
* which is the right approach here where x and y may not even have the
* same units.
*
* @param {array of arrays} z
* The 2D array to fill in. Will be mutated here. Assumed to already be
* cleaned, so all entries are numbers except gaps, which are `undefined`.
* @param {array of arrays} emptyPoints
* Each entry [i, j, neighborCount] for empty points z[i][j] and the number
* of neighbors that are *not* missing. Assumed to be sorted from most to
* least neighbors, as produced by heatmap/find_empties.
*/
module.exports = function interp2d(z, emptyPoints) {
var maxFractionalChange = 1;
var i;

// one pass to fill in a starting value for all the empties
iterateInterp2d(z, emptyPoints);

// we're don't need to iterate lone empties - remove them
for(i = 0; i < emptyPoints.length; i++) {
Expand Down
42 changes: 42 additions & 0 deletions test/jasmine/tests/contour_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,4 +458,46 @@ describe('contour plotting and editing', function() {
.catch(fail)
.then(done);
});

it('can change z values with gaps', function(done) {
Plotly.newPlot(gd, [{
type: 'contour',
z: [[1, 2], [null, 4], [1, 2]]
}])
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[1, 2], [2, 4], [1, 2]]);
expect(gd.calcdata[0][0].zmask).toEqual([[1, 1], [0, 1], [1, 1]]);

return Plotly.react(gd, [{
type: 'contour',
z: [[6, 5], [8, 7], [null, 10]]
}]);
})
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[6, 5], [8, 7], [9, 10]]);
expect(gd.calcdata[0][0].zmask).toEqual([[1, 1], [1, 1], [0, 1]]);

return Plotly.react(gd, [{
type: 'contour',
z: [[1, 2], [null, 4], [1, 2]]
}]);
})
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[1, 2], [2, 4], [1, 2]]);
expect(gd.calcdata[0][0].zmask).toEqual([[1, 1], [0, 1], [1, 1]]);

return Plotly.react(gd, [{
type: 'contour',
// notice that this one is the same as the previous, except that
// a previously present value was removed...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this comment 📚

z: [[1, 2], [null, 4], [1, null]]
}]);
})
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[1, 2], [2, 4], [1, 2.5]]);
expect(gd.calcdata[0][0].zmask).toEqual([[1, 1], [0, 1], [1, 0]]);
})
.catch(fail)
.then(done);
});
});
29 changes: 29 additions & 0 deletions test/jasmine/tests/heatmap_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,35 @@ describe('heatmap plot', function() {
.catch(failTest)
.then(done);
});

it('can change z values with connected gaps', function(done) {
var gd = createGraphDiv();
Plotly.newPlot(gd, [{
type: 'heatmap', connectgaps: true,
z: [[1, 2], [null, 4], [1, 2]]
}])
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[1, 2], [2, 4], [1, 2]]);

return Plotly.react(gd, [{
type: 'heatmap', connectgaps: true,
z: [[6, 5], [8, 7], [null, 10]]
}]);
})
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[6, 5], [8, 7], [9, 10]]);

return Plotly.react(gd, [{
type: 'heatmap', connectgaps: true,
z: [[1, 2], [null, 4], [1, 2]]
}]);
})
.then(function() {
expect(gd.calcdata[0][0].z).toEqual([[1, 2], [2, 4], [1, 2]]);
})
.catch(fail)
.then(done);
});
});

describe('heatmap hover', function() {
Expand Down