/R/TxdbView-class.R

http://github.com/tengfei/visnab · R · 442 lines · 248 code · 53 blank · 141 comment · 17 complexity · 6ac641d7510c3d307f9623fe58e67cf0 MD5 · raw file

  1. ##----------------------------------------------------------##
  2. ## For class "IntervalView"
  3. ##----------------------------------------------------------##
  4. ## setAs("TranscriptDb", "GRanges", function(From){
  5. ## })
  6. ## TxdbGRanges.gen <- setProxyGRanges("Txdb")
  7. TxdbView.gen <- setRefClass("TxdbView",
  8. contains=c("QtVisnabView", "LinearView"),
  9. fields=list(
  10. track ="TranscriptDb",
  11. introns="GRangesList",
  12. fiveUTR="GRangesList",
  13. threeUTR="GRangesList",
  14. cds="GRangesList",
  15. tx="GRanges",
  16. exons = "GRanges"
  17. ),
  18. methods = list(
  19. fetchFromSource = function(){
  20. ## compute exons/intons/... store to operands?
  21. }
  22. ))
  23. ##----------------------------------------------------------##
  24. ## "IntervalView" constructor
  25. ##----------------------------------------------------------##
  26. ##' To create a view for displaying information in a \code{TranscriptDb}
  27. ##' object.
  28. ##'
  29. ##' The constructor may take some time to retrieve information from
  30. ##' a \code{TranscriptDb} object, and store all the information which
  31. ##' required for visualiztion as fields, this is currently not ideal,
  32. ##' since \pkg{GenomicFeatures} doesn't support sending a small query to
  33. ##' SQLite database yet.
  34. ##'
  35. ##' ##' @title \code{TxdbView} object constructor.
  36. ##' @param track A TranscriptDb object
  37. ##' @param seqname Chromosome name, expect the
  38. ##' name with 'chr' prefix, e.g. 'chr1'.
  39. ##' @param geom Geometry of the view. default is 'full'.
  40. ##' \describe{
  41. ##' \item{\code{full}}{Showing all the introns/cds/5'-UTR/3'-UTR,
  42. ##' grouped by transcripts.}
  43. ##' \item{\code{dense}}{Showing one single genmoic structure, collapse
  44. ##' all information into one single strand.}
  45. ##' \item{\code{slice}}{Cut off introns and facilitate gene-centric view.}
  46. ##' }
  47. ##' @param rescale Control view port behaviors when zoom in/out
  48. ##' \describe{
  49. ##' \item{\code{geometry}}{Hide sroll bar when zoomed in, default}
  50. ##' \item{\code{transform}}{...}
  51. ##' \item{\code{none}}{Showing scroll bar when zoomed in}
  52. ##' }
  53. ##' @param viewname Name used for this view, will show as widget title when
  54. ##' embeded into tracks view.
  55. ##' @return A \code{TxdbView} object.
  56. ##' @author Tengfei Yin <yintengfei@gmail.com>
  57. TxdbView <- function(track,
  58. seqname,
  59. geom=c("full", "dense", "slice"),
  60. rescale = c("geometry", "transform", "none"),
  61. viewname = "TranscriptDb",
  62. ...){
  63. ## tootip information
  64. ## TODO: need to get information automatical some where
  65. ## may be integrate some data automatically
  66. tooltips <- capture.output(print(track))
  67. if(missing(seqname))
  68. seqname <- as.character(unique(as.character(seqnames(seqinfo(track))))[1])
  69. start <- 0
  70. end <- seqlengths(track)[[seqname]]
  71. seqlength <- end
  72. xlimZoom <- c(start,end)
  73. geom <- match.arg(geom)
  74. geom <- new("TxdbViewGeomSingleEnum", geom)
  75. rescale <- match.arg(rescale)
  76. rescale <- new("RescaleSingleEnum", rescale)
  77. pars <- GraphicPars(xlimZoom = xlimZoom,
  78. geom = geom,
  79. view = "TxdbView")
  80. ## store those infor in object, so make switch to other chromosome fast
  81. message("Loading Introns...")
  82. introns <- intronsByTranscript(track)
  83. message("Loading 5' UTR...")
  84. fiveUTR <- fiveUTRsByTranscript(track)
  85. message("Loading 3' UTR...")
  86. threeUTR <- threeUTRsByTranscript(track)
  87. message("Loading CDS...")
  88. cds <- cdsBy(track,by="tx")
  89. message("Loading transcripts...")
  90. tx <- transcripts(track)
  91. ## loading exons?
  92. viewrange <- MutableGRanges(seqname, IRanges(start, end))
  93. seqlengths(viewrange) <- end
  94. mode <- IModeGroup(scaleMode = ScaleMode(zoomMode = "Horizontal"))
  95. obj <- TxdbView.gen$new(track = track, pars = pars, mode = mode,
  96. viewrange = viewrange,
  97. introns = introns, fiveUTR = fiveUTR, threeUTR = threeUTR,
  98. rescale = rescale, tooltipinfo = tooltips,
  99. cds = cds,tx = tx, viewname = viewname,
  100. eventTrace = new("EventTrace"))
  101. ## add default attributes
  102. ## addAttr(obj$track,.color=obj$pars$fill,.hover=FALSE,.brushed=FALSE)
  103. message("Processing and creating view...")
  104. obj$createView()
  105. obj$regSignal()
  106. message("Ready")
  107. return(obj)
  108. }
  109. ############################################################
  110. ## createview method
  111. ############################################################
  112. TxdbView.gen$methods(createView = function(){
  113. seqname <- as.character(seqnames(viewrange))
  114. setDislayWidgets()
  115. setBgColor()
  116. ## compute levels
  117. tx.sub <- tx[seqnames(tx)==seqname]
  118. tx_id <- values(tx.sub)$tx_id
  119. .levels <- disjointBins(ranges(tx.sub))
  120. names(.levels) <- tx_id
  121. introns.sub <- introns[names(introns) %in% as.character(tx_id)]
  122. fiveUTR.sub <- fiveUTR[names(fiveUTR) %in% as.character(tx_id)]
  123. threeUTR.sub <- threeUTR[names(threeUTR) %in% as.character(tx_id)]
  124. cds.sub <- cds[names(cds) %in% as.character(tx_id)]
  125. ## exons.sub <- exons[names(exons) %in% as.character(tx_id)]
  126. int.l <- elementLengths(introns.sub)
  127. futr.l <- elementLengths(fiveUTR.sub)
  128. tutr.l <- elementLengths(threeUTR.sub)
  129. cds.l <- elementLengths(cds.sub)
  130. ## exons.l <- elementLengths(exons.sub)
  131. int <- unlist(introns.sub)
  132. futr <- unlist(fiveUTR.sub)
  133. tutr <- unlist(threeUTR.sub)
  134. cdss <- unlist(cds.sub)
  135. ## exn <- unlist(exons.sub)
  136. ## prepare for "reduce" geom
  137. int.r <- reduce(int)
  138. cds.r <- reduce(cdss)
  139. five.r <- reduce(futr)
  140. three.r <- reduce(tutr)
  141. ## should think a better way to do this
  142. irs <- reduce(c(cds.r,five.r,three.r))
  143. int.r <- setdiff(int.r,irs)
  144. values(int)$tx_id <- rep(names(introns.sub),int.l)
  145. values(futr)$tx_id <- rep(names(fiveUTR.sub),futr.l)
  146. values(tutr)$tx_id <- rep(names(threeUTR.sub),tutr.l)
  147. values(cdss)$tx_id <- rep(names(cds.sub),cds.l)
  148. ## values(exn)$tx_id <- rep(names(exons.sub),exons.l)
  149. values(int)$.level <- .levels[as.character(values(int)$tx_id)]
  150. values(futr)$.level <- .levels[as.character(values(futr)$tx_id)]
  151. values(tutr)$.level <- .levels[as.character(values(tutr)$tx_id)]
  152. values(cdss)$.level <- .levels[as.character(values(cdss)$tx_id)]
  153. ## values(exn)$.level <- .levels[as.character(values(exn)$tx_id)]
  154. ## int.pos <- int[strand(int)=="+"]
  155. ## int.neg <- int[strand(int)=="-"]
  156. ## tail(sort(width(introns.sub)))
  157. st.int <- start(int)
  158. ed.int <- end(int)
  159. lv.int <- values(int)$.level
  160. strand.int <- as.character(strand(int))
  161. st.five <- start(futr)
  162. ed.five <- end(futr)
  163. lv.five <- values(futr)$.level
  164. st.three <- start(tutr)
  165. ed.three <- end(tutr)
  166. lv.three <- values(tutr)$.level
  167. st.cds <- start(cdss)
  168. ed.cds <- end(cdss)
  169. lv.cds <- values(cdss)$.level
  170. ## for "dense"
  171. st.five.r <- start(five.r)
  172. ed.five.r <- end(five.r)
  173. st.three.r <- start(three.r)
  174. ed.three.r <- end(three.r)
  175. st.cds.r <- start(cds.r)
  176. ed.cds.r <- end(cds.r)
  177. st.int.r <- start(int.r)
  178. ed.int.r <- end(int.r)
  179. strand.int.r <- as.character(strand(int.r))
  180. ylim <- c(0,max(c(lv.int, lv.five, lv.cds, lv.three))*5+10)
  181. xlim <- c(0,seqlengths(viewrange))
  182. ## xlim.mar <- 0.05*diff(xlim)
  183. ## ylim.mar <- 0.05*diff(ylim)
  184. ## pars$xlim <<- c(xlim[1]-xlim.mar,xlim[2]+xlim.mar)
  185. ## pars$ylim <<- c(ylim[1]-ylim.mar,ylim[2]+ylim.mar)
  186. pars$xlimChanged$block()
  187. pars$ylimChanged$block()
  188. pars$xlim <<- xlim
  189. pars$ylim <<- expand_range(ylim, mul = 0.05)
  190. pars$xlimChanged$unblock()
  191. pars$ylimChanged$unblock()
  192. ## canonical strucuture
  193. drawfun <- function(layer,painter,exposed){
  194. pars$xlimZoomChanged$block()
  195. pars$xlimZoom <<- as.matrix(exposed)[,1]
  196. xlimZoom <- pars$xlimZoom
  197. if(!eventTrace$selfSignal){
  198. viewrange$rangesChanged$unblock()
  199. ranges(viewrange) <<- IRanges(pars$xlimZoom[1], pars$xlimZoom[2])
  200. }
  201. if(eventTrace$selfSignal){
  202. viewrange$rangesChanged$block()
  203. ranges(viewrange) <<- IRanges(pars$xlimZoom[1], pars$xlimZoom[2])
  204. }
  205. pars$xlimZoomChanged$unblock()
  206. if(pars$geom=="full"){
  207. ## 5'UTR
  208. if(length(st.five)>0)
  209. qdrawRect(painter,st.five,10*lv.five-2,ed.five,
  210. 10*lv.five+2,fill="black",stroke=NA)
  211. ## 3'
  212. if(length(st.three)>0)
  213. qdrawRect(painter,st.three,10*lv.three-2,ed.three,
  214. 10*lv.three+2,fill="black",stroke=NA)
  215. ## cds
  216. if(length(st.cds)>0)
  217. qdrawRect(painter,st.cds,10*lv.cds-4,ed.cds,10*lv.cds+4,
  218. fill="black",stroke=NA)
  219. ## intron
  220. if(length(st.int)>0)
  221. qdrawSegment(painter,st.int,10*lv.int,ed.int,10*lv.int,stroke="black")
  222. if(diff(xlimZoom)<8e5){
  223. unit <- as.integer(diff(xlimZoom)/50)
  224. ## draw arrow to indicate strand
  225. ## subset first
  226. seqlengths(int)
  227. grsub <- GRanges(seqnames(viewrange), ranges = ranges(viewrange))
  228. intsub <- subsetByOverlaps(int, grsub)
  229. st.int <- start(intsub)
  230. ed.int <- end(intsub)
  231. lv.int <- values(intsub)$.level
  232. ardf <- lapply(seq_along(st.int), function(i){
  233. n <- round((ed.int[i]-st.int[i])/unit, dig = 0)
  234. xs <- cbreaks(c(st.int[i], ed.int[i]), pretty_breaks(n))$breaks
  235. xs <- xs[xs >= st.int[i] & xs <= ed.int[i]]
  236. df <- data.frame(x = xs, y = rep(as.numeric(lv.int[i])*10, length(xs)))
  237. })
  238. ardf <- do.call("rbind", ardf)
  239. ## negative strand
  240. idx <- as.character(strand(intsub)) == "-"
  241. arrow <- qglyphArrow(dir = "left")
  242. qdrawGlyph(painter, arrow, ardf[idx, "x"], ardf[idx, "y"], cex = 0.5, fill = NA)
  243. arrow <- qglyphArrow(dir = "right")
  244. qdrawGlyph(painter, arrow, ardf[!idx, "x"], ardf[!idx, "y"], cex = 0.5, fill = NA)
  245. ## positive strand
  246. }
  247. pars$ylim <<- ylim
  248. }
  249. if(pars$geom=="dense"){
  250. ## reduced structure
  251. ## 5'UTR
  252. if(length(st.five.r)>0)
  253. qdrawRect(painter,st.five.r,10-2,ed.five.r,
  254. 10+2,fill="black",stroke=NA)
  255. ## 3'UTR
  256. if(length(st.three.r)>0)
  257. qdrawRect(painter,st.three.r,10-2,ed.three.r,
  258. 10+2,fill
  259. ="black",stroke=NA)
  260. ## cds
  261. if(length(st.cds.r)>0)
  262. qdrawRect(painter,st.cds.r,10-4,ed.cds.r,10+4,
  263. fill="black",stroke=NA)
  264. ## introns
  265. if(length(st.int.r)>0)
  266. qdrawSegment(painter,st.int.r,10,ed.int.r,10,stroke="black")
  267. ## if(diff(xlimZoom)<8e5){
  268. ## unit <- as.integer(diff(xlimZoom)/50)
  269. ## ## draw arrow to indicate strand
  270. ## ## subset first
  271. ## grsub <- GRanges(seqnames(viewrange), ranges = ranges(viewrange))
  272. ## intsub <- subsetByOverlaps(int, grsub)
  273. ## st.int <- start(intsub)
  274. ## ed.int <- end(intsub)
  275. ## lv.int <- values(intsub)$.level
  276. ## ardf <- lapply(seq_along(st.int), function(i){
  277. ## n <- round((ed.int[i]-st.int[i])/unit, dig = 0)
  278. ## xs <- cbreaks(c(st.int[i], ed.int[i]), pretty_breaks(n))$breaks
  279. ## xs <- xs[xs >= st.int[i] & xs <= ed.int[i]]
  280. ## df <- data.frame(x = xs, y = rep(10, length(xs)))
  281. ## })
  282. ## ardf <- do.call("rbind", ardf)
  283. ## ## negative strand
  284. ## idx <- as.character(strand(intsub)) == "-"
  285. ## ## reduce with no arrow
  286. ## ## arrow <- qglyphArrow(dir = "left")
  287. ## ## qdrawGlyph(painter, arrow, ardf[idx, "x"], ardf[idx, "y"], cex = 0.5, fill = NA)
  288. ## ## arrow <- qglyphArrow(dir = "right")
  289. ## ## qdrawGlyph(painter, arrow, ardf[!idx, "x"], ardf[!idx, "y"], cex = 0.5, fill = NA)
  290. ## ## positive strand
  291. ## }
  292. pars$ylim <<- c(-20,40)
  293. }
  294. }
  295. ## selectedRangesFun
  296. ## selectedRangesFun <- function(layer, painter){
  297. ## srm <- selectedRangesModel
  298. ## if(length(srm)>0){
  299. ## cols <- selectedRangesModelColor
  300. ## if((as.character(cols) %in% names(elementMetadata(srm)))){
  301. ## cols.value <- elementMetadata(srm)[[cols]]
  302. ## if(is.numeric(cols.value)){
  303. ## cols <- cscale(cols.value, pars$cpal)
  304. ## }else{
  305. ## cols <- dscale(factor(cols.value), pars$dpal)
  306. ## }}else{
  307. ## cols <- rep(cols,length(srm))
  308. ## }
  309. ## idx <- as.character(seqnames(selectedRangesModel)) == seqname
  310. ## qdrawRect(painter, start(srm)[idx], 0,
  311. ## end(srm)[idx], 10, stroke = NA, fill = cols[idx])
  312. ## }
  313. ## }
  314. keyOutFun <- function(layer, event){
  315. eventTrace$focusin <<- FALSE
  316. }
  317. hoverEnterFun <- function(layer, event){
  318. eventTrace$focusin <<- TRUE
  319. }
  320. hoverLeaveFun <- function(layer, event){
  321. eventTrace$focusin <<- FALSE
  322. }
  323. rootLayer[0,0] <<- qlayer(scene, drawfun,
  324. wheelFun= wheelEventZoom(),
  325. keyPressFun = keyPressEventZoom(),
  326. hoverEnterFun = hoverEnterFun,
  327. focusOutFun = keyOutFun, hoverLeaveFun = hoverLeaveFun)
  328. rootLayer[0,0]$setLimits(qrect(pars$xlim[1],pars$ylim[1],
  329. pars$xlim[2],pars$ylim[2]))
  330. pars$ylimChanged$connect(function(){
  331. rootLayer[0,0]$setLimits(qrect(pars$xlim,pars$ylim))
  332. })
  333. if(pars$geom == "dense")
  334. rootLayer$setGeometry(0, 0, 800, 50)
  335. })
  336. TxdbView.gen$methods(regSignal = function(){
  337. viewrange$rangesChanged$connect(function(){
  338. ## pars$xlimZoomChanged$block()
  339. ## pars$xlimZoom <- as.matrix(exposed)[,1]
  340. ## xlimZoom <- pars$xlimZoom
  341. qupdate(scene)
  342. })
  343. pars$xlimZoomChanged$connect(function(){
  344. zoom_factor <- diff(pars$xlimZoom)/seqlengths(viewrange)
  345. ## then scale view
  346. view$resetTransform()
  347. view$scale(1/zoom_factor, 1)
  348. ## then center view
  349. pos.x <- mean(pars$xlimZoom)
  350. pos.y <- mean(pars$ylim)
  351. pos.scene <- as.numeric(rootLayer[0,0]$mapToScene(pos.x, pos.y))
  352. view$centerOn(pos.scene[1], pos.scene[2])
  353. })
  354. ## geom
  355. pars$geomChanged$connect(function(){
  356. qupdate(scene)
  357. })
  358. ## signal when change xlimZoom
  359. ## seqname change should update view and update seqlength
  360. viewrange$seqnamesChanged$connect(function(){
  361. ## end <- max(end(ranges(track[seqnames(track)==seqname])))
  362. viewrange$seqnamesChanged$block()
  363. seqlengths(viewrange) <<- seqlengths(track)[[as.character(seqnames(viewrange))]]
  364. viewrange$seqnamesChanged$unblock()
  365. ## pars$xlimZoom <<- c(0 ,end)
  366. ## selectedRange <<- c(start,end)
  367. ## rootLayer[0,0]$close()
  368. ## obj$rootLayer[0,0]$gridLayout()$removeAt(0)
  369. rootLayer[0,0]$close()
  370. view$resetTransform()
  371. createView()
  372. regSignal()
  373. })
  374. ## selectedRangesModelChanged$connect(function(){
  375. ## qupdate(scene)
  376. ## })
  377. pars$bgColorChanged$connect(function(){
  378. bgcol <- pars$bgColor
  379. bgalpha <- pars$alpha
  380. qcol <- col2qcol(bgcol,bgalpha)
  381. scene$setBackgroundBrush(qbrush(qcol))
  382. })
  383. })
  384. TxdbView.gen$methods(show = function(){
  385. view$show()
  386. })
  387. setMethod("print","TxdbView",function(x,..){
  388. x$show()
  389. })