Skip to content

Handle streamtube coordinates in string format and handle different data orders in isosurface and volume #4431

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 11 commits into from
Dec 30, 2019
66 changes: 44 additions & 22 deletions src/traces/streamtube/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ module.exports = function calc(gd, trace) {
var slen = 0;
var startx, starty, startz;
if(trace.starts) {
startx = trace.starts.x || [];
starty = trace.starts.y || [];
startz = trace.starts.z || [];
startx = filter(trace.starts.x || []);
starty = filter(trace.starts.y || []);
startz = filter(trace.starts.z || []);
slen = Math.min(startx.length, starty.length, startz.length);
}
trace._startsX = startx || [];
trace._startsY = starty || [];
trace._startsZ = startz || [];

var normMax = 0;
var normMin = Infinity;
Expand Down Expand Up @@ -61,13 +64,18 @@ module.exports = function calc(gd, trace) {
var filledX;
var filledY;
var filledZ;
var firstX;
var firstY;
var firstZ;
var firstX, lastX;
var firstY, lastY;
var firstZ, lastZ;
if(len) {
firstX = x[0];
firstY = y[0];
firstZ = z[0];
firstX = +x[0];
firstY = +y[0];
firstZ = +z[0];
}
if(len > 1) {
lastX = +x[len - 1];
lastY = +y[len - 1];
lastZ = +z[len - 1];
}

for(i = 0; i < len; i++) {
Expand All @@ -80,15 +88,15 @@ module.exports = function calc(gd, trace) {
zMax = Math.max(zMax, z[i]);
zMin = Math.min(zMin, z[i]);

if(!filledX && x[i] !== firstX) {
if(!filledX && (+x[i]) !== firstX) {
filledX = true;
gridFill += 'x';
}
if(!filledY && y[i] !== firstY) {
if(!filledY && (+y[i]) !== firstY) {
filledY = true;
gridFill += 'y';
}
if(!filledZ && z[i] !== firstZ) {
if(!filledZ && (+z[i]) !== firstZ) {
filledZ = true;
gridFill += 'z';
}
Expand All @@ -98,13 +106,13 @@ module.exports = function calc(gd, trace) {
if(!filledY) gridFill += 'y';
if(!filledZ) gridFill += 'z';

var Xs = distinctVals(trace.x.slice(0, len));
var Ys = distinctVals(trace.y.slice(0, len));
var Zs = distinctVals(trace.z.slice(0, len));
var Xs = distinctVals(filter(trace.x, len));
var Ys = distinctVals(filter(trace.y, len));
var Zs = distinctVals(filter(trace.z, len));

gridFill = gridFill.replace('x', (x[0] > x[len - 1] ? '-' : '+') + 'x');
gridFill = gridFill.replace('y', (y[0] > y[len - 1] ? '-' : '+') + 'y');
gridFill = gridFill.replace('z', (z[0] > z[len - 1] ? '-' : '+') + 'z');
gridFill = gridFill.replace('x', (firstX > lastX ? '-' : '+') + 'x');
gridFill = gridFill.replace('y', (firstY > lastY ? '-' : '+') + 'y');
gridFill = gridFill.replace('z', (firstZ > lastZ ? '-' : '+') + 'z');

var empty = function() {
len = 0;
Expand All @@ -118,7 +126,7 @@ module.exports = function calc(gd, trace) {

var getArray = function(c) { return c === 'x' ? x : c === 'y' ? y : z; };
var getVals = function(c) { return c === 'x' ? Xs : c === 'y' ? Ys : Zs; };
var getDir = function(c) { return (c[len - 1] < c[0]) ? -1 : 1; };
var getDir = function(c) { return lessThan(c[len - 1], c[0]) ? -1 : 1; };

var arrK = getArray(gridFill[1]);
var arrJ = getArray(gridFill[3]);
Expand Down Expand Up @@ -146,9 +154,9 @@ module.exports = function calc(gd, trace) {
var q100 = getIndex(i + 1, j, k);

if(
!(arrK[q000] * dirK < arrK[q001] * dirK) ||
!(arrJ[q000] * dirJ < arrJ[q010] * dirJ) ||
!(arrI[q000] * dirI < arrI[q100] * dirI)
!lessThan(arrK[q000] * dirK, arrK[q001] * dirK) ||
!lessThan(arrJ[q000] * dirJ, arrJ[q010] * dirJ) ||
!lessThan(arrI[q000] * dirI, arrI[q100] * dirI)
) {
arbitrary = true;
}
Expand Down Expand Up @@ -194,3 +202,17 @@ module.exports = function calc(gd, trace) {
function distinctVals(col) {
return Lib.distinctVals(col).vals;
}

function filter(arr, len) {
if(len === undefined) len = arr.length;

var values = [];
for(var i = 0; i < len; i++) {
values[i] = +arr[i];
}
return values;
}

function lessThan(a, b) {
return +a < +b;
}
6 changes: 3 additions & 3 deletions src/traces/streamtube/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ function convert(scene, trace) {
var slen = trace._slen;
if(slen) {
tubeOpts.startingPositions = zip3(
toDataCoords(trace.starts.x.slice(0, slen), 'xaxis'),
toDataCoords(trace.starts.y.slice(0, slen), 'yaxis'),
toDataCoords(trace.starts.z.slice(0, slen), 'zaxis')
toDataCoords(trace._startsX, 'xaxis'),
toDataCoords(trace._startsY, 'yaxis'),
toDataCoords(trace._startsZ, 'zaxis')
);
} else {
// Default starting positions:
Expand Down
122 changes: 77 additions & 45 deletions test/jasmine/tests/streamtube_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,55 +246,87 @@ describe('Test streamtube interactions', function() {
.then(done);
});

it('@gl should work with negative grid steps', function(done) {
var x = [];
var y = [];
var z = [];
var u = [];
var v = [];
var w = [];

for(var i = 0; i < 3; i++) {
for(var j = 0; j < 4; j++) {
for(var k = 0; k < 5; k++) {
x.push(-i);
y.push(-j);
z.push(-k);
u.push(1);
v.push(1);
w.push(1);
[ // list of directions
'number',
'string'
].forEach(function(format) {
[ // list of directions
[-1, -1, -1],
[-1, -1, 1],
[-1, 1, -1],
[1, -1, -1],
[1, 1, -1],
[1, -1, 1],
[-1, 1, 1],
[1, 1, 1]
].forEach(function(dir) {
it('@gl should work with grid steps: ' + dir + ' and values in ' + format + ' format.', function(done) {
var x = [];
var y = [];
var z = [];
var u = [];
var v = [];
var w = [];

for(var i = 0; i < 3; i++) {
for(var j = 0; j < 4; j++) {
for(var k = 0; k < 5; k++) {
var newU = 1;
var newV = 1;
var newW = 1;
var newX = i * dir[0];
var newY = j * dir[1];
var newZ = k * dir[2];

if(format === 'string') {
newU = String(newU);
newV = String(newV);
newW = String(newW);
newX = String(newX);
newY = String(newY);
newZ = String(newZ);
}

u.push(newU);
v.push(newV);
w.push(newW);
x.push(newX);
y.push(newY);
z.push(newZ);
}
}
}
}
}

var fig = {
data: [{
type: 'streamtube',
x: x,
y: y,
z: z,
u: u,
v: v,
w: w
}]
};

function _assert(msg, exp) {
var scene = gd._fullLayout.scene._scene;
var objs = scene.glplot.objects;
expect(objs.length).toBe(1, 'one gl-vis object - ' + msg);
expect(exp.positionsLength).toBe(objs[0].positions.length, 'positions length - ' + msg);
expect(exp.cellsLength).toBe(objs[0].cells.length, 'cells length - ' + msg);
}
var fig = {
data: [{
type: 'streamtube',
x: x,
y: y,
z: z,
u: u,
v: v,
w: w
}]
};

function _assert(msg, exp) {
var scene = gd._fullLayout.scene._scene;
var objs = scene.glplot.objects;
expect(objs.length).toBe(1, 'one gl-vis object - ' + msg);
expect(exp.positionsLength).toBe(objs[0].positions.length, 'positions length - ' + msg);
expect(exp.cellsLength).toBe(objs[0].cells.length, 'cells length - ' + msg);
}

Plotly.plot(gd, fig).then(function() {
_assert('with negative steps', {
positionsLength: 6336,
cellsLength: 2112
Plotly.plot(gd, fig).then(function() {
_assert('lengths', {
positionsLength: 6336,
cellsLength: 2112
});
})
.catch(failTest)
.then(done);
});
})
.catch(failTest)
.then(done);
});
});

it('@gl should return blank mesh grid if encountered arbitrary coordinates', function(done) {
Expand Down