@@ -167,8 +167,9 @@ module.exports = function calc(gd, trace) {
167167 * smallest bins of any of the auto values for all histograms grouped/stacked
168168 * together.
169169 */
170- function calcAllAutoBins ( gd , trace , pa , mainData ) {
170+ function calcAllAutoBins ( gd , trace , pa , mainData , _overlayEdgeCase ) {
171171 var binAttr = mainData + 'bins' ;
172+ var isOverlay = gd . _fullLayout . barmode === 'overlay' ;
172173 var i , tracei , calendar , firstManual , pos0 ;
173174
174175 // all but the first trace in this group has already been marked finished
@@ -178,7 +179,9 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
178179 }
179180 else {
180181 // 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 ) ;
182185 var autoBinnedTraces = [ ] ;
183186
184187 var minSize = Infinity ;
@@ -202,6 +205,19 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
202205
203206 binSpec = Axes . autoBin ( pos0 , pa , tracei [ 'nbins' + mainData ] , false , calendar ) ;
204207
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+
205221 // adjust for CDF edge cases
206222 if ( cumulativeSpec . enabled && ( cumulativeSpec . currentbin !== 'include' ) ) {
207223 if ( cumulativeSpec . direction === 'decreasing' ) {
@@ -218,9 +234,9 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
218234 }
219235 else if ( ! firstManual ) {
220236 // 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...
224240 firstManual = {
225241 size : binSpec . size ,
226242 start : pa . r2c ( binSpec . start , 0 , calendar ) ,
@@ -282,14 +298,90 @@ function calcAllAutoBins(gd, trace, pa, mainData) {
282298}
283299
284300/*
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
287381 * similar way to how we do manually binned histograms, though this
288382 * would have tons of edge cases and value judgments to make.
289383 */
290384function getConnectedHistograms ( gd , trace ) {
291- if ( gd . _fullLayout . barmode === 'overlay' ) return [ trace ] ;
292-
293385 var xid = trace . xaxis ;
294386 var yid = trace . yaxis ;
295387 var orientation = trace . orientation ;
0 commit comments