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

Support phylogenies and phyloreferences that cannot be parsed #308

Merged
merged 8 commits into from
Mar 17, 2024
Merged
12 changes: 8 additions & 4 deletions src/components/modals/AdvancedOptionsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,15 @@ export default {
// Exports the PHYX file as an OWL/JSON-LD file, which can be opened in
// Protege or converted into OWL/XML or other formats.
const wrapped = new PhyxWrapper(this.$store.state.phyx.currentPhyx);
const content = [JSON.stringify([wrapped.asJSONLD()], undefined, 4)];
try {
const content = [JSON.stringify([wrapped.asJSONLD()], undefined, 4)];

// Save to local hard drive.
const jsonldFile = new File(content, 'download.jsonld', { type: 'application/json;charset=utf-8' });
saveAs(jsonldFile);
// Save to local hard drive.
const jsonldFile = new File(content, `${this.$store.getters.getDownloadFilenameForPhyx}.jsonld`, { type: 'application/json;charset=utf-8' });
saveAs(jsonldFile, `${this.$store.getters.getDownloadFilenameForPhyx}.jsonld`);
} catch (err) {
alert(`Could not convert Phyx to JSON-LD: ${err}`);
}
},
},
};
Expand Down
22 changes: 22 additions & 0 deletions src/components/phylogeny/PhylogenyView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,13 @@ export default {

// Look for an unbalanced Newick string.
let parenLevels = 0;
let singleQuoteCount = 0;
let doubleQuoteCount = 0;
for (let x = 0; x < newickTrimmed.length; x += 1) {
if (newickTrimmed[x] === '(') parenLevels += 1;
if (newickTrimmed[x] === ')') parenLevels -= 1;
if (newickTrimmed[x] === '\'') singleQuoteCount += 1;
if (newickTrimmed[x] === '"') doubleQuoteCount += 1;
}

if (parenLevels !== 0) {
Expand All @@ -254,6 +258,24 @@ export default {
});
}

if (singleQuoteCount % 2 > 0) {
errors.push({
title: "Unbalanced single quotes (') in Newick string",
message:
`Every single quote should be closed by another single quote, but this Newick string has ` +
`${singleQuoteCount} single quotes. Try doubling the single quote to escape it.`,
});
}

if (doubleQuoteCount % 2 > 0) {
errors.push({
title: 'Unbalanced double quotes (") in Newick string',
message:
`Every double quote should be closed by another double quote, but this Newick string has ` +
`${doubleQuoteCount} double quotes. Try doubling the double quote to escape it.`,
});
}

// Finally, try parsing it with parseNewick and see if we get an error.
try {
parseNewick(newickTrimmed);
Expand Down
12 changes: 8 additions & 4 deletions src/components/phylogeny/Phylotree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,14 @@ export default {
return this.phylogeny.newick || "()";
},
parsedNewick() {
return new PhylogenyWrapper(this.phylogeny).getParsedNewickWithIRIs(
this.$store.getters.getPhylogenyId(this.phylogeny),
newickParser
);
try {
return new PhylogenyWrapper(this.phylogeny).getParsedNewickWithIRIs(
this.$store.getters.getPhylogenyId(this.phylogeny),
newickParser
);
} catch {
return undefined;
}
},
newickErrors() {
// Check to see if the newick could actually be parsed.
Expand Down
10 changes: 7 additions & 3 deletions src/components/phyloref/PhylorefView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -648,14 +648,18 @@ export default {
},
getNodeLabels(phylogeny, nodeType) {
// Return a list of node labels in a particular phylogeny.
return new PhylogenyWrapper(phylogeny).getNodeLabels(nodeType).sort();
try {
return new PhylogenyWrapper(phylogeny).getNodeLabels(nodeType).sort();
} catch {
return [];
}
},
getExpectedNodeLabel(phylogeny) {
// Return the node label we expect this phyloref to resolve to on the
// specified phylogeny.
return this.$store.getters.getExpectedNodeLabel(
this.selectedPhyloref,
phylogeny,
this.selectedPhyloref,
phylogeny,
);
},
getSpecifierLabel(specifier) {
Expand Down
17 changes: 11 additions & 6 deletions src/components/phyx/PhyxView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,21 @@ export default {
getPhylorefExpectedNodeLabel(phyloref, phylogeny) {
// Return a list of nodes that a phyloreference is expected to resolve to.
return this.$store.getters.getExpectedNodeLabel(
phyloref,
phylogeny,
phyloref,
phylogeny,
);
},
getNodesById(phylogeny, nodeId) {
// Return all node labels with this nodeId in this phylogeny.
const parsed = new PhylogenyWrapper(phylogeny).getParsedNewickWithIRIs(
this.$store.getters.getPhylogenyId(phylogeny),
newickParser,
);
let parsed;
try {
parsed = new PhylogenyWrapper(phylogeny).getParsedNewickWithIRIs(
this.$store.getters.getPhylogenyId(phylogeny),
newickParser,
);
} catch {
return [];
}

function searchNode(node, results = []) {
if (has(node, '@id') && node['@id'] === nodeId) {
Expand Down
55 changes: 38 additions & 17 deletions src/components/sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,26 @@ export default {
url: 'examples/fisher_et_al_2007.json',
title: 'Fisher et al, 2007',
},
{
url: 'examples/testudinata_phylonym.json',
title: 'Testudinata from Phylonym',
},
{
url: "examples/testudinata_phylonym.json",
title: "Testudinata from Phylonym",
},
];
},
wrappedPhyx() {
return new PhyxWrapper(
this.$store.state.phyx.currentPhyx,
newickParser
);
},
wrappedPhyxAsJSONLD() {
try {
return this.wrappedPhyx.asJSONLD();
} catch (err) {
alert(`Could not convert Phyx to JSON-LD: ${err}`);
return undefined;
}
},
...mapGetters([
'phyxTitle',
]),
Expand Down Expand Up @@ -416,8 +430,9 @@ export default {
downloadAsJSONLD() {
// Exports the PHYX file as an OWL/JSON-LD file, which can be opened in
// Protege or converted into OWL/XML or other formats.
const wrapped = new PhyxWrapper(this.$store.state.phyx.currentPhyx);
const content = [JSON.stringify([wrapped.asJSONLD()], undefined, 4)];
const jsonld = this.wrappedPhyxAsJSONLD;
if (!jsonld) return;
const content = [JSON.stringify([jsonld], undefined, 4)];

// Save to local hard drive.
const jsonldFile = new File(content, `${this.downloadFilenameForPhyx}.jsonld`, { type: 'application/json;charset=utf-8' });
Expand All @@ -427,15 +442,19 @@ export default {
downloadAsNQuads() {
// Exports the PHYX file as an OWL/N-Quads file, which can be opened in
// Protege or converted into other RDF formats.
const wrapped = new PhyxWrapper(this.$store.state.phyx.currentPhyx);
const wrapped = this.wrappedPhyx;

// TODO: we need a baseIRI here because of https://github.com/phyloref/phyx.js/issues/113
// Once that is fixed in phyx.js, we can remove it here.
wrapped.toRDF('https://example.phyloref.org/phyx#').then((content) => {
// Save to local hard drive.
const nqFile = new File([content], `${this.downloadFilenameForPhyx}.owl`, { type: 'application/n-quads;charset=utf-8' });
saveAs(nqFile, `${this.downloadFilenameForPhyx}.owl`);
});
try {
wrapped.toRDF('https://example.org/phyx#').then((content) => {
// Save to local hard drive.
const nqFile = new File([content], `${this.downloadFilenameForPhyx}.owl`, {type: 'application/n-quads;charset=utf-8'});
saveAs(nqFile, `${this.downloadFilenameForPhyx}.owl`);
});
} catch (err) {
alert(`Could not convert phylogeny to ontology: ${err}`);
}
},

reasonOverPhyloreferences() {
Expand All @@ -456,13 +475,15 @@ export default {
const outerThis = this;
Vue.nextTick(() => {
// Prepare JSON-LD file for submission.
const jsonld = JSON.stringify([new PhyxWrapper(
outerThis.$store.state.phyx.currentPhyx,
newickParser,
).asJSONLD()]);
const jsonld = outerThis.wrappedPhyxAsJSONLD;
if (!jsonld) {
outerThis.reasoningInProgress = false;
return;
}
const jsonldAsStr = JSON.stringify([jsonld]);

// To improve upload speed, let's Gzip the file before upload.
const jsonldGzipped = pako.gzip(jsonld);
const jsonldGzipped = pako.gzip(jsonldAsStr);

// Prepare request for submission.
const query = $.param({
Expand Down
10 changes: 7 additions & 3 deletions src/store/modules/resolution.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,13 @@ export default {
}

// Is there a node on the phylogeny with the same label as this phyloreference?
const allNodeLabels = new PhylogenyWrapper(phylogeny).getNodeLabels();
if (phyloref.label && allNodeLabels.includes(phyloref.label)) {
return phyloref.label;
try {
const allNodeLabels = new PhylogenyWrapper(phylogeny).getNodeLabels();
if (phyloref.label && allNodeLabels.includes(phyloref.label)) {
return phyloref.label;
}
} catch {
return undefined;
}

// No expected node labels!
Expand Down