# b2bTools

`b2bTools` is the Bio2Byte Python package for predicting biophysical properties
from protein sequences and multiple-sequence alignments. It also provides
lightweight readers for FASTA, alignment, NEF, and NMR-STAR files.

> **ELIXIR Belgium infrastructure**
> b2bTools is an ELIXIR Belgium Core Service. Explore the
> [ELIXIR Belgium services](https://elixir-belgium.org/services).

## Installation

Install the package with `python -m pip install b2bTools`.

Supported Python versions are 3.7 through 3.12 (`>=3.7, <3.13`).

Optional external tools are required only for particular workflows:

- [HMMER](http://hmmer.org) is required for PSPer.
- [T-Coffee](https://tcoffee.crg.eu) is required when b2bTools creates an
  alignment from two input sequence files.

For the command-line interface, run the following after installation.

<!-- docs-test: cli-help -->
```console
python -m b2bTools --help
```

## Choose a workflow

| Input | Entry point | Use it for |
| --- | --- | --- |
| One or more unaligned protein sequences | `SingleSeq` | Per-residue predictions from FASTA input. |
| A multiple-sequence alignment | `MultipleSeq` | Predictions mapped to an existing alignment. |
| NMR chemical shifts | `ShiftCrypt` | Residue-level biophysical indices from NEF or NMR-STAR data. |
| File parsing only | `b2bTools.general.parsers` | Reading supported formats without importing predictor models. |

## Quick start

### Predict properties for a FASTA file

Create a FASTA file named `proteins.fasta`, then run DynaMine and write its
results as JSON. Add other predictor constants from the reference table below
when needed.

<!-- docs-test: single-sequence -->
```python
from pathlib import Path
import json

from b2bTools import SingleSeq, constants

input_fasta = Path("proteins.fasta")
predictor = SingleSeq(str(input_fasta), short_id=False)
predictor.predict(tools=[constants.TOOL_DYNAMINE])

results = predictor.get_all_predictions()
Path("predictions.json").write_text(json.dumps(results, indent=2), encoding="utf-8")
```

`results["proteins"]` maps each sequence identifier to its per-residue values.
`results["metadata"]` records the requested tools and package metadata. Use
`get_all_predictions_tabular(path, sep=",")` for CSV or
`get_all_predictions_tabular(path, sep="\t")` for TSV output.

### Predict properties for an existing alignment

Use an existing, aligned FASTA file when the relationship between residues must
be preserved across sequences.

<!-- docs-test: multiple-sequence -->
```python
from pathlib import Path

from b2bTools import MultipleSeq, constants

input_alignment = Path("alignment.fasta")
predictor = MultipleSeq()
predictor.from_aligned_file(str(input_alignment), tools=[constants.TOOL_DYNAMINE])

results = predictor.get_all_predictions_msa()
```

`results["proteins"]` contains the aligned prediction values. To select one
sequence, pass its identifier to `get_all_predictions_msa(sequence_key)`.

## Predictor reference

| Predictor | Constant | Produces |
| --- | --- | --- |
| DynaMine | `constants.TOOL_DYNAMINE` | Backbone and side-chain dynamics; helix, sheet, coil, and polyproline-II propensities. |
| EFoldMine | `constants.TOOL_EFOLDMINE` | Early-folding propensity. |
| DisoMine | `constants.TOOL_DISOMINE` | Disorder propensity. |
| AgMata | `constants.TOOL_AGMATA` | Beta-aggregation propensity. |
| PSPer | `constants.TOOL_PSP` | Phase-separation features and a protein-level score. |

Dependencies are resolved automatically. For example, requesting PSPer also
runs the predictors whose outputs it requires. Runtime depends on the selected
tools, sequence lengths, and the number of sequences.

## Understanding prediction outputs

The prediction APIs preserve positional correspondence: element *n* in a
per-residue prediction list describes `residue_index` *n*. This makes the JSON
results suitable for programmatic analysis and the tabular exports suitable for
spreadsheets and statistical tools.

### JSON result structure

`SingleSeq.get_all_predictions()` returns `proteins` and `metadata`.
`proteins` maps each sequence identifier to its sequence and prediction lists;
`metadata` records the requested tools and package information. For an existing
alignment, `MultipleSeq.get_all_predictions_msa()` returns `proteins` together
with `sequences`, which retains the aligned sequence (including gap positions)
for every identifier.

Every numeric prediction key contains one value per residue or aligned
position. `viterbi` is the exception: it contains PSPer's categorical state
labels. A value can be `null` when a property was not calculated for that
position, for example at an alignment gap.

### Per-residue CSV and TSV columns

`get_all_predictions_tabular(path, sep=",")` writes a CSV file; pass
`sep="\t"` for TSV. Each row represents one sequence position. Numeric values
are rounded to three decimal places in this export.

| Column | Meaning | Type in the table |
| --- | --- | --- |
| `sequence_id` | Identifier of the input sequence. | Text |
| `residue` | One-letter residue code. In an MSA export, this can be the gap character `-`. | Text |
| `residue_index` | Zero-based position in the sequence or alignment. | Integer |
| Prediction key | Value for the property described below. A blank cell means that the predictor was not selected or no value is available at that position. | Numeric, except `viterbi` |

The following keys are included as prediction columns. Their JSON values are
ordered lists; in the CSV or TSV, each list is expanded into its corresponding
residue row.

| Predictor | Output keys | Value type |
| --- | --- | --- |
| DynaMine | `backbone`, `sidechain`, `ppII`, `coil`, `sheet`, `helix` | Numeric per residue |
| EFoldMine | `earlyFolding` | Numeric per residue |
| DisoMine | `disoMine` | Numeric per residue |
| AgMata | `agmata` | Numeric per residue |
| PSPer | `complexity`, `arg`, `tyr`, `RRM`, `disorder` | Numeric per residue |
| PSPer | `viterbi` | Categorical state per residue |

PSPer also supplies `protein_score`, a single score for the complete protein.
It is available in the JSON result and metadata statistics rather than as a
per-residue column.

### MSA distribution outputs

`MultipleSeq.get_all_predictions_msa_distrib()` summarises the numeric
predictions across sequences at every alignment position. Its `results` value
is organised as `prediction_key` → `summary_name` → ordered values. Use
`get_msa_distrib_tabular(path, sep=",")` to write the same data as columns
named `prediction_key_summary_name`, alongside the zero-based
`residue_index`.

| Summary name | Meaning at each alignment position |
| --- | --- |
| `median` | Median of available numeric values. |
| `firstQuartile` | 25th percentile. |
| `thirdQuartile` | 75th percentile. |
| `bottomOutlier` | Lower outlier boundary: first quartile minus 1.5 times the interquartile range. |
| `topOutlier` | Upper outlier boundary: third quartile plus 1.5 times the interquartile range. |

`viterbi` is categorical, so it is intentionally excluded from MSA distribution
statistics. When an alignment column has no numeric values, all of its summary
values are `null` (or blank in the tabular export).

## File-parser reference

The parser modules are safe to import in services that do not need PyTorch or
other predictor-model dependencies.

### FASTA

`FastaIO.read_fasta_from_file` and `FastaIO.read_fasta_from_string` return a
list of `(sequence_id, sequence)` pairs. By default, `short_id=False` retains
the complete header, collapses whitespace to `_`, and sanitises spaces, full
stops, vertical bars, and commas. Pass `short_id=True` to use the first header
token, capped at 20 characters.

<!-- docs-test: fasta-parser -->
```python
from pathlib import Path

from b2bTools.general.parsers.fasta import FastaIO

records = FastaIO.read_fasta_from_file(Path("proteins.fasta"), short_id=False)
for sequence_id, sequence in records:
    print(sequence_id, len(sequence))
```

### Alignments

`AlignmentsIO` reads FASTA, A3M, BLAST, BaliBase, CLUSTAL, PSI, PHYLIP, and
Stockholm alignments. Each `read_alignments*` method returns a dictionary that
maps sequence identifiers to aligned sequences.

`short_id=False` is the default. Where the format provides a complete header,
the parser retains it with whitespace collapsed to `_`; `short_id=True` uses
the first header token capped at 20 characters. Write helpers and NMR readers
do not take `short_id` because they do not derive sequence identifiers from
FASTA-style headers.

<!-- docs-test: alignment-parser -->
```python
from pathlib import Path

from b2bTools.general.parsers.alignments import AlignmentsIO

alignment = AlignmentsIO.read_alignments("alignment.fasta", short_id=False)
for sequence_id, aligned_sequence in alignment.items():
    print(sequence_id, len(aligned_sequence))
```

### NEF and NMR-STAR

`NefIO` reads NEF projects and sequence/chemical-shift data. `NMRStarIO`
provides the equivalent NMR-STAR readers. Neither API uses `short_id`.

<!-- docs-test: nef-parser -->
```python
from pathlib import Path

from b2bTools.general.parsers.nef import NefIO

sequence_shifts = NefIO.read_nef_file_sequence_shifts(Path("example.nef"))
print(sequence_shifts.keys())
```

## ShiftCrypt

Use ShiftCrypt when your input contains NMR chemical shifts. `modelClass="2"`
is the default model; model classes `"1"` and `"3"` are available for the full
chemical-shift set and the N/H-only model, respectively.

<!-- docs-test: shiftcrypt -->
```python
from pathlib import Path

from b2bTools.nmr.shiftCrypt.Predictor import ShiftCrypt
from b2bTools.nmr.shiftCrypt.shiftcrypt_pkg.parser import parse_official

protein_shifts = parse_official(Path("example.nef"))
results = ShiftCrypt().predictShifts(protein_shifts, modelClass="2")
```

`predictShifts` returns one dictionary per parsed chain. Its fields are:

| Field | Meaning | Type |
| --- | --- | --- |
| `ID_file` | Identifier supplied by the input file. | Text |
| `sequence` | Residue sequence. | List of one-letter residue codes |
| `seqCodes` | Residue numbering from the source data. | List of integers |
| `shiftCrypt` | Residue-level ShiftCrypt values. | List of numeric values |
| `chainCode` | Chain identifier from the source data. | Text |

## Command-line interface

The CLI processes a FASTA file in single-sequence mode by default. Use
`--mode msa` for an existing alignment; add predictor flags such as
`--disomine` or `--psper` to request additional outputs. `--short_ids` selects
the 20-character identifier mode.

Required options are `--input_file` and `--output_json_file`. Optional
`--output_tabular_file`, `--metadata_file`, and, for MSA runs,
`--distribution_json_file` and `--distribution_tabular_file` write additional
outputs. Use `--help` for the authoritative option list in the installed
version.

## Development

From the repository root, run `make test` to execute the maintained test suite.
Run `make generate-docs` to generate API documentation in
`wrapper_documentation`.

## Further documentation and citations

The [Bio2Byte package documentation](https://bio2byte.be/b2btools/package-documentation)
contains detailed API material and method-level documentation. The Bio2Byte
[tools page](https://bio2byte.be/tool/) describes the scientific background of
each predictor.

If you use b2bTools in published work, cite the relevant predictor:

| Predictor | Citation |
| --- | --- |
| DynaMine | Cilia *et al.* (2013), *Nature Communications* 4:2741. [DOI](https://doi.org/10.1038/ncomms3741) |
| DisoMine | Orlando *et al.* (2022), *Journal of Molecular Biology*. [DOI](https://doi.org/10.1016/j.jmb.2022.167579) |
| EFoldMine | Raimondi *et al.* (2017), *Scientific Reports* 7:8826. [DOI](https://doi.org/10.1038/s41598-017-08366-3) |
| AgMata | Orlando *et al.* (2020), *Bioinformatics* 36:2076–2081. [DOI](https://doi.org/10.1093/bioinformatics/btz912) |
| PSPer | Orlando *et al.* (2019), *Bioinformatics* 35:4617–4623. [DOI](https://doi.org/10.1093/bioinformatics/btz274) |
| ShiftCrypt | Orlando *et al.* (2020), *Nucleic Acids Research* 48:W36–W40. [DOI](https://doi.org/10.1093/nar/gkaa391) |

## Licence and terms of use

b2bTools is distributed under the GNU General Public License v3.0 (GPLv3).

Bio2Byte promotes open science by providing freely available online services,
databases, and software for the life sciences, with a focus on proteins. Please
attribute Bio2Byte services, databases, and software in publications, services,
or products according to good scientific practice and the relevant citation
guidance above. Bio2Byte is not liable for loss or damage arising from the use
of this software.

Questions about these terms may be sent to
[bio2byte@vub.be](mailto:bio2byte@vub.be).
