@@ -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