---
title: "ggchord tutorial"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{ggchord tutorial}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  warning = FALSE,
  message = FALSE,
  fig.width = 8,
  fig.height = 7,
  fig.align = "center",
  out.width = "100%"
)
```

```{r library}
library(ggchord)
library(ggplot2)

data(seq_data_example)
data(ribbon_data_example)
data(gene_data_example)
```

This tutorial walks through the complete `ggchord` workflow: preparing input
data, importing files in R, validating and cleaning data, and building plots
layer by layer.

## 1. Data preparation

Three types of input data are used. All three are plain data frames.

### [Required] Sequence data (`seq_data`)

| Column | Type | Description |
| --- | --- | --- |
| `seq_id` | character | Unique sequence identifier |
| `length` | integer | Sequence length (must be positive) |

Example:

| seq_id | length |
| --- | --- |
| MT108731.1 | 64323 |
| MT118296.1 | 32090 |
| OQ646790.1 | 57367 |
| OR222515.1 | 83080 |

A common way to build this table from FASTA files:

```bash
seqkit fx2tab -nil examples/fasta/*.fna | sed '1i seq_id\tlength' > examples/seq_track.tsv
```

### [Optional] Alignment data (`ribbon_data`)

One row per alignment block between two sequences (the column names follow
common alignment-tool conventions):

| Column | Type | Description |
| --- | --- | --- |
| `qaccver` | character | Query sequence ID |
| `saccver` | character | Subject sequence ID |
| `length` | integer | Alignment length (bp) |
| `pident` | numeric | Percent identity (0–100) |
| `qstart` | integer | Start position on the query sequence |
| `qend` | integer | End position on the query sequence |
| `sstart` | integer | Start position on the subject sequence |
| `send` | integer | End position on the subject sequence |

Example rows:

| qaccver | saccver | length | pident | qstart | qend | sstart | send |
| --- | --- | --- | --- | --- | --- | --- | --- |
| MT108731.1 | MT118296.1 | 24856 | 98.612 | 26298 | 51139 | 7121 | 31959 |
| MT108731.1 | MT118296.1 | 4412 | 97.031 | 21513 | 25922 | 2365 | 6772 |
| MT108731.1 | MT118296.1 | 464 | 94.181 | 20691 | 21146 | 1032 | 1495 |

For example, the standard BLAST `-outfmt 7` output can be parsed into this
table directly:

```bash
seqs=("MT108731.1" "MT118296.1" "OQ646790.1" "OR222515.1")
ext="fna"
for ((i=0; i<${#seqs[@]}-1; i++)); do
  for ((j=i+1; j<${#seqs[@]}; j++)); do
    blastn \
      -outfmt '7 qaccver saccver pident length mismatch gapopen qstart qend sstart send evalue bitscore qcovs qlen slen sstrand stitle' \
      -query "examples/fasta/${seqs[$i]}.${ext}" \
      -subject "examples/fasta/${seqs[$j]}.${ext}" \
      -out "examples/blastn/${seqs[$i]}__${seqs[$j]}.o7"
  done
done
```

### [Optional] Gene data (`gene_data`)

One row per gene (or feature) on a sequence:

| Column | Type | Description |
| --- | --- | --- |
| `seq_id` | character | Sequence ID the gene belongs to |
| `start` | integer | Gene start position |
| `end` | integer | Gene end position |
| `strand` | character | Strand direction (`+` or `-`) |
| `anno` | character | Gene annotation / functional category |

Example rows:

| seq_id | start | end | strand | anno |
| --- | --- | --- | --- | --- |
| MT108731.1 | 60709 | 63087 | + | hypothetical protein |
| MT118296.1 | 14628 | 16301 | + | virion structural protein |
| OQ646790.1 | 43765 | 46140 | + | integrase |
| OQ646790.1 | 13194 | 15551 | + | tail tape measure protein |

For example, this table can be converted from GFF3 files:

```r
library(tidyverse)
gff3FilesPath <- list.files(path = "examples/gff3", pattern = "\\.gff3$", full.names = TRUE)
gff3Table <- map_df(gff3FilesPath, ~read_tsv(.x, show_col_types = F, comment = "#",
  col_names = F) %>% set_names(c("seq_id", "source", "type", "start", "end",
  "score", "strand", "phase", "attributes")))
geneTrackTable <- gff3Table %>%
  filter(type == "CDS") %>%
  mutate(anno = str_extract(attributes, "(?<=product=)[^;]+(?=;)")) %>%
  select(seq_id, start, end, strand, anno)
write_tsv(geneTrackTable, "examples/gene_track.tsv")
```

## 2. Importing FASTA / BLAST / GFF3 data in R

External command-line tools (BLAST, seqkit, ...) are often used to *prepare*
the data, but the files they produce can also be read directly in R with the
built-in import helpers. This keeps the "prepare data outside R" and
"import + plot in R" steps clearly separated:

```{r import-helpers, eval=FALSE}
library(ggchord)

# FASTA -> seq_data (read and combine all example FASTA files)
seq_data <- invisible(read_fasta_lengths(files = "examples/fasta/*.fna"))

# BLAST -outfmt 6/7 tabular output -> ribbon_data (12 or 17 columns auto-detected)
ribbon_data <- invisible(read_blast(files = "examples/blastn/*.o7"))

# GFF3 -> gene_data (CDS features by default; anno from product/Name/...)
gene_data <- invisible(read_gff3(files = "examples/gff3/*.gff3"))

ggchord(seq_data, ribbon_data, gene_data) +
  geom_seq() + geom_ribbon() + geom_gene()
```

`read_blast()` preserves useful extra columns (`evalue`, `bitscore`, `qcovs`,
`qlen`, `slen`, `sstrand`, `stitle`); `read_gff3()` preserves `type`,
`source`, `score`, `phase` and `attributes`; `read_fasta_lengths()` optionally
splits NCBI-style headers with `header_delim = "|"`.

## 3. Tutorial: from data to a diagram

This section turns the prepared data into a complete chord diagram. Each step
shows a short, runnable example and its corresponding figure.

### 3.1 Validate and clean input data

```{r validate-clean, eval=FALSE}
data(seq_data_example)
data(ribbon_data_example)
data(gene_data_example)

validate_ggchord_data(seq_data_example, ribbon_data_example, gene_data_example)

clean_ggchord_data(seq_data_example, ribbon_data_example, gene_data_example,
                   unknown_id = "drop", out_of_range = "clip",
                   reversed_interval = "sort", invalid_pident = "clip")
```

`ggchord()` also validates automatically with `validate = "warn"`. Use
`"error"` to stop on severe problems or `"none"` for large inputs.

### 3.2 Filter and merge ribbons

```{r ribbon-tidy, eval=FALSE}
kept <- filter_ggchord_ribbons(ribbon_data_example, min_pident = 90,
                               drop_self_links = TRUE,
                               sort_by = "pident")
dedup <- deduplicate_ggchord_ribbons(kept$data, by = "exact",
                                     keep = "best_pident")
merged <- merge_ggchord_ribbons(dedup$data, max_gap = 0)
```

The returned `$data` tables can be passed directly to `ggchord()`.

### 3.3 Start with sequence arcs

```{r tutorial-seq, eval=FALSE}
ggchord(seq_data_example) +
  geom_seq()
```

```{r tutorial-seq-img, echo=FALSE, fig.cap="Sequence arcs."}
knitr::include_graphics("../man/figures/seq_only_default.png")
```

### 3.4 Add alignment ribbons

```{r tutorial-ribbon, eval=FALSE}
ggchord(seq_data_example, ribbon_data_example) +
  geom_seq() + geom_ribbon()
```

```{r tutorial-ribbon-img, echo=FALSE, fig.cap="Ribbons coloured by percent identity."}
knitr::include_graphics("../man/figures/ribbon_pident.png")
```

### 3.5 Add genes and labels

```{r tutorial-gene, eval=FALSE}
ggchord(seq_data_example, gene_data = gene_data_example) +
  geom_seq() + geom_gene() + geom_gene_label_repel()
```

```{r tutorial-gene-img, echo=FALSE, fig.cap="Gene arrows with repelled labels."}
knitr::include_graphics("../man/figures/gene_repel.png")
```

### 3.6 Add axes and sequence labels

```{r tutorial-axis, eval=FALSE}
ggchord(seq_data_example) +
  geom_seq() + geom_axis() + geom_seq_label()
```

```{r tutorial-axis-img, echo=FALSE, fig.cap="Axes and sequence labels."}
knitr::include_graphics("../man/figures/axis_seq_label.png")
```

### 3.7 Group sequences

```{r tutorial-group, eval=FALSE}
seq_grouped <- transform(seq_data_example,
                         seq_group = c("host", "host", "phage", "phage"))

ggchord(seq_grouped, ribbon_data_example, gene_data_example) +
  geom_seq(seq_group = "seq_group",
           seq_group_colors = c(host = "#E41A1C", phage = "#377EB8")) +
  geom_ribbon() + geom_gene()
```

```{r tutorial-group-img, echo=FALSE, fig.cap="Sequences grouped with an inter-group gap and labels."}
knitr::include_graphics("../man/figures/tutorial_seq_group.png")
```

### 3.8 Map numeric ribbon columns and direction

```{r tutorial-ribbon-map, eval=FALSE}
rb_scored <- transform(ribbon_data_example,
                       bitscore = seq_len(nrow(ribbon_data_example)) * 10)

ggchord(seq_data_example, rb_scored) +
  geom_seq() +
  geom_ribbon(ribbon_color_by = "bitscore",
              ribbon_alpha_by = "bitscore",
              ribbon_direction = "linetype")
```

```{r tutorial-ribbon-map-img, echo=FALSE, fig.cap="Continuous ribbon fill, alpha and direction mapping."}
knitr::include_graphics("../man/figures/tutorial_ribbon_mapping.png")
```

### 3.9 Highlight regions and ribbons

```{r tutorial-highlight, eval=FALSE}
regions <- data.frame(seq_id = "MT108731.1",
                      start = 1000, end = 4000, color = "orange")

ggchord(seq_data_example, ribbon_data_example) +
  geom_seq() + geom_ribbon() +
  geom_seq_region(regions = regions) +
  geom_ribbon_highlight(ribbon_ids = 1)
```

```{r tutorial-highlight-img, echo=FALSE, fig.cap="Sequence regions and ribbon highlight."}
knitr::include_graphics("../man/figures/tutorial_highlights.png")
```

### 3.10 Draw generic features

```{r tutorial-feature, eval=FALSE}
features <- data.frame(seq_id = c("MT108731.1", "MT118296.1"),
                       start = c(1000, 500), end = c(4000, 2000),
                       strand = c("+", "-"), type = c("CDS", "tRNA"))

ggchord(seq_data_example, ribbon_data_example) +
  geom_seq() + geom_ribbon() + geom_feature(features)
```

```{r tutorial-feature-img, echo=FALSE, fig.cap="Generic features drawn with geom_feature()."}
knitr::include_graphics("../man/figures/tutorial_features.png")
```

### 3.11 Apply themes and scales

```{r tutorial-theme, eval=FALSE}
ggchord(seq_data_example, ribbon_data_example, gene_data_example) +
  geom_seq() + geom_ribbon() + geom_gene() + geom_axis() +
  scale_color_manual(values = c("MT108731.1" = "#E41A1C",
                                "MT118296.1" = "#377EB8",
                                "OQ646790.1" = "#4DAF4A",
                                "OR222515.1" = "#984EA3")) +
  theme(panel.background = element_rect(fill = "grey95"),
        legend.position = "bottom", legend.box = "horizontal")
```

```{r tutorial-theme-img, echo=FALSE, fig.cap="A themed plot with all legends grouped."}
knitr::include_graphics("../man/figures/legend_bottom.png")
```

### 3.12 Fine-tuned publication-style plot

```{r tutorial-fine, eval=FALSE}
ggchord(seq_data_example, ribbon_data_example, gene_data_example,
        title = "ggchord") +
  geom_seq(seq_radius = c(3.3, 2.5, 1.8, 1.25),
           seq_orientation = c(-1, -1, 1, -1),
           seq_colors = c("MT108731.1" = "#E76F51",
                          "MT118296.1" = "#264653",
                          "OQ646790.1" = "#2A9D8F",
                          "OR222515.1" = "#D9A62E")) +
  geom_ribbon(ribbon_alpha = 0.45) +
  geom_gene() +
  geom_gene_label_repel(gene_label_size = 2, seed = 42) +
  geom_seq_label() +
  geom_axis() +
  theme(plot.background = element_rect(fill = "#FBF9F6", colour = NA),
        panel.background = element_rect(fill = "#FBF9F6", colour = NA))
```

```{r tutorial-fine-img, echo=FALSE, fig.cap="A complete fine-tuned chord diagram."}
knitr::include_graphics("../man/figures/combined_fine.png")
```

## 6. Flexible parameter formats

Sequence-level parameters (`seq_radius`, `seq_gap`, `axis_label_size`, ...)
accept **a single value, an unnamed vector, a vector/list named by sequence ID,
a list named by sequence order (`"1"`, `"2"`, ...), or an unnamed list**.
Gene-level parameters (`gene_label_rotation`, `gene_offset`, ...) additionally
accept per-strand (`+`/`-`) values. All of the following are valid:

```{r flexible-formats, eval=FALSE}
# 1. One value for everything
gene_label_rotation = 20

# 2. One value per strand, for every sequence
gene_label_rotation = c("+" = -15, "-" = -45)

# 3. By sequence ID
gene_label_rotation = list(
  "MT118296.1" = c("+" = -15, "-" = -45),
  "OR222515.1" = c("+" = 30, "-" = -30),
  "MT108731.1" = c("+" = 15, "-" = -15),
  "OQ646790.1" = c("+" = 0,  "-" = 0)
)

# 4. By sequence order ("1" = first sequence)
gene_label_rotation = list(
  "1" = c("+" = -15, "-" = -45),
  "2" = c("+" = 30, "-" = -30),
  "3" = c("+" = 15, "-" = -15),
  "4" = c("+" = 0,  "-" = 0)
)

# 5. Unnamed list: follows the sequence order (same as #4)
gene_label_rotation = list(
  c("+" = -15, "-" = -45),
  c("+" = 30, "-" = -30),
  c("+" = 15, "-" = -15),
  c("+" = 0,  "-" = 0)
)

# 6. A length-one list recycles to every sequence
gene_label_rotation = list(20)
```

## 7. Layer reference

| Layer | Function | Description |
| --- | --- | --- |
| Sequence arcs | `geom_seq()` | Draws an arc (or line) for each sequence, with direction arrows |
| Alignment ribbons | `geom_ribbon()` | Draws colored ribbons from alignment results |
| Gene arrows | `geom_gene()` | Draws gene/feature arrow polygons |
| Gene labels | `geom_gene_label()` | Draws gene labels at fixed positions |
| Repelled gene labels | `geom_gene_label_repel()` | ggrepel-style labels with leader lines, wrapping and overlap hiding |
| Axes | `geom_axis()` | Draws axis lines, major/minor ticks and tick labels |
| Sequence labels | `geom_seq_label()` | Places sequence names on/outside the arcs |

## 8. Plot interpretation

- **Sequence arcs** — each colored arc is one sequence, with length
  proportional to the sequence length and arrows showing direction.
- **Ribbons** — colored regions connecting sequences represent aligned/
  homologous intervals; color encodes identity, query or subject by default.
- **Gene arrows** — arrow polygons on the sequences; color encodes strand or
  functional category, with optional labels.
- **Axes** — ticks and numbers outside each arc label sequence positions.


## Further reading

- [Function reference](https://dangjem.github.io/ggchord/reference/index.html)
- [Version history (NEWS.md)](https://dangjem.github.io/ggchord/news/index.html)
- [Package homepage](https://dangjem.github.io/ggchord/)
