0;
+ // Create a dict of feature names to the total absolute saliency of all
+ // its feature values, to sort features with the most salienct features at
+ // the top.
+ const saliencyTotals = checkSal ?
+ Object.assign({}, ...Object.keys(saliency).map(
+ name => ({[name]: typeof saliency[name] == 'number' ?
+ Math.abs(saliency[name] as number) :
+ (saliency[name] as Array).reduce((total, cur) =>
+ Math.abs(total) + Math.abs(cur) , 0)}))) :
+ {};
+
if (searchValue != '') {
const re = new RegExp(searchValue, 'i');
filtered = featureList.filter(feature => re.test(feature.name));
@@ -288,6 +299,18 @@ Polymer({
} else if (this.isImage(b.name) && !this.isImage(a.name)) {
return 1;
} else {
+ if (checkSal) {
+ if (a.name in saliency && !(b.name in saliency)) {
+ return -1;
+ } else if (b.name in saliency && !(a.name in saliency)) {
+ return 1;
+ } else {
+ const diff = saliencyTotals[b.name] - saliencyTotals[a.name];
+ if (diff != 0) {
+ return diff;
+ }
+ }
+ }
return a.name.localeCompare(b.name);
}
});
@@ -326,29 +349,32 @@ Polymer({
]);
},
+ selectAll: function(query: string) {
+ return d3.selectAll(
+ Polymer.dom(this.root).querySelectorAll(query) as any);
+ },
+
haveSaliency: function() {
- if (!this.featuresList || !this.saliency ||
+ if (!this.filteredFeaturesList || !this.saliency ||
Object.keys(this.saliency).length === 0 || !this.colors) {
return;
}
// TODO(jwexler): Find a way to do this without requestAnimationFrame.
- // If the paper-inputs for the features have yet to be rendered, wait to
- // perform this processing. There should be paper-inputs for all non-image
+ // If the inputs for the features have yet to be rendered, wait to
+ // perform this processing. There should be inputs for all non-image
// features.
- if (d3.selectAll('.value input').size() <
- (this.featuresList.length - Object.keys(this.imageInfo).length)) {
+ if (this.selectAll('input.value-pill').size() <
+ (this.filteredFeaturesList.length - Object.keys(this.imageInfo).length)) {
requestAnimationFrame(() => this.haveSaliency());
return;
}
- // Reset all text to black
- d3.selectAll('.value-pill')
- .style('background', 'lightgrey');
-
+ // Reset all backgrounds to the neutral color.
+ this.selectAll('.value-pill').style('background', neutralSaliencyColor);
// Color the text of each input element of each feature according to the
// provided saliency information.
- for (const feat of this.featuresList) {
+ for (const feat of this.filteredFeaturesList) {
const val = this.saliency[feat.name] as SaliencyValue;
// If there is no saliency information for the feature, do not color it.
if (!val) {
@@ -357,13 +383,28 @@ Polymer({
const colorFn = Array.isArray(val) ?
(d: {}, i: number) => this.getColorForSaliency(val[i]) :
() => this.getColorForSaliency(val);
-
- d3.selectAll(
- `.${this.sanitizeFeature(feat.name)}.value-pill`)
- .style('background', this.showSaliency ? colorFn : () => 'lightgrey');
+ this.selectAll(
+ `input.${this.sanitizeFeature(feat.name)}.value-pill`)
+ .style('background',
+ this.showSaliency ? colorFn : () => neutralSaliencyColor);
+
+ // Color the "more feature values" button with the most extreme saliency
+ // of any of the feature values hidden behind the button.
+ if (Array.isArray(val)) {
+ const valArray = val as Array;
+ const moreButton = this.selectAll(
+ `paper-button.${this.sanitizeFeature(feat.name)}.value-pill`);
+ let mostExtremeSal = 0;
+ for (let i = 1; i < valArray.length; i++) {
+ if (Math.abs(valArray[i]) > Math.abs(mostExtremeSal)) {
+ mostExtremeSal = valArray[i];
+ }
+ }
+ moreButton.style('background', this.showSaliency ?
+ () => this.getColorForSaliency(mostExtremeSal) :
+ () => neutralSaliencyColor);
+ }
}
- // TODO(jwexler): Determine how to set non-fixed widths to input boxes
- // inside of grid iron-list.
},
/**
@@ -382,7 +423,7 @@ Polymer({
// TODO(jwexler): Find a way to do this without requestAnimationFrame.
// If the paper-inputs for the features have yet to be rendered, wait to
// perform this processing.
- if (d3.selectAll('.value input').size() < this.seqFeaturesList.length) {
+ if (this.selectAll('.value input').size() < this.seqFeaturesList.length) {
requestAnimationFrame(() => this.seqSaliency());
return;
}
@@ -401,7 +442,7 @@ Polymer({
(d: {}, i: number) => this.getColorForSaliency(val[i]) :
() => this.getColorForSaliency(val);
- d3.selectAll(
+ this.selectAll(
`.${this.sanitizeFeature(feat.name)} input`)
.style('color', this.showSaliency ? colorFn : () => 'black');
}
@@ -954,6 +995,7 @@ Polymer({
this.ignoreChange = false;
setTimeout(() => {
this.example = temp;
+ this.haveSaliency();
}, 0);
},
@@ -1057,7 +1099,7 @@ Polymer({
const legendSvg = d3.select(this.$.saliencyLegend).append('g');
const gradient = legendSvg.append('defs')
.append('linearGradient')
- .attr('id', 'gradient')
+ .attr('id', 'vzexampleviewergradient')
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
@@ -1106,7 +1148,7 @@ Polymer({
.attr('y1', 0)
.attr('width', LEGEND_WIDTH_PX)
.attr('height', LEGEND_HEIGHT_PX)
- .style('fill', 'url(#gradient)');
+ .style('fill', 'url(#vzexampleviewergradient)');
const legendScale =
d3.scaleLinear().domain([this.minSal, this.maxSal]).range([