@@ -167,8 +167,9 @@ module.exports = function calc(gd, trace) {
167
167
* smallest bins of any of the auto values for all histograms grouped/stacked
168
168
* together.
169
169
*/
170
- function calcAllAutoBins ( gd , trace , pa , mainData ) {
170
+ function calcAllAutoBins ( gd , trace , pa , mainData , _overlayEdgeCase ) {
171
171
var binAttr = mainData + 'bins' ;
172
+ var isOverlay = gd . _fullLayout . barmode === 'overlay' ;
172
173
var i , tracei , calendar , firstManual , pos0 ;
173
174
174
175
// all but the first trace in this group has already been marked finished
@@ -178,7 +179,9 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
178
179
}
179
180
else {
180
181
// must be the first trace in the group - do the autobinning on them all
181
- var traceGroup = getConnectedHistograms ( gd , trace ) ;
182
+
183
+ // find all grouped traces - in overlay mode each trace is independent
184
+ var traceGroup = isOverlay ? [ trace ] : getConnectedHistograms ( gd , trace ) ;
182
185
var autoBinnedTraces = [ ] ;
183
186
184
187
var minSize = Infinity ;
@@ -202,6 +205,19 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
202
205
203
206
binSpec = Axes . autoBin ( pos0 , pa , tracei [ 'nbins' + mainData ] , false , calendar ) ;
204
207
208
+ // Edge case: single-valued histogram overlaying others
209
+ // Use them all together to calculate the bin size for the single-valued one
210
+ if ( isOverlay && binSpec . _count === 1 && pa . type !== 'category' ) {
211
+ // trace[binAttr] = binSpec;
212
+
213
+ // Several single-valued histograms! Stop infinite recursion,
214
+ // just return an extra flag that tells handleSingleValueOverlays
215
+ // to sort out this trace too
216
+ if ( _overlayEdgeCase ) return [ binSpec , pos0 , true ] ;
217
+
218
+ binSpec = handleSingleValueOverlays ( gd , trace , pa , mainData , binAttr ) ;
219
+ }
220
+
205
221
// adjust for CDF edge cases
206
222
if ( cumulativeSpec . enabled && ( cumulativeSpec . currentbin !== 'include' ) ) {
207
223
if ( cumulativeSpec . direction === 'decreasing' ) {
@@ -218,9 +234,9 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
218
234
}
219
235
else if ( ! firstManual ) {
220
236
// Remember the first manually set binSpec. We'll try to be extra
221
- // accommodating of this one, so other bins line up with these
222
- // if there's more than one manual bin set and they're mutually inconsistent,
223
- // then there's not much we can do...
237
+ // accommodating of this one, so other bins line up with these.
238
+ // But if there's more than one manual bin set and they're mutually
239
+ // inconsistent, then there's not much we can do...
224
240
firstManual = {
225
241
size : binSpec . size ,
226
242
start : pa . r2c ( binSpec . start , 0 , calendar ) ,
@@ -282,14 +298,90 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
282
298
}
283
299
284
300
/*
285
- * Return an array of traces that are all stacked or grouped together
286
- * Only considers histograms. In principle we could include them in a
301
+ * Adjust single-value histograms in overlay mode to make as good a
302
+ * guess as we can at autobin values the user would like.
303
+ *
304
+ * Returns the binSpec for the trace that sparked all this
305
+ */
306
+ function handleSingleValueOverlays ( gd , trace , pa , mainData , binAttr ) {
307
+ var overlaidTraceGroup = getConnectedHistograms ( gd , trace ) ;
308
+ var pastThisTrace = false ;
309
+ var minSize = Infinity ;
310
+ var singleValuedTraces = [ trace ] ;
311
+ var i , tracei ;
312
+
313
+ // first collect all the:
314
+ // - min bin size from all multi-valued traces
315
+ // - single-valued traces
316
+ for ( i = 0 ; i < overlaidTraceGroup . length ; i ++ ) {
317
+ tracei = overlaidTraceGroup [ i ] ;
318
+ if ( tracei === trace ) pastThisTrace = true ;
319
+ else if ( ! pastThisTrace ) {
320
+ // This trace has already had its autobins calculated
321
+ // (so must not have been single-valued).
322
+ minSize = Math . min ( minSize , tracei [ binAttr ] . size ) ;
323
+ }
324
+ else {
325
+ var resulti = calcAllAutoBins ( gd , tracei , pa , mainData , true ) ;
326
+ var binSpeci = resulti [ 0 ] ;
327
+ var isSingleValued = resulti [ 2 ] ;
328
+
329
+ // so we can use this result when we get to tracei in the normal
330
+ // course of events, mark it as done and put _pos0 back
331
+ tracei . _autoBinFinished = 1 ;
332
+ tracei . _pos0 = resulti [ 1 ] ;
333
+
334
+ if ( isSingleValued ) {
335
+ singleValuedTraces . push ( tracei ) ;
336
+ }
337
+ else {
338
+ minSize = Math . min ( minSize , binSpeci . size ) ;
339
+ }
340
+ }
341
+ }
342
+
343
+ // find the real data values for each single-valued trace
344
+ // hunt through pos0 for the first valid value
345
+ var dataVals = new Array ( singleValuedTraces . length ) ;
346
+ for ( i = 0 ; i < singleValuedTraces . length ; i ++ ) {
347
+ var pos0 = singleValuedTraces [ i ] . _pos0 ;
348
+ for ( var j = 0 ; j < pos0 . length ; j ++ ) {
349
+ if ( pos0 [ j ] !== undefined ) {
350
+ dataVals [ i ] = pos0 [ j ] ;
351
+ break ;
352
+ }
353
+ }
354
+ }
355
+
356
+ // are ALL traces are single-valued? use the min difference between
357
+ // all of their values (which defaults to 1 if there's still only one)
358
+ if ( ! isFinite ( minSize ) ) {
359
+ minSize = Lib . distinctVals ( dataVals ) . minDiff ;
360
+ }
361
+
362
+ // now apply the min size we found to all single-valued traces
363
+ for ( i = 0 ; i < singleValuedTraces . length ; i ++ ) {
364
+ tracei = singleValuedTraces [ i ] ;
365
+ var calendar = tracei [ mainData + 'calendar' ] ;
366
+
367
+ tracei . _input [ binAttr ] = tracei [ binAttr ] = {
368
+ start : pa . c2r ( dataVals [ i ] - minSize / 2 , 0 , calendar ) ,
369
+ end : pa . c2r ( dataVals [ i ] + minSize / 2 , 0 , calendar ) ,
370
+ size : minSize
371
+ } ;
372
+ }
373
+
374
+ return trace [ binAttr ] ;
375
+ }
376
+
377
+ /*
378
+ * Return an array of histograms that share axes and orientation.
379
+ *
380
+ * Only considers histograms. In principle we could include bars in a
287
381
* similar way to how we do manually binned histograms, though this
288
382
* would have tons of edge cases and value judgments to make.
289
383
*/
290
384
function getConnectedHistograms ( gd , trace ) {
291
- if ( gd . _fullLayout . barmode === 'overlay' ) return [ trace ] ;
292
-
293
385
var xid = trace . xaxis ;
294
386
var yid = trace . yaxis ;
295
387
var orientation = trace . orientation ;
0 commit comments