66* LICENSE file in the root directory of this source tree.
77*/
88
9-
109'use strict' ;
1110
1211var isNumeric = require ( 'fast-isnumeric' ) ;
1312
1413var Lib = require ( '../../lib' ) ;
14+ var Registry = require ( '../../registry' ) ;
1515var Axes = require ( '../../plots/cartesian/axes' ) ;
1616
1717var arraysToCalcdata = require ( '../bar/arrays_to_calcdata' ) ;
@@ -20,16 +20,10 @@ var normFunctions = require('./norm_functions');
2020var doAvg = require ( './average' ) ;
2121var getBinSpanLabelRound = require ( './bin_label_vals' ) ;
2222
23- module . exports = function calc ( gd , trace ) {
24- // ignore as much processing as possible (and including in autorange) if not visible
25- if ( trace . visible !== true ) return ;
26-
27- // depending on orientation, set position and size axes and data ranges
28- // note: this logic for choosing orientation is duplicated in graph_obj->setstyles
23+ function calc ( gd , trace ) {
2924 var pos = [ ] ;
3025 var size = [ ] ;
31- var pa = Axes . getFromId ( gd , trace . orientation === 'h' ?
32- ( trace . yaxis || 'y' ) : ( trace . xaxis || 'x' ) ) ;
26+ var pa = Axes . getFromId ( gd , trace . orientation === 'h' ? trace . yaxis : trace . xaxis ) ;
3327 var mainData = trace . orientation === 'h' ? 'y' : 'x' ;
3428 var counterData = { x : 'y' , y : 'x' } [ mainData ] ;
3529 var calendar = trace [ mainData + 'calendar' ] ;
@@ -143,7 +137,6 @@ module.exports = function calc(gd, trace) {
143137 // after all normalization etc, now we can accumulate if desired
144138 if ( cumulativeSpec . enabled ) cdf ( size , cumulativeSpec . direction , cumulativeSpec . currentbin ) ;
145139
146-
147140 var seriesLen = Math . min ( pos . length , size . length ) ;
148141 var cd = [ ] ;
149142 var firstNonzero = 0 ;
@@ -201,23 +194,30 @@ module.exports = function calc(gd, trace) {
201194 }
202195
203196 return cd ;
204- } ;
197+ }
205198
206199/*
207- * calcAllAutoBins: we want all histograms on the same axes to share bin specs
208- * if they're grouped or stacked. If the user has explicitly specified differing
200+ * calcAllAutoBins: we want all histograms inside the same bingroup
201+ * (see logic in Histogram.crossTraceDefaults) to share bin specs
202+ *
203+ * If the user has explicitly specified differing
209204 * bin specs, there's nothing we can do, but if possible we will try to use the
210- * smallest bins of any of the auto values for all histograms grouped/stacked
211- * together .
205+ * smallest bins of any of the auto values for all histograms inside the same
206+ * bingroup .
212207 */
213208function calcAllAutoBins ( gd , trace , pa , mainData , _overlayEdgeCase ) {
214209 var binAttr = mainData + 'bins' ;
215210 var fullLayout = gd . _fullLayout ;
211+ var groupName = trace [ '_' + mainData + 'bingroup' ] ;
212+ var binOpts = fullLayout . _histogramBinOpts [ groupName ] ;
216213 var isOverlay = fullLayout . barmode === 'overlay' ;
217214 var i , traces , tracei , calendar , pos0 , autoVals , cumulativeSpec ;
218215
219- var cleanBound = ( pa . type === 'date' ) ?
220- function ( v ) { return ( v || v === 0 ) ? Lib . cleanDate ( v , null , pa . calendar ) : null ; } :
216+ var r2c = function ( v ) { return pa . r2c ( v , 0 , calendar ) ; } ;
217+ var c2r = function ( v ) { return pa . c2r ( v , 0 , calendar ) ; } ;
218+
219+ var cleanBound = pa . type === 'date' ?
220+ function ( v ) { return ( v || v === 0 ) ? Lib . cleanDate ( v , null , calendar ) : null ; } :
221221 function ( v ) { return isNumeric ( v ) ? Number ( v ) : null ; } ;
222222
223223 function setBound ( attr , bins , newBins ) {
@@ -230,45 +230,73 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
230230 }
231231 }
232232
233- var binOpts = fullLayout . _histogramBinOpts [ trace . _groupName ] ;
234-
235233 // all but the first trace in this group has already been marked finished
236234 // clear this flag, so next time we run calc we will run autobin again
237235 if ( trace . _autoBinFinished ) {
238236 delete trace . _autoBinFinished ;
239237 } else {
240238 traces = binOpts . traces ;
241- var sizeFound = binOpts . sizeFound ;
242239 var allPos = [ ] ;
243- autoVals = traces [ 0 ] . _autoBin = { } ;
240+
244241 // Note: we're including `legendonly` traces here for autobin purposes,
245242 // so that showing & hiding from the legend won't affect bins.
246243 // But this complicates things a bit since those traces don't `calc`,
247244 // hence `isFirstVisible`.
248245 var isFirstVisible = true ;
246+ var has2dMap = false ;
247+ var hasHist2dContour = false ;
249248 for ( i = 0 ; i < traces . length ; i ++ ) {
250249 tracei = traces [ i ] ;
250+
251251 if ( tracei . visible ) {
252- pos0 = tracei . _pos0 = pa . makeCalcdata ( tracei , mainData ) ;
252+ var mainDatai = binOpts . dirs [ i ] ;
253+ pos0 = tracei [ '_' + mainDatai + 'pos0' ] = pa . makeCalcdata ( tracei , mainDatai ) ;
254+
253255 allPos = Lib . concat ( allPos , pos0 ) ;
254256 delete tracei . _autoBinFinished ;
257+
255258 if ( trace . visible === true ) {
256259 if ( isFirstVisible ) {
257260 isFirstVisible = false ;
258261 } else {
259262 delete tracei . _autoBin ;
260263 tracei . _autoBinFinished = 1 ;
261264 }
265+ if ( Registry . traceIs ( tracei , '2dMap' ) ) {
266+ has2dMap = true ;
267+ }
268+ if ( tracei . type === 'histogram2dcontour' ) {
269+ hasHist2dContour = true ;
270+ }
262271 }
263272 }
264273 }
274+
265275 calendar = traces [ 0 ] [ mainData + 'calendar' ] ;
266- var newBinSpec = Axes . autoBin (
267- allPos , pa , binOpts . nbins , false , calendar , sizeFound && binOpts . size ) ;
276+ var newBinSpec = Axes . autoBin ( allPos , pa , binOpts . nbins , has2dMap , calendar , binOpts . sizeFound && binOpts . size ) ;
268277
278+ var autoBin = traces [ 0 ] . _autoBin = { } ;
279+ autoVals = autoBin [ binOpts . dirs [ 0 ] ] = { } ;
280+
281+ if ( hasHist2dContour ) {
282+ // the "true" 2nd argument reverses the tick direction (which we can't
283+ // just do with a minus sign because of month bins)
284+ if ( ! binOpts . size ) {
285+ newBinSpec . start = c2r ( Axes . tickIncrement (
286+ r2c ( newBinSpec . start ) , newBinSpec . size , true , calendar ) ) ;
287+ }
288+ if ( binOpts . end === undefined ) {
289+ newBinSpec . end = c2r ( Axes . tickIncrement (
290+ r2c ( newBinSpec . end ) , newBinSpec . size , false , calendar ) ) ;
291+ }
292+ }
293+
294+ // TODO how does work with bingroup ????
295+ // - https://github.com/plotly/plotly.js/issues/3881
296+ //
269297 // Edge case: single-valued histogram overlaying others
270298 // Use them all together to calculate the bin size for the single-valued one
271- if ( isOverlay && newBinSpec . _dataSpan === 0 &&
299+ if ( isOverlay && ! Registry . traceIs ( trace , '2dMap' ) && newBinSpec . _dataSpan === 0 &&
272300 pa . type !== 'category' && pa . type !== 'multicategory' ) {
273301 // Several single-valued histograms! Stop infinite recursion,
274302 // just return an extra flag that tells handleSingleValueOverlays
@@ -279,23 +307,19 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
279307 }
280308
281309 // adjust for CDF edge cases
282- cumulativeSpec = tracei . cumulative ;
310+ cumulativeSpec = tracei . cumulative || { } ;
283311 if ( cumulativeSpec . enabled && ( cumulativeSpec . currentbin !== 'include' ) ) {
284312 if ( cumulativeSpec . direction === 'decreasing' ) {
285- newBinSpec . start = pa . c2r ( Axes . tickIncrement (
286- pa . r2c ( newBinSpec . start , 0 , calendar ) ,
287- newBinSpec . size , true , calendar
288- ) ) ;
313+ newBinSpec . start = c2r ( Axes . tickIncrement (
314+ r2c ( newBinSpec . start ) , newBinSpec . size , true , calendar ) ) ;
289315 } else {
290- newBinSpec . end = pa . c2r ( Axes . tickIncrement (
291- pa . r2c ( newBinSpec . end , 0 , calendar ) ,
292- newBinSpec . size , false , calendar
293- ) ) ;
316+ newBinSpec . end = c2r ( Axes . tickIncrement (
317+ r2c ( newBinSpec . end ) , newBinSpec . size , false , calendar ) ) ;
294318 }
295319 }
296320
297321 binOpts . size = newBinSpec . size ;
298- if ( ! sizeFound ) {
322+ if ( ! binOpts . sizeFound ) {
299323 autoVals . size = newBinSpec . size ;
300324 Lib . nestedProperty ( traces [ 0 ] , binAttr + '.size' ) . set ( newBinSpec . size ) ;
301325 }
@@ -304,8 +328,8 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
304328 setBound ( 'end' , binOpts , newBinSpec ) ;
305329 }
306330
307- pos0 = trace . _pos0 ;
308- delete trace . _pos0 ;
331+ pos0 = trace [ '_' + mainData + 'pos0' ] ;
332+ delete trace [ '_' + mainData + 'pos0' ] ;
309333
310334 // Each trace can specify its own start/end, or if omitted
311335 // we ensure they're beyond the bounds of this trace's data,
@@ -398,7 +422,7 @@ function handleSingleValueOverlays(gd, trace, pa, mainData, binAttr) {
398422 // so we can use this result when we get to tracei in the normal
399423 // course of events, mark it as done and put _pos0 back
400424 tracei . _autoBinFinished = 1 ;
401- tracei . _pos0 = resulti [ 1 ] ;
425+ tracei [ '_' + mainData + 'pos0' ] = resulti [ 1 ] ;
402426
403427 if ( isSingleValued ) {
404428 singleValuedTraces . push ( tracei ) ;
@@ -412,7 +436,7 @@ function handleSingleValueOverlays(gd, trace, pa, mainData, binAttr) {
412436 // hunt through pos0 for the first valid value
413437 var dataVals = new Array ( singleValuedTraces . length ) ;
414438 for ( i = 0 ; i < singleValuedTraces . length ; i ++ ) {
415- var pos0 = singleValuedTraces [ i ] . _pos0 ;
439+ var pos0 = singleValuedTraces [ i ] [ '_' + mainData + 'pos0' ] ;
416440 for ( var j = 0 ; j < pos0 . length ; j ++ ) {
417441 if ( pos0 [ j ] !== undefined ) {
418442 dataVals [ i ] = pos0 [ j ] ;
@@ -470,7 +494,6 @@ function getConnectedHistograms(gd, trace) {
470494 return out ;
471495}
472496
473-
474497function cdf ( size , direction , currentBin ) {
475498 var i , vi , prevSum ;
476499
@@ -518,3 +541,8 @@ function cdf(size, direction, currentBin) {
518541 }
519542 }
520543}
544+
545+ module . exports = {
546+ calc : calc ,
547+ calcAllAutoBins : calcAllAutoBins
548+ } ;
0 commit comments