├── Figure
├── 1.jpg
├── 10.jpg
├── 11.jpg
├── 2-3.jpg
├── 2-5.jpg
├── 2.jpg
├── 2_2.jpg
├── 2_4.jpg
├── 2_6.jpg
├── 2_6_1.jpg
├── 2_6_2.jpg
├── 3.jpg
├── 4.jpg
├── 4_1.jpg
├── 4_2.jpg
├── 5.jpg
├── 5_new.jpg
├── 5_new_multi_xaxis.jpg
├── 6.jpg
├── 7.jpg
├── 8.jpg
├── 9.jpg
├── PN.jpg
├── PN_1.jpg
├── illumilla_60K.jpg
├── illumilla_60K_Qc.jpg
└── issue1.svg
├── R
└── CMplot.r
├── README.md
└── User Manual for CMplot.pdf
/Figure/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/1.jpg
--------------------------------------------------------------------------------
/Figure/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/10.jpg
--------------------------------------------------------------------------------
/Figure/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/11.jpg
--------------------------------------------------------------------------------
/Figure/2-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2-3.jpg
--------------------------------------------------------------------------------
/Figure/2-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2-5.jpg
--------------------------------------------------------------------------------
/Figure/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2.jpg
--------------------------------------------------------------------------------
/Figure/2_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2_2.jpg
--------------------------------------------------------------------------------
/Figure/2_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2_4.jpg
--------------------------------------------------------------------------------
/Figure/2_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2_6.jpg
--------------------------------------------------------------------------------
/Figure/2_6_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2_6_1.jpg
--------------------------------------------------------------------------------
/Figure/2_6_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/2_6_2.jpg
--------------------------------------------------------------------------------
/Figure/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/3.jpg
--------------------------------------------------------------------------------
/Figure/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/4.jpg
--------------------------------------------------------------------------------
/Figure/4_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/4_1.jpg
--------------------------------------------------------------------------------
/Figure/4_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/4_2.jpg
--------------------------------------------------------------------------------
/Figure/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/5.jpg
--------------------------------------------------------------------------------
/Figure/5_new.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/5_new.jpg
--------------------------------------------------------------------------------
/Figure/5_new_multi_xaxis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/5_new_multi_xaxis.jpg
--------------------------------------------------------------------------------
/Figure/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/6.jpg
--------------------------------------------------------------------------------
/Figure/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/7.jpg
--------------------------------------------------------------------------------
/Figure/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/8.jpg
--------------------------------------------------------------------------------
/Figure/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/9.jpg
--------------------------------------------------------------------------------
/Figure/PN.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/PN.jpg
--------------------------------------------------------------------------------
/Figure/PN_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/PN_1.jpg
--------------------------------------------------------------------------------
/Figure/illumilla_60K.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/illumilla_60K.jpg
--------------------------------------------------------------------------------
/Figure/illumilla_60K_Qc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinLiLin/CMplot/a8084aa1bc63d0a366300e61f3be3b79263a6de4/Figure/illumilla_60K_Qc.jpg
--------------------------------------------------------------------------------
/Figure/issue1.svg:
--------------------------------------------------------------------------------
1 |
2 |
89 |
--------------------------------------------------------------------------------
/R/CMplot.r:
--------------------------------------------------------------------------------
1 | CMplot <- function(
2 | Pmap,
3 | col=c("#4197d8", "#f8c120", "#413496", "#495226", "#d60b6f", "#e66519", "#d581b7", "#83d3ad", "#7c162c", "#26755d"),
4 | bin.size=1e6,
5 | bin.breaks=NULL,
6 | LOG10=TRUE,
7 | pch=19,
8 | type="p",
9 | band=1,
10 | H=1.5,
11 | ylim=NULL,
12 | axis.cex=1,
13 | axis.lwd=1.5,
14 | lab.cex=1.5,
15 | lab.font=2,
16 | plot.type=c("m","c","q","d"),
17 | multracks=FALSE,
18 | multracks.xaxis=FALSE,
19 | multraits=FALSE,
20 | points.alpha=100L,
21 | r=0.3,
22 | cex=c(0.5,1,1),
23 | outward=FALSE,
24 | ylab=expression(-log[10](italic(p))),
25 | ylab.pos=3,
26 | xticks.pos=1,
27 | mar=c(3,6,3,3),
28 | mar.between=0,
29 | threshold=NULL,
30 | threshold.col="red",
31 | threshold.lwd=1,
32 | threshold.lty=2,
33 | amplify= TRUE,
34 | signal.cex=1.5,
35 | signal.pch=19,
36 | signal.col=NULL,
37 | signal.line=2,
38 | highlight=NULL,
39 | highlight.cex=1,
40 | highlight.pch=19,
41 | highlight.type="p",
42 | highlight.col="red",
43 | highlight.text=NULL,
44 | highlight.text.col="black",
45 | highlight.text.cex=1,
46 | highlight.text.font=3,
47 | chr.labels=NULL,
48 | chr.border=FALSE,
49 | chr.labels.angle=0,
50 | chr.den.col="black",
51 | chr.pos.max=FALSE,
52 | cir.band=1,
53 | cir.chr=TRUE,
54 | cir.chr.h=1.5,
55 | cir.axis=TRUE,
56 | cir.axis.col="black",
57 | cir.axis.grid=TRUE,
58 | conf.int=TRUE,
59 | conf.int.col=NULL,
60 | file.output=TRUE,
61 | file.name=NULL,
62 | file=c("jpg","pdf","tiff","png"),
63 | dpi=300,
64 | height=NULL,
65 | width=NULL,
66 | main=NULL,
67 | main.cex=1.5,
68 | main.font=2,
69 | legend.ncol=NULL,
70 | legend.cex=1,
71 | legend.pos=c("left","middle","right","none"),
72 | box=FALSE,
73 | verbose=TRUE
74 | )
75 | {
76 |
77 | #plot a circle with a radius of r
78 | circle.plot <- function(myr,type="l",x=NULL,lty=1,lwd=1,col="black",add=TRUE,n.point=1000)
79 | {
80 | curve(sqrt(myr^2-x^2),xlim=c(-myr,myr),n=n.point,ylim=c(-myr,myr),type=type,lty=lty,col=col,lwd=lwd,add=add)
81 | curve(-sqrt(myr^2-x^2),xlim=c(-myr,myr),n=n.point,ylim=c(-myr,myr),type=type,lty=lty,col=col,lwd=lwd,add=TRUE)
82 | }
83 |
84 | highlight_text <- function(
85 | x,
86 | y,
87 | words=NULL,
88 | point.cex=1,
89 | text.cex=1,
90 | pch=19,
91 | type = "p",
92 | point.col = "red",
93 | text.col = "black",
94 | text.font=3,
95 | xlim=c(-Inf, Inf),
96 | ylim=c(-Inf, Inf)
97 | )
98 | {
99 | overlap <- function(x1, y1, sw1, sh1, boxes) {
100 | if (length(boxes) == 0) return(FALSE)
101 | for (i in c(1:length(boxes))) {
102 | bnds <- boxes[[i]]
103 | x2 <- bnds[1]
104 | y2 <- bnds[2]
105 | sw2 <- bnds[3]
106 | sh2 <- bnds[4]
107 |
108 | if (x1 < x2)
109 | overlap <- x1 + sw1 > x2
110 | else
111 | overlap <- x2 + sw2 > x1
112 |
113 | if (y1 < y2)
114 | overlap <- overlap && (y1 + sh1 > y2)
115 | else
116 | overlap <- overlap && (y2 + sh2 > y1)
117 |
118 | if (overlap) {
119 | return(TRUE)
120 | }
121 | }
122 | return(FALSE)
123 | }
124 |
125 | layout <- function(x, y, words, cex=1, xlim=c(-Inf, Inf), ylim=c(-Inf, Inf)) {
126 | sdx <- sd(x, na.rm=TRUE)
127 | sdy <- sd(y, na.rm=TRUE)
128 | if (sdx == 0) sdx <- 1
129 | if (sdy == 0) sdy <- 1
130 | boxes <- list()
131 | for(i in 1:length(words)){
132 | wid <- strwidth(words[i], cex=cex[i])
133 | ht <- strheight(words[i], cex=cex[i])
134 | if(i <= (length(words) / 2)){
135 | boxes[[length(boxes) + 1]] <- c(x[i]-0.5*wid, y[i]-0.5*ht, wid, ht)
136 | }else{
137 | xupdt <- xrot <- x[i]
138 | yupdt <- yrot <- y[i]
139 | r <- 0
140 | theta <- runif(1, 0, 2 * pi)
141 | ht <- 1.5 * ht
142 | isOverlaped <- TRUE
143 | while(isOverlaped){
144 | if(
145 | !overlap(xupdt-0.5*wid, yupdt-0.5*ht, wid, ht, boxes) &&
146 | (xupdt-0.5*wid) > xlim[1] &&
147 | (yupdt-0.5*ht) > ylim[1] &&
148 | (xupdt+0.5*wid) < xlim[2] &&
149 | (yupdt+0.5*ht) < ylim[2]
150 | ){
151 | boxes[[length(boxes) + 1]] <- c(xupdt-0.5*wid, yupdt-0.5*ht, wid, ht)
152 | isOverlaped <- FALSE
153 | }else{
154 | theta <- theta + 0.1
155 | r <- r + 0.001 / (2 * base::pi)
156 | xupdt <- xrot + 0.1 * sdx * r * cos(theta)
157 | yupdt <- yrot + sdy * r * sin(theta)
158 | }
159 | }
160 | }
161 | }
162 | result <- do.call(rbind, boxes)
163 | colnames(result) <- c("x", "y", "width", "ht")
164 | rownames(result) <- words
165 | result
166 | }
167 |
168 | if(!is.null(words)){
169 | if(length(x) != length(words)) stop("length of highlighted labels is not equal to the highlighted SNPs.")
170 | indx <- order(y, decreasing=TRUE)
171 | x <- x[indx]
172 | y <- y[indx]
173 | words <- words[indx]
174 | if(length(point.cex)!=1){if(length(point.cex)==length(x)){point.cex=point.cex[indx]}else{stop("unequal length of 'cex' for highlighted points.")}}else{point.cex=rep(point.cex,length(x))}
175 | if(length(pch)!=1){if(length(pch)==length(x)){pch=pch[indx]}else{stop("unequal length of 'pch' for highlighted points.")}}else{pch=rep(pch,length(x))}
176 | if(length(point.col)!=1){if(length(point.col)==length(x)){point.col=point.col[indx]}else{stop("unequal length of 'col' for highlighted points.")}}else{point.col=rep(point.col,length(x))}
177 | if(length(text.col)!=1){if(length(text.col)==length(x)){text.col=text.col[indx]}else{stop("unequal length of 'col' for highlighted text.")}}else{text.col=rep(text.col,length(x))}
178 | if(length(text.cex)!=1){if(length(text.cex)==length(x)){text.cex=text.cex[indx]}else{stop("unequal length of 'cex' for highlighted text.")}}else{text.cex=rep(text.cex,length(x))}
179 |
180 | words_ety <- words[words == "" | is.na(words)]
181 | if(length(words_ety)){
182 | logical_idx <- words == "" | is.na(words)
183 | if(type=="h"){
184 | points(x[logical_idx],y[logical_idx],pch=pch[logical_idx],type="h",col=point.col[logical_idx], lwd=point.cex[logical_idx]+1)
185 | points(x[logical_idx],y[logical_idx],pch=pch[logical_idx],type="p",col=point.col[logical_idx], cex=point.cex[logical_idx])
186 | }else if(type=="l"){
187 | segments(x[logical_idx], ylim[1], x[logical_idx], ylim[2], col=point.col[logical_idx], lwd=point.cex[logical_idx], lty=2)
188 | }else{
189 | points(x[logical_idx],y[logical_idx],pch=pch[logical_idx],type="p",col=point.col[logical_idx],cex=point.cex[logical_idx])
190 | }
191 | words <- words[!logical_idx]
192 | x <- x[!logical_idx]
193 | y <- y[!logical_idx]
194 | point.cex <- point.cex[!logical_idx]
195 | pch <- pch[!logical_idx]
196 | point.col <- point.col[!logical_idx]
197 | text.col <- text.col[!logical_idx]
198 | text.cex <- text.cex[!logical_idx]
199 | }
200 |
201 | x1 <- x
202 | y1 <- y
203 | xadj <- sample(c(1.5, 0, -0.5), size=length(x), rep=TRUE)
204 | # xadj <- rep(c(1.5, 0, -0.5), length=max(3, length(x)))
205 | # xadj <- sort(xadj)[1:length(x)]
206 | # xadj[order(x)] <- xadj
207 | yadj <- rep(c(1.5, 0, -0.5), length=max(3, length(x)))
208 | yadj <- sort(yadj)[1:length(x)]
209 | for(i in 1:length(x)){
210 | if(xadj[i] == 0){
211 | if(yadj[i] == -0.5){
212 | if((y[i] + 2*strheight(words[i],cex=text.cex)) > max(ylim)){
213 | y[i] = y[i] - 1.5*strheight(words[i],cex=text.cex)
214 | }else{
215 | y[i] = y[i] + 1.5*strheight(words[i],cex=text.cex)
216 | }
217 | }
218 | if(yadj[i] == 1.5) y[i] = y[i] - 1.5*strheight(words[i],cex=text.cex)
219 | }else{
220 | if(yadj[i] == -0.5){
221 | if((y[i] + 1.5*strheight(words[i],cex=text.cex)) > max(ylim)){
222 | y[i] = y[i] - strheight(words[i],cex=text.cex)
223 | }else{
224 | y[i] = y[i] + strheight(words[i],cex=text.cex)
225 | }
226 | }
227 | if(yadj[i] == -0.5) y[i] = y[i] + strheight(words[i],cex=text.cex)
228 | if(yadj[i] == 1.5) y[i] = y[i] - strheight(words[i],cex=text.cex)
229 | }
230 | if(xadj[i] == 1.5){
231 | if((x[i] - 1.2*strwidth(words[i],cex=text.cex)) < min(xlim)){
232 | x[i] = x[i] + 0.6*strwidth(words[i],cex=text.cex)
233 | }else{
234 | x[i] = x[i] - 0.6*strwidth(words[i],cex=text.cex)
235 | }
236 | }
237 | if(xadj[i] == -0.5){
238 | if((x[i] + 1.2*strwidth(words[i],cex=text.cex)) > max(xlim)){
239 | x[i] = x[i] - 0.6*strwidth(words[i],cex=text.cex)
240 | }else{
241 | x[i] = x[i] + 0.6*strwidth(words[i],cex=text.cex)
242 | }
243 | }
244 | }
245 |
246 | x <- c(x1,x)
247 | y <- c(y1,y)
248 | words <- c(rep("OO", length(words)), as.character(words))
249 | lay <- layout(x=x,y=y,words=words,cex=c(rep(text.cex[1],length(x1)),text.cex),xlim=xlim,ylim=ylim)
250 | n <- length(x1)
251 | indd <- (n+1):length(x)
252 | for(i in indd){
253 | xl <- lay[i,1]
254 | yl <- lay[i,2]
255 | w <- lay[i,3]
256 | h <- lay[i,4]
257 | nx <- xl + 0.5 * w
258 | ny <- yl + 0.5 * h
259 | if((nx + 0.5 * strwidth(words[i],cex=text.cex[i-n])) < x1[i-n]){
260 | nx=nx + 0.5 * strwidth(words[i],cex=text.cex[i-n])
261 | }else if((nx - 0.5 * strwidth(words[i],cex=text.cex[i-n])) > x1[i-n]){
262 | nx=nx - 0.5 * strwidth(words[i],cex=text.cex[i-n])
263 | }
264 | if((ny + strheight(words[i],cex=text.cex[i-n])) < y1[i-n]){
265 | ny=ny + 0.5 * strheight(words[i],cex=text.cex[i-n])
266 | }else if((ny - strheight(words[i],cex=text.cex[i-n])) > y1[i-n]){
267 | ny=ny - 0.5 * strheight(words[i],cex=text.cex[i-n])
268 | }
269 | # arrows(x1[i-n], y1[i-n], nx, ny, length=.08, angle=15, code=2, col="grey", lwd=2)
270 | segments(x1[i-n], y1[i-n], nx, ny, col="black", lwd=text.cex[i-n])
271 | }
272 | if(type=="h"){
273 | points(x1,y1,pch=pch,type="h",col=point.col, lwd=point.cex+1)
274 | points(x1,y1,pch=pch,type="p",col=point.col, cex=point.cex)
275 | }else if(type=="l"){
276 | segments(x1, ylim[1], x1, ylim[2], col=point.col, lwd=point.cex, lty=2)
277 | # points(x1,y1,pch=pch,type="p",col=point.col, cex=point.cex)
278 | }else{
279 | points(x1,y1,pch=pch,type=type,col=point.col,cex=point.cex)
280 | }
281 | text(lay[indd,1]+0.5*lay[indd,3],lay[indd,2]+0.5*lay[indd,4],words[indd],xpd=TRUE,cex=text.cex,col=text.col,font=text.font)
282 | }else{
283 | if(type=="h"){
284 | points(x,y,pch=pch,type="h",col=point.col, lwd=point.cex+1)
285 | points(x,y,pch=pch,type="p",col=point.col, cex=point.cex)
286 | }else if(type=="l"){
287 | segments(x, ylim[1], x, ylim[2], col=point.col, lwd=point.cex, lty=2)
288 | # points(x,y,pch=pch,type="p",col=point.col, cex=point.cex)
289 | }else{
290 | points(x,y,pch=pch,type=type,col=point.col,cex=point.cex)
291 | }
292 | }
293 | }
294 |
295 | max_ylim <- function(x){
296 | if(x == 0) return(x)
297 | if(abs(x) >= 1){
298 | return(ceiling(x))
299 | }else{
300 | if(x < 0){
301 | digit <- 10^(-ceiling(-log10(abs(x))))
302 | return(-(floor(abs(x) / digit - 1) * digit))
303 | }else{
304 | digit <- 10^(-ceiling(-log10(x)))
305 | return((floor(x / digit + 1) * digit))
306 | }
307 | }
308 | }
309 |
310 | min_ylim <- function(x){
311 | if(x == 0) return(x)
312 | if(abs(x) >= 1){
313 | return(floor(x))
314 | }else{
315 | if(x < 0){
316 | digit <- 10^(-ceiling(-log10(abs(x))))
317 | return(-(floor(abs(x) / digit + 1) * digit))
318 | }else{
319 | digit <- 10^(-ceiling(-log10(x)))
320 | return((floor(x / digit - 1) * digit))
321 | }
322 | }
323 | }
324 |
325 | min_no_na <- function(x){
326 | return(min(x, na.rm=TRUE))
327 | }
328 |
329 | max_no_na <- function(x){
330 | return(max(x, na.rm=TRUE))
331 | }
332 |
333 | # created by Haohao Zhang
334 | filter.points <- function(x, y, w, h, dpi, scale=1) {
335 | x <- ceiling((x - min(x, na.rm=TRUE)) / (max(x, na.rm=TRUE) - min(x, na.rm=TRUE)) * w * dpi / scale)
336 | y <- ceiling((y - min(y, na.rm=TRUE)) / (max(y, na.rm=TRUE) - min(y, na.rm=TRUE)) * h * dpi / scale)
337 | index <- !duplicated(cbind(x, y))
338 | }
339 |
340 | DensityPlot <- function(
341 | chr,
342 | pos,
343 | chr.orig.labels,
344 | col=c("darkgreen", "yellow", "red"),
345 | main=NULL,
346 | main.cex=1.2,
347 | main.font=2,
348 | chr.labels=NULL,
349 | chr.pos.max=FALSE,
350 | bin=1e6,
351 | bin.breaks=NULL,
352 | band=3,
353 | width=5,
354 | legend.cex=1,
355 | legend.y.intersp=1,
356 | legend.x.intersp=1,
357 | xticks.pos=1,
358 | plot=TRUE,
359 | dpi=NULL,
360 | wh=NULL,
361 | ht=NULL
362 | )
363 | {
364 | legend.min <- 1
365 | legend.max <- NULL
366 | if(is.null(legend.cex)) legend.cex = 1
367 | if(!is.null(bin.breaks)){
368 | bin.breaks <- sort(bin.breaks)
369 | if(sum(bin.breaks < 0)) stop("breaks should not contain a negative value.")
370 | if(bin.breaks[1]){
371 | legend.min <- bin.breaks[1]
372 | }else{
373 | bin.breaks <- bin.breaks[-1]
374 | }
375 | legend.max <- bin.breaks[length(bin.breaks)]
376 | }
377 | if(is.null(col) | length(col) == 1){col=c("darkgreen", "yellow", "red")}
378 | max.chr <- max(chr)
379 | chr.num <- unique(chr)
380 | chorm.maxlen <- max(pos)
381 | bp <- ifelse(chorm.maxlen < 1e3, 1, ifelse(chorm.maxlen < 1e6, 1e3, 1e6))
382 | bp_label <- ifelse(bp == 1, "bp", ifelse(bp == 1e3, "Kb", "Mb"))
383 | if(is.null(main)) main <- paste("The number of SNPs within ", bin / bp, bp_label, " window size", sep="")
384 | if(plot) plot(NULL, xlim=c(0, chorm.maxlen + chorm.maxlen/10), ylim=c(0, length(chr.num) * band + band), main=main, cex.main=main.cex, font.main=main.font, axes=FALSE, xlab="", ylab="", xaxs="i", yaxs="i")
385 | pos.x <- list()
386 | chr.pos.max.v <- NULL
387 | col.index <- list()
388 | maxbin.num <- NULL
389 | windinfo <- list()
390 | for(i in 1 : length(chr.num)){
391 | pos.x[[i]] <- pos[chr == chr.num[i]]
392 | maxposindx <- which.max(pos.x[[i]])
393 | max.pos <- pos.x[[i]][maxposindx]
394 | chr.pos.max.v <- c(chr.pos.max.v, max.pos)
395 | cut.breaks <- seq(0, max.pos, bin)
396 | cut.len <- length(cut.breaks)
397 | if(cut.breaks[length(cut.breaks)] < max.pos) cut.breaks <- c(cut.breaks, cut.breaks[length(cut.breaks)] + bin)
398 | if(chr.pos.max){
399 | pos.x[[i]] <- pos.x[[i]][-maxposindx]
400 | }
401 | if(cut.len <= 1){
402 | maxbin.num <- c(maxbin.num, length(pos.x[[i]]))
403 | col.index[[i]] <- rep(length(pos.x[[i]]), length(pos.x[[i]]))
404 | names(col.index[[i]]) <- 1
405 | }else{
406 | cut.r <- cut(pos.x[[i]], cut.breaks, labels=FALSE)
407 | eachbin.num <- table(cut.r)
408 | maxbin.num <- c(maxbin.num, max(eachbin.num))
409 | col.index[[i]] <- rep(eachbin.num, eachbin.num)
410 | }
411 | if(plot){
412 | windinfo <- c(windinfo, tapply(pos.x[[i]], as.numeric(names(col.index[[i]])), function(x){
413 | return(c(ifelse(!is.null(chr.labels), chr.labels[i], chr.orig.labels[i]),
414 | min(x),max(x),length(x)))})
415 | )
416 | }
417 | }
418 | if(plot){
419 | windinfo <- as.data.frame(do.call(rbind, windinfo))
420 | colnames(windinfo) <- c("Chr", "Start", "End", "Num")
421 | rownames(windinfo) <- NULL
422 | for(i in 2:ncol(windinfo)){windinfo[, i]<-as.numeric(windinfo[, i])}
423 | }
424 | Maxbin.num <- max(maxbin.num)
425 | maxbin.num <- Maxbin.num
426 | if(!is.null(legend.max)){
427 | maxbin.num <- legend.max
428 | }
429 | if(Maxbin.num < legend.min) stop("the maximum number of markers in windows is smaller than the lower boundary of breaks.")
430 | col=colorRampPalette(col)(maxbin.num - legend.min + 1)
431 | col.seg=NULL
432 | for(i in 1 : length(chr.num)){
433 | if(plot){
434 | polygon(c(0, 0, chr.pos.max.v[i], chr.pos.max.v[i]),
435 | c(-width/5 - band * (i - length(chr.num) - 1), width/5 - band * (i - length(chr.num) - 1),
436 | width/5 - band * (i - length(chr.num) - 1), -width/5 - band * (i - length(chr.num) - 1)), col="grey95", border="grey95")
437 | rect(xleft=0, ybottom = -width/5 - band * (i - length(chr.num) - 1), xright=chr.pos.max.v[i], ytop=width/5 - band * (i - length(chr.num) - 1), border="grey80")
438 | }
439 | if(!is.null(legend.max)){
440 | if(legend.max < Maxbin.num){
441 | col.index[[i]][col.index[[i]] > legend.max] <- legend.max
442 | }
443 | }
444 | col.index[[i]][col.index[[i]] < legend.min] <- legend.min
445 | if(!plot) col.seg <- c(col.seg, col[col.index[[i]] - legend.min + 1])
446 | if(!is.null(ht) && !is.null(wh) && !is.null(dpi)){
447 | is_visable <- filter.points(pos.x[[i]], -width/5 - band * (i - length(chr.num) - 1), wh * (max(pos.x[[i]])/chorm.maxlen), ht, dpi=dpi)
448 | if(plot) segments(pos.x[[i]][is_visable], -width/5 - band * (i - length(chr.num) - 1), pos.x[[i]][is_visable], width/5 - band * (i - length(chr.num) - 1),
449 | col=col[col.index[[i]][is_visable] - legend.min + 1], lwd=1)
450 | }else{
451 | if(plot) segments(pos.x[[i]], -width/5 - band * (i - length(chr.num) - 1), pos.x[[i]], width/5 - band * (i - length(chr.num) - 1),
452 | col=col[col.index[[i]] - legend.min + 1], lwd=1)
453 | }
454 | }
455 |
456 | chr.num <- rev(chr.orig.labels)
457 | if(plot){
458 | if(!is.null(chr.labels)){
459 | mtext(at=seq(band, length(chr.num) * band, band), text=chr.labels, side=2, las=2, font=1, cex=axis.cex*0.6, line=0.2, xpd=TRUE)
460 | }else{
461 | if(max.chr == 0) mtext(at=seq(band, length(chr.num) * band, band), text=chr.num, side=2, las=2, font=1, cex=axis.cex*0.6, line=0.2, xpd=TRUE)
462 | if(max.chr != 0) mtext(at=seq(band, length(chr.num) * band, band), text=paste("Chr", chr.num, sep=""), side=2, las=2, font=1, cex=axis.cex*0.6, line=0.2, xpd=TRUE)
463 | }
464 | }
465 | if(plot){
466 | xticks=seq(0, chorm.maxlen / bp, length=10)
467 |
468 | if(round(xticks[2]) <= 10){
469 | xticks=seq(0, chorm.maxlen / bp, round(xticks[2], 1))
470 | }else{
471 | xticks=seq(0, chorm.maxlen / bp, round(xticks[2]))
472 | }
473 |
474 | if((chorm.maxlen/bp - max(xticks)) > 0.5*xticks[2]){
475 | xticks=c(xticks, round(chorm.maxlen / bp))
476 | }
477 | axis(3, mgp=c(3,xticks.pos,0), at=xticks*bp, labels=paste(xticks, bp_label, sep=""), font=1, cex.axis=axis.cex*0.8, tck=0.01, lwd=axis.lwd, padj=1.2)
478 | axis(3, at=c(0, chorm.maxlen), labels=c("",""), tcl=0, lwd=axis.lwd)
479 | }
480 |
481 | if(is.null(bin.breaks)){
482 | legend.len <- 10
483 | if(maxbin.num <= legend.len) legend.len <- maxbin.num
484 | legend.y <- round(seq(0, maxbin.num, length=legend.len + 1))
485 | legend.y <- unique(legend.y)
486 | len <- ifelse(length(legend.y)==1, 1, legend.y[2])
487 | legend.y <- seq(legend.y[2], maxbin.num, len)
488 | }else{
489 | legend.y <- bin.breaks
490 | }
491 |
492 | if(!is.null(bin.breaks)){
493 | if(legend.max < Maxbin.num){
494 | legend.y[length(legend.y)] <- paste(">=", maxbin.num, sep="")
495 | legend.y.col <- c(legend.y[c(-length(legend.y))], maxbin.num)
496 | }else{
497 | legend.y.col <- legend.y
498 | }
499 | }else{
500 | legend.y.col <- legend.y
501 | }
502 | if(legend.min != 1){
503 | legend.y[1] <- paste("<=", legend.min, sep="")
504 | }
505 | legend.y <- c("0", legend.y)
506 | legend.y.col <- as.numeric(legend.y.col)
507 | legend.col <- c("grey95", col[legend.y.col - legend.min + 1])
508 | if(plot){
509 | legend(x=(chorm.maxlen + chorm.maxlen/50), y=(-width/2.5 + band), title="", legend=legend.y, pch=15, pt.cex=legend.cex*3, col=legend.col,
510 | cex=legend.cex, bty="n", y.intersp=legend.y.intersp, x.intersp=legend.x.intersp, yjust=0, xjust=0, xpd=TRUE)
511 | return(windinfo)
512 | }else{
513 | return(list(den.col=col.seg, legend.col=legend.col, legend.y=legend.y))
514 | }
515 | }
516 |
517 | if(!all(plot.type %in% c("c","m","q","d"))) stop("unknown 'plot.type'.")
518 | legend.pos <- match.arg(legend.pos)
519 | file <- match.arg(file)
520 | trait <- colnames(Pmap)[-c(1:3)]
521 | if(length(trait) == 0) trait <- paste("Trait", 1:(ncol(Pmap)-3), sep="")
522 | taxa <- paste(trait, collapse="_")
523 |
524 | if(length(points.alpha) != 1L) stop("invalid 'points.alpha': must be 'TRUE', 'FALSE' or an integer between 0 and 255")
525 | if(is.logical(points.alpha)) points.alpha <- ifelse(points.alpha, formals()$points.alpha, 255L)
526 | if(!is.integer(points.alpha)){
527 | if(is.numeric(points.alpha) && points.alpha == as.integer(points.alpha)) points.alpha <- as.integer(points.alpha)
528 | else stop("invalid 'points.alpha': must an integer between")
529 | }
530 | if(!is.integer(points.alpha)) stop("invalid 'points.alpha': must an integer between")
531 | if(points.alpha < 0L || points.alpha > 255L) stop("out-of range 'points.alpha': must be between 0 and 255")
532 |
533 | #get the number of traits
534 | R=ncol(Pmap)-3
535 |
536 | #remove illegal SNPs
537 | suppressWarnings(Pmap <- Pmap[Pmap[, 2] != "0", ])
538 | Pmap <- as.matrix(Pmap)
539 | Pmap <- Pmap[!is.na(Pmap[, 2]), ]
540 | suppressWarnings(Pmap <- Pmap[!is.na(as.numeric(Pmap[, 3])), ])
541 |
542 | #replace the non-euchromosome
543 | suppressWarnings(numeric.chr <- as.numeric(Pmap[, 2]))
544 | suppressWarnings(max.chr <- max(numeric.chr, na.rm=TRUE))
545 | if(is.infinite(max.chr)) max.chr <- 0
546 | suppressWarnings(map.xy.index <- which(!numeric.chr %in% c(0:max.chr)))
547 | if(length(map.xy.index) != 0){
548 | chr.xy <- unique(Pmap[map.xy.index, 2])
549 | for(i in 1:length(chr.xy)){
550 | Pmap[Pmap[, 2] == chr.xy[i], 2] <- max.chr + i
551 | }
552 | }
553 | SNP_id <- Pmap[,1]
554 |
555 | #delete the column of SNPs names
556 | Pmap <- Pmap[, -1]
557 | Pmap <- apply(Pmap, 2, as.numeric)
558 | order_index <- order(Pmap[, 1], Pmap[,2])
559 |
560 | #order the GWAS results by chromosome and position
561 | Pmap <- Pmap[order_index, ]
562 | SNP_id <- SNP_id[order_index]
563 |
564 | chr <- unique(Pmap[,1])
565 | chr.ori <- chr
566 | if(length(map.xy.index) != 0){
567 | for(i in 1:length(chr.xy)){
568 | chr.ori[chr.ori == max.chr + i] <- chr.xy[i]
569 | }
570 | }
571 |
572 | #SNP-Density plot
573 | wind_snp_num <- NULL
574 | if("d" %in% plot.type){
575 | if(verbose) cat(" Marker density plotting.\n")
576 | if(file.output){
577 | ht=ifelse(is.null(height), 6, height)
578 | wh=ifelse(is.null(width), 9, width)
579 | if(file=="jpg") jpeg(paste("Marker_Density.",ifelse(is.null(file.name),taxa,file.name[1]),".jpg",sep=""), width=wh*dpi,height=ht*dpi,res=dpi,quality=100)
580 | if(file=="pdf") pdf(paste("Marker_Density.",ifelse(is.null(file.name),taxa,file.name[1]),".pdf",sep=""), width=wh,height=ht)
581 | if(file=="tiff") tiff(paste("Marker_Density.",ifelse(is.null(file.name),taxa,file.name[1]),".tiff",sep=""), width=wh*dpi,height=ht*dpi,res=dpi)
582 | if(file=="png") png(paste("Marker_Density.",ifelse(is.null(file.name),taxa,file.name[1]),".png",sep=""), width=wh*dpi,height=ht*dpi,res=dpi,bg=NA)
583 | # par(xpd=TRUE)
584 | par(mar=c(mar[1]-2, mar[2]-1, mar[3]+1, mar[4]))
585 | }else{
586 | ht=ifelse(is.null(height), 6, height)
587 | wh=ifelse(is.null(width), 9, width)
588 | if(is.null(dev.list())) dev.new(width=wh,height=ht)
589 | # par(xpd=TRUE)
590 | }
591 | wind_snp_num <- DensityPlot(Pmap[, 1], Pmap[, 2], chr.ori, chr.pos.max=chr.pos.max, dpi=dpi, wh=wh, ht=ht, chr.labels=chr.labels, col=chr.den.col, bin=bin.size, bin.breaks=bin.breaks, main=main[1], main.cex=main.cex, main.font=main.font, legend.cex=legend.cex, xticks.pos=xticks.pos)
592 | if(file.output) dev.off()
593 | }
594 |
595 | if(length(plot.type) > 1 | (!"d" %in% plot.type)){
596 |
597 | #scale and adjust the parameters
598 | cir.chr.h <- cir.chr.h/5
599 | cir.band <- cir.band/5
600 | if(!is.null(threshold)){
601 | if(!is.list(threshold)){
602 | thresholdlist <- list()
603 | for(i in 1:R){
604 | thresholdlist[[i]] <- threshold
605 | }
606 | threshold <- thresholdlist
607 | }
608 |
609 | if(LOG10){
610 | if(sum(unlist(threshold) <= 0) != 0) stop("threshold must be greater than 0.")
611 | }
612 |
613 | threshold.col <- rep(threshold.col, max(sapply(threshold, length)))
614 | threshold.lwd <- rep(threshold.lwd, max(sapply(threshold, length)))
615 | threshold.lty <- rep(threshold.lty, max(sapply(threshold, length)))
616 | signal.col <- rep(signal.col, max(sapply(threshold, length)))
617 | signal.pch <- rep(signal.pch, max(sapply(threshold, length)))
618 | signal.cex <- rep(signal.cex, max(sapply(threshold, length)))
619 | }
620 | if(length(cex)!=3) cex <- rep(cex,3)
621 |
622 | if(!is.null(ylim)){
623 | if(!is.list(ylim)){
624 | if(R > 1) cat(" (warning: all phenotypes will use the same ylim.)\n")
625 | if(length(ylim)!=2) stop("ylim for each phenotype should be assigned two values.")
626 | if(ylim[2] <= ylim[1]) stop("second value should be larger than the first in ylim.")
627 | ylimlist <- list()
628 | for(i in 1:R){
629 | ylimlist[[i]] <- ylim
630 | }
631 | ylim <- ylimlist
632 | }else{
633 | if(length(ylim)!=R) stop("length of list of ylim should equal to the number of phenotype.")
634 | for(i in 1:R){
635 | if(length(ylim[[i]])!=2) stop("ylim for each phenotype should be assigned two values.")
636 | if(ylim[[i]][2] <= ylim[[i]][1]) stop("second value should be larger than the first in ylim.")
637 | }
638 | }
639 | }
640 |
641 | if(!is.null(conf.int.col)) conf.int.col <- rep(conf.int.col, R)
642 | if(!is.null(main)) main <- rep(main, R)
643 | if(length(mar) != 4) stop("length of 'mar' shoud equal to 4.")
644 | if(chr.labels.angle > 90 | chr.labels.angle < -90) stop("'chr.labels.angle' should be > -90 and < 90.")
645 | pch=rep(pch, R)
646 |
647 | if(!is.null(highlight)){
648 | highlight_index <- list()
649 | highlight_col <- list()
650 | if(is.list(highlight.col)){
651 | if(length(highlight.col) != R){stop("length of 'highlight.col' not equals to the number of traits.")}
652 | highlight_col=highlight.col
653 | }
654 | if(!is.list(highlight)){
655 | highlight <- list(highlight)
656 | for(i in 1:R){highlight[[i]] = highlight[[1]]}
657 | }else{
658 | if(length(highlight) != R){stop("length of 'highlight' not equals to the number of traits.")}
659 | }
660 | length(highlight_index) <- length(highlight)
661 | for(i in 1:length(highlight)){
662 | if(sum(!is.na(highlight[[i]])) == 0 | length(highlight[[i]]) == 0){
663 | highlight_index[[i]] <- NA
664 | highlight_col[[i]] <- NA
665 | }else{
666 | highlight[[i]] <- highlight[[i]][!is.na(highlight[[i]])]
667 | highlight_index[[i]] <- match(as.character(as.matrix(highlight[[i]])), SNP_id)
668 | if(all(is.na(highlight_index[[i]]))) stop("No shared SNPs between Pmap and highlight!")
669 | highlight_index[[i]] <- na.omit(highlight_index[[i]])
670 | if(!is.null(highlight.col) && !is.list(highlight.col)) highlight_col[[i]] <- highlight.col
671 | }
672 | }
673 | }
674 |
675 | if(!is.null(highlight.text)){
676 | if(!is.list(highlight.text)){
677 | highlight.text <- list(highlight.text)
678 | for(i in 1:R){highlight.text[[i]] = highlight.text[[1]]}
679 | }else{
680 | if(length(highlight.text) != R){stop("length of 'highlight.text' not equals to the number of traits.")}
681 | }
682 | }
683 |
684 | pvalueT <- as.matrix(Pmap[,-c(1:2)])
685 | pvalue.pos <- Pmap[, 2]
686 | pvalue.pos.list <- tapply(pvalue.pos, Pmap[, 1], list)
687 |
688 | #scale the space parameter between chromosomes
689 | if(!missing(band)){
690 | band <- floor(band*(sum(sapply(pvalue.pos.list, max)) - min(unlist(pvalue.pos.list)))/100)
691 | }else{
692 | band <- floor((sum(sapply(pvalue.pos.list, max)) - min(unlist(pvalue.pos.list)))/100)
693 | }
694 | if(band==0) band=100
695 |
696 | if(LOG10){
697 | if(sum(pvalueT <= 0, na.rm=TRUE) != 0 || sum(pvalueT > 1, na.rm=TRUE) != 0) stop("p values should be at range of (0, 1).")
698 | pvalueT[pvalueT <= 0] <- NA
699 | pvalueT[pvalueT > 1] <- NA
700 | }
701 | Pmap[,-c(1:2)] <- pvalueT
702 |
703 | #set the colors for the plot
704 | if(is.vector(col)){
705 | col <- matrix(col,R,length(col),byrow=TRUE)
706 | }
707 | if(is.matrix(col)){
708 | #try to transform the colors into matrix for all traits
709 | col <- matrix(as.vector(t(col)),R,dim(col)[2],byrow=TRUE)
710 | }
711 |
712 | Num <- as.numeric(table(Pmap[,1]))
713 | Nchr <- length(Num)
714 | N <- NULL
715 |
716 | #set the colors for each traits
717 | for(i in 1:R){
718 | colx <- col[i,]
719 | colx <- colx[!is.na(colx)]
720 | N[i] <- ceiling(Nchr/length(colx))
721 | }
722 |
723 | #insert the space into chromosomes and return the midpoint of each chromosome
724 | ticks <- NULL
725 | chr.border.pos <- NULL
726 | pvalue.posN <- NULL
727 | #pvalue <- pvalueT[,j]
728 | if(Nchr == 1){
729 | bp <- ifelse((max_no_na(pvalue.pos.list[[1]]) - min_no_na(pvalue.pos.list[[1]])) > 1000000, 1000000, 1000)
730 | bp_lab <- ifelse(bp == 1000000, " (Mb)", " (Kb)")
731 | pvalue.posN <- pvalue.pos.list[[1]] + band
732 | ticks <- seq(min_no_na(pvalue.pos.list[[1]]), max_no_na(pvalue.pos.list[[1]]), length=10)
733 | ticks <- seq(round(min_no_na(pvalue.pos.list[[1]]) / bp), round(max_no_na(pvalue.pos.list[[1]]) / bp), round((ticks[2]-ticks[1])/bp) + 0.5)
734 | if(!round(max_no_na(pvalue.pos.list[[1]]) / bp) %in% ticks){
735 | if(round(max_no_na(pvalue.pos.list[[1]]) / bp) - ticks[length(ticks)] > 0.5 * ticks[2])
736 | ticks <- c(ticks, round(max_no_na(pvalue.pos.list[[1]]) / bp))
737 | }
738 | ticks <- ticks[-1]
739 | chr.labels <- ticks
740 | ticks <- ticks * bp + band
741 | chr.border <- FALSE
742 | }else{
743 | for(i in 0:(Nchr-1)){
744 | if (i==0){
745 | #pvalue <- append(pvalue,rep(Inf,band),after=0)
746 | pvalue.posN <- pvalue.pos.list[[i+1]] + band
747 | ticks[i+1] <- floor((max_no_na(pvalue.posN)+min_no_na(pvalue.pos.list[[i+1]])+band)/2)
748 | chr.border.pos[i+1] <- max_no_na(pvalue.posN) + 0.5 * band
749 | }else{
750 | #pvalue <- append(pvalue,rep(Inf,band),after=sum(Num[1:i])+i*band)
751 | pvalue.posN <- c(pvalue.posN, max_no_na(pvalue.posN) + band + pvalue.pos.list[[i+1]])
752 | ticks[i+1] <- max_no_na(pvalue.posN)-floor(max_no_na(pvalue.pos.list[[i+1]])/2)
753 | chr.border.pos[i+1] <- max_no_na(pvalue.posN) + 0.5 * band
754 | }
755 | }
756 | chr.border.pos=chr.border.pos[-length(chr.border.pos)]
757 | }
758 |
759 | if(!is.null(chr.labels) & Nchr != 1){
760 | chr.labels <- as.character(chr.labels)
761 | if(length(chr.labels) != Nchr) stop("length of 'chr.labels' should equal to the number of chromosomes.")
762 | ticks.logi <- rep(TRUE, length(ticks))
763 | for(ti in 1:Nchr){
764 | if(is.na(chr.labels[ti])) ticks.logi[ti] <- FALSE
765 | }
766 | if(!all(ticks.logi)){
767 | chr.labels <- chr.labels[ticks.logi]
768 | ticks <- ticks[ticks.logi]
769 | }
770 | }
771 |
772 | pvalue.posN.list <- tapply(pvalue.posN, Pmap[, 1], list)
773 |
774 | #merge the pvalues of traits by column
775 | if(LOG10){
776 | logpvalueT <- -log10(pvalueT)
777 | }else{
778 | logpvalueT <- pvalueT
779 | }
780 |
781 | add <- list()
782 | for(i in 1:R){
783 | colx <- col[i,]
784 | colx <- colx[!is.na(colx)]
785 | add[[i]] <- c(Num,rep(0,N[i]*length(colx)-Nchr))
786 | }
787 |
788 | circleMin <- (min_no_na(pvalue.posN) - band - 1)
789 | TotalN <- max_no_na(pvalue.posN)-circleMin
790 |
791 | if(length(chr.den.col) > 1){
792 | cir.density=TRUE
793 | den.fold <- 20
794 | density.list <- DensityPlot(Pmap[, 1], Pmap[, 2], chr.ori, chr.pos.max=FALSE, col=chr.den.col, plot=FALSE, bin=bin.size, bin.breaks=bin.breaks)
795 | }else{
796 | cir.density=FALSE
797 | }
798 | }
799 |
800 | #plot circle Manhattan
801 | if("c" %in% plot.type){
802 |
803 | signal.line.index <- NULL
804 | if(!is.null(threshold)){
805 | if(!is.null(signal.line)){
806 | for(l in 1:R){
807 | if(!is.null(threshold[[l]])){
808 | if(LOG10){
809 | signal.line.index <- c(signal.line.index,which(pvalueT[,l] < min_no_na(threshold[[l]])))
810 | }else{
811 | signal.line.index <- c(signal.line.index,which(pvalueT[,l] > max_no_na(threshold[[l]])))
812 | }
813 | }
814 | }
815 | signal.line.index <- unique(signal.line.index)
816 | }
817 | signal.line.index <- pvalue.posN[signal.line.index]
818 | }
819 |
820 | if(file.output){
821 | ht=ifelse(is.null(height), 10, height)
822 | wh=ifelse(is.null(width), 10, width)
823 | if(file=="jpg") jpeg(paste("Cir_Manhtn.",ifelse(is.null(file.name),taxa,file.name[1]),".jpg",sep=""), width=wh*dpi,height=ht*dpi,res=dpi,quality=100)
824 | if(file=="pdf") pdf(paste("Cir_Manhtn.",ifelse(is.null(file.name),taxa,file.name[1]),".pdf",sep=""), width=wh,height=ht)
825 | if(file=="tiff") tiff(paste("Cir_Manhtn.",ifelse(is.null(file.name),taxa,file.name[1]),".tiff",sep=""), width=wh*dpi,height=ht*dpi,res=dpi)
826 | if(file=="png") png(paste("Cir_Manhtn.",ifelse(is.null(file.name),taxa,file.name[1]),".png",sep=""), width=wh*dpi,height=ht*dpi,res=dpi,bg=NA)
827 | par(pty="s", xpd=TRUE, mar=c(1,1,1,1))
828 | }
829 | if(!file.output){
830 | ht=ifelse(is.null(height), 10, height)
831 | wh=ifelse(is.null(width), 10, width)
832 | if(is.null(dev.list())) dev.new(width=wh, height=ht)
833 | par(pty="s", xpd=TRUE)
834 | }
835 | RR <- r+H*R+cir.band*R
836 | if(cir.density){
837 | plot(NULL,xlim=c(1.05*(-RR-4*cir.chr.h),1.1*(RR+4*cir.chr.h)),ylim=c(1.05*(-RR-4*cir.chr.h),1.1*(RR+4*cir.chr.h)),axes=FALSE,xlab="",ylab="")
838 | }else{
839 | plot(NULL,xlim=c(1.05*(-RR-4*cir.chr.h),1.05*(RR+4*cir.chr.h)),ylim=c(1.05*(-RR-4*cir.chr.h),1.05*(RR+4*cir.chr.h)),axes=FALSE,xlab="",ylab="")
840 | }
841 | if(!is.null(signal.line)){
842 | if(!is.null(signal.line.index)){
843 | X1chr <- (RR)*sin(2*base::pi*(signal.line.index-round(band/2)-circleMin)/TotalN)
844 | Y1chr <- (RR)*cos(2*base::pi*(signal.line.index-round(band/2)-circleMin)/TotalN)
845 | X2chr <- (r)*sin(2*base::pi*(signal.line.index-round(band/2)-circleMin)/TotalN)
846 | Y2chr <- (r)*cos(2*base::pi*(signal.line.index-round(band/2)-circleMin)/TotalN)
847 | segments(X1chr,Y1chr,X2chr,Y2chr,lty=2,lwd=signal.line,col="grey")
848 | }
849 | }
850 | for(i in 1:R){
851 |
852 | #get the colors for each trait
853 | colx <- col[i,]
854 | colx <- colx[!is.na(colx)]
855 |
856 | if(verbose) cat(paste(" Circular Manhattan plotting ",trait[i],".\n",sep=""))
857 | pvalue <- pvalueT[,i]
858 | logpvalue <- logpvalueT[,i]
859 | if(is.null(ylim)){
860 | if(LOG10){
861 | Max <- max_ylim(-log10(min_no_na(pvalue)))
862 | Min <- min_ylim(-log10(max_no_na(pvalue)))
863 | }else{
864 | Max <- max_ylim(max_no_na(pvalue))
865 | #if(abs(Max)<=1) Max <- max_no_na(pvalue)
866 | Min <- min_ylim(min_no_na(pvalue))
867 | #if(abs(Min)<=1) Min <- min_no_na(pvalue)
868 | }
869 | }else{
870 | Max <- ylim[[i]][2]
871 | Min <- ylim[[i]][1]
872 | }
873 | Cpvalue <- (H*(logpvalue-Min))/(Max-Min)
874 | ylimIndx <- logpvalue >= Min & logpvalue <= Max
875 | if(outward==TRUE){
876 | if(cir.chr==TRUE & i == 1){
877 |
878 | #plot the boundary which represents the chromosomes
879 | polygon.num <- 1000
880 | for(k in 1:length(chr)){
881 | if(k==1){
882 | polygon.index <- seq(round(band/2)+1,-round(band/2)-circleMin+max_no_na(pvalue.posN.list[[1]]), length=polygon.num)
883 | #change the axis from right angle into circle format
884 | X1chr=(RR)*sin(2*base::pi*(polygon.index)/TotalN)
885 | Y1chr=(RR)*cos(2*base::pi*(polygon.index)/TotalN)
886 | X2chr=(RR+cir.chr.h)*sin(2*base::pi*(polygon.index)/TotalN)
887 | Y2chr=(RR+cir.chr.h)*cos(2*base::pi*(polygon.index)/TotalN)
888 | if(is.null(chr.den.col)){
889 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col=rep(colx,ceiling(length(chr)/length(colx)))[k],border=rep(colx,ceiling(length(chr)/length(colx)))[k])
890 | }else{
891 | if(cir.density){
892 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col="grey",border="grey")
893 | }else{
894 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col=chr.den.col,border=chr.den.col)
895 | }
896 | }
897 | }else{
898 | polygon.index <- seq(1+round(band/2)+max_no_na(pvalue.posN.list[[k-1]])-circleMin,-round(band/2)-circleMin+max_no_na(pvalue.posN.list[[k]]), length=polygon.num)
899 | X1chr=(RR)*sin(2*base::pi*(polygon.index)/TotalN)
900 | Y1chr=(RR)*cos(2*base::pi*(polygon.index)/TotalN)
901 | X2chr=(RR+cir.chr.h)*sin(2*base::pi*(polygon.index)/TotalN)
902 | Y2chr=(RR+cir.chr.h)*cos(2*base::pi*(polygon.index)/TotalN)
903 | if(is.null(chr.den.col)){
904 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col=rep(colx,ceiling(length(chr)/length(colx)))[k],border=rep(colx,ceiling(length(chr)/length(colx)))[k])
905 | }else{
906 | if(cir.density){
907 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col="grey",border="grey")
908 | }else{
909 | polygon(c(rev(X1chr),X2chr),c(rev(Y1chr),Y2chr),col=chr.den.col,border=chr.den.col)
910 | }
911 | }
912 | }
913 | }
914 |
915 | if(cir.density){
916 |
917 | if(file.output){
918 | is_visable <- filter.points((RR+cir.chr.h)*sin(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN), (RR+cir.chr.h)*cos(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN), wh, ht, dpi=dpi)
919 | }else{
920 | is_visable <- rep(TRUE, length(pvalue.posN))
921 | }
922 | segments(
923 | (RR)*sin(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN)[is_visable],
924 | (RR)*cos(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN)[is_visable],
925 | (RR+cir.chr.h)*sin(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN)[is_visable],
926 | (RR+cir.chr.h)*cos(2*base::pi*(pvalue.posN-round(band/2)-circleMin)/TotalN)[is_visable],
927 | col=density.list$den.col[is_visable], lwd=0.5
928 | )
929 | legend(
930 | x=RR+4*cir.chr.h,
931 | y=(RR+4*cir.chr.h)/2,
932 | title="", legend=density.list$legend.y, pch=15, pt.cex=3, col=density.list$legend.col,
933 | cex=legend.cex, bty="n",
934 | y.intersp=1,
935 | x.intersp=1,
936 | yjust=0.3, xjust=0, xpd=TRUE
937 | )
938 |
939 | }
940 |
941 | # XLine=(RR+cir.chr.h)*sin(2*base::pi*(1:TotalN)/TotalN)
942 | # YLine=(RR+cir.chr.h)*cos(2*base::pi*(1:TotalN)/TotalN)
943 | # lines(XLine,YLine,lwd=1.5)
944 | if(cir.density){
945 | circle.plot(myr=RR+cir.chr.h,lwd=1.5,add=TRUE,col='grey')
946 | circle.plot(myr=RR,lwd=1.5,add=TRUE,col='grey')
947 | }else{
948 | circle.plot(myr=RR+cir.chr.h,lwd=1.5,add=TRUE)
949 | circle.plot(myr=RR,lwd=1.5,add=TRUE)
950 | }
951 |
952 | }
953 |
954 | X=(Cpvalue[ylimIndx]+r+H*(i-1)+cir.band*(i-1))*sin(2*base::pi*(pvalue.posN[ylimIndx]-round(band/2)-circleMin)/TotalN)
955 | Y=(Cpvalue[ylimIndx]+r+H*(i-1)+cir.band*(i-1))*cos(2*base::pi*(pvalue.posN[ylimIndx]-round(band/2)-circleMin)/TotalN)
956 | if(file.output){
957 | is_visable <- filter.points(X, Y, wh, ht, dpi=dpi)
958 | }else{
959 | is_visable <- rep(TRUE, length(X))
960 | }
961 |
962 | if(cir.axis && cir.axis.grid){
963 | circle.plot(myr=r+H*(i-1)+cir.band*(i-1),lwd=0.5,add=TRUE,col='grey')
964 | circle.plot(myr=r+H*(i-0.75)+cir.band*(i-1),lwd=0.5,add=TRUE,col='grey')
965 | circle.plot(myr=r+H*(i-0.5)+cir.band*(i-1),lwd=0.5,add=TRUE,col='grey')
966 | circle.plot(myr=r+H*(i-0.25)+cir.band*(i-1),lwd=0.5,add=TRUE,col='grey')
967 | circle.plot(myr=r+H*(i-0)+cir.band*(i-1),lwd=0.5,add=TRUE,col='grey')
968 | }
969 |
970 | points(X[is_visable],Y[is_visable],pch=19,cex=cex[1],col=rep(rep(colx,N[i]),add[[i]])[ylimIndx][is_visable])
971 |
972 | #plot the legend for each trait
973 | if(cir.axis==TRUE){
974 | #try to get the number after radix point
975 | if((Max-Min) > 1) {
976 | round.n=2
977 | }else{
978 | if(Max == 1){
979 | round.n=1
980 | }else{
981 | round.n=nchar(as.character(10^(-ceiling(-log10(Max)))))-1
982 | }
983 | }
984 | segments(0,r+H*(i-1)+cir.band*(i-1),0,r+H*i+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
985 | segments(0,r+H*(i-1)+cir.band*(i-1),H/20,r+H*(i-1)+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
986 | segments(0,r+H*(i-0.75)+cir.band*(i-1),H/20,r+H*(i-0.75)+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
987 | segments(0,r+H*(i-0.5)+cir.band*(i-1),H/20,r+H*(i-0.5)+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
988 | segments(0,r+H*(i-0.25)+cir.band*(i-1),H/20,r+H*(i-0.25)+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
989 | segments(0,r+H*(i-0)+cir.band*(i-1),H/20,r+H*(i-0)+cir.band*(i-1),col=cir.axis.col,lwd=axis.lwd)
990 |
991 | lab=seq(round(Min+(Max-Min)*0,round.n), round(Min+(Max-Min)*1,round.n), length=5)
992 | text(-H/20,r+H*(i-0.94)+cir.band*(i-1),lab[1],adj=1,col=cir.axis.col,cex=axis.cex*0.5,font=lab.font)
993 | text(-H/20,r+H*(i-0.75)+cir.band*(i-1),lab[2],adj=1,col=cir.axis.col,cex=axis.cex*0.5,font=lab.font)
994 | text(-H/20,r+H*(i-0.5)+cir.band*(i-1),lab[3],adj=1,col=cir.axis.col,cex=axis.cex*0.5,font=lab.font)
995 | text(-H/20,r+H*(i-0.25)+cir.band*(i-1),lab[4],adj=1,col=cir.axis.col,cex=axis.cex*0.5,font=lab.font)
996 | text(-H/20,r+H*(i-0.06)+cir.band*(i-1),lab[5],adj=1,col=cir.axis.col,cex=axis.cex*0.5,font=lab.font)
997 | }
998 |
999 | if(!is.null(threshold[[i]])){
1000 | if(sum(threshold[[i]]!=0)==length(threshold[[i]])){
1001 | for(thr in 1:length(threshold[[i]])){
1002 | significantline1=ifelse(LOG10, H*(-log10(threshold[[i]][thr])-Min)/(Max-Min), H*(threshold[[i]][thr]-Min)/(Max-Min))
1003 | #s1X=(significantline1+r+H*(i-1)+cir.band*(i-1))*sin(2*base::pi*(0:TotalN)/TotalN)
1004 | #s1Y=(significantline1+r+H*(i-1)+cir.band*(i-1))*cos(2*base::pi*(0:TotalN)/TotalN)
1005 | if(significantline1
94 |
95 |
113 |
114 |
131 |
132 |
151 |
152 |
170 |
171 |
191 |
192 |
8 |
21 |
22 | ### Installation
23 |
24 | **CMplot** is available on CRAN, so it can be installed with the following R code:
25 |
26 | ```r
27 | > install.packages("CMplot")
28 | > library("CMplot")
29 |
30 | # if you want to use the latest version on GitHub:
31 | > source("https://raw.githubusercontent.com/YinLiLin/CMplot/master/R/CMplot.r")
32 | ```
33 |
34 | ---
35 |
36 | There are two example datasets attached in **CMplot**, users can export and view the details by following R code:
37 |
38 | ```r
39 | > data(pig60K) #calculated p-values by MLM
40 | > data(cattle50K) #calculated SNP effects by rrblup
41 | > head(pig60K)
42 |
43 | SNP Chromosome Position trait1 trait2 trait3
44 | 1 ALGA0000009 1 52297 0.7738187 0.51194318 0.51194318
45 | 2 ALGA0000014 1 79763 0.7738187 0.51194318 0.51194318
46 | 3 ALGA0000021 1 209568 0.7583016 0.98405289 0.98405289
47 | 4 ALGA0000022 1 292758 0.7200305 0.48887140 0.48887140
48 | 5 ALGA0000046 1 747831 0.9736840 0.22096836 0.22096836
49 | 6 ALGA0000047 1 761957 0.9174565 0.05753712 0.05753712
50 |
51 | > head(cattle50K)
52 |
53 | SNP chr pos Somatic cell score Milk yield Fat percentage
54 | 1 SNP1 1 59082 0.000244361 0.000484255 0.001379210
55 | 2 SNP2 1 118164 0.000532272 0.000039800 0.000598951
56 | 3 SNP3 1 177246 0.001633058 0.000311645 0.000279427
57 | 4 SNP4 1 236328 0.001412865 0.000909370 0.001040161
58 | 5 SNP5 1 295410 0.000090700 0.002202973 0.000351394
59 | 6 SNP6 1 354493 0.000110681 0.000342628 0.000105792
60 |
61 | ```
62 | As the example datasets, the first three columns are names, chromosome, position of SNPs respectively, the rest of columns are the pvalues of GWAS or effects of GS/GP for traits, the number of traits is unlimited.
63 | Note: if plotting SNP_Density, only the first three columns are needed.
64 |
65 | Now **CMplot** could handle not only Genome-wide association study results, but also SNP effects, Fst, tajima's D and so on.
66 |
67 | ---
68 |
69 | Total 50~ parameters are available in **CMplot**, typing ```?CMplot``` can get the detail function of all parameters.
70 |
71 | ---
72 | ### Citation
73 | CMplot has been integrated into our developed GWAS package ```rMVP```, please cite the following paper:
74 | Yin, L. et al. [rMVP: A Memory-efficient, Visualization-enhanced, and Parallel-accelerated tool for Genome-Wide Association Study](https://doi.org/10.1016/j.gpb.2020.10.007), ***Genomics, Proteomics & Bioinformatics*** (2021), doi: 10.1016/j.gpb.2020.10.007.
75 |
76 | ---
77 | ### SNP-density plot
78 |
79 | ```r
80 | > CMplot(pig60K,plot.type="d",bin.size=1e6,chr.den.col=c("darkgreen", "yellow", "red"),file="jpg",file.name=NULL,dpi=300,
81 | main="illumilla_60K",file.output=TRUE,verbose=TRUE,width=9,height=6)
82 | # set the window size: bin.size=1e6
83 | # set the legend breaks by: bin.breaks=seq(min, max, step), e.g., bin.breaks=seq(0, 50, 10), the windows out of the breaks will be plotted in the same color as min or max.
84 | # get the detailed information of all windows: "windinfo <- CMplot(pig60K, plot.type="d", ...)"
85 | # file: the format of the output file, if file="png", CMplot will output a transparent background file
86 | # file.name: specify the output file name, the default is corresponding column name when setting file.name=NULL
87 | # chr.labels: change the chromosome names
88 | # main: change the title of the plots
89 | # NOTE: to show the full length of each chromosome, users can manually add every chromosome with one SNP, whose
90 | # position equals to the length of corresponding chromosome, then specify the parameter: CMplot(..., chr.pos.max=TRUE).
91 | ```
92 |
93 |
9 |
12 |
10 |
11 |
13 |
16 |
14 |
15 |
17 |
20 |
18 |
19 |
96 |
97 |
115 |
116 |
133 |
134 |
153 |
154 |
172 |
173 |
193 |
194 |
212 |
213 |
214 |
215 |
216 | #### Highlight a group of SNPs on pch, cex, type, and col
217 |
218 | ```r
219 | > signal <- pig60K$Position[which.min(pig60K$trait2)]
220 | > SNPs <- pig60K$SNP[pig60K$Chromosome==13 &
221 | pig60K$Position<(signal+1000000)&pig60K$Position>(signal-1000000)]
222 | > CMplot(pig60K, plot.type="m",LOG10=TRUE,col=c("grey30","grey60"),highlight=SNPs,
223 | highlight.col="green",highlight.cex=1,highlight.pch=19,file="jpg",file.name=NULL,
224 | chr.border=TRUE,dpi=300,file.output=TRUE,verbose=TRUE,width=14,height=6)
225 | # Note:
226 | # 'highlight' could be vector or list, if it is a vector, all traits will use the same highlighted SNPs index,
227 | # if it is a list, the length of the list should equal to the number of traits.
228 | # highlight.col, highlight.cex, highlight.pch can be value or vector, if its length equals to the length of highlighted SNPs,
229 | # each SNPs have its special colour, size and shape.
230 | ```
231 |
232 |
234 |
235 |
236 |
237 |
238 | ```r
239 | > SNPs <- pig60K[pig60K$trait2 < 1e-4, 1]
240 | > CMplot(pig60K,type="h",plot.type="m",LOG10=TRUE,highlight=SNPs,highlight.type="p",
241 | highlight.col=NULL,highlight.cex=1.2,highlight.pch=19,file="jpg",file.name=NULL,
242 | dpi=300,file.output=TRUE,verbose=TRUE,width=14,height=6,band=0.6)
243 | ```
244 |
245 |
247 |
248 |
249 |
250 |
251 | ```r
252 | > SNPs <- pig60K[pig60K$trait2 < 1e-4, 1]
253 | > CMplot(pig60K,type="p",plot.type="m",LOG10=TRUE,highlight=SNPs,highlight.type="h",
254 | col=c("grey30","grey60"),highlight.col="darkgreen",highlight.cex=1.2,highlight.pch=19,
255 | file="jpg",dpi=300,file.output=TRUE,verbose=TRUE,width=14,height=6)
256 | ```
257 |
258 |
260 |
261 |
262 |
263 |
264 | ```r
265 | > SNPs <- pig60K[
266 | pig60K$trait1 < 1e-4 |
267 | pig60K$trait2 < 1e-4 |
268 | pig60K$trait3 < 1e-4, 1]
269 | > CMplot(pig60K,type="p",plot.type="m",LOG10=TRUE,highlight=SNPs,highlight.type="l",
270 | threshold=1e-4,threshold.col="black",threshold.lty=1,col=c("grey60","#4197d8"),
271 | signal.cex=1.2, signal.col="red", highlight.col="grey",highlight.cex=0.7,
272 | file="jpg",dpi=300,file.output=TRUE,verbose=TRUE,multracks=TRUE)
273 |
274 | ```
275 |
276 |
278 |
279 |
280 |
281 |
282 | #### Visualize only one chromosome
283 |
284 | ```r
285 | > CMplot(pig60K[pig60K$Chromosome==13, ], plot.type="m",LOG10=TRUE,col=c("grey60"),highlight=SNPs,
286 | highlight.col="green",highlight.cex=1,highlight.pch=19,file="jpg",file.name=NULL,
287 | threshold=c(1e-6,1e-4),threshold.lty=c(1,2),threshold.lwd=c(1,2), width=9,height=6,
288 | threshold.col=c("red","blue"),amplify=FALSE,dpi=300,file.output=TRUE,verbose=TRUE)
289 | ```
290 |
291 |
293 |
294 |
295 |
296 |
297 | #### add genes or SNP names around the highlighted SNPs
298 |
299 | ```r
300 | > SNPs <- pig60K[pig60K[,5] < (0.05 / nrow(pig60K)), 1]
301 | > genes <- paste("GENE", 1:length(SNPs), sep="_")
302 | > set.seed(666666)
303 | > CMplot(pig60K[,c(1:3,5)], plot.type="m",LOG10=TRUE,col=c("grey30","grey60"),highlight=SNPs,
304 | highlight.col=rep(c("green","blue"),length=length(SNPs)),highlight.cex=1, highlight.text=genes,
305 | highlight.text.col=rep("red",length(SNPs)),threshold=0.05/nrow(pig60K),threshold.lty=2,
306 | amplify=FALSE,file="jpg",file.name=NULL,dpi=300,file.output=TRUE,verbose=TRUE,width=14,height=6)
307 | # Note:
308 | # 'highlight', 'highlight.text' could be vector or list, if it is a vector, all traits will
309 | # use the same highlighted SNPs index and text, if it is a list, the length of the list should equal to the number of traits.
310 | # the order of 'highlight.text' must be consistent with 'highlight'
311 | # highlight.text.cex: value or vecter, control the size of added text
312 | # highlight.text.font: value or vecter, control the font of added text
313 | ```
314 |
315 |
317 |
318 |
319 |
320 |
321 | #### Genomic Selection/Prediction(GS/GP) or other none p-values
322 |
323 | ```r
324 | > CMplot(cattle50K, plot.type="m", band=0.5, LOG10=FALSE, ylab="SNP effect",threshold=0.015,
325 | threshold.lty=2, threshold.lwd=1, threshold.col="red", amplify=TRUE, width=14,height=6,
326 | signal.col=NULL, chr.den.col=NULL, file="jpg",file.name=NULL,dpi=300,file.output=TRUE,
327 | verbose=TRUE,cex=0.8)
328 | #Note: if signal.col=NULL, the significant SNPs will be plotted with original colors.
329 | ```
330 |
331 |
332 |
333 |
334 |
335 |
347 |
348 |
349 |
350 |
369 |
370 |
371 |
372 |
384 |
385 |
386 |
387 |
399 |
400 |
401 |
402 | ---
403 |
404 | ### Q-Q plot
405 |
406 | ```r
407 | > CMplot(pig60K,plot.type="q",box=FALSE,file="jpg",file.name=NULL,dpi=300,
408 | conf.int=TRUE,conf.int.col=NULL,threshold.col="red",threshold.lty=2,
409 | file.output=TRUE,verbose=TRUE,width=5,height=5)
410 | ```
411 |
412 |
413 |
414 |
415 |
416 |
430 |
431 |
432 |
433 |
445 |
446 |
447 |
448 |