@@ -51,7 +51,7 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
51
51
// TODO Limit and sort for bar charts (e.g. alphabet)?
52
52
// TODO Look at Plot warnings and see how many we can prevent
53
53
// 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
55
55
56
56
// To apply heuristics based on the data types (values), realize the columns.
57
57
// 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} = {}) {
100
100
: xZero || yZero || colorReduce != null // histogram or heatmap
101
101
? "bar"
102
102
: 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 "
106
106
: x || y
107
107
? "rule"
108
108
: null ;
@@ -132,28 +132,21 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
132
132
colorMode = "stroke" ;
133
133
break ;
134
134
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 )
155
141
? 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 ;
157
150
colorMode = "fill" ;
158
151
break ;
159
152
default :
@@ -198,10 +191,6 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
198
191
return colorMode === "stroke" ? marks ( frames , rules , mark ) : marks ( frames , mark , rules ) ;
199
192
}
200
193
201
- function isContinuous ( values ) {
202
- return ! isOrdinal ( values ) ;
203
- }
204
-
205
194
// TODO What about sorted within series?
206
195
function isMonotonic ( values ) {
207
196
let previous ;
@@ -225,10 +214,22 @@ function makeOptions(value) {
225
214
return isReducer ( value ) ? { reduce : value } : { value} ;
226
215
}
227
216
217
+ // The distinct, count, sum, and proportion reducers are additive (stackable).
228
218
function isZeroReducer ( reduce ) {
229
219
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 ) ;
230
220
}
231
221
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
+
232
233
// https://github.com/observablehq/plot/blob/818562649280e155136f730fc496e0b3d15ae464/src/transforms/group.js#L236
233
234
function isReducer ( reduce ) {
234
235
if ( typeof reduce ?. reduce === "function" && isObject ( reduce ) ) return true ; // N.B. array.reduce
0 commit comments