--- title: "ggchord:弦图、共线性图与质粒图教程" output: rmarkdown::html_vignette: self_contained: true css: vignette.css vignette: > %\VignetteIndexEntry{ggchord:弦图、共线性图与质粒图教程} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(eval = FALSE, collapse = TRUE, comment = "#>") ``` ggchord 本教程与英语教程、网站从同一组来源生成。vignette 渲染时只展示代码,不自动执行;共享文档脚本直接验证相关例子。示例优先使用随包数据和有来源的原始记录;人为构造的诊断错误会明确标注。每章提供本页准备代码;第一次使用请从首图教程开始。 ## 安装与环境准备 {#installation}
本页完成安装和环境确认,然后选择一个模块逐步学习;不要求先读完全部功能参考。
### 安装并确认环境 {#installation-requirements} 需要R ≥4.1.0、ggplot2 ≥4.0.0。安装和示例均对应v0.16.6。 ```{r example-1, eval=FALSE} install.packages(c("remotes", "dplyr", "purrr", "tidyr")) remotes::install_github("DangJem/ggchord@v0.16.6") library(ggchord) packageVersion("ggchord") ``` #### 你正在使用哪个版本? {#installation-source} 基础安装和示例对应 **ggchord 0.16.6**。上面的安装命令固定到该版本的正式标签;发布资产可在 [GitHub Releases](https://github.com/DangJem/ggchord/releases/tag/v0.16.6) 查阅。 如果你使用的是源码 checkout,在仓库根目录运行: ```{r example-2, eval=FALSE} install.packages("pkgload") pkgload::load_all(".") packageVersion("ggchord") ``` 选择与你手中源码相符的加载方式,不需要同时运行两条安装路径。复现图时记录包版本。 本教程不需要可选的 Bioconductor 或 Biopython 依赖。 #### 支持证据 {#installation-support-evidence} 声明下限为 R 4.1.0、ggplot2 4.0.0。发布检查及实际平台版本记录在正式验收中,不代表所有依赖组合均获认证。可选读取器需要其文档列出的依赖。 ### 选择一条学习路线 {#installation-first-steps} 1. [模块一『弦图』:先认识三张表](#chord-data),再读导入、骨架、图层与参数。 2. [模块二『共线性图』:复用弦图数据](#collinear-data),再替换坐标、路由与局部比较。 3. [模块三『质粒图』:从单序列与DNA开始](#plasmid-data),再逐层添加,遍历13个参考案例。 建议从弦图开始,符合ggchord的发展顺序。完整学习地图见[全部教程](#articles)。下面的两序列练习仅用于快速确认环境,不代替三个模块的递进课程。 ### 输入表先看哪些列? {#installation-input} 序列表最少accver和length;连接表最少两个ID及四个端点;基因表最少accver/start/end/strand。[模块一的第一课](#chord-data)提供真实表格、可选列与BLAST命名说明。 ### 可选:快速确认一次绘图 {#installation-first-plot} 运行整个折叠块,再查看图片。原始记录来自随包数据,不需要BLAST或外部文件。
准备代码 · 在本页运行一次 ```{r example-3, eval=FALSE} library(ggchord) library(dplyr) data(seq_data_example) data(gene_data_example) data(ribbon_data_example) ids <- c("MT108731.1", "MT118296.1") first_sequences <- seq_data_example |> filter(accver %in% ids) |> select(accver, length) first_genes <- gene_data_example |> filter(accver %in% ids) |> transmute(accver, start, end, strand = source_strand) first_links <- ribbon_data_example |> filter(qaccver %in% ids, saccver %in% ids) |> select(qaccver, saccver, qstart, qend, sstart, send) first_colours <- setNames(c("#E64B35", "#233E4A"), ids) p_first <- ggchord( seq_data = first_sequences, ribbon_data = first_links, gene_data = first_genes ) + geom_link_ribbon(fill = "#82B6AD", alpha = .55) + geom_seq(colour = "#233E4A", show.legend = FALSE) + geom_gene(aes(gene_fill = accver), position = position_strand(.10), width = .045) + geom_seq_label(size = 4) + coord_collinear() + scale_gene_fill_manual( values = first_colours, name = "Sequence", guide = guide_ggchord_legend(nrow = 1, 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.margin = margin(l = 7, unit = "mm") )) ) + scale_seq_position_continuous(n.breaks = 3, minor_breaks = NULL) + theme_ggchord_publication(axis.text = element_text(size = 11)) + theme( legend.position = "bottom", plot.background = element_rect(fill = "#FFFCF5", colour = NA), panel.background = element_blank() ) p_first ```
第一张图:两条真实随包序列、基因箭头及已有比对区间
第一张图:两条真实随包序列、基因箭头及已有比对区间 · 点击放大查看
### 如何阅读这个快速结果 {#installation-read} 箭头保留真实链方向,颜色只区分所属序列;连线是已有比对区间,绘图没有生成新的同源结论。该小图选择线性视图便于读位置;完整弦图教学从序列骨架开始。 ### 可选:保存快速结果 {#installation-save} 仅当上方代码已运行、p_first已创建时执行: ```{r example-4, eval=FALSE} ggsave("first-comparison.png", p_first, width = 10, height = 5, units = "in", dpi = 144) ``` 预览与保存使用相同10×5 in尺寸,参见[输出](#output)。 ### 常见运行问题 {#installation-troubleshooting} 找不到对象时,检查是否运行了本页准备;找不到函数时先确认版本。保存位置由getwd()决定。其他格式的可选依赖只在相应专题需要,基础模块不要求安装Bioconductor或Biopython。 ## 选择合适的学习模块 {#modes}

为你的问题选择布局,而不是为了圆形效果改变问题。下面用同一批真实随包记录比较三种表达。

### 怎么选择? {#modes-choose} | 场景 | 更合适的图 | 应避免的误读 | | --- | --- | --- | | 几条序列之间的总体对应关系 | 弦图 | 连线交叉本身不等于倒位 | | 一条质粒或环形序列上的注释 | 圆图 | 多条序列不能塞进单序列坐标 | | 比较位置、基因顺序与局部邻域 | 共线性图 | 显示对齐或翻转不等于生物学结论 | 三种图都消费已有数据,不计算新的 BLAST 比对。先尝试下面的最小组合,再进入[原始记录流程](#real-data)、[完整质粒图](#plasmids)或[局部同源比较](#homology)。 ### 本页准备 {#modes-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-5, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") library(ggchord) feature_palette <- c( CDS = "#993366", promoter = "#31849B", rep_origin = "#F1E51D", primer_bind = "#A020F0", misc_feature = "#A6ACB3", protein_bind = "#31849B" ) 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) ```
下列对象都可按普通 ggplot 组合, 打印或使用 `ggsave()` 保存。 ### 弦图:比较多条序列 {#modes-chord} ```{r example-6, eval=FALSE} p_chord <- ggchord(seq_data = seqs, ribbon_data = links, gene_data = genes) + geom_link_ribbon(aes(ribbon_fill = qaccver), alpha = .7) + scale_ribbon_fill_manual(values = seq_palette, guide = "none") + geom_seq(show.legend = FALSE) + geom_gene(position = position_strand(.1), width = .04) + geom_seq_label(size = 4, seq_label_radius = .84, seq_label_hjust = .5) + coord_chord() + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + doc_theme p_chord ```
随包序列与已有比对区间的弦图
随包序列与已有比对区间的弦图 · 点击放大查看
连接按 query 序列标识配色,与骨架使用同一类别色板;这不表示相似度或同源基因分组。按真实相似度配色见[原始记录教程](#real-data-chord)。 `coord_chord()` 控制全局旋转和拟合。逐序列半径、曲率、间隙和方向属于 `geom_seq()`。 连接控制点为 NULL 时,弦图保留历史的原点路径,并不表示各模式统一使用直线。 区间连接默认避障为 `uniform`,点连接默认避障为 `none`。 ### 共线性图:对齐局部比较 {#modes-collinear} ```{r example-7, eval=FALSE} anchors <- genes |> group_by(accver) |> slice_max(end - start, n = 1, with_ties = FALSE) |> ungroup() |> select(accver, start, end) p_collinear <- ggchord(seq_data = seqs, ribbon_data = links, gene_data = genes) + geom_link_ribbon(aes(ribbon_fill = qaccver), alpha = .7) + scale_ribbon_fill_manual(values = seq_palette, guide = "none") + geom_seq() + geom_gene(position = position_strand(.1)) + geom_seq_label(size = 4) + coord_collinear(anchor = anchors, align = "center", orientation = "auto") + doc_axis() + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + doc_theme p_collinear ```
按选定注释锚定的随包序列共线性图
按选定注释锚定的随包序列共线性图 · 点击放大查看
本例分别选每条序列最长的已知基因作显示锚点,不将它们当作同源基因。 `anchor` 对齐指定区间,`orientation = "auto"` 按现有证据选择支持的显示方向。 应查看方向诊断,不能直接把显示翻转解释为生物学倒位。区间连接默认连接相邻显示行; 使用 `adjacent_only = FALSE` 或明确 `pairs` 保留其他连接。非相邻边框默认虚线, 显式样式优先。这些规则与弦图不同。[局部视图与分段](#views)为裁剪或局部翻转 保留源坐标。 ### 圆图:注释单条序列 {#modes-circular} ```{r example-8, eval=FALSE} circle_features <- features |> filter(type %in% c("CDS", "rep_origin")) p_circular <- ggchord(seq_data = plasmid_seq) + geom_seq() + geom_feature(aes(feature_fill = type), data = circle_features, position = position_plasmid()) + geom_feature_label_repel(data = circle_features, position = position_plasmid(), size = 4) + geom_seq_center_label() + scale_feature_fill_manual(values = feature_palette, breaks = unique(circle_features$type)) + coord_circular() + doc_theme p_circular ```
pUC19 注释的单序列圆图
pUC19 注释的单序列圆图 · 点击放大查看
本例只选 CDS 与复制起点显示,保留完整序列的 bp 刻度。 `coord_circular()` 要求单条序列。通用注释可带未知链。 `geom_feature_plasmid()` 是有独立默认值的便利预设,应在需要这些默认值时显式选择。 引物和酶切图层见[识别注释](#recognition)。 ### 完成后检查 {#modes-check-result} 先看序列数:单序列注释用圆图;多序列总体连接用弦图;位置、距离或邻域比较用共线性图。
继续:开始使用:绘制第一张图 →
## 1.1 输入表与字段含义 {#chord-data} 先认识表格,再决定使用哪些图层。弦图是ggchord最早的核心视图;早期工作流围绕BLAST比对表展开,因此保留了紧凑的BLAST风格字段。这里的“多序列比对弦图”展示多条序列间已有的区间比对,绘图本身不执行多序列比对算法。 ### 三张表的最小形状 {#chord-data-tables} | 表 | 必需列 | 每行的含义 | | --- | --- | --- | | seq_data | accver, length | 一条序列及其完整长度,bp | | ribbon_data | qaccver, saccver, qstart, qend, sstart, send | 两条序列上的一对已有比对区间 | | gene_data | accver, start, end, strand | 一个有已知正负链的基因区间 | 只画骨架时,后两张表都不需要。通用注释可保留未知链,请使用 `geom_feature()`,不要冒充有方向的基因。 ### 名称与可选列 {#chord-data-names} `accver` 源于 accession.version,但值可为任意稳定字符串,例如自己的contig名称;不会自动添加或删除版本号。`q` 是query,`s` 是subject,所以 `qstart` 是query端起点。两个标识都必须能在序列表中找到。 `pident` 是百分比相似度,仅映射或筛选相似度时需要;比对表的 `length` 是比对长度,序列表的 `length` 是完整序列长度,二者不能混用。`evalue`、`bitscore`、`qlen`、`slen` 按分析需求保留。基因的 `anno` 是可选注释文字;要画标签时提供它。其他类别列可供 `aes()` 映射,不是强制输入。 ### 查看真实表格 {#chord-data-inspect} ```{r example-9, eval=FALSE} library(ggchord) library(dplyr) seq_data_example |> select(accver, length) |> slice_head(n = 3) ribbon_data_example |> select(qaccver, saccver, qstart, qend, sstart, send) |> slice_head(n = 3) gene_data_example |> transmute(accver, start, end, strand = source_strand, anno) |> slice_head(n = 3) ``` 这些行来自随包真实记录;原始生物学链在该历史教学对象的 `source_strand` 中,因此显式恢复。自己的GFF3读入结果直接使用其 `strand`。 ### 坐标与方向 {#chord-data-coordinates} 使用一基闭区间bp坐标。基因 `start <= end`,方向另存于 `strand`。连接端点次序可表达反向比对;不要一律排序。未知完整长度不能由最大特征终点推断。详细契约见[数据与坐标](#data-coordinates)。 继续:[1.2 从分析结果到输入表](#chord-import)。 ## 1.2 生成与导入比对数据 {#chord-import} 先有序列与分析结果,再由ggchord读取;没有比对表时不应为了连线伪造同源关系。 ### 从FASTA与GFF3开始 {#chord-import-files} 解压[教学输入包](https://github.com/DangJem/ggchord/tree/main/examples),使当前目录包含 `examples/`。FASTA提供完整长度,GFF3提供区间和链;保留原始记录,在显示表中选择必要字段。
准备代码 · 在本页运行一次 ```{r example-10, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
```{r example-11, eval=FALSE} library(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ``` `show_alignments` 保留32条原始HSP,`show_links` 明确筛为12条;`show_genes` 保留全部266条CDS,`show_features` 按长度至少500 bp、序列内注释顺序分四组各选一个,并补充有来源的负链首尾注释用于展示。筛选不是重跑比对,也不证明功能同源。 坐标排查时可用tidyr将四个端点列转成长表,原始连接表保持原样: ```{r example-12, eval=FALSE} link_endpoints <- show_links |> select(qaccver, saccver, qstart, qend, sstart, send) |> pivot_longer( cols = c(qstart, qend, sstart, send), names_to = c("side", "endpoint"), names_pattern = "([qs])(start|end)", values_to = "position" ) head(link_endpoints) ``` ### 用BLAST产生自己的结果 {#chord-import-blast} 以下命令是分析者在安装BLAST后对自己的文件执行的生产步骤,网站构建不运行它们。 ```sh blastn -query query.fna -subject subject.fna -outfmt 6 -out result.tsv ``` ```{r example-13, eval=FALSE} library(ggchord) blast_source <- read_blast(file = "result.tsv") ``` 无自定义字段列表的 `-outfmt 6` 为标准12列表,7另带注释;完全不写outfmt是其他格式。query/subject ID由读取器映射到qaccver/saccver。参见[NCBI字段说明](https://www.ncbi.nlm.nih.gov/sites/books/NBK279684/table/appendices.T.options_common_to_all_blast/)和[核酸/蛋白比对教程](#alignments)。随站历史HSP只是格式转换,没有冒充本轮新BLAST结果。 ### 已有其他格式时 {#chord-import-alternatives} | 来源 | 入口 | 注意 | | --- | --- | --- | | 已读表格 | as_ggchord_seq/feature/link | 显式mapping映射角色,保留原表 | | BED、PAF | read_bed、read_paf | 读取器只转换一次零基半开坐标 | | GenBank | read_genbank | 需要可用Biopython;保留记录与分段来源 | | GRanges、Seqinfo | as_ggchord_feature、as_ggchord_seq | 完整长度来自Seqinfo,未知链不转成正链 | | GInteractions | as_ggchord_link、as_ggchord_seq | 第一锚点为query;仍需可靠完整长度 | 这些适配器对应[用户issue #2](https://github.com/DangJem/ggchord/issues/2)提出的需求。当前代码已有入口;issue中的历史“开发版未经测试”不等于现阶段所有组合均已验证。本地缺失可选包的路径会明确跳过。[格式专题](#formats-ranges)给出可选对象的完整代码和限制。 继续:[1.3 从骨架逐层画起](#chord-build)。 ## 1.3 从骨架逐层添加 {#chord-build} 先完成每个小步骤,再查看综合图。四步复用同一组数据,直接比较每次新增图层的作用。 ### 本页准备 {#chord-build-prepare} 先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples)。
准备代码 · 在本页运行一次 ```{r example-14, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ```
### 第一步:只有序列骨架 {#chord-build-backbones} ```{r example-15, eval=FALSE} p_learn_seq <- ggchord(seq_data = show_sequences) + geom_seq() + geom_seq_label(size = 4) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_seq_position_continuous(breaks = c(0, 20000, 40000), minor_breaks = NULL) + coord_chord() + doc_theme p_learn_seq ```
弦图第一步:序列骨架
弦图第一步:序列骨架 · 点击放大查看
`geom_seq()` 画骨架,`geom_seq_label()` 标识序列,`coord_chord()` 选择整体视图;此时不需要连接或基因输入。 ### 第二步:加入已有比对 {#chord-build-links} ```{r example-16, eval=FALSE} p_learn_links <- p_learn_seq + geom_link_ribbon( aes(ribbon_fill = pident), data = show_links, adjacent_only = FALSE, link_avoid = "smooth" ) + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) p_learn_links ```
弦图第二步:已有比对
弦图第二步:已有比对 · 点击放大查看
相似度由aes和scale表达;显式保留非相邻连接,让后面替换坐标时仍使用相同的连接数据。 ### 第三步:加入精选基因 {#chord-build-genes} ```{r example-17, eval=FALSE} p_learn_genes <- p_learn_links + geom_gene(data = show_features, position = position_strand(0.08)) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + guides(gene_fill = strand_guide) p_learn_genes ```
弦图第三步:精选基因
弦图第三步:精选基因 · 点击放大查看
`position_strand()` 将正负链分到骨架两侧。仅展示真实筛选的注释,原表仍保留全部CDS。 ### 第四步:给每个展示特征加标签 {#chord-build-labels} ```{r example-18, eval=FALSE} p_learn_labels <- p_learn_genes + geom_gene_label_repel( data = show_features, label_layout = "arc", label_wrap = 24, label_max_lines = 3, position = position_strand(0.08), size = 3 ) p_learn_labels ```
弦图第四步:逐一添加标签
弦图第四步:逐一添加标签 · 点击放大查看
同一特征表交给箭头层与repel标签层;标签层不另行筛选。与单独添加图层相比,改名、删行或排序会改变业务含义,应保留明确中间对象。 继续:[1.4 方向、半径、曲率和避障](#chord-tuning)。 ## 1.4 方向、曲率与避障 {#chord-tuning} 这些调整属于不同职责:geom控制逐序列几何,Position控制局部放置,coord控制整体视图,scale与guide负责颜色和图例。 ### 本页准备 {#chord-tuning-prepare} 先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples)。
准备代码 · 在本页运行一次 ```{r example-19, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ```
### 先检查方向证据 {#chord-tuning-orientation} `show_optimization` 只优化显示方向,保留序列顺序;按真实比对长度加权。检查其seq_orientation与score_before/score_after,不能把显示翻转解释为新的生物学倒位结论。自动优化是启发式,不保证全局最优。 ### 将功能组合成可读的图 {#chord-tuning-parameters} ```{r example-20, eval=FALSE} show_curvature <- c( "MT108731.1" = 0, "MT118296.1" = 0.85, "OQ646790.1" = 1.1, "OR222515.1" = -0.4 ) show_radius <- c( "MT108731.1" = 1, "MT118296.1" = 1.05, "OQ646790.1" = 0.95, "OR222515.1" = 1.08 ) p_show_chord <- ggchord(show_sequences, show_links, show_features) + geom_link_ribbon(aes(ribbon_fill = pident), link_avoid = "smooth", alpha = 0.58, linewidth = 0.18) + geom_seq( seq_orientation = show_optimization$seq_orientation, seq_curvature = show_curvature, seq_radius = show_radius, seq_gap = 0.06, linewidth = 1.1 ) + geom_gene(position = position_strand(0.07), width = 0.035) + geom_gene_label_repel( data = show_labels, label_layout = "radial", label_wrap = 24, size = 3.1, label_max_lines = 3, position = position_strand(0.07) ) + geom_seq_label(size = 4, seq_label_radius = 0.84, seq_label_hjust = 0.5) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + guides(gene_fill = strand_guide) + scale_seq_position_continuous(breaks = c(0, 20000, 40000), minor_breaks = NULL) + coord_chord(rotation = 50) + doc_theme + labs( title = "Four genomes, one connected view", subtitle = "Signed curvature and radius · selected strand-aware CDS · local ribbon clearance" ) p_show_chord ```
四基因组弦图:混合骨架曲率与实测相似度
四基因组弦图:混合骨架曲率与实测相似度 · 点击放大查看
命名向量逐序列匹配:曲率0是直线,正负值向相反方向弯曲,绝对值影响弓高;半径改变序列位置。上图同时演示自动方向、不同半径、零/正/负曲率和局部避障。参数不修改源坐标。 ### 避障方式为何看起来不同 {#chord-tuning-clearance} `link_avoid = "uniform"` 在整个端区间留统一空隙;`"smooth"` 只在特征附近平滑退让,形成局部缺口;`"none"` 不做特征避障。`link_gap = NULL` 才启用自动规则,给出固定数值会覆盖自动间距。避障检测箭头/特征几何,不避让文字,也不会自动绕过跨行连接途经的整条中间序列。 ### 颜色与导出 {#chord-tuning-guides} identity采用独立左侧长色条,序列和链图例在底部。链图例显式传递方向覆盖,箭头符号与图中几何一致。[样式专题](#styling)解释图例职责;按12×10 in导出,最后到[1.7 首页综合示例](#chord)核对数据与结果。 ## 1.5 筛选与整理连接 {#ribbons}

减少连接拥挤,同时保留每一步的来源:筛选、去重、合并和聚束有不同含义。

### 本页准备 {#ribbons-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 涉及文件时,先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples),使工作目录包含 `examples/`。
准备代码 · 在本页运行一次 ```{r example-21, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) sequence_source <- read_fasta_lengths(files = "examples/fasta/*.fna", source_file = TRUE) seq_real <- sequence_source |> select(accver, length) annotation_source <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep", source_file = TRUE) feature_real <- annotation_source |> select(accver, start, end, strand, type, anno) alignment_source <- read_blast(files = "examples/blastn-standard/*.tsv", source_file = TRUE) link_real <- alignment_source |> select(qaccver, saccver, qstart, qend, sstart, send, pident, length) real_validation <- validate_ggchord_data(seq_real, link_real) real_validation real_prepared <- prepare_ggchord_data(seq_real, link_real, features = list(annotation = feature_real) ) real_filtered <- filter_ggchord_ribbons(link_real, min_pident = 80, min_length = 500) # Explicit display subset: the six longest CDS per sequence; raw annotations stay intact. real_display_features <- feature_real |> group_by(accver) |> slice_max(end - start + 1, n = 6, with_ties = FALSE) |> ungroup() real_labels <- real_display_features |> filter(anno != "hypothetical protein") |> group_by(accver) |> slice_head(n = 2) |> ungroup() real_filtered$report ```
### 从原始连接表开始 {#ribbons-input} 先用[真实记录工作流](#real-data-selection)创建 `seq_real`、`link_real` 和 `real_filtered`,保留原表及筛选报告。 ```{r example-22, eval=FALSE} unique_links <- deduplicate_ggchord_ribbons(real_filtered$data, by = "overlap", min_reciprocal_overlap = .9 ) merged_links <- merge_ggchord_ribbons(unique_links$data, max_gap = 100, min_pident_difference = 2 ) bundled_links <- bundle_ggchord_ribbons(link_real, seq_real, bins = 30) p_density <- ggchord(seq_real, link_real, validate = "none") + geom_seq(show.legend = FALSE) + geom_seq_label(size = 4, seq_label_radius = .84, seq_label_hjust = .5) + stat_ribbon_density(aes(ribbon_alpha = after_stat(density)), fill = "#269B82") + scale_ribbon_alpha_continuous( name = "Relative density", range = c(.1, .6), guide = guide_ggchord_legend(position = "bottom", nrow = 1, theme = doc_legend_theme) ) + scale_seq_colour_manual(values = seq_palette) + coord_chord() + doc_theme p_bundle <- ggchord(seq_real, link_real, validate = "none") + geom_seq() + stat_ribbon_bundle(bins = 30, fill = "#269B82") + coord_chord() + doc_theme p_density ``` | 项目 | 结果 | | --- | --- | | 筛选后的比对数 | 8 | | 重叠去重后数量 | 8 | | 合并后的显示区间数 | 8 | | 聚束输出行数 | 28 | ### 理解每步转换 {#ribbons-transformations} 筛选保留满足已声明阈值的观测;互惠重叠去重选择已有代表观测,不累加相似度; 合并把邻近兼容区间组合为显示外包范围;聚束按邻近 query/subject 位置形成汇总。 逐步检查 `$report` 和源行成员,特别注意冲突的额外元数据。 合并或聚束范围不是重新计算的核苷酸比对,估计长度保留标记,不凭空生成相似度。 ### 密度是显式统计 {#ribbons-density}
原始比对记录的区间密度
原始比对记录的区间密度 · 点击放大查看
`stat_ribbon_density()` 映射计算后的密度,`stat_ribbon_bundle()` 在 build 时执行 明确聚合,普通区间连接几何层仍逐行绘制。计数、已报告长度和相似度加权有各自单位, 更不透明的连接不一定表示更强的独立同源证据。没有方向证据的点锚,不能因端点 相等就获得聚合方向。 ### 选择区间区间连接或点连接 {#ribbons-points} ```{r example-23, eval=FALSE} # Midpoints summarize existing HSPs for display; they are not new alignments. points <- ribbon_data_example |> transmute( qaccver, saccver, qpos = floor((qstart + qend) / 2), spos = floor((sstart + send) / 2), pident ) p_points <- ggchord(seq_data = seqs) + geom_seq() + geom_seq_label(size = 4) + geom_link_line(aes(link_colour = pident), data = points, arrow = arrow(length = unit(2, "mm")), linewidth = .7 ) + scale_link_colour_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = guide_ggchord_colourbar( available_aes = "link_colour", position = "bottom", direction = "horizontal", theme = doc_legend_theme + theme(legend.key.width = unit(65, "mm"), legend.key.height = unit(5, "mm")) ) ) + scale_seq_colour_manual(values = seq_palette) + coord_chord() + doc_theme p_points ```
从已有 HSP 区间计算中点的点连接
从已有 HSP 区间计算中点的点连接 · 点击放大查看
点位置由随包真实 HSP 的中点向下取整得到,颜色使用已报告的 `pident`。line 使用 `qpos/spos`,而非区间端点,箭头由 query 指向 subject。点连接默认避障为 `none`,区间连接为 `uniform`。 全局弦图旋转属于坐标系,直线模式选对与相邻行默认见[三种模式](#modes-collinear)。 点连接的颜色条明确指定 `available_aes = "link_colour"`。普通 ggplot2 颜色条和 包装器默认值不接受全部扩展角色;自定义图例时应明确选择对应美学角色。 ### 完成后检查 {#ribbons-check-result} 先检查各步骤 report 和成员行,再读图。聚合带的范围不是新比对;点连接是已有 HSP 中点的摘要。
继续:查看局部和分段区域 →
## 1.6 原始文件完整流程 {#real-data}

把原始 FASTA、GFF3 和标准 BLAST 表格组合成一张可追溯的序列比较图。你将检查输入、选择显示子集,再对照弦图与全长概览。

### 本页准备 {#real-data-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 涉及文件时,先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples),使工作目录包含 `examples/`。
准备代码 · 在本页运行一次 ```{r example-24, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
这条完整工作流使用源码仓库已有的四条序列记录,不需要重新比对或预测基因。 使用匹配的开发 checkout,或[下载教学输入](https://github.com/DangJem/ggchord/tree/main/examples),解压后让 工作目录下包含 `examples/`。保存图形时同时记录包版本与[构建清单](https://github.com/DangJem/ggchord/tree/main/website)。 ### 1. 读取并检查原始记录 {#real-data-read} ```{r example-25, eval=FALSE} library(dplyr) sequence_source <- read_fasta_lengths(files = "examples/fasta/*.fna", source_file = TRUE) seq_real <- sequence_source |> select(accver, length) annotation_source <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep", source_file = TRUE) feature_real <- annotation_source |> select(accver, start, end, strand, type, anno) alignment_source <- read_blast(files = "examples/blastn-standard/*.tsv", source_file = TRUE) link_real <- alignment_source |> select(qaccver, saccver, qstart, qend, sstart, send, pident, length) real_validation <- validate_ggchord_data(seq_real, link_real) real_validation ``` FASTA 头部提供原样 accession version 与长度,GFF3 提供 CDS 区间和真实链方向, BLAST 文件提供已有比对;读取器不运行 BLAST。继续前检查 `real_validation`: 连接端点递减可能是合法的反向命中。不能把未知注释链改成 `+` 来满足基因快捷层。 ### 2. 明确显示筛选规则 {#real-data-selection} ```{r example-26, eval=FALSE} real_prepared <- prepare_ggchord_data(seq_real, link_real, features = list(annotation = feature_real) ) real_filtered <- filter_ggchord_ribbons(link_real, min_pident = 80, min_length = 500) # Explicit display subset: the six longest CDS per sequence; raw annotations stay intact. real_display_features <- feature_real |> group_by(accver) |> slice_max(end - start + 1, n = 6, with_ties = FALSE) |> ungroup() real_labels <- real_display_features |> filter(anno != "hypothetical protein") |> group_by(accver) |> slice_head(n = 2) |> ungroup() real_filtered$report ``` | 项目 | 结果 | | --- | --- | | 序列数 | 4 | | 注释记录数 | 266 | | 弦图中选出的 CDS 数 | 24 | | 原始比对记录数 | 32 | | 通过显示筛选的比对数 | 8 | | 选出的文字标签数 | 6 | 显示连接保留相似度 ≥80%、已报告比对长度 ≥500 bp 的记录。弦图每条序列选择最长 六条已导入 CDS,并在这些 CDS 中最多标记两条非 hypothetical protein 注释。这是显示规则,不是生物学结论,未显示的 基因不表示不存在。原始 `feature_real`、`link_real` 不变,`real_prepared$report` 和 `real_filtered$report` 保留准备与筛选证据。链方向不重编码;这与生成说明中 明确进行显示链重编码的小型随包教学 fixture 不同。 ### 3. 构建弦图比较 {#real-data-chord} ```{r example-27, eval=FALSE} p_real_chord <- ggchord(seq_data = seq_real, ribbon_data = real_filtered$data, validate = "none") + geom_link_ribbon(aes(ribbon_fill = pident), alpha = .65) + geom_seq(show.legend = FALSE) + geom_feature(aes(feature_fill = strand), data = real_display_features, width = .045, position = position_strand(.08) ) + geom_feature_label_repel( data = real_labels, label_layout = "radial", label_wrap = 20, size = 4, position = position_strand(.08) ) + geom_seq_label(size = 4, seq_label_radius = .84, seq_label_hjust = .5) + coord_chord() + scale_seq_colour_manual(values = seq_palette) + scale_feature_fill_manual(values = gene_palette, breaks = c("+", "-")) + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + doc_theme p_real_chord ```
原始序列、选定 CDS 与已有比对的弦图
原始序列、选定 CDS 与已有比对的弦图 · 点击放大查看
先读序列名称,再读真实链方向的注释箭头及区间连接。区间连接表达已有比对区间 和映射的相似度,连接交叉本身不构成重排证据。选定注释与更宽的比对区间分开阅读。 科学解释涉及显示子集之外的注释时,应使用完整输入表。 ### 4. 在线性视图检查全部注释 {#real-data-linear} ```{r example-28, eval=FALSE} p_real_linear <- ggchord(seq_real, real_filtered$data, validate = "none") + geom_link_ribbon(fill = "#6BAFA6", alpha = .45) + geom_seq() + geom_seq_label(size = 4) + geom_feature(data = feature_real, feature_fill = "#CE1536", show.legend = FALSE, position = position_strand(.18)) + geom_seq_scale(length = 10000) + coord_collinear() + doc_axis() + scale_seq_colour_manual(values = seq_palette) + doc_theme p_real_linear ```
原始序列、全部导入 CDS 与筛选连接的线性图
原始序列、全部导入 CDS 与筛选连接的线性图 · 点击放大查看
这张图绘制全部导入注释。区间连接默认只连接相邻显示序列,保留所有比较需要显式 图层设置。bp 参照条属于共线性坐标。裁剪、源坐标轴与独立窗口见[局部视图](#views), 按图集明确尺寸预览保存见[输出](#output)。 ### 5. 随图保留证据 {#real-data-provenance} 教学输入包包含未改写的 FASTA/GFF3/BLAST、SHA256 清单和共享示例脚本。 绘图清单记录代码 hash、PNG 设备、宽高和 dpi。accession 名称标识来源记录, 图片不替代原始注释或比对证据。 ### 先选列,再传入函数 {#real-data-minimal-fields} `*_source` 对象保留原字段与来源;`seq_real` 只有两列,`feature_real` 只保留几何、 类型和注释文字,`link_real` 因为本例实际筛选和映射相似度,才额外保留 `pident` 和已报告的 `length`。这里使用标准 12 列转换文件,不要求历史 17 列布局。 随包基因示例将真实链保存在 `source_strand`;简短例子恢复该方向后,只选四列传入 基因图层。格式和单位的区别见[比对输入教程](#alignments)。 ### 完成后检查 {#real-data-check-result} 检查序列 ID 在三张表中一致,查看筛选报告,再确认图例表达相似度与链方向。全长概览用于定位;若要研究具体 CDS,请继续聚焦邻域。
继续:连接同源基因 →
### 保存本页结果 {#real-data-save-result} 在工作目录中保存刚刚创建的图;预览时使用相同宽高。 ```{r example-29, eval=FALSE} ggsave("phage-comparison.png", p_real_chord, width = 10, height = 8, units = "in", dpi = 144) ``` ## 1.7 弦图综合展示 {#chord}
把四条基因组放在同一张关系图中,组合直线与弧形骨架、保留真实链方向的基因、连续相似度标度和精选标签,同时保留数据来源。
### 综合结果 {#chord-overview}
四基因组弦图:混合骨架曲率与实测相似度
四基因组弦图:混合骨架曲率与实测相似度 · 点击放大查看
本页是模块一的终点。初学请按[输入表](#chord-data) → [生成与导入](#chord-import) → [逐层绘图](#chord-build) → [参数与避障](#chord-tuning)学习。四条真实序列上只展示18个精选CDS,每个均交给repel标签层,避免密集箭头淹没连接。 ### 准备原始记录 {#chord-prepare} 将[教程输入包](https://github.com/DangJem/ggchord/tree/main/examples)解压到工作目录,使其包含 `examples/`。使用 `install.packages(c("dplyr", "purrr", "tidyr"))` 安装示例可选依赖;完整流程用它们整理表格和计算 GC 轨道。
准备代码 · 在本页运行一次 ```{r example-30, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
```{r example-31, eval=FALSE} library(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ``` 输入包含四条未改写的 FASTA、对应 GFF3 注释和 32 条原始 HSP。展示保留长度至少 900 bp、相似度至少 75% 的 HSP,每对序列最多三条,以减少拥挤;没有合并或编造比对。 ### 组合图层 {#chord-compose} ```{r example-32, eval=FALSE} show_curvature <- c( "MT108731.1" = 0, "MT118296.1" = 0.85, "OQ646790.1" = 1.1, "OR222515.1" = -0.4 ) show_radius <- c( "MT108731.1" = 1, "MT118296.1" = 1.05, "OQ646790.1" = 0.95, "OR222515.1" = 1.08 ) p_show_chord <- ggchord(show_sequences, show_links, show_features) + geom_link_ribbon(aes(ribbon_fill = pident), link_avoid = "smooth", alpha = 0.58, linewidth = 0.18) + geom_seq( seq_orientation = show_optimization$seq_orientation, seq_curvature = show_curvature, seq_radius = show_radius, seq_gap = 0.06, linewidth = 1.1 ) + geom_gene(position = position_strand(0.07), width = 0.035) + geom_gene_label_repel( data = show_labels, label_layout = "radial", label_wrap = 24, size = 3.1, label_max_lines = 3, position = position_strand(0.07) ) + geom_seq_label(size = 4, seq_label_radius = 0.84, seq_label_hjust = 0.5) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + guides(gene_fill = strand_guide) + scale_seq_position_continuous(breaks = c(0, 20000, 40000), minor_breaks = NULL) + coord_chord(rotation = 50) + doc_theme + labs( title = "Four genomes, one connected view", subtitle = "Signed curvature and radius · selected strand-aware CDS · local ribbon clearance" ) p_show_chord ``` `geom_seq(seq_curvature = ...)` 通过命名向量将曲率绑定到稳定的序列标识,`0` 表示直线。曲率只改变展示几何,不改变序列长度、生物学链方向或比对端点。 ### 阅读与调整 {#chord-read} 先看序列颜色和基因方向,再沿较大的比对区间阅读连接。连接交叉本身不能证明重排。相似度色条与[共线性视图](#collinear)使用相同范围和配色。 需要减少连接时查看[连接筛选](#ribbons),调整文字密度时查看[标签](#labels),改变半径和曲率时查看[逐序列参数](#parameters)。从文件读取开始学习可先看[真实序列比较](#real-data)。 ### 按预定尺寸保存 {#chord-save} ```{r example-33, eval=FALSE} ggsave("four-genome-chord.png", p_show_chord, width = 12, height = 10, units = "in", dpi = 144) ``` ## 2.1 复用弦图的数据 {#collinear-data} 共线性图是ggchord从弦图扩展出的直线视图。设计目标是保留共同数据和图层,尽可能通过替换坐标系完成转换。 ### 相同的三张表 {#collinear-data-tables} | 输入 | 必需列 | 共线性含义 | | --- | --- | --- | | seq_data | accver, length | 每条序列占一行,共享bp横向比例 | | ribbon_data | qaccver, saccver, qstart, qend, sstart, send | 两行之间的已有区间对应 | | gene_data | accver, start, end, strand | 行上基因,正负链由Position上下分列 | 可选列和BLAST命名来历与[1.1](#chord-data)相同;相似度需要pident,标签需要anno。局部窗口的source字段用于保留原始坐标,不能将显示间隙解释为缺失DNA长度。 ### 数据如何获得 {#collinear-data-import} [1.2](#chord-import)的FASTA/GFF3/BLAST流程可以直接复用;已有PAF、GRanges、GInteractions通过[适配器](#formats)读入。蛋白比对必须先[投影到已知CDS坐标](#projection),不能把aa直接画成bp。 ### 当前转换边界 {#collinear-data-contract} [下一页](#collinear-build)给出只替换coord的实际例子。显式圆形半径、曲率、ring和径向序列标签位置在当前共线性合同中会被拒绝,而不是悄悄忽略。将这些坐标特有样式留给各自展示图;“任意组合完美转换”仍是长期目标,不是当前保证。 共线性默认只连接相邻显示行;要保持弦图的连接集合,需要在共同图层明确 `adjacent_only = FALSE`。显示方向可手动指定或交给coord自动判断,两种入口不能同时使用。 ## 2.2 只替换坐标系,再逐层添加 {#collinear-build} 先验证共同语法,再为直线视图调整排版。以下三个对象只在弦图教学对象上替换坐标系,不改表格、不重新计算比对。 ### 本页准备 {#collinear-build-prepare} 先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples)。
准备代码 · 在本页运行一次 ```{r example-34, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ```
准备代码 · 在本页运行一次 ```{r example-35, eval=FALSE} p_learn_seq <- ggchord(seq_data = show_sequences) + geom_seq() + geom_seq_label(size = 4) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_seq_position_continuous(breaks = c(0, 20000, 40000), minor_breaks = NULL) + coord_chord() + doc_theme p_learn_seq p_learn_links <- p_learn_seq + geom_link_ribbon( aes(ribbon_fill = pident), data = show_links, adjacent_only = FALSE, link_avoid = "smooth" ) + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) p_learn_links p_learn_genes <- p_learn_links + geom_gene(data = show_features, position = position_strand(0.08)) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + guides(gene_fill = strand_guide) p_learn_genes p_learn_labels <- p_learn_genes + geom_gene_label_repel( data = show_features, label_layout = "arc", label_wrap = 24, label_max_lines = 3, position = position_strand(0.08), size = 3 ) p_learn_labels ```
### 替换coord {#collinear-build-switch} ```{r example-36, eval=FALSE} # Reuse exactly the same data and layers; replace only the coordinate system. p_linear_seq <- p_learn_seq + coord_collinear() p_linear_links <- p_learn_links + coord_collinear() p_linear_labels <- p_learn_labels + coord_collinear(ratio = 0.65) p_linear_labels ``` ### 从骨架看比例 {#collinear-build-backbones}
相同骨架,仅替换坐标系
相同骨架,仅替换坐标系 · 点击放大查看
每一行共享同一bp比例。序列长度不同,行长也不同;不是将每行任意缩放成一样长。 ### 加入连接 {#collinear-build-links}
相同连接,仅替换坐标系
相同连接,仅替换坐标系 · 点击放大查看
相同的HSP保留在图层中,跨行连接也保留,因此可直接看到默认路由的局限。长连接更适合在下一页明确路由。 ### 加入上下分链与标签 {#collinear-build-labels}
相同基因与标签,仅替换坐标系
相同基因与标签,仅替换坐标系 · 点击放大查看
箭头和标签来自同一个筛选表。正负链不改写;显示翻转也不会更改原始strand。继续:[2.3 调整跨行路由](#collinear-routing)。 ## 2.3 跨行连接、避障与比例尺 {#collinear-routing} 相邻行连接与跨行连接有不同阅读负担。先分开数据,再分别控制;保留原始HSP端点,控制点只改变显示路径。 ### 本页准备 {#collinear-routing-prepare} 先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples)。
准备代码 · 在本页运行一次 ```{r example-37, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ```
### 明确长连接的控制点 {#collinear-routing-routes} ```{r example-38, eval=FALSE} # Omit two short, crowded candidates from this linear display only. # Both source rows remain in show_features and in the chord display. show_linear_features <- show_features |> filter(!anno %in% c("tail assembly protein", "gp4 protein")) # Separate adjacent and cross-row links, retaining original endpoint values. show_pair_rows <- show_links |> mutate( query_row = match(qaccver, show_sequences$accver), subject_row = match(saccver, show_sequences$accver), span = abs(query_row - subject_row) ) show_adjacent <- show_pair_rows |> filter(span == 1) # One longest observed HSP per non-neighbour pair keeps the long routes legible. show_cross <- show_pair_rows |> filter(span > 1) |> group_by(qaccver, saccver) |> slice_max(length, n = 1, with_ties = FALSE) |> ungroup() # Inspect a backbone-only layout using the same alignment and gap as the final view. show_linear_coord <- coord_collinear(align = "center", orientation = "auto", ratio = 0.7) show_routing_base <- ggchord(show_sequences, show_links) + geom_seq(seq_gap = 0.42) + show_linear_coord show_reference <- get_chord_layout(show_routing_base)$sequence_reference # Shared controls sit just beyond the intervening backbones, rather than far away. show_cross_controls <- map2(show_cross$query_row, show_cross$subject_row, function(query_row, subject_row) { between <- seq(min(query_row, subject_row) + 1L, max(query_row, subject_row) - 1L) middle_ids <- show_sequences$accver[between] right_edge <- max(show_reference$x_offset[middle_ids] + show_reference$lens[middle_ids] * show_reference$x_scale) middle_y <- mean(show_reference$y[show_sequences$accver[c(query_row, subject_row)]]) c(right_edge + if (abs(query_row - subject_row) == 3) 0.85 else 0.65, middle_y) }) p_show_collinear <- ggchord(show_sequences, gene_data = show_linear_features) + geom_link_ribbon( aes(ribbon_fill = pident), data = show_adjacent, link_avoid = "smooth", alpha = 0.48, linewidth = 0.22 ) + geom_link_ribbon( aes(ribbon_fill = pident), data = show_cross, adjacent_only = FALSE, link_ctrl_point = show_cross_controls, link_avoid = "smooth", alpha = 0.28, linewidth = 0.3 ) + geom_seq(seq_gap = 0.42, linewidth = 1) + geom_gene(position = position_strand(0.09), width = 0.045) + geom_gene_label_repel( data = show_linear_features |> arrange(desc(nchar(anno)), accver, start), label_layout = "auto", label_wrap = 24, label_side = "auto", position = position_strand(0.09), size = 3.3 ) + geom_seq_label(size = 4) + geom_seq_scale(length = 10000, offset = unit(c(0, 10), "mm")) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + guides(gene_fill = strand_guide) + scale_seq_position_continuous(breaks = c(0, 20000, 40000, 60000, 80000), minor_breaks = NULL) + show_linear_coord + doc_theme + labs( title = "Sequence architecture, across four genomes", subtitle = "Selected labelled CDS · strand-separated arrows · routed cross-row comparisons" ) p_show_collinear ```
四基因组共线性图:分链特征与绕行的跨行连接
四基因组共线性图:分链特征与绕行的跨行连接 · 点击放大查看
线性宣传图省略tail assembly protein与gp4 protein两条拥挤候选,它们仍保留在原始表和弦图中;其余16个特征逐一标注。相邻行保留筛选HSP,非相邻每对只选最长一条。`show_cross_controls` 与 `show_cross` 的行顺序一一对应;筛选或重新排序后应一同重建。控制点单位是导出布局x/y,不是bp。当前接口支持每条连接2个或4个数值;它塑造两条ribbon边的控制位置,并非全局路径规划器。 本例将短序列水平居中,使用骨架预布局导出的真实行位置、长度与偏移计算控制点,放在中间序列右端附近;不再把路径拉到远处。行距与seq_gap及最长骨架宽度有关,不能把bp直接填进控制点。修改行距、顺序或方向后,应重新检查实际路径;不能保证任意控制点都无自交。 ### 局部缺口与虚线 {#collinear-routing-clearance} 上下分链用 `position_strand()`;`link_avoid = "smooth"` 配合默认NULL gap,在箭头附近产生局部退让。跨行外框默认虚线;本例增大linewidth使其可见,不用显式linetype覆盖。此规则依据最终显示邻接,不表示反向比对。 ### 比例尺为何曾经没对齐 {#collinear-routing-ruler} `geom_seq_scale()` 的默认offset是横向2 mm、纵向6 mm,因此原图左端略向右偏移是明确配置,而非bp长度计算出错。本例使用 `offset = unit(c(0, 10), "mm")`,水平起点对齐左侧序列包络,纵向留出标签空间。本例采用水平居中,各行源坐标0不再相互对齐;比例尺对齐左侧包络,反向行的源坐标0还会移到另一端。比例尺衡量距离,不代表某个源区间。 ### 继续深入 {#collinear-routing-next} 局部比较优先用[focus/分段](#views),同源证据见[基因邻域](#homology),最终结果见[2.6 综合图](#collinear)。GC等定量轨道留在[轨道专题](#tracks),首页为标签和连接留空间。 ## 2.4 比较基因邻域 {#homology}

比较两条质粒的 AmpR 邻域。先核对真实编码 DNA,再建立对应关系,最后聚焦到 CDS 两侧各 200 bp。

### 本页准备 {#homology-prepare} 只需随包数据,无需下载文件或重新比对。先加载包和本例的可选排版设置。
准备代码 · 在本页运行一次 ```{r example-39, eval=FALSE} 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) ) } ```
### 1. 提取实际 CDS 与编码 DNA {#homology-membership} 选择随包 pUC19 与 pETDuet-1 的 AmpR 注释,保留 ID、坐标、链和文字。按负链进行反向互补,保证比较的是同一生物学方向的 DNA,而非仅比较注释名称。 ```{r example-40, eval=FALSE} library(dplyr) data(plasmid_example_pUC19) data(plasmid_example_pETDuet_1) homolog_source <- bind_rows(plasmid_example_pUC19, plasmid_example_pETDuet_1) homolog_seq <- homolog_source |> select(accver, length) cluster_features <- homolog_source |> find_common_features() |> filter(type == "CDS", anno == "AmpR") |> select(accver, start, end, strand, anno) |> arrange(match(accver, homolog_source$accver)) |> mutate(feature_id = paste(accver, start, end, sep = ":")) # Membership is computed from exact strand-corrected CDS DNA equality, not gene names. reverse_complement <- function(sequence) { bases <- strsplit(sequence, "")[[1]] chartr("ACGT", "TGCA", paste(rev(bases), collapse = "")) } coding_sequences <- cluster_features |> left_join(select(homolog_source, accver, sequence), by = "accver") |> rowwise() |> mutate( coding_dna = substr(sequence, start, end), coding_dna = if (strand == "-") reverse_complement(coding_dna) else coding_dna ) |> ungroup() cds_dna <- pull(coding_sequences, coding_dna) ``` `cluster_features` 应有两条实际 CDS,`cds_dna` 保存各自的定向编码序列。本例的严格目标是完全相同 DNA;一般同源性分析可使用外部比对与聚类结果,不能要求所有同源基因完全一致。 ### 2. 显式声明成员和序列对 {#homology-links} 用编码 DNA 的完全一致性建立成员表;不同 DNA 不会因为都叫 AmpR 就分入同一组。 ```{r example-41, eval=FALSE} membership <- tibble( feature_id = cluster_features$feature_id, cluster_id = paste0("exact_CDS_", match(cds_dna, unique(cds_dna))) ) homologs <- link_ggchord_clusters(cluster_features, membership, pairs = tibble(qaccver = homolog_seq$accver[1], saccver = homolog_seq$accver[2]) ) loci <- find_ggchord_loci(homolog_seq, cluster_features, targets = cluster_features$feature_id[cluster_features$anno == "AmpR"][1], upstream = 100, downstream = 100 ) ``` 查看 `membership` 与 `homologs$report$comparisons`、`$members`。连接工具消费已有分组,不计算新的序列比对。未知成员与歧义 paralog 会被报告;只有明确选择 `paralogs = "all"` 才请求受界限约束的所有组合。 ### 3. 聚焦到可比较的邻域 {#homology-focus} 全长质粒图会把单个 CDS 压得很小。这里从两条真实 CDS 的源范围构建窗口,两侧各增加 200 bp;原始序列表与注释表保持不变。 ```{r example-42, eval=FALSE} # Compare equivalent local windows instead of shrinking one gene on full plasmids. homolog_windows <- cluster_features |> select(accver, start, end) local_homologs <- focus_ggchord_data(homolog_seq, homologs$data, cluster_features, loci = homolog_windows, expand = 200 ) p_homologs <- ggchord( seq_data = local_homologs$seq_data, ribbon_data = local_homologs$ribbon_data, gene_data = local_homologs$gene_data ) + geom_link_ribbon(fill = "#269B82", alpha = .65) + geom_seq(colour = "#233E4A", show.legend = FALSE) + geom_feature( data = local_homologs$gene_data, feature_fill = "#F1D334", position = position_strand(.10), width = .07 ) + geom_feature_label_repel(data = local_homologs$gene_data, size = 4, label_fit = "shrink") + geom_seq_label(size = 4) + geom_seq_break() + coord_collinear() + doc_axis("source") + doc_theme p_homologs ```
两条质粒的 AmpR 邻域:相同 CDS、200 bp 侧翼与源坐标
两条质粒的 AmpR 邻域:相同 CDS、200 bp 侧翼与源坐标 · 点击放大查看
两条金色箭头表示已核对的相同编码序列,紫色带连接对应 CDS 范围,内部文字直接标明 AmpR。刻度来自各自源序列,因此同一个横向位置可以显示不同源坐标。断点标记说明图中只保留了局部窗口。 `local_homologs$report` 记录保留与裁剪情况。窗口外的基因没有显示,不表示它们不存在。区间连接表达分组对应范围,不是逐碱基比对;跨分段注释的外包范围也不等于外显子级对应。 ### 4. 将有证据的蛋白区间投影到两端 CDS {#homology-projection} ```{r example-43, eval=FALSE} # Exact CDS DNA equality supplies evidence for these selected ungapped residues. matching <- homologs$data |> slice_head(n = 1) paired_coding <- cluster_features |> mutate(phase = 0) paired_cds <- build_ggchord_cds(paired_coding) protein_link <- tibble( qfeature_id = matching$qfeature_id, sfeature_id = matching$sfeature_id, qstart = 1, qend = 20, sstart = 1, send = 20 ) projected_links <- project_ggchord_links(protein_link, paired_cds, ungapped = TRUE) projected_links ``` | 项目 | 结果 | | --- | --- | | 投影到基因组的注释行数 | 1 | | 投影后的核苷酸连接行数 | 1 | 这里选择相同 CDS 的前 20 个残基,因此 `ungapped = TRUE` 有实际序列依据。普通 BLASTp HSP 不能仅凭两端跨度相等作出这个断言。工具保留源蛋白统计,不把蛋白相似度冒充核苷酸相似度。 ### 完成后检查 {#homology-check-result} 两个内部标签都应为 AmpR,箭头保留真实负链方向。对应关系来自编码 DNA;源坐标与聚焦报告解释了局部显示。保存时使用 [10 × 5 in 的明确尺寸](#output)。 下一步:[真实 BLASTp 查询区间读取](#alignments-protein)、[CDS 投影及分段限制](#projection)、[独立局部窗口](#views)。 ### 保存本页结果 {#homology-save-result} 在工作目录中保存刚刚创建的图;预览时使用相同宽高。 ```{r example-44, eval=FALSE} ggsave("ampR-neighbourhood.png", p_homologs, width = 10, height = 5, units = "in", dpi = 144) ``` ## 2.5 局部、锚定与分段 {#views}

为已有输入选择局部窗口或分段视图,同时保留原始位置与显示变换的区别。

### 本页准备 {#views-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-45, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
### 保留来源的局部聚焦 {#views-focus} ```{r example-46, eval=FALSE} focus_loci <- tibble( accver = seqs$accver, start = floor(seqs$length * .25), end = floor(seqs$length * .75) ) focused <- focus_ggchord_data(seqs, links, genes, loci = focus_loci) p_focus <- ggchord( seq_data = focused$seq_data, ribbon_data = focused$ribbon_data, gene_data = focused$gene_data ) + geom_seq() + geom_link_ribbon(fill = "#6BAFA6", alpha = .5) + geom_gene() + geom_seq_break() + geom_seq_label(size = 4) + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + doc_axis("source") + coord_collinear() + doc_theme p_focus ```
保留原始坐标刻度的局部序列视图
保留原始坐标刻度的局部序列视图 · 点击放大查看
focus 把保留位置移到局部一基坐标,同时保留源原点、截断标记与报告。 `boundary = "trim"` 可按线性显示投影裁剪连接,不重新比对序列;缩放后的比对长度 带估计标记。`coordinates = "source"` 恢复源坐标轴标签,重复聚焦后同样适用。 ### 独立窗口与局部翻转 {#views-segments} ```{r example-47, eval=FALSE} windows <- tibble( accver = rep(seqs$accver[1], 2), start = c(1, floor(seqs$length[1] * .65)), end = c(floor(seqs$length[1] * .4), seqs$length[1]), locus_id = c("left_window", "right_window"), row_id = seqs$accver[1], orientation = c(1, -1) ) segmented <- segment_ggchord_data(slice_head(seqs, n = 1), windows = windows) p_segments <- ggchord(seq_data = segmented$seq_data) + geom_seq() + coord_collinear(segments = segmented$segments, segment_gap = 2000) p_segments ``` 各窗口有可逆的源映射,被省略的间隙没有映射。`map_ggchord_position()` 把显式源 位置映射到图中,供普通 ggplot2 注释使用。多个窗口共享源序列时应指定窗口 ID。 显示方向不表示原始链发生改变。 ### 显式生物学关系 {#views-homology} `find_ggchord_loci()` 按声明的注释/名称查询选择位置。 `link_ggchord_clusters()` 要求显式成员表和序列对,基因名称相同不构成同源证据。 `filter_ggchord_ribbons()`、`deduplicate_ggchord_ribbons()`、 `merge_ggchord_ribbons()` 整理已有比对,保留源成员和估计长度标记。 聚束和密度统计汇总已提供连接,不创建新的序列比对。 ### 按源坐标放置普通注释 {#views-mapping} ```{r example-48, eval=FALSE} source_position <- focus_loci$start[1] + 100 source_mark <- map_ggchord_position(p_focus, seqs$accver[1], source_position, source = TRUE) p_marked <- p_focus + ggplot2::geom_point( data = source_mark, aes(x, y), inherit.aes = FALSE, colour = "#D59B17", size = 3 ) p_marked ``` 先运行[focus 例子](#views-focus)。辅助函数返回第一个所选窗口起点后 100 bp 位置的笛卡尔 x/y, 不把全部普通 ggplot2 坐标变成基因组 bp。分段视图应选窗口 ID,检查落在省略间隙 的位置,不跨间隙外推。区域 选择来自明确注释/同源分组 证据时见[显式同源关系](#homology)。 ### 完成后检查 {#views-check-result} 关注裁剪报告、断点与源坐标。被省略的间隙没有映射;显示翻转不应直接解释为生物学倒位。
继续:连接同源基因 →
## 2.6 共线性综合展示 {#collinear}
模块二的综合结果:四条真实基因组、分链特征和向外绕行的跨行连接。
### 综合结果 {#collinear-overview}
四基因组共线性图:分链特征与绕行的跨行连接
四基因组共线性图:分链特征与绕行的跨行连接 · 点击放大查看
共线性来自弦图的坐标表达扩展;复用数据和图层是设计目标。先读[数据](#collinear-data)、[坐标替换](#collinear-build)、[路由与比例尺](#collinear-routing),再运行下方完整代码。沿用弦图的精选候选与相似度标度;线性图省略两条拥挤的短候选,展示16个CDS,每个特征传入标签层。正负链在骨架上下分列。 ### 准备原始记录 {#collinear-prepare} 解压[教学输入包](https://github.com/DangJem/ggchord/tree/main/examples),安装dplyr、purrr、tidyr后运行:
准备代码 · 在本页运行一次 ```{r example-49, eval=FALSE} # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
```{r example-50, eval=FALSE} library(ggchord) library(dplyr) library(purrr) library(tidyr) # Original repository records; extract the tutorial input bundle first. show_sequences <- read_fasta_lengths(files = "examples/fasta/*.fna") |> select(accver, length) show_annotations <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep") show_genes <- show_annotations |> filter(type == "CDS") |> select(accver, start, end, strand, anno) show_alignments <- read_blast(files = "examples/blastn-standard/*.tsv") # At most three substantial observed HSPs per pair; no coordinates are invented. show_links <- show_alignments |> filter(length >= 900, pident >= 75) |> group_by(qaccver, saccver) |> slice_max(length, n = 3, with_ties = FALSE) |> ungroup() # Select up to four source CDS per sequence, spread across annotation order. # No feature is moved or invented; keep complete source tables separately. show_features <- show_genes |> filter(end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> mutate(display_bin = ntile(row_number(), 4), informative = !is.na(anno) & anno != "hypothetical protein") |> group_by(accver, display_bin) |> arrange(desc(informative), desc(end - start), .by_group = TRUE) |> slice_head(n = 1) |> ungroup() |> select(accver, start, end, strand, anno) # Also retain well-separated negative-strand CDS, if not already represented. show_reverse <- show_genes |> filter(strand == "-", end - start + 1 >= 500) |> group_by(accver) |> arrange(start, .by_group = TRUE) |> slice(c(1, n())) |> ungroup() show_features <- bind_rows(show_features, show_reverse) |> distinct(accver, start, end, strand, .keep_all = TRUE) |> arrange(accver, start) show_labels <- show_features show_optimization <- optimize_ggchord_layout( show_sequences, show_links, optimize = "orientation", weight = "length" ) ``` 保留四条完整FASTA、266条CDS及32条原始HSP。相邻行使用明确筛选的观测区间;非相邻每对仅保留最长一条,减轻长连接重叠。 ### 为连接和标签保留空间 {#collinear-gc} 首页不再添加GC轨道,序列组成分析留在[轨道专题](#tracks)。避免将两种不同的阅读任务挤在同一宣传图中。 ### 组合图层 {#collinear-compose} ```{r example-51, eval=FALSE} # Omit two short, crowded candidates from this linear display only. # Both source rows remain in show_features and in the chord display. show_linear_features <- show_features |> filter(!anno %in% c("tail assembly protein", "gp4 protein")) # Separate adjacent and cross-row links, retaining original endpoint values. show_pair_rows <- show_links |> mutate( query_row = match(qaccver, show_sequences$accver), subject_row = match(saccver, show_sequences$accver), span = abs(query_row - subject_row) ) show_adjacent <- show_pair_rows |> filter(span == 1) # One longest observed HSP per non-neighbour pair keeps the long routes legible. show_cross <- show_pair_rows |> filter(span > 1) |> group_by(qaccver, saccver) |> slice_max(length, n = 1, with_ties = FALSE) |> ungroup() # Inspect a backbone-only layout using the same alignment and gap as the final view. show_linear_coord <- coord_collinear(align = "center", orientation = "auto", ratio = 0.7) show_routing_base <- ggchord(show_sequences, show_links) + geom_seq(seq_gap = 0.42) + show_linear_coord show_reference <- get_chord_layout(show_routing_base)$sequence_reference # Shared controls sit just beyond the intervening backbones, rather than far away. show_cross_controls <- map2(show_cross$query_row, show_cross$subject_row, function(query_row, subject_row) { between <- seq(min(query_row, subject_row) + 1L, max(query_row, subject_row) - 1L) middle_ids <- show_sequences$accver[between] right_edge <- max(show_reference$x_offset[middle_ids] + show_reference$lens[middle_ids] * show_reference$x_scale) middle_y <- mean(show_reference$y[show_sequences$accver[c(query_row, subject_row)]]) c(right_edge + if (abs(query_row - subject_row) == 3) 0.85 else 0.65, middle_y) }) p_show_collinear <- ggchord(show_sequences, gene_data = show_linear_features) + geom_link_ribbon( aes(ribbon_fill = pident), data = show_adjacent, link_avoid = "smooth", alpha = 0.48, linewidth = 0.22 ) + geom_link_ribbon( aes(ribbon_fill = pident), data = show_cross, adjacent_only = FALSE, link_ctrl_point = show_cross_controls, link_avoid = "smooth", alpha = 0.28, linewidth = 0.3 ) + geom_seq(seq_gap = 0.42, linewidth = 1) + geom_gene(position = position_strand(0.09), width = 0.045) + geom_gene_label_repel( data = show_linear_features |> arrange(desc(nchar(anno)), accver, start), label_layout = "auto", label_wrap = 24, label_side = "auto", position = position_strand(0.09), size = 3.3 ) + geom_seq_label(size = 4) + geom_seq_scale(length = 10000, offset = unit(c(0, 10), "mm")) + scale_seq_colour_manual( values = seq_palette, name = "Sequence", guide = sequence_guide ) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand") + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + guides(gene_fill = strand_guide) + scale_seq_position_continuous(breaks = c(0, 20000, 40000, 60000, 80000), minor_breaks = NULL) + show_linear_coord + doc_theme + labs( title = "Sequence architecture, across four genomes", subtitle = "Selected labelled CDS · strand-separated arrows · routed cross-row comparisons" ) p_show_collinear ``` 虚线外框标识非相邻显示行,较明显的线宽便于辨认。控制点沿右侧分流,局部smooth避障在箭头附近退让。identity左侧色条与弦图一致,底部链图例使用箭头。比例尺水平offset为0,长度仍按共享bp转换计算。 ### 调整与限制 {#collinear-read} 修改seq_gap、行顺序、方向或连接筛选后,应同步重建控制点。局部箭头避障不是绕过中间整条序列的自动路由器;跨行ribbon之间仍可合法相交。需要局部观察时使用[focus与分段](#views)。当前显式圆形半径/曲率不能直接传入共线性坐标,见[转换边界](#collinear-data-contract)。 ### 按预定尺寸保存 {#collinear-save} ```{r example-52, eval=FALSE} ggsave("four-genome-collinear.png", p_show_collinear, width = 12, height = 8, units = "in", dpi = 144) ``` ## 3.1 DNA、注释与13个参考序列 {#plasmid-data} 单序列圆图可从一张两列表开始。要识别特征、引物或酶切位点,则另外提供真实DNA;已有注释时可以直接画表格,无需再次识别。 ### 输入表与可选信息 {#plasmid-data-tables} | 输入 | 必需内容 | 可选内容 | | --- | --- | --- | | 骨架 | accver, length,且只有一条序列 | label用于显示名称;sequence用于搜索 | | 通用特征 | accver, start, end与方向声明 | type、anno/label、feature_id、形状类别 | | 引物 | 已计算的结合区间、链与名称等对应geom要求 | 识别与来源信息 | | 酶切位点 | 搜索结果中对应geom的位点与名称 | 酶目录、甲基化假设与筛选来源 | 最简单骨架只需要前两列,不能要求所有人都提供DNA。后两类优先使用本包搜索返回的表,字段细节查相应函数帮助。未知链特征由通用feature层表达,不伪造正链。 ### 查看随包真实记录 {#plasmid-data-inspect} ```{r example-53, eval=FALSE} library(ggchord) library(dplyr) plasmid_example_pUC19 |> select(accver, length) find_common_features(plasmid_example_pUC19) |> select(accver, start, end, strand, type, anno) |> slice_head(n = 5) ``` 数据字段命名沿用ggchord早期的BLAST风格;单序列ID仍称accver,不要求来自数据库。完整DNA与长度必须一致。识别得到的是计算匹配,不是实验验证。 ### 导入自己的质粒 {#plasmid-data-import} `read_fasta_lengths()`只读取FASTA标识与完整长度。识别还需要额外读取实际DNA,例如用可选Biostrings的 `readDNAStringSet()` 和 `as.character()`,保留与表格一致的ID;有GFF3/BED/GenBank或GRanges时按[格式专题](#formats)导入注释,保留来源。跨圆周起点与分段记录按对应导入契约处理,不手工把所有片段合成一个虚假的连续区间。 ### 案例如何循序渐进 {#plasmid-data-path} [3.2](#plasmid-build)从pUC19双线骨架逐层添加;[3.3](#recognition)解释识别目录和引物/酶切;[3.4](#plasmid-catalog)覆盖仓库13个独立质粒;[3.5](#plasmids-complex)完成pETDuet-1密集图。`pUC19c`只是兼容别名,不能冒充第14个案例。 ## 3.2 从圆圈到多层注释 {#plasmid-build} 这一页只关注每次新增的视觉信息。准备时计算输入,绘图仍由独立图层完成。 ### 本页准备 {#plasmid-build-prepare}
准备代码 · 在本页运行一次 ```{r example-54, eval=FALSE} library(ggchord) feature_palette <- c( CDS = "#993366", promoter = "#31849B", rep_origin = "#F1E51D", primer_bind = "#A020F0", misc_feature = "#A6ACB3", protein_bind = "#31849B" ) 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) plasmid_feature_source <- find_common_features(plasmid_example_pUC19) # Dedicated primer layers already show bindings; avoid duplicate primer annotations. plasmid_features <- plasmid_feature_source |> filter(type != "primer_bind") |> select(accver, start, end, strand, type, anno) plasmid_primers <- find_primer_bindings(plasmid_example_pUC19, set = "universal") plasmid_sites <- find_restriction_sites(plasmid_example_pUC19) display_sites <- filter_restriction_sites(plasmid_sites, enzymes = c("EcoRI", "BamHI", "HindIII")) primer_names <- primer_catalog(set = "universal") ```
```{r example-55, eval=FALSE} plasmid_position <- position_feature_stack(spacing = 0.085, base_position = position_plasmid()) p_plasmid_backbone <- ggchord(seq_data = plasmid_seq) + geom_seq(seq_style = "double", colour = "#252525") + geom_seq_center_label() + coord_circular(rotation = 90) + theme_ggchord_plasmid() + theme( panel.background = element_blank(), plot.background = element_rect(fill = doc_background, colour = NA) ) p_plasmid_features <- p_plasmid_backbone + geom_feature_plasmid(data = plasmid_features, position = plasmid_position) p_plasmid_text <- p_plasmid_features + geom_feature_label_repel( data = plasmid_features, position = plasmid_position, external = TRUE, label_fit = "shrink", label_min_size = 2.5 ) p_plasmid_text ``` ### 第一步:双线骨架与中心名称 {#plasmid-build-backbone}
pUC19第一步:双线骨架
pUC19第一步:双线骨架 · 点击放大查看
先检查长度和名称。`coord_circular()` 仅接受一条序列;双线样式由geom控制。 ### 第二步:加入特征形状 {#plasmid-build-features}
pUC19第二步:特征
pUC19第二步:特征 · 点击放大查看
`position_feature_stack()` 为重叠注释分层,`geom_feature_plasmid()` 按实际类别选择形状和配色。短特征可能使用紧凑形状,不等于缺失。 ### 第三步:为特征适配标签 {#plasmid-build-labels}
pUC19第三步:标签
pUC19第三步:标签 · 点击放大查看
箭头层与标签层使用同一Position。允许文字在明确字号下限内缩小,必要时外置;尺寸变化后重新检查。 ### 第四步:引物与选定酶切位点 {#plasmid-build-details} ```{r example-56, eval=FALSE} plasmid_position <- position_feature_stack(spacing = .10, base_position = position_plasmid()) p_plasmid <- ggchord(seq_data = plasmid_seq) + geom_seq(seq_style = "double") + geom_feature_plasmid(aes(feature_fill = type), data = plasmid_features, position = plasmid_position) + geom_feature_label_repel( data = plasmid_features, position = plasmid_position, size = 4 ) + geom_primer(data = plasmid_primers, colour = "#A020F0") + geom_primer_label_repel(data = plasmid_primers, colour = "#A020F0", max_overlaps = 0, size = 3) + geom_restriction_site(data = display_sites, colour = "#29364B", label_size = 3, leader = "radial") + geom_seq_center_label() + scale_feature_fill_manual(values = feature_palette) + scale_seq_position_continuous() + coord_circular(rotation = 90) + theme_ggchord_plasmid() + theme( legend.title = element_text(size = 13, face = "bold"), legend.text = element_text(size = 11), legend.spacing.x = unit(9, "mm"), legend.spacing.y = unit(7, "mm"), plot.background = element_rect(fill = doc_background, colour = NA), panel.background = element_blank() ) p_plasmid ```
pUC19 注释、精确引物命中与三个选定酶切位点
pUC19 注释、精确引物命中与三个选定酶切位点 · 点击放大查看
只展示选定的三个酶切位点,完整搜索表仍保留。完整的识别方法、来源与假设见[3.3](#recognition)。然后使用[13个参考案例](#plasmid-catalog)比较注释密度,最后完成[pETDuet-1综合图](#plasmids-complex)。 ## 3.3 识别特征、引物与酶切 {#recognition}

从已知 DNA 搜索引物、限制酶和常见注释,再决定如何显示;计算命中与实验验证是不同事情。

### 本页准备 {#recognition-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 ```{r example-57, eval=FALSE} library(ggchord) library(dplyr) ``` ### 搜索与显示分开 {#recognition-search} 直接使用随包 pUC19 DNA,查找目录引物的精确命中与选定酶切位点: ```{r example-58, eval=FALSE} data(plasmid_example_pUC19) target <- setNames(plasmid_example_pUC19$sequence, plasmid_example_pUC19$accver) primers <- find_primer_bindings(target, set = "universal") sites <- find_restriction_sites(target, enzymes = c("EcoRI", "BamHI", "HindIII"), methylation = "none") recognition_seq <- plasmid_example_pUC19 |> select(accver, length) p_sites <- ggchord(seq_data = recognition_seq) + geom_seq() + geom_primer(data = primers, colour = "#A020F0") + geom_restriction_site(data = sites, colour = "#29364B") + coord_circular() p_sites ``` 圆形搜索也检查跨原点的候选位置。线性序列应设置 `circular = FALSE`。搜索命中是计算匹配, 不等于实验验证。引物 `"three_prime"` 模式寻找精确后缀,没有错配模型; Wallace 熔解温度估计是基于组成的启发式值。 ### 解释酶切结果 {#recognition-restriction} `find_restriction_sites()` 返回未筛选匹配和切割坐标,`filter_restriction_sites()` 选择显示集合。酶位点计数针对完整输入序列,筛选后保持不变。 `methylation = "auto"` 仅为精确识别的内置参考使用已审计背景,不能据此声称未知 样品不受阻断。本例明确选择 `"none"`,这是搜索条件,不是对实际样品甲基化状态的测量。 `geom_restriction_site(leader = "radial")` 是默认连线方式。 ### 通用注释识别 {#recognition-features} `find_common_features()` 支持精确参考的整理注释、DNA 匹配及逐记录检测模式。 蛋白搜索采用标准遗传密码六框翻译,不处理剪接、替代起始或跨原点蛋白匹配。 来源中的遗传密码元数据不选择另一套翻译表;非标准遗传密码应使用 DNA 匹配或外部 支持相应遗传密码的分析。confidence 是启发式标签,不是概率。 已知蛋白/基因组对应关系应使用[显式 CDS 投影](#projection)。 ### 跟随完整参考注释流程 {#recognition-reference} 这个简短流程和完整圆图使用同一条有来源的随包质粒。[完整 pUC19 流程](#plasmids)将目录注释、 精确参考匹配、酶位点显示筛选、引物标签及注释堆叠组合起来。 只修改序列名称不能让它成为已知参考,有来源的识别依据是序列内容。 应读取结果方法及甲基化来源,不能把参考结论赋予未知样本。 ### 完成后检查 {#recognition-check-result} 查看命中坐标、方法与来源。酶位点筛选是显示选择;甲基化搜索条件不是对未知样本状态的测量。
继续:绘制完整质粒图 →
## 3.4 13个质粒参考案例 {#plasmid-catalog} 本图库包含13个独立的仓库FASTA参考记录,全部由当前代码重绘。旧版PNG和.dna文件不是本轮输出;下方只将载体用途作为学习线索,不由图形证明实验功能。完整来源和长度由随包数据及生成规则保留。 ### 一次准备全部案例 {#plasmid-catalog-prepare}
准备代码 · 在本页运行一次 ```{r example-59, eval=FALSE} 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) ) } ```
```{r example-60, eval=FALSE} library(ggchord) library(dplyr) library(purrr) # Thirteen unique records; the compatibility spelling pUC19c is not an extra plasmid. catalog_objects <- c( "plasmid_example_pSB1C3", "plasmid_example_pUC19", "plasmid_example_pBR322", "plasmid_example_pBluescript_II_SK_plus", "plasmid_example_pET_28a_plus", "plasmid_example_pETDuet_1", "plasmid_example_pDONR221", "plasmid_example_pcDNA3_1_plus", "plasmid_example_pTRE_Tight_BI", "plasmid_example_pTRIPZ", "plasmid_example_pCAMBIA1300", "plasmid_example_pEarleyGate_201", "plasmid_example_pSpCas9_BB_2A_GFP_PX458" ) read_catalog_record <- function(object) { target <- new.env(parent = emptyenv()) data(list = object, package = "ggchord", envir = target) target[[object]] } catalog_sequences <- map(catalog_objects, read_catalog_record) catalog_features <- map(catalog_sequences, find_common_features) catalog_summary <- map2(catalog_sequences, catalog_features, function(sequence, features) { tibble(accver = sequence$accver, length = sequence$length, features = nrow(features)) }) |> bind_rows() ``` ```{r example-61, eval=FALSE} make_catalog_plot <- function(sequence, features) { placement <- position_feature_stack(spacing = 0.085, base_position = position_plasmid()) ggchord(seq_data = sequence |> select(accver, length)) + geom_seq(seq_style = "double", colour = "#252525") + geom_feature_plasmid(data = features, position = placement) + geom_feature_label_repel( data = features, position = placement, external = FALSE, label_fit = "shrink", label_min_size = 2.5, max_overlaps = 0 ) + geom_seq_center_label() + coord_circular(rotation = 90, fit = "manual", xlim = c(-1.35, 1.35), ylim = c(-1.35, 1.35)) + theme_ggchord_plasmid() + theme( panel.background = element_blank(), plot.background = element_rect(fill = doc_background, colour = NA) ) } catalog_plots <- map2(catalog_sequences, catalog_features, make_catalog_plot) names(catalog_plots) <- catalog_summary$accver # Save any record at the same size used in the gallery. # ggsave("pBR322.png", catalog_plots[["pBR322"]], width = 10, height = 8, dpi = 144) ``` 同一个小函数组合独立图层,所有识别结果保留在catalog_features,实际数量见下表。这里保留全部特征几何,标签优先在图内适配,空间不足时可隐藏;引物与密集酶切的完整示例在[综合实战](#plasmids-complex)。选择任一名字即可用注释掉的ggsave调用保存。 ### 输入与识别结果 {#plasmid-catalog-counts} | 参考序列 | 长度(bp) | 识别特征数 | | --- | --- | --- | | [pSB1C3](#plasmid-catalog-catalogpsb) | 2070 | 7 | | [pUC19](#plasmid-catalog-catalogpuc) | 2686 | 9 | | [pBR322](#plasmid-catalog-catalogpbr) | 4361 | 6 | | [pBluescript II SK(+)](#plasmid-catalog-catalogblue) | 2961 | 14 | | [pET-28a(+)](#plasmid-catalog-catalogpet) | 5369 | 16 | | [pETDuet-1](#plasmid-catalog-catalogduet) | 5420 | 20 | | [pDONR221](#plasmid-catalog-catalogdonr) | 4761 | 11 | | [pcDNA3.1(+)](#plasmid-catalog-catalogpcdna) | 5428 | 13 | | [pTRE-Tight-BI](#plasmid-catalog-catalogtre) | 2856 | 15 | | [pTRIPZ](#plasmid-catalog-catalogtripz) | 13320 | 33 | | [pCAMBIA1300](#plasmid-catalog-catalogcambia) | 8959 | 17 | | [pEarleyGate 201](#plasmid-catalog-catalogearley) | 11779 | 21 | | [pSpCas9(BB)-2A-GFP (PX458)](#plasmid-catalog-catalogcas) | 9288 | 19 | ### pSB1C3:小载体与基本骨架 {#plasmid-catalog-catalogpsb}
pSB1C3:参考特征图
pSB1C3:参考特征图 · 点击放大查看
### pUC19:常见注释与复制起点 {#plasmid-catalog-catalogpuc}
pUC19:参考特征图
pUC19:参考特征图 · 点击放大查看
### pBR322:多个抗性区与方向 {#plasmid-catalog-catalogpbr}
pBR322:参考特征图
pBR322:参考特征图 · 点击放大查看
### pBluescript II SK(+):局部调控与短特征 {#plasmid-catalog-catalogblue}
pBluescript II SK(+):参考特征图
pBluescript II SK(+):参考特征图 · 点击放大查看
### pET-28a(+):表达区与标签 {#plasmid-catalog-catalogpet}
pET-28a(+):参考特征图
pET-28a(+):参考特征图 · 点击放大查看
### pETDuet-1:双表达单元,进入密集案例 {#plasmid-catalog-catalogduet}
pETDuet-1:参考特征图
pETDuet-1:参考特征图 · 点击放大查看
### pDONR221:重组相关结构 {#plasmid-catalog-catalogdonr}
pDONR221:参考特征图
pDONR221:参考特征图 · 点击放大查看
### pcDNA3.1(+):表达载体的注释层级 {#plasmid-catalog-catalogpcdna}
pcDNA3.1(+):参考特征图
pcDNA3.1(+):参考特征图 · 点击放大查看
### pTRE-Tight-BI:双向调控布局 {#plasmid-catalog-catalogtre}
pTRE-Tight-BI:参考特征图
pTRE-Tight-BI:参考特征图 · 点击放大查看
### pTRIPZ:更长序列的显示密度 {#plasmid-catalog-catalogtripz}
pTRIPZ:参考特征图
pTRIPZ:参考特征图 · 点击放大查看
### pCAMBIA1300:较大植物载体的结构 {#plasmid-catalog-catalogcambia}
pCAMBIA1300:参考特征图
pCAMBIA1300:参考特征图 · 点击放大查看
### pEarleyGate 201:另一植物载体的类别对照 {#plasmid-catalog-catalogearley}
pEarleyGate 201:参考特征图
pEarleyGate 201:参考特征图 · 点击放大查看
### pSpCas9(BB)-2A-GFP (PX458):大型表达载体与文字适配 {#plasmid-catalog-catalogcas}
pSpCas9(BB)-2A-GFP (PX458):参考特征图
pSpCas9(BB)-2A-GFP (PX458):参考特征图 · 点击放大查看
### 下一步 {#plasmid-catalog-next} 比较不同密度后,进入[3.5 综合实战](#plasmids-complex),添加独立引物与酶切图层。 ## 3.5 质粒综合实战 {#plasmids}

用随包 pUC19 DNA 完成一张可阅读的质粒图:注释、引物和酶切分别成层,显示选择与完整结果分开保存。

### 本页准备 {#plasmids-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-62, eval=FALSE} library(ggchord) feature_palette <- c( CDS = "#993366", promoter = "#31849B", rep_origin = "#F1E51D", primer_bind = "#A020F0", misc_feature = "#A6ACB3", protein_bind = "#31849B" ) 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) ) } ```
其中定义了本例使用的配色。 ### 使用有来源的序列 {#plasmids-input} 随包 `plasmid_example_pUC19` 原样来自仓库 `examples/plasmid/pUC19.fna`,不会为显示 修改碱基或序列标识。本流程使用包中有来源记录的识别目录,不需要网络请求,也不 为图形伪造实验测量值。 ```{r example-63, eval=FALSE} library(dplyr) data(plasmid_example_pUC19) plasmid_seq <- plasmid_example_pUC19 |> select(accver, length) plasmid_feature_source <- find_common_features(plasmid_example_pUC19) # Dedicated primer layers already show bindings; avoid duplicate primer annotations. plasmid_features <- plasmid_feature_source |> filter(type != "primer_bind") |> select(accver, start, end, strand, type, anno) plasmid_primers <- find_primer_bindings(plasmid_example_pUC19, set = "universal") plasmid_sites <- find_restriction_sites(plasmid_example_pUC19) display_sites <- filter_restriction_sites(plasmid_sites, enzymes = c("EcoRI", "BamHI", "HindIII")) primer_names <- primer_catalog(set = "universal") ``` 先查看 `plasmid_features`、`plasmid_primers` 与 `display_sites`,区分完整搜索与显示选择。 ### 组合独立图层 {#plasmids-draw} 下面按骨架、注释、标签、引物和酶切的顺序添加图层。注释与标签共享同一个 Position;每个图层只读取自己的数据。 ```{r example-64, eval=FALSE} plasmid_position <- position_feature_stack(spacing = .10, base_position = position_plasmid()) p_plasmid <- ggchord(seq_data = plasmid_seq) + geom_seq(seq_style = "double") + geom_feature_plasmid(aes(feature_fill = type), data = plasmid_features, position = plasmid_position) + geom_feature_label_repel( data = plasmid_features, position = plasmid_position, size = 4 ) + geom_primer(data = plasmid_primers, colour = "#A020F0") + geom_primer_label_repel(data = plasmid_primers, colour = "#A020F0", max_overlaps = 0, size = 3) + geom_restriction_site(data = display_sites, colour = "#29364B", label_size = 3, leader = "radial") + geom_seq_center_label() + scale_feature_fill_manual(values = feature_palette) + scale_seq_position_continuous() + coord_circular(rotation = 90) + theme_ggchord_plasmid() + theme( legend.title = element_text(size = 13, face = "bold"), legend.text = element_text(size = 11), legend.spacing.x = unit(9, "mm"), legend.spacing.y = unit(7, "mm"), plot.background = element_rect(fill = doc_background, colour = NA), panel.background = element_blank() ) p_plasmid ```
pUC19 注释、精确引物命中与三个选定酶切位点
pUC19 注释、精确引物命中与三个选定酶切位点 · 点击放大查看
| 项目 | 结果 | | --- | --- | | 完整序列长度(bp) | 2686 | | 注释记录数 | 7 | | 精确引物命中记录数 | 6 | | 酶条目匹配记录数(非独立位置数) | 49845 | | 选定显示的酶切记录数 | 3 | 混合的圈外标签按锚点顺序共同排版,包括少量酶切标签与引物共存的情况。 本例使用质粒专用主题和默认 feature 适配;默认先尝试内部文字,再使用相邻或 外侧位置。不要通过不断缩小文字或强制手动偏移掩盖交叉;请在相同导出尺寸下检查。 原始注释保留在 `plasmid_feature_source`。显示表去掉 `primer_bind` 注释,交由独立 引物层表达,避免重复;注释层只接收几何、类型和注释文字。 ### 阅读各注释层 {#plasmids-layers} 双线骨架建立单条圆形序列,通用注释使用 plasmid 预设和显式 stacking Position, 标签共享该 Position。引物弧线表达结合范围,酶切短线表达切割/显示位置,中心标签 给出序列名称和长度。裁剪或筛选显示不改变完整序列的酶位点计数。 ### 有意选择显示位点 {#plasmids-sites} `find_restriction_sites()` 返回全部匹配。本图明确选择 EcoRI、BamHI 与 HindIII, 使局部酶切簇保持可读;`plasmid_sites` 保留完整搜索结果。只有完整输入序列精确匹配参考时, `reference` 筛选才使用已保存的参考显示集合。其他任务可选 `unique`、`six_plus` 或明确酶名。绘图前检查 `display_sites` 及甲基化/来源列。参考集合是显示选择, 不表示未知样本的生物学状态已经确定。 ### 理解目录和标签的限制 {#plasmids-limits} `primer_names` 展示目录条目。本例精确搜索 universal 目录,参考引物注释与精确寡核苷酸搜索有不同来源。 近似蛋白注释识别遵循[识别专题](#recognition)的限制,不验证生物学功能或 引物实验。文字可以移位、在显式字号下限内缩小或隐藏。应保留几何并在最终尺寸 检查导出标签原因,而不是要求每条注释必须显示文字。 ### 应用到自己的数据 {#plasmids-adapt} 将输入替换成有明确名称的 DNA 序列,先检查搜索结果再添加几何层。已有整理注释时, 直接提供注释表,无需再次运行识别。[堆叠与形状](#annotations)说明几何, [标签](#labels)说明适配,[输出](#output)说明设备与尺寸。 `geom_primer_label_repel(side = "inside")` 将引物引出标签保留在骨架内侧, 包括同时存在外侧酶切及注释标签时。0.16.6 已修复此行为; v0.16.5 可能将请求内侧的标签移到外侧。外侧默认布局和原始坐标不变。 内侧酶切标签继续保留内侧几何,导出 annotation registry 现在也正确记录内侧; 早期版本将这些诊断行误标为外侧资源。 完整内侧场景仍可能出现长引物文字与其他 feature 区域交叠;默认 `max_overlaps = Inf` 不认证跨 feature 图层的零交叠。空间不足时优先使用默认外侧, 或通过 `show_location = FALSE` 缩短显示文字,并在最终尺寸检查结果。 ### 完成后检查 {#plasmids-check-result} 从中心的名称与长度开始,沿骨架读位置,再读类别色、箭头方向和外侧标签。核对 display_sites 的酶名;删减显示不会改变 plasmid_sites。
继续:放置和调整标签 →
### 保存本页结果 {#plasmids-save-result} 在工作目录中保存刚刚创建的图;预览时使用相同宽高。 ```{r example-65, eval=FALSE} ggsave("pUC19-map.png", p_plasmid, width = 10, height = 9, units = "in", dpi = 144) ``` ### 完整示例:pETDuet-1 密集质粒图 {#plasmids-complex} 先用上面的 pUC19 掌握图层,再用 pETDuet-1 展示复杂注释。以下来自随包真实序列、常见特征与参考引物表;酶切输入保留 commercial_all 中唯一的六碱基及以上识别位点,不把筛选后的图误称为全部酶的所有切点。 ```{r example-66, eval=FALSE} library(ggchord) library(dplyr) data(plasmid_example_pETDuet_1) show_plasmid <- plasmid_example_pETDuet_1 |> select(accver, length) show_plasmid_features <- find_common_features(plasmid_example_pETDuet_1) show_plasmid_primers <- find_primer_bindings(plasmid_example_pETDuet_1, set = "reference") show_plasmid_all_sites <- find_restriction_sites(plasmid_example_pETDuet_1) show_plasmid_sites <- filter_restriction_sites( show_plasmid_all_sites, set = "unique_6plus", parent_set = "commercial_all" ) ``` ```{r example-67, eval=FALSE} show_plasmid_position <- position_feature_stack( spacing = 0.085, base_position = position_plasmid() ) p_show_plasmid <- ggchord(show_plasmid, validate = "none") + geom_seq(seq_style = "double", colour = "#252525") + geom_feature_plasmid(data = show_plasmid_features, position = show_plasmid_position) + geom_feature_label_repel( data = show_plasmid_features, position = show_plasmid_position, external = TRUE, max_overlaps = 0, label_fit = "shrink", label_min_size = 2.5 ) + geom_primer(data = show_plasmid_primers, colour = "#A020F0") + geom_primer_label_repel( data = show_plasmid_primers, colour = "#A020F0", max_overlaps = 0 ) + geom_restriction_site(data = show_plasmid_sites, colour = "#252525") + geom_seq_center_label() + coord_circular( rotation = 90, fit = "manual", xlim = c(-3.4, 4.6), ylim = c(-1.6, 2.4) ) + theme_ggchord_plasmid() + theme( legend.title = element_text(size = 13, face = "bold"), legend.text = element_text(size = 11), legend.spacing.x = unit(9, "mm"), legend.spacing.y = unit(7, "mm"), plot.background = element_rect(fill = doc_background, colour = NA), panel.background = element_blank() ) p_show_plasmid ```
pETDuet-1密集质粒图:特征、参考引物与合并酶切位点
pETDuet-1密集质粒图:特征、参考引物与合并酶切位点 · 点击放大查看
20 个特征、5 个参考引物、58 个合并切点构成输入。默认 feature 配色保留紫红编码区域、浅绿抗性基因、黄色复制起点和蓝色调控注释;引物为紫色,与本站其他图的相同语义保持一致。密集标签对尺寸敏感,下载原图或打开大图阅读。 显式视野将密集图固定在文档给出的导出尺寸。`label_fit = "shrink"` 允许短特征文字缩至 2.5 mm;仍放不下的文字保留为外置标签。预览和保存应使用相同的 16.5 × 8 in 尺寸。 ```{r example-68, eval=FALSE} ggsave("pETDuet-1-map.png", p_show_plasmid, width = 16.5, height = 8, units = "in", dpi = 144) ``` ## 数据与坐标 {#data}

把文件中的观测整理成绘图角色。先检查最小字段与坐标,再使用校验报告决定是否清理;不要为了出图猜测缺失的长度或方向。

### 本页准备 {#data-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 涉及文件时,先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples),使工作目录包含 `examples/`。
准备代码 · 在本页运行一次 ```{r example-69, eval=FALSE} 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) ```
### 输入表 {#data-tables} | 输入 | 必需字段 | 含义 | | --- | --- | --- | | 序列 | `accver`, `length` | 唯一标识;正值的完整序列长度,单位 bp | |区间连接| `qaccver`, `saccver`, `qstart`, `qend`, `sstart`, `send` | query 与 subject 锚点 | | 基因 | `accver`, `start`, `end`, `strand` | 链为已知 `+`/`-`;`anno` 可选 | | 通用注释| `accver`, `start`, `end`, `strand` 或已声明方向 | 可保留未知链;`type`, `label`, `feature_id` 可选 | 标识可以是任意字符串,accession version 原样保留。只有映射、筛选或统计需要时, 才要求 `pident` 和比对 `length`。不能由注释的范围推断完整序列长度。 ### 坐标契约 {#data-coordinates} 基因组坐标采用 **一基、闭区间 bp**。BED/PAF 读取器已转换源坐标约定,不要重复转换。 基因起止坐标有序,链单独存储;连接端点的次序可表达方向。没有方向证据的单 bp 连接保持未知。未知链不会被静默改成 `+`;应使用 `geom_feature()`,而非严格的基因层。 氨基酸坐标需要[显式 CDS 投影](#projection)。笛卡尔布局单位、基因组 bp、角度、 物理 mm 和轨道数值单位是不同的域。详见完整的数据格式说明 (`help("ggchord_data_contract", package = "ggchord")`)。 ### 导入原始记录 {#data-import} 在仓库根目录运行这个仅用于源码仓库的例子,不改写原始文件。 ```{r example-70, eval=FALSE} seq_files <- read_fasta_lengths(files = "examples/fasta/*.fna", source_file = TRUE) link_files <- read_blast(files = "examples/blastn-standard/*.tsv", source_file = TRUE) feature_files <- read_gff3(files = "examples/gff3/*.gff3", unstranded = "keep", source_file = TRUE) ``` `read_genbank()` 保留记录/注释来源和分段位置。`read_bed()`、`read_paf()` 保留 坐标转换元数据。`as_ggchord_seq()`、`as_ggchord_feature()`、`as_ggchord_link()` 适配支持的 S4 对象;对象缺少完整长度或标识时必须显式提供。 `file` 与 `files` 均支持路径向量或 glob,重复解析路径按首次出现顺序只读一次。 一个工作流选择一个清晰入口。缺失的序列或同源关系应由分析者 提供,绘图层不生成这些业务数据。 ### 校验、清理与准备 {#data-validation} ```{r example-71, eval=FALSE} validation <- validate_ggchord_data(seqs, links, genes) cleaned <- clean_ggchord_data(seqs, links, genes) prepared <- prepare_ggchord_data(seqs, links, features = list(genes = genes)) ``` 校验报告问题;清理执行明确修复并返回报告;准备函数组合工作流步骤,不推断生物学 归属。绘图前检查 `validation`、`cleaned$report` 和 `prepared$report`。 几何表的 `source_row` 指图层已解析输入行,`.source_line` 才是物理文件行;GenBank 另有记录/注释来源。聚合可带 `source_rows` 和 `.length_estimated`,筛选合并时应保留。 ### 检查问题输入及修复报告 {#data-repairs} ```{r example-72, eval=FALSE} # Deliberately corrupt copies to demonstrate diagnostics; original rows remain intact. problem_links <- ribbon_data_example |> slice_head(n = 2) |> select(qaccver, saccver, qstart, qend, sstart, send, pident) |> mutate( qaccver = replace(qaccver, 2, "absent"), pident = replace(pident, 1, 103) ) problem_report <- validate_ggchord_data(seqs, problem_links) repaired <- clean_ggchord_data(seqs, problem_links, unknown_id = "drop", invalid_pident = "clip") ``` | 项目 | 结果 | | --- | --- | | 输入行数 | 2 | | 明确清理后保留的行数 | 1 | 例子只修改原始记录的副本,故意加入未知 ID 和超过 0–100 的相似度。明确修复不表示应该静默 截断科学观测。检查 `problem_report`、`repaired$report`,保留原表,并按实际证据 选择策略。合法反向比对可以保持端点顺序,而非排序。`prepare_ggchord_data()` 因此有其工作流相关的默认策略,不能假定独立清理和准备函数完全相同。 ### 声明 genome 与 contig 键 {#data-hierarchy} ```{r example-73, eval=FALSE} # Each source record represents a separate complete phage genome. contigs <- seqs |> mutate(genome = accver) genomes <- tibble(genome = seqs$accver) hierarchy <- validate_ggchord_hierarchy(contigs, genomes, strict = TRUE) ``` `hierarchy$contigs` 汇总已声明归属,不拼接 contig,也不由 accession 前缀推断归属。 不同样本重复局部 contig 名时须显式提供全局唯一标识。 [文件格式与适配器](#formats)说明格式及可选对象,[真实记录教程](#real-data) 把这些报告带入完整绘图流程。 ### 最小输入与蛋白比对 {#data-minimal} | 项目 | 结果 | | --- | --- | | 传入绘图的序列列数 | 2 | | 传入绘图的连接列数 | 6 | | 传入绘图的基因列数 | 4 | 构造函数的第二个位置参数是 `ribbon_data`,不是 `gene_data`。建议像共享例子一样 写明参数名,避免把基因表误当成连接表。相似度、比对长度和覆盖率字段只在相应 映射、筛选或统计中才需要。详见[标准 BLAST 与蛋白输入](#alignments)和 [按序列、按链设置参数](#parameters)。 ### 完成后检查 {#data-check-result} 输入 ID 必须能匹配到完整序列表;原始记录与修复副本分开保存。反向比对端点递减可以合法,不能把所有警告都当作需要删除的数据。
继续:导入和转换数据 →
## 导入和转换数据 {#formats}

将已有表格、BED、PAF 或 GenBank 转成 ggchord 输入,保留记录身份,并且只转换一次坐标约定。

### 本页准备 {#formats-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 涉及文件时,先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples),使工作目录包含 `examples/`。
准备代码 · 在本页运行一次 ```{r example-74, eval=FALSE} 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) ```
### 把已有表格转换成需要的列 {#formats-adapters} 这里使用随包的实际序列、连接和基因, 只重命名列来演示角色映射;没有额外生成示意序列或比对。 ```{r example-75, eval=FALSE} 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) ``` 转换返回普通数据框,并记录 `ggchord_conversion` 信息。标识原样保留;缺少完整 序列长度时应补充可靠来源,不能把最大注释端点当作全长。核酸与蛋白比对的最小列 和单位见[导入比对结果](#alignments)。 ### BED 和 PAF:坐标只转换一次 {#formats-zero-based} BED 例子把已知 pUC19 注释写为最小 BED3,再读回;PAF 直接读取公开教程中的真实 minimap2 输出,保留原始可选标签和值。显示筛选保留 mapq ≥30 的记录,绘图只接收六个端点角色。 ```{r example-76, eval=FALSE} # 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 ```
从真实 minimap2 PAF 结果绘制的两条 EMALE 序列
从真实 minimap2 PAF 结果绘制的两条 EMALE 序列 · 点击放大查看
BED 的零起点半开区间由读取器转成一基包含坐标;不要再手工加一次 1。 BED3 没有链列,读回时链为未知;需要链方向时应使用含 strand 的原始格式。 PAF 的负相对方向表现为递减的 subject 端点,这是合法反向命中,不能一律排序去掉方向。 比对质量和 `pident` 来自生产工具报告的字段,不在绘图时重新计算碱基比对。 ### GenBank:保留记录身份 {#formats-genbank} ```{r example-77, eval=FALSE} # 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") } ``` 这个文件是 NCBI 的原始 L09137.2 记录,名称是 pUC19c;不要把它强行改成随包 pUC19。 返回值包括 `seq_data`、`features$annotation` 与 `report`,分段位置及记录/注释来源 保留。这里需要所选 Python 已安装 Biopython;函数不自动安装依赖。 `unsupported = "report"` 将不支持的位置记入报告,不把远端或复杂位置猜成区间。 ### 可选的区间对象 {#formats-ranges} ```{r example-78, eval=FALSE} 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)) } ``` ```{r example-79, eval=FALSE} 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) ) } ``` | 项目 | 结果 | | --- | --- | | GenBank 可选读取器 | 依赖未安装,已跳过 | | 可选区间对象适配器 | PASS | | 可选GInteractions适配器 | PASS | 这里选择 pUC19 中原本未知链的注释;转换后的 `*` 仍表示未知。 完整长度来自已知序列长度和 Seqinfo。`GInteractions` 可以转换成连接,但仍需明确 两端序列及长度。缺少可选依赖时结果会标记跳过,不把源码存在当作运行通过。 详见数据格式说明 (`help("ggchord_data_contract", package = "ggchord")`)。当前不直接解析 SAM/BAM 的 CIGAR;需先由相应工具正确解析,再通过表格角色映射转换,不能仅靠改列名处理剪接。 ### 完成后检查 {#formats-check-result} 先查看返回列与转换报告,再选绘图列。PAF 反向命中保留端点方向;GenBank 记录身份不能因为展示需要而改成另一条随包质粒。
继续:导入核酸和蛋白比对 →
## 导入核酸和蛋白比对 {#alignments}

使用 BLAST 标准表格输出,无需早期自定义 17 列。区分“文件有哪些列”“绘图需要哪些列”及核酸/蛋白单位。

### 本页准备 {#alignments-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。 涉及文件时,先解压[教学输入](https://github.com/DangJem/ggchord/tree/main/examples),使工作目录包含 `examples/`。 ```{r example-80, eval=FALSE} library(ggchord) library(dplyr) ``` ### 默认表格列就够用 {#alignments-standard} 不需要早期教程中的 17 列自定义字段。使用 BLAST 标准表格输出即可: ```sh blastn -query query.fna -subject subject.fna -outfmt 6 -out result.tsv blastp -query proteins.faa -subject reference.faa -outfmt 7 -out result.tsv ``` `6` 是无注释表格,`7` 加上注释头;不再列出自定义字段时,两者使用默认 12 列。 完全省略 `-outfmt` 得到的是 pairwise 文本,当前表格读取器不解析该格式。 默认列为 query ID、subject ID、pident、length、mismatch、gapopen、qstart、qend、 sstart、send、evalue、bitscore。读取器将两个 ID 的角色命名为 `qaccver`、`saccver`, 保留字符串原值,并不要求它们一定是 accession version。 [NCBI 格式说明](https://www.ncbi.nlm.nih.gov/sites/books/NBK279684/table/appendices.T.options_common_to_all_blast/)。 ### 文件布局与绘图最小列是两回事 {#alignments-minimal} 文件里有 12 列,不表示绘图必须接收 12 列。运行本页准备代码加载包后,使用下面的真实记录: ```{r example-81, eval=FALSE} blast_source <- read_blast("examples/blastn-standard/MT108731.1__MT118296.1.tsv") blast_links <- blast_source |> select(qaccver, saccver, qstart, qend, sstart, send) # A six-column table is sufficient for drawing; extra fields stay in blast_source. custom_path <- tempfile(fileext = ".tsv") write.table(blast_links, custom_path, sep = "\t", quote = FALSE, row.names = FALSE, col.names = FALSE) custom_source <- read_blast(custom_path, format = "custom", col_names = names(blast_links)) custom_links <- custom_source |> select(all_of(names(blast_links))) unlink(custom_path) ``` `blast_source` 保留全部统计和来源信息;`blast_links` 只有六个端点角色。 `pident` 只有在按相似度配色/筛选时才需要,`length` 只有按比对长度筛选/加权时才需要。 `qlen`、`slen` 用于相应覆盖率计算,不能为了基础出图强制要求它们。 无表头的自定义列须明确 `col_names`,读取器不猜测任意六列的含义。 也可对任意已读入的表使用 `as_ggchord_link(x, mapping = ...)`,见[格式转换](#formats-adapters)。 仓库 `examples/blastn-standard/` 的文件是历史原始 HSP 的前 12 列转换,保留行和值, 不是本轮重新计算的 BLAST 结果。旧 `.o7` 文件保持原样,转换脚本和 hash 在来源清单中。 ### BLASTp 可以读取,但坐标单位不同 {#alignments-protein} 下面是真实 BLASTP 2.9.0+ 结果与对应查询 CDS 注释,来自公开 EMALE 教程。 先保留完整输入,再选择有完整 CDS 映射、足够长度和较小 evalue 的查询 HSP。 ```{r example-82, eval=FALSE} protein_source <- read_blast("examples/format-inputs/emales-mavirus-blastp.tsv", source_file = TRUE) emale_source <- read_gff3("examples/format-inputs/emales-BVI_023A.gff3", source_file = TRUE) # The source declares complete Prodigal CDS and translation table 11. emale_coding <- emale_source |> filter(grepl("partial=00", attributes)) |> select(feature_id, accver, start, end, strand, phase) emale_cds <- build_ggchord_cds(emale_coding, genetic_code = 11) # Keep strong HSPs whose query protein has a known complete CDS. # Gaps are retained: projecting one query span does not assert an ungapped pair. protein_kept <- protein_source |> filter(qaccver %in% emale_coding$feature_id, evalue <= 1e-10, length >= 50) |> arrange(desc(bitscore)) selected_hsp <- protein_kept |> slice_head(n = 1) query_interval <- tibble( feature_id = "query_HSP", parent_id = selected_hsp$qaccver, start = selected_hsp$qstart, end = selected_hsp$qend ) projected_query <- project_ggchord_features(query_interval, emale_cds) # Subject projection additionally requires its own CDS map; it is not guessed from an accession. ``` | 项目 | 结果 | | --- | --- | | 原始 BLASTp 比对记录数 | 2948 | | 具有完整注释的查询 CDS 数 | 24 | | 明确筛选后保留的查询 HSP 数 | 3 | | 所选查询起点(aa) | 50 | | 所选查询终点(aa) | 289 | | 投影后的查询范围行数 | 1 | BLASTp 的 `qstart/qend/sstart/send` 是氨基酸坐标。这里将查询蛋白的 HSP 范围 转换到已知 CDS 的基因组坐标,保留负链和 phase;有缺口的 HSP 仍可投影查询范围, 但这只是范围,不能解释为逐个核苷酸的配对。原始弱命中、gapopen 和统计仍在原表中。 要得到两端的核苷酸连接,还须提供 subject 的 CDS 映射。不能从蛋白 accession、 最大端点或同名注释猜出来。`project_ggchord_links()` 的 `ungapped = TRUE` 必须有 证据,不能为了让默认 BLASTp 文件通过而随意打开。[投影教程](#projection) 使用两条编码 DNA 完全一致的真实质粒 CDS,展示可证明无缺口的双端例子。 本版不直接绘制以 aa 为轴的蛋白骨架。`blastx`、`tblastn` 的两侧单位也可能不同, 必须逐侧核对和转换;读取成功不代表可以直接用 bp 坐标绘图。 ### 来源与限制 {#alignments-source} EMALE 原始输出来自 [gggenomes 的公开数据与教程](https://thackl.github.io/gggenomes/articles/emales.html)。 本项目只复用数据记录,用 ggchord 自行绘图;没有复制上游图或绘图代码。 下载、原始成员、行号范围、SHA256 和筛选规则见教学输入包的 `sources.json`。 表格解析不重新运行比对,也不验证命中的生物学功能。 ### 完成后检查 {#alignments-check-result} 基础连接表只需六列。BLASTp 读取后仍是 aa 坐标,必须通过有证据的 CDS 映射转换后才能用于本版 bp 绘图。
继续:将蛋白坐标转换为基因组坐标 →
## 将蛋白区间转换为基因组坐标 {#projection}

把已知蛋白区间投影到真实 CDS 的基因组位置,显式保留 phase、链与分段关系。

### 本页准备 {#projection-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-83, eval=FALSE} 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) data(plasmid_example_pETDuet_1) homolog_source <- bind_rows(plasmid_example_pUC19, plasmid_example_pETDuet_1) homolog_seq <- homolog_source |> select(accver, length) cluster_features <- homolog_source |> find_common_features() |> filter(type == "CDS", anno == "AmpR") |> select(accver, start, end, strand, anno) |> arrange(match(accver, homolog_source$accver)) |> mutate(feature_id = paste(accver, start, end, sep = ":")) # Membership is computed from exact strand-corrected CDS DNA equality, not gene names. reverse_complement <- function(sequence) { bases <- strsplit(sequence, "")[[1]] chartr("ACGT", "TGCA", paste(rev(bases), collapse = "")) } coding_sequences <- cluster_features |> left_join(select(homolog_source, accver, sequence), by = "accver") |> rowwise() |> mutate( coding_dna = substr(sequence, start, end), coding_dna = if (strand == "-") reverse_complement(coding_dna) else coding_dna ) |> ungroup() cds_dna <- pull(coding_sequences, coding_dna) membership <- tibble( feature_id = cluster_features$feature_id, cluster_id = paste0("exact_CDS_", match(cds_dna, unique(cds_dna))) ) homologs <- link_ggchord_clusters(cluster_features, membership, pairs = tibble(qaccver = homolog_seq$accver[1], saccver = homolog_seq$accver[2]) ) loci <- find_ggchord_loci(homolog_seq, cluster_features, targets = cluster_features$feature_id[cluster_features$anno == "AmpR"][1], upstream = 100, downstream = 100 ) # Compare equivalent local windows instead of shrinking one gene on full plasmids. homolog_windows <- cluster_features |> select(accver, start, end) local_homologs <- focus_ggchord_data(homolog_seq, homologs$data, cluster_features, loci = homolog_windows, expand = 200 ) p_homologs <- ggchord( seq_data = local_homologs$seq_data, ribbon_data = local_homologs$ribbon_data, gene_data = local_homologs$gene_data ) + geom_link_ribbon(fill = "#269B82", alpha = .65) + geom_seq(colour = "#233E4A", show.legend = FALSE) + geom_feature( data = local_homologs$gene_data, feature_fill = "#F1D334", position = position_strand(.10), width = .07 ) + geom_feature_label_repel(data = local_homologs$gene_data, size = 4, label_fit = "shrink") + geom_seq_label(size = 4) + geom_seq_break() + coord_collinear() + doc_axis("source") + doc_theme p_homologs ```
### 先准备有来源的 CDS {#projection-cds} 本页准备代码包含[完全相同 CDS 的比较](#homology-membership),使用随包质粒的真实注释 和 DNA。完整 CDS 的 phase 明确为 0,翻译表显式设为 11。 ```{r example-84, eval=FALSE} # Run the exact-CDS comparison first; these are complete source-backed CDS. coding <- cluster_features |> mutate(phase = 0) cds <- build_ggchord_cds(coding, genetic_code = 11) # This selects residues for a display example; it does not claim a detected domain. domains <- tibble(feature_id = "selected_residues", parent_id = coding$feature_id[1], start = 2, end = 20) genomic <- project_ggchord_features(domains, cds) genomic ``` 这个例子选择第 2–20 个残基作显示范围,不声称它是检测到的蛋白结构域。 投影结果是基因组区间,保留正负链与分段关系。真实检测到的 domain 也应提供确切 父 CDS ID 及氨基酸范围;不能通过同名注释或注释最大端点猜测。 ### 分段、phase 和部分区域 {#projection-boundaries} `build_ggchord_cds()` 先建立 CDS 分段映射,`project_ggchord_features()` 再将氨基酸 区间按映射切分。跨剪接边界可能返回多行;不要简单把坐标乘以 3。 不完整 CDS、phase、截断或不支持的位置必须按文档策略处理并检查报告。 DNA 匹配、氨基酸区间投影和真实翻译/比对是不同步骤,绘图库不会代为推断缺失证据。 ### BLASTp 查询范围与双端连接 {#projection-links} ```{r example-85, eval=FALSE} # Exact CDS DNA equality supplies evidence for these selected ungapped residues. matching <- homologs$data |> slice_head(n = 1) paired_coding <- cluster_features |> mutate(phase = 0) paired_cds <- build_ggchord_cds(paired_coding) protein_link <- tibble( qfeature_id = matching$qfeature_id, sfeature_id = matching$sfeature_id, qstart = 1, qend = 20, sstart = 1, send = 20 ) projected_links <- project_ggchord_links(protein_link, paired_cds, ungapped = TRUE) projected_links ``` 这个无缺口例子依赖[同源专题](#homology)中已核对的相同编码序列。 真实 BLASTp 输入可以有 gap;查询区间仍能投影,但双端连接还需要 subject 的 CDS 和无缺口对应证据。请阅读[真实 BLASTp 读取与投影](#alignments-protein)。 本版不把 aa 单位伪装成 bp,也不新增原生蛋白坐标绘图。 ### 完成后检查 {#projection-check-result} 检查父 CDS ID、投影报告及返回分段。选择的残基区间只是显示例子,不能将其描述为检测到的结构域。
继续:导入核酸和蛋白比对 →
## 绘制注释与处理重叠 {#annotations}

把真实注释画为独立图层,选择合适形状,并让重叠区间和文字共享堆叠位置。

### 本页准备 {#annotations-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-86, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") library(ggchord) feature_palette <- c( CDS = "#993366", promoter = "#31849B", rep_origin = "#F1E51D", primer_bind = "#A020F0", misc_feature = "#A6ACB3", protein_bind = "#31849B" ) 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) ```
### 保留注释语义 {#annotations-stack} 本页准备代码已加载 pUC19 的实际注释。 这里保留 pUC19 中实际重叠的注释和原本未知的链方向。 几何和填色分别映射同一类别;显式固定 `shape` 会覆盖 shape 映射。 ```{r example-87, eval=FALSE} stack_features <- features |> select(accver, start, end, strand, type, anno) stack_position <- position_feature_stack(spacing = .12) feature_shapes <- setNames(ifelse(names(feature_palette) == "CDS", "arrow", "block"), names(feature_palette)) p_stack <- ggchord(seq_data = plasmid_seq) + geom_seq(show.legend = FALSE) + geom_feature(aes(feature_fill = type, feature_shape = type), data = stack_features, width = .08, position = stack_position ) + geom_feature_label_repel(data = stack_features, position = stack_position, size = 3.8, label_fit = "shrink", label_min_size = 2.8) + scale_feature_shape_manual(values = feature_shapes) + scale_feature_fill_manual(values = feature_palette) + coord_collinear() + doc_axis() + doc_theme p_stack ```
pUC19 中重叠注释的分层显示
pUC19 中重叠注释的分层显示 · 点击放大查看
`position_feature_stack()` 解决注释轨道重叠。标签层使用同一 Position,让文字锚点 跟随轨道。标签子集或重排时优先提供唯一 `feature_id`。严格的 gene 快捷层要求 已知 `+/-`,通用注释保留未知/双向语义。 ### 按含义选择形状 {#annotations-shapes} | 几何 | 常见用途 | 重要区别 | | --- | --- | --- | | `arrow`, `compact_arrow` | 有方向的编码/注释区间 | 已知方向来自证据,不由显示猜测 | | `block`, `capped_line` | 区域或不填充区间 | 选择形状不推断生物学功能 | | `promoter_arrow`, `primer_arrow`, `primer_arc` | 已声明的启动子/引物式注释 | 计算匹配与绘图分开 | | `marker`, `chevron`, `lollipop` | 自定义区间/类点强调 | 保留真实区间元数据,显示形状属于映射 | `geom_gene()`、`geom_feature_plasmid()` 是有用预设,默认值并不相同。 `position_strand()` 提供带符号位移,`position_plasmid()` 提供圆图放置预设, 后者不构成第四类坐标模式。 ### 高亮区间而不改写观测 {#annotations-decoration} ```{r example-88, eval=FALSE} regions <- tibble( accver = links$qaccver[1], start = min(links$qstart[1], links$qend[1]), end = max(links$qstart[1], links$qend[1]), category = "alignment interval" ) p_decorated <- ggchord(seq_data = seqs, ribbon_data = links) + geom_seq_region(aes(region_fill = category), data = regions, colour = NA) + geom_link_ribbon(fill = "#6BAFA6", alpha = .4) + geom_seq() + geom_seq_label(size = 4) + scale_region_fill_manual(values = c("alignment interval" = "#F4D35E")) + scale_seq_colour_manual(values = seq_palette) + geom_seq_scale(length = 10000) + coord_collinear() + doc_axis() + doc_theme p_decorated ```
突出显示一条实际比对的查询区间
突出显示一条实际比对的查询区间 · 点击放大查看
区域叠层有自己的数据和 `region_fill` 标度。`geom_seq_label()` 命名序列, `geom_seq_center_label()` 在单圆图中心提供名称/长度,`geom_seq_break()` 标记裁剪或 分段末端。`geom_seq_scale()` 是仅用于共线性图的独立 bp 参照条,与控制序列基因组轴 的 `scale_seq_position_continuous()` 不同。普通 ggplot2 注释应使用 [位置映射](#views-mapping),不能把 bp 直接当作笛卡尔 x/y。 ### 完成后检查 {#annotations-check-result} 先检查区间与链,再看形状与标签。未知链仍保留在通用注释中;堆叠改变显示位置,不改变原始基因组坐标。
继续:放置和调整标签 →
## 放置和调整标签 {#labels}

在保持注释几何的前提下安排文字:先选输出尺寸和标签子集,再选择自动或固定位置。

### 本页准备 {#labels-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-89, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
### 选择布局 {#labels-layout} 基因标签提供 `"auto"`、`"radial"`、`"arc"` 布局。通用注释标签还支持优先 内部放置的默认 `"feature"` 和外部 `"callout"`。应按实际图层选择已记录的取值, 这些布局并不是可在所有入口互换的预设。 ```{r example-90, eval=FALSE} label_data <- gene_data_example |> filter(anno != "hypothetical protein") |> transmute(accver, start, end, strand = source_strand, anno) p_labels <- ggchord(seq_data = seqs, gene_data = genes) + geom_seq() + geom_gene() + geom_gene_label_repel(data = label_data, label_layout = "auto", size = 4, label_wrap = 22) + geom_seq_label(size = 4) + coord_collinear() + doc_axis() + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + doc_theme p_labels ```
实际基因注释的自动标签布局
实际基因注释的自动标签布局 · 点击放大查看
### 固定与自动放置 {#labels-fixed} 手动 `label_rotation`、径向/周向位移和方向控制使用 `geom_gene_label()` 或 `geom_feature_label()`。自动层拒绝这些手动控制,应选择 `label_layout` 或删除手动参数。 固定文字样式使用受支持的 `size`、`colour`、`family`。 在支持的入口中,`label_fit`、`label_wrap`、`label_max_lines`、`label_min_size` 控制适配。缩小字号须显式选择且有下限。无法放置的标签可能移位或隐藏,注释 几何仍保留。应在最终导出尺寸查看 `label_fit_diagnostics`、`label_diagnostics`。 ### 跨层匹配锚点 {#labels-anchors} 共线性模式中,省略的注释标签 Position 可继承无歧义的匹配注释层。 唯一 `feature_id` 允许重排或取子集,但标识、区间、链仍须一致。 多个匹配层需要明确 Position 或无歧义 ID。先选最终设备尺寸再预览;调整 Plots 面板会改变可用空间。 ### 对照三种基因标签布局 {#labels-comparison} ```{r example-91, eval=FALSE} # Compare layouts with at most the first and last informative label per sequence. comparison_labels <- label_data |> group_by(accver) |> filter(row_number() %in% c(1L, n())) |> ungroup() label_plots <- lapply(c("auto", "radial", "arc"), function(layout) { ggchord(seq_data = seqs, gene_data = genes) + geom_seq() + geom_gene() + geom_gene_label_repel(data = comparison_labels, label_layout = layout, size = 4, label_wrap = 22) + geom_seq_label(size = 4) + scale_seq_colour_manual(values = seq_palette, name = "Sequence", guide = guide_ggchord_legend(nrow = 2, theme = doc_legend_theme)) + scale_gene_fill_manual(values = gene_palette, breaks = c("+", "-"), name = "Strand", guide = strand_guide) + coord_chord(xlim = c(-1.8, 1.8), ylim = c(-1.6, 1.6)) + theme_ggchord_publication(axis = element_blank()) + doc_legend_theme + theme( legend.position = "bottom", plot.background = element_rect(fill = doc_background, colour = NA), panel.background = element_blank() ) + labs(title = layout) }) names(label_plots) <- c("auto", "radial", "arc") p_manual_labels <- ggchord(seq_data = seqs, gene_data = genes) + geom_seq() + geom_gene() + geom_gene_label(data = label_data, label_rotation = 30) + coord_collinear() label_plots$auto ```
实际基因注释的自动侧边标签
实际基因注释的自动侧边标签 · 点击放大查看
同一组基因注释的径向标签
同一组基因注释的径向标签 · 点击放大查看
同一组基因注释的沿弧标签
同一组基因注释的沿弧标签 · 点击放大查看
每条序列最多选最前和最后两个有信息的标签,保留全部基因箭头,便于比较文字方向。 打印 `label_plots$auto`、`$radial` 或 `$arc` 查看候选图。三图输入和请求字号相同, 仅布局选择不同。auto 在适用处使用共享侧列,radial 跟随局部轮廓,arc 跟随序列切线。 `p_manual_labels` 展示独立固定标签入口,显式旋转不属于自动 repel 图层。 通用注释标签还可选内部优先/callout,密集混合注释见[完整圆图](#plasmids), 继承或显式 Position 锚点见[堆叠](#annotations-stack)。 ### 完成后检查 {#labels-check-result} 三张布局对照使用同一输入。判断可读性时同时看文字方向、连线和隐藏原因;没有标签不等于注释丢失。
继续:预览和保存图形 →
## 添加数据轨道 {#tracks}

从真实 DNA 计算 GC 比例,再逐步叠加柱、滑动均值和注释带。读者应能说清每个轨道的单位、窗口与基线。

### 本页准备 {#tracks-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-92, eval=FALSE} library(ggchord) feature_palette <- c( CDS = "#993366", promoter = "#31849B", rep_origin = "#F1E51D", primer_bind = "#A020F0", misc_feature = "#A6ACB3", protein_bind = "#31849B" ) 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) ```
### 从实际 DNA 计算数据轨道 {#tracks-domain} 本例读取随包 pUC19,每 100 bp 计算 一次 GC 比例;末尾不足 100 bp 的窗口按实际碱基数计算。 ```{r example-93, eval=FALSE} library(dplyr) data(plasmid_example_pUC19) track_seq <- plasmid_example_pUC19 |> select(accver, length) starts <- seq.int(1L, track_seq$length, by = 100L) gc_fraction <- function(sequence) { bases <- strsplit(sequence, "")[[1]] mean(bases %in% c("G", "C")) } bins <- tibble( accver = track_seq$accver, start = starts, end = pmin(starts + 99L, track_seq$length) ) |> rowwise() |> mutate(gc = gc_fraction(substr(plasmid_example_pUC19$sequence, start, end))) |> ungroup() head(bins) ``` `bins` 的每一行是一段实际序列窗口;先检查起止位置及 `gc`,再把数值映射到轨道高度与颜色。 #### 绘制 GC 比例 {#tracks-draw-gc} ```{r example-94, eval=FALSE} p_tracks <- ggchord(seq_data = track_seq) + geom_seq() + geom_seq_center_label() + geom_track_bar(aes(track_value = gc, track_fill = gc), data = bins, position = position_track("gc", width = unit(10, "mm")) ) + scale_track_value_continuous("gc", limits = c(0, 1), unit = "GC fraction") + scale_track_fill_gradientn("gc", colours = c("#E4F3EA", "#65B79B", "#27775C")) + coord_circular() + doc_theme p_tracks ```
从随包 pUC19 DNA 计算的 GC 比例
从随包 pUC19 DNA 计算的 GC 比例 · 点击放大查看
值域为 0–1,单位是比例。换成其他测量值时,要声明对应单位和有效范围。 `position_track()` 决定放置与物理宽度,`scale_track_value_continuous()` 决定数值映射, 二者不能互相替代。 ### 同一 ID 共享同一条轨道 {#tracks-sharing} 同名轨道上的各层共享数值域,bar 的基线也参与范围计算;它们必须声明一致的宽度和 放置方式。颜色标度按轨道 ID 独立设置。tile 表示区间类别,line 连接观测位置, bar 表示相对基线的区间值。不要把相同数值域误认为必须位于同一条轨道。 ### 检查裁剪和数值范围 {#tracks-diagnostics} `export_ggchord_layout()` 的 `track_registry` 与 `track_diagnostics` 记录值域、 物理尺寸、原生位移及裁剪情况。被裁剪或省略的行不等于测量值为零。 局部视图使用 `focus_ggchord_track()` 并共享相同窗口。 ### 叠加柱、滑动均值和注释带 {#tracks-multiple} 本页准备代码已创建实际注释 `features`,完成上面的 GC 计算后继续: ```{r example-95, eval=FALSE} line_bins <- bins |> transmute( accver, pos = floor((start + end) / 2), gc_mean = as.numeric(stats::filter(gc, rep(1 / 3, 3), sides = 2)) ) |> filter(is.finite(gc_mean)) categories <- features |> select(accver, start, end, type) p_multitrack <- ggchord(seq_data = track_seq) + geom_seq() + geom_seq_center_label() + geom_track_bar(aes(track_value = gc, track_fill = gc), data = bins, position = position_track("gc", width = unit(10, "mm")) ) + geom_track_line(aes(track_value = gc_mean), data = line_bins, position = position_track("gc", width = unit(10, "mm")), colour = "#233E4A" ) + scale_track_value_continuous("gc", limits = c(0, 1), unit = "GC fraction") + scale_track_fill_gradientn("gc", colours = c("#E4F3EA", "#65B79B", "#27775C")) + geom_track_tile(aes(track_fill = type), data = categories, position = position_track("features", order = 2, width = unit(2, "mm")) ) + scale_track_fill_manual("features", values = feature_palette) + coord_circular() + doc_theme + theme(legend.box = "vertical", legend.box.just = "left") focused_bins <- focus_ggchord_track(bins, track_seq, loci = tibble(accver = track_seq$accver, start = 500, end = 1500), type = "interval" ) p_multitrack ```
pUC19 GC 比例、三点滑动均值和注释类型带
pUC19 GC 比例、三点滑动均值和注释类型带 · 点击放大查看
柱和线都来自同一组实际 GC 值,线使用三个窗口的滑动均值;两端没有完整窗口时省略, 不填造观测值。折线位置是整数窗口中点。注释类型带有独立 ID 和配色。 轨道放在圆外并按顺序排列;小半径下过宽的内侧带可能折叠,此时会明确报错。 ### 完成后检查 {#tracks-check-result} bins 的 gc 在 0–1 之间,每行对应一个实际窗口;最后窗口可短于 100 bp。连续色表达数值,类别带只表达注释类型,不能用它比较 GC 大小。
继续:预览和保存图形 →
### 保存本页结果 {#tracks-save-result} 在工作目录中保存刚刚创建的图;预览时使用相同宽高。 ```{r example-96, eval=FALSE} ggsave("pUC19-tracks.png", p_multitrack, width = 9, height = 8, units = "in", dpi = 144) ``` ## 设置配色、图例和主题 {#styling}

让颜色表达明确含义:先决定类别或连续数值,再选择映射、标度和图例。网站强调色不决定数据配色。

### 本页准备 {#styling-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-97, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
### 从数据角色构建样式 {#styling-roles} 例子明确声明类别:区间连接填色映射 query ID,序列颜色映射序列 ID,基因填色映射链。手动标度的名称与实际取值匹配。 ```{r example-98, eval=FALSE} p_styled <- ggchord(seq_data = seqs, ribbon_data = links, gene_data = genes) + geom_seq() + geom_link_ribbon(aes(ribbon_fill = qaccver), alpha = .5) + geom_gene() + geom_seq_label(size = 4) + coord_collinear() + doc_axis() + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + scale_ribbon_fill_manual(values = seq_palette) + guides(gene_fill = guide_ggchord_legend(nrow = 1, theme = doc_legend_theme)) + doc_theme theme_variants <- list(minimal = theme_ggchord_minimal(), dark = theme_ggchord_dark(), plasmid = theme_ggchord_plasmid()) p_styled ```
显式设置序列、链方向和查询类别的颜色标度
显式设置序列、链方向和查询类别的颜色标度 · 点击放大查看
| 角色 | 映射数据 | 常用标度家族 | | --- | --- | --- | | `seq_colour`, `seq_ring` | 序列/类别 | 序列颜色或 ring 手动标度 | | `ribbon_fill`, `ribbon_alpha`, `ribbon_colour`, `ribbon_linetype` | 比对元数据或统计 | 手动、渐变/分段/identity 和透明度标度 | | `feature_fill`, `feature_shape`, `gene_fill`, `region_fill` | 注释类别或链 | 相应角色的手动/预设标度 | | `link_colour`, `link_alpha`, `link_linewidth`, `link_linetype` | 点连接元数据 | 连续或手动 link标度| | `track_value`, `track_fill`, `track_colour` | 命名轨道的数值/类别 | 命名数值域与颜色/填色标度 | ### 固定样式和用户标度优先 {#styling-priority} 常量样式写在 `aes()` 外,变化样式写在映射中并配合合适的标度。 显式几何层固定值优先,省略该固定参数才保持映射。用户标度优先于自动默认。 同类多层独立保留数据、映射和参数。按 `accver` 命名的几何向量,不表示标度 也接受逐序列列表。 ### 组织可读图例 {#styling-guides} `guide_ggchord_legend()` 控制离散角色图例,`guide_ggchord_colourbar()` 控制连续颜色 图例。colour/color 拼写别名保留,本文优先用 `colour`。图层 `show.legend` 决定显示,`guides()` 选择图例,`theme(legend.position = ...)` 决定位置。 过宽图例可分行或增加导出宽度,不需要删减生物学数据来迁就。 ### 为场景选择主题 {#styling-themes} 例子在 `theme_variants` 中保存 minimal、dark 和 plasmid 备选,按场景添加到相应图中。 上图使用 `theme_ggchord_publication()`,plasmid 预设用于圆图流程。 主题控制非数据外观,不选择坐标系,也不替代数据驱动的填色标度。 文字外观用 `theme(text = element_text(...))`;已删除的 `base_size` 式快捷参数见 [迁移指南](#migration)。 ### 完成后检查 {#styling-check-result} 同一 query 的连接颜色一致;连续相似度应使用连续标度。固定颜色放在 aes() 外,图例必须能说明映射。
继续:调整图形 →
## 按序列和链设置参数 {#parameters}

按序列或链调整几何,保留旧版灵活参数的实用性,同时明确它不适用于所有参数。

### 本页准备 {#parameters-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-99, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
旧版称为“灵活的参数格式”。本页用“按序列和链设置参数”明确其用途与边界。 ### 这个能力仍然保留 {#parameters-recommendation} 同一图里常要单独调整某条序列,或分别调整正负链。为这些几何参数保留简洁的 逐序列/逐链写法是合理的;没有必要为了多一条序列而复制整个图层。 推荐先用单值,确实需要差异时用按 `accver` 命名的向量;正负链使用 `+`/`-` 命名向量。 ```{r example-100, eval=FALSE} # Sequence IDs remain stable when the data is reordered; positional lists do not. radii <- setNames(c(1.1, 1, 1, 1), seqs$accver) widths <- c("+" = .045, "-" = .065) p_parameters <- ggchord(seq_data = seqs, gene_data = genes) + geom_seq(seq_radius = radii) + geom_gene( width = widths, position = position_strand(c("+" = .08, "-" = -.1)) ) + geom_seq_label(size = 4) + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + coord_chord() + doc_theme p_parameters ``` `radii` 的名称对应实际序列 ID, `widths` 和位移对应链。重新排序时,命名值仍能找到原序列;无名值只按当前位置对应。 这个例子修改的是布局和几何,未把颜色或 theme 参数当成同一套扩展语法。 ### 哪些参数支持 {#parameters-scope} | 接口 | 支持参数 | 匹配范围 | | --- | --- | --- | | `geom_seq()` | `seq_radius`, `seq_curvature`, `seq_gap`, `seq_orientation` | 按序列;半径/曲率的效果取决于坐标模式 | | `geom_seq_label()` | `labels`, `seq_label_radius`, `seq_label_rotation`, `size`, `seq_label_hjust`, `seq_label_vjust` | 按序列;`seq_label_orientation` 是单个模式选项 | | `geom_link_ribbon()` / `geom_link_line()` | `link_gap` | 按端点所在序列;控制点不是逐序列标量 | | `geom_gene()` / `geom_feature()` | `width` | 按序列,或分别按 `+`/`-` 链 | | `position_strand()` / `position_plasmid()` | `offset` | 按序列或链;优先使用 Position 而非兼容 offset 入口 | | 固定标签 `geom_gene_label()` / `geom_feature_label()` | `label_radial_offset`, `label_circum_offset`, `label_circum_limit`, `label_rotation` | 按序列或链;不代表所有文本参数都接受列表 | | `position_track()` | 数值型 `width`, `gap` | 原生布局数值可按序列;物理 `unit()` 使用单个绝对尺寸 | `seq_order` 本身就是序列排列,不是上述值的循环规则。自动避让标签的 `label_layout` 是布局模式;手动角度和偏移请使用固定标签层,不把它们塞进自动标签的 `...`。 axis/theme、aesthetic、标度、图例不继承这套列表扩展规则。手工标度本来就支持 按**数据类别**命名的颜色向量,那属于 ggplot2 的标度语义,见[配色教程](#styling)。 ### 兼容写法与取舍 {#parameters-compatibility} 当前还兼容等长无名向量、按序列名的列表、按序号的列表及等长无名列表;gene/注释 的一项还可包含 `+`/`-` 两个值。它们是现有几何接口的兼容形式,不是任意参数的 通用容器。不同参数仍有自己的类型、长度、范围和单位检查。 v0.16.6 RC 审计决定保留这些等价形式,没有新增删除或弃用。位置写法跟随筛选后 当前显示序列顺序;名称匹配 accession ID 时优先按 ID。width/固定标签的逐序列 列表元素应为链值对,单值循环用 `list(value)`;Position offset 还允许逐序列单值 列表。显式按链命名的 Position offset 已带符号,未指定的链或序列补零; `position_plasmid()` 使用共享 offset,拒绝链值对。键应唯一;`"1"`、`"+"`、`"-"` 这类序列 ID 可能与序号或链简写混淆,按链设置时宜使用按序列命名的嵌套列表。 原生数值型 track width/gap 必须覆盖所有显示序列。这些规则不扩展到 theme。 数值并不共用一个单位:`seq_gap` 是比例,旋转角度以度表示,物理轨道尺寸使用 明确的 `unit()`。`seq_backbone_gap`、`seq_backbone_width` 是单值样式参数,不在 上述列表规则中。共线性自动方向用 `coord_collinear(orientation = "auto")`; `geom_seq(seq_orientation = ...)` 指定的是 +1/-1 数值方向。 ### 完成后检查 {#parameters-check-result} 命名向量的键应对应实际 accver 或 +/− 链。重排后再次检查匹配;不要将列表规则推广到 theme、scale 或 aesthetic。
继续:设置配色、图例和主题 →
## 调整图形 {#adjustments}

把常见调整放到正确的 ggplot2 组件:数据映射、几何位置、坐标和主题各负其责。

### 本页准备 {#adjustments-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-101, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } ```
### 职责分配 {#adjustments-grammar} | 任务 | 接口 | | --- | --- | | 把数据列映射到 aesthetic | `aes()` | | 定义映射规则与图例 | `scale_*()`, `guides()` | | 几何与固定样式 | `geom_*()` | | 局部放置 | `position_*()` | | 全局坐标系 | `coord_*()` | | 非数据外观 | `theme_*()`, `theme()` | | 标题与说明 | `labs()` | 固定样式可直接传给几何层,数据驱动差异则使用映射和标度。显式固定值优先于映射, 省略固定参数则保留映射;用户标度优先于自动默认值。 `shape` 是固定注释几何参数,`feature_shape` 仍是映射角色。 显式 `shape = NULL` 无效,不表示改用映射。 ### 映射连接相似度 {#adjustments-mapping} ```{r example-102, eval=FALSE} identity_links <- ribbon_data_example |> select(qaccver, saccver, qstart, qend, sstart, send, pident) p_mapped <- ggchord(seq_data = seqs, ribbon_data = identity_links) + geom_seq() + geom_link_ribbon(aes(ribbon_fill = pident), alpha = .6) + scale_ribbon_fill_gradientn( colours = identity_palette, values = identity_values, limits = c(0, 100), breaks = identity_breaks, name = "Identity (%)", guide = identity_guide ) + scale_seq_colour_manual(values = seq_palette) + coord_chord(rotation = 20) + labs(title = "Sequence comparison") + doc_theme p_mapped ``` ### 放置注释{#position} 使用 `position_strand(c("+" = .1, "-" = -.2))` 指定带符号的逐链位移。 `position_feature_stack()` 处理重叠注释,`position_track()` 分配命名定量轨道。 逐序列几何参数可用单值、等长无名向量或按 `accver` 命名的向量;推荐命名向量。 这套语法不扩展到标度、图例或 theme。 每层独立拥有 `data`、`mapping` 和参数,同类注释/连接层不会互相替换。 `show.legend` 和 `inherit.aes` 遵循 ggplot2。输入角色映射在几何生成前处理, 后期视觉映射遵循 ggplot2 求值。详见 接口说明 (`help("ggchord_api_contract", package = "ggchord")`)。 ### 完成后检查 {#adjustments-check-result} 旋转整体图形使用 coord;逐序列几何使用明确命名值;颜色随数据变化时使用映射和标度。
继续:按序列和链设置参数 →
## 预览和保存图形 {#output}

按真实导出尺寸检查图形,再用标准 ggsave() 保存,并了解布局表与诊断可以证明什么。

### 本页准备 {#output-prepare} 在新的 R 会话中先运行下方代码,再按页面顺序继续。配色和排版是可选的显示设置,输入只选择需要的列。
准备代码 · 在本页运行一次 ```{r example-103, eval=FALSE} 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) # Optional appearance choices; none of these columns or scales is required input. library(ggchord) seq_palette <- setNames( c("#E64B35", "#233E4A", "#269B82", "#D59B17"), c("MT108731.1", "MT118296.1", "OQ646790.1", "OR222515.1") ) gene_palette <- c("+" = "#CE1536", "-" = "#346B9D", "." = "#8291A6") 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) ) } anchors <- genes |> group_by(accver) |> slice_max(end - start, n = 1, with_ties = FALSE) |> ungroup() |> select(accver, start, end) p_collinear <- ggchord(seq_data = seqs, ribbon_data = links, gene_data = genes) + geom_link_ribbon(aes(ribbon_fill = qaccver), alpha = .7) + scale_ribbon_fill_manual(values = seq_palette, guide = "none") + geom_seq() + geom_gene(position = position_strand(.1)) + geom_seq_label(size = 4) + coord_collinear(anchor = anchors, align = "center", orientation = "auto") + doc_axis() + scale_seq_colour_manual(values = seq_palette) + scale_gene_fill_manual(values = gene_palette) + doc_theme p_collinear ```
### 按目标尺寸保存 {#output-size} 先在[三种模式](#modes)中创建 `p_collinear`: ```{r example-104, eval=FALSE} ggsave("comparison.png", p_collinear, width = 8, height = 5, units = "in", dpi = 144) ``` RStudio Plots 使用当前面板尺寸,标签与图例可能随面板调整而重新排列。 最终 `ggsave()` 前,按相同显式尺寸预览: ```{r example-105, eval=FALSE} view_ggchord(p_collinear, width = 8, height = 5, units = "in") diagnosis <- diagnose_ggchord(p_collinear, width = 8, height = 5, units = "in") ``` `view_ggchord()` 返回临时图片路径,不保存最终导出文件。 网站、README 和 vignette 共用标准 `ggsave()` 生成的 PNG,尺寸见[图集](#gallery), 不截取临时调整后的交互面板。最终矢量输出应显式选择目标 PDF/SVG 设备;字体可用性 和嵌入仍取决于设备。 ### 按字段名消费几何 {#output-geometry} ```{r example-106, eval=FALSE} geometry <- export_ggchord_layout(p_collinear, include = "seq") rows <- geometry$seq |> distinct(layer_id, component, source_row) ``` `export_ggchord_layout()` 是推荐的分层表格接口;`get_chord_layout()` 保留完整的 已记录布局,两者都未弃用。选择字段名,不依赖固定列位置。 `source_row` 指已解析图层输入行,ID 是构建期资源,不是永久生物学标识。 详见完整布局结果说明 (`help("ggchord_layout_contract", package = "ggchord")`)。 ### 理解诊断证据 {#output-diagnostics} `diagnose_ggchord()` 区分面板已测量与几何收敛。面板已测量不表示文字无碰撞、字体 已嵌入或跨应用表现已认证。应检查警告、文字/图例测量及放置原因。 `optimize_ggchord_layout()` 按文档执行主动选择的调整,应保留副本并查看结果。 预览和诊断使用独立渲染副本。直接改动共享 ggproto 图层环境仍遵循普通 ggplot2 引用语义,不会自动隔离为一次独立编辑。 ### 完整布局、表格与主动选择的排序 {#output-consumption} ```{r example-107, eval=FALSE} full_layout <- get_chord_layout(p_collinear) layer_tables <- export_ggchord_layout(p_collinear, include = c("seq", "gene"), original_data = TRUE) layout_choice <- optimize_ggchord_layout(seqs, links, optimize = c("order", "orientation"), weight = "count") ``` 先在[三种模式](#modes-collinear)创建 `p_collinear`。 `full_layout` 保留完整的已记录 getter 结果,`layer_tables` 选择序列/基因表与已解析 原始数据,不是原始文件档案。layer ID 和源行角色区分独立同类图层。 空组件可没有固定列原型,应按字段名读取。 `layout_choice` 以计数权重选择顺序/方向,因为本例的最小绘图表有意未保留比对长度统计列。 返回的选择应显式用于序列设置,不修改原图,也不确立生物学方向。 采用前应保存该选择并对照结果。文档精确尺寸见资产清单 (`website/assets/plots.csv` in the source repository)。 ### 完成后检查 {#output-check-result} 预览与保存使用相同宽高。检查文字、图例与警告;一次测量成功不代表跨设备字体和发布质量已认证。
继续:常见问题 →
## 使用教程 {#articles}
按模块循序学习,再按需查阅共用技巧。每个模块从输入表出发,以完整展示图结束。
### 三条学习路线 {#articles-modules}
模块一『弦图』部分表格 → 导入 → 骨架与图层 → 参数与避障 → 综合图 模块二『共线性图』部分复用数据 → 替换坐标 → 跨行路由 → 局部比较 → 综合图 模块三『质粒图』部分DNA与注释 → 圆圈与图层 → 识别 → 13个案例 → 密集综合图
### 依次阅读或按需查阅 {#articles-guides} #### 安装与学习路线 {#articles-path-start} - [安装与环境准备](#installation) - [选择合适的学习模块](#modes) #### 模块一『弦图』部分 {#articles-path-chord} - [1.1 输入表与字段含义](#chord-data) - [1.2 生成与导入比对数据](#chord-import) - [1.3 从骨架逐层添加](#chord-build) - [1.4 方向、曲率与避障](#chord-tuning) - [1.5 筛选与整理连接](#ribbons) - [1.6 原始文件完整流程](#real-data) - [1.7 弦图综合展示](#chord) #### 模块二『共线性图』部分 {#articles-path-collinear} - [2.1 复用弦图的数据](#collinear-data) - [2.2 只替换坐标系,再逐层添加](#collinear-build) - [2.3 跨行连接、避障与比例尺](#collinear-routing) - [2.4 比较基因邻域](#homology) - [2.5 局部、锚定与分段](#views) - [2.6 共线性综合展示](#collinear) #### 模块三『质粒图』部分 {#articles-path-plasmid} - [3.1 DNA、注释与13个参考序列](#plasmid-data) - [3.2 从圆圈到多层注释](#plasmid-build) - [3.3 识别特征、引物与酶切](#recognition) - [3.4 13个质粒参考案例](#plasmid-catalog) - [3.5 质粒综合实战](#plasmids) #### 按需查阅:数据与图层 {#articles-path-shared} - [数据与坐标](#data) - [导入和转换数据](#formats) - [导入核酸和蛋白比对](#alignments) - [将蛋白区间转换为基因组坐标](#projection) - [绘制注释与处理重叠](#annotations) - [放置和调整标签](#labels) - [添加数据轨道](#tracks) - [设置配色、图例和主题](#styling) - [按序列和链设置参数](#parameters) - [调整图形](#adjustments) - [预览和保存图形](#output) #### 学习地图与函数查阅 {#articles-path-reference} - [示例图集](#gallery) - [常见问题](#faq) - [迁移到候选 API](#migration) - [术语说明](#glossary) ### 功能与可运行证据 {#articles-capabilities} | 功能 | 使用教程 | 代码与结果 | | --- | --- | --- | | 三种坐标模式 | [选择合适的学习模块](#modes) | `chord`, `circular`, `collinear` · chord, circular, collinear | | 真实记录比较 | [1.6 原始文件完整流程](#real-data) | `realimport`, `realprepare`, `realchord`, `reallinear` · realchord, reallinear | | 完整圆图注释 | [3.5 质粒综合实战](#plasmids) | `plasmid` · plasmid | | 校验、清理与层次 | [数据与坐标](#data) | `validation`, `cleaning`, `hierarchy` | | 文件格式与适配器 | [导入和转换数据](#formats), [导入核酸和蛋白比对](#alignments) | `adapters`, `formats`, `genbank`, `optionalranges`, `standardblast`, `protein` · paf | | 连接准备与统计 | [1.5 筛选与整理连接](#ribbons) | `ribbons` · density | | 区间与点连接 | [1.5 筛选与整理连接](#ribbons), [选择合适的学习模块](#modes) | `pointlinks`, `collinear` · pointlinks | | Feature 与 Position | [绘制注释与处理重叠](#annotations) | `featurestack` · featurestack | | 自动与固定标签 | [放置和调整标签](#labels), [3.5 质粒综合实战](#plasmids) | `labellayouts`, `labels`, `plasmid` · labelauto, labelradial, labelarc | | 轴、参照条与区域 | [绘制注释与处理重叠](#annotations), [2.5 局部、锚定与分段](#views) | `decorations`, `focus` · decorations | | 定量轨道与数值域 | [添加数据轨道](#tracks) | `tracks`, `multitrack` · multitrack | | 引物、酶切及 feature 搜索 | [3.3 识别特征、引物与酶切](#recognition), [3.5 质粒综合实战](#plasmids) | `recognition`, `plasmid` · plasmid | | CDS 与连接投影 | [将蛋白区间转换为基因组坐标](#projection), [2.4 比较基因邻域](#homology) | `projection`, `linkprojection` | | 显式 cluster 与 loci | [2.4 比较基因邻域](#homology) | `homologs` · homologs | | 局部、分段与源映射 | [2.5 局部、锚定与分段](#views) | `focus`, `segment`, `mappingposition` · focus | | 标度、图例与主题 | [设置配色、图例和主题](#styling), [调整图形](#adjustments), [按序列和链设置参数](#parameters) | `styling`, `adjustments`, `parameters` · styling | | 预览、结果与排序 | [预览和保存图形](#output) | `save`, `preview`, `provenance`, `layoutresults` | | 迁移与常见问题 | [迁移到候选 API](#migration), [常见问题](#faq) | `migration` | ## 示例图集 {#gallery}

按要回答的问题选择案例;缩略图用于找到方向,点击可查看完整尺寸。每张图都链接到数据准备、代码和读图说明。

### 按任务找图 {#gallery-tasks} | 总体关系 | 单序列注释 | 局部位置 | 定量与排版 | | --- | --- | --- | --- | | [弦图](#gallery-realchord) | [质粒](#gallery-plasmid) | [CDS 邻域](#gallery-homologs) | [GC 轨道](#gallery-multitrack) | | [点连接](#gallery-pointlinks) | [注释堆叠](#gallery-featurestack) | [聚焦](#gallery-focus) | [标签布局](#gallery-labelauto) | ### 图片与尺寸 {#gallery-figures} ### 两种语言共用一个来源 {#gallery-source} 所有图均使用随包数据或有来源的真实记录,见[共享文档示例源码](https://github.com/DangJem/ggchord/blob/main/tools/documentation-examples.R) 。未为改善外观改写任何原始 FASTA/GFF3/BLAST 记录。 两种语言、README 和 vignette 引用相同图片字节,图注分别说明含义。 源码及资产 hash 记录在资产清单 (`website/assets/plots.csv` in the source repository)中。 各专题说明显示筛选。GC 来自实际 DNA 计算,同源分组例子核对实际编码序列; 只有诊断示例会故意修改原始记录的副本,并明确标注,不把错误副本当作生物学数据。 ### 重建 {#gallery-reproduce} 在源码仓库中准备好建议的开发依赖后运行: ```sh Rscript tools/documentation-plots.R python3 tools/sync-tutorials.py --check python3 tools/build-website.py python3 tools/check-documentation.py ``` PNG 设备仅用于更新这些文档图片,不是输出设备矩阵或发布验收。 源码和尺寸位于 `tools/documentation-plots.R`,参数变化后须重建清单。 自己的图片导出方式见[输出](#output)。 ### 资产来源 {#gallery-assets} [原画、模板和依赖许可](https://github.com/DangJem/ggchord/blob/main/website/ASSET-SOURCES.md)。 ## 常见问题 {#faq} ### 调整尺寸后标签为什么不同? {#faq-resize} 可用物理空间改变了。使用[显式尺寸预览与保存](#output-size),并检查隐藏标签 诊断,不能由文字未显示直接推断输入行丢失。 ### 旧参数为什么报错? {#faq-removed} API 清理已删除旧别名的执行路径,见[迁移表](#migration)。同一语义不要混用新旧 写法。colour/color 函数拼写别名仍保留,文档优先使用 `colour`。 ### 注释为什么不能作为 gene 绘制? {#faq-strand} 基因快捷层要求已知 `+`/`-` 链。未知链保留在通用注释层,不要猜成 `+`。 氨基酸区间需要显式投影。 ### 直线模式的区间连接为什么没显示? {#faq-ribbons} 默认只连接相邻显示序列。应检查序列对选择、裁剪和校验结果,再有意使用明确 `pairs` 或 `adjacent_only = FALSE`。这个默认规则不删除原始输入记录。 ### 包会计算比对或验证引物实验吗? {#faq-biology} 包可视化已有比对和计算搜索结果,不运行 BLAST、不由名称推断同源分组,也不验证湿实验 结果。搜索 confidence 不是概率。详见[识别能力边界](#recognition)。 ### 已测量诊断等于发布认证吗? {#faq-quality} 不等于。它描述一次指定渲染。平台、设备、字体、完整 vignette 和包检查属于明确授权 后的发布流程。验证范围见正式发布验收记录。 ### 在哪里报告问题? {#faq-report} 在 [问题反馈页](https://github.com/DangJem/ggchord/issues) 提供小型输入、包与 ggplot2 版本、代码、目标宽高、设备和诊断结果。避免附带私有序列,通常可用合成数据复现。 ## 迁移到候选 API {#migration} ### 范围与时间 {#migration-scope} 下列写法是当前候选替代,不是 v1.0.0 长期兼容承诺。0.16.0–0.16.4 阶段成果已随 v0.16.5 交付。 当前安装标签为 v0.16.6。RC 审计保留 灵活参数、拼写别名、重导出及 getter/export 入口,没有新增弃用。 表中的旧调用用于解释迁移,不应作为当前例子执行。 历史证据只提供删除上界时,不猜测精确首删 tag。 ### 替代表 {#migration-table} | 旧写法(勿执行) | 当前写法 | 删除 / 守卫 | 含义 | | --- | --- | --- | --- | | `geom_ribbon()` | `geom_link_ribbon()` | ≤ 0.16.1 | 连接图层改名,不影响 ggplot2::geom_ribbon()。 | | `ggchord(..., rotation = 20)` | `ggchord(...) + coord_chord(rotation = 20)` | ≤ 0.16.1 | 全局坐标使用 + 组合。 | | `geom_feature(feature_shape = "block", feature_width = .05)` | `geom_feature(shape = "block", width = .05)` | 0.16.1 | 映射角色 feature_shape 保留。 | | `geom_gene(gene_offset = c("+" = .1, "-" = .2))` | `geom_gene(position = position_strand(c("+" = .1, "-" = -.2)))` | 0.16.1 | 显式 Position 值带符号。 | | `geom_feature(feature_offset = .1)` | `geom_feature(position = position_strand(.1))` | 0.16.1 | 使用 Position 对象。 | | `geom_gene(gene_width = .05)` | `geom_gene(width = .05)` | 0.16.1 | 固定几何统一使用 width。 | | `geom_link_ribbon(ribbon_gap = .01)` | `geom_link_ribbon(link_gap = .01)` | 0.16.1 | 使用 link_gap,控制点同样使用 link_ctrl_point。 | | `geom_gene_label_repel(gene_label_layout = "aligned")` | `geom_gene_label_repel(label_layout = "auto")` | 0.16.1 | 同时迁移参数名和取值。 | | `geom_gene_label_repel(label_rotation = 90)` | `geom_gene_label(label_rotation = 90)` | 0.16.4 guard | 原先忽略的手动控制现报错,也可删除它使用自动布局。 | | `geom_feature_label_repel(label_orientation = "horizontal")` | `geom_feature_label(label_orientation = "horizontal")` | 0.16.4 guard | 未知链 feature 使用固定 feature 标签层。 | | `geom_restriction_site(leader = "trunk")` | `geom_restriction_site(leader = "radial")` | 0.16.1 | radial 默认值保持。 | | `theme_ggchord(base_size = 10)` | `theme_ggchord() + theme(text = element_text(size = 10))` | ≤ 0.16.1 | 文字外观属于 theme 元素。 | ### 运行当前替代 {#migration-replacement} 在新会话中运行下面的准备代码,再执行当前替代写法:
准备代码 · 在本页运行一次 ```{r example-108, eval=FALSE} 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(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) ```
```{r example-109, eval=FALSE} p_migrated <- ggchord(plasmid_seq) + geom_seq() + geom_feature(data = features, shape = "block", width = .05) + geom_feature_label(data = features, label_rotation = 0) + coord_circular() p_offsets <- ggchord(seqs, gene_data = genes) + geom_seq() + geom_gene(position = position_strand(c("+" = .1, "-" = -.2))) ``` 旧负链 offset 幅度在显式 Position 中需要负号。映射仍使用 `aes(feature_shape = type)` 配合 shape 标度,固定参数则为 `shape`。 自动标签使用 `label_layout`,手动几何控制使用相应固定标签层。 `label_layout = "aligned"` 改为 `"auto"`。已删除名称明确报错,不保留静默执行路径。 ### 保留的支持 {#migration-retained} 五个 colour/color 拼写别名、全部上游重导出、gene/注释/plasmid 快捷入口及 getter/export 两类几何接口均保留。各坐标默认差异和已记录结果字段保持。NULL/NA/缺参语义应查阅 接口说明 (`help("ggchord_api_contract", package = "ggchord")`)和当前参考;NULL 不统一表示关闭。 ## 术语说明 {#glossary} ### 对照术语 {#glossary-terms} | English | 现代汉语 | API / units | | --- | --- | --- | | sequence | 序列 | accver / length | | chord diagram | 弦图 | coord_chord() | | circular sequence map | 单序列圆图 | coord_circular() | | collinearity plot | 共线性图 | coord_collinear() | | interval link / ribbon | 区间连接 / 连接带 | qaccver / saccver | | feature | 通用注释特征(feature) | geom_feature() | | gene | 已知链的基因 | geom_gene() | | strand | 链方向 | + / - / unknown | | aesthetic mapping | 美学属性映射 | aes() | | scale | 标度 | scale_*() | | guide | 图例 / 标度指南 | guides() | | position | 局部位置调整 | position_*() | | track | 定量轨道 | position_track() | | genomic position | 基因组位置 | one-based inclusive bp / 一基闭区间 | | layout units | 原生布局单位 | not bp or mm / 不等于 bp 或 mm | | source row | 已解析输入来源行 | source_row | | physical file line | 物理文件行 | .source_line | | focus | 局部聚焦 | focus_ggchord_data() | | segment | 分段窗口 | segment_ggchord_data() | | leader | 标签引导线 | label / connection | | CDS projection | 编码序列坐标投影 | build_ggchord_cds() | | measured panel | 已测量面板 | not visual certification / 不等于视觉认证 | ### 设计与资产来源 {#glossary-sources} 语法参考 [ggplot2](https://ggplot2.tidyverse.org/),映射、标度、几何、位置、坐标与主题 分别承担不同职责。紧凑的 query/subject 字段参考 BLAST 风格表格,ggchord 绘图时 不运行比对工具。环形层次和注释可读性与 Circos、clinker、DNA Features Viewer 进行比较,具体边界记录在仓库设计文档中;这些是概念借鉴,不是复制 API。 精细的 ggchord 图标由用户于 2026-11-01 提供,授权用于网站和说明文档。 完整 PNG 和 WebP 保留逐像素 RGBA,只有导航缩略图调整尺寸。 图标清单 (`website/assets/icon.json` in the source repository)记录来源 hash 和准确体积。下方的简洁六边形研究标识、网站 CSS/JS 及文档示意图是本项目原创资产,遵循仓库 MIT 条款。研究标识作为补充方案保留, 不替代用户提供的图标。 ![简洁六边形研究标识](tutorial-assets/logo.svg) 使用系统字体,不下载网络字体、图标库或第三方图片。 图中颜色来自包的现有默认值或显式教学代码,具体色值随源码记录。 网站在构建时使用已有 Pandoc 和 R 文档转换器,不捆绑其二进制或样式表。