Skip to content

Commit a788ccc

Browse files
committed
Add test for full-domain
1 parent 195dfa5 commit a788ccc

File tree

1 file changed

+158
-11
lines changed

1 file changed

+158
-11
lines changed

test/jasmine/tests/pikul_test.js

Lines changed: 158 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var createGraphDiv = require('../assets/create_graph_div');
55
var destroyGraphDiv = require('../assets/destroy_graph_div');
66

77
// Boilerplate taken from axes_test.js
8-
describe('When generating axes w/ `tickmode`:"domain array",', function() {
8+
describe('Generating ticks with `tickmode`,', function() {
99
var gd;
1010

1111
beforeEach(function() {
@@ -18,20 +18,25 @@ describe('When generating axes w/ `tickmode`:"domain array",', function() {
1818
// Passed as tickLen argument to specify a major or minor tick config
1919
const MAJOR = 10;
2020
const MINOR = 5;
21-
function generateTickConfig(tickLen){
21+
function generateTickConfig(tickLen, tickmode, nticks){
22+
if (tickmode === undefined) tickmode = 'domain array';
2223
// Intentionally configure to produce a single `(x|y)tick` class per tick
2324
// labels and tick marks each produce one, so one or the other
24-
standardConfig = {tickmode: 'domain array', ticklen: tickLen, showticklabels: false};
25+
standardConfig = {tickmode: tickmode, ticklen: tickLen, showticklabels: false};
2526

2627
// Tick values will be random:
27-
var n = Math.floor(Math.random() * 100);
28-
tickVals = [];
28+
if (tickmode === 'domain array') {
29+
var n = Math.floor(Math.random() * 100);
30+
tickVals = [];
2931

30-
for(let i = 0; i <= n; i++){
31-
intermediate = (Math.trunc(Math.random()*150) - 25) / 100; // Number between -.25 and 1.25 w/ 2 decimals max
32-
tickVals.push(Math.min(Math.max(intermediate, 0), 1)); // 2 decimal number between 0 and 1 w/ higher odds of 0 or 1
32+
for(let i = 0; i <= n; i++){
33+
intermediate = (Math.trunc(Math.random()*150) - 25) / 100; // Number between -.25 and 1.25 w/ 2 decimals max
34+
tickVals.push(Math.min(Math.max(intermediate, 0), 1)); // 2 decimal number between 0 and 1 w/ higher odds of 0 or 1
35+
}
36+
standardConfig['tickvals'] = tickVals;
37+
} else if (tickmode === 'full domain') {
38+
standardConfig['nticks'] = nticks;
3339
}
34-
standardConfig['tickvals'] = tickVals;
3540
return standardConfig;
3641
}
3742

@@ -63,9 +68,9 @@ describe('When generating axes w/ `tickmode`:"domain array",', function() {
6368
{ type:'date'},
6469
{ type:'category'},
6570
];
66-
for (let graphTypeIndex = 0; graphTypeIndex < graphTypes.length; graphTypeIndex++) {
71+
for(let graphTypeIndex = 0; graphTypeIndex < graphTypes.length; graphTypeIndex++) {
6772
(function(tickConfig, xGraphType) { // wrap in func or else it() can't see variable because of javascript closure scope
68-
it('fraction mapping to geometries for config ' + binaryToTickType(tickConfig) , function(done) {
73+
it('"domain array" and config ' + binaryToTickType(tickConfig) , function(done) {
6974
var xMajor = tickConfig & XMAJOR; // does this config include xmajor?
7075
var xMinor = tickConfig & XMINOR; // does this config include xminor?
7176
var yMajor = tickConfig & YMAJOR; // ... etc
@@ -188,6 +193,148 @@ describe('When generating axes w/ `tickmode`:"domain array",', function() {
188193
}
189194
}).then(done, done.fail);
190195
});
196+
for(let nticks_param = 0; nticks_param < 5; nticks_param++) {
197+
(function(nticks_param) {
198+
it('"full domain" and config ' + binaryToTickType(tickConfig) , function(done) {
199+
var xMajor = tickConfig & XMAJOR; // does this config include xmajor?
200+
var xMinor = tickConfig & XMINOR; // does this config include xminor?
201+
var yMajor = tickConfig & YMAJOR; // ... etc
202+
var yMinor = tickConfig & YMINOR;
203+
ticksOff = {ticklen: 0, showticklabels: false};
204+
var xMajorConfig = xMajor ? generateTickConfig(MAJOR, 'full domain', nticks_param) : ticksOff; // generate configs
205+
var xMinorConfig = xMinor ? generateTickConfig(MINOR, 'full domain', nticks_param) : ticksOff;
206+
var yMajorConfig = yMajor ? generateTickConfig(MAJOR, 'full domain', nticks_param) : ticksOff;
207+
var yMinorConfig = yMinor ? generateTickConfig(MINOR, 'full domain', nticks_param) : ticksOff;
208+
var configInfo = "" // for debugging
209+
configInfo += xMajor ? "\n " + `xMajor nticks: ${xMajorConfig['nticks']}` : "";
210+
configInfo += xMinor ? "\n " + `xMinor nticks: ${xMinorConfig['nticks']}` : "";
211+
configInfo += yMajor ? "\n " + `yMajor nticks: ${yMajorConfig['nticks']}` : "";
212+
configInfo += yMinor ? "\n " + `yMinor nticks: ${yMinorConfig['nticks']}` : "";
213+
214+
// stolen from axes_test.js
215+
Plotly.newPlot(gd, {
216+
data: [{
217+
x: [0, 1],
218+
y: [0, 1]
219+
}],
220+
layout: {
221+
width: 400,
222+
height: 400,
223+
margin: { t: 40, b: 40, l: 40, r: 40, },
224+
...xGraphType,
225+
xaxis: {
226+
autorange: true,
227+
...xMajorConfig, // explode config into this key
228+
minor: xMinorConfig, // set config to this key
229+
},
230+
yaxis: { // same as above
231+
autorange: true,
232+
...yMajorConfig,
233+
minor: yMinorConfig,
234+
},
235+
}}).then(function() {
236+
// This regex is for extracting geometric position of a tick
237+
// regex: `.source` converts to string, laid out this way to make for easier reading
238+
const funcName = "translate" + /\(/.source; // literally simplest way to regex '('
239+
const integerPart = /\d+/.source; // numbers left of decimal
240+
const fractionalPart = /(?:\.\d+)?/.source; // decimal + numbers to right
241+
const floatNum = integerPart + fractionalPart; // all together
242+
const any = /.+/.source;
243+
const close = /\)/.source;
244+
const reX = new RegExp(funcName + '(' + floatNum + '),' + any + close); // parens () are capture not fn()
245+
const reY = new RegExp(funcName + any + ',(' + floatNum + ')' + close);
246+
247+
for(let runNumber = 0b1; runNumber <= 0b1000; runNumber <<= 0b1) { // Check all ticks on all axes ☺
248+
var runInfo = "\n Checking: " + binaryToTickType(runNumber);
249+
var elementName = "";
250+
var targetConfig;
251+
var re;
252+
if(runNumber & xMajor) { // ie. (this run wants xMajor) & (xMajor was set in config above)
253+
elementName = "xtick";
254+
targetConfig = xMajorConfig;
255+
re = reX;
256+
} else if(runNumber & xMinor) {
257+
elementName = "xtick";
258+
targetConfig = xMinorConfig;
259+
re = reX;
260+
} else if(runNumber & yMajor) {
261+
elementName = "ytick";
262+
targetConfig = yMajorConfig;
263+
re = reY;
264+
} else if(runNumber & yMinor) {
265+
elementName = "ytick";
266+
targetConfig = yMinorConfig;
267+
re = reY;
268+
} else continue; // This run would have been to check ticks that don't exist
269+
270+
var tickElements = document.getElementsByClassName(elementName);
271+
var nt = targetConfig['nticks'];
272+
var expectedTickLen = String(targetConfig['ticklen'])
273+
var tickValsUnique = new Array();
274+
if (nt == 0) {
275+
// pass
276+
} else if (nt == 1) {
277+
tickValsUnique = [0];
278+
} else if (nt == 2) {
279+
tickValsUnique = [0, 1];
280+
} else {
281+
var increment = 1/(nt-1); // (nt-2) + 1
282+
tickValsUnique.push(0);
283+
for (let i = 0; i < nt-2; i++) {
284+
tickValsUnique.push((i+1)*increment);
285+
}
286+
tickValsUnique.push(1);
287+
}
288+
// Filter out major/minor and grab geometry
289+
transformVals = []; // "transform" ie the positional property
290+
for(let i = 0; i < tickElements.length; i++) {
291+
if(!tickElements[i].getAttribute("d").endsWith(expectedTickLen)) continue;
292+
var translate = tickElements[i].getAttribute("transform");
293+
var match = translate.match(re);
294+
if (match === null) continue;
295+
transformVals.push(Number(match[1]));
296+
}
297+
298+
var debugInfo = "\n " + `tickElements: (${tickElements.length}) ${tickElements}` + "\n " +
299+
`nticks: ${tickValsUnique.length}`;
300+
301+
expect(transformVals.length).toBe(tickValsUnique.length,
302+
"filtered tick elements vs tickvals failed" + runInfo + configInfo + debugInfo);
303+
304+
if(transformVals.length < 2) return; // Can't test proportions with < 2 ticks (since no fixed reference)
305+
306+
307+
// To test geometries without using fixed point or data values...
308+
// we can check consistency of y = mx+b! (y is DOM position, x is proportion)
309+
// If x = 0 then y = b, but we may not have a 0 valued x
310+
// m = (y1 - y2) / (x1 - x2)
311+
// b = y1 - mx1
312+
y = transformVals;
313+
x = tickValsUnique;
314+
var m, b;
315+
var b_index = x.indexOf(0);
316+
317+
m = (y[0] - y[1]) / (x[0] - x[1]);
318+
b = (b_index != -1) ? b = y[b_index] : y[0] - m*x[0];
319+
320+
calculatedY = [];
321+
for(let i = 0; i < x.length; i++) calculatedY.push(m*x[i] + b);
322+
323+
/* **** Close this comment line to manually inspect output -->
324+
yout = [];
325+
ycalcout = [];
326+
for (i = 0; i < Math.min(x.length, 10); i++) {
327+
yout.push(Number.parseFloat(y[i]).toFixed(2));
328+
ycalcout.push(Number.parseFloat(calculatedY[i]).toFixed(2));
329+
}
330+
console.log(yout);
331+
console.log(ycalcout);/* */
332+
expect(y).toBeCloseToArray(calculatedY, 1, `y=mx+b test failed comparing\n${y}\n${calculatedY}`);
333+
}
334+
}).then(done, done.fail);
335+
});
336+
})(nticks_param);
337+
}
191338
})(tickConfig, graphTypes[graphTypeIndex]);
192339
}
193340
}

0 commit comments

Comments
 (0)