@@ -654,6 +654,53 @@ describe('Test colorscale:', function() {
654654 expect ( fullLayout . coloraxis . cmax ) . toBe ( 4 ) ;
655655 expect ( fullLayout . coloraxis . _cmax ) . toBe ( 4 ) ;
656656 } ) ;
657+
658+ it ( 'should fall back to a linear colorbar when zmin/zmax is explicitly non-positive for a log colorbar' , function ( ) {
659+ trace = {
660+ type : 'heatmap' ,
661+ z : [ [ - 5 , 10 , 100 ] , [ 10 , 100 , 1000 ] ] ,
662+ zmin : - 5 ,
663+ zmax : 1000 ,
664+ zauto : false ,
665+ colorbar : { type : 'log' }
666+ } ;
667+ gd = _supply ( trace ) ;
668+ calcColorscale ( gd , trace , { vals : trace . z , containerStr : '' , cLetter : 'z' } ) ;
669+
670+ expect ( trace . colorbar . type ) . toBe ( 'linear' ) ;
671+ expect ( trace . _zmin ) . toBe ( - 5 ) ;
672+ expect ( trace . _zmax ) . toBe ( 1000 ) ;
673+ } ) ;
674+
675+ it ( 'should fall back to a linear colorbar when autoscaling finds no positive values for a log colorbar' , function ( ) {
676+ trace = {
677+ type : 'heatmap' ,
678+ z : [ [ - 5 , - 10 ] , [ - 100 , - 1 ] ] ,
679+ colorbar : { type : 'log' }
680+ } ;
681+ gd = _supply ( trace ) ;
682+ calcColorscale ( gd , trace , { vals : trace . z , containerStr : '' , cLetter : 'z' } ) ;
683+
684+ expect ( trace . colorbar . type ) . toBe ( 'linear' ) ;
685+ expect ( trace . _zmin ) . toBe ( - 100 ) ;
686+ expect ( trace . _zmax ) . toBe ( - 1 ) ;
687+ } ) ;
688+
689+ it ( 'should mask out non-positive values when autoscaling a log colorbar, like log cartesian axes do' , function ( ) {
690+ trace = {
691+ type : 'heatmap' ,
692+ z : [ [ - 5 , 2 , 100 ] , [ 10 , 100 , 1000 ] ] ,
693+ colorbar : { type : 'log' }
694+ } ;
695+ gd = _supply ( trace ) ;
696+ calcColorscale ( gd , trace , { vals : trace . z , containerStr : '' , cLetter : 'z' } ) ;
697+
698+ // stays log - there is positive data to scale from
699+ expect ( trace . colorbar . type ) . toBe ( 'log' ) ;
700+ // -5 is masked out; the smallest positive value (2) becomes zmin
701+ expect ( trace . _zmin ) . toBe ( 2 ) ;
702+ expect ( trace . _zmax ) . toBe ( 1000 ) ;
703+ } ) ;
657704 } ) ;
658705
659706 describe ( 'extractScale + makeColorScaleFunc' , function ( ) {
@@ -1247,7 +1294,42 @@ describe('Test colorscale restyle calls:', function() {
12471294 expect ( colorFn ( 0 ) ) . toEqual ( 'rgba(0,0,0,0)' ) ;
12481295 expect ( colorFn ( - 10 ) ) . toEqual ( 'rgba(0,0,0,0)' ) ;
12491296 } ) ;
1250-
1297+
1298+ it ( 'should return numeric rgba arrays (not strings) when called with returnArray/noNumericCheck, as heatmap rendering does' , function ( ) {
1299+ var trace = {
1300+ cmin : 1 ,
1301+ cmax : 100 ,
1302+ colorscale : [
1303+ [ 0 , 'rgb(0, 0, 0)' ] ,
1304+ [ 1 , 'rgb(200, 100, 50)' ]
1305+ ] ,
1306+ colorbar : {
1307+ type : 'log'
1308+ }
1309+ } ;
1310+
1311+ var colorFn = makeColorScaleFuncFromTrace ( trace , { noNumericCheck : true , returnArray : true } ) ;
1312+
1313+ // log10(1) = 0 -> maps to 0% of the scale
1314+ var cLow = colorFn ( 1 ) ;
1315+ expect ( cLow ) . toEqual ( [ 0 , 0 , 0 , 1 ] ) ;
1316+ expect ( typeof cLow [ 0 ] ) . toBe ( 'number' ) ;
1317+
1318+ // log10(100) = 2 -> maps to 100% of the scale
1319+ var cHigh = colorFn ( 100 ) ;
1320+ expect ( cHigh ) . toEqual ( [ 200 , 100 , 50 , 1 ] ) ;
1321+
1322+ // zero/negative must clamp to a numeric transparent array, not a css string,
1323+ // since callers like heatmap/plot.js index directly into the result (c[0], c[1], c[2])
1324+ var cZero = colorFn ( 0 ) ;
1325+ expect ( cZero ) . toEqual ( [ 0 , 0 , 0 , 0 ] ) ;
1326+ expect ( typeof cZero [ 0 ] ) . toBe ( 'number' ) ;
1327+
1328+ var cNeg = colorFn ( - 10 ) ;
1329+ expect ( cNeg ) . toEqual ( [ 0 , 0 , 0 , 0 ] ) ;
1330+ expect ( typeof cNeg [ 0 ] ) . toBe ( 'number' ) ;
1331+ } ) ;
1332+
12511333 it ( 'should safely fall back to linear if type is undefined or linear' , function ( ) {
12521334 var trace = {
12531335 cmin : 1 ,
0 commit comments