# nj.rs
Neighbor-Joining phylogenetic tree inference in Rust, with Python and WASM bindings.
[](https://github.com/holmrenser/nj.rs/actions/workflows/release.yml)
[](https://github.com/holmrenser/nj.rs/actions/workflows/test.yml)
[](https://crates.io/crates/nj)
[](https://pypi.org/project/nj_py/)
[](https://www.npmjs.com/package/@holmrenser/nj)
Takes an aligned FASTA file as input and outputs a Newick string. Alphabet (DNA/protein) is auto-detected. Supports optional bootstrap support values on internal nodes.
**Substitution models:** `PDiff` (DNA + protein), `JukesCantor` (DNA), `Kimura2P` (DNA), `Poisson` (protein)
## CLI
```bash
cargo install nj --features cli
nj sequences.fasta
nj --substitution-model kimura2-p --n-bootstrap-samples 100 sequences.fasta > tree.nwk
```
A progress bar is shown on stderr when bootstrapping.
## Rust
```toml
[dependencies]
nj = "0.0.12"
```
```rust
use nj::{NJConfig, SequenceObject, nj, models::SubstitutionModel};
let newick = nj(NJConfig {
msa: vec![
SequenceObject { identifier: "A".into(), sequence: "ACGT".into() },
SequenceObject { identifier: "B".into(), sequence: "ACCT".into() },
],
n_bootstrap_samples: 100,
substitution_model: SubstitutionModel::JukesCantor,
## Python
```bash
pip install nj_py
```
```python
from tqdm import tqdm
from nj_py import nj
msa = [
{"identifier": "A", "sequence": "ACGT"},
{"identifier": "B", "sequence": "ACCT"},
]
with tqdm(total=100) as bar:
newick = nj(
msa,
substitution_model="JukesCantor",
n_bootstrap_samples=100,
on_progress=lambda current, total: bar.update(1),
)
```
## JavaScript / WASM
```bash
npm install @holmrenser/nj
```
```js
import { nj } from '@holmrenser/nj';
const config = {
msa: [
{ identifier: 'A', sequence: 'ACGT' },
{ identifier: 'B', sequence: 'ACCT' },
],
n_bootstrap_samples: 100,
substitution_model: 'JukesCantor',
};
const newick = nj(config, (current, total) => {
progressBar.value = current / total * 100;
});
```