-
Notifications
You must be signed in to change notification settings - Fork 197
axis mark #1197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
axis mark #1197
Changes from 145 commits
Commits
Show all changes
156 commits
Select commit
Hold shift + click to select a range
d2b54b7
axis mark
mbostock e36bf48
deferred channels
mbostock 9d029d2
vector tick
mbostock 1aa729c
tickPadding
mbostock dbbe828
grid
mbostock 1c1b911
grid
mbostock 0811d59
no rounded stroke
mbostock e71972a
fix half-pixel offset
mbostock f90bdb0
more conditional axes
mbostock bb5d976
grid mark
mbostock c44c29d
DRY tick
mbostock 8d838b4
tick[XY]
mbostock 6fb3f78
explicit ticks
mbostock b9ac607
axisTick[XY]
mbostock f67dcc7
axis mark data
mbostock 59239de
axis insets
mbostock df951b8
tickFormat
mbostock ec672c5
better default tick format
mbostock d273968
simpler inferTickFormat
mbostock 8ef29d7
auto ticks; expose scale.interval
mbostock edb549a
anchor
mbostock c1046a0
manual axis label, for now
mbostock 50f0d92
tickRotate
mbostock b204427
fix crash in sparse excludeIndex
mbostock 564970e
facetAnchor; fix mark-level missing facet
mbostock e0d8ed2
simpler facet sorting
mbostock 2e5663d
fix #522; better facetAnchor
mbostock a1fb2ac
fix #1198; better empty facets
mbostock 754cd3c
fix for ordinal scales
mbostock d1b3c75
soft hyphen
mbostock dc77e25
test label wrapping
mbostock 70e854a
facet grid
mbostock b03d2a3
better facet grid
mbostock 3347586
better facet grid, again
mbostock a364e66
better grid
mbostock 4e0e469
better facet axes; fix font variant
mbostock a041fdf
extract facetSkip
mbostock 7923696
empty facets
mbostock 0ae5493
destructure options
mbostock 74b0840
remove redundant defaults
mbostock 00535df
fix tickPadding, tickRotate
mbostock b41631d
better grid defaults
mbostock e22bf59
more empty facets
mbostock 49c32af
simpler facet warning
mbostock 6d892d3
decoration
mbostock 3c651af
better empty facets
mbostock a2e3725
better facet sort
mbostock 28b7afd
extract facetAnchor
mbostock 4517a5b
extract more facet logic
mbostock 0962cbb
const facets
mbostock 426364a
unify code
mbostock bc70e1b
more facet anchors
mbostock 68a1bbb
invert facetAnchor
mbostock 2c76baf
checkpoint axis label
mbostock b854a09
checkpoint axis mark integration
mbostock 9d94b22
fix minimum offset margin
mbostock 319e59e
fix for null marks and scales
mbostock 4fef6a0
better implicit axes
mbostock 0d27b07
denote side-effect
mbostock 7794fce
better axis options
mbostock 93b1a77
implicit facet axes
mbostock 7aad4ac
more implicit axis options
mbostock 4797caf
inferAxes
mbostock cdda45e
delete old axes
mbostock 5f54f60
minimize diff
mbostock ebc9394
fix default margins
mbostock 0fc7d7d
remove mark.decoration
mbostock d3490e7
facet margin options
mbostock f1b71f2
move side effect
mbostock 938c9d6
inheritScaleLabels
mbostock 1ff510d
Merge branch 'main' into mbostock/axis-mark
mbostock 027b13c
remove comment
mbostock 5492bde
better ARIA labels; restore prior axis order
mbostock 0b1fcb6
regenerate tests; smarter partial implicit axes
mbostock e58cac6
more smarter partial implicit axes
mbostock f6c9c38
axis line
mbostock d4915e4
text stroke options
mbostock 924ec49
don’t inline text elements
mbostock a54c209
do inline title elements
mbostock 5083551
axis label
mbostock a65946b
fix axes for interval scales
mbostock 660d9b2
gridDasharray
mbostock 2faf620
better implicit axis
mbostock c55990c
x-axis label
mbostock 0be9887
another fancy axis example
mbostock 8701c2f
polish example
mbostock 8f21d24
fancy multi-line time ticks
mbostock a29691e
another fancy axis example
mbostock 4df432e
remove secondary grid shorthand
mbostock 819705c
tweak y-axis label position
mbostock 70ebb1f
first stab at documentation
Fil c5e0cec
the grid doesn't follow anchor
Fil db310f1
Merge branch 'main' into mbostock/axis-mark
mbostock b60d2b8
better deferred channels
mbostock 973aa59
better explicit built-in axes
mbostock 8e69ee2
fix metroUnemploymentRidgeline test
mbostock 773daa9
use insetTop for better semantics
mbostock 3c8f5ec
fix label option inheritance
mbostock a6d91fe
axis = both
mbostock 3bf205f
Merge branch 'main' into mbostock/axis-mark
mbostock 3106285
fix comment
mbostock f3ad022
a few fixes to axis label position
mbostock 96065f4
labelAnchor
mbostock ace8885
smarter default labelAnchor
mbostock 30b3022
fix googleTrendsRidgeline
mbostock 19a3502
fix longLabels
mbostock 27ee28d
non-fix for named time intervals
mbostock ae038c7
fix projectionHeightGeometry
mbostock e0fd9f6
non-fix for x-axis label position
mbostock 599ae3a
better axis label position
mbostock 0b75819
inset axis label
mbostock d7fc5a7
fix #375; respect facet margins
mbostock 5cd87f0
fix industryUnemploymentTrack
mbostock e4410be
restore grid in penguinCulmen
mbostock e80954b
facet margin collapse
mbostock f1a1e1e
better facet margin collapse
mbostock 34afc03
drop comment
mbostock dfc2e5c
labelOffset
mbostock 5d15a63
fix auto labels and arrows
mbostock 57cde69
named exports for tests
mbostock 366a045
enable facet axis labels
mbostock 7022708
add non-faceted athletesSample test
mbostock 245d7da
better facet axis label position
mbostock 5d7c944
cleaner
mbostock 7f3865a
enforce constant tick options
mbostock e789969
shorter athletesSportWeight
mbostock f6b71ff
remove dead code
mbostock c62d35d
checkpoint cross-facet marks
mbostock 9da51d5
checkpoint supermarks
mbostock 1187cda
super option
mbostock 686fda6
better super marks
mbostock 4c002c0
drop unused mid facet anchors
mbostock 5745309
disallow superposition, for now
mbostock fdd950b
facet = super
mbostock 9177f3e
minimize diff
mbostock 6b9bd91
fix axis label position, finally?
mbostock 0113c85
better hexbin tests
mbostock 6159142
polish tests
mbostock 2ea8f2c
fix named time intervals for ticks
mbostock a653e54
grid xy shorthand
mbostock 8150d8f
consistent scale checks
mbostock 3be2f7c
better axis options
mbostock 25d0f29
tickSpacing option
mbostock b7baa23
propagate tickSpacing option
mbostock aba84ee
fix off-by-one with interval ticks
mbostock c071fa4
typo (thanks, @yurivish!)
Fil c785d93
only one label for both axes
mbostock 9c57820
a bit of documentation for axisX
Fil 61e1145
given data, don’t defer channels
mbostock 6624e7a
reduce aaplCloseDataTicks test
mbostock 2e9544e
implicit grid with explicit axis
mbostock 9a06f17
more grid shorthand
mbostock cfd47ac
Update README
mbostock 3e095a3
fix default facet axis anchor
mbostock be246de
axis plot shorthand
mbostock 85e6456
Update README
mbostock File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,172 +1,22 @@ | ||
| import {extent} from "d3"; | ||
| import {AxisX, AxisY} from "./axis.js"; | ||
| import {formatDefault} from "./format.js"; | ||
| import {isOrdinalScale, isTemporalScale, scaleOrder} from "./scales.js"; | ||
| import {position, registry} from "./scales/index.js"; | ||
|
|
||
| export function Axes( | ||
| {x: xScale, y: yScale, fx: fxScale, fy: fyScale}, | ||
| { | ||
| x = {}, | ||
| y = {}, | ||
| fx = {}, | ||
| fy = {}, | ||
| axis = true, | ||
| grid, | ||
| line, | ||
| label, | ||
| facet: {axis: facetAxis = axis, grid: facetGrid, label: facetLabel = label} = {} | ||
| } = {} | ||
| ) { | ||
| let {axis: xAxis = axis} = x; | ||
| let {axis: yAxis = axis} = y; | ||
| let {axis: fxAxis = facetAxis} = fx; | ||
| let {axis: fyAxis = facetAxis} = fy; | ||
| if (!xScale) xAxis = null; | ||
| else if (xAxis === true) xAxis = "bottom"; | ||
| if (!yScale) yAxis = null; | ||
| else if (yAxis === true) yAxis = "left"; | ||
| if (!fxScale) fxAxis = null; | ||
| else if (fxAxis === true) fxAxis = xAxis === "bottom" ? "top" : "bottom"; | ||
| if (!fyScale) fyAxis = null; | ||
| else if (fyAxis === true) fyAxis = yAxis === "left" ? "right" : "left"; | ||
| return { | ||
| ...(xAxis && {x: new AxisX(xScale, {grid, line, label, ...x, axis: xAxis})}), | ||
| ...(yAxis && {y: new AxisY(yScale, {grid, line, label, ...y, axis: yAxis})}), | ||
| ...(fxAxis && {fx: new AxisX(fxScale, {name: "fx", grid: facetGrid, label: facetLabel, ...fx, axis: fxAxis})}), | ||
| ...(fyAxis && {fy: new AxisY(fyScale, {name: "fy", grid: facetGrid, label: facetLabel, ...fy, axis: fyAxis})}) | ||
| }; | ||
| } | ||
|
|
||
| // Mutates axis.ticks! | ||
| // TODO Populate tickFormat if undefined, too? | ||
| export function autoAxisTicks({x, y, fx, fy}, {x: xAxis, y: yAxis, fx: fxAxis, fy: fyAxis}) { | ||
| if (fxAxis) autoAxisTicksK(fx, fxAxis, 80); | ||
| if (fyAxis) autoAxisTicksK(fy, fyAxis, 35); | ||
| if (xAxis) autoAxisTicksK(x, xAxis, 80); | ||
| if (yAxis) autoAxisTicksK(y, yAxis, 35); | ||
| } | ||
|
|
||
| function autoAxisTicksK(scale, axis, k) { | ||
| if (axis.ticks === undefined) { | ||
| const interval = scale.interval; | ||
| if (interval !== undefined) { | ||
| const [min, max] = extent(scale.scale.domain()); | ||
| axis.ticks = interval.range(interval.floor(min), interval.offset(interval.floor(max))); | ||
| } else { | ||
| const [min, max] = extent(scale.scale.range()); | ||
| axis.ticks = (max - min) / k; | ||
| } | ||
| } | ||
| // D3’s ordinal scales simply use toString by default, but if the ordinal | ||
| // scale domain (or ticks) are numbers or dates (say because we’re applying a | ||
| // time interval to the ordinal scale), we want Plot’s default formatter. | ||
| if (axis.tickFormat === undefined && isOrdinalScale(scale)) { | ||
| axis.tickFormat = formatDefault; | ||
| } | ||
| } | ||
|
|
||
| // Mutates axis.{label,labelAnchor,labelOffset} and scale.label! | ||
| export function autoScaleLabels(channels, scales, {x, y, fx, fy}, dimensions, options) { | ||
| if (fx) { | ||
| autoAxisLabelsX(fx, scales.fx, channels.get("fx")); | ||
| if (fx.labelOffset === undefined) { | ||
| const {facetMarginTop, facetMarginBottom} = dimensions; | ||
| fx.labelOffset = fx.axis === "top" ? facetMarginTop : facetMarginBottom; | ||
| } | ||
| } | ||
| if (fy) { | ||
| autoAxisLabelsY(fy, fx, scales.fy, channels.get("fy")); | ||
| if (fy.labelOffset === undefined) { | ||
| const {facetMarginLeft, facetMarginRight} = dimensions; | ||
| fy.labelOffset = fy.axis === "left" ? facetMarginLeft : facetMarginRight; | ||
| } | ||
| } | ||
| if (x) { | ||
| autoAxisLabelsX(x, scales.x, channels.get("x")); | ||
| if (x.labelOffset === undefined) { | ||
| const {marginTop, marginBottom, facetMarginTop, facetMarginBottom} = dimensions; | ||
| x.labelOffset = x.axis === "top" ? marginTop - facetMarginTop : marginBottom - facetMarginBottom; | ||
| } | ||
| } | ||
| if (y) { | ||
| autoAxisLabelsY(y, x, scales.y, channels.get("y")); | ||
| if (y.labelOffset === undefined) { | ||
| const {marginRight, marginLeft, facetMarginLeft, facetMarginRight} = dimensions; | ||
| y.labelOffset = y.axis === "left" ? marginLeft - facetMarginLeft : marginRight - facetMarginRight; | ||
| } | ||
| } | ||
| for (const [key, type] of registry) { | ||
| if (type !== position && scales[key]) { | ||
| // not already handled above | ||
| autoScaleLabel(key, scales[key], channels.get(key), options[key]); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Mutates axis.labelAnchor, axis.label, scale.label! | ||
| function autoAxisLabelsX(axis, scale, channels) { | ||
| if (axis.labelAnchor === undefined) { | ||
| axis.labelAnchor = isOrdinalScale(scale) ? "center" : scaleOrder(scale) < 0 ? "left" : "right"; | ||
| } | ||
| if (axis.label === undefined) { | ||
| axis.label = inferLabel(channels, scale, axis, "x"); | ||
| } | ||
| scale.label = axis.label; | ||
| } | ||
|
|
||
| // Mutates axis.labelAnchor, axis.label, scale.label! | ||
| function autoAxisLabelsY(axis, opposite, scale, channels) { | ||
| if (axis.labelAnchor === undefined) { | ||
| axis.labelAnchor = isOrdinalScale(scale) | ||
| ? "center" | ||
| : opposite && opposite.axis === "top" | ||
| ? "bottom" // TODO scaleOrder? | ||
| : "top"; | ||
| } | ||
| if (axis.label === undefined) { | ||
| axis.label = inferLabel(channels, scale, axis, "y"); | ||
| } | ||
| scale.label = axis.label; | ||
| } | ||
|
|
||
| // Mutates scale.label! | ||
| function autoScaleLabel(key, scale, channels, options) { | ||
| if (options) { | ||
| scale.label = options.label; | ||
| } | ||
| if (scale.label === undefined) { | ||
| scale.label = inferLabel(channels, scale, null, key); | ||
| } | ||
| } | ||
|
|
||
| // Channels can have labels; if all the channels for a given scale are | ||
| // consistently labeled (i.e., have the same value if not undefined), and the | ||
| // corresponding axis doesn’t already have an explicit label, then the channels’ | ||
| // label is promoted to the corresponding axis. | ||
| function inferLabel(channels = [], scale, axis, key) { | ||
| let candidate; | ||
| for (const {label} of channels) { | ||
| if (label === undefined) continue; | ||
| if (candidate === undefined) candidate = label; | ||
| else if (candidate !== label) return; | ||
| } | ||
| if (candidate !== undefined) { | ||
| // Ignore the implicit label for temporal scales if it’s simply “date”. | ||
| if (isTemporalScale(scale) && /^(date|time|year)$/i.test(candidate)) return; | ||
| if (!isOrdinalScale(scale)) { | ||
| if (scale.percent) candidate = `${candidate} (%)`; | ||
| if (key === "x" || key === "y") { | ||
| const order = scaleOrder(scale); | ||
| if (order) { | ||
| if (key === "x" || (axis && axis.labelAnchor === "center")) { | ||
| candidate = (key === "x") === order < 0 ? `← ${candidate}` : `${candidate} →`; | ||
| } else { | ||
| candidate = `${order < 0 ? "↑ " : "↓ "}${candidate}`; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return candidate; | ||
| import {format, utcFormat} from "d3"; | ||
| import {formatIsoDate} from "./format.js"; | ||
| import {constant, isTemporal, string} from "./options.js"; | ||
| import {isOrdinalScale} from "./scales.js"; | ||
|
|
||
| export function inferFontVariant(scale) { | ||
| return isOrdinalScale(scale) && scale.interval === undefined ? undefined : "tabular-nums"; | ||
| } | ||
|
|
||
| // D3 doesn’t provide a tick format for ordinal scales; we want shorthand when | ||
| // an ordinal domain is numbers or dates, and we want null to mean the empty | ||
| // string, not the default identity format. TODO Remove this in favor of the | ||
| // axis mark’s inferTickFormat. | ||
| export function maybeAutoTickFormat(tickFormat, domain) { | ||
| return tickFormat === undefined | ||
| ? isTemporal(domain) | ||
| ? formatIsoDate | ||
| : string | ||
| : typeof tickFormat === "function" | ||
| ? tickFormat | ||
| : (typeof tickFormat === "string" ? (isTemporal(domain) ? utcFormat : format) : constant)(tickFormat); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.