Site guide · find your task
Setup and learning paths
HomeInstall and prepare the environmentChoose your learning moduleModule I · Chord
1.1 Tables and field meanings1.2 Produce and import comparisons1.3 Build the layers step by step1.4 Direction, curvature and clearance1.5 Filter and summarize links1.6 Full source-file workflow1.7 Complete chord showcaseModule II · Collinear
2.1 Reuse chord input tables2.2 Switch coordinates and add layers2.3 Routes, clearance and the ruler2.4 Compare CDS neighbourhoods2.5 Focus, anchors and segments2.6 Complete collinear showcaseModule III · Plasmid
3.1 DNA, annotations and 13 references3.2 From a circle to annotation layers3.3 Features, primers and restriction3.4 Thirteen plasmid references3.5 Complete plasmid casesConsult as needed · Data and layers
Prepare tables and coordinatesImport and convert dataImport nucleotide and protein alignmentsProject protein intervals to genomic coordinatesFeatures, stacking and genomic decorationLabels and local placementQuantitative tracksMappings, scales, guides and themesSet values by sequence and strandCommon adjustments and grammarExport, preview and diagnosticsLearning map and reference
Articles and complete workflowsFunction referenceReproducible galleryFrequently asked questionsMigrate to the candidate APITerminology and design sourcesDevelopment status and changesImport and convert data
On this page
Convert tables, BED, PAF or GenBank into ggchord inputs while retaining record identity and converting coordinate conventions only once.
Prepare this page
In a fresh R session, run the code below, then follow this page in order. Colours and layout are optional display choices; inputs select only the fields needed. For file-based examples, first extract the input bundle so the working directory contains examples/.
Preparation code — run once on this page
Code
library(ggchord)
library(dplyr)
data(seq_data_example)
data(ribbon_data_example)
data(gene_data_example)
seqs <- seq_data_example |>
select(accver, length)
links <- ribbon_data_example |>
select(qaccver, saccver, qstart, qend, sstart, send)
# The fixture preserves biological strands separately from its old display strands.
genes <- gene_data_example |>
transmute(accver, start, end, strand = source_strand)
library(ggchord)
doc_background <- "#FFFCF5"
identity_palette <- c("#303B71", "#36537D", "#269B82", "#A5D52C", "#ECEB31")
identity_values <- c(0, 0.5, 0.8, 0.9, 1)
identity_breaks <- c(0, 50, 80, 90, 100)
doc_legend_theme <- theme(
legend.title = element_text(size = 13, face = "bold"),
legend.text = element_text(size = 11),
legend.key.width = unit(9, "mm"), legend.key.height = unit(5, "mm"),
legend.spacing.x = unit(9, "mm"), legend.spacing.y = unit(7, "mm"),
legend.margin = margin(l = 4, r = 4, unit = "mm")
)
sequence_guide <- guide_ggchord_legend(nrow = 1, theme = doc_legend_theme)
strand_guide <- guide_ggchord_legend(
nrow = 1, override.aes = list(strand = c("+", "-")), theme = doc_legend_theme
)
identity_guide <- guide_ggchord_colourbar(
position = "left", direction = "vertical",
theme = theme(
legend.key.height = unit(75, "mm"), legend.key.width = unit(5, "mm"),
legend.title = element_text(size = 13, face = "bold"),
legend.text = element_text(size = 11), legend.margin = margin(r = 7, unit = "mm")
)
)
doc_theme <- theme_ggchord_publication(
axis.text = element_text(size = 11),
axis.text.check.overlap = TRUE
) +
theme(
legend.position = "bottom",
legend.title = element_text(size = 13, face = "bold"),
legend.text = element_text(size = 11),
legend.key.width = unit(9, "mm"), legend.key.height = unit(5, "mm"),
legend.spacing.x = unit(9, "mm"), legend.spacing.y = unit(7, "mm"),
legend.box.spacing = unit(6, "mm"),
plot.background = element_rect(fill = doc_background, colour = NA),
panel.background = element_blank(),
plot.title = element_text(face = "bold", size = 18),
plot.subtitle = element_text(size = 10, colour = "#5C625A"),
plot.margin = margin(14, 18, 14, 18)
)
doc_axis <- function(coordinates = "relative") {
scale_seq_position_continuous(
coordinates = coordinates, n.breaks = 3, minor_breaks = NULL,
labels = function(x) format(x, scientific = FALSE, big.mark = ",", trim = TRUE)
)
}
library(dplyr)
data(plasmid_example_pUC19)
plasmid_seq <- plasmid_example_pUC19 |>
select(accver, length)
feature_source <- find_common_features(plasmid_example_pUC19)
features <- feature_source |>
select(accver, start, end, strand, type, anno)Adapt an existing table
The preparation above loads the input tables. These examples rename columns of bundled source-backed sequences, links and genes; they do not invent alignments.
Code
renamed_sequences <- seqs |>
rename(chrom = accver, size = length)
sequence_input <- as_ggchord_seq(renamed_sequences, mapping = c(accver = "chrom", length = "size"))
renamed_features <- genes |>
rename(chrom = accver, left = start, right = end)
feature_input <- as_ggchord_feature(renamed_features,
mapping = c(accver = "chrom", start = "left", end = "right")
)
link_input <- as_ggchord_link(links)Adapters return ordinary frames with ggchord_conversion provenance. IDs remain unchanged. Supply reliable full lengths rather than using maximum feature ends. See alignment input for minimal fields and coordinate units.
BED and PAF: convert coordinates once
The BED example writes known pUC19 intervals as minimal BED3 and reads them back. PAF comes directly from real minimap2 output in the public tutorial, with original optional tags/values. The display retains mapq ≥30 and receives only six endpoint roles.
Code
# BED3 carries intervals only; the source annotations remain in features.
bed_path <- tempfile(fileext = ".bed")
bed_rows <- tibble(accver = features$accver, start0 = features$start - 1L, end = features$end)
write.table(bed_rows, bed_path, sep = "\t", quote = FALSE, row.names = FALSE, col.names = FALSE)
bed_features <- read_bed(bed_path)
unlink(bed_path)
# Unchanged PAF rows from the public EMALE tutorial, not a simulated alignment.
paf_source <- read_paf("examples/format-inputs/emales-pair.paf")
paf_selected <- paf_source |>
filter(!is.na(mapq), mapq >= 30)
paf_links <- paf_selected |>
select(qaccver, saccver, qstart, qend, sstart, send)
paf_seqs <- bind_rows(
transmute(paf_source, accver = qaccver, length = qlen),
transmute(paf_source, accver = saccver, length = slen)
) |>
distinct()
p_paf <- ggchord(seq_data = paf_seqs, ribbon_data = paf_links) +
geom_link_ribbon(fill = "#6BAFA6", alpha = .5) +
geom_seq(colour = "#233E4A") +
geom_seq_label(size = 4) +
coord_collinear() +
doc_axis() +
doc_theme
p_paf
The reader converts BED zero-based half-open intervals to one-based inclusive coordinates; do not add one again. BED3 has no strand, so it returns unknown strand; use a strand-bearing format when needed. Negative PAF relative direction becomes decreasing subject endpoints. These are valid reverse hits, not values to sort indiscriminately. Quality/identity use producer fields, not new alignments.
GenBank: retain record identity
Code
# The original NCBI L09137.2 record identifies pUC19c; keep that identity.
genbank_result <- NULL
if (nzchar(Sys.which("python3")) && identical(suppressWarnings(system2("python3",
c("-c", shQuote("from Bio import SeqIO")),
stdout = FALSE, stderr = FALSE
)), 0L)) {
genbank_result <- read_genbank("examples/format-inputs/pUC19c-L09137.2.gb")
}This is the original NCBI L09137.2 record, named pUC19c; do not rename it to the bundled pUC19. Results include seq_data, features$annotation and report, retaining segmented locations and record/feature provenance. The selected Python needs Biopython already installed; no automatic installation occurs. unsupported = "report" records unsupported locations rather than guessing bounds.
Optional interval objects
Code
range_inputs <- NULL
if (requireNamespace("GenomicRanges", quietly = TRUE)) {
unknown <- features |>
filter(strand == ".") |>
slice_head(n = 1)
ranges <- GenomicRanges::GRanges(
seqnames = unknown$accver,
ranges = IRanges::IRanges(unknown$start, unknown$end), strand = "*",
seqlengths = setNames(plasmid_seq$length, plasmid_seq$accver)
)
range_inputs <- list(seq_data = as_ggchord_seq(ranges), features = as_ggchord_feature(ranges))
}Code
interaction_inputs <- NULL
if (requireNamespace("GenomicRanges", quietly = TRUE) &&
requireNamespace("InteractionSet", quietly = TRUE)) {
source_links <- ribbon_data_example |>
slice_head(n = 2)
lengths <- setNames(seq_data_example$length, seq_data_example$accver)
query <- GenomicRanges::GRanges(
seqnames = source_links$qaccver,
ranges = IRanges::IRanges(
pmin(source_links$qstart, source_links$qend),
pmax(source_links$qstart, source_links$qend)
),
strand = ifelse(source_links$qstart <= source_links$qend, "+", "-"),
seqlengths = lengths
)
subject <- GenomicRanges::GRanges(
seqnames = source_links$saccver,
ranges = IRanges::IRanges(
pmin(source_links$sstart, source_links$send),
pmax(source_links$sstart, source_links$send)
),
strand = ifelse(source_links$sstart <= source_links$send, "+", "-"),
seqlengths = lengths
)
interactions <- InteractionSet::GInteractions(query, subject)
interaction_inputs <- list(
seq_data = as_ggchord_seq(interactions),
ribbon_data = as_ggchord_link(interactions)
)
}| Metric | Observed output |
|---|---|
| GenBank optional reader | SKIP: Biopython unavailable |
| Optional interval adapter | SKIP: GenomicRanges unavailable |
| Optional GInteractions adapter | SKIP: InteractionSet or GenomicRanges unavailable |
An originally unknown-strand pUC19 annotation remains unknown as *. Known full lengths populate Seqinfo. GInteractions can become links but still needs explicit sequence/length context. Missing dependencies are marked skipped, not validated by source presence. See the data contract. SAM/BAM CIGAR is not parsed directly: use an alignment-aware tool before table adaptation; renaming columns alone cannot resolve splicing.
Check your result
Inspect returned fields and conversion reports before selecting plotting fields. Preserve endpoint direction for reverse PAF hits; do not rename a GenBank record to pretend it is a different bundled plasmid.