PGAP2 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pgap2/__init__.py +4 -0
- pgap2/dependencies/draw_post_profile.r +193 -0
- pgap2/dependencies/draw_post_stat.r +97 -0
- pgap2/dependencies/draw_prep.r +159 -0
- pgap2/dependencies/maskrc-svg.py +236 -0
- pgap2/dependencies/run_fastbaps +55 -0
- pgap2/lib/basic.py +203 -0
- pgap2/lib/panclust.py +24 -0
- pgap2/lib/pangenome.py +343 -0
- pgap2/lib/pangp.py +121 -0
- pgap2/lib/phylogeny.py +596 -0
- pgap2/lib/pklcheck.py +80 -0
- pgap2/lib/species.py +160 -0
- pgap2/lib/strain.py +7 -0
- pgap2/lib/tree.py +210 -0
- pgap2/main.py +33 -0
- pgap2/pgap2/__init__.py +2 -0
- pgap2/pgap2/dependencies/maskrc-svg.py +236 -0
- pgap2/pgap2/lib/basic.py +203 -0
- pgap2/pgap2/lib/panclust.py +24 -0
- pgap2/pgap2/lib/pangenome.py +343 -0
- pgap2/pgap2/lib/pangp.py +121 -0
- pgap2/pgap2/lib/phylogeny.py +596 -0
- pgap2/pgap2/lib/pklcheck.py +80 -0
- pgap2/pgap2/lib/species.py +160 -0
- pgap2/pgap2/lib/strain.py +7 -0
- pgap2/pgap2/lib/tree.py +210 -0
- pgap2/pgap2/main.py +33 -0
- pgap2/pgap2/postprocess/baps.py +144 -0
- pgap2/pgap2/postprocess/profile.py +122 -0
- pgap2/pgap2/postprocess/singletree.py +130 -0
- pgap2/pgap2/postprocess/stat.py +511 -0
- pgap2/pgap2/postprocess/tajimas_d.py +124 -0
- pgap2/pgap2/utils/__init__.py +0 -0
- pgap2/pgap2/utils/alignment.py +45 -0
- pgap2/pgap2/utils/arrangement_detector.py +122 -0
- pgap2/pgap2/utils/data_loader.py +679 -0
- pgap2/pgap2/utils/draw.py +1095 -0
- pgap2/pgap2/utils/gene_retriever.py +212 -0
- pgap2/pgap2/utils/generate_tree.py +310 -0
- pgap2/pgap2/utils/partition.py +851 -0
- pgap2/pgap2/utils/postprocess.py +18 -0
- pgap2/pgap2/utils/preprocess.py +475 -0
- pgap2/pgap2/utils/supply.py +139 -0
- pgap2/pgap2/utils/tools.py +607 -0
- pgap2/postprocess/baps.py +144 -0
- pgap2/postprocess/profile.py +122 -0
- pgap2/postprocess/singletree.py +130 -0
- pgap2/postprocess/stat.py +511 -0
- pgap2/postprocess/tajimas_d.py +123 -0
- pgap2/toy_input/287_91.fa +1 -0
- pgap2/toy_input/287_91.gff +7657 -0
- pgap2/toy_input/AKU_12601.gff +1 -0
- pgap2/toy_input/Readme_input.md +3 -0
- pgap2/toy_input/SC_B67.gbk +1 -0
- pgap2/utils/__init__.py +0 -0
- pgap2/utils/alignment.py +45 -0
- pgap2/utils/arrangement_detector.py +122 -0
- pgap2/utils/data_loader.py +684 -0
- pgap2/utils/draw.py +1095 -0
- pgap2/utils/gene_retriever.py +212 -0
- pgap2/utils/generate_tree.py +310 -0
- pgap2/utils/partition.py +851 -0
- pgap2/utils/postprocess.py +18 -0
- pgap2/utils/preprocess.py +475 -0
- pgap2/utils/supply.py +138 -0
- pgap2/utils/tools.py +615 -0
- pgap2-0.1.2.dist-info/METADATA +154 -0
- pgap2-0.1.2.dist-info/RECORD +73 -0
- pgap2-0.1.2.dist-info/WHEEL +5 -0
- pgap2-0.1.2.dist-info/entry_points.txt +2 -0
- pgap2-0.1.2.dist-info/licenses/LICENSE +21 -0
- pgap2-0.1.2.dist-info/top_level.txt +1 -0
pgap2/__init__.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env Rscript
|
|
2
|
+
# install.packages(c("ggplot2", "dplyr", "optparse", "readr", "scales", "patchwork"))
|
|
3
|
+
library(ggpubr)
|
|
4
|
+
|
|
5
|
+
library(dplyr)
|
|
6
|
+
library(optparse)
|
|
7
|
+
library(patchwork)
|
|
8
|
+
|
|
9
|
+
# 设置命令行参数解析
|
|
10
|
+
option_list <- list(
|
|
11
|
+
make_option(c("-a", "--pan_group_stat"), type = "character", help = "postprocess.pan_group_stat.tsv"),
|
|
12
|
+
make_option(c("-b", "--clust_strain_freq"), type = "character", help = "postprocess.clust_strain_freq.tsv"),
|
|
13
|
+
make_option(c("-c", "--rarefaction"), type = "character", help = "postprocess.rarefaction.tsv"),
|
|
14
|
+
make_option(c("-d", "--new_clusters"), type = "character", help = "postprocess.new_clusters.tsv"),
|
|
15
|
+
make_option(c("-e", "--para_stat"), type = "character", help = "postprocess.para_stat.tsv"),
|
|
16
|
+
make_option(c("-s", "--single_file"), type = "logical", action = "store_true", default = FALSE, help = "Generate each plot to the single file"),
|
|
17
|
+
make_option(c("-o", "--output_dir"), type = "character", help = "Output directory")
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# 解析命令行参数
|
|
21
|
+
opt_parser <- OptionParser(option_list = option_list)
|
|
22
|
+
opt <- parse_args(opt_parser)
|
|
23
|
+
|
|
24
|
+
# 创建输出目录
|
|
25
|
+
if (!dir.exists(opt$output_dir)) {
|
|
26
|
+
dir.create(opt$output_dir)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# 读取饼图数据文件
|
|
30
|
+
|
|
31
|
+
pan_group_stat_data <- read.csv(opt$pan_group_stat, header = TRUE, sep = "\t")
|
|
32
|
+
|
|
33
|
+
clust_strain_freq_data <- read.csv(opt$clust_strain_freq, header = TRUE, sep = "\t")
|
|
34
|
+
|
|
35
|
+
rarefaction_data <- read.csv(opt$rarefaction, header = TRUE, sep = "\t")
|
|
36
|
+
|
|
37
|
+
new_clusters_data <- read.csv(opt$new_clusters, header = TRUE, sep = "\t")
|
|
38
|
+
|
|
39
|
+
para_stat_data <- read.csv(opt$para_stat, header = TRUE, sep = "\t")
|
|
40
|
+
|
|
41
|
+
#-----------------------------------------------------------------------------#
|
|
42
|
+
# 保存图形
|
|
43
|
+
save_para_plots <- function(A, B, single_file, output_dir) {
|
|
44
|
+
if (single_file) {
|
|
45
|
+
ggsave(file.path(output_dir, "postprocess.para_stat.pdf"), A + ggtitle(""))
|
|
46
|
+
ggsave(file.path(output_dir, "postprocess.para_stat_facet.pdf"), B + ggtitle(""))
|
|
47
|
+
} else {
|
|
48
|
+
combined_plot <- A + B +
|
|
49
|
+
plot_layout(
|
|
50
|
+
ncol = 2, # 2列
|
|
51
|
+
nrow = 1, # 2行
|
|
52
|
+
widths = c(1, 1), # 第一列宽度为第二列的两倍
|
|
53
|
+
heights = c(1, 1) # 两行的高度相等
|
|
54
|
+
)
|
|
55
|
+
ggsave(file.path(output_dir, "pgap2.postprocess_stat_para.pdf"), combined_plot, width = 10.52, height = 5.8)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
save_basic_plots <- function(A, B, C, D, single_file, output_dir) {
|
|
60
|
+
if (single_file) {
|
|
61
|
+
ggsave(file.path(output_dir, "postprocess.pan_group_stat.pdf"), A)
|
|
62
|
+
ggsave(file.path(output_dir, "postprocess.clust_strain_freq.pdf"), B)
|
|
63
|
+
ggsave(file.path(output_dir, "postprocess.rarefaction.pdf"), C)
|
|
64
|
+
ggsave(file.path(output_dir, "postprocess.new_clusters.pdf"), D)
|
|
65
|
+
} else {
|
|
66
|
+
combined_plot <- A + B + C + D +
|
|
67
|
+
plot_layout(
|
|
68
|
+
ncol = 2, # 2列
|
|
69
|
+
nrow = 2, # 2行
|
|
70
|
+
widths = c(1, 1), # 第一列宽度为第二列的两倍
|
|
71
|
+
heights = c(1, 1) # 两行的高度相等
|
|
72
|
+
)
|
|
73
|
+
ggsave(file.path(output_dir, "pgap2.postprocess_profile.pdf"), combined_plot, width = 9.52, height = 7.25)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
draw_pan_group_stat <- function(pan_group_stat_data) {
|
|
78
|
+
labs <- paste0(pan_group_stat_data$Group, ": ", pan_group_stat_data$Count, " (", pan_group_stat_data$Proportion, "%)")
|
|
79
|
+
|
|
80
|
+
pan_group_stat <- ggpie(pan_group_stat_data, "Count",
|
|
81
|
+
label = labs,
|
|
82
|
+
fill = "Group", color = "white", lab.pos = "in", size = 1,
|
|
83
|
+
palette = c("#B8DBB3", "#72B063", "#719AAC", "#E29135", "#94C6CD"),
|
|
84
|
+
lab.font = c(4, "plain", "black"),
|
|
85
|
+
) + theme(
|
|
86
|
+
legend.position = "none",
|
|
87
|
+
plot.margin = margin(0, 0, 0, 0), # 去除空白边距
|
|
88
|
+
axis.text = element_blank(), # 隐藏坐标轴
|
|
89
|
+
axis.title = element_blank()
|
|
90
|
+
) + ggtitle("A")
|
|
91
|
+
return(pan_group_stat)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
draw_clust_strain_freq <- function(clust_strain_freq_data) {
|
|
95
|
+
clust_strain_freq <- gghistogram(clust_strain_freq_data,
|
|
96
|
+
x = "Freq", bins = 50, fill = "#B8DBB3",
|
|
97
|
+
xlab = "Genome Frequency", ylab = "Gene Cluster Number"
|
|
98
|
+
) + scale_y_log10() + ggtitle("B")
|
|
99
|
+
return(clust_strain_freq)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
draw_rarefaction <- function(rarefaction_data) {
|
|
104
|
+
rarefaction <- ggscatter(rarefaction_data,
|
|
105
|
+
x = "Strain", y = "Sampling", color = "Type", fill = NA, alpha = 0.5, size = 1, palette = c("#72B063", "#719AAC"),
|
|
106
|
+
xlab = "Genome Number", ylab = "Gene Cluster Number"
|
|
107
|
+
) + theme(
|
|
108
|
+
axis.line = element_line(linewidth = 0),
|
|
109
|
+
panel.background = element_blank(),
|
|
110
|
+
panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5), # 添加边框
|
|
111
|
+
panel.grid = element_blank(), # 去除网格线
|
|
112
|
+
plot.margin = margin(10, 10, 10, 10), # 增加图形的外边距,防止文字被裁剪
|
|
113
|
+
legend.position = c(0.15, 0.85), # 将图例放到图框内
|
|
114
|
+
legend.box = "horizontal", # 使图例在框内水平排列
|
|
115
|
+
legend.background = element_blank(), # 去除图例背景
|
|
116
|
+
legend.key.size = unit(0.5, "cm"), # 控制图例块的大小
|
|
117
|
+
legend.title = element_text(size = 10), # 设置图例标题字体大小
|
|
118
|
+
legend.text = element_text(size = 8) # 设置图例文本字体大小
|
|
119
|
+
) + guides(color = guide_legend(override.aes = list(alpha = 1))) + ggtitle("C")
|
|
120
|
+
# ggboxplot(rarefaction.data, color = 'Type', x = 'Strain', y = 'Sampling',fill=NA) +
|
|
121
|
+
# theme(
|
|
122
|
+
# axis.line = element_line(linewidth = 0),
|
|
123
|
+
# panel.border = element_rect(color = "black", fill = NA, linewidth = 0.75), # 添加边框
|
|
124
|
+
# panel.grid = element_blank(), # 去除网格线
|
|
125
|
+
# plot.margin = margin(10, 10, 10, 10) # 增加图形的外边距,防止文字被裁剪
|
|
126
|
+
# )+
|
|
127
|
+
# scale_x_discrete(breaks = unique(rarefaction.data$Strain)[seq(1, length(unique(rarefaction.data$Strain)), by = 5)])
|
|
128
|
+
|
|
129
|
+
return(rarefaction)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
draw_new_clusters <- function(new_clusters_data) {
|
|
133
|
+
new_clusters <- ggbarplot(new_clusters_data,
|
|
134
|
+
x = "Strain", y = "Sampling", add = "mean_se", fill = "#94C6CD",
|
|
135
|
+
xlab = "Genome Number", ylab = "New Gene Cluster Number"
|
|
136
|
+
) + theme(
|
|
137
|
+
axis.line = element_line(linewidth = 0),
|
|
138
|
+
panel.background = element_blank(),
|
|
139
|
+
panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5), # 添加边框
|
|
140
|
+
panel.grid = element_blank(), # 去除网格线
|
|
141
|
+
plot.margin = margin(10, 10, 10, 10), # 增加图形的外边距,防止文字被裁剪
|
|
142
|
+
legend.box = "horizontal", # 使图例在框内水平排列
|
|
143
|
+
legend.key.size = unit(0.5, "cm"), # 控制图例块的大小
|
|
144
|
+
legend.title = element_text(size = 10), # 设置图例标题字体大小
|
|
145
|
+
legend.text = element_text(size = 8) # 设置图例文本字体大小
|
|
146
|
+
) + guides(color = guide_legend(override.aes = list(alpha = 1))) + ggtitle("D")
|
|
147
|
+
return(new_clusters)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
draw_para_stat <- function(para_stat_data) {
|
|
151
|
+
para_stat_data$duplication_degree <- log(para_stat_data$Para_gene / para_stat_data$Para_strain)
|
|
152
|
+
para_stat_a <- ggscatter(para_stat_data,
|
|
153
|
+
x = "Para_strain", y = "Para_gene", size = "duplication_degree",
|
|
154
|
+
color = "black", shape = 21, fill = "Group",
|
|
155
|
+
conf.int = TRUE,
|
|
156
|
+
palette = c("#B8DBB3", "#72B063", "#719AAC", "#E29135", "#94C6CD"),
|
|
157
|
+
xlab = "Paralogous Strain",
|
|
158
|
+
ylab = "Paralogous Gene"
|
|
159
|
+
) +
|
|
160
|
+
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "red") + # 添加 x = y 线
|
|
161
|
+
guides(
|
|
162
|
+
size = "none" # 隐藏 size 图例
|
|
163
|
+
) + ggtitle("A")
|
|
164
|
+
return(para_stat_a)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
draw_para_stat_facet <- function(para_stat_data) {
|
|
168
|
+
para_stat_data$duplication_degree <- log(para_stat_data$Para_gene / para_stat_data$Para_strain)
|
|
169
|
+
para_stat_b <- ggscatter(para_stat_data,
|
|
170
|
+
x = "Para_strain", y = "Para_gene", size = "duplication_degree", color = "duplication_degree",
|
|
171
|
+
conf.int = TRUE, facet.by = "Group",
|
|
172
|
+
xlab = "Paralogous Strain",
|
|
173
|
+
ylab = "Paralogous Gene"
|
|
174
|
+
) +
|
|
175
|
+
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "red") + # 添加 x = y 线
|
|
176
|
+
scale_y_log10() + scale_x_log10() + # 对数缩放
|
|
177
|
+
scale_color_gradient(low = "#dddfe6", high = "#d90429") +
|
|
178
|
+
labs(color = "Dup degree") +
|
|
179
|
+
guides(
|
|
180
|
+
size = "none" # 隐藏 size 图例
|
|
181
|
+
) + ggtitle("B")
|
|
182
|
+
return(para_stat_b)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
A <- draw_pan_group_stat(pan_group_stat_data)
|
|
186
|
+
B <- draw_clust_strain_freq(clust_strain_freq_data)
|
|
187
|
+
C <- draw_rarefaction(rarefaction_data)
|
|
188
|
+
D <- draw_new_clusters(new_clusters_data)
|
|
189
|
+
E <- draw_para_stat(para_stat_data)
|
|
190
|
+
F <- draw_para_stat_facet(para_stat_data)
|
|
191
|
+
|
|
192
|
+
save_basic_plots(A, B, C, D, opt$single_file, opt$output_dir)
|
|
193
|
+
save_para_plots(E, F, opt$single_file, opt$output_dir)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env Rscript
|
|
2
|
+
library(ggpubr)
|
|
3
|
+
|
|
4
|
+
library(dplyr)
|
|
5
|
+
library(optparse)
|
|
6
|
+
library(patchwork)
|
|
7
|
+
|
|
8
|
+
# 设置命令行参数解析
|
|
9
|
+
option_list <- list(
|
|
10
|
+
make_option(c("-a", "--stat_attrs"), type = "character", help = "postprocess.stat_attrs.tsv"),
|
|
11
|
+
make_option(c("-s", "--single_file"), action = "store_true", default = FALSE, help = "Generate each plot to the single file"),
|
|
12
|
+
make_option(c("-o", "--output_dir"), type = "character", help = "Output directory")
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# 解析命令行参数
|
|
16
|
+
opt_parser <- OptionParser(option_list = option_list)
|
|
17
|
+
opt <- parse_args(opt_parser)
|
|
18
|
+
|
|
19
|
+
# 创建输出目录
|
|
20
|
+
if (!dir.exists(opt$output_dir)) {
|
|
21
|
+
dir.create(opt$output_dir)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
stat_attrs_data <- read.csv(opt$stat_attrs, header = TRUE, sep = "\t")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
#-----------------------------------------------------------------------------#
|
|
28
|
+
# 保存图形
|
|
29
|
+
|
|
30
|
+
save_basic_plots <- function(A, B, C, D, single_file, output_dir) {
|
|
31
|
+
if (single_file) {
|
|
32
|
+
ggsave(file.path(output_dir, "postprocess.stat_attrs_mean.pdf"), A)
|
|
33
|
+
ggsave(file.path(output_dir, "postprocess.stat_attrs_min.pdf"), B)
|
|
34
|
+
ggsave(file.path(output_dir, "postprocess.stat_attrs_var.pdf"), C)
|
|
35
|
+
ggsave(file.path(output_dir, "postprocess.stat_attrs_uni.pdf"), D)
|
|
36
|
+
} else {
|
|
37
|
+
combined_plot <- A + B + C + D +
|
|
38
|
+
plot_layout(
|
|
39
|
+
guides = "collect",
|
|
40
|
+
ncol = 2, # 2列
|
|
41
|
+
nrow = 2, # 2行
|
|
42
|
+
widths = c(1, 1), # 第一列宽度为第二列的两倍
|
|
43
|
+
heights = c(1, 1)
|
|
44
|
+
) +
|
|
45
|
+
theme(legend.position = "bottom")
|
|
46
|
+
ggsave(file.path(output_dir, "pgap2.postprocess_stat.pdf"), combined_plot, width = 8.6, height = 7.4)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
draw_stat_attr <- function(stat_attrs_data, attr, xlab_name) {
|
|
51
|
+
if (attr == "mean" || attr == "min") {
|
|
52
|
+
left_position <- 0.15
|
|
53
|
+
} else {
|
|
54
|
+
left_position <- 0.85
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
attr_plot <- ggline(subset(stat_attrs_data, Attr == attr),
|
|
59
|
+
x = "Edge", y = "Prop",
|
|
60
|
+
color = "Group", scales = "free", size = 1,
|
|
61
|
+
xlab = xlab_name, ylab = "Gene Cluster Proportion",
|
|
62
|
+
palette = c("#B8DBB3", "#72B063", "#719AAC", "#E29135", "#94C6CD")
|
|
63
|
+
) +
|
|
64
|
+
scale_y_log10() +
|
|
65
|
+
theme(
|
|
66
|
+
axis.text.x = element_text(angle = 45, hjust = 1),
|
|
67
|
+
axis.line = element_line(linewidth = 0),
|
|
68
|
+
panel.background = element_blank(),
|
|
69
|
+
panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5), # 添加边框
|
|
70
|
+
panel.grid = element_blank(), # 去除网格线
|
|
71
|
+
plot.margin = margin(10, 10, 10, 10), # 增加图形的外边距,防止文字被裁剪
|
|
72
|
+
legend.box = "vertical", # 使图例在框内水平排列
|
|
73
|
+
legend.position = c(left_position, 0.85),
|
|
74
|
+
legend.background = element_blank(),
|
|
75
|
+
legend.direction = "vertical",
|
|
76
|
+
legend.key.size = unit(0.5, "cm"), # 控制图例块的大小
|
|
77
|
+
legend.title = element_text(size = 10), # 设置图例标题字体大小
|
|
78
|
+
legend.text = element_text(size = 8)
|
|
79
|
+
) +
|
|
80
|
+
guides(color = guide_legend(override.aes = list(alpha = 1))) + ggtitle(toupper(attr))
|
|
81
|
+
|
|
82
|
+
return(attr_plot)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
stat_attrs_data <- stat_attrs_data %>%
|
|
87
|
+
group_by(Attr, Group) %>% # 按 Attr 分组
|
|
88
|
+
mutate(Prop = Count / sum(Count)) %>% # 计算每行的 Prop 值
|
|
89
|
+
ungroup() # 取消分组
|
|
90
|
+
stat_attrs_data$Group <- factor(stat_attrs_data$Group, levels = c("Strict_core", "Core", "Soft_core", "Shell", "Cloud"))
|
|
91
|
+
|
|
92
|
+
A <- draw_stat_attr(stat_attrs_data, "mean", xlab_name = "Gene Identity")
|
|
93
|
+
B <- draw_stat_attr(stat_attrs_data, "min", xlab_name = "Gene Identity")
|
|
94
|
+
C <- draw_stat_attr(stat_attrs_data, "var", xlab_name = "Gene Cluster Variance")
|
|
95
|
+
D <- draw_stat_attr(stat_attrs_data, "uni", xlab_name = "Gene Identity")
|
|
96
|
+
|
|
97
|
+
save_basic_plots(A, B, C, D, opt$single_file, opt$output_dir)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env Rscript
|
|
2
|
+
|
|
3
|
+
library(ggpubr)
|
|
4
|
+
library(ggrepel)
|
|
5
|
+
|
|
6
|
+
library(dplyr)
|
|
7
|
+
library(tidyr)
|
|
8
|
+
library(optparse)
|
|
9
|
+
library(patchwork)
|
|
10
|
+
|
|
11
|
+
# 设置命令行参数解析
|
|
12
|
+
option_list <- list(
|
|
13
|
+
make_option(c("-a", "--stat_attrs"), type = "character", help = "preprocess.stat.tsv"),
|
|
14
|
+
make_option(c("-b", "--gene_code"), type = "character", help = "preprocess.gene_code.csv"),
|
|
15
|
+
make_option(c("-c", "--ani_thre"), type = "character", help = "ANI threshold"),
|
|
16
|
+
make_option(c("-s", "--single_file"), action = "store_true", default = FALSE, help = "Generate each plot to the single file"),
|
|
17
|
+
make_option(c("-o", "--output_dir"), type = "character", help = "Output directory")
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# 解析命令行参数
|
|
21
|
+
opt_parser <- OptionParser(option_list = option_list)
|
|
22
|
+
opt <- parse_args(opt_parser)
|
|
23
|
+
|
|
24
|
+
# 创建输出目录
|
|
25
|
+
if (!dir.exists(opt$output_dir)) {
|
|
26
|
+
dir.create(opt$output_dir)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
input_prep <- read.csv(opt$stat_attrs, header = TRUE, sep = "\t")
|
|
30
|
+
input_code <- read.csv(opt$gene_code, header = TRUE, sep = ",", row.names = 1)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#-----------------------------------------------------------------------------#
|
|
34
|
+
# 保存图形
|
|
35
|
+
|
|
36
|
+
save_basic_plots <- function(A, B, C, D, E, single_file, output_dir) {
|
|
37
|
+
if (single_file) {
|
|
38
|
+
ggsave(file.path(output_dir, "preprocess.ANI.pdf"), A)
|
|
39
|
+
ggsave(file.path(output_dir, "preprocess.gene_number.pdf"), B)
|
|
40
|
+
ggsave(file.path(output_dir, "preprocess.half_core.pdf"), C)
|
|
41
|
+
ggsave(file.path(output_dir, "preprocess.proportion.pdf"), D)
|
|
42
|
+
ggsave(file.path(output_dir, "preprocess.gene_code.pdf"), E)
|
|
43
|
+
} else {
|
|
44
|
+
p1 <- A + ggtitle("A") +
|
|
45
|
+
B + ggtitle("B") +
|
|
46
|
+
C + ggtitle("C") +
|
|
47
|
+
plot_layout(guides = "collect", ncol = 3)
|
|
48
|
+
p2 <- D + ggtitle("D") +
|
|
49
|
+
E + ggtitle("E") +
|
|
50
|
+
plot_layout(guides = "collect", ncol = 2) & # 合并图例
|
|
51
|
+
theme(legend.position = "right")
|
|
52
|
+
combined_plot <- p1 / p2 + plot_layout(heights = c(1, 2))
|
|
53
|
+
ggsave(file.path(output_dir, "pgap2.preprocess.pdf"), combined_plot, width = 9.8, height = 8.4)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
draw_ani <- function(input_prep, ani_thre) {
|
|
58
|
+
p <- ggviolin(input_prep,
|
|
59
|
+
y = "ani", add = "jitter",
|
|
60
|
+
add.params = list(size = 3, color = "black", fill = "#B8DBB3", shape = 21),
|
|
61
|
+
xlab = "Genome", ylab = "ANI"
|
|
62
|
+
) +
|
|
63
|
+
geom_hline(yintercept = ani_thre, linetype = "dotted", col = "red") +
|
|
64
|
+
theme(legend.position = "none") +
|
|
65
|
+
scale_x_discrete(labels = c("")) +
|
|
66
|
+
# 使用 geom_text_repel() 添加标签和箭头
|
|
67
|
+
geom_text_repel(
|
|
68
|
+
data = subset(input_prep, ani == 100 | is_outlier_ani == 1), # 筛选满足条件的数据
|
|
69
|
+
aes(x = as.factor(1), y = ani, label = strain), # 标签位置与数据
|
|
70
|
+
arrow = arrow(type = "closed", length = unit(0.1, "inches")), # 添加箭头
|
|
71
|
+
vjust = -0.5, size = 3, color = "black", # 标签和箭头的样式
|
|
72
|
+
box.padding = 0.2, min.segment.length = 1 # 调整标签与点的间距
|
|
73
|
+
)
|
|
74
|
+
return(p)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
draw_gene_number <- function(input_prep) {
|
|
78
|
+
p <- ggviolin(input_prep,
|
|
79
|
+
y = "total_gene_num", add = "jitter", xlab = "Genome", ylab = "Number of genes",
|
|
80
|
+
add.params = list(size = 3, color = "black", fill = "#B8DBB3", shape = 21)
|
|
81
|
+
) + theme(legend.position = "None") + scale_x_discrete(labels = c(""))
|
|
82
|
+
return(p)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
draw_half_core <- function(input_prep) {
|
|
86
|
+
p <- ggscatter(input_prep,
|
|
87
|
+
x = "half_core", y = "single_cloud",
|
|
88
|
+
size = "total_gene_num", color = "total_gene_num", xlab = "Half core", ylab = "Single cloud"
|
|
89
|
+
) +
|
|
90
|
+
guides(size = "none", color = guide_colorbar(barheight = 5)) +
|
|
91
|
+
scale_color_gradient(high = "#990033", low = "white") +
|
|
92
|
+
theme(legend.position = "right") +
|
|
93
|
+
labs(color = "Count")
|
|
94
|
+
return(p)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
draw_proportion <- function(input_prep) {
|
|
98
|
+
input_prep$others <- input_prep$total_gene_num - input_prep$half_core - input_prep$single_cloud
|
|
99
|
+
used_prep <- input_prep %>% select(strain, total_gene_num, half_core, single_cloud, others)
|
|
100
|
+
# Transform the data into a long format
|
|
101
|
+
long_data <- used_prep %>%
|
|
102
|
+
pivot_longer(cols = c(half_core, single_cloud, others), names_to = "Category", values_to = "Count") %>%
|
|
103
|
+
mutate(
|
|
104
|
+
Category = factor(Category, levels = c("single_cloud", "others", "half_core")), # Reorder the categories
|
|
105
|
+
strain = factor(strain, levels = used_prep$strain)
|
|
106
|
+
) # Maintain the order of strains
|
|
107
|
+
|
|
108
|
+
p <- ggplot(long_data, aes(x = strain, y = Count, fill = Category)) +
|
|
109
|
+
geom_bar(position = "fill", stat = "identity") +
|
|
110
|
+
coord_flip() +
|
|
111
|
+
theme_minimal() +
|
|
112
|
+
labs(x = "Strains", y = "Proportion", fill = "Category") +
|
|
113
|
+
scale_fill_manual(values = c("single_cloud" = "#72B063", "others" = "#719AAC", "half_core" = "#E29135"), labels = c("Single", "Others", "Half")) +
|
|
114
|
+
scale_x_discrete(
|
|
115
|
+
breaks = function(x) {
|
|
116
|
+
y_levels <- levels(factor(long_data$strain))
|
|
117
|
+
# 如果类别数大于 20,选择均匀的 20 个类别
|
|
118
|
+
if (length(y_levels) > 25) {
|
|
119
|
+
return(y_levels[seq(1, length(y_levels), length.out = 25)]) # 选择 20 个类别
|
|
120
|
+
} else {
|
|
121
|
+
return(y_levels) # 如果类别少于 20 个,显示所有
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
return(p)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
draw_gene_code <- function(input_code) {
|
|
129
|
+
df <- as.data.frame(as.table(as.matrix(input_code)))
|
|
130
|
+
df <- df %>%
|
|
131
|
+
rename(Count = Freq)
|
|
132
|
+
df$Count <- as.numeric(as.character(df$Count))
|
|
133
|
+
p <- ggplot(df, aes(x = Var1, y = Var2, fill = Count)) +
|
|
134
|
+
geom_tile() +
|
|
135
|
+
scale_fill_gradient2(high = "#990033", low = "white") +
|
|
136
|
+
theme_bw() +
|
|
137
|
+
theme(panel.grid = element_blank(), axis.text.x = element_text(angle = 90, hjust = 0.5, vjust = 0.5), ) +
|
|
138
|
+
xlab("Start|Stop codon") +
|
|
139
|
+
ylab(NULL) +
|
|
140
|
+
scale_y_discrete(
|
|
141
|
+
breaks = function(x) {
|
|
142
|
+
# 获取 Var2 的所有类别
|
|
143
|
+
y_levels <- levels(factor(df$Var2))
|
|
144
|
+
if (length(y_levels) > 25) {
|
|
145
|
+
return(y_levels[seq(1, length(y_levels), length.out = 25)])
|
|
146
|
+
} else {
|
|
147
|
+
return(y_levels) # 如果类别少于 20 个,显示所有
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
return(p)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
A <- draw_ani(input_prep, as.numeric(opt$ani_thre))
|
|
155
|
+
B <- draw_gene_number(input_prep)
|
|
156
|
+
C <- draw_half_core(input_prep)
|
|
157
|
+
D <- draw_proportion(input_prep)
|
|
158
|
+
E <- draw_gene_code(input_code)
|
|
159
|
+
save_basic_plots(A, B, C, D, E, opt$single_file, opt$output_dir)
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Script by Jason Kwong & Torsten Seemann
|
|
3
|
+
# Script to mask recombination from CFML output and draw SVG of recombinant regions
|
|
4
|
+
|
|
5
|
+
# Usage
|
|
6
|
+
import argparse
|
|
7
|
+
from argparse import RawTextHelpFormatter
|
|
8
|
+
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
formatter_class=RawTextHelpFormatter,
|
|
11
|
+
description='Mask recombination from ClonalFrameML/Gubbins output and draw SVG of recombinant regions',
|
|
12
|
+
usage='\n %(prog)s --aln FASTA --out OUTFILE [--gubbins] <PREFIX>')
|
|
13
|
+
parser.add_argument('prefix', metavar='PREFIX', help='prefix used for CFML/Gubbins input files (required)')
|
|
14
|
+
parser.add_argument('--gubbins', action='store_true', help='parse as Gubbins instead of ClonalFrameML')
|
|
15
|
+
parser.add_argument('--aln', metavar='FASTA', required=True, help='multiFASTA alignment used as input for CFML (required)')
|
|
16
|
+
parser.add_argument('--out', metavar='OUTFILE', default='maskrc.aln', help='output file for masked alignment (default="maskrc.aln")')
|
|
17
|
+
parser.add_argument('--symbol', metavar='CHAR', default='?', help='symbol to use for masking (default="?")')
|
|
18
|
+
parser.add_argument('--regions', metavar='FILE', help='output recombinant regions to file')
|
|
19
|
+
parser.add_argument('--svg', metavar='FILE', help='draw SVG output of recombinant regions and save as specified file')
|
|
20
|
+
parser.add_argument('--svgsize', metavar='WIDExHIGH', default='800x600', help='specify width and height of SVG in pixels (default="800x600")')
|
|
21
|
+
parser.add_argument('--svgorder', metavar='FILE', help='specify file containing list of taxa (1 per line) in desired order')
|
|
22
|
+
parser.add_argument('--svgcolour', metavar='COLOUR', default='black', help='specify colour of recombination regions in HEX format (default=black)')
|
|
23
|
+
parser.add_argument('--consensus', action='store_true', help='add consensus row of recombination hotspots')
|
|
24
|
+
parser.add_argument('--version', action='version', version='%(prog)s 0.5')
|
|
25
|
+
|
|
26
|
+
args = parser.parse_args()
|
|
27
|
+
|
|
28
|
+
prefix = str(args.prefix)
|
|
29
|
+
treefn = prefix + ('.labelled_tree.newick', '.final_tree.tre')[args.gubbins]
|
|
30
|
+
coordfn = prefix + ('.importation_status.txt', '.recombination_predictions.gff')[args.gubbins]
|
|
31
|
+
|
|
32
|
+
import os
|
|
33
|
+
import sys
|
|
34
|
+
import csv
|
|
35
|
+
from collections import defaultdict
|
|
36
|
+
from ete3 import Tree
|
|
37
|
+
from Bio import SeqIO
|
|
38
|
+
from Bio.Seq import Seq
|
|
39
|
+
from Bio.Seq import MutableSeq
|
|
40
|
+
from Bio.SeqRecord import SeqRecord
|
|
41
|
+
import svgwrite
|
|
42
|
+
from BCBio import GFF
|
|
43
|
+
import pprint
|
|
44
|
+
|
|
45
|
+
# Functions
|
|
46
|
+
def msg(*args, **kwargs):
|
|
47
|
+
print(*args, file=sys.stderr, **kwargs)
|
|
48
|
+
|
|
49
|
+
def err(*args, **kwargs):
|
|
50
|
+
msg(*args, **kwargs)
|
|
51
|
+
sys.exit(1);
|
|
52
|
+
|
|
53
|
+
def check_file(f):
|
|
54
|
+
msg('Checking file: {}'.format(f))
|
|
55
|
+
if os.path.isfile(f) == False:
|
|
56
|
+
err('ERROR: Cannot find "{}". Check output files exist in this directory.'.format(f))
|
|
57
|
+
|
|
58
|
+
# Check input files (output from CFML)
|
|
59
|
+
check_file(treefn)
|
|
60
|
+
check_file(coordfn)
|
|
61
|
+
|
|
62
|
+
# Setup lists and dictionary
|
|
63
|
+
d = defaultdict(list)
|
|
64
|
+
seqLIST = []
|
|
65
|
+
leafLIST = []
|
|
66
|
+
t = Tree(treefn, format=1)
|
|
67
|
+
|
|
68
|
+
# Set taxa order for SVG
|
|
69
|
+
if args.svgorder:
|
|
70
|
+
msg('Setting taxa order using --svgorder {}'.format(args.svgorder));
|
|
71
|
+
with open(args.svgorder) as file:
|
|
72
|
+
for row in file:
|
|
73
|
+
leafLIST.append(row.rstrip())
|
|
74
|
+
else:
|
|
75
|
+
msg('Setting taxa order using leaves from: {}'.format(treefn));
|
|
76
|
+
for leaf in t:
|
|
77
|
+
leafLIST.append(leaf.name)
|
|
78
|
+
|
|
79
|
+
# gubbins GFF
|
|
80
|
+
# node="internal_13->2016-04538";neg_log_likelihood="3764.359443";taxa="2016-04538";snp_count="108";
|
|
81
|
+
# node="internal_ROOT->internal_10";neg_log_likelihood="47939.649932";taxa=" 2016-23066 2015-19014";snp_count="8";
|
|
82
|
+
# node="internal_15->internal_16";neg_log_likelihood="574.375212";taxa=" 2008-16004 2010-22387";snp_count="39";
|
|
83
|
+
# node="internal_15->internal_16";neg_log_likelihood="418.840895";taxa=" 2008-16004 2010-22387";snp_count="38";
|
|
84
|
+
# node="internal_12->internal_14";neg_log_likelihood="17258.115166";taxa=" 2012-21203 2008-20031 2008-16004 2010-22387";
|
|
85
|
+
|
|
86
|
+
# clonalframeml "BED"
|
|
87
|
+
#Node Beg End
|
|
88
|
+
#2016-11776 5624 6619
|
|
89
|
+
#2016-11776 10778 11326
|
|
90
|
+
#Reference 2489729 2490893
|
|
91
|
+
#NODE_10 1165936 1166465
|
|
92
|
+
|
|
93
|
+
# internal
|
|
94
|
+
# ['Reference', ['2434777', '2434933', 'ancestral']],
|
|
95
|
+
# ['2016-17702', ['2483546', '2485711', 'ancestral']],
|
|
96
|
+
# ['2016-17705', ['2483546', '2485711', 'ancestral']],
|
|
97
|
+
# ['2016-11776', ['2483546', '2485711', 'ancestral']],
|
|
98
|
+
# ['2016-11778', ['2483546', '2485711', 'ancestral']],
|
|
99
|
+
# ['2016-11777', ['2483546', '2485711', 'ancestral']],
|
|
100
|
+
# ['2016-17701', ['2483546', '2485711', 'ancestral']],
|
|
101
|
+
# ['Reference', ['2483546', '2485711', 'ancestral']]]
|
|
102
|
+
|
|
103
|
+
if args.gubbins:
|
|
104
|
+
msg('Parsing Gubbins file: {}'.format(coordfn))
|
|
105
|
+
with open(coordfn) as gff:
|
|
106
|
+
for rec in GFF.parse(gff):
|
|
107
|
+
for f in rec.features:
|
|
108
|
+
taxa = f.qualifiers['taxa'][0].strip().split()
|
|
109
|
+
state = ('ancestral', 'extant')[ len(taxa)==1 ]
|
|
110
|
+
for taxon in taxa:
|
|
111
|
+
# BCBio-GFF module parser seems to extract coordinate-1 for f.location.start
|
|
112
|
+
seqLIST.append( [ taxon, [ int(f.location.start)+1, int(f.location.end), state ] ] )
|
|
113
|
+
else:
|
|
114
|
+
msg('Parsing ClonalFrameML file: {}'.format(coordfn))
|
|
115
|
+
with open(coordfn) as csvfile:
|
|
116
|
+
RCseqs = csv.reader(csvfile, delimiter='\t')
|
|
117
|
+
next(csvfile)
|
|
118
|
+
for row in RCseqs:
|
|
119
|
+
seq = row[0]
|
|
120
|
+
RCstart = row[1]
|
|
121
|
+
RCstop = row[2]
|
|
122
|
+
node = t.search_nodes(name=seq)[0]
|
|
123
|
+
if node.is_leaf():
|
|
124
|
+
leaf_names = [node.name]
|
|
125
|
+
z = 'extant'
|
|
126
|
+
else:
|
|
127
|
+
leaves = node.get_leaves()
|
|
128
|
+
leaf_names = [leaf.name for leaf in leaves]
|
|
129
|
+
z = 'ancestral'
|
|
130
|
+
for l in leaf_names:
|
|
131
|
+
seqLIST.append([l, [RCstart, RCstop, z]])
|
|
132
|
+
|
|
133
|
+
# Build dictionary of recombinant regions
|
|
134
|
+
for k,v in seqLIST:
|
|
135
|
+
d[k].append(v)
|
|
136
|
+
|
|
137
|
+
# Mask recombination in sequences
|
|
138
|
+
seqALN = []
|
|
139
|
+
for record in SeqIO.parse(args.aln, 'fasta'):
|
|
140
|
+
msg('Reading {} ... '.format(record.id))
|
|
141
|
+
seqlen = len(record.seq)
|
|
142
|
+
regions = d.get(record.id, None)
|
|
143
|
+
newrec = MutableSeq(str(record.seq))
|
|
144
|
+
if regions:
|
|
145
|
+
for a in regions:
|
|
146
|
+
start = int(a[0]) - 1
|
|
147
|
+
end = int(a[1])
|
|
148
|
+
lenMASK = end - start
|
|
149
|
+
newrec[start:end] = (args.symbol)*lenMASK
|
|
150
|
+
seqALN.append(SeqRecord(Seq(str(newrec)), record.id, description=''))
|
|
151
|
+
|
|
152
|
+
# Write masked alignment to file
|
|
153
|
+
msg('Writing masked alignment to {} ... '.format(args.out))
|
|
154
|
+
SeqIO.write(seqALN, args.out, 'fasta')
|
|
155
|
+
|
|
156
|
+
# Write recombinant regions to file
|
|
157
|
+
if args.regions:
|
|
158
|
+
with open(args.regions, 'w') as csvfile:
|
|
159
|
+
csvwriter = csv.writer(csvfile, delimiter='\t')
|
|
160
|
+
for k,v in list(d.items()):
|
|
161
|
+
for b in v:
|
|
162
|
+
x = b[0]
|
|
163
|
+
y = b[1]
|
|
164
|
+
z = b[2]
|
|
165
|
+
csvwriter.writerow([k,x,y,z])
|
|
166
|
+
|
|
167
|
+
# Draw SVG
|
|
168
|
+
svgsize = args.svgsize.split('x',1)
|
|
169
|
+
width = int(svgsize[0])
|
|
170
|
+
height = int(svgsize[1])
|
|
171
|
+
numseqs = len(leafLIST)
|
|
172
|
+
h = height/float(numseqs)
|
|
173
|
+
s = width/float(int(seqlen))
|
|
174
|
+
fsize = int(h*0.9)
|
|
175
|
+
font = 'font-size:{}px; font-family:Arial'.format(fsize)
|
|
176
|
+
colour = args.svgcolour
|
|
177
|
+
main_colour = 'black'
|
|
178
|
+
ancestral_colour = '#A9A9A9'
|
|
179
|
+
interval = 500000 # Tick interval in bp
|
|
180
|
+
|
|
181
|
+
dwg = svgwrite.Drawing(args.svg)
|
|
182
|
+
|
|
183
|
+
def rect(x,p,w,colour): # Draw regions
|
|
184
|
+
dwg.add(dwg.rect(insert=((x*s)+5, (p*h)+5), size=(w, h*0.8), fill=colour))
|
|
185
|
+
if args.consensus:
|
|
186
|
+
dwg.add(dwg.rect(insert=((x*s)+5, 5), size=(w, h*0.8), fill=main_colour))
|
|
187
|
+
|
|
188
|
+
def label(n,p): # Sequence ID labels
|
|
189
|
+
dwg.add(dwg.text(n, insert=((seqlen*s)+15, (((p+1)*h)-(0.2*h))+5), fill=main_colour, style=font))
|
|
190
|
+
|
|
191
|
+
def ticks(q): # Draw tick marks
|
|
192
|
+
count = interval
|
|
193
|
+
while count < seqlen:
|
|
194
|
+
dwg.add(dwg.line((count*s,((q)*h)), (count*s,((q)*h)-3), stroke=main_colour))
|
|
195
|
+
dwg.add(dwg.text((count/1000000.0), insert=((count*s)-6, ((q)*h)+13), fill=main_colour, style=font))
|
|
196
|
+
count = count + interval
|
|
197
|
+
|
|
198
|
+
def box(width,h): # Box with 5px margin
|
|
199
|
+
dwg.add(dwg.line((0,0), ((width+10),0), stroke=main_colour))
|
|
200
|
+
dwg.add(dwg.line(((width+10),0), ((width+10),((p+1)*h)), stroke=main_colour))
|
|
201
|
+
dwg.add(dwg.line(((width+10),((p+1)*h)), (0,((p+1)*h)), stroke=main_colour))
|
|
202
|
+
dwg.add(dwg.line((0,((p+1)*h)), (0,0), stroke=main_colour))
|
|
203
|
+
|
|
204
|
+
# Draw recombinant regions and labels
|
|
205
|
+
if args.svg:
|
|
206
|
+
msg('Drawing SVG to {} ...'.format(args.svg))
|
|
207
|
+
if args.consensus:
|
|
208
|
+
p = 1
|
|
209
|
+
dwg.add(dwg.text('Consensus', insert=((seqlen*s)+15, (0.8*h)+5), fill=main_colour, style=font))
|
|
210
|
+
else:
|
|
211
|
+
p = 0
|
|
212
|
+
for seq in leafLIST:
|
|
213
|
+
v = d.get(seq, None)
|
|
214
|
+
if v:
|
|
215
|
+
for b in v:
|
|
216
|
+
x = int(b[0])
|
|
217
|
+
y = int(b[1])
|
|
218
|
+
z = b[2]
|
|
219
|
+
w = (y-x)*s
|
|
220
|
+
if w < 1:
|
|
221
|
+
w = 1
|
|
222
|
+
if z == 'extant':
|
|
223
|
+
rect(x,p,w,colour) # regions
|
|
224
|
+
elif z == 'ancestral':
|
|
225
|
+
rect(x,p,w,ancestral_colour)
|
|
226
|
+
label(seq,p) # labels
|
|
227
|
+
p = p+1
|
|
228
|
+
# Draw bounding box
|
|
229
|
+
box(width,h)
|
|
230
|
+
# Add tick marks
|
|
231
|
+
ticks(p+1)
|
|
232
|
+
dwg.save()
|
|
233
|
+
|
|
234
|
+
# Exit
|
|
235
|
+
msg('Done.')
|
|
236
|
+
sys.exit(0)
|