Skip to content
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

2.2 #156

Merged
merged 37 commits into from
Jan 26, 2019
Merged

2.2 #156

merged 37 commits into from
Jan 26, 2019

Conversation

mbostock
Copy link
Member

@mbostock mbostock commented Jan 6, 2019

Fixes #62 - implements transforms on other scale types.
Fixes #93 - scaleSequentialQuantile computes p-quantile.
Fixes #97 - adds scale.unknown to all scale types.
Fixes #102 - allow unlimited band.paddingOuter and point.padding.
Fixes #105 - implements symlog transform.
Fixes #117 - use midpoint of domain or range when collapsed.
Fixes #123 - documents that quantize.domain must be ascending.
Fixes #132 - clarifies documentation for band.paddingOuter.
Fixes #148 - exposes d3.tickFormat.
Fixes #157 - adds convenience constructors for scales.
Fixes #159 - adds default constructors for sequential and diverging scales.

TODO

  • Add scaleSymlog. Support 'symlog' scale #105
  • Add scaleSequentialPow.
  • Add scaleSequentialSqrt.
  • Add scaleSequentialLog.
  • Add scaleSequentialQuantile.
  • Add scaleDivergingPow.
  • Add scaleDivergingSqrt.
  • Add scaleDivergingLog.
  • Add scaleDivergingQuantile.
  • Transforms on scaleQuantize? No; seems too niche.
  • Transforms on scaleQuantile? No; transforms are assumed to be monotonic.
  • Transforms on scaleThreshold? No; transforms are assumed to be monotonic.
  • Transforms on scaleIdentity? No; nonsensical.

@mbostock
Copy link
Member Author

mbostock commented Jan 6, 2019

We’re almost there. Before, this hack (which didn’t work with descending domains):

z = d3.scaleLog()
    .domain(domain)
    .interpolate(() => d3.interpolateBlues)

After, with sequential.transform:

z = d3.scaleSequential(d3.interpolateBlues)
    .transform(d3.transformLog)
    .domain(domain)

This is not ideal, though, since the sequential scale has linear ticks and it’s more verbose. So we could have a dedicated sequential-log class as a convenient way of setting the transform and tick/nice method:

z = d3.scaleSequentialLog(d3.interpolateBlues)
    .domain(domain)

That’s probably a good idea anyway because scaleSequentialLog would choose between transformLog and transformLogn automatically based on the domain.

With a convenience constructor, this is even shorter:

z = d3.scaleSequentialLog(domain, d3.interpolateBlues)

And we’d need scaleSequentialPow and scaleSequentialSqrt aliases too, and diverging ones, which is kind of a combinatorial explosion, but I think at least we could minimize the code duplication in the implementations.

@mbostock
Copy link
Member Author

It’s confusing that scaleLog supports scale.transform, given that setting the base or domain of a log scale will reset the transform back to transformLog or transformLogn. It maybe makes sense to hide scale.transform on scaleLog, but then what if you want to use transformSymlog with log ticks? (You probably don’t, since you’ll get no ticks if the domain spans zero, and if it doesn’t span zero, you probably don’t need the symlog transform.)

Similarly, it’s confusing that scaleLinear supports scale.transform, since if you set the transform to anything other than the identity transform, it’s no longer a true linear scale. Unless we mean that the ticks are uniformly-spaced, but that’s not a reasonable definition.

On the other hand, it seems reasonable to support scale.transform on scaleTime, since nothing in the name suggests that it’s linear. There’s still no obvious way to have log ticks on a time scale, but if you want a log transform, presumably you want scaleLog anyway?

Perhaps we should be thinking about this in terms of four orthogonal scale characteristics:

  • Input type (date or number)
  • Output class (values or function)
  • Tick generation, tick format, domain nicing (linear, log, or time)
  • Transform (fixed or configurable)

So, if our current transforms are fixed, we have:

Constructor Input Output Ticks Transform
scaleLinear number values linear linear
scalePow number values linear pow
scaleLog number values log log
scaleTime date values time linear
scaleSequential number function linear linear

(We can treat scaleSqrt as a special case of scalePow and scaleDiverging as a special case of scaleSequential.)

If we don’t expose configurable transforms, we could still add:

Constructor Input Output Ticks Transform
scaleSymlog number values linear symlog
scaleSequentialPow number function linear pow
scaleSequentialLog number function log log

I’m not sure whether it makes sense to offer transformed versions of scaleQuantize. At any rate, it feels pretty niche.

It’s probably better to start with specific transformed implementations (e.g., scaleSequentialPow, scaleSymlog), and we can expose custom transformations in the future when the value of that feature is more apparent.

@mbostock mbostock changed the title Arbitrary transforms for continuous scales. More transforms. Jan 25, 2019
@mbostock mbostock mentioned this pull request Jan 25, 2019
@mbostock mbostock mentioned this pull request Jan 25, 2019
65 tasks
This was referenced Jan 26, 2019
@mbostock mbostock changed the title More transforms. 2.2 Jan 26, 2019
Also clarify the documentation for outer padding.

Fixes #101.
Fixes #102.
Fixes #132.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant