bio-graphics 1.2 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (331) hide show
  1. data/doc/classes/Bio.html +4 -26
  2. data/doc/classes/Bio/Feature.html +350 -0
  3. data/doc/classes/Bio/Feature.src/M000010.html +21 -0
  4. data/doc/classes/Bio/Feature.src/M000011.html +20 -0
  5. data/doc/classes/Bio/Feature.src/M000012.html +19 -0
  6. data/doc/classes/Bio/Feature.src/M000014.html +21 -0
  7. data/doc/classes/Bio/Feature.src/M000016.html +21 -0
  8. data/doc/classes/Bio/Feature.src/M000034.html +21 -0
  9. data/doc/classes/Bio/Feature.src/M000035.html +20 -0
  10. data/doc/classes/Bio/Feature.src/M000036.html +19 -0
  11. data/doc/classes/Bio/Feature.src/M000038.html +21 -0
  12. data/doc/classes/Bio/Feature.src/M000040.html +21 -0
  13. data/doc/classes/Bio/Feature.src/M000042.html +21 -0
  14. data/doc/classes/Bio/Feature.src/M000043.html +20 -0
  15. data/doc/classes/Bio/Feature.src/M000044.html +21 -0
  16. data/doc/classes/Bio/Feature.src/M000045.html +20 -0
  17. data/doc/classes/Bio/Feature.src/M000046.html +19 -0
  18. data/doc/classes/Bio/Feature.src/M000048.html +21 -0
  19. data/doc/classes/Bio/Feature.src/M000050.html +21 -0
  20. data/doc/classes/Bio/Feature.src/M000074.html +21 -0
  21. data/doc/classes/Bio/Feature.src/M000075.html +20 -0
  22. data/doc/classes/Bio/Feature.src/M000076.html +19 -0
  23. data/doc/classes/Bio/Feature.src/M000078.html +21 -0
  24. data/doc/classes/Bio/Feature.src/M000080.html +21 -0
  25. data/doc/classes/Bio/Feature/Qualifier.html +189 -0
  26. data/doc/classes/Bio/Feature/Qualifier.src/M000017.html +18 -0
  27. data/doc/classes/Bio/Feature/Qualifier.src/M000041.html +18 -0
  28. data/doc/classes/Bio/Feature/Qualifier.src/M000049.html +18 -0
  29. data/doc/classes/Bio/Feature/Qualifier.src/M000051.html +18 -0
  30. data/doc/classes/Bio/Feature/Qualifier.src/M000081.html +18 -0
  31. data/doc/classes/Bio/Features.html +329 -0
  32. data/doc/classes/Bio/Features.src/M000004.html +18 -0
  33. data/doc/classes/Bio/Features.src/M000005.html +19 -0
  34. data/doc/classes/Bio/Features.src/M000006.html +21 -0
  35. data/doc/classes/Bio/Features.src/M000007.html +18 -0
  36. data/doc/classes/Bio/Features.src/M000008.html +18 -0
  37. data/doc/classes/Bio/Features.src/M000009.html +18 -0
  38. data/doc/classes/Bio/Features.src/M000028.html +18 -0
  39. data/doc/classes/Bio/Features.src/M000029.html +19 -0
  40. data/doc/classes/Bio/Features.src/M000030.html +21 -0
  41. data/doc/classes/Bio/Features.src/M000031.html +18 -0
  42. data/doc/classes/Bio/Features.src/M000032.html +18 -0
  43. data/doc/classes/Bio/Features.src/M000033.html +18 -0
  44. data/doc/classes/Bio/Features.src/M000036.html +18 -0
  45. data/doc/classes/Bio/Features.src/M000037.html +19 -0
  46. data/doc/classes/Bio/Features.src/M000038.html +18 -0
  47. data/doc/classes/Bio/Features.src/M000039.html +19 -0
  48. data/doc/classes/Bio/Features.src/M000040.html +21 -0
  49. data/doc/classes/Bio/Features.src/M000041.html +18 -0
  50. data/doc/classes/Bio/Features.src/M000042.html +18 -0
  51. data/doc/classes/Bio/Features.src/M000043.html +18 -0
  52. data/doc/classes/Bio/Features.src/M000068.html +18 -0
  53. data/doc/classes/Bio/Features.src/M000069.html +19 -0
  54. data/doc/classes/Bio/Features.src/M000070.html +21 -0
  55. data/doc/classes/Bio/Features.src/M000071.html +18 -0
  56. data/doc/classes/Bio/Features.src/M000072.html +18 -0
  57. data/doc/classes/Bio/Features.src/M000073.html +18 -0
  58. data/doc/classes/Bio/Graphics.html +28 -42
  59. data/doc/classes/Bio/Graphics/{Panel/Track/Feature.html → Feature.html} +98 -125
  60. data/doc/classes/Bio/Graphics/Feature.src/M000020.html +51 -0
  61. data/doc/classes/Bio/Graphics/Feature.src/M000021.html +65 -0
  62. data/doc/classes/Bio/Graphics/Feature.src/M000022.html +55 -0
  63. data/doc/classes/Bio/Graphics/Feature.src/M000023.html +66 -0
  64. data/doc/classes/Bio/Graphics/Feature.src/M000024.html +51 -0
  65. data/doc/classes/Bio/Graphics/Feature.src/M000025.html +65 -0
  66. data/doc/classes/Bio/Graphics/Feature.src/M000026.html +55 -0
  67. data/doc/classes/Bio/Graphics/Feature.src/M000054.html +51 -0
  68. data/doc/classes/Bio/Graphics/Feature.src/M000055.html +65 -0
  69. data/doc/classes/Bio/Graphics/Feature.src/M000056.html +55 -0
  70. data/doc/classes/Bio/Graphics/Feature/SubFeature.html +348 -0
  71. data/doc/classes/Bio/Graphics/Feature/SubFeature.src/M000025.html +68 -0
  72. data/doc/classes/Bio/Graphics/Feature/SubFeature.src/M000026.html +67 -0
  73. data/doc/classes/Bio/Graphics/Glyph.html +178 -0
  74. data/doc/classes/Bio/Graphics/Glyph/Box.html +139 -0
  75. data/doc/classes/Bio/Graphics/Glyph/Box.src/M000004.html +24 -0
  76. data/doc/classes/Bio/Graphics/Glyph/Box.src/M000032.html +24 -0
  77. data/doc/classes/Bio/Graphics/Glyph/Common.html +187 -0
  78. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000004.html +18 -0
  79. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000005.html +18 -0
  80. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000006.html +24 -0
  81. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000007.html +24 -0
  82. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000033.html +18 -0
  83. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000034.html +24 -0
  84. data/doc/classes/Bio/Graphics/Glyph/Common.src/M000035.html +24 -0
  85. data/doc/classes/Bio/Graphics/Glyph/CustomTestGlyph.html +139 -0
  86. data/doc/classes/Bio/Graphics/Glyph/CustomTestGlyph.src/M000037.html +22 -0
  87. data/doc/classes/Bio/Graphics/Glyph/CustomTestGlyphInFile.html +139 -0
  88. data/doc/classes/Bio/Graphics/Glyph/CustomTestGlyphInFile.src/M000038.html +22 -0
  89. data/doc/classes/Bio/Graphics/Glyph/DirectedBox.html +139 -0
  90. data/doc/classes/Bio/Graphics/Glyph/DirectedBox.src/M000009.html +31 -0
  91. data/doc/classes/Bio/Graphics/Glyph/DirectedBox.src/M000039.html +31 -0
  92. data/doc/classes/Bio/Graphics/Glyph/DirectedGeneric.html +139 -0
  93. data/doc/classes/Bio/Graphics/Glyph/DirectedGeneric.src/M000011.html +26 -0
  94. data/doc/classes/Bio/Graphics/Glyph/DirectedGeneric.src/M000013.html +26 -0
  95. data/doc/classes/Bio/Graphics/Glyph/DirectedGeneric.src/M000043.html +26 -0
  96. data/doc/classes/Bio/Graphics/Glyph/DirectedSpliced.html +139 -0
  97. data/doc/classes/Bio/Graphics/Glyph/DirectedSpliced.src/M000008.html +40 -0
  98. data/doc/classes/Bio/Graphics/Glyph/DirectedSpliced.src/M000010.html +40 -0
  99. data/doc/classes/Bio/Graphics/Glyph/DirectedSpliced.src/M000040.html +40 -0
  100. data/doc/classes/Bio/Graphics/{Panel/Track/Feature/PixelRange.html → Glyph/Dot.html} +16 -19
  101. data/doc/classes/Bio/Graphics/Glyph/Dot.src/M000013.html +22 -0
  102. data/doc/classes/Bio/Graphics/Glyph/Dot.src/M000015.html +22 -0
  103. data/doc/classes/Bio/Graphics/Glyph/Dot.src/M000045.html +22 -0
  104. data/doc/classes/Bio/Graphics/Glyph/Generic.html +139 -0
  105. data/doc/classes/Bio/Graphics/Glyph/Generic.src/M000009.html +18 -0
  106. data/doc/classes/Bio/Graphics/Glyph/Generic.src/M000011.html +18 -0
  107. data/doc/classes/Bio/Graphics/Glyph/Generic.src/M000041.html +18 -0
  108. data/doc/classes/Bio/Graphics/Glyph/Line.html +139 -0
  109. data/doc/classes/Bio/Graphics/Glyph/Line.src/M000012.html +20 -0
  110. data/doc/classes/Bio/Graphics/Glyph/Line.src/M000014.html +20 -0
  111. data/doc/classes/Bio/Graphics/Glyph/Line.src/M000044.html +20 -0
  112. data/doc/classes/Bio/Graphics/Glyph/LineWithHandles.html +139 -0
  113. data/doc/classes/Bio/Graphics/Glyph/LineWithHandles.src/M000014.html +28 -0
  114. data/doc/classes/Bio/Graphics/Glyph/LineWithHandles.src/M000016.html +28 -0
  115. data/doc/classes/Bio/Graphics/Glyph/LineWithHandles.src/M000046.html +28 -0
  116. data/doc/classes/Bio/Graphics/Glyph/Spliced.html +139 -0
  117. data/doc/classes/Bio/Graphics/Glyph/Spliced.src/M000010.html +19 -0
  118. data/doc/classes/Bio/Graphics/Glyph/Spliced.src/M000012.html +19 -0
  119. data/doc/classes/Bio/Graphics/Glyph/Spliced.src/M000042.html +19 -0
  120. data/doc/classes/Bio/Graphics/Glyph/Transcript.html +113 -0
  121. data/doc/classes/Bio/Graphics/Glyph/Triangle.html +139 -0
  122. data/doc/classes/Bio/Graphics/Glyph/Triangle.src/M000007.html +21 -0
  123. data/doc/classes/Bio/Graphics/Glyph/Triangle.src/M000008.html +21 -0
  124. data/doc/classes/Bio/Graphics/Glyph/Triangle.src/M000036.html +21 -0
  125. data/doc/classes/{ImageMap.html → Bio/Graphics/ImageMap.html} +50 -16
  126. data/doc/classes/{ImageMap.src/M000001.html → Bio/Graphics/ImageMap.src/M000030.html} +3 -3
  127. data/doc/classes/Bio/Graphics/ImageMap.src/M000031.html +18 -0
  128. data/doc/classes/Bio/Graphics/ImageMap.src/M000032.html +18 -0
  129. data/doc/classes/Bio/Graphics/ImageMap.src/M000033.html +18 -0
  130. data/doc/classes/{ImageMap.src/M000002.html → Bio/Graphics/ImageMap.src/M000034.html} +7 -4
  131. data/doc/classes/Bio/Graphics/ImageMap.src/M000035.html +24 -0
  132. data/doc/classes/Bio/Graphics/ImageMap.src/M000062.html +18 -0
  133. data/doc/classes/Bio/Graphics/ImageMap.src/M000063.html +18 -0
  134. data/doc/classes/Bio/Graphics/ImageMap.src/M000064.html +27 -0
  135. data/doc/classes/Bio/Graphics/ImageMap.src/M000065.html +24 -0
  136. data/doc/classes/{ImageMap/ImageMapElement.html → Bio/Graphics/ImageMap/Element.html} +14 -14
  137. data/doc/classes/{ImageMap/ImageMapElement.src/M000003.html → Bio/Graphics/ImageMap/Element.src/M000034.html} +3 -3
  138. data/doc/classes/{ImageMap/ImageMapElement.src/M000004.html → Bio/Graphics/ImageMap/Element.src/M000035.html} +6 -4
  139. data/doc/classes/Bio/Graphics/ImageMap/Element.src/M000036.html +19 -0
  140. data/doc/classes/Bio/Graphics/ImageMap/Element.src/M000037.html +22 -0
  141. data/doc/classes/Bio/Graphics/ImageMap/Element.src/M000066.html +19 -0
  142. data/doc/classes/Bio/Graphics/ImageMap/Element.src/M000067.html +22 -0
  143. data/doc/classes/Bio/Graphics/Panel.html +70 -69
  144. data/doc/classes/Bio/Graphics/Panel.src/M000025.html +52 -0
  145. data/doc/classes/Bio/Graphics/Panel.src/M000026.html +20 -0
  146. data/doc/classes/Bio/Graphics/Panel.src/M000027.html +98 -0
  147. data/doc/classes/Bio/Graphics/Panel.src/M000028.html +20 -0
  148. data/doc/classes/Bio/Graphics/Panel.src/M000029.html +52 -0
  149. data/doc/classes/Bio/Graphics/Panel.src/M000030.html +20 -0
  150. data/doc/classes/Bio/Graphics/Panel.src/M000031.html +98 -0
  151. data/doc/classes/Bio/Graphics/Panel.src/M000059.html +52 -0
  152. data/doc/classes/Bio/Graphics/Panel.src/M000060.html +20 -0
  153. data/doc/classes/Bio/Graphics/Panel.src/M000061.html +98 -0
  154. data/doc/classes/Bio/Graphics/{Panel/Ruler.html → Ruler.html} +50 -21
  155. data/doc/classes/Bio/Graphics/Ruler.src/M000015.html +30 -0
  156. data/doc/classes/Bio/Graphics/Ruler.src/M000016.html +20 -0
  157. data/doc/classes/Bio/Graphics/Ruler.src/M000017.html +30 -0
  158. data/doc/classes/Bio/Graphics/Ruler.src/M000018.html +20 -0
  159. data/doc/classes/Bio/Graphics/Ruler.src/M000019.html +26 -0
  160. data/doc/classes/Bio/Graphics/Ruler.src/M000020.html +45 -0
  161. data/doc/classes/Bio/Graphics/Ruler.src/M000047.html +30 -0
  162. data/doc/classes/Bio/Graphics/Ruler.src/M000048.html +20 -0
  163. data/doc/classes/Bio/Graphics/Ruler.src/M000049.html +26 -0
  164. data/doc/classes/Bio/Graphics/Ruler.src/M000050.html +45 -0
  165. data/doc/classes/Bio/Graphics/SubFeature.html +348 -0
  166. data/doc/classes/Bio/Graphics/SubFeature.src/M000001.html +73 -0
  167. data/doc/classes/Bio/Graphics/SubFeature.src/M000002.html +69 -0
  168. data/doc/classes/Bio/Graphics/SubFeature.src/M000023.html +73 -0
  169. data/doc/classes/Bio/Graphics/SubFeature.src/M000024.html +69 -0
  170. data/doc/classes/Bio/Graphics/SubFeature.src/M000027.html +73 -0
  171. data/doc/classes/Bio/Graphics/SubFeature.src/M000028.html +69 -0
  172. data/doc/classes/Bio/Graphics/SubFeature.src/M000057.html +73 -0
  173. data/doc/classes/Bio/Graphics/SubFeature.src/M000058.html +69 -0
  174. data/doc/classes/Bio/Graphics/{Panel/Track.html → Track.html} +67 -69
  175. data/doc/classes/Bio/Graphics/Track.src/M000017.html +39 -0
  176. data/doc/classes/Bio/Graphics/Track.src/M000018.html +37 -0
  177. data/doc/classes/Bio/Graphics/Track.src/M000019.html +45 -0
  178. data/doc/classes/Bio/Graphics/Track.src/M000020.html +41 -0
  179. data/doc/classes/Bio/Graphics/Track.src/M000021.html +39 -0
  180. data/doc/classes/Bio/Graphics/Track.src/M000022.html +37 -0
  181. data/doc/classes/Bio/Graphics/Track.src/M000023.html +45 -0
  182. data/doc/classes/Bio/Graphics/Track.src/M000051.html +39 -0
  183. data/doc/classes/Bio/Graphics/Track.src/M000052.html +37 -0
  184. data/doc/classes/Bio/Graphics/Track.src/M000053.html +45 -0
  185. data/doc/classes/Range.html +129 -0
  186. data/doc/classes/String.html +167 -0
  187. data/doc/classes/String.src/M000001.html +18 -0
  188. data/doc/classes/String.src/M000002.html +18 -0
  189. data/doc/classes/String.src/M000003.html +23 -0
  190. data/doc/classes/String.src/M000029.html +18 -0
  191. data/doc/classes/String.src/M000030.html +18 -0
  192. data/doc/classes/String.src/M000031.html +23 -0
  193. data/doc/classes/TestCustomGlyph.html +137 -0
  194. data/doc/classes/TestCustomGlyph.src/M000025.html +25 -0
  195. data/doc/classes/TestCustomGlyphInFile.html +167 -0
  196. data/doc/classes/TestCustomGlyphInFile.src/M000026.html +19 -0
  197. data/doc/classes/TestCustomGlyphInFile.src/M000027.html +25 -0
  198. data/doc/classes/TestCustomGlyphInFile.src/M000028.html +18 -0
  199. data/doc/classes/TestExtensions.html +152 -0
  200. data/doc/classes/TestExtensions.src/M000015.html +22 -0
  201. data/doc/classes/TestExtensions.src/M000016.html +25 -0
  202. data/doc/classes/TestFeature.html +152 -0
  203. data/doc/classes/TestFeature.src/M000017.html +19 -0
  204. data/doc/classes/TestFeature.src/M000018.html +21 -0
  205. data/doc/classes/TestImageMap.html +182 -0
  206. data/doc/classes/TestImageMap.src/M000019.html +22 -0
  207. data/doc/classes/TestImageMap.src/M000020.html +56 -0
  208. data/doc/classes/TestImageMap.src/M000021.html +56 -0
  209. data/doc/classes/TestImageMap.src/M000022.html +20 -0
  210. data/doc/classes/TestPanel.html +276 -0
  211. data/doc/classes/TestPanel.src/M000001.html +18 -0
  212. data/doc/classes/TestPanel.src/M000002.html +61 -0
  213. data/doc/classes/TestPanel.src/M000003.html +35 -0
  214. data/doc/classes/TestPanel.src/M000004.html +54 -0
  215. data/doc/classes/TestPanel.src/M000005.html +54 -0
  216. data/doc/classes/TestPanel.src/M000006.html +41 -0
  217. data/doc/classes/TestPanel.src/M000007.html +36 -0
  218. data/doc/classes/TestPanel.src/M000008.html +20 -0
  219. data/doc/classes/TestPanel.src/M000009.html +26 -0
  220. data/doc/classes/TestPanel.src/M000010.html +21 -0
  221. data/doc/classes/TestRuler.html +152 -0
  222. data/doc/classes/TestRuler.src/M000013.html +22 -0
  223. data/doc/classes/TestRuler.src/M000014.html +31 -0
  224. data/doc/classes/TestSubFeature.html +152 -0
  225. data/doc/classes/TestSubFeature.src/M000023.html +21 -0
  226. data/doc/classes/TestSubFeature.src/M000024.html +18 -0
  227. data/doc/classes/TestTrack.html +152 -0
  228. data/doc/classes/TestTrack.src/M000011.html +19 -0
  229. data/doc/classes/TestTrack.src/M000012.html +23 -0
  230. data/doc/created.rid +1 -1
  231. data/doc/files/README_DEV.html +399 -70
  232. data/doc/files/TUTORIAL.html +188 -67
  233. data/doc/files/lib/bio-graphics_rb.html +3 -2
  234. data/doc/files/lib/bio/graphics/feature_rb.html +12 -6
  235. data/doc/files/lib/bio/graphics/glyphs/box_rb.html +113 -0
  236. data/doc/files/lib/bio/graphics/glyphs/common_rb.html +113 -0
  237. data/doc/files/lib/bio/graphics/glyphs/directed_box_rb.html +113 -0
  238. data/doc/files/lib/bio/graphics/glyphs/directed_generic_rb.html +113 -0
  239. data/doc/files/lib/bio/graphics/glyphs/directed_spliced_rb.html +113 -0
  240. data/doc/files/lib/bio/graphics/glyphs/dot_rb.html +113 -0
  241. data/doc/files/lib/bio/graphics/glyphs/generic_rb.html +113 -0
  242. data/doc/files/lib/bio/graphics/glyphs/line_rb.html +113 -0
  243. data/doc/files/lib/bio/graphics/glyphs/line_with_handles_rb.html +113 -0
  244. data/doc/files/lib/bio/graphics/glyphs/spliced_rb.html +113 -0
  245. data/doc/files/lib/bio/graphics/glyphs/transcript_rb.html +113 -0
  246. data/doc/files/lib/bio/graphics/glyphs/triangle_rb.html +113 -0
  247. data/doc/files/lib/bio/graphics/image_map_rb.html +3 -2
  248. data/doc/files/lib/bio/graphics/panel_rb.html +10 -2
  249. data/doc/files/lib/bio/graphics/ruler_rb.html +3 -2
  250. data/doc/files/lib/bio/graphics/subfeature_rb.html +114 -0
  251. data/doc/files/lib/bio/graphics/track_rb.html +3 -2
  252. data/doc/files/lib/feature_rb.html +101 -0
  253. data/doc/files/samples/arkdb_features_rb.html +101 -0
  254. data/doc/files/samples/glyph_showcase_rb.html +108 -0
  255. data/doc/files/samples/protein_domains_rb.html +115 -0
  256. data/doc/files/samples/subfeatures_rb.html +108 -0
  257. data/doc/files/scripts/gff2png_rb.html +154 -0
  258. data/doc/files/test/unit/custom_glyph_in_file_rb.html +101 -0
  259. data/doc/files/test/unit/test_class_extensions_rb.html +108 -0
  260. data/doc/files/test/unit/test_creation_rb.html +108 -0
  261. data/doc/files/test/unit/test_custom_glyph_rb.html +108 -0
  262. data/doc/files/test/unit/test_draw_rb.html +108 -0
  263. data/doc/files/test/unit/test_imagemap_rb.html +108 -0
  264. data/doc/files/test/unit/test_subfeatures_rb.html +108 -0
  265. data/doc/fr_class_index.html +24 -6
  266. data/doc/fr_file_index.html +14 -0
  267. data/doc/fr_method_index.html +51 -19
  268. data/doc/images/glyph_showcase.png +0 -0
  269. data/doc/images/terms.svg +146 -132
  270. data/images/glyph_showcase.png +0 -0
  271. data/lib/bio-graphics.rb +38 -6
  272. data/lib/bio/graphics/feature.rb +212 -440
  273. data/lib/bio/graphics/glyphs/box.rb +21 -0
  274. data/lib/bio/graphics/glyphs/common.rb +149 -0
  275. data/lib/bio/graphics/glyphs/directed_box.rb +28 -0
  276. data/lib/bio/graphics/glyphs/directed_generic.rb +23 -0
  277. data/lib/bio/graphics/glyphs/directed_spliced.rb +39 -0
  278. data/lib/bio/graphics/glyphs/dot.rb +21 -0
  279. data/lib/bio/graphics/glyphs/generic.rb +15 -0
  280. data/lib/bio/graphics/glyphs/line.rb +17 -0
  281. data/lib/bio/graphics/glyphs/line_with_handles.rb +25 -0
  282. data/lib/bio/graphics/glyphs/spliced.rb +16 -0
  283. data/lib/bio/graphics/glyphs/transcript.rb +12 -0
  284. data/lib/bio/graphics/glyphs/triangle.rb +18 -0
  285. data/lib/bio/graphics/image_map.rb +25 -4
  286. data/lib/bio/graphics/panel.rb +266 -209
  287. data/lib/bio/graphics/ruler.rb +95 -96
  288. data/lib/bio/graphics/subfeature.rb +187 -0
  289. data/lib/bio/graphics/track.rb +155 -156
  290. data/lib/feature.rb +204 -0
  291. data/samples/arkdb_features.rb +10 -8
  292. data/samples/glyph_showcase.rb +58 -22
  293. data/samples/protein_domains.rb +19 -0
  294. data/samples/subfeatures.rb +31 -0
  295. data/test/unit/custom_glyph_in_file.rb +12 -0
  296. data/test/unit/data.txt +32 -0
  297. data/test/unit/test_class_extensions.rb +23 -0
  298. data/test/unit/test_creation.rb +43 -13
  299. data/test/unit/test_custom_glyph.rb +50 -0
  300. data/test/unit/test_draw.rb +211 -0
  301. data/test/unit/test_imagemap.rb +134 -0
  302. data/test/unit/test_subfeatures.rb +17 -0
  303. metadata +396 -119
  304. data/doc/classes/Bio/Graphics/Panel.src/M000005.html +0 -29
  305. data/doc/classes/Bio/Graphics/Panel.src/M000006.html +0 -19
  306. data/doc/classes/Bio/Graphics/Panel.src/M000007.html +0 -68
  307. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000008.html +0 -20
  308. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000009.html +0 -28
  309. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000010.html +0 -54
  310. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000013.html +0 -20
  311. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000014.html +0 -20
  312. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000015.html +0 -28
  313. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000016.html +0 -59
  314. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000017.html +0 -20
  315. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000018.html +0 -28
  316. data/doc/classes/Bio/Graphics/Panel/Ruler.src/M000019.html +0 -59
  317. data/doc/classes/Bio/Graphics/Panel/Track.src/M000008.html +0 -26
  318. data/doc/classes/Bio/Graphics/Panel/Track.src/M000009.html +0 -42
  319. data/doc/classes/Bio/Graphics/Panel/Track.src/M000010.html +0 -52
  320. data/doc/classes/Bio/Graphics/Panel/Track.src/M000011.html +0 -23
  321. data/doc/classes/Bio/Graphics/Panel/Track.src/M000012.html +0 -43
  322. data/doc/classes/Bio/Graphics/Panel/Track.src/M000013.html +0 -259
  323. data/doc/classes/Bio/Graphics/Panel/Track/Feature.src/M000011.html +0 -65
  324. data/doc/classes/Bio/Graphics/Panel/Track/Feature.src/M000012.html +0 -39
  325. data/doc/classes/Bio/Graphics/Panel/Track/Feature.src/M000013.html +0 -27
  326. data/doc/classes/Bio/Graphics/Panel/Track/Feature.src/M000014.html +0 -225
  327. data/doc/classes/Bio/Graphics/Panel/Track/Feature.src/M000015.html +0 -48
  328. data/doc/classes/Bio/Graphics/Panel/Track/Feature/PixelRange.src/M000012.html +0 -18
  329. data/doc/classes/Bio/Graphics/Panel/Track/Feature/PixelRange.src/M000013.html +0 -18
  330. data/doc/classes/Bio/Graphics/Panel/Track/Feature/PixelRange.src/M000015.html +0 -18
  331. data/doc/classes/Bio/Graphics/Panel/Track/Feature/PixelRange.src/M000016.html +0 -18
@@ -1,440 +1,212 @@
1
- require 'yaml'
2
- #
3
- # = bio/graphics/feature.rb - feature class
4
- #
5
- # Copyright:: Copyright (C) 2007
6
- # Jan Aerts <jan.aerts@bbsrc.ac.uk>
7
- # License:: The Ruby License
8
- #
9
- module Bio
10
- module Graphics
11
- class Panel
12
- class Track
13
- # The Bio::Graphics::Track::Feature class describes features to be
14
- # placed on the graph. See Bio::Graphics documentation for explanation
15
- # of interplay between different classes.
16
- #
17
- # The position of the Feature is a Bio::Locations object to make it possible
18
- # to transparently work with simple and spliced features.
19
- class Feature
20
- # !!Not to be used directly. Use
21
- # Bio::Graphics::Panel::Track.add_feature instead!!
22
- # A feature can not exist except within the confines of a
23
- # Bio::Graphics::Panel::Track object.
24
- #
25
- #--
26
- # This is necessary because the feature needs to know the colour and glyph,
27
- # both of which are defined within the panel.
28
- #++
29
- #
30
- # ---
31
- # *Arguments*:
32
- # * _panel_ (required) :: Bio::Graphics::Panel::Track object that this
33
- # feature belongs to
34
- # * _name_ (required) :: Name of the feature
35
- # * _location_ :: Bio::Locations object. Default = whole panel, forward strand
36
- # * _link_ :: URL for clickable images
37
- # *Returns*:: Bio::Graphics::Track::Feature object
38
- def initialize(track, name, location = Bio::Locations.new('1..' + track.panel.length.to_s), link = nil)
39
- @track = track
40
- @name = name
41
- @location = location
42
- @start = location.collect{|l| l.from}.min.to_i
43
- @stop = location.collect{|l| l.to}.max.to_i
44
- @strand = location[0].strand.to_i
45
- @link = link
46
- @pixel_range_collection = Array.new
47
- @chopped_at_start = false
48
- @chopped_at_stop = false
49
- @hidden_subfeatures_at_start = false
50
- @hidden_subfeatures_at_stop = false
51
-
52
- # Get all pixel ranges for the subfeatures
53
- location.each do |l|
54
- # xxxxxx [ ]
55
- if l.to < track.panel.display_start
56
- @hidden_subfeatures_at_start = true
57
- next
58
- # [ ] xxxxx
59
- elsif l.from > track.panel.display_stop
60
- @hidden_subfeatures_at_stop = true
61
- next
62
- # xxxx[xxx ]
63
- elsif l.from < track.panel.display_start and l.to > track.panel.display_start
64
- start_pixel = 1
65
- stop_pixel = ( l.to - track.panel.display_start ).to_f / track.panel.rescale_factor
66
- @chopped_at_start = true
67
- # [ xxxx]xxxx
68
- elsif l.from < track.panel.display_stop and l.to > track.panel.display_stop
69
- start_pixel = ( l.from - track.panel.display_start ).to_f / track.panel.rescale_factor
70
- stop_pixel = track.panel.width
71
- @chopped_at_stop = true
72
- # xxxx[xxxxxxxxxx]xxxx
73
- elsif l.from < track.panel.display_start and l.to > track.panel.display_stop
74
- start_pixel = 1
75
- stop_pixel = track.panel.width
76
- @chopped_at_start = true
77
- @chopped_at_stop = true
78
- # [ xxxxx ]
79
- else
80
- start_pixel = ( l.from - track.panel.display_start ).to_f / track.panel.rescale_factor
81
- stop_pixel = ( l.to - track.panel.display_start ).to_f / track.panel.rescale_factor
82
- end
83
-
84
- @pixel_range_collection.push(PixelRange.new(start_pixel, stop_pixel))
85
-
86
- end
87
- end
88
-
89
- # The track that this feature belongs to
90
- attr_accessor :track
91
-
92
- # The name of the feature
93
- attr_accessor :name
94
-
95
- # The location of the feature (which is a Bio::Locations object)
96
- attr_accessor :location
97
-
98
- # The start position of the feature (in bp)
99
- attr_accessor :start
100
-
101
- # The stop position of the feature (in bp)
102
- attr_accessor :stop
103
-
104
- # The strand of the feature
105
- attr_accessor :strand
106
-
107
- # The URL to be followed when the glyph for this feature is clicked
108
- attr_accessor :link
109
-
110
- # The array keeping the pixel ranges for the sub-features. Unspliced
111
- # features will just have one element, while spliced features will
112
- # have more than one.
113
- attr_accessor :pixel_range_collection
114
-
115
- # Is the first subfeature incomplete?
116
- attr_accessor :chopped_at_start
117
-
118
- # Is the last subfeature incomplete?
119
- attr_accessor :chopped_at_stop
120
-
121
- # Are there subfeatures out of view at the left side of the picture?
122
- attr_accessor :hidden_subfeatures_at_start
123
-
124
- # Are there subfeatures out of view at the right side of the picture?
125
- attr_accessor :hidden_subfeatures_at_stop
126
-
127
- # Method to draw the arrows of directed glyphs. Not to be used
128
- # directly, but called by Feature#draw.
129
- def arrow(track,direction,x,y,size)
130
- case direction
131
- when :right
132
- track.move_to(x,y)
133
- track.rel_line_to(size,size)
134
- track.rel_line_to(-size,size)
135
- track.close_path.fill
136
- when :left
137
- track.move_to(x,y)
138
- track.rel_line_to(-size,size)
139
- track.rel_line_to(size,size)
140
- track.close_path.fill
141
- when :north
142
- track.move_to(x-size,y+size)
143
- track.rel_line_to(size,-size)
144
- track.rel_line_to(size,size)
145
- track.close_path.fill
146
- when :south
147
- track.move_to(x-size,y-size)
148
- track.rel_line_to(size,size)
149
- track.rel_line_to(size,-size)
150
- track.close_path.fill
151
- end
152
- end
153
-
154
- # Method to draw the connections (introns) of spliced glyphs. Not to
155
- # be used directly, but called by Feature#draw.
156
- def connector(track,from,to,top, color)
157
- line_width = track.line_width
158
- track.set_source_rgb([0,0,0])
159
- track.set_line_width(0.5)
160
- middle = from + ((to - from)/2)
161
- track.move_to(from, top+2)
162
- track.line_to(middle, top+7)
163
- track.line_to(to, top+2)
164
- track.stroke
165
- track.set_line_width(line_width)
166
- track.set_source_rgb(color)
167
- end
168
-
169
- # Adds the feature to the track cairo context. This method should not
170
- # be used directly by the user, but is called by
171
- # Bio::Graphics::Panel::Track.draw
172
- # ---
173
- # *Arguments*:
174
- # * _trackdrawing_ (required) :: the track cairo object
175
- # * _row_ (required) :: row within the track that this feature has
176
- # been bumped to
177
- # *Returns*:: FIXME: I don't know
178
- def draw(track_drawing)
179
- # We have to check if we want to change the glyph type from directed to
180
- # undirected
181
- # There are 2 cases where we don't want to draw arrows on
182
- # features:
183
- # (a) when the picture is really zoomed out, features are
184
- # so small that the arrow itself is too big
185
- # (b) if a directed feature on the fw strand extends beyond
186
- # the end of the picture, the arrow is out of view. This
187
- # is the same as considering the feature as undirected.
188
- # The same obviously goes for features on the reverse
189
- # strand that extend beyond the left side of the image.
190
- #
191
- # (a) Zoomed out
192
- replace_directed_with_undirected = false
193
- if (self.stop - self.start).to_f/self.track.panel.rescale_factor.to_f < 2
194
- replace_directed_with_undirected = true
195
- end
196
- # (b) Extending beyond borders picture
197
- if ( self.chopped_at_stop and self.strand = 1 ) or ( self.chopped_at_start and self.strand = -1 )
198
- replace_directed_with_undirected = true
199
- end
200
-
201
- local_feature_glyph = nil
202
- if self.track.glyph == :directed_generic and replace_directed_with_undirected
203
- local_feature_glyph = :generic
204
- elsif self.track.glyph == :directed_spliced and replace_directed_with_undirected
205
- local_feature_glyph = :spliced
206
- else
207
- local_feature_glyph = self.track.glyph
208
- end
209
-
210
- # And draw the thing.
211
- row = self.find_row
212
- top_pixel_of_feature = FEATURE_V_DISTANCE + (FEATURE_HEIGHT+FEATURE_V_DISTANCE)*row
213
- bottom_pixel_of_feature = top_pixel_of_feature + FEATURE_HEIGHT
214
-
215
- case local_feature_glyph
216
- # triangles are typical for features which have a 1 bp position (start == stop)
217
- when :triangle
218
- raise "Start and stop are not the same (necessary if you want triangle glyphs)" if self.start != self.stop
219
-
220
- # Need to get this for the imagemap
221
- left_pixel_of_feature = self.pixel_range_collection[0].start_pixel - FEATURE_ARROW_LENGTH
222
- right_pixel_of_feature = self.pixel_range_collection[0].stop_pixel + FEATURE_ARROW_LENGTH
223
- arrow(track_drawing,:north,left_pixel_of_feature + FEATURE_ARROW_LENGTH, top_pixel_of_feature, FEATURE_ARROW_LENGTH)
224
- track_drawing.close_path.stroke
225
- when :line
226
- left_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
227
- right_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
228
- track_drawing.move_to(left_pixel_of_feature,top_pixel_of_feature+FEATURE_ARROW_LENGTH)
229
- track_drawing.line_to(right_pixel_of_feature,top_pixel_of_feature+FEATURE_ARROW_LENGTH)
230
- track_drawing.stroke
231
-
232
- track_drawing.set_source_rgb([0,0,0])
233
- arrow(track_drawing,:right,left_pixel_of_feature,top_pixel_of_feature,FEATURE_ARROW_LENGTH)
234
- track_drawing.close_path.stroke
235
- arrow(track_drawing,:left,right_pixel_of_feature,top_pixel_of_feature,FEATURE_ARROW_LENGTH)
236
- track_drawing.close_path.stroke
237
-
238
- track_drawing.set_source_rgb(self.track.colour)
239
- when :directed_generic
240
- # Need to get this for the imagemap
241
- left_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
242
- right_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
243
- if self.strand == -1 # Reverse strand
244
- track_drawing.rectangle(left_pixel_of_feature+FEATURE_ARROW_LENGTH, top_pixel_of_feature, right_pixel_of_feature - left_pixel_of_feature - FEATURE_ARROW_LENGTH, FEATURE_HEIGHT).fill
245
- arrow(track_drawing,:left,left_pixel_of_feature+FEATURE_ARROW_LENGTH,top_pixel_of_feature,FEATURE_ARROW_LENGTH)
246
- track_drawing.close_path.fill
247
- else #default is forward strand
248
- track_drawing.rectangle(left_pixel_of_feature, top_pixel_of_feature, right_pixel_of_feature - left_pixel_of_feature - FEATURE_ARROW_LENGTH, FEATURE_HEIGHT).fill
249
- arrow(track_drawing,:right,right_pixel_of_feature-FEATURE_ARROW_LENGTH,top_pixel_of_feature,FEATURE_ARROW_LENGTH)
250
- track_drawing.close_path.fill
251
- end
252
- when :spliced
253
- gap_starts = Array.new
254
- gap_stops = Array.new
255
-
256
- # Need to get this for the imagemap
257
- left_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
258
- right_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
259
-
260
- # First draw the parts
261
- self.pixel_range_collection.sort_by{|pr| pr.start_pixel}.each do |pr|
262
- track_drawing.rectangle(pr.start_pixel, top_pixel_of_feature, (pr.stop_pixel - pr.start_pixel), FEATURE_HEIGHT).fill
263
- gap_starts.push(pr.stop_pixel)
264
- gap_stops.push(pr.start_pixel)
265
- end
266
-
267
- # And then draw the connections in the gaps
268
- # Start with removing the very first start and the very last stop.
269
- gap_starts.sort!.pop
270
- gap_stops.sort!.shift
271
-
272
- gap_starts.length.times do |gap_number|
273
- connector(track_drawing,gap_starts[gap_number].to_f,gap_stops[gap_number].to_f,top_pixel_of_feature,track.colour)
274
- end
275
-
276
- if self.hidden_subfeatures_at_stop
277
- from = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
278
- to = self.track.panel.width
279
- track_drawing.move_to(from, top_pixel_of_feature+5)
280
- track_drawing.line_to(to, top_pixel_of_feature+5)
281
- track_drawing.stroke
282
- end
283
-
284
- if self.hidden_subfeatures_at_start
285
- from = 1
286
- to = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
287
- track_drawing.move_to(from, top_pixel_of_feature+5)
288
- track_drawing.line_to(to, top_pixel_of_feature+5)
289
- track_drawing.stroke
290
- end
291
-
292
- when :directed_spliced
293
- gap_starts = Array.new
294
- gap_stops = Array.new
295
- # First draw the parts
296
- locations = self.location.sort_by{|l| l.from}
297
-
298
- # Need to get this for the imagemap
299
- left_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
300
- right_pixel_of_feature = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
301
-
302
- # Start with the one with the arrow
303
- pixel_ranges = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}
304
- range_with_arrow = nil
305
- if self.strand == -1 # reverse strand => box with arrow is first one
306
- range_with_arrow = pixel_ranges.shift
307
- track_drawing.rectangle((range_with_arrow.start_pixel)+FEATURE_ARROW_LENGTH, top_pixel_of_feature, range_with_arrow.stop_pixel - range_with_arrow.start_pixel - FEATURE_ARROW_LENGTH, FEATURE_HEIGHT).fill
308
- arrow(track_drawing,:left,range_with_arrow.start_pixel+FEATURE_ARROW_LENGTH, top_pixel_of_feature,FEATURE_ARROW_LENGTH)
309
- track_drawing.close_path.fill
310
- else # forward strand => box with arrow is last one
311
- range_with_arrow = pixel_ranges.pop
312
- track_drawing.rectangle(range_with_arrow.start_pixel, top_pixel_of_feature, range_with_arrow.stop_pixel - range_with_arrow.start_pixel - FEATURE_ARROW_LENGTH, FEATURE_HEIGHT).fill
313
- arrow(track_drawing,:right,range_with_arrow.stop_pixel-FEATURE_ARROW_LENGTH, top_pixel_of_feature,FEATURE_ARROW_LENGTH)
314
- track_drawing.close_path.fill
315
- end
316
- gap_starts.push(range_with_arrow.stop_pixel)
317
- gap_stops.push(range_with_arrow.start_pixel)
318
-
319
- # And then add the others
320
- pixel_ranges.each do |range|
321
- track_drawing.rectangle(range.start_pixel, top_pixel_of_feature, range.stop_pixel - range.start_pixel, FEATURE_HEIGHT).fill
322
- gap_starts.push(range.stop_pixel)
323
- gap_stops.push(range.start_pixel)
324
- end
325
-
326
- # And then draw the connections in the gaps
327
- # Start with removing the very first start and the very last stop.
328
- gap_starts.sort!.pop
329
- gap_stops.sort!.shift
330
-
331
- gap_starts.length.times do |gap_number|
332
- connector(track_drawing,gap_starts[gap_number].to_f,gap_stops[gap_number].to_f,top_pixel_of_feature,track.colour)
333
- end
334
-
335
- if self.hidden_subfeatures_at_stop
336
- from = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[-1].stop_pixel
337
- to = self.track.panel.width
338
- track_drawing.move_to(from, top_pixel_of_feature+FEATURE_ARROW_LENGTH)
339
- track_drawing.line_to(to, top_pixel_of_feature+FEATURE_ARROW_LENGTH)
340
- track_drawing.stroke
341
- end
342
-
343
- if self.hidden_subfeatures_at_start
344
- from = 1
345
- to = self.pixel_range_collection.sort_by{|pr| pr.start_pixel}[0].start_pixel
346
- track_drawing.move_to(from, top_pixel_of_feature+FEATURE_ARROW_LENGTH)
347
- track_drawing.line_to(to, top_pixel_of_feature+FEATURE_ARROW_LENGTH)
348
- track_drawing.stroke
349
- end
350
-
351
- else #treat as 'generic'
352
- left_pixel_of_feature, right_pixel_of_feature = self.pixel_range_collection[0].start_pixel, self.pixel_range_collection[0].stop_pixel
353
- track_drawing.rectangle(left_pixel_of_feature, top_pixel_of_feature, (right_pixel_of_feature - left_pixel_of_feature), FEATURE_HEIGHT).fill
354
- end
355
-
356
- # Add the label for the feature
357
- if self.track.show_label
358
- pango_layout = track_drawing.create_pango_layout
359
- pango_layout.text = self.name
360
- fdesc = Pango::FontDescription.new('Sans Serif')
361
- fdesc.set_size(8 * Pango::SCALE)
362
- pango_layout.font_description = fdesc
363
-
364
- text_range = self.start.floor..(self.start.floor + pango_layout.pixel_size[0]*self.track.panel.rescale_factor)
365
- if self.track.grid[row+1].nil?
366
- self.track.grid[row+1] = Array.new
367
- end
368
- self.track.grid[row].push(text_range)
369
- self.track.grid[row+1].push(text_range)
370
- track_drawing.move_to(left_pixel_of_feature, top_pixel_of_feature + TRACK_HEADER_HEIGHT)
371
- track_drawing.set_source_rgb(0,0,0)
372
- track_drawing.show_pango_layout(pango_layout)
373
- track_drawing.set_source_rgb(self.track.colour)
374
- end
375
-
376
-
377
- # And add the region to the image map
378
- if self.track.panel.clickable
379
- # Comment: we have to add the vertical_offset and TRACK_HEADER_HEIGHT!
380
- self.track.panel.image_map.elements.push(ImageMap::ImageMapElement.new(left_pixel_of_feature,
381
- top_pixel_of_feature + self.track.vertical_offset + TRACK_HEADER_HEIGHT,
382
- right_pixel_of_feature,
383
- bottom_pixel_of_feature + self.track.vertical_offset + TRACK_HEADER_HEIGHT,
384
- self.link
385
- ))
386
- end
387
- end
388
-
389
- # Calculates the row within the track where this feature should be
390
- # drawn. This method should not
391
- # be used directly by the user, but is called by
392
- # Bio::Graphics::Panel::Track::Feature.draw
393
- # ---
394
- # *Arguments*:: none
395
- # *Returns*:: row number
396
- def find_row
397
- row_found = false
398
-
399
- # We've got to find out what row to draw the feature on. If two
400
- # features overlap, one of them has to be 'bumped' down. So we'll
401
- # first try to draw a new feature at the top of the track. If
402
- # it however would overlap with another one, we'll bump it down
403
- # to the next row.
404
- feature_range = (self.start.floor..self.stop.ceil)
405
- row = 1
406
- row_available = true
407
- until row_found
408
- if ! self.track.grid[row].nil?
409
- self.track.grid[row].each do |covered|
410
- if feature_range.include?(covered.first) or covered.include?(feature_range.first)
411
- row_available = false
412
- end
413
- end
414
- end
415
-
416
- if ! row_available
417
- row += 1
418
- row_available = true
419
- else # We've found the place where to draw the feature.
420
- if self.track.grid[row].nil?
421
- self.track.grid[row] = Array.new
422
- end
423
- self.track.grid[row].push(feature_range)
424
- row_found = true
425
- end
426
- end
427
- return row
428
- end
429
-
430
- class PixelRange
431
- def initialize(start_pixel, stop_pixel)
432
- @start_pixel, @stop_pixel = start_pixel, stop_pixel
433
- end
434
- attr_accessor :start_pixel, :stop_pixel
435
- end
436
- end #Feature
437
- end #Track
438
- end #Panel
439
- end #Graphics
440
- end #Bio
1
+ #
2
+ # = bio/graphics/feature.rb - feature class
3
+ #
4
+ # Copyright:: Copyright (C) 2007, 2008
5
+ # Jan Aerts <jan.aerts@bbsrc.ac.uk>
6
+ # Charles Comstock <dgtized@gmail.com>
7
+ # License:: The Ruby License
8
+ #
9
+
10
+ # The Bio::Graphics::Feature class describes features to be
11
+ # placed on the graph. See Bio::Graphics documentation for explanation
12
+ # of interplay between different classes.
13
+ #
14
+ # The position of the Feature is a Bio::Locations object to make it possible
15
+ # to transparently work with simple and spliced features.
16
+ #
17
+ # The Bio::Graphics::Feature class inherits from Bio::Feature.
18
+ class Bio::Graphics::Feature
19
+ # !!Not to be used directly. Use
20
+ # Bio::Graphics::Track.add_feature instead!!
21
+ # A feature can not exist except within the confines of a
22
+ # Bio::Graphics::Track object.
23
+ #
24
+ #--
25
+ # This is necessary because the feature needs to know the colour and glyph,
26
+ # both of which are defined within the panel.
27
+ #++
28
+ #
29
+ # ---
30
+ # *Arguments*:
31
+ # * _track_ (required) :: Bio::Graphics::Track object that this
32
+ # feature belongs to
33
+ # * _feature_ _object_ (required) :: A Bio::Feature object (see bioruby)
34
+ # * _:label_ :: Label of the feature. Default = 'anonymous'
35
+ # * _:link_ :: URL for clickable images. Default = nil
36
+ # * _:glyph_ :: Glyph to use. Default = glyph of the track
37
+ # * _:colour_ :: Colour. Default = colour of the track
38
+ # *Returns*:: Bio::Graphics::Feature object
39
+ def initialize(track, feature_object, opts = {})
40
+ @track = track
41
+ @feature_object = feature_object
42
+ opts = {
43
+ :label => 'anonymous',
44
+ :link => nil,
45
+ :glyph => @track.glyph,
46
+ :colour => @track.colour
47
+ }.merge(opts)
48
+
49
+ @label = opts[:label]
50
+ @link = opts[:link]
51
+ @glyph = opts[:glyph]
52
+ @colour = opts[:colour]
53
+
54
+ @locations = @feature_object.locations
55
+
56
+ @start = @locations.collect{|l| l.from}.min.to_i
57
+ @stop = @locations.collect{|l| l.to}.max.to_i
58
+
59
+ # Create Bio::Graphics SubFeatures
60
+ # The drawing is handled by subfeatures. If there are no defined, the
61
+ # subfeatures array will just hold one element: the @feature_object of
62
+ # self.
63
+ @subfeatures = Array.new
64
+ if ! @feature_object.subfeatures.empty?
65
+ @feature_object.subfeatures.each do |subfeature|
66
+ @subfeatures.push(Bio::Graphics::SubFeature.new(self, subfeature, :glyph => @glyph, :colour => @colour))
67
+ end
68
+ else
69
+ @subfeatures.push(Bio::Graphics::SubFeature.new(self, @feature_object, :glyph => @glyph, :colour => @colour))
70
+ end
71
+
72
+ @left_pixel_of_subfeatures = Array.new
73
+ @right_pixel_of_subfeatures = Array.new
74
+ end
75
+
76
+ # The bioruby Bio::Feature object
77
+ attr_accessor :feature_object
78
+
79
+ attr_accessor :locations
80
+
81
+ # The Bio::Graphics SubFeatures
82
+ attr_accessor :subfeatures
83
+
84
+ # The track that this feature belongs to
85
+ attr_accessor :track
86
+
87
+ # The label of the feature
88
+ attr_accessor :label
89
+ alias :name :label
90
+
91
+ # The URL to be followed when the glyph for this feature is clicked
92
+ attr_accessor :link
93
+
94
+ # The glyph to use to draw this (sub)feature
95
+ attr_accessor :glyph
96
+
97
+ # The colour to use to draw this (sub)feature
98
+ attr_accessor :colour
99
+
100
+ attr_accessor :start, :stop
101
+ attr_accessor :left_pixel_of_feature, :top_pixel_of_feature
102
+ attr_accessor :left_pixel_of_subfeatures, :right_pixel_of_subfeatures
103
+
104
+ attr_accessor :vertical_offset
105
+
106
+ # Adds the feature to the track cairo context. This method should not
107
+ # be used directly by the user, but is called by
108
+ # Bio::Graphics::Track.draw
109
+ # ---
110
+ # *Arguments*:
111
+ # * _track_drawing_ (required) :: the track cairo object
112
+ # *Returns*:: FIXME: I don't know
113
+ def draw(panel_destination)
114
+ feature_context = Cairo::Context.new(panel_destination)
115
+
116
+ # Move the feature drawing down based on track it's in and the number
117
+ # of times is has to be bumped
118
+ row = self.find_row
119
+
120
+ @vertical_offset = self.track.vertical_offset + Bio::Graphics::TRACK_HEADER_HEIGHT + Bio::Graphics::FEATURE_V_DISTANCE
121
+ @vertical_offset += (Bio::Graphics::FEATURE_HEIGHT+Bio::Graphics::FEATURE_V_DISTANCE)*row
122
+
123
+ feature_context.translate(0, @vertical_offset)
124
+
125
+ # Let the subfeatures do the drawing.
126
+ @subfeatures.each do |subfeature|
127
+ subfeature.draw(feature_context)
128
+ end
129
+
130
+ @left_pixel_of_feature = @left_pixel_of_subfeatures.min
131
+ @right_pixel_of_feature = @right_pixel_of_subfeatures.max
132
+
133
+ # Add the label for the feature
134
+ if @track.show_label
135
+ pango_layout = feature_context.create_pango_layout
136
+ pango_layout.text = @label
137
+ fdesc = Pango::FontDescription.new('Sans Serif')
138
+ fdesc.set_size(8 * Pango::SCALE)
139
+ pango_layout.font_description = fdesc
140
+
141
+ text_range = @start.floor..(@start.floor + pango_layout.pixel_size[0]*@track.panel.rescale_factor)
142
+ if @track.grid[row+1].nil?
143
+ @track.grid[row+1] = Array.new
144
+ end
145
+ @track.grid[row].push(text_range)
146
+ @track.grid[row+1].push(text_range)
147
+ feature_context.move_to(@left_pixel_of_feature, Bio::Graphics::TRACK_HEADER_HEIGHT)
148
+ feature_context.set_source_rgb(0,0,0)
149
+ feature_context.show_pango_layout(pango_layout)
150
+ feature_context.set_source_rgb(@colour)
151
+ end
152
+
153
+
154
+ # And add the region to the image map
155
+ # Comment: we have to add the vertical_offset and TRACK_HEADER_HEIGHT!
156
+ @track.panel.image_map.add_element(@left_pixel_of_feature,
157
+ @vertical_offset,
158
+ @right_pixel_of_feature,
159
+ @vertical_offset + Bio::Graphics::FEATURE_HEIGHT,
160
+ @link
161
+ )
162
+ end
163
+
164
+ # Calculates the row within the track where this feature should be
165
+ # drawn. This method should not
166
+ # be used directly by the user, but is called by
167
+ # Bio::Graphics::Feature.draw
168
+ # ---
169
+ # *Arguments*:: none
170
+ # *Returns*:: row number
171
+ def find_row
172
+ row_found = false
173
+
174
+ # We've got to find out what row to draw the feature on. If two
175
+ # features overlap, one of them has to be 'bumped' down. So we'll
176
+ # first try to draw a new feature at the top of the track. If
177
+ # it however would overlap with another one, we'll bump it down
178
+ # to the next row.
179
+ feature_range = (@start.floor - 1..@stop.ceil + 1)
180
+ row = 1
181
+ row_available = true
182
+ until row_found
183
+ if ! @track.grid[row].nil?
184
+ @track.grid[row].each do |covered|
185
+ if feature_range.include?(covered.first) or covered.include?(feature_range.first)
186
+ row_available = false
187
+ end
188
+ end
189
+ if ! @track.grid[row+1].nil? #Still have to check if there is no label there.
190
+ @track.grid[row+1].each do |covered|
191
+ if feature_range.include?(covered.first) or covered.include?(feature_range.first)
192
+ row_available = false
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ if ! row_available
199
+ row += 1
200
+ row_available = true
201
+ else # We've found the place where to draw the feature.
202
+ if @track.grid[row].nil?
203
+ @track.grid[row] = Array.new
204
+ end
205
+ @track.grid[row].push(feature_range)
206
+ row_found = true
207
+ end
208
+ end
209
+ return row
210
+ end
211
+
212
+ end #Feature