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

autoSpec #1284

Merged
merged 12 commits into from
Feb 27, 2023
Merged

autoSpec #1284

merged 12 commits into from
Feb 27, 2023

Conversation

tophtucker
Copy link
Contributor

@tophtucker tophtucker commented Feb 17, 2023

Factors out the parts of the auto mark that fill in its options. Produces an object that you can pass as a fully-specified Plot.auto options object.

As an optimization, there are two versions:

  • the internal spec function optionally returns the materialized columns, so that Plot.auto doesn't have to re-materialize them in order to determine the implementation of the marks
  • the exported autoSpec function, which calls spec but doesn't return the materialized columns

So, calling Plot.auto will still only materialize columns once; calling Plot.auto(data, Plot.autoSpec(data, options)) will materialize them twice.

Optional to-dos, I'm not sure they're necessary for now:

  • Investigate making all undefineds into nulls
  • More tests. I have a couple just for autoSpec but am still mostly relying on the usual mark snapshots
  • Bring zero and z assignments up from auto to autoSpec?

@tophtucker tophtucker requested review from Fil and mbostock February 17, 2023 15:14
@tophtucker tophtucker changed the title First draft of autoSpec autoSpec Feb 17, 2023
@Fil
Copy link
Contributor

Fil commented Feb 17, 2023

I'd suggest we make the tests much more stringent, by comparing their serialized version to a template (which can be in a separate file on disk, or in the unit test page).

For example instead of testing

it("Plot.autoSpec makes a histogram from a quantitative dimension", () => {
  const data = [{value: 1}, {value: 1}, {value: 38}];
  const A = Plot.autoSpec(data, {x: "value"});
  assert.strictEqual(A.y.reduce, "count");
  assert.strictEqual(A.mark, "bar");
});

we do:

it("Plot.autoSpec makes a histogram from a quantitative dimension", () => {
  assert.strictEqual(JSON.stringify(Plot.autoSpec([{value: 1}, {value: 1}, {value: 38}], {x: "value"})), `{ expected spec }`);
});

of course this could be a nice function if we want to keep it readable.

@mbostock
Copy link
Member

Why not use assert.deepStrictEqual?

@@ -91,7 +86,7 @@ export function auto(data, {x, y, color, size, fx, fy, mark} = {}) {
// Determine the default mark type.
if (mark === undefined) {
mark =
sizeValue != null || sizeReduce != null
size != null || sizeReduce != null
Copy link
Member

Choose a reason for hiding this comment

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

What is this change doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At one point in refactoring, I didn't have a reference to sizeValue here, and it seemed inconsistent to refer to x and y (not xValue and yValue) below, but sizeValue (not size) here, so I changed it. Upon further reflection, if sizeValue is undefined / null, then size will be undefined / null, so it doesn't matter. I'll revert this.

Copy link
Member

Choose a reason for hiding this comment

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

I think it’ll be clearer if we store the materialized columns as a separate array, rather than redefining local variables/function arguments. I’ll incorporate into this into a commit I’m about to push.

fx,
fy,
mark
} = spec(data, initialOptions, {materialize: true});
Copy link
Member

Choose a reason for hiding this comment

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

A different way we can do this (without requiring an internal option and separate function) is to materialize the values as arrays, and then pass them into autoSpec; this way valueof does nothing (it returns the existing arrays). I’ll take a crack at this and push a commit if it works.

return {
x: {
...(materialize ? {value: x} : xValue !== undefined && {value: xValue}),
...(xReduce !== undefined && {reduce: xReduce}),
Copy link
Member

Choose a reason for hiding this comment

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

I think it might be clearer to return null here to fully realize the defaults. I’ll try that and see.

Copy link
Contributor Author

@tophtucker tophtucker left a comment

Choose a reason for hiding this comment

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

TIL "??=". Thanks for simplifying back to one function and for tackling the "return something that's defined one way or the other" thing!

@tophtucker tophtucker merged commit 9c52b94 into main Feb 27, 2023
@tophtucker tophtucker deleted the toph/autospec branch February 27, 2023 22:41
chaichontat pushed a commit to chaichontat/plot that referenced this pull request Jan 14, 2024
* first draft of autospec

* more stringent tests

* exported autoSpec doesn't return materialized columns; internal spec function does

* fix tests

* revert useless change

* normalize & materialize prior to autoSpec

* materializeValues

* preTTieR

* lazy materialization for autoSpec

* move comment

* zero comments

* nullish comments

---------

Co-authored-by: Mike Bostock <mbostock@gmail.com>
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.

3 participants