@@ -132,6 +132,19 @@ axes.minDtick = function(ax, newDiff, newFirst, allow) {
132
132
}
133
133
} ;
134
134
135
+ // Find the autorange for this axis
136
+ //
137
+ // assumes ax._min and ax._max have already been set by calling axes.expand
138
+ // using calcdata from all traces. These are arrays of:
139
+ // {val: calcdata value, pad: extra pixels beyond this value}
140
+ //
141
+ // Returns an array of [min, max]. These are calcdata for log and category axes
142
+ // and data for linear and date axes.
143
+ //
144
+ // TODO: we want to change log to data as well, but it's hard to do this
145
+ // maintaining backward compatibility. category will always have to use calcdata
146
+ // though, because otherwise values between categories (or outside all categories)
147
+ // would be impossible.
135
148
axes . getAutoRange = function ( ax ) {
136
149
var newRange = [ ] ;
137
150
@@ -150,7 +163,12 @@ axes.getAutoRange = function(ax) {
150
163
151
164
var j , minpt , maxpt , minbest , maxbest , dp , dv ,
152
165
mbest = 0 ,
153
- axReverse = ( ax . range && ax . range [ 1 ] < ax . range [ 0 ] ) ;
166
+ axReverse = false ;
167
+
168
+ if ( ax . range ) {
169
+ var rng = ax . range . map ( ax . r2l ) ;
170
+ axReverse = rng [ 1 ] < rng [ 0 ] ;
171
+ }
154
172
155
173
// one-time setting to easily reverse the axis
156
174
// when plotting from code
@@ -239,11 +257,9 @@ axes.getAutoRange = function(ax) {
239
257
}
240
258
241
259
// maintain reversal
242
- if ( axReverse ) {
243
- newRange . reverse ( ) ;
244
- }
260
+ if ( axReverse ) newRange . reverse ( ) ;
245
261
246
- return newRange ;
262
+ return newRange . map ( ax . l2r || Number ) ;
247
263
} ;
248
264
249
265
axes . doAutoRange = function ( ax ) {
@@ -444,10 +460,22 @@ axes.autoBin = function(data, ax, nbins, is2d) {
444
460
}
445
461
446
462
// piggyback off autotick code to make "nice" bin sizes
447
- var dummyax = {
448
- type : ax . type === 'log' ? 'linear' : ax . type ,
449
- range : [ datamin , datamax ]
450
- } ;
463
+ var dummyax ;
464
+ if ( ax . type === 'log' ) {
465
+ dummyax = {
466
+ type : 'linear' ,
467
+ range : [ datamin , datamax ]
468
+ } ;
469
+ }
470
+ else {
471
+ dummyax = {
472
+ type : ax . type ,
473
+ // conversion below would be ax.c2r but that's only different from l2r
474
+ // for log, and this is the only place (so far?) we would want c2r.
475
+ range : [ datamin , datamax ] . map ( ax . l2r )
476
+ } ;
477
+ }
478
+
451
479
axes . autoTicks ( dummyax , size0 ) ;
452
480
var binstart = axes . tickIncrement (
453
481
axes . tickFirst ( dummyax ) , dummyax . dtick , 'reverse' ) ,
@@ -529,6 +557,8 @@ axes.autoBin = function(data, ax, nbins, is2d) {
529
557
axes . calcTicks = function calcTicks ( ax ) {
530
558
if ( ax . tickmode === 'array' ) return arrayTicks ( ax ) ;
531
559
560
+ var rng = ax . range . map ( ax . r2l ) ;
561
+
532
562
// calculate max number of (auto) ticks to display based on plot size
533
563
if ( ax . tickmode === 'auto' || ! ax . dtick ) {
534
564
var nt = ax . nticks ,
@@ -543,7 +573,7 @@ axes.calcTicks = function calcTicks(ax) {
543
573
nt = Lib . constrain ( ax . _length / minPx , 4 , 9 ) + 1 ;
544
574
}
545
575
}
546
- axes . autoTicks ( ax , Math . abs ( ax . range [ 1 ] - ax . range [ 0 ] ) / nt ) ;
576
+ axes . autoTicks ( ax , Math . abs ( rng [ 1 ] - rng [ 0 ] ) / nt ) ;
547
577
// check for a forced minimum dtick
548
578
if ( ax . _minDtick > 0 && ax . dtick < ax . _minDtick * 2 ) {
549
579
ax . dtick = ax . _minDtick ;
@@ -553,8 +583,7 @@ axes.calcTicks = function calcTicks(ax) {
553
583
554
584
// check for missing tick0
555
585
if ( ! ax . tick0 ) {
556
- ax . tick0 = ( ax . type === 'date' ) ?
557
- new Date ( 2000 , 0 , 1 ) . getTime ( ) : 0 ;
586
+ ax . tick0 = ( ax . type === 'date' ) ? '2000-01-01' : 0 ;
558
587
}
559
588
560
589
// now figure out rounding of tick values
@@ -564,12 +593,12 @@ axes.calcTicks = function calcTicks(ax) {
564
593
ax . _tmin = axes . tickFirst ( ax ) ;
565
594
566
595
// check for reversed axis
567
- var axrev = ( ax . range [ 1 ] < ax . range [ 0 ] ) ;
596
+ var axrev = ( rng [ 1 ] < rng [ 0 ] ) ;
568
597
569
598
// return the full set of tick vals
570
599
var vals = [ ] ,
571
600
// add a tiny bit so we get ticks which may have rounded out
572
- endtick = ax . range [ 1 ] * 1.0001 - ax . range [ 0 ] * 0.0001 ;
601
+ endtick = rng [ 1 ] * 1.0001 - rng [ 0 ] * 0.0001 ;
573
602
if ( ax . type === 'category' ) {
574
603
endtick = ( axrev ) ? Math . max ( - 0.5 , endtick ) :
575
604
Math . min ( ax . _categories . length - 0.5 , endtick ) ;
@@ -597,15 +626,15 @@ function arrayTicks(ax) {
597
626
var vals = ax . tickvals ,
598
627
text = ax . ticktext ,
599
628
ticksOut = new Array ( vals . length ) ,
600
- r0expanded = ax . range [ 0 ] * 1.0001 - ax . range [ 1 ] * 0.0001 ,
601
- r1expanded = ax . range [ 1 ] * 1.0001 - ax . range [ 0 ] * 0.0001 ,
629
+ rng = ax . range . map ( ax . r2l ) ,
630
+ r0expanded = rng [ 0 ] * 1.0001 - rng [ 1 ] * 0.0001 ,
631
+ r1expanded = rng [ 1 ] * 1.0001 - rng [ 0 ] * 0.0001 ,
602
632
tickMin = Math . min ( r0expanded , r1expanded ) ,
603
633
tickMax = Math . max ( r0expanded , r1expanded ) ,
604
634
vali ,
605
635
i ,
606
636
j = 0 ;
607
637
608
-
609
638
// without a text array, just format the given values as any other ticks
610
639
// except with more precision to the numbers
611
640
if ( ! Array . isArray ( text ) ) text = [ ] ;
@@ -658,7 +687,7 @@ axes.autoTicks = function(ax, roughDTick) {
658
687
var base ;
659
688
660
689
if ( ax . type === 'date' ) {
661
- ax . tick0 = new Date ( 2000 , 0 , 1 ) . getTime ( ) ;
690
+ ax . tick0 = ' 2000-01-01' ;
662
691
663
692
if ( roughDTick > 15778800000 ) {
664
693
// years if roughDTick > 6mo
@@ -675,7 +704,7 @@ axes.autoTicks = function(ax, roughDTick) {
675
704
// days if roughDTick > 12h
676
705
ax . dtick = roundDTick ( roughDTick , 86400000 , roundDays ) ;
677
706
// get week ticks on sunday
678
- ax . tick0 = new Date ( 2000 , 0 , 2 ) . getTime ( ) ;
707
+ ax . tick0 = ' 2000-01-01' ;
679
708
}
680
709
else if ( roughDTick > 1800000 ) {
681
710
// hours if roughDTick > 30m
@@ -697,16 +726,19 @@ axes.autoTicks = function(ax, roughDTick) {
697
726
}
698
727
else if ( ax . type === 'log' ) {
699
728
ax . tick0 = 0 ;
729
+ var rng = ax . range . map ( ax . r2l ) ;
700
730
701
- // only show powers of 10
702
- if ( roughDTick > 0.7 ) ax . dtick = Math . ceil ( roughDTick ) ;
703
- else if ( Math . abs ( ax . range [ 1 ] - ax . range [ 0 ] ) < 1 ) {
731
+ if ( roughDTick > 0.7 ) {
732
+ // only show powers of 10
733
+ ax . dtick = Math . ceil ( roughDTick ) ;
734
+ }
735
+ else if ( Math . abs ( rng [ 1 ] - rng [ 0 ] ) < 1 ) {
704
736
// span is less than one power of 10
705
- var nt = 1.5 * Math . abs ( ( ax . range [ 1 ] - ax . range [ 0 ] ) / roughDTick ) ;
737
+ var nt = 1.5 * Math . abs ( ( rng [ 1 ] - rng [ 0 ] ) / roughDTick ) ;
706
738
707
739
// ticks on a linear scale, labeled fully
708
- roughDTick = Math . abs ( Math . pow ( 10 , ax . range [ 1 ] ) -
709
- Math . pow ( 10 , ax . range [ 0 ] ) ) / nt ;
740
+ roughDTick = Math . abs ( Math . pow ( 10 , rng [ 1 ] ) -
741
+ Math . pow ( 10 , rng [ 0 ] ) ) / nt ;
710
742
base = Math . pow ( 10 , Math . floor ( Math . log ( roughDTick ) / Math . LN10 ) ) ;
711
743
ax . dtick = 'L' + roundDTick ( roughDTick , base , roundBase10 ) ;
712
744
}
@@ -745,13 +777,16 @@ axes.autoTicks = function(ax, roughDTick) {
745
777
// for date ticks, the last date part to show (y,m,d,H,M,S)
746
778
// or an integer # digits past seconds
747
779
function autoTickRound ( ax ) {
748
- var dtick = ax . dtick ,
749
- maxend ;
780
+ var dtick = ax . dtick ;
750
781
751
782
ax . _tickexponent = 0 ;
752
- if ( ! isNumeric ( dtick ) && typeof dtick !== 'string' ) dtick = 1 ;
783
+ if ( ! isNumeric ( dtick ) && typeof dtick !== 'string' ) {
784
+ dtick = 1 ;
785
+ }
753
786
754
- if ( ax . type === 'category' ) ax . _tickround = null ;
787
+ if ( ax . type === 'category' ) {
788
+ ax . _tickround = null ;
789
+ }
755
790
else if ( isNumeric ( dtick ) || dtick . charAt ( 0 ) === 'L' ) {
756
791
if ( ax . type === 'date' ) {
757
792
if ( dtick >= 86400000 ) ax . _tickround = 'd' ;
@@ -761,14 +796,13 @@ function autoTickRound(ax) {
761
796
else ax . _tickround = 3 - Math . round ( Math . log ( dtick / 2 ) / Math . LN10 ) ;
762
797
}
763
798
else {
799
+ // linear or log
800
+ var rng = ax . range . map ( ax . r2d || Number ) ;
764
801
if ( ! isNumeric ( dtick ) ) dtick = Number ( dtick . substr ( 1 ) ) ;
765
802
// 2 digits past largest digit of dtick
766
803
ax . _tickround = 2 - Math . floor ( Math . log ( dtick ) / Math . LN10 + 0.01 ) ;
767
804
768
- if ( ax . type === 'log' ) {
769
- maxend = Math . pow ( 10 , Math . max ( ax . range [ 0 ] , ax . range [ 1 ] ) ) ;
770
- }
771
- else maxend = Math . max ( Math . abs ( ax . range [ 0 ] ) , Math . abs ( ax . range [ 1 ] ) ) ;
805
+ var maxend = Math . max ( Math . abs ( rng [ 0 ] ) , Math . abs ( rng [ 1 ] ) ) ;
772
806
773
807
var rangeexp = Math . floor ( Math . log ( maxend ) / Math . LN10 + 0.01 ) ;
774
808
if ( Math . abs ( rangeexp ) > 3 ) {
@@ -824,13 +858,16 @@ axes.tickIncrement = function(x, dtick, axrev) {
824
858
825
859
// calculate the first tick on an axis
826
860
axes . tickFirst = function ( ax ) {
827
- var axrev = ax . range [ 1 ] < ax . range [ 0 ] ,
861
+ var r2l = ax . r2l || Number ,
862
+ rng = ax . range . map ( r2l ) ,
863
+ axrev = rng [ 1 ] < rng [ 0 ] ,
828
864
sRound = axrev ? Math . floor : Math . ceil ,
829
865
// add a tiny extra bit to make sure we get ticks
830
866
// that may have been rounded out
831
- r0 = ax . range [ 0 ] * 1.0001 - ax . range [ 1 ] * 0.0001 ,
867
+ r0 = rng [ 0 ] * 1.0001 - rng [ 1 ] * 0.0001 ,
832
868
dtick = ax . dtick ,
833
- tick0 = ax . tick0 ;
869
+ tick0 = r2l ( ax . tick0 ) ;
870
+
834
871
if ( isNumeric ( dtick ) ) {
835
872
var tmin = sRound ( ( r0 - tick0 ) / dtick ) * dtick + tick0 ;
836
873
@@ -916,7 +953,8 @@ axes.tickText = function(ax, x, hover) {
916
953
i ;
917
954
918
955
if ( arrayMode && Array . isArray ( ax . ticktext ) ) {
919
- var minDiff = Math . abs ( ax . range [ 1 ] - ax . range [ 0 ] ) / 10000 ;
956
+ var rng = ax . range . map ( ax . r2l ) ,
957
+ minDiff = Math . abs ( rng [ 1 ] - rng [ 0 ] ) / 10000 ;
920
958
for ( i = 0 ; i < ax . ticktext . length ; i ++ ) {
921
959
if ( Math . abs ( x - ax . d2l ( ax . tickvals [ i ] ) ) < minDiff ) break ;
922
960
}
@@ -1106,7 +1144,7 @@ function numFormat(v, ax, fmtoverride, hover) {
1106
1144
( isNumeric ( v ) ? Math . abs ( v ) || 1 : 1 ) ,
1107
1145
// if not showing any exponents, don't change the exponent
1108
1146
// from what we calculate
1109
- range : ax . showexponent === 'none' ? ax . range : [ 0 , v || 1 ]
1147
+ range : ax . showexponent === 'none' ? ax . range . map ( ax . r2d ) : [ 0 , v || 1 ]
1110
1148
} ;
1111
1149
autoTickRound ( ah ) ;
1112
1150
tickRound = ( Number ( ah . _tickround ) || 0 ) + 4 ;
@@ -1354,8 +1392,9 @@ axes.makeClipPaths = function(gd) {
1354
1392
// doTicks: draw ticks, grids, and tick labels
1355
1393
// axid: 'x', 'y', 'x2' etc,
1356
1394
// blank to do all,
1357
- // 'redraw' to force full redraw, and reset ax._r
1358
- // (stored range for use by zoom/pan)
1395
+ // 'redraw' to force full redraw, and reset:
1396
+ // ax._r (stored range for use by zoom/pan)
1397
+ // ax._rl (stored linearized range for use by zoom/pan)
1359
1398
// or can pass in an axis object directly
1360
1399
axes . doTicks = function ( gd , axid , skipTitle ) {
1361
1400
var fullLayout = gd . _fullLayout ,
@@ -1393,7 +1432,10 @@ axes.doTicks = function(gd, axid, skipTitle) {
1393
1432
return function ( ) {
1394
1433
if ( ! ax . _id ) return ;
1395
1434
var axDone = axes . doTicks ( gd , ax . _id ) ;
1396
- if ( axid === 'redraw' ) ax . _r = ax . range . slice ( ) ;
1435
+ if ( axid === 'redraw' ) {
1436
+ ax . _r = ax . range . slice ( ) ;
1437
+ ax . _rl = ax . _r . map ( ax . r2l ) ;
1438
+ }
1397
1439
return axDone ;
1398
1440
} ;
1399
1441
} ) ) ;
@@ -1411,9 +1453,6 @@ axes.doTicks = function(gd, axid, skipTitle) {
1411
1453
}
1412
1454
}
1413
1455
1414
- // in case a val turns into string somehow
1415
- ax . range = [ + ax . range [ 0 ] , + ax . range [ 1 ] ] ;
1416
-
1417
1456
// set scaling to pixels
1418
1457
ax . setScale ( ) ;
1419
1458
@@ -1802,7 +1841,8 @@ axes.doTicks = function(gd, axid, skipTitle) {
1802
1841
break ;
1803
1842
}
1804
1843
}
1805
- var showZl = ( ax . range [ 0 ] * ax . range [ 1 ] <= 0 ) && ax . zeroline &&
1844
+ var rng = ax . range . map ( ax . r2l ) ,
1845
+ showZl = ( rng [ 0 ] * rng [ 1 ] <= 0 ) && ax . zeroline &&
1806
1846
( ax . type === 'linear' || ax . type === '-' ) && gridvals . length &&
1807
1847
( hasBarsOrFill || clipEnds ( { x : 0 } ) || ! ax . showline ) ;
1808
1848
var zl = zlcontainer . selectAll ( 'path.' + zcls )
0 commit comments