-
Notifications
You must be signed in to change notification settings - Fork 593
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
Support field
in condition
#1980
Conversation
- Conditional as a generic type for conditional channelDef - Condition as a generic type of channelDef with `selection` predicate
45fcf6b
to
4fe69f8
Compare
…annelDef.condition)` if applicable - Introduce - `getFieldDef()` which returns the fieldDef -- either from the outer channelDef or from the condition of channelDef - `hasConditionFieldDef()` and `isConditionalDef()`
4fe69f8
to
323e4bb
Compare
ff059d7
to
a789df8
Compare
- Correct type signature for subsets of Channel (SingleDefChannel, ScaleChannel, etc.) - Remove outdated logic for row/column's axis (we no longer use axis for row/column -- and use header instead!) - Make model.fieldDef() references check for undefined
a789df8
to
584361b
Compare
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.
Hurrah 🎉 for this PR! The changes look good to me. I've left minor questions/comments throughout that may yield some cleaner code paths.
src/fielddef.ts
Outdated
*/ | ||
export function hasConditionFieldDef<F>(channelDef: ChannelDef<F>): channelDef is (ValueDef<any> & {condition: FieldDef<F>}) { | ||
return !!channelDef && !!channelDef.condition && isFieldDef(channelDef.condition); | ||
} | ||
|
||
export function isFieldDef<F>(channelDef: ChannelDef<F>): channelDef is FieldDef<F> | PositionFieldDef<F> | LegendFieldDef<F, any> | OrderFieldDef<F> | TextFieldDef<F> { | ||
return !!channelDef && (!!channelDef['field'] || channelDef['aggregate'] === 'count'); |
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.
getFieldDef
below looks good, but I'm curious why isFieldDef
doesn't account for a Conditional
field def?
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.
Relatedly, I see that several isFieldDef
calls have been replaced with getFieldDef
to account for the conditional. If there's a difference in how the two should be used/what they should check for, perhaps we can name them more clearly to reflect that? Unfortunately I don't have suggestions yet because I don't grasp the difference, sorry!
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.
Yeah, say a channelDef could be
- FieldDef (with no condition)
- FieldDef with ConditionValueDef
(1 & 2 are ConditionalFieldDef
as I make condition?
so I don't have to declare too many types)
- ValueDef (with no condition)
- ValueDef with ConditionFieldDef
- ValueDef with ConditionValueDef
(3-5 are ConditionalValueDef
as I make condition?
so I don't have to declare too many types)
- ConditionFieldDef only (akin to if without else)
- ConditionValueDef only
(6-7 are ConditionOnlyDef
)
isFieldDef
is more scoped to one object and can check if the object is a fieldDef.
The input can be either:
- a) the parent object of a channelDef (
encoding.<channel>
), which will returntrue
for 1 or 2, - b) the condition object of a channelDef (
encoding.<channel>.condition
), which will return true for case 4 or 6.
On the other hand, getFieldDef
is for getting the fieldDef
from a channelDef.
Given a channelDef (from encoding.<channel>
), this will return either the parent channelDef object (for case 1 or 2) or its condition object (for case 4 or 6).
In a way, getFieldDef is more like getFieldDefFromChannelDef
but it is kinda verbose, so I just chose the brief getFieldDef. That said, I agree that it can be confusing.
If you have better name suggestions, let me know :)
build/vega-lite-schema.json
Outdated
@@ -1032,32 +1032,47 @@ | |||
"$ref": "#/definitions/CompositeUnitSpecAlias", | |||
"description": "Unit spec that can have a composite mark." | |||
}, | |||
"Condition<(string|number)>": { | |||
"additionalProperties": false, | |||
"Condition<(LegendFieldDef<Field,number>|ValueDef<number>)>": { |
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.
Reminder to update rename-schema
for these keys.
@@ -156,10 +156,13 @@ export class UnitModel extends ModelWithField { | |||
if (isFieldDef(channelDef)) { | |||
fieldDef = channelDef; | |||
specifiedScale = channelDef.scale; | |||
} else if (isConditionalDef(channelDef) && isFieldDef(channelDef.condition)) { | |||
fieldDef = channelDef.condition; | |||
specifiedScale = channelDef.condition.scale; |
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.
Could these first two branches be consolidated using the new getFieldDef
method?
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.
Yeah I tried this earlier too. However, TypeScript won't know that channelDef.condition
is not only a FieldDef
, but also a ScaleFieldDef
. So we either have to do type casting or have to do this and I generally prefer to avoid casting.
_legend[channel] = {...legendSpec}; | ||
if (channelDef) { | ||
const legend = isFieldDef(channelDef) ? channelDef.legend : | ||
(channelDef.condition && isFieldDef(channelDef.condition)) ? channelDef.condition.legend : null; |
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.
Similarly, here, rather than multiple ternaries depending on where the fieldDef
might be, could this be simplified with a single getFieldDef
call?
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.
Similar to #1980 (comment), TS won't know that this is a LegendFieldDef
, not just FieldDef
.
src/channel.ts
Outdated
@@ -55,6 +55,10 @@ export const TOOLTIP = Channel.TOOLTIP; | |||
export const CHANNELS = [X, Y, X2, Y2, ROW, COLUMN, SIZE, SHAPE, COLOR, ORDER, OPACITY, TEXT, DETAIL, TOOLTIP]; | |||
const CHANNEL_INDEX = toSet(CHANNELS); | |||
|
|||
export const SINGLE_DEF_CHANNELS = [X, Y, X2, Y2, ROW, COLUMN, SIZE, SHAPE, COLOR, OPACITY, TEXT, TOOLTIP]; |
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.
What is a "single def" channel? Perhaps a comment to explain what this class of channels is and why it's needed?
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.
Good catch.
I'll add
/**
* Channels cannot have an array of channelDef.
* model.fieldDef, getFieldDef only work for these channels.
*
* (The only two channels that can have an array of channelDefs are "detail" and "order".
* Since there can be multiple fieldDefs for detail and order, getFieldDef/model.fieldDef
* are not applicable for them. Similarly, selection projecttion won't work with "detail" and "order".)
*/
return false; | ||
} | ||
|
||
export function grid(model: UnitModel, channel: SpatialScaleChannel, isGridAxis: boolean) { |
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.
For my edification, why do we no longer skip grid for ROW
and CHANNEL
?
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.
With the new layout operator, we no longer use axes for row/column but use layout header instead. Here I basically forgot to remove the code.
// Binned fields should capture extents, for a range test against the raw field. | ||
return model.fieldDef(channel).bin ? (bins[p.field] = 1, | ||
// FIXME: Arvind -- please log proper warning when the specified encoding channel has no field |
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.
Good catch!
build/vega-lite-schema.json
Outdated
], | ||
"type": "object" | ||
}, | ||
"Condition<(LegendFieldDef|ValueDef<string>)>": { |
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.
@domoritz looks like we have a bug in the schema generator?
Some properties are missing here
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.
(None of the properties from LegendFieldDef
or ValueDef
are here at all.)
d3e0e21
to
ddf2317
Compare
5311e14
to
61a62d7
Compare
1) Avoid schema generator bug (cc: @domoritz) 2) Produce better schema Also update rename script
0e5925f
to
28a18bc
Compare
I got |
@arvind -- I added a few more commits to simplify the schema. |
Travis is detecting differences with the schema. Is that due to the issue you mention above? |
ba37042
to
012807d
Compare
@arvind I don't think so. I just force push an update. looks like I somehow forgot to commit the diff. |
Note that we can update the schema and remove b82b8ab in a separate PR. |
Follow up from #1971.
It's probably more natural to do the following way in many cases:
Currently this PR only contains interface changes, but haven't make it work.
This will require a major refactor since we can no longer just refer to
encoding.<channel>.field
for accessing field, so I'm gonna punt on it for now.