Skip to content

Commit

Permalink
ref organ processing improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
bherr2 committed Sep 26, 2023
1 parent d073a54 commit 5ebe774
Showing 1 changed file with 40 additions and 56 deletions.
96 changes: 40 additions & 56 deletions src/normalization/normalize-ref-organ.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function normalizeRefOrganData(context) {
}

async function getRawData(context) {
const { path } = context.selectedDigitalObject;
const { path, doString } = context.selectedDigitalObject;

const metadata = readMetadata(context);

Expand All @@ -33,17 +33,15 @@ async function getRawData(context) {
header: true,
skipEmptyLines: true,
})
).data;
).data.filter((row) => row.OntologyID.trim() !== '-');

const dataUrl = Array.isArray(metadata.datatable) ? metadata.datatable[0] : metadata.datatable;

let data;
if (dataUrl.startsWith('http')) {
data = await processSpatialEntities(context, metadata, dataUrl, undefined, crosswalk);
} else {
// FIXME: Add deployment URL option to context
const baseUrl = 'https://ccf-ontology.hubmapconsortium.org/objects/v1.2/';
const gltfUrl = `${baseUrl}${dataUrl}`;
const gltfUrl = `${context.cdnIri}${doString}/assets/${dataUrl}`;

// Load local GLB file, but ensure that the URL is placed in the output
// for when it is deployed
Expand All @@ -60,10 +58,10 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw
const scalar = new Matrix4(Matrix4.IDENTITY).scale([1000, 1000, 1000]);
const nodes = await processSceneNodes(gltfFile, scalar, undefined, cache);

const baseIri = metadata.config?.id || context.selectedDigitalObject.iri;
const obj = context.selectedDigitalObject;
const baseIri = obj.iri;
const separator = baseIri?.indexOf('#') === -1 ? '#' : '_' ?? '#';

const parentIri = metadata.config?.parentIri || `${baseIri}${separator}Parent`;
const primaryId = `${baseIri}${separator}primary`;

return Object.values(nodes)
.filter((node) => excludeNodeType(node))
Expand All @@ -74,22 +72,21 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw
const primaryNodeId = crosswalk[0]['node_name'];
const id =
nodeId === primaryNodeId
? `${baseIri}${separator}primary`
? primaryId
: `${baseIri}${separator}${encodeURIComponent(nodeId)}`;
const creationDate = metadata.creation_date;
const T = { x: node.bbox.lowerBound.x, y: node.bbox.lowerBound.y, z: node.bbox.lowerBound.z };
const typeOf = crosswalk.reduce(
(accumulator, value) => {
const typeOf = [
...crosswalk.reduce((accumulator, value) => {
if (value['node_name'] === node['@id']) {
accumulator.push(value['OntologyID'].trim());
accumulator.add(value['OntologyID'].trim());
}
return accumulator;
},
['SpatialEntity']
);
}, new Set()),
].concat(['SpatialEntity']);

const organName = getOrganName(nodeId, crosswalk);
const organOwnerSex = getOrganOwnerSex(nodeId);
const organSide = getOrganSide(nodeId);
const { organOwnerSex, organSide } = getOrganMetadata(obj.name);
const nodeLabel = getNodeLabel(nodeId);
let organLabel = `${organOwnerSex} ${nodeLabel}`.trim();
if (organSide !== '') {
Expand All @@ -100,12 +97,21 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw
}
}

let parentIri = `${baseIri}${separator}Parent`;
if (organOwnerSex) {
parentIri = `https://purl.humanatlas.io/graph/ccf-body#VH${organOwnerSex}`;
}

return {
id,
label: `Spatial entity of ${organLabel}`,
pref_label: organName,
class_type: 'SpatialEntity',
typeOf: typeOf,
representation_of: typeOf[0],
organ_donor_sex: organOwnerSex || undefined,
organ_side: organSide || undefined,
reference_organ: primaryId,
creator: metadata.creators.map((c) => {
return {
id: `https://orcid.org/${c.orcid}`,
Expand All @@ -126,7 +132,7 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw

object_reference: {
id: `${id}Obj`,
label: `The 3D object of ${organLabel}`,
label: `3D object of ${organLabel}`,
class_type: 'SpatialObjectReference',
typeOf: ['SpatialObjectReference'],
file: gltfFile,
Expand All @@ -135,7 +141,7 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw

placement: {
id: `${id}ObjPlacement`,
label: `The local placement of ${organLabel}`,
label: `local placement of ${organLabel}`,
class_type: 'SpatialPlacement',
typeOf: ['SpatialPlacement'],
target: id,
Expand All @@ -161,7 +167,7 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw
placements: [
{
id: `${id}GlobalPlacement`,
label: `The global placement of ${organLabel}`,
label: `global placement of ${organLabel}`,
class_type: 'SpatialPlacement',
typeOf: ['SpatialPlacement'],
target: parentIri,
Expand All @@ -187,47 +193,20 @@ async function processSpatialEntities(context, metadata, gltfFile, cache, crossw
});
}

function getOrganMetadata(name) {
const sex = name.includes('female') ? 'Female' : name.includes('male') ? 'Male' : undefined;
const side = name.includes('left') ? 'Left' : name.includes('right') ? 'Right' : undefined;

const exclude = new Set(['left', 'right', 'male', 'female']);
const organName = name.split('-').filter(n => !exclude.has(n)).join(' ');
return { organOwnerSex: sex, organSide: side, organName };
}

function getOrganName(nodeId, crosswalk) {
const organ = crosswalk.filter((value) => value['node_name'] === nodeId);
return organ[0]['label'];
}

function getOrganOwnerSex(nodeId) {
let matching = nodeId.match(/^VH_(F|M)_([a-z_]+)_?([L|R]?)_?(.?)/);
let organOwnerSexIndex = 1;
if (matching === null) {
matching = nodeId.match(/^VH_(F|M)_([L|R])_([a-z_]+)_?(.?)/);
organOwnerSexIndex = 1;
}
if (matching !== null) {
const sexAbbreviation = matching[organOwnerSexIndex];
return sexAbbreviation === 'F' ? 'female' : 'male';
} else {
return '';
}
}

function getOrganSide(nodeId) {
let matching = nodeId.match(/^VH_(F|M)_([a-z_]+)_?([L|R]?)_?(.?)/);
let organSideIndex = 3;
if (matching === null) {
matching = nodeId.match(/^VH_(F|M)_([L|R])_([a-z_]+)_?(.?)/);
organSideIndex = 2;
}
if (matching !== null) {
const sideAbbreviation = matching[organSideIndex];
if (sideAbbreviation === 'L') {
return 'left';
} else if (sideAbbreviation === 'R') {
return 'right';
} else {
return '';
}
} else {
return '';
}
}

function getNodeLabel(nodeId) {
let matching = nodeId.match(/^VH_(F|M)_([a-z_]+)_?([L|R]?)_?(.?)/);
let organLabelIndex = 2;
Expand All @@ -242,6 +221,11 @@ function getNodeLabel(nodeId) {
organLabelIndex = 1;
partOrderIndex = 2;
}
if (matching === null) {
matching = nodeId.match(/^Allen_([a-z_]+)_?(.?)/);
organLabelIndex = 1;
partOrderIndex = 2;
}
if (matching !== null) {
const organLabel = matching[organLabelIndex].replaceAll('_', ' ').trim();
const partOrder = matching[partOrderIndex];
Expand Down

0 comments on commit 5ebe774

Please sign in to comment.