@@ -51,7 +51,7 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
5151  // TODO Limit and sort for bar charts (e.g. alphabet)? 
5252  // TODO Look at Plot warnings and see how many we can prevent 
5353  // TODO Default to something other than turbo for continuous? Like: 
54-   //      scheme: (colorValue && isContinuous (color)) || colorReduce ? "ylgnbu" : undefined 
54+   //      scheme: (colorValue && !isOrdinal (color)) || colorReduce ? "ylgnbu" : undefined 
5555
5656  // To apply heuristics based on the data types (values), realize the columns. 
5757  // We could maybe look at the data.schema here, but Plot’s behavior depends on 
@@ -100,9 +100,9 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
100100        : xZero  ||  yZero  ||  colorReduce  !=  null  // histogram or heatmap 
101101        ? "bar" 
102102        : x  &&  y 
103-         ? isContinuous ( x )  &&   isContinuous ( y )  &&  ( xReduce  !=  null  ||  yReduce  !=  null  ||   isMonotonic ( x )  ||   isMonotonic ( y ) ) 
104-           ? "line " 
105-           : "dot " 
103+         ? isOrdinal ( x )  ||   isOrdinal ( y )  ||  ( xReduce  ==  null  &&  yReduce  ==  null  &&   ! isMonotonic ( x )  &&   ! isMonotonic ( y ) ) 
104+           ? "dot " 
105+           : "line " 
106106        : x  ||  y 
107107        ? "rule" 
108108        : null ; 
@@ -132,28 +132,21 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
132132        colorMode  =  "stroke" ; 
133133        break ; 
134134      case  "bar" :
135-         mark  = 
136-           yReduce  !=  null 
137-             ? isOrdinal ( x ) 
138-               ? barY 
139-               : rectY 
140-             : xReduce  !=  null 
141-             ? isOrdinal ( y ) 
142-               ? barX 
143-               : rectX 
144-             : colorReduce  !=  null 
145-             ? x  &&  y  &&  isOrdinal ( x )  &&  isOrdinal ( y ) 
146-               ? cell 
147-               : x  &&  isOrdinal ( x ) 
148-               ? barY 
149-               : y  &&  isOrdinal ( y ) 
150-               ? barX 
151-               : rect 
152-             : x  &&  y  &&  isOrdinal ( x )  &&  isOrdinal ( y ) 
153-             ? cell 
154-             : y  &&  isOrdinal ( y ) 
135+         mark  =  yZero 
136+           ? isOrdinalReduced ( xReduce ,  x ) 
137+             ? barY 
138+             : rectY 
139+           : xZero 
140+           ? isOrdinalReduced ( yReduce ,  y ) 
155141            ? barX 
156-             : barY ; 
142+             : rectX 
143+           : isOrdinalReduced ( xReduce ,  x )  &&  isOrdinalReduced ( yReduce ,  y ) 
144+           ? cell 
145+           : isOrdinalReduced ( xReduce ,  x ) 
146+           ? barY 
147+           : isOrdinalReduced ( yReduce ,  y ) 
148+           ? barX 
149+           : rect ; 
157150        colorMode  =  "fill" ; 
158151        break ; 
159152      default :
@@ -198,10 +191,6 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
198191  return  colorMode  ===  "stroke"  ? marks ( frames ,  rules ,  mark )  : marks ( frames ,  mark ,  rules ) ; 
199192} 
200193
201- function  isContinuous ( values )  { 
202-   return  ! isOrdinal ( values ) ; 
203- } 
204- 
205194// TODO What about sorted within series? 
206195function  isMonotonic ( values )  { 
207196  let  previous ; 
@@ -225,10 +214,22 @@ function makeOptions(value) {
225214  return  isReducer ( value )  ? { reduce : value }  : { value} ; 
226215} 
227216
217+ // The distinct, count, sum, and proportion reducers are additive (stackable). 
228218function  isZeroReducer ( reduce )  { 
229219  return  / ^ (?: d i s t i n c t | c o u n t | s u m | p r o p o r t i o n ) $ / i. test ( reduce ) ; 
230220} 
231221
222+ // The first, last, and mode reducers preserve the type of the aggregated values. 
223+ function  isSelectReducer ( reduce )  { 
224+   return  / ^ (?: f i r s t | l a s t | m o d e ) $ / i. test ( reduce ) ; 
225+ } 
226+ 
227+ // We can’t infer the type of a custom reducer without invoking it, so 
228+ // assume most reducers produce quantitative values. 
229+ function  isOrdinalReduced ( reduce ,  value )  { 
230+   return  ( reduce  !=  null  &&  ! isSelectReducer ( reduce ) )  ||  ! value  ? false  : isOrdinal ( value ) ; 
231+ } 
232+ 
232233// https://github.com/observablehq/plot/blob/818562649280e155136f730fc496e0b3d15ae464/src/transforms/group.js#L236 
233234function  isReducer ( reduce )  { 
234235  if  ( typeof  reduce ?. reduce  ===  "function"  &&  isObject ( reduce ) )  return  true ;  // N.B. array.reduce 
0 commit comments