Skip to content

Commit

Permalink
[ENH] Update object sorting, and begin sub and participantInfo revamp
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Levitas committed Mar 12, 2024
1 parent d7642af commit 057c4b1
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 94 deletions.
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
**/node_modules
.vscode/*
api/*.js
api/*.js.map
api/*.js.map
handler/convert.js
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode/settings.json
node_modules
ui/node_modules
ui/src/components/modalityForm.vue
ui/src/components/modalityForm.vue
handler/convert.js
15 changes: 10 additions & 5 deletions handler/convert.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions handler/ezBIDS_core/ezBIDS_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ def generate_dataset_list(uploaded_files_list, exclude_data):
image = nib.load(img_file)
ndim = image.ndim

# Check for RepetitionTime (TR) if not in JSON metadata and if so, add to file
# If RepetitionTime (TR) not in JSON metadata, add to file
if repetition_time == 0:
if len(image.header.get_zooms()) == 4:
repetition_time = image.header.get_zooms()[-1]
Expand Down Expand Up @@ -1425,7 +1425,8 @@ def determine_sub_ses_IDs(dataset_list, bids_compliant):
"age": x["PatientAge"],
"handedness": x["PatientHandedness"],
"PatientName": x["PatientID"],
"PatientID": x["PatientName"]
"PatientID": x["PatientName"],
"FileDirectory": x["file_directory"]
} for x in sub_dics_list)[0]

participants_info.update({str(x["subject_idx"]): phenotype_info})
Expand Down
36 changes: 29 additions & 7 deletions ui/src/Participant.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
</tr>
</thead>
<tbody>
<!-- <tr v-for="info in finalSubs" :key="info">
<th>{{ 'sub-' + info.subID }}</th>
<td v-for="(column, key) in ezbids.participantsColumn" :key="key">
<el-input v-model.trim="ezbids.participantsInfo[info.subIdx][key]" size="mini" />
</td>
</tr> -->
<tr v-for="subject_idx in finalSubs" :key="subject_idx">
<th>{{ 'sub-' + ezbids.subjects[subject_idx].subject }}</th>
<td v-for="(column, key) in ezbids.participantsColumn" :key="key">
Expand All @@ -72,7 +78,7 @@ import { mapState } from 'vuex';
import { defineComponent } from 'vue';
import { OrganizedSubject } from './store';
import { validateParticipantsInfo } from './libUnsafe';
// import { updateParticipantsInfo } from './libUnsafe';
//element-plus icons are bad .. replace it with fontawesome
// @ts-ignore
Expand All @@ -93,6 +99,20 @@ export default defineComponent({
...mapState(['ezbids', 'config']),
//...mapGetters(['findSubjectFromString']),
// //only show subjects that are really used (not excluded)
// finalSubs() {
// let finalSubs: any = [];
// this.ezbids._organized.forEach((sub: OrganizedSubject) => {
// let use = false;
// sub.sess.forEach((ses) => {
// if (ses.objects.some((o) => !o._exclude)) use = true;
// });
// if (use) finalSubs.push({ subIdx: sub.subject_idx, subID: sub.sess[0].objects[0]._entities.subject });
// });
// console.log('finalSubs', finalSubs);
// return finalSubs;
// },
//only show subjects that are really used (not excluded)
finalSubs() {
let finalSubs = [] as number[];
Expand All @@ -109,9 +129,11 @@ export default defineComponent({
created() {
//initialize
// TODO: don't need this I think if we're updating participants Info due to user changes in UI.
this.ezbids._organized.forEach((o: OrganizedSubject) => {
if (!this.ezbids.participantsInfo[o.subject_idx]) this.ezbids.participantsInfo[o.subject_idx] = {};
});
// this.ezbids.participantsInfo = updateParticipantsInfo(this.ezbids);
},
methods: {
Expand Down Expand Up @@ -143,12 +165,12 @@ export default defineComponent({
isValid(cb: (v?: string) => void) {
this.validate();
let errors = validateParticipantsInfo(this.ezbids);
if (errors.length) {
for (const e of errors) {
return cb(e);
}
}
// let errors = validateParticipantsInfo(this.ezbids);
// if (errors.length) {
// for (const e of errors) {
// return cb(e);
// }
// }
cb();
},
},
Expand Down
183 changes: 112 additions & 71 deletions ui/src/libUnsafe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import aslYaml from '../src/assets/schema/rules/sidecars/asl.yaml';
import petYaml from '../src/assets/schema/rules/sidecars/pet.yaml';

import metadata_types from '../src/assets/schema/rules/sidecars/metadata_types.yaml';
import { faNewspaper } from '@fortawesome/free-solid-svg-icons';

//deepEqual and isPrimitive functions come from https://stackoverflow.com/a/45683145
export function deepEqual(obj1: any, obj2: any) {
Expand Down Expand Up @@ -1678,77 +1679,77 @@ export function fileLogicLink($root: IEzbids, o: IObject) {
}
}

// TODO, currently no validation on Participants Info page
export function validateParticipantsInfo($root: IEzbids) {
let finalSubs = [] as number[];
$root._organized.forEach((sub: OrganizedSubject) => {
let use = false;
sub.sess.forEach((ses) => {
if (ses.objects.some((o) => !o._exclude)) use = true;
});
if (use) finalSubs.push(sub.subject_idx);
});

let errors: string[] = [];
let participantsInfo: any = $root.participantsInfo;
Object.entries($root.subjects).forEach(([key, value]) => {
let subject: string = value.subject;
let columnInfo: any = participantsInfo[key];
Object.entries(columnInfo).forEach(([col, val]) => {
let v: string | any = val;
if (!['PatientName', 'PatientID'].includes(col)) {
if (val !== 'n/a') {
if (col === 'age' && !/^[0-9]*$/.test(v)) {
errors.push('Subject ' + subject + ': The age column has non-numeric values, please fix');
} else if (
col === 'sex' &&
![
'male',
'm',
'M',
'MALE',
'Male',
'female',
'f',
'F',
'FEMALE',
'Female',
'other',
'o',
'O',
'OTHER',
'Other',
].includes(v)
) {
errors.push('Subject ' + subject + ': The sex column has an improper term, please fix');
} else if (
col === 'handedness' &&
![
'left',
'l',
'L',
'LEFT',
'Left',
'right',
'r',
'R',
'RIGHT',
'Right',
'ambidextrous',
'a',
'A',
'AMBIDEXTROUS',
'Ambidextrous',
].includes(v)
) {
errors.push('Subject ' + subject + ': The handedness column has an improper term, please fix');
}
}
}
});
});
return errors;
}
// // TODO, currently no validation on Participants Info page
// export function validateParticipantsInfo($root: IEzbids) {
// let finalSubs = [] as number[];
// $root._organized.forEach((sub: OrganizedSubject) => {
// let use = false;
// sub.sess.forEach((ses) => {
// if (ses.objects.some((o) => !o._exclude)) use = true;
// });
// if (use) finalSubs.push(sub.subject_idx);
// });

// let errors: string[] = [];
// let participantsInfo: any = $root.participantsInfo;
// Object.entries($root.subjects).forEach(([key, value]) => {
// let subject: string = value.subject;
// let columnInfo: any = participantsInfo[key];
// Object.entries(columnInfo).forEach(([col, val]) => {
// let v: string | any = val;
// if (!['PatientName', 'PatientID'].includes(col)) {
// if (val !== 'n/a') {
// if (col === 'age' && !/^[0-9]*$/.test(v)) {
// errors.push('Subject ' + subject + ': The age column has non-numeric values, please fix');
// } else if (
// col === 'sex' &&
// ![
// 'male',
// 'm',
// 'M',
// 'MALE',
// 'Male',
// 'female',
// 'f',
// 'F',
// 'FEMALE',
// 'Female',
// 'other',
// 'o',
// 'O',
// 'OTHER',
// 'Other',
// ].includes(v)
// ) {
// errors.push('Subject ' + subject + ': The sex column has an improper term, please fix');
// } else if (
// col === 'handedness' &&
// ![
// 'left',
// 'l',
// 'L',
// 'LEFT',
// 'Left',
// 'right',
// 'r',
// 'R',
// 'RIGHT',
// 'Right',
// 'ambidextrous',
// 'a',
// 'A',
// 'AMBIDEXTROUS',
// 'Ambidextrous',
// ].includes(v)
// ) {
// errors.push('Subject ' + subject + ': The handedness column has an improper term, please fix');
// }
// }
// }
// });
// });
// return errors;
// }

export function metadataAlerts(
bidsDatatypeMetadata: MetadataFields,
Expand Down Expand Up @@ -1969,3 +1970,43 @@ export function metadataAlerts(
// console.log('typo', typoFields);
return metadataAlertFields;
}

// //TODO: Need to work on this more
// export function updateParticipantsInfo($root: IEzbids) {
// let participantsInfo: any = $root.participantsInfo;
// console.log('participantsInfo', participantsInfo);
// let finalSubs: any = [];
// $root._organized.forEach((sub: OrganizedSubject) => {
// let use = false;
// sub.sess.forEach((ses) => {
// if (ses.objects.some((o) => !o._exclude)) use = true;
// });
// if (use) finalSubs.push({ subIdx: sub.subject_idx, subID: sub.sess[0].objects[0]._entities.subject });
// });

// let newParticipantsInfo: any = {};
// if (Object.keys(participantsInfo).length < finalSubs.length) {
// // Only an issue when the final number of subjects is greather than the original participantsInfo length

Check failure on line 1989 in ui/src/libUnsafe.ts

View workflow job for this annotation

GitHub Actions / Check for spelling errors

greather ==> greater
// let idx_counter = 0;

// for (let key of Object.keys(finalSubs)) {
// let info = finalSubs[key];
// // console.log('info', info);
// let participantsInfoRef = participantsInfo[info.subIdx];
// // console.log(participantsInfoRef);
// newParticipantsInfo[idx_counter] = participantsInfoRef;
// idx_counter += 1;
// let subObjs = $root.objects.filter((e) => e._entities.subject === info.subID);
// let subObjsIdx = subObjs[0].subject_idx.toString();
// if (subObjsIdx !== key) {
// subObjs.forEach((o: IObject) => {
// o.subject_idx = Number(key);
// });
// }
// $root._organized[key].subject_idx = Number(key);
// console.log('new', newParticipantsInfo);
// }
// }
// console.log('root', $root);
// return newParticipantsInfo;
// }
14 changes: 7 additions & 7 deletions ui/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,15 +597,15 @@ const store = createStore({

//sort object by subject / session / series # / json path
state.ezbids.objects.sort((a, b) => {
const asub_idx = a.subject_idx;
const bsub_idx = b.subject_idx;
if (asub_idx != bsub_idx) return asub_idx - bsub_idx;
const asub_id = a._entities.subject;
const bsub_id = b._entities.subject;
if (asub_id !== bsub_id) return asub_id.localeCompare(bsub_id);

const ases_idx = a.session_idx;
const bses_idx = b.session_idx;
if (ases_idx != bses_idx) return ases_idx - bses_idx;
const ases_id = a._entities.session;
const bses_id = b._entities.session;
if (ases_id !== bses_id) return ases_id.localeCompare(bses_id);

// Shouldn't use this anymore, use AcquisitionTime instead
// NOTE: Shouldn't use this anymore, use AcquisitionTime instead (more thorough)
// const amodseriesnum = a.ModifiedSeriesNumber;
// const bmodseriesnum = b.ModifiedSeriesNumber;
// if (amodseriesnum && bmodseriesnum && amodseriesnum != bmodseriesnum)
Expand Down

0 comments on commit 057c4b1

Please sign in to comment.