-
Notifications
You must be signed in to change notification settings - Fork 7
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
Implement missing values vocabulary #143
Conversation
- clicking the button will now emit the update:missingValue event
- this is only implemented for row-mode - when the user declares a value to be missing in the interface by pressing the "missing value" button, this value will be hidden from the annotation view
- made non-reactive assignments to this.vocabularyMapping reactive - changed the logic for the button-enabling function to computed variable (hence requiring the reactivity) - refactored the deep object merge into a method (will have to be eventually refactored out of here so we can reuse across components)
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.
Aside from the handful of comments on the code itself and one significant interface error, all looks good.
The error has to do with this piece of functionality:
conversely, if a missing value is added back (e.g. designated not-missing), its mapping should be empty and the annotation status should reflect that (e.g. go from "complete" to "incomplete")
There exists a scenario where this breaks. Steps to reproduce:
- Mark a value as missing (on the diagnosis tab)
- Fill out all other non-missing vocabulary term boxes
- Place back the missing value (as not missing)
- Type in its box
- Observe that the "Save Annotation" button remains greyed out and that vocabulary term values (in some test cases) may be shifted to different boxes depending on the order of the initially removed value. Having all boxes filled out no longer enables the 'Save Annotation' button
I am also getting this warning from lines 553 and 575 in index.js
:
Could not find 'sex' in p_state.missingColumnValues. Will treat as not missing.
components/annot-vocabulary.vue
Outdated
saveButtonEnabled() { | ||
|
||
for ( const [columnName, columnMappings] of Object.entries(this.vocabularyMapping) ) { | ||
console.log("val", columnName, columnMappings) |
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.
Remove debug line?
components/annot-vocabulary.vue
Outdated
// The first time we find any mapped value that is neither non-empty nor missing, we return | ||
// a status of false. Otherwise, we return true. | ||
if ( | ||
// We use negate the first conditional tuple so that lazy evaluation of the two conditionals |
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.
It's not typical practice to insert a comment within a conditional statement. I suggest just moving this description above the if
statement.
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.
The comment is not referring to the if statement but to the logic inside the condition. Could you maybe give a reason why you think we should not put comments inside if statements?
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.
The short answer to this is precedent - it's just not common practice to do so. The better answer though is that the condition should be rewritten for clarity and in doing so likely not need as much commentary.
I believe this original comment
// The first time we find any mapped value that is neither non-empty nor missing, we return
// a status of false. Otherwise, we return true.
if (
// We use negate the first conditional tuple so that lazy evaluation of the two conditionals
// joined by && will skip the second conditional if uniqueValue is null. This is important
// because null doesn't have a .trim() method.
! ( mappedValue !== null && mappedValue.trim().length > 0 ) &&
( ! this.isMissingValue(columnName, uniqueValue) )
) {
return false;
}
Can also be written this way:
// If there is any mapped value that is empty or unique value that is not missing, we return false
if ( (mappedValue !== null && mappedValue.trim().length === 0) ||
!this.isMissingValue(columnName, uniqueValue) ) {
return false;
}
The reasoning for this as follows. If we map out how your original condition could succeed, we get the following:
mappedValue !== null && mappedValue.trim().length === 0 (T and F)
OR
mappedValue === null --> short-circuit out of evaluating second condition (F)
AND
this.isMissingValue(columnName, uniqueValue) === false
@surchs Can you provide some feedback here as to if I have correctly understood the intent of this condition?
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.
Oh, ok. Sorry, I didn't realize that this was a case of comments inside the if clause. Yeah, agreed. That's a mistake. Thanks for catching it. I read that wrong.
Can you provide some feedback here as to if I have correctly understood the intent of this condition?
Yes, almost. I think
mappedValue.trim().length === 0
should be mappedValue.trim().length > 0
as before because a length of 0
would imply an empty string. But with that addition, I agree that your way of writing it is a lot clearer because we get rid of the double negative!
edit: hold on a sec, I think I confused myself 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.
Ah, hold on. Now I confused myself (goes to show that the if clause needs cleaning). The idea is that we want to turn on/make available the NEXT button when all unique values have been either mapped or declared missing.
So for a uniqueValue
, if
the corresponding mappedValue
is NOT set (i.e. is null
) OR is empty (i.e. is an empty string with length zero)
AND
the uniqueValue
has not been marked as a missingValue
THEN
this tells me that at least one value remains unmapped and the button shouldn't be enabled.
(this is the intent, not the literal code)
The problem is that we can't write it like that because if
mappedValue === null
is true, then we'll go on to evaluate mappedValue.trim(appedValue !== null).length > 0
and then crash because a null object doesn't have a trim()
method.
Your version does a different thing:
if ( (mappedValue !== null && mappedValue.trim().length === 0) ||
!this.isMissingValue(columnName, uniqueValue) ) {
for a uniqueValue
, if
the corresponding mappedValue
IS set (i.e. is NOT null
) BUT is empty (i.e. is an empty string with length zero)
OR
the uniqueValue
has not been marked as a missingValue
THEN
we consider the annotation not complete and the button to not be enabled. But this is not correct, the OR
here is wrong.
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, yes, I think this is going to be it, with one minor change (length > 0
-> length === 0
):
if ( ( mappedValue === null || (mappedValue !== null && mappedValue.trim().length === 0) ) &&
!this.isMissingValue(columnName, uniqueValue ) {
return false;
}
And then maybe add a comment on why we cannot just do
if ( ( mappedValue === null || mappedValue.trim().length === 0 ) && ...
so that we don't accidentally "improve" it later and get surprised when things break.
Very cool, thanks for thinking through this!
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.
It had to get done! Good talking through.
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 @surchs
if ( ( mappedValue === null || mappedValue.trim().length === 0 ) && ...
should work given that if mappedValue
is null
it won't check the second condition once mappedValue === null
evaluates to true. But of course, mappedValue !== null
can be left in for clarity even if it's redundant
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.
Ah, that's right. I didn't think about this because now we have turned the statement from !==
to ===
. OK, in that case I think it is really clear, we might not even need a comment. Look at that!
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.
Excellent work. Exactly where we want it to be.
components/annot-vocabulary.vue
Outdated
|
||
// Initialize the mapping of all unique values as null | ||
this.initializeMapping(); | ||
}, | ||
|
||
methods: { | ||
|
||
declareMissing(p_row) { | ||
|
||
console.log("please declare", p_row, "missing") |
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.
Remove debug?
I can reproduce the behaviour, but I think it is a display bug. The internal state is correctly represented, but the text boxes are not. Try this:
I think this happens because the text fields are not using dynamic ids and are generally not hooked up to the store. This is a problem we currently have for all of the annotation components. Not sure how to proceed. On the one hand I'd like to handle the visual = state problem in a future PR with #128 . On the other hand it's a bad idea to merge things that are not working as intended. I think I still lean towards having this go in with the display bug now so we can start building with the internal functionality (that is working correctly as far as I can tell) and address the visual issues in parallel. Wdyt @jarmoza |
My initial reaction is that we (you) should spend a little bit of time trying that ID fix to see if it resolves the issue. I'd have to take a look at the code before I could suggest other ideas. I agree it's bad to merge something broken - but this should also not become a blocker for this week's/upcoming work. The stipulation is that this bug is written up into an issue and not lost. |
This line is likely from a previous implementation where `tableItems` was a data field. Since it is now a computed property.
Thanks for the commits @jarmoza! I can confirm that this takes care of the wandering label issue for the vocabulary mapper! The weird thing though is that the text fields still reset to empty when I navigate away and back to the annotation tab. I'll take another look to see if I can fix that with your v-model solution! |
Thanks @jarmoza. looks good to merge to me! Thanks a lot for taking care of the v-model |
This PR adds a UI element to the diagnosis (vocabulary) component to declare values missing and hook these actions up to the global store.
Work done:
Resolves #121