@@ -40,12 +40,9 @@ module.exports = function calc(gd, trace) {
4040
4141 cleanBins ( trace , pa , maindata ) ;
4242
43- var binspec = calcAllAutoBins ( gd , trace , pa , maindata ) ;
44-
45- // the raw data was prepared in calcAllAutoBins (during the first trace in
46- // this group) and stashed. Pull it out and drop the stash
47- var pos0 = trace . _pos0 ;
48- delete trace . _pos0 ;
43+ var binsAndPos = calcAllAutoBins ( gd , trace , pa , maindata ) ;
44+ var binspec = binsAndPos [ 0 ] ;
45+ var pos0 = binsAndPos [ 1 ] ;
4946
5047 var nonuniformBins = typeof binspec . size === 'string' ;
5148 var bins = nonuniformBins ? [ ] : binspec ;
@@ -166,115 +163,116 @@ module.exports = function calc(gd, trace) {
166163 */
167164function calcAllAutoBins ( gd , trace , pa , maindata ) {
168165 var binAttr = maindata + 'bins' ;
166+ var i , tracei , calendar , firstManual , pos0 ;
169167
170168 // all but the first trace in this group has already been marked finished
171169 // clear this flag, so next time we run calc we will run autobin again
172170 if ( trace . _autoBinFinished ) {
173171 delete trace . _autoBinFinished ;
174-
175- return trace [ binAttr ] ;
176172 }
173+ else {
174+ // must be the first trace in the group - do the autobinning on them all
175+ var traceGroup = getConnectedHistograms ( gd , trace ) ;
176+ var autoBinnedTraces = [ ] ;
177+
178+ var minSize = Infinity ;
179+ var minStart = Infinity ;
180+ var maxEnd = - Infinity ;
181+
182+ var autoBinAttr = 'autobin' + maindata ;
183+
184+ for ( i = 0 ; i < traceGroup . length ; i ++ ) {
185+ tracei = traceGroup [ i ] ;
186+
187+ // stash pos0 on the trace so we don't need to duplicate this
188+ // in the main body of calc
189+ pos0 = tracei . _pos0 = pa . makeCalcdata ( tracei , maindata ) ;
190+ var binspec = tracei [ binAttr ] ;
191+
192+ if ( ( tracei [ autoBinAttr ] ) || ! binspec ||
193+ binspec . start === null || binspec . end === null ) {
194+ calendar = tracei [ maindata + 'calendar' ] ;
195+ var cumulativeSpec = tracei . cumulative ;
196+
197+ binspec = Axes . autoBin ( pos0 , pa , tracei [ 'nbins' + maindata ] , false , calendar ) ;
198+
199+ // adjust for CDF edge cases
200+ if ( cumulativeSpec . enabled && ( cumulativeSpec . currentbin !== 'include' ) ) {
201+ if ( cumulativeSpec . direction === 'decreasing' ) {
202+ minStart = Math . min ( minStart , pa . r2c ( binspec . start , 0 , calendar ) - binspec . size ) ;
203+ }
204+ else {
205+ maxEnd = Math . max ( maxEnd , pa . r2c ( binspec . end , 0 , calendar ) + binspec . size ) ;
206+ }
207+ }
177208
178- // must be the first trace in the group - do the autobinning on them all
179- var traceGroup = getConnectedHistograms ( gd , trace ) ;
180- var autoBinnedTraces = [ ] ;
181-
182- var minSize = Infinity ;
183- var minStart = Infinity ;
184- var maxEnd = - Infinity ;
185-
186- var autoBinAttr = 'autobin' + maindata ;
187- var i , tracei , calendar , firstManual ;
188-
209+ // note that it's possible to get here with an explicit autobin: false
210+ // if the bins were not specified. mark this trace for followup
211+ autoBinnedTraces . push ( tracei ) ;
212+ }
213+ else if ( ! firstManual ) {
214+ // Remember the first manually set binspec. We'll try to be extra
215+ // accommodating of this one, so other bins line up with these
216+ // if there's more than one manual bin set and they're mutually inconsistent,
217+ // then there's not much we can do...
218+ firstManual = {
219+ size : binspec . size ,
220+ start : pa . r2c ( binspec . start , 0 , calendar ) ,
221+ end : pa . r2c ( binspec . end , 0 , calendar )
222+ } ;
223+ }
189224
190- for ( i = 0 ; i < traceGroup . length ; i ++ ) {
191- tracei = traceGroup [ i ] ;
225+ // Even non-autobinned traces get included here, so we get the greatest extent
226+ // and minimum bin size of them all.
227+ // But manually binned traces won't be adjusted, even if the auto values
228+ // are inconsistent with the manual ones (or the manual ones are inconsistent
229+ // with each other).
230+ minSize = getMinSize ( minSize , binspec . size ) ;
231+ minStart = Math . min ( minStart , pa . r2c ( binspec . start , 0 , calendar ) ) ;
232+ maxEnd = Math . max ( maxEnd , pa . r2c ( binspec . end , 0 , calendar ) ) ;
233+
234+ // add the flag that lets us abort autobin on later traces
235+ if ( i ) trace . _autoBinFinished = 1 ;
236+ }
192237
193- // stash pos0 on the trace so we don't need to duplicate this
194- // in the main body of calc
195- var pos0 = tracei . _pos0 = pa . makeCalcdata ( tracei , maindata ) ;
196- var binspec = tracei [ binAttr ] ;
238+ // do what we can to match the auto bins to the first manual bins
239+ // but only if sizes are all numeric
240+ if ( firstManual && isNumeric ( firstManual . size ) && isNumeric ( minSize ) ) {
241+ // first need to ensure the bin size is the same as or an integer fraction
242+ // of the first manual bin
243+ // allow the bin size to increase just under the autobin step size to match,
244+ // (which is a factor of 2 or 2.5) otherwise shrink it
245+ if ( minSize > firstManual . size / 1.9 ) minSize = firstManual . size ;
246+ else minSize = firstManual . size / Math . ceil ( firstManual . size / minSize ) ;
247+
248+ // now decrease minStart if needed to make the bin centers line up
249+ var adjustedFirstStart = firstManual . start + ( firstManual . size - minSize ) / 2 ;
250+ minStart = adjustedFirstStart - minSize * Math . ceil ( ( adjustedFirstStart - minStart ) / minSize ) ;
251+ }
197252
198- if ( ( tracei [ autoBinAttr ] ) || ! binspec ||
199- binspec . start === null || binspec . end === null ) {
253+ // now go back to the autobinned traces and update their bin specs with the final values
254+ for ( i = 0 ; i < autoBinnedTraces . length ; i ++ ) {
255+ tracei = autoBinnedTraces [ i ] ;
200256 calendar = tracei [ maindata + 'calendar' ] ;
201- var cumulativeSpec = tracei . cumulative ;
202-
203- binspec = Axes . autoBin ( pos0 , pa , tracei [ 'nbins' + maindata ] , false , calendar ) ;
204257
205- // adjust for CDF edge cases
206- if ( cumulativeSpec . enabled && ( cumulativeSpec . currentbin !== 'include' ) ) {
207- if ( cumulativeSpec . direction === 'decreasing' ) {
208- minStart = Math . min ( minStart , pa . r2c ( binspec . start , 0 , calendar ) - binspec . size ) ;
209- }
210- else {
211- maxEnd = Math . max ( maxEnd , pa . r2c ( binspec . end , 0 , calendar ) + binspec . size ) ;
212- }
213- }
258+ tracei . _input [ binAttr ] = tracei [ binAttr ] = {
259+ start : pa . c2r ( minStart , 0 , calendar ) ,
260+ end : pa . c2r ( maxEnd , 0 , calendar ) ,
261+ size : minSize
262+ } ;
214263
215264 // note that it's possible to get here with an explicit autobin: false
216- // if the bins were not specified. mark this trace for followup
217- autoBinnedTraces . push ( tracei ) ;
265+ // if the bins were not specified.
266+ // in that case this will remain in the trace, so that future updates
267+ // which would change the autobinning will not do so.
268+ tracei . _input [ autoBinAttr ] = tracei [ autoBinAttr ] ;
218269 }
219- else if ( ! firstManual ) {
220- // 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...
224- firstManual = {
225- size : binspec . size ,
226- start : pa . r2c ( binspec . start , 0 , calendar ) ,
227- end : pa . r2c ( binspec . end , 0 , calendar )
228- } ;
229- }
230-
231- // Even non-autobinned traces get included here, so we get the greatest extent
232- // and minimum bin size of them all.
233- // But manually binned traces won't be adjusted, even if the auto values
234- // are inconsistent with the manual ones (or the manual ones are inconsistent
235- // with each other).
236- minSize = getMinSize ( minSize , binspec . size ) ;
237- minStart = Math . min ( minStart , pa . r2c ( binspec . start , 0 , calendar ) ) ;
238- maxEnd = Math . max ( maxEnd , pa . r2c ( binspec . end , 0 , calendar ) ) ;
239-
240- // add the flag that lets us abort autobin on later traces
241- if ( i ) trace . _autoBinFinished = 1 ;
242270 }
243271
244- // do what we can to match the auto bins to the first manual bins
245- // but only if sizes are all numeric
246- if ( firstManual && isNumeric ( firstManual . size ) && isNumeric ( minSize ) ) {
247- // first need to ensure the bin size is the same as or an integer fraction
248- // of the first manual bin
249- // allow the bin size to increase just under the autobin step size to match,
250- // (which is a factor of 2 or 2.5) otherwise shrink it
251- if ( minSize > firstManual . size / 1.9 ) minSize = firstManual . size ;
252- else minSize = firstManual . size / Math . ceil ( firstManual . size / minSize ) ;
253-
254- // now decrease minStart if needed to make the bin centers line up
255- var adjustedFirstStart = firstManual . start + ( firstManual . size - minSize ) / 2 ;
256- minStart = adjustedFirstStart - minSize * Math . ceil ( ( adjustedFirstStart - minStart ) / minSize ) ;
257- }
258-
259- // now go back to the autobinned traces and update their bin specs with the final values
260- for ( i = 0 ; i < autoBinnedTraces . length ; i ++ ) {
261- tracei = autoBinnedTraces [ i ] ;
262- calendar = tracei [ maindata + 'calendar' ] ;
263-
264- tracei . _input [ binAttr ] = tracei [ binAttr ] = {
265- start : pa . c2r ( minStart , 0 , calendar ) ,
266- end : pa . c2r ( maxEnd , 0 , calendar ) ,
267- size : minSize
268- } ;
269-
270- // note that it's possible to get here with an explicit autobin: false
271- // if the bins were not specified.
272- // in that case this will remain in the trace, so that future updates
273- // which would change the autobinning will not do so.
274- tracei . _input [ autoBinAttr ] = tracei [ autoBinAttr ] ;
275- }
272+ pos0 = trace . _pos0 ;
273+ delete trace . _pos0 ;
276274
277- return trace [ binAttr ] ;
275+ return [ trace [ binAttr ] , pos0 ] ;
278276}
279277
280278/*
0 commit comments