Skip to content

Commit

Permalink
Add preliminary Nexus support (#458)
Browse files Browse the repository at this point in the history
* update

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* update

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* clarify

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update localBackendWorker.js

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
theosanderson and pre-commit-ci[bot] authored Jan 1, 2023
1 parent 3ed4648 commit 7edb069
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 7 deletions.
3 changes: 2 additions & 1 deletion docs/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ Loading very large (>5M tips) trees in Taxonium works better in the desktop appl
You can download the Taxonium desktop app for Windows, MacOS, or Linux from the [releases](https://github.com/theosanderson/taxonium/releases) page.

:::{note}
On MacOS you will need to "unquarantine" the app, because the code has not been signed. Before you do this, the application will claim that it is "damaged and can't be opened".
On MacOS you will need to "unquarantine" the app, because the code has not been signed. Before you do this, the application will claim that it is "damaged and can't be opened".

Please use the terminal command below to achieve this:

```
sudo xattr -r -d com.apple.quarantine "/Applications/Taxonium.app"
```
Expand Down
6 changes: 5 additions & 1 deletion taxonium_electron/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ const setup = (mainWindow, args) => {
stdio: ["pipe", "pipe", "pipe", "ipc"],
});

console.log("Executing", binaryPath, [max_old_space_arg, scriptPath, ...args]);
console.log("Executing", binaryPath, [
max_old_space_arg,
scriptPath,
...args,
]);
fork_id = p.pid;

setTimeout(() => {
Expand Down
1 change: 1 addition & 0 deletions taxonium_web_client/src/components/InputSupplier.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function formatBytes(bytes, decimals = 2) {
const prettyTypes = {
jsonl: "Taxonium JSONL",
nwk: "Newick tree",
nexus: "Nexus tree (Nexus support is experimental)",
meta_tsv: "Metadata TSV",
meta_csv: "Metadata CSV",
nextstrain: "Nextstrain JSON",
Expand Down
25 changes: 21 additions & 4 deletions taxonium_web_client/src/hooks/useInputHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ function guessType(file_object) {
if (tree_extensions.includes(file_extension)) {
return "nwk";
}

if (file_extension === "nexus" || file_extension === "nex") {
return "nexus";
}

if (file_extension === "jsonl") {
return "jsonl";
}
Expand Down Expand Up @@ -112,7 +117,11 @@ export const useInputHelper = ({
return ["invalid", "You can only use a single metadata file"];
}
// can't have more than one tree file
if (inputs.filter((input) => input.filetype === "nwk").length > 1) {
if (
inputs.filter(
(input) => input.filetype === "nwk" || input.filetype === "nexus"
).length > 1
) {
return ["invalid", "You can only use a single tree file"];
}
if (inputs.some((input) => input.filetype === "unknown")) {
Expand All @@ -121,7 +130,9 @@ export const useInputHelper = ({
// must have a tree file or a jsonl
if (
inputs.filter((input) => input.filetype === "jsonl").length === 0 &&
inputs.filter((input) => input.filetype === "nwk").length === 0 &&
inputs.filter(
(input) => input.filetype === "nwk" || input.filetype === "nexus"
).length === 0 &&
inputs.filter((input) => input.filetype === "nextstrain").length === 0
) {
return [
Expand Down Expand Up @@ -152,7 +163,10 @@ export const useInputHelper = ({
input.filetype.startsWith("meta_")
);
const tree_file = inputs.find(
(input) => input.filetype === "nwk" || input.filetype === "nextstrain"
(input) =>
input.filetype === "nwk" ||
input.filetype === "nextstrain" ||
input.filetype === "nexus"
);
const newQuery = {
treeUrl: tree_file.name,
Expand Down Expand Up @@ -192,7 +206,10 @@ export const useInputHelper = ({

// if there is a tree file find it
const tree_file = inputs.find(
(input) => input.filetype === "nwk" || input.filetype === "nextstrain"
(input) =>
input.filetype === "nwk" ||
input.filetype === "nextstrain" ||
input.filetype === "nexus"
);

upload_obj.filename = tree_file.name;
Expand Down
43 changes: 43 additions & 0 deletions taxonium_web_client/src/utils/nexusToNewick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// get nexusString from tree.nexus
function nexusToNewick(nexusString) {
// get Translate section if present
const translateBlock = nexusString.match(/Translate(.*?);/gims);
const translate = translateBlock[0];

let translations = {};

// get all the translations
translate.split("\n").forEach((line) => {
line = line.trim();
const parts = line.split(" ");
if (parts.length === 2) {
const key = parts[0];
const value = parts[1].replace(",", "");
translations[key] = value;
}
});

// get all the trees

const treeBlock = nexusString.match(/tree TREE1 = (.*?;)/gims);

// get the Newick string from the tree block
const newickString = treeBlock[0].match(/\((.*?)\).+;/gims)[0];

//remove comments, which are indicated by [...]

const newick = newickString.replace(/\[(.*?)\]/gims, "");

// translate the taxon labels in the Newick string
const translatedNewickString = newick.replace(
/([^:\,\(\)]+)/gims,
(match) => {
//console.log(translations[match])
return translations[match] || match;
}
);

return translatedNewickString;
}

export default nexusToNewick;
6 changes: 6 additions & 0 deletions taxonium_web_client/src/utils/processNewick.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import pako from "pako";
import axios from "axios";
import reduceMaxOrMin from "./reduceMaxOrMin";
import nexusToNewick from "../utils/nexusToNewick.js";
const emptyList = [];

function removeSquareBracketedComments(str) {
Expand Down Expand Up @@ -113,6 +114,11 @@ export async function processNewick(data, sendStatusMessage) {

the_data = await fetch_or_extract(data, sendStatusMessage, "tree");

console.log("data.filetype", data.filetype);
if (data.filetype == "nexus") {
the_data = nexusToNewick(the_data);
}

sendStatusMessage({
message: "Parsing Newick file",
});
Expand Down
2 changes: 1 addition & 1 deletion taxonium_web_client/src/webworkers/localBackendWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ onmessage = async (event) => {
data.type === "upload" &&
data.data &&
data.data.filename &&
data.data.filetype === "nwk"
(data.data.filetype === "nwk" || data.data.filetype === "nexus")
) {
console.log("got nwk file", data.data);
data.data.useDistances = true;
Expand Down

1 comment on commit 7edb069

@vercel
Copy link

@vercel vercel bot commented on 7edb069 Jan 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.