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

Hide feature metadata barplot controls if no feature metadata is available; add first barplot panel tests; abstract Empress initialization code for JS testing #320

Merged
merged 6 commits into from
Aug 13, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
105 changes: 61 additions & 44 deletions empress/support_files/js/barplot-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function (
this.layerContainer = layerContainer;
this.num = num;

this.fmAvailable = this.fmCols.length > 0;

// This should be "fm" if the barplot is for feature metadata; "sm" if
// the barplot is for sample metadata
this.barplotType = "fm";
// the barplot is for sample metadata. (The default is to use feature
// metadata barplots, but if no feature metadata was passed to Empress
// then we have no choice but to just draw sample metadata barplots for
// everything.)
this.barplotType = this.fmAvailable ? "fm" : "sm";

// Various properties of the barplot layer state for feature metadata
this.initialDefaultColorHex = Colorer.getQIIMEColor(this.num - 1);
Expand Down Expand Up @@ -81,47 +86,55 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function (
this.updateHeader();

// Add UI elements for switching between feature and sample metadata
// barplots for this layer
var metadataChoiceP = this.layerDiv.appendChild(
document.createElement("p")
);
var fmBtn = metadataChoiceP.appendChild(
document.createElement("button")
);
var smBtn = metadataChoiceP.appendChild(
document.createElement("button")
);
fmBtn.innerText = "Feature Metadata";
smBtn.innerText = "Sample Metadata";
// Center the feature and sample metadata buttons
fmBtn.setAttribute("style", "margin: 0 auto;");
smBtn.setAttribute("style", "margin: 0 auto;");
// Since we default to feature metadata barplot layers, we mark the
// feature metadata button as "selected" (a.k.a. we darken it a bit)
fmBtn.classList.add("selected-metadata-choice");

this.initFMDiv();
this.initSMDiv();

fmBtn.onclick = function () {
if (scope.barplotType !== "fm") {
scope.smDiv.classList.add("hidden");
scope.fmDiv.classList.remove("hidden");
fmBtn.classList.add("selected-metadata-choice");
smBtn.classList.remove("selected-metadata-choice");
scope.barplotType = "fm";
}
};
smBtn.onclick = function () {
if (scope.barplotType !== "sm") {
scope.fmDiv.classList.add("hidden");
scope.smDiv.classList.remove("hidden");
smBtn.classList.add("selected-metadata-choice");
fmBtn.classList.remove("selected-metadata-choice");
scope.barplotType = "sm";
}
};
// barplots for this layer (only if feature metadata is available;
// otherwise, things will just default to sample metadata barplots.)
if (this.fmAvailable) {
var metadataChoiceP = this.layerDiv.appendChild(
document.createElement("p")
);
var fmBtn = metadataChoiceP.appendChild(
document.createElement("button")
);
var smBtn = metadataChoiceP.appendChild(
document.createElement("button")
);
fmBtn.innerText = "Feature Metadata";
smBtn.innerText = "Sample Metadata";
// Center the feature and sample metadata buttons
fmBtn.setAttribute("style", "margin: 0 auto;");
smBtn.setAttribute("style", "margin: 0 auto;");
// Since we default to feature metadata barplot layers, we mark the
// feature metadata button as "selected" (a.k.a. we darken it a bit)
fmBtn.classList.add("selected-metadata-choice");

// We delay calling initFMDiv() (and initSMDiv(), although that
// isn't in this block because it doesn't depend on feature
// metadata being available) until after we create the
// "type switching" choice buttons above. This is so that the
// buttons are placed above the FM / SM divs in the page layout.
this.initFMDiv();

fmBtn.onclick = function () {
if (scope.barplotType !== "fm") {
scope.smDiv.classList.add("hidden");
scope.fmDiv.classList.remove("hidden");
fmBtn.classList.add("selected-metadata-choice");
smBtn.classList.remove("selected-metadata-choice");
scope.barplotType = "fm";
}
};
smBtn.onclick = function () {
if (scope.barplotType !== "sm") {
scope.fmDiv.classList.add("hidden");
scope.smDiv.classList.remove("hidden");
smBtn.classList.add("selected-metadata-choice");
fmBtn.classList.remove("selected-metadata-choice");
scope.barplotType = "sm";
}
};
}

this.initSMDiv();
// Add a row of UI elements that supports removing this layer
var rmP = this.layerDiv.appendChild(document.createElement("p"));
var rmLbl = rmP.appendChild(document.createElement("label"));
Expand All @@ -144,6 +157,9 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function (
BarplotLayer.prototype.initFMDiv = function () {
var scope = this;
this.fmDiv = this.layerDiv.appendChild(document.createElement("div"));
if (this.barplotType !== "fm") {
this.fmDiv.classList.add("hidden");
}

// Add default color stuff
var dfltColorP = document.createElement("p");
Expand Down Expand Up @@ -416,8 +432,9 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function (
BarplotLayer.prototype.initSMDiv = function () {
var scope = this;
this.smDiv = this.layerDiv.appendChild(document.createElement("div"));
// Hide this div by default
this.smDiv.classList.add("hidden");
if (this.barplotType !== "sm") {
this.smDiv.classList.add("hidden");
}

var chgFieldP = this.smDiv.appendChild(document.createElement("p"));
// Add a label
Expand Down
14 changes: 11 additions & 3 deletions tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
'CanvasEvents' : './support_files/js/canvas-events',
'SelectedNodeMenu' : './support_files/js/select-node-menu',

/* test utility code */
'UtilitiesForTesting' : './../tests/utilities-for-testing',

/* test paths */
'testBPTree' : './../tests/test-bp-tree',
'testByteTree' : './../tests/test-byte-array',
Expand All @@ -103,7 +106,8 @@
'testVectorOps' : './../tests/test-vector-ops',
'testEmpress' : './../tests/test-empress',
'testExport': './../tests/test-export',
'testAnimationHandler': './../tests/test-animation-panel-handler'
'testAnimationHandler': './../tests/test-animation-panel-handler',
'testBarplotPanelHandler': './../tests/test-barplot-panel-handler'
}
});

Expand All @@ -125,6 +129,7 @@
'util',
'Empress',
'Legend',
'UtilitiesForTesting',
'testBPTree',
'testByteTree',
'testBIOMTable',
Expand All @@ -134,8 +139,9 @@
'testCircularLayoutComputation',
'testVectorOps',
'testEmpress',
'testExport',
'testAnimationHandler',
'testExport'
'testBarplotPanelHandler',
],

// start tests
Expand All @@ -157,6 +163,7 @@
util,
Empress,
Legend,
UtilitiesForTesting,
testBPTree,
testByteTree,
testCamera,
Expand All @@ -165,8 +172,9 @@
testCircularLayoutComputation,
testVectorOps,
testEmpress,
testExport,
testAnimationHandler,
testExport
testBarplotPanelHandler
) {
$(document).ready(function() {
QUnit.start();
Expand Down
123 changes: 123 additions & 0 deletions tests/test-barplot-panel-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
require(["jquery", "Empress", "UtilitiesForTesting"], function (
$,
Empress,
UtilitiesForTesting
) {
module("Barplot Panel Handler", {
setup: function () {
this.testData = UtilitiesForTesting.getTestData();
},
});

test("Layout availability toggling: initialization", function () {
// The default layout should influence whether the barplot panel's
// "available" or "unavailable" content is shown. First, let's try the
// unrooted layout, which doesn't support barplots.
var empress = new Empress(
this.testData.tree,
this.testData.treeData,
this.testData.tdToInd,
this.testData.nameToKeys,
this.testData.layoutToCoordSuffix,
"Unrooted",
this.testData.yrscf,
this.testData.biom,
this.testData.fmCols,
this.testData.tm,
this.testData.im,
this.testData.canvas
);
ok(empress._barplotPanel.availContent.classList.contains("hidden"));
notOk(
empress._barplotPanel.unavailContent.classList.contains("hidden")
);

// And now let's try starting out in the rectangular layout, which
// *does* support barplots.
var empress2 = new Empress(
this.testData.tree,
this.testData.treeData,
this.testData.tdToInd,
this.testData.nameToKeys,
this.testData.layoutToCoordSuffix,
"Rectangular",
this.testData.yrscf,
this.testData.biom,
this.testData.fmCols,
this.testData.tm,
this.testData.im,
this.testData.canvas
);
notOk(empress2._barplotPanel.availContent.classList.contains("hidden"));
ok(empress2._barplotPanel.unavailContent.classList.contains("hidden"));
});
// test("Layout availability toggling post-initialization", function () {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The error is caused by line 453 in drawer because treeSpaceCenterX and treeSpaceCenterY are defined by taking the offsetWidth/offsetHeight of treeContainer which is an html component that is not defined in the test. So, when glMatrix tries to multiply on line 465, it cant because centerMat has undefined entries. You should be able to fix this by adding an div with the id 'tree-container' to utilities-for-testing

Copy link
Collaborator Author

@fedarko fedarko Aug 11, 2020

Choose a reason for hiding this comment

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

I don't believe this is the problem -- a div with the ID tree-container is already defined in tests/index.html, and it has offset width / height properties (document.getElementById("tree-container").offsetWidth; produces a number when run in the console of tests/index.html).

Did some digging and I think I've managed to solve the problem (this test works now, at least). the problem was that empress.initialize() (which calls drawer.initialize()) wasn't being called anywhere (in the non-test Empress code it's only called in the empress-template.html file). Took care of this by calling the function within the test, but then more errors came up -- but they boiled down to other HTML elements on the page not existing, like you said. I added for the missing elements and now this test works??? (edit: I realize now that the test-empress.js file already initialized just the drawer, so these changes may have been overkill... ah well things work at least :)

The testing HTML is getting kind of bloated so we may want to try to auto-populate it in the future... but for now the tests work at least :P

(As a nice side note, I think this should make testing select-node-menu / canvasEvents / drawer more feasible down the line)

// var empress = new Empress(
// this.testData.tree,
// this.testData.treeData,
// this.testData.tdToInd,
// this.testData.nameToKeys,
// this.testData.layoutToCoordSuffix,
// "Unrooted",
// this.testData.yrscf,
// this.testData.biom,
// this.testData.fmCols,
// this.testData.tm,
// this.testData.im,
// this.testData.canvas
// );

// // After updating the layout to something that supports barplots, the
// // barplot "available content" should now be shown.
// //
// // NOTE: This fails in testing -- I get the following error:
// // TypeError: Cannot set property '0' of undefined
// // at Object.u (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/vendor/gl-matrix.min.js:28:30362)
// // at Drawer.centerCameraOn (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/drawer.js:466:17)
// // at Empress.centerLayoutAvgPoint (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/empress.js:1929:22)
// // at Empress.updateLayout (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/empress.js:1816:22)
// // at Object.<anonymous> (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/tests/test-barplot-panel-handler.js:68:17)
// empress.updateLayout("Rectangular");
// notOk(empress._barplotPanel.availContent.classList.contains("hidden"));
// ok(empress._barplotPanel.unavailContent.classList.contains("hidden"));

// // ... And going back to a not-compatible-with-barplots layout should
// // switch back to the unavailable content.
// empress.updateLayout("Unrooted");
// ok(empress._barplotPanel.availContent.classList.contains("hidden"));
// notOk(empress._barplotPanel.unavailContent.classList.contains("hidden"));
// });
test("Barplot layers default to feature metadata layers, but only if feature metadata is available", function () {
var empressWithFM = new Empress(
this.testData.tree,
this.testData.treeData,
this.testData.tdToInd,
this.testData.nameToKeys,
this.testData.layoutToCoordSuffix,
"Unrooted",
this.testData.yrscf,
this.testData.biom,
this.testData.fmCols,
this.testData.tm,
this.testData.im,
this.testData.canvas
);
equal(empressWithFM._barplotPanel.layers[0].barplotType, "fm");

var empressWithNoFM = new Empress(
this.testData.tree,
this.testData.treeData,
this.testData.tdToInd,
this.testData.nameToKeys,
this.testData.layoutToCoordSuffix,
"Unrooted",
this.testData.yrscf,
this.testData.biom,
[],
{},
{},
this.testData.canvas
);
equal(empressWithNoFM._barplotPanel.layers[0].barplotType, "sm");
});
});
Loading