Skip to content

Commit

Permalink
fix hexbin default stroke
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed May 26, 2023
1 parent 90d20a5 commit 9605805
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
7 changes: 4 additions & 3 deletions src/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ export function styles(
imageFilter,
paintOrder,
pointerEvents,
shapeRendering
shapeRendering,
channels
},
{
ariaLabel: cariaLabel,
Expand Down Expand Up @@ -81,9 +82,9 @@ export function styles(
// default fill becomes none. Similarly for marks that stroke by stroke, the
// default stroke only applies if the fill is (constant) none.
if (isNoneish(defaultFill)) {
if (!isNoneish(defaultStroke) && !isNoneish(fill)) defaultStroke = "none";
if (!isNoneish(defaultStroke) && (!isNoneish(fill) || channels?.fill)) defaultStroke = "none";
} else {
if (isNoneish(defaultStroke) && !isNoneish(stroke)) defaultFill = "none";
if (isNoneish(defaultStroke) && (!isNoneish(stroke) || channels?.stroke)) defaultFill = "none";
}

const [vfill, cfill] = maybeColorChannel(fill, defaultFill);
Expand Down
16 changes: 9 additions & 7 deletions src/transforms/hexbin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {isNoneish, map, number, valueof} from "../options.js";
import {map, number, valueof} from "../options.js";
import {applyPosition} from "../projection.js";
import {sqrt3} from "../symbol.js";
import {initializer} from "./basic.js";
Expand All @@ -13,17 +13,19 @@ export const ox = 0.5,
oy = 0;

export function hexbin(outputs = {fill: "count"}, {binWidth, ...options} = {}) {
const {z} = options;

// TODO filter e.g. to show empty hexbins?
// TODO disallow x, x1, x2, y, y1, y2 reducers?
binWidth = binWidth === undefined ? 20 : number(binWidth);
outputs = maybeOutputs(outputs, options);

// A fill output means a fill channel, and hence the stroke should default to
// none (assuming a mark that defaults to fill and no stroke, such as dot).
// Note that it’s safe to mutate options here because we just created it with
// the rest operator above.
const {z, fill, stroke} = options;
if (stroke === undefined && isNoneish(fill) && hasOutput(outputs, "fill")) options.stroke = "none";
// A fill output means a fill channel; declaring the channel here instead of
// waiting for the initializer allows the mark constructor to determine that
// the stroke should default to none (assuming a mark that defaults to fill
// and no stroke, such as dot). Note that it’s safe to mutate options here
// because we just created it with the rest operator above.
if (hasOutput(outputs, "fill")) options.channels = {...options.channels, fill: {value: []}};

// Populate default values for the r and symbol options, as appropriate.
if (options.symbol === undefined) options.symbol = "hexagon";
Expand Down
13 changes: 13 additions & 0 deletions test/plots/tip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ export async function tipHexbin() {
return Plot.hexagon(olympians, Plot.hexbin({r: "count"}, {x: "weight", y: "height", tip: true})).plot();
}

// Normally you would slap a tip: true on the hexagon, as above, but here we
// want to test that the hexbin transform isn’t applying an erroneous stroke:
// none to the tip options (which would change the tip appearance).
export async function tipHexbinExplicit() {
const olympians = await d3.csv<any>("data/athletes.csv", d3.autoType);
return Plot.plot({
marks: [
Plot.hexagon(olympians, Plot.hexbin({fill: "count"}, {x: "weight", y: "height"})),
Plot.tip(olympians, Plot.pointer(Plot.hexbin({fill: "count"}, {x: "weight", y: "height"})))
]
});
}

export async function tipLine() {
const aapl = await d3.csv<any>("data/aapl.csv", d3.autoType);
return Plot.lineY(aapl, {x: "Date", y: "Close", tip: true}).plot();
Expand Down

0 comments on commit 9605805

Please sign in to comment.