Skip to content

Commit b6d458b

Browse files
andrewkfiedlerrzwiefel
authored andcommitted
DDF-2644 Update histogram to handle issues with Plotly
- plotly/plotly.js#1229 - plotly/plotly.js#1231 - Also ensures that strings are treated as strings (by adding a zero width space).
1 parent e0165d0 commit b6d458b

File tree

1 file changed

+137
-60
lines changed
  • catalog/ui/catalog-ui-search/src/main/webapp/component/visualization/histogram

1 file changed

+137
-60
lines changed

catalog/ui/catalog-ui-search/src/main/webapp/component/visualization/histogram/histogram.view.js

+137-60
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ define([
2828
'properties'
2929
], function (wreqr, $, _, Marionette, CustomElements, template, Plotly, Property, PropertyView, metacardDefinitions, Common, properties) {
3030

31+
var zeroWidthSpace = "\u200B";
32+
3133
function calculateAvailableAttributes(results){
3234
var availableAttributes = [];
3335
results.forEach(function(result){
@@ -91,13 +93,12 @@ define([
9193
switch(metacardDefinitions.metacardTypes[attribute].type){
9294
case 'DATE':
9395
return values.indexOf(Common.getHumanReadableDate(value)) >= 0;
94-
break;
96+
case 'BOOLEAN':
97+
case 'STRING':
98+
return values.indexOf(value.toString() + zeroWidthSpace) >= 0;
9599
default:
96-
return values.indexOf(value.toString()) >= 0;
97-
break;
100+
return value >= values[0] && value <= values[1];
98101
}
99-
} else {
100-
return values.indexOf("") >= 0;
101102
}
102103
}
103104

@@ -107,41 +108,67 @@ define([
107108
case 'DATE':
108109
valueArray.push(Common.getHumanReadableDate(value));
109110
break;
111+
case 'BOOLEAN':
112+
case 'STRING':
113+
valueArray.push(value.toString() + zeroWidthSpace);
114+
break;
110115
default:
111-
valueArray.push(value.toString());
116+
valueArray.push(parseFloat(value));
112117
break;
113118
}
119+
}
120+
}
121+
122+
function getIndexClicked(data){
123+
return Math.max.apply(this, data.points.map(function(point){
124+
return point.pointNumber;
125+
}));
126+
}
127+
128+
function getValueFromClick(data){
129+
if (data.points[0].x.constructor === Number){
130+
var spread = data.points[0].data.xbins.size*0.5;
131+
return [data.points[0].x - spread, data.points[0].x + spread];
114132
} else {
115-
valueArray.push("");
133+
return [data.points[0].x];
116134
}
117135
}
118136

119-
var layout = {
120-
autosize: true,
121-
paper_bgcolor:'rgba(0,0,0,0)',
122-
plot_bgcolor: 'rgba(0,0,0,0)',
123-
font: {
124-
family: '"Open Sans Light","Helvetica Neue",Helvetica,Arial,sans-serif',
125-
size: 18,
126-
color: 'white'
127-
},
128-
margin: {
129-
l: 100,
130-
r: 100,
131-
t: 100,
132-
b: 200,
133-
pad: 20,
134-
autoexpand: true
135-
},
136-
barmode: 'overlay',
137-
xaxis: {
138-
fixedrange: true
139-
},
140-
yaxis: {
141-
fixedrange: true
142-
},
143-
showlegend: true
144-
};
137+
function getLayout(plot){
138+
var baseLayout = {
139+
autosize: true,
140+
paper_bgcolor:'rgba(0,0,0,0)',
141+
plot_bgcolor: 'rgba(0,0,0,0)',
142+
font: {
143+
family: '"Open Sans Light","Helvetica Neue",Helvetica,Arial,sans-serif',
144+
size: 18,
145+
color: 'white'
146+
},
147+
margin: {
148+
l: 100,
149+
r: 100,
150+
t: 100,
151+
b: 200,
152+
pad: 20,
153+
autoexpand: true
154+
},
155+
barmode: 'overlay',
156+
xaxis: {
157+
fixedrange: true
158+
},
159+
yaxis: {
160+
fixedrange: true
161+
},
162+
showlegend: true
163+
};
164+
if (plot){
165+
baseLayout.xaxis.autorange = false;
166+
baseLayout.xaxis.range = plot._fullLayout.xaxis.range;
167+
baseLayout.yaxis.range = plot._fullLayout.yaxis.range;
168+
baseLayout.yaxis.autorange = false;
169+
}
170+
return baseLayout;
171+
}
145172

146173
return Marionette.LayoutView.extend({
147174
tagName: CustomElements.register('histogram'),
@@ -158,13 +185,18 @@ define([
158185
this.setupListeners();
159186
},
160187
showHistogram: function(){
161-
if (this.histogramAttribute.currentView.getCurrentValue()[0]){
188+
if (this.histogramAttribute.currentView.getCurrentValue()[0] && this.options.selectionInterface.getActiveSearchResults().length !== 0){
162189
var histogramElement = this.el.querySelector('.histogram-container');
163-
Plotly.newPlot(histogramElement, this.determineData(), layout, {
190+
//Plotly.purge(histogramElement);
191+
Plotly.newPlot(histogramElement, this.determineInitialData(), getLayout(), {
164192
displayModeBar: false
165-
});
166-
this.handleResize();
167-
this.listenToHistogram();
193+
}).then(function(plot){
194+
Plotly.newPlot(histogramElement, this.determineData(plot), getLayout(plot), {
195+
displayModeBar: false
196+
});
197+
this.handleResize();
198+
this.listenToHistogram();
199+
}.bind(this));
168200
} else {
169201
this.el.querySelector('.histogram-container').innerHTML = '';
170202
}
@@ -191,10 +223,29 @@ define([
191223
this.showHistogram();
192224
this.handleEmpty();
193225
},
194-
determineData: function(){
226+
determineInitialData: function(){
227+
var activeResults = this.options.selectionInterface.getActiveSearchResults();
228+
return [
229+
{
230+
x: calculateAttributeArray(activeResults, this.histogramAttribute.currentView.getCurrentValue()[0]),
231+
opacity: 1,
232+
type: 'histogram',
233+
name: 'Hits ',
234+
marker: {
235+
color: 'rgba(255, 255, 255, .05)',
236+
line: {
237+
color: 'rgba(255,255,255,.2)',
238+
width: '2'
239+
}
240+
}
241+
}
242+
];
243+
},
244+
determineData: function(plot){
195245
var activeResults = this.options.selectionInterface.getActiveSearchResults();
196246
var selectedResults = this.options.selectionInterface.getSelectedResults();
197-
247+
var xbins = Common.duplicate(plot._fullData[0].xbins);
248+
xbins.end = xbins.end + xbins.size; //https://github.com/plotly/plotly.js/issues/1229
198249
return [
199250
{
200251
x: calculateAttributeArray(activeResults, this.histogramAttribute.currentView.getCurrentValue()[0]),
@@ -207,15 +258,19 @@ define([
207258
color: 'rgba(255,255,255,.2)',
208259
width: '2'
209260
}
210-
}
261+
},
262+
autobinx: false,
263+
xbins: xbins
211264
}, {
212265
x: calculateAttributeArray(selectedResults, this.histogramAttribute.currentView.getCurrentValue()[0]),
213266
opacity: 1,
214267
type: 'histogram',
215268
name: 'Selected',
216269
marker: {
217270
color: 'rgba(255, 255, 255, .2)'
218-
}
271+
},
272+
autobinx: false,
273+
xbins: xbins
219274
}
220275
]
221276

@@ -258,7 +313,8 @@ define([
258313
this.el.querySelector('.histogram-container').on('plotly_click', this.plotlyClickHandler.bind(this));
259314
},
260315
plotlyClickHandler: function(data){
261-
var alreadySelected = this.pointsSelected.indexOf(data.points[0].pointNumber) >= 0;
316+
var indexClicked = getIndexClicked(data);
317+
var alreadySelected = this.pointsSelected.indexOf(indexClicked) >= 0;
262318
if (this.shiftKey){
263319
this.handleShiftClick(data);
264320
} else if (this.ctrlKey || this.metaKey){
@@ -276,24 +332,20 @@ define([
276332
this.options.selectionInterface.removeSelectedResult(findMatchesForAttributeValues(
277333
this.options.selectionInterface.getActiveSearchResults(),
278334
attributeToCheck,
279-
[data.points[0].x]
335+
getValueFromClick(data)
280336
));
281-
this.pointsSelected.splice(this.pointsSelected.indexOf(data.points[0].pointNumber), 1);
337+
this.pointsSelected.splice(this.pointsSelected.indexOf(getIndexClicked(data)), 1);
282338
} else {
283339
this.options.selectionInterface.addSelectedResult(findMatchesForAttributeValues(
284340
this.options.selectionInterface.getActiveSearchResults(),
285341
attributeToCheck,
286-
[data.points[0].x]
342+
getValueFromClick(data)
287343
));
288-
this.pointsSelected.push(Math.max.apply(this, data.points.map(function(point){
289-
return point.pointNumber;
290-
})));
344+
this.pointsSelected.push(getIndexClicked(data));
291345
}
292346
},
293347
handleShiftClick: function(data, alreadySelected){
294-
var indexClicked = Math.max.apply(this, data.points.map(function(point){
295-
return point.pointNumber;
296-
}));
348+
var indexClicked = getIndexClicked(data);
297349
var firstIndex = this.pointsSelected.length === 0 ? -1 : this.pointsSelected.reduce(function(currentMin, point){
298350
return Math.min(currentMin, point);
299351
}, this.pointsSelected[0]);
@@ -312,19 +364,44 @@ define([
312364
}
313365
},
314366
selectBetween: function(firstIndex, lastIndex){
367+
for (var i = firstIndex; i<=lastIndex; i++){
368+
if (this.pointsSelected.indexOf(i) === -1){
369+
this.pointsSelected.push(i);
370+
}
371+
}
315372
var attributeToCheck = this.histogramAttribute.currentView.getCurrentValue()[0];
316373
var categories = this.retrieveCategoriesFromPlotly();
317374
var validCategories = categories.slice(firstIndex, lastIndex);
318-
this.options.selectionInterface.addSelectedResult(findMatchesForAttributeValues(
319-
this.options.selectionInterface.getActiveSearchResults(),
320-
attributeToCheck,
321-
validCategories
322-
));
375+
var activeSearchResults = this.options.selectionInterface.getActiveSearchResults();
376+
this.options.selectionInterface.addSelectedResult(validCategories.reduce(function(results, category){
377+
results = results.concat(findMatchesForAttributeValues(
378+
activeSearchResults,
379+
attributeToCheck,
380+
category.constructor === Array ? category: [category]
381+
));
382+
return results;
383+
}, []));
323384
},
385+
// This is an internal variable for Plotly, so it might break if we update Plotly in the future.
386+
// Regardless, there was no other way to reliably get the categories.
324387
retrieveCategoriesFromPlotly: function(){
325-
// This is an internal variable for Plotly, so it might break if we update Plotly in the future.
326-
// Regardless, there was no other way to reliably get the categories.
327-
return this.el.querySelector('.histogram-container')._fullLayout.xaxis._categories;
388+
var histogramElement = this.el.querySelector('.histogram-container');
389+
var xaxis = histogramElement._fullLayout.xaxis;
390+
if (xaxis._categories.length > 0){
391+
return xaxis._categories;
392+
} else {
393+
var xbins = histogramElement._fullData[0].xbins;
394+
var min = xbins.start;
395+
var max = xbins.end;
396+
var binSize = xbins.size;
397+
var categories = [];
398+
var start = min;
399+
while(start < max) {
400+
categories.push([start, start+binSize]);
401+
start+=binSize;
402+
}
403+
return categories;
404+
}
328405
},
329406
resetKeyTracking: function(){
330407
this.shiftKey = false;

0 commit comments

Comments
 (0)