-
Notifications
You must be signed in to change notification settings - Fork 187
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
exploring initializers composition #818
Conversation
1. Plot.selectFirst should be able to select the first hexbin 2. Plot.hexbin should be able to operate on scaled X and Y channels
Yeah, we definitely need to avoid a duplicate implementation (once as a “data transform” and the other as a “channel transform” a.k.a. “initializer”). I think the options here are either (1) data transforms always run before channel transforms, and hence you can’t run the select transform after the hexbin transform, or (2) we somehow generalize it so that data transforms and channel transforms are the same thing, and you can somehow have an arbitrary dependency graph for channels that depend on other channels. I expect that (2) would take us at least another month to figure out, so I am inclined to not attempt this at all and just treat data transforms as a different class of transform than channel transforms. Another thought is that we could throw an error (or issue a warning) if you apply them in the wrong order. E.g., the |
i've reverted the changes that made Plot.select work both as a data or a channel transform, and we now throw an error if a data transform is applied after a channel transform. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to implement initializer composition within the basic transform helper? My impression is that could be implemented in a separate helper like we did before. The basic
transform helper could still check that the incoming initialize option is nullish and error if any transform is specified.
Possibly, but the difficulty is that a channel transform can make use of both functions (in hexbin, transform is used to initialize the output reducers, and initialize to create the bins). So at least to check if it's ok to compose, it can't be done as two independent tests. 🤔 |
I don’t see the problem. The hexbin transform will declare both a transform (data transform) and an initializer (channel transform); the former will error if there’s already an initializer declared, which is what we want. (We don’t expect any initializers to run before the hexbin transform?) If someone tries to declare another transform (data transform) after the hexbin transform, that will also error because the hexbin transform declared an initializer. |
A concrete use case would be Plot.hexbin + Plot.dodgeY (which may or may not make sense from a dataviz standpoint). Maybe the problem here is that Plot.hexbin uses a data transform to initialize its reducers—it could probably do this in the initializer part of the code instead. I'm also starting to get lost between all the branches I have opened :) |
Yeah, the only reason the hexbin transform does this is that it needs access to the (possibly transformed) data, which is not normally passed to an initializer. If we passed Line 97 in bca32ba
|
Okay, done in 42ac4f0. Seem good? |
yes! |
const x = X.scale !== undefined ? scales[X.scale] : identity.transform; | ||
const y = Y.scale !== undefined ? scales[Y.scale] : identity.transform; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixing the behavior of the hexbin transform when identity scales are used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, no, since we still have scale objects when position scales use the identity scale type…
So this is instead respecting the incoming channel’s scale definition, rather than assuming that the x channel is bound to the x scale and the y channel is bound to the y scale. That’s interesting and I hadn’t considered that possibility; all the built-in marks bind x and y to the corresponding scales, but it is theoretically possible for a custom mark not too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that's for when you compose layouts, and the previous layout has returned channels that are already scaled. Typically hexbin + dodgeY leads to this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha. Thanks for the context.
b305131
to
886615b
Compare
Note: I've also tested merging this branch with
fil/reinitialize-dodge
and composing Plot.hexbin (Plot.dodgeX(…)).