Skip to content

make facet indexes rectangular if they overlap #1068

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

Closed
wants to merge 2 commits into from

Conversation

Fil
Copy link
Contributor

@Fil Fil commented Oct 3, 2022

Yet another approach to the overlapping facet issue (alternatives: #1069, #1070).

Instead of reading the value of X for index i as X[i], we read it as X[i % X.length]. This allows to create "long" channels as rectangular representations of n * m values (n being the length of the data, and m the number of facets), where default channels are a "line" of n values. There is no need for a reindexation plan, since the addressing system doesn't need extra information to read the proper value when the index is "out of range".

Besides this change, only the transforms that need to care about overlapping facets need to be modified: stack, map, and dodge.

Performance. This works only if we are allowed to create a Uint32Array of length n*m — in some very specific cases (such as facets that overlap by pairs), it can break earlier than a subtler reindexing plan. Since it doesn't need to expand any existing channels, it should be faster and consume less memory in general.

(In the case of cumulative facets where each data point creates its own facet (which do not exist for now but will be created by time facets), this means we get a cap at something like 32k keyframes if we use one of the expanding transforms, such as stack or dodge).

Backward compatibility. Note that this will change the output if you used a column that had a length inferior to the data it covers. However, relying on this would have been a hack, which afaik was never used in the wild nor in our examples and tests. Furthermore, Plot's introduction of columnar channels explicitly mentions that a columnar channel is “an array of values of the same length as the data”.

Code aesthetics. It's a bit ugly that every lookup of a value in a channel has to be done with this "modulo length" operator. We could change this to a function get(X,i) for readability, but it's probably not that much more readable (only a bit less ugly), and maybe a bit slower. But happy to change if this looks nicer. It might also be something that we'd want to expose, for users who want to write their own reducers.

I'm not sure how to document this.

supersedes the first item of #1041, as well as #1057 and the other branches we were working on…

@Fil Fil requested a review from mbostock October 3, 2022 14:31
This was referenced Oct 3, 2022
Comment on lines 369 to 373
function union(facets) {
const U = new Set();
for (const f of facets) for (const i of f) U.add(i);
return U;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: optimize as in fc37827

@Fil
Copy link
Contributor Author

Fil commented Oct 5, 2022

Closing in favor of #169

@Fil Fil closed this Oct 5, 2022
@Fil Fil deleted the fil/rectangular-facets branch October 5, 2022 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant