bio-graphics 1.2 → 1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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