diff --git a/src/marks/auto.js b/src/marks/auto.js
index b53c632ef0..4724a98f68 100644
--- a/src/marks/auto.js
+++ b/src/marks/auto.js
@@ -1,6 +1,6 @@
import {ascending, InternSet} from "d3";
import {marks} from "../mark.js";
-import {isColor, isObject, isOptions, isOrdinal, labelof, valueof} from "../options.js";
+import {isColor, isNumeric, isObject, isOptions, isOrdinal, labelof, valueof} from "../options.js";
import {bin, binX, binY} from "../transforms/bin.js";
import {group, groupX, groupY} from "../transforms/group.js";
import {areaX, areaY} from "./area.js";
@@ -113,27 +113,32 @@ export function autoSpec(data, options) {
colorMode = "stroke";
break;
case "bar":
- markImpl = yZero
- ? isOrdinalReduced(xReduce, X)
- ? barY
- : rectY
- : xZero
- ? isOrdinalReduced(yReduce, Y)
- ? barX
- : rectX
- : isOrdinalReduced(xReduce, X) && isOrdinalReduced(yReduce, Y)
- ? cell
- : isOrdinalReduced(xReduce, X)
- ? barY
- : isOrdinalReduced(yReduce, Y)
- ? barX
- : xReduce != null
- ? rectX
- : yReduce != null
- ? rectY
- : colorReduce != null
- ? rect
- : cell;
+ markImpl =
+ xReduce != null // bin or group on y
+ ? isOrdinal(Y)
+ ? isSelectReducer(xReduce) && X && isOrdinal(X)
+ ? cell
+ : barX
+ : rectX
+ : yReduce != null // bin or group on x
+ ? isOrdinal(X)
+ ? isSelectReducer(yReduce) && Y && isOrdinal(Y)
+ ? cell
+ : barY
+ : rectY
+ : colorReduce != null || sizeReduce != null // bin or group on both x and y
+ ? X && isOrdinal(X) && Y && isOrdinal(Y)
+ ? cell
+ : X && isOrdinal(X)
+ ? barY
+ : Y && isOrdinal(Y)
+ ? barX
+ : rect
+ : X && isNumeric(X) && !(Y && isNumeric(Y))
+ ? barX // if y is temporal, treat as ordinal
+ : Y && isNumeric(Y) && !(X && isNumeric(X))
+ ? barY // if x is temporal, treat as ordinal
+ : cell;
colorMode = "fill";
break;
default:
@@ -300,12 +305,6 @@ function isSelectReducer(reduce) {
return /^(?:first|last|mode)$/i.test(reduce);
}
-// We can’t infer the type of a custom reducer without invoking it, so
-// assume most reducers produce quantitative values.
-function isOrdinalReduced(reduce, value) {
- return (reduce != null && !isSelectReducer(reduce)) || !value ? false : isOrdinal(value);
-}
-
// https://github.com/observablehq/plot/blob/818562649280e155136f730fc496e0b3d15ae464/src/transforms/group.js#L236
function isReducer(reduce) {
if (reduce == null) return false;
diff --git a/test/output/autoBarTimeSeries.svg b/test/output/autoBarTimeSeries.svg
new file mode 100644
index 0000000000..6a7dbd2ed1
--- /dev/null
+++ b/test/output/autoBarTimeSeries.svg
@@ -0,0 +1,77 @@
+
\ No newline at end of file
diff --git a/test/output/autoBarTimeSeriesReduce.svg b/test/output/autoBarTimeSeriesReduce.svg
new file mode 100644
index 0000000000..058c8bf0cc
--- /dev/null
+++ b/test/output/autoBarTimeSeriesReduce.svg
@@ -0,0 +1,71 @@
+
\ No newline at end of file
diff --git a/test/plots/autoplot.ts b/test/plots/autoplot.ts
index 0b876f3326..619a8639c6 100644
--- a/test/plots/autoplot.ts
+++ b/test/plots/autoplot.ts
@@ -103,6 +103,24 @@ export async function autoBar() {
return Plot.auto(alphabet, {x: "frequency", y: "letter", mark: "bar"}).plot();
}
+const timeSeries = [
+ {date: new Date("2023-04-01"), type: "triangle", value: 5},
+ {date: new Date("2023-04-05"), type: "circle", value: 7},
+ {date: new Date("2023-04-10"), type: "circle", value: 8},
+ {date: new Date("2023-04-15"), type: "circle", value: 3},
+ {date: new Date("2023-04-15"), type: "triangle", value: 7},
+ {date: new Date("2023-04-20"), type: "triangle", value: 4},
+ {date: new Date("2023-04-25"), type: "square", value: 5}
+];
+
+export async function autoBarTimeSeries() {
+ return Plot.auto(timeSeries, {x: "date", y: "value", color: "type", mark: "bar"}).plot({x: {type: "band"}}); // TODO suppress warning?
+}
+
+export async function autoBarTimeSeriesReduce() {
+ return Plot.auto(timeSeries, {x: "date", y: {value: "value", reduce: "sum"}, color: "type", mark: "bar"}).plot();
+}
+
export async function autoConnectedScatterplot() {
const driving = await d3.csv("data/driving.csv", d3.autoType);
return Plot.auto(driving, {x: "miles", y: "gas", mark: "line"}).plot();