bio-svgenes 0.3.0 → 0.3.1
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.
- data/Gemfile +2 -1
- data/Gemfile.lock +3 -1
- data/VERSION +1 -1
- data/bio-svgenes.gemspec +8 -15
- data/lib/bio/graphics/glyph.rb +149 -16
- data/lib/bio/graphics/mini_feature.rb +23 -0
- data/lib/bio/graphics/page.rb +315 -262
- data/lib/bio/graphics/primitive.rb +12 -3
- data/lib/bio/graphics/svgee.rb +19 -6
- data/lib/bio/graphics/track.rb +14 -5
- metadata +21 -15
- data/.DS_Store +0 -0
- data/doc/.DS_Store +0 -0
- data/doc/Bio/.DS_Store +0 -0
- data/examples/.DS_Store +0 -0
- data/examples/drawn_from_json.svg +0 -269
- data/examples/drawn_from_json2.svg +0 -467
- data/lib/.DS_Store +0 -0
- data/lib/bio/.DS_Store +0 -0
- data/test/gene.gff +0 -4
- data/test/test_bio-svgenes.rb +0 -7
data/Gemfile
CHANGED
|
@@ -7,8 +7,9 @@ source "http://rubygems.org"
|
|
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
|
8
8
|
group :development do
|
|
9
9
|
gem "shoulda", ">= 0"
|
|
10
|
-
gem "bundler", "
|
|
10
|
+
gem "bundler", ">= 1.0.0"
|
|
11
11
|
gem "jeweler", "~> 1.6.4"
|
|
12
12
|
gem "rcov", ">= 0"
|
|
13
13
|
gem "bio", ">= 1.4.2"
|
|
14
|
+
gem "json", ">=1.7"
|
|
14
15
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -7,6 +7,7 @@ GEM
|
|
|
7
7
|
bundler (~> 1.0)
|
|
8
8
|
git (>= 1.2.5)
|
|
9
9
|
rake
|
|
10
|
+
json (1.7.7)
|
|
10
11
|
rake (0.9.2.2)
|
|
11
12
|
rcov (0.9.11)
|
|
12
13
|
shoulda (2.11.3)
|
|
@@ -16,7 +17,8 @@ PLATFORMS
|
|
|
16
17
|
|
|
17
18
|
DEPENDENCIES
|
|
18
19
|
bio (>= 1.4.2)
|
|
19
|
-
bundler (
|
|
20
|
+
bundler (>= 1.0.0)
|
|
20
21
|
jeweler (~> 1.6.4)
|
|
22
|
+
json (>= 1.7)
|
|
21
23
|
rcov
|
|
22
24
|
shoulda
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.3.
|
|
1
|
+
0.3.1
|
data/bio-svgenes.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = "bio-svgenes"
|
|
8
|
-
s.version = "0.3.
|
|
8
|
+
s.version = "0.3.1"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Dan MacLean"]
|
|
12
|
-
s.date = "2013-03-
|
|
12
|
+
s.date = "2013-03-05"
|
|
13
13
|
s.description = "This bio-gem facilitates the creation of pretty, publication quality SVG images from feature data."
|
|
14
14
|
s.email = "maclean.daniel@gmail.com"
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -17,7 +17,6 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
"README.rdoc"
|
|
18
18
|
]
|
|
19
19
|
s.files = [
|
|
20
|
-
".DS_Store",
|
|
21
20
|
".document",
|
|
22
21
|
"Gemfile",
|
|
23
22
|
"Gemfile.lock",
|
|
@@ -26,9 +25,7 @@ Gem::Specification.new do |s|
|
|
|
26
25
|
"Rakefile",
|
|
27
26
|
"VERSION",
|
|
28
27
|
"bio-svgenes.gemspec",
|
|
29
|
-
"doc/.DS_Store",
|
|
30
28
|
"doc/Bio.html",
|
|
31
|
-
"doc/Bio/.DS_Store",
|
|
32
29
|
"doc/Bio/Graphics.html",
|
|
33
30
|
"doc/Bio/Graphics/Glyph.html",
|
|
34
31
|
"doc/Bio/Graphics/MiniFeature.html",
|
|
@@ -72,12 +69,9 @@ Gem::Specification.new do |s|
|
|
|
72
69
|
"doc/js/searcher.js",
|
|
73
70
|
"doc/rdoc.css",
|
|
74
71
|
"doc/table_of_contents.html",
|
|
75
|
-
"examples/.DS_Store",
|
|
76
72
|
"examples/annotate_snps.rb",
|
|
77
73
|
"examples/data.txt",
|
|
78
74
|
"examples/draw_from_json.rb",
|
|
79
|
-
"examples/drawn_from_json.svg",
|
|
80
|
-
"examples/drawn_from_json2.svg",
|
|
81
75
|
"examples/eg2.rb",
|
|
82
76
|
"examples/example.rb",
|
|
83
77
|
"examples/example.svg",
|
|
@@ -86,19 +80,15 @@ Gem::Specification.new do |s|
|
|
|
86
80
|
"examples/get_coverage_in_windows.rb",
|
|
87
81
|
"examples/make_example.rb",
|
|
88
82
|
"examples/transcripts.gff",
|
|
89
|
-
"lib/.DS_Store",
|
|
90
83
|
"lib/bio-svgenes.rb",
|
|
91
|
-
"lib/bio/.DS_Store",
|
|
92
84
|
"lib/bio/graphics/glyph.rb",
|
|
93
85
|
"lib/bio/graphics/mini_feature.rb",
|
|
94
86
|
"lib/bio/graphics/page.rb",
|
|
95
87
|
"lib/bio/graphics/primitive.rb",
|
|
96
88
|
"lib/bio/graphics/svgee.rb",
|
|
97
89
|
"lib/bio/graphics/track.rb",
|
|
98
|
-
"test/gene.gff",
|
|
99
90
|
"test/helper.rb",
|
|
100
91
|
"test/json_config.json",
|
|
101
|
-
"test/test_bio-svgenes.rb",
|
|
102
92
|
"test/test_glyph.rb",
|
|
103
93
|
"test/test_mini_feature.rb",
|
|
104
94
|
"test/test_page.rb",
|
|
@@ -118,23 +108,26 @@ Gem::Specification.new do |s|
|
|
|
118
108
|
|
|
119
109
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
120
110
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
|
121
|
-
s.add_development_dependency(%q<bundler>, ["
|
|
111
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
|
122
112
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
123
113
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
|
124
114
|
s.add_development_dependency(%q<bio>, [">= 1.4.2"])
|
|
115
|
+
s.add_development_dependency(%q<json>, [">= 1.7"])
|
|
125
116
|
else
|
|
126
117
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
127
|
-
s.add_dependency(%q<bundler>, ["
|
|
118
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
|
128
119
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
129
120
|
s.add_dependency(%q<rcov>, [">= 0"])
|
|
130
121
|
s.add_dependency(%q<bio>, [">= 1.4.2"])
|
|
122
|
+
s.add_dependency(%q<json>, [">= 1.7"])
|
|
131
123
|
end
|
|
132
124
|
else
|
|
133
125
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
134
|
-
s.add_dependency(%q<bundler>, ["
|
|
126
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
|
135
127
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
136
128
|
s.add_dependency(%q<rcov>, [">= 0"])
|
|
137
129
|
s.add_dependency(%q<bio>, [">= 1.4.2"])
|
|
130
|
+
s.add_dependency(%q<json>, [">= 1.7"])
|
|
138
131
|
end
|
|
139
132
|
end
|
|
140
133
|
|
data/lib/bio/graphics/glyph.rb
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
module Bio
|
|
2
2
|
class Graphics
|
|
3
|
+
#A Glyph is an array of Primitive objects, holding information about the type of Glyph being created.
|
|
4
|
+
#Each different type of Glyph has different arguments, pertaining to how the Glyph will be drawn and the parameters provided to SVGEE.
|
|
5
|
+
#
|
|
6
|
+
|
|
3
7
|
class Glyph
|
|
4
|
-
|
|
8
|
+
|
|
9
|
+
#The different type of Glyphs are:
|
|
10
|
+
#* generic
|
|
11
|
+
#* circle
|
|
12
|
+
#* directed
|
|
13
|
+
#* \down_triangle
|
|
14
|
+
#* \up_triangle
|
|
15
|
+
#* span
|
|
16
|
+
#* transcript
|
|
17
|
+
#* scale
|
|
18
|
+
#* label
|
|
19
|
+
#* histogram
|
|
20
|
+
|
|
21
|
+
attr_reader :glyphs
|
|
5
22
|
#holds a load of definitions for glyphs .. a glyph is an array of primitives...
|
|
6
23
|
@glyphs = [:generic, :directed, :transcript, :scale, :label, :histogram, :circle, :down_triangle, :up_triangle, :span]
|
|
7
|
-
|
|
24
|
+
#Creates a generic glyph, which is a rectangle
|
|
25
|
+
#
|
|
26
|
+
#+args+
|
|
27
|
+
#* height = the height of the Glyph (10)
|
|
28
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
29
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
30
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
31
|
+
#* x_round = x-axis radius of the ellipse used to round off the corners of the rectangle (1)
|
|
32
|
+
#* y_round = y-axis radius of the ellipse used to round off the corners of the rectangle (1)
|
|
33
|
+
#* style = the opacity of the fill color ("fill-opacity:0.4;")
|
|
34
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
35
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
36
|
+
|
|
8
37
|
def self.generic(args) #:x, :y, :width :fill, :stroke :stroke_width, :style, :height,
|
|
9
38
|
args = {
|
|
10
39
|
:height => 10,
|
|
@@ -15,8 +44,19 @@ class Glyph
|
|
|
15
44
|
:y_round => 1,
|
|
16
45
|
:style => "fill-opacity:0.4;"}.merge!(args)
|
|
17
46
|
[Bio::Graphics::Primitive.new(:rectangle, args)]
|
|
18
|
-
end
|
|
19
|
-
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#Creates a circular Glyph
|
|
50
|
+
#
|
|
51
|
+
#+args+
|
|
52
|
+
#* radius = the radius of the circle (10)
|
|
53
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
54
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
55
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
56
|
+
#* style = the opacity of the fill color
|
|
57
|
+
#* x = x-axis centre of the circle
|
|
58
|
+
#* y = y-axis centre of the circle
|
|
59
|
+
|
|
20
60
|
def self.circle(args)
|
|
21
61
|
args = {
|
|
22
62
|
:radius => 10,
|
|
@@ -30,7 +70,18 @@ class Glyph
|
|
|
30
70
|
[Bio::Graphics::Primitive.new(:circle, args)]
|
|
31
71
|
end
|
|
32
72
|
|
|
33
|
-
|
|
73
|
+
#Creates a polygon Glyph to indicate the direction in which the Glyph is pointing
|
|
74
|
+
#+args+
|
|
75
|
+
#* width = the width of the feature
|
|
76
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
77
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
78
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
79
|
+
#* style = the opacity of the fill color
|
|
80
|
+
#* strand = the strand on which the Glyph is located. May be '+' or '-'
|
|
81
|
+
#* points = the x and y axis points used to calculate the shape of the polygon
|
|
82
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
83
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
84
|
+
#The points of the polygon are calculated form the +x+ and +y+ co-ordinates
|
|
34
85
|
def self.directed(args) #:x, :y, :width :fill, :stroke :stroke_width, :style, :height
|
|
35
86
|
args = {
|
|
36
87
|
|
|
@@ -43,11 +94,22 @@ class Glyph
|
|
|
43
94
|
if args[:strand] == '-'
|
|
44
95
|
args[:points] = "#{args[:x]},#{args[:y]} #{args[:x] + args[:width]},#{args[:y]} #{args[:x] + args[:width]},#{args[:y] + args[:height] } #{args[:x]},#{args[:y] + (args[:height])} #{args[:x] - (args[:height] * 0.2)},#{args[:y] + (args[:height]/2)}"
|
|
45
96
|
else
|
|
46
|
-
args[:points] = "#{args[:x]},#{args[:y]} #{args[:x] + args[:width] - (args[:height] * 0.2)},#{args[:y]} #{args[:x] + args[:width]},#{args[:y] + (args[:height]/2) } #{args[:x] + args[:width] - (args[:height] * 0.2)},#{args[:y] + args[:height]} #{args[:x]},#{args[:y] + args[:height]}"
|
|
97
|
+
args[:points] = "#{args[:x]},#{args[:y]} #{args[:x] + args[:width] - (args[:height] * 0.2)},#{args[:y]} #{args[:x] + args[:width]},#{args[:y] + (args[:height]/2) } #{args[:x] + args[:width] - (args[:height] * 0.2)},#{args[:y] + args[:height]} #{args[:x]},#{args[:y] + args[:height]}"
|
|
98
|
+
|
|
47
99
|
end
|
|
48
100
|
[Bio::Graphics::Primitive.new(:polygon, args)]
|
|
49
101
|
end
|
|
50
|
-
|
|
102
|
+
#Creates a polygon Glyph for a downward-pointing triangle
|
|
103
|
+
#+args+
|
|
104
|
+
#* height = the height of the Glyph (10)
|
|
105
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
106
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
107
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
108
|
+
#* style = the opacity of the fill color ("fill-opacity:0.4;")
|
|
109
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
110
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
111
|
+
#The points of the triangle are calculated form the +x+ and +y+ co-ordinates
|
|
112
|
+
|
|
51
113
|
def self.down_triangle(args) #:x, :y, :width :fill, :stroke :stroke_width, :style, :height
|
|
52
114
|
args = {
|
|
53
115
|
|
|
@@ -56,10 +118,21 @@ class Glyph
|
|
|
56
118
|
:stroke => "black",
|
|
57
119
|
:stroke_width => 1,
|
|
58
120
|
:style => "fill-opacity:0.4;"}.merge!(args)
|
|
121
|
+
|
|
59
122
|
args[:points] = "#{args[:x]},#{args[:y]} #{args[:x] + args[:width]},#{args[:y]} #{ args[:x] + (args[:width]/2) },#{(args[:y] + args[:height]) }"
|
|
60
123
|
[Bio::Graphics::Primitive.new(:polygon, args)]
|
|
61
124
|
end
|
|
62
|
-
|
|
125
|
+
#Creates a polygon Glyph for an upward-pointing triangle
|
|
126
|
+
#+args+
|
|
127
|
+
#* height = the height of the Glyph (10)
|
|
128
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
129
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
130
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
131
|
+
#* style = the opacity of the fill color ("fill-opacity:0.4;")
|
|
132
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
133
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
134
|
+
#The points of the triangle are calculated form the +x+ and +y+ co-ordinates
|
|
135
|
+
|
|
63
136
|
def self.up_triangle(args) #:x, :y, :width :fill, :stroke :stroke_width, :style, :height
|
|
64
137
|
args = {
|
|
65
138
|
:height => 10,
|
|
@@ -70,7 +143,16 @@ class Glyph
|
|
|
70
143
|
args[:points] = "#{args[:x]},#{args[:y] + args[:height]} #{args[:x] + args[:width]},#{args[:y] + args[:height]} #{ args[:x] + (args[:width]/2) },#{args[:y] }"
|
|
71
144
|
[Bio::Graphics::Primitive.new(:polygon, args)]
|
|
72
145
|
end
|
|
73
|
-
|
|
146
|
+
#Creates a span glyph, which is a line
|
|
147
|
+
#
|
|
148
|
+
#+args+
|
|
149
|
+
#* height = the height of the Glyph (10)
|
|
150
|
+
#* fill_color = the fill colour of the Glyph ('red')
|
|
151
|
+
#* stroke = the outline colour of the Glyph ("black")
|
|
152
|
+
#* stroke_width = The width of the outline stroke (1)
|
|
153
|
+
#* style = the opacity of the fill color ("fill-opacity:0.4;")
|
|
154
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
155
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
74
156
|
def self.span(args)
|
|
75
157
|
args = {
|
|
76
158
|
:height => 10,
|
|
@@ -85,7 +167,26 @@ class Glyph
|
|
|
85
167
|
args[:y2] = args[:y]
|
|
86
168
|
[Bio::Graphics::Primitive.new(:line, args)]
|
|
87
169
|
end
|
|
88
|
-
|
|
170
|
+
#Creates a transcript glyph, which is a number of different types of Glyph, depending on the features
|
|
171
|
+
#within the transcript
|
|
172
|
+
#
|
|
173
|
+
#+args+
|
|
174
|
+
#* height = the height of the Glyph (10)
|
|
175
|
+
#* utr_fill_color = the fill colour of the Glyph ('black')
|
|
176
|
+
#* utr_stroke = the outline colour of the Glyph ("black")
|
|
177
|
+
#* utr_stroke_width = The width of the outline stroke (1)
|
|
178
|
+
#* exon_fill_color = the fill colour of the Glyph ('red')
|
|
179
|
+
#* exon_stroke = the outline colour of the Glyph ("black")
|
|
180
|
+
#* exon_stroke_width = The width of the outline stroke (1)
|
|
181
|
+
#* line_color = the colour for any line Glyphs
|
|
182
|
+
#* line_width = the width for any line Glyphs
|
|
183
|
+
#* exon_style = the opacity of the fill color for exons ("fill-opacity:0.4;")
|
|
184
|
+
#* utr_style = the opacity of the fill color for utrs
|
|
185
|
+
#* line_style = the opacity of the fill color for lines
|
|
186
|
+
#* block_gaps = ****I'm not sure what these are****
|
|
187
|
+
#* gap_marker = ****I'm not sure what these are****
|
|
188
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
189
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
89
190
|
def self.transcript(args)
|
|
90
191
|
args = {
|
|
91
192
|
:height => 10,
|
|
@@ -178,10 +279,19 @@ class Glyph
|
|
|
178
279
|
end
|
|
179
280
|
composite
|
|
180
281
|
end
|
|
181
|
-
|
|
282
|
+
#Creates the scale across the top of the SVG page
|
|
283
|
+
#
|
|
284
|
+
#+args+
|
|
285
|
+
#* start = the start of the scale
|
|
286
|
+
#* stop = the end of the scale
|
|
287
|
+
#* \number_of_intervals = the number of tick-marks on the scale to show the current position
|
|
288
|
+
#* page_width = the width of the page
|
|
289
|
+
#
|
|
290
|
+
#+returns+
|
|
291
|
+
#
|
|
292
|
+
#* An Array[http://www.ruby-doc.org/core-2.0/Array.html] of Primitive objects (of type 'line', 'rectangle' and 'text')
|
|
293
|
+
|
|
182
294
|
def self.scale(args)
|
|
183
|
-
|
|
184
|
-
|
|
185
295
|
first_mark = args[:start]
|
|
186
296
|
last_mark = args[:stop]
|
|
187
297
|
#(num.to_f / @nt_per_px_x.to_f)
|
|
@@ -217,7 +327,15 @@ class Glyph
|
|
|
217
327
|
end
|
|
218
328
|
return a
|
|
219
329
|
end
|
|
220
|
-
|
|
330
|
+
#Creates a label Glyph to write text
|
|
331
|
+
#
|
|
332
|
+
#+args+
|
|
333
|
+
#* text = the text to write
|
|
334
|
+
#* fill = the colour of the text ("black")
|
|
335
|
+
#* style = the style of writing ("font-family:monospace;")
|
|
336
|
+
#* x = the co-ordinates of the Glyph for the x-axis
|
|
337
|
+
#* y = the co-ordinates of the Glyph for the y-axis
|
|
338
|
+
|
|
221
339
|
def self.label(args)
|
|
222
340
|
[Bio::Graphics::Primitive.new(:text,
|
|
223
341
|
:text => args[:text],
|
|
@@ -226,11 +344,26 @@ class Glyph
|
|
|
226
344
|
:fill => "black",
|
|
227
345
|
:style => "font-family:monospace;")]
|
|
228
346
|
end
|
|
229
|
-
|
|
347
|
+
#The list of pre-defined gradients
|
|
230
348
|
def self.gradients #needs to know which of its gradients are predefined
|
|
231
349
|
[:red_white_h, :green_white_h, :blue_white_h, :yellow_white_h, :red_white_radial, :green_white_radial, :blue_white_radial, :yellow_white_radial ]
|
|
232
350
|
end
|
|
233
|
-
|
|
351
|
+
|
|
352
|
+
#Sets the the type (linear or radial) and colour of gradient for a pre-defined gradient
|
|
353
|
+
#along with the pertinent parameters for that type
|
|
354
|
+
#
|
|
355
|
+
#+args+
|
|
356
|
+
#* gradient = a pre-defined gradient
|
|
357
|
+
#The types of gradient are:
|
|
358
|
+
#* red_white_h
|
|
359
|
+
#* green_white_h
|
|
360
|
+
#* blue_white_h
|
|
361
|
+
#* yellow_white_h
|
|
362
|
+
#* red_white_radial
|
|
363
|
+
#* green_white_radial
|
|
364
|
+
#* blue_white_radial
|
|
365
|
+
#* yellow_white_radial
|
|
366
|
+
|
|
234
367
|
def self.gradient(gradient)
|
|
235
368
|
type, color = case gradient
|
|
236
369
|
when :red_white_h
|
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
module Bio
|
|
2
2
|
class Graphics
|
|
3
|
+
##
|
|
4
|
+
#The MiniFeature class represents any feature (e.g. a gene, transcript, exon, start codon, etc) on a track.
|
|
5
|
+
#
|
|
3
6
|
class MiniFeature
|
|
4
7
|
attr_accessor :start, :end, :strand, :exons, :utrs, :block_gaps, :segment_height, :id
|
|
8
|
+
#Creates a new MiniFeature
|
|
9
|
+
#
|
|
10
|
+
#_Arguments_
|
|
11
|
+
#* start = the start position of the feature
|
|
12
|
+
#* end = the end position of the feature
|
|
13
|
+
#* strand = the strand of the feature
|
|
14
|
+
#* exons = an array of exon positions
|
|
15
|
+
#* utrs = an array of utrs positions
|
|
16
|
+
#* \block_gaps = an array of regions with nothing to be drawn, e.g. introns
|
|
17
|
+
#* id = the name of the feature such as the gene name or transcript ID
|
|
18
|
+
#* \segment_height = the height of the current feature
|
|
19
|
+
#
|
|
20
|
+
#==Example usage
|
|
21
|
+
#
|
|
22
|
+
##@mini1 = Bio::Graphics::MiniFeature.new(:start=>3631, :end=>5899, :strand=>'+',
|
|
23
|
+
# :exons=>[4000, 4500, 4700, 5000], :utrs=>[3631, 3650], :segment_height=>5, :id=>"AT1G01010")
|
|
24
|
+
#
|
|
25
|
+
#===MiniFeatures and Tracks
|
|
26
|
+
#MiniFeatures are added to Track objects, with overlapping MiniFeatures being placed onto separate rows
|
|
27
|
+
#
|
|
5
28
|
def initialize(args)
|
|
6
29
|
@start = args[:start]
|
|
7
30
|
@end = args[:end]
|
data/lib/bio/graphics/page.rb
CHANGED
|
@@ -1,290 +1,343 @@
|
|
|
1
1
|
module Bio
|
|
2
2
|
class Graphics
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
#The Page class represents the top level container on which svg objects are written. It will contain a scale
|
|
6
|
+
#and all the tracks along with their features. The scale will start at the genomic co-ordinates of the start
|
|
7
|
+
#of the first feature and stop at the end of the last feature)
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Page
|
|
12
|
+
#Creates a new Page object.
|
|
13
|
+
#
|
|
14
|
+
#A new Page contains the following arguments:
|
|
15
|
+
#* height = the height of the page
|
|
16
|
+
#* width = the width of the page
|
|
17
|
+
#* style = includes the a background colour
|
|
18
|
+
#* svg = a new SVGEE object
|
|
19
|
+
#* scale_start = the scale-start of the page (1.0/0.0)
|
|
20
|
+
#* scale_stop = the scale-stop of the page (-1.0/0.0)
|
|
21
|
+
#* tracks = an array of track objects with loads of features in it...
|
|
22
|
+
#* nt_per_percent = the number of nucleotides that are represented by 1% of the page (1);
|
|
23
|
+
#* num_intervals = the number of intervals
|
|
24
|
+
#* track_top = the position of the top of the first track (30)
|
|
25
|
+
#
|
|
26
|
+
#A new page maybe set up as follows:
|
|
27
|
+
# @page = Bio::Graphics::Page.new(:width => 800,
|
|
28
|
+
# :height => 110, :number_of_intervals => 10)
|
|
29
|
+
#
|
|
30
|
+
def initialize(args)
|
|
31
|
+
@height = args[:height]
|
|
32
|
+
@width = args[:width]
|
|
33
|
+
args[:style] = "background-color:#{args[:background_color]};" if args[:background_color]
|
|
34
|
+
@svg = SVGEE.new(args)
|
|
35
|
+
@scale_start = 1.0/0.0
|
|
36
|
+
@scale_stop = -1.0/0.0
|
|
37
|
+
@tracks = [] #array of track objects with loads of features in it...
|
|
38
|
+
@nt_per_percent = 1;
|
|
39
|
+
@num_intervals = args[:number_of_intervals]
|
|
40
|
+
@track_top = 30
|
|
41
|
+
|
|
42
|
+
def @svg.update_height(height)
|
|
43
|
+
@height = height
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#def @svg.update_width(width)
|
|
47
|
+
# @width = width
|
|
48
|
+
#end
|
|
43
49
|
end
|
|
50
|
+
#Takes a custom-written json file and writes an svg page to file which will contain the given features described within the json file.
|
|
51
|
+
#* +args+ - a custom-written json file describing the parameters and resources needed for a new page
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
end
|
|
53
|
+
def self.from_json(args)
|
|
54
|
+
require 'rubygems'
|
|
55
|
+
require 'json'
|
|
56
|
+
data = JSON.parse(File.open(args[:json], 'r').read)
|
|
57
|
+
p = Page.new(:width => data["Page"]["width"],
|
|
58
|
+
:height => data["Page"]["height"],
|
|
59
|
+
:number_of_intervals => data["Page"]["intervals"])
|
|
60
|
+
data["Tracks"].each do |track|
|
|
61
|
+
#prep the track args
|
|
62
|
+
track_args = track.dup
|
|
63
|
+
track_args.delete("file")
|
|
64
|
+
track_args.delete("file_type")
|
|
65
|
+
track_args = track_args.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
|
|
66
|
+
##convert any of the pre-made gradient strings in the keys to symbol
|
|
67
|
+
track_args.each_key do |k|
|
|
68
|
+
next unless track_args[k].respond_to?(:to_sym)
|
|
69
|
+
track_args[k] = track_args[k].to_sym if Glyph.gradients.include?(track_args[k].to_sym)
|
|
63
70
|
end
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
|
|
72
|
+
svg_track = p.add_track(track_args)
|
|
73
|
+
features = [] ##set up the features...
|
|
74
|
+
|
|
75
|
+
case track["file_type"] ##deal with the gff and data files
|
|
76
|
+
when "gff"
|
|
77
|
+
groups = {}
|
|
78
|
+
parentless_features = []
|
|
79
|
+
Page.parse_gff(track["file"]).each do |gff| #gets features in a list and links their children to them as members of the array at the key
|
|
80
|
+
parent_id = gff.attributes.select { |a| a.first == 'Parent' }
|
|
81
|
+
if parent_id.empty?
|
|
82
|
+
parentless_features << gff
|
|
83
|
+
else
|
|
84
|
+
if groups[parent_id.first.last].nil?
|
|
85
|
+
groups[parent_id.first.last] = []
|
|
86
|
+
groups[parent_id.first.last] << gff
|
|
87
|
+
else
|
|
88
|
+
groups[parent_id.first.last] << gff
|
|
89
|
+
end
|
|
90
|
+
end
|
|
79
91
|
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
#now flick through the parentless features and add any exons / UTRs
|
|
93
|
+
parentless_features.each do |plf|
|
|
94
|
+
require 'pp'
|
|
95
|
+
#pp parentless_features
|
|
96
|
+
gff_id = plf.attributes.select { |a| a.first == 'ID' }
|
|
97
|
+
gff_id = gff_id.first.last
|
|
98
|
+
exons = []
|
|
99
|
+
utrs = []
|
|
100
|
+
children = groups[gff_id] || children = []
|
|
101
|
+
children.each do |child|
|
|
102
|
+
if child.feature == 'exon' or child.feature == 'CDS'
|
|
103
|
+
exons += [child.start, child.end]
|
|
104
|
+
elsif child.feature =~ /utr/i
|
|
105
|
+
utrs += [child.start, child.end]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
features << MiniFeature.new(:start => plf.start, :end => plf.end, :exons => exons, :utrs => utrs, :strand => plf.strand, :id => gff_id)
|
|
109
|
+
end #parentless features end
|
|
110
|
+
when "data"
|
|
111
|
+
##each line is a data feature
|
|
112
|
+
File.open(track["file"], "r").each do |line|
|
|
113
|
+
start, stop, value = line.split(/\t/)
|
|
114
|
+
features << MiniFeature.new(:start => start.to_i, :end => stop.to_i, :segment_height => value.to_f)
|
|
115
|
+
end
|
|
116
|
+
end #data end
|
|
117
|
+
features.each { |f| svg_track.add(f) }
|
|
118
|
+
end #track end
|
|
119
|
+
p.write(args[:outfile])
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#Parses a GFF file into an Array of Bio::GFF::GFF3::Record[http://bioruby.org/rdoc/Bio/GFF/GFF3/Record.html] objects
|
|
123
|
+
#* +gff_file+ - a GFF-formatted file
|
|
124
|
+
#* +returns+ - an Array of Bio::GFF::GFF3::Record[http://bioruby.org/rdoc/Bio/GFF/GFF3/Record.html] objects
|
|
125
|
+
def self.parse_gff(gff_file)
|
|
126
|
+
require 'bio'
|
|
127
|
+
a = []
|
|
128
|
+
File.open(gff_file).each do |line|
|
|
129
|
+
next if line =~ /^#/
|
|
130
|
+
a << Bio::GFF::GFF3::Record.new(line)
|
|
88
131
|
end
|
|
89
|
-
|
|
90
|
-
features.each {|f| svg_track.add(f) }
|
|
91
|
-
end #track end
|
|
92
|
-
p.write(args[:outfile])
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def self.parse_gff(gff_file)
|
|
96
|
-
require 'bio'
|
|
97
|
-
a = []
|
|
98
|
-
File.open( gff_file ).each do |line|
|
|
99
|
-
next if line =~ /^#/
|
|
100
|
-
a << Bio::GFF::GFF3::Record.new(line)
|
|
101
|
-
end
|
|
102
|
-
a
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def add_track(args)
|
|
106
|
-
#sort out the colour/gradient options
|
|
107
|
-
[:fill_color, :exon_fill_color, :utr_fill_color].each do |colour_tag|
|
|
108
|
-
if Glyph.gradients.include?(args[colour_tag])
|
|
109
|
-
@svg.gradient(Glyph.gradient(args[colour_tag]) )
|
|
110
|
-
args[colour_tag] = "url(##{args[colour_tag]})"
|
|
111
|
-
elsif
|
|
112
|
-
args[colour_tag].instance_of?(Hash)
|
|
113
|
-
@svg.gradient(args[colour_tag])
|
|
114
|
-
args[colour_tag] = "url(##{args[colour_tag][:id]})"
|
|
132
|
+
a
|
|
115
133
|
end
|
|
116
|
-
end
|
|
117
|
-
@tracks << Track.new(args)
|
|
118
|
-
return @tracks.last
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def get_limits
|
|
122
|
-
@tracks.each do |track|
|
|
123
|
-
lowest = track.features.sort {|x,y| x.start <=> y.start}.first.start
|
|
124
|
-
highest = track.features.sort {|x,y| y.end <=> x.end}.first.end
|
|
125
|
-
@scale_start = lowest if lowest < @scale_start
|
|
126
|
-
@scale_stop = highest if highest > @scale_stop
|
|
127
|
-
@nt_per_px_x = (@scale_stop - @scale_start).to_f / @width.to_f
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def draw_scale
|
|
132
|
-
Glyph.scale(:start => @scale_start,
|
|
133
|
-
:stop => @scale_stop,
|
|
134
|
-
:number_of_intervals => @num_intervals, :page_width => @width).each {|g| @svg.add_primitive(g)}
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def draw_label(args)
|
|
138
|
-
Glyph.label(:text => args[:text],
|
|
139
|
-
:x => args[:x],
|
|
140
|
-
:y => args[:y] ).each {|g| @svg.add_primitive(g)}
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def draw_generic(args) #remember presentation info comes from track@args when the track is defined
|
|
144
|
-
Glyph.generic(args).each {|g| @svg.add_primitive(g) }
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def draw_directed(args)
|
|
148
|
-
Glyph.directed(args).each {|g| @svg.add_primitive(g) }
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def draw_circle(args)
|
|
152
|
-
Glyph.circle(args).each {|g| @svg.add_primitive(g) }
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def draw_transcript(args)
|
|
156
|
-
Glyph.transcript(args).each {|g| @svg.add_primitive(g) }
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def draw_histogram(args)
|
|
160
|
-
Glyph.generic(args).each {|g| @svg.add_primitive(g) }
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def draw_up_triangle(args)
|
|
164
|
-
Glyph.up_triangle(args).each {|g| @svg.add_primitive(g) }
|
|
165
|
-
end
|
|
166
134
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
135
|
+
#Calculates the colour or gradient for the supplied Bio::Graphics::Track objects and adds them to the Track array for the current Page
|
|
136
|
+
#* +args+ - an Array of Bio::Graphics::Track objects
|
|
137
|
+
#* +returns+ - the last element of the Track array
|
|
138
|
+
def add_track(args)
|
|
139
|
+
#sort out the colour/gradient options
|
|
140
|
+
[:fill_color, :exon_fill_color, :utr_fill_color].each do |colour_tag|
|
|
141
|
+
if Glyph.gradients.include?(args[colour_tag])
|
|
142
|
+
@svg.gradient(Glyph.gradient(args[colour_tag]))
|
|
143
|
+
args[colour_tag] = "url(##{args[colour_tag]})"
|
|
144
|
+
elsif args[colour_tag].instance_of?(Hash)
|
|
145
|
+
@svg.gradient(args[colour_tag])
|
|
146
|
+
args[colour_tag] = "url(##{args[colour_tag][:id]})"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
@tracks << Track.new(args)
|
|
150
|
+
return @tracks.last
|
|
151
|
+
end
|
|
170
152
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
153
|
+
#Calculates the Page scale-start and scale-stop position and the nucleotides per pixel for the current Page
|
|
154
|
+
def get_limits
|
|
155
|
+
@tracks.each do |track|
|
|
156
|
+
lowest = track.features.sort { |x, y| x.start <=> y.start }.first.start
|
|
157
|
+
highest = track.features.sort { |x, y| y.end <=> x.end }.first.end
|
|
158
|
+
@scale_start = lowest if lowest < @scale_start
|
|
159
|
+
@scale_stop = highest if highest > @scale_stop
|
|
160
|
+
@nt_per_px_x = (@scale_stop - @scale_start).to_f / @width.to_f
|
|
161
|
+
end
|
|
162
|
+
end
|
|
177
163
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
164
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
165
|
+
def draw_scale
|
|
166
|
+
Glyph.scale(:start => @scale_start,
|
|
167
|
+
:stop => @scale_stop,
|
|
168
|
+
:number_of_intervals => @num_intervals, :page_width => @width).each { |g| @svg.add_primitive(g) }
|
|
169
|
+
end
|
|
170
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
171
|
+
#* +args+ - an Array of Bio::Graphics::Primitive object
|
|
172
|
+
def draw_label(args)
|
|
173
|
+
Glyph.label(:text => args[:text],
|
|
174
|
+
:x => args[:x],
|
|
175
|
+
:y => args[:y]).each { |g| @svg.add_primitive(g) }
|
|
176
|
+
end
|
|
177
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
178
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
179
|
+
def draw_generic(args) #remember presentation info comes from track@args when the track is defined
|
|
180
|
+
Glyph.generic(args).each { |g| @svg.add_primitive(g) }
|
|
181
|
+
end
|
|
182
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
183
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
184
|
+
def draw_directed(args)
|
|
185
|
+
Glyph.directed(args).each { |g| @svg.add_primitive(g) }
|
|
186
|
+
end
|
|
187
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
188
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
189
|
+
def draw_circle(args)
|
|
190
|
+
Glyph.circle(args).each { |g| @svg.add_primitive(g) }
|
|
183
191
|
end
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
track.features.each do |f|
|
|
189
|
-
x = to_px(f.start - @scale_start)
|
|
190
|
-
width = to_px( (f.end - @scale_start) - (f.start - @scale_start) )
|
|
191
|
-
height = f.segment_height.to_f * data_per_px
|
|
192
|
-
y = @track_top + track.track_height - height + 5
|
|
193
|
-
#$stderr.puts f.segment_height, data_per_px, data_interval, max, min, "------"
|
|
194
|
-
self.send("draw_#{track.glyph}", {:x => x,
|
|
195
|
-
:y => y,
|
|
196
|
-
:width => width,
|
|
197
|
-
:height => height }.merge!(track.args) )
|
|
192
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
193
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
194
|
+
def draw_transcript(args)
|
|
195
|
+
Glyph.transcript(args).each { |g| @svg.add_primitive(g) }
|
|
198
196
|
end
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
198
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
199
|
+
def draw_histogram(args)
|
|
200
|
+
Glyph.generic(args).each { |g| @svg.add_primitive(g) }
|
|
201
|
+
end
|
|
202
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
203
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
204
|
+
def draw_up_triangle(args)
|
|
205
|
+
Glyph.up_triangle(args).each { |g| @svg.add_primitive(g) }
|
|
206
|
+
end
|
|
207
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
208
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
209
|
+
def draw_down_triangle(args)
|
|
210
|
+
Glyph.down_triangle(args).each { |g| @svg.add_primitive(g) }
|
|
211
|
+
end
|
|
212
|
+
#Adds the Bio::Graphics::Primitive objects to the SVGEE object
|
|
213
|
+
#* +args+ - an Array of Bio::Graphics::Primitive objects of the stated type
|
|
214
|
+
def draw_span(args)
|
|
215
|
+
Glyph.span(args).each { |g| @svg.add_primitive(g) }
|
|
203
216
|
end
|
|
204
|
-
track.get_rows ##work out how many rows and which features belong in each row...
|
|
205
|
-
track.features.each_with_index do |f,index|
|
|
206
|
-
x = to_px(f.start - @scale_start) #bottom left of feature
|
|
207
|
-
all_sub_blocks = []
|
|
208
217
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
exons << [to_px(exon[0] - @scale_start), to_px( (exon[1] - @scale_start) - (exon[0] - @scale_start) ) ]
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
f.exons = exons
|
|
218
|
+
#Takes a Bio::Graphics::Track object and sorts out the input information into a user friendly format.
|
|
219
|
+
#
|
|
220
|
+
#It examines the the type of track and calculates the required parameters
|
|
221
|
+
#* +args+ - an Array of Bio::Graphics::Track object
|
|
222
|
+
def draw_features(track)
|
|
223
|
+
if [:histogram, "histogram"].include?(track.glyph) #do different stuff for data tracks...
|
|
219
224
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
utrs << [to_px(utr[0] - @scale_start), to_px( (utr[1] - @scale_start) - (utr[0] - @scale_start) ) ]
|
|
225
|
+
y = @track_top + (track.track_height)
|
|
226
|
+
max = track.max_y ? track.max_y : track.features.sort { |a, b| a.segment_height <=> b.segment_height }.last.segment_height
|
|
227
|
+
min = 0
|
|
228
|
+
if track.label
|
|
229
|
+
draw_label(:text => track.name, :y => @track_top += 30, :x => 3)
|
|
226
230
|
end
|
|
227
|
-
|
|
228
|
-
|
|
231
|
+
draw_label(:text => max, :x => to_px(@scale_stop - @scale_start) + 5, :y => @track_top + 5)
|
|
232
|
+
draw_label(:text => min, :x => to_px(@scale_stop - @scale_start) + 5, :y => @track_top + track.track_height + 5)
|
|
233
|
+
data_interval = max - min
|
|
234
|
+
data_per_px = track.track_height.to_f / data_interval.to_f
|
|
235
|
+
track.features.each do |f|
|
|
236
|
+
x = to_px(f.start - @scale_start)
|
|
237
|
+
width = to_px((f.end - @scale_start) - (f.start - @scale_start))
|
|
238
|
+
height = f.segment_height.to_f * data_per_px
|
|
239
|
+
y = @track_top + track.track_height - height + 5
|
|
240
|
+
#$stderr.puts f.segment_height, data_per_px, data_interval, max, min, "------"
|
|
241
|
+
self.send("draw_#{track.glyph}", {:x => x,
|
|
242
|
+
:y => y,
|
|
243
|
+
:width => width,
|
|
244
|
+
:height => height}.merge!(track.args))
|
|
245
|
+
end
|
|
246
|
+
@track_top += (track.track_height) + 20
|
|
247
|
+
else ##following stuff for the features
|
|
248
|
+
if track.label
|
|
249
|
+
draw_label(:text => track.name, :y => @track_top += 30, :x => 3)
|
|
250
|
+
end
|
|
251
|
+
track.get_rows ##work out how many rows and which features belong in each row...
|
|
252
|
+
track.features.each_with_index do |f, index|
|
|
253
|
+
x = to_px(f.start - @scale_start) #bottom left of feature
|
|
254
|
+
all_sub_blocks = []
|
|
255
|
+
|
|
256
|
+
#convert the exon and utr start stops to px start stops and px widths
|
|
257
|
+
exons = []
|
|
258
|
+
if f.exons
|
|
259
|
+
f.exons.each_slice(2).each do |exon|
|
|
260
|
+
all_sub_blocks << exon
|
|
261
|
+
next if exon.nil?
|
|
262
|
+
exons << [to_px(exon[0] - @scale_start), to_px((exon[1] - @scale_start) - (exon[0] - @scale_start))]
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
f.exons = exons
|
|
266
|
+
|
|
267
|
+
utrs = []
|
|
268
|
+
if f.utrs
|
|
269
|
+
f.utrs.each_slice(2).each do |utr|
|
|
270
|
+
all_sub_blocks << utr
|
|
271
|
+
next if utr.nil?
|
|
272
|
+
utrs << [to_px(utr[0] - @scale_start), to_px((utr[1] - @scale_start) - (utr[0] - @scale_start))]
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
f.utrs = utrs
|
|
276
|
+
|
|
277
|
+
#if there are any intron like gaps.. get where they would be
|
|
278
|
+
if not all_sub_blocks.empty?
|
|
279
|
+
all_sub_blocks = all_sub_blocks.sort { |a, b| a.first <=> b.first }
|
|
280
|
+
all_sub_blocks.each_index do |i|
|
|
281
|
+
next if i + 1 == all_sub_blocks.length or all_sub_blocks[i].last >= all_sub_blocks[i + 1].first #skip if there is no gap
|
|
282
|
+
f.block_gaps << [to_px(all_sub_blocks[i].last - @scale_start), to_px((all_sub_blocks[i + 1].first - @scale_start) - (all_sub_blocks[i].last - @scale_start))]
|
|
283
|
+
end
|
|
284
|
+
end
|
|
229
285
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
286
|
+
width = to_px((f.end - @scale_start) - (f.start - @scale_start))
|
|
287
|
+
if track.min_width and width < track.min_width
|
|
288
|
+
width = track.min_width
|
|
289
|
+
end
|
|
290
|
+
y = @track_top + (track.feature_rows[index] * 2 * track.feature_height)
|
|
291
|
+
|
|
292
|
+
self.send("draw_#{track.glyph}", {:x => x,
|
|
293
|
+
:y => y,
|
|
294
|
+
:width => width,
|
|
295
|
+
:strand => f.strand,
|
|
296
|
+
:exons => f.exons,
|
|
297
|
+
:utrs => f.utrs,
|
|
298
|
+
:block_gaps => f.block_gaps,
|
|
299
|
+
:height => track.feature_height
|
|
300
|
+
}.merge!(track.args))
|
|
301
|
+
|
|
302
|
+
if f.id
|
|
303
|
+
draw_label(:y => y, :x => x + width +2, :text => f.id)
|
|
304
|
+
end
|
|
236
305
|
end
|
|
306
|
+
@track_top += (track.feature_height * track.number_rows * 2) + 20
|
|
237
307
|
end
|
|
238
308
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
end
|
|
243
|
-
y = @track_top + (track.feature_rows[index] * 2 * track.feature_height)
|
|
309
|
+
@height = @track_top + 100 #fudge...
|
|
310
|
+
@svg.update_height(@height)
|
|
311
|
+
#@svg.update_width(@width + 200)
|
|
244
312
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
313
|
+
end
|
|
314
|
+
#Provides the number of pixels required for a given number of nucleotides, e.g the length of a certain exon
|
|
315
|
+
#* +num+ - the number of nucleotides
|
|
316
|
+
#* +returns+ - the required number of pixels to draw the object
|
|
317
|
+
def to_px(num)
|
|
318
|
+
(num.to_f / @nt_per_px_x.to_f)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
#Pulls together all track information to create svg text which will draw all the features on the page to scale
|
|
322
|
+
#Uses the methods +get_limits+ and +draw_scale+ and then +draw_feature+ for each track on the page
|
|
323
|
+
def get_markup
|
|
324
|
+
get_limits
|
|
325
|
+
draw_scale
|
|
326
|
+
@tracks.each do |track|
|
|
327
|
+
draw_features(track)
|
|
257
328
|
end
|
|
329
|
+
@svg.draw
|
|
330
|
+
end
|
|
331
|
+
#Prints out the svg text
|
|
332
|
+
def draw
|
|
333
|
+
puts get_markup
|
|
258
334
|
end
|
|
259
|
-
@track_top += (track.feature_height * track.number_rows * 2) + 20
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
@height = @track_top + 100 #fudge...
|
|
263
|
-
@svg.update_height(@height)
|
|
264
|
-
#@svg.update_width(@width + 200)
|
|
265
335
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
def get_markup
|
|
273
|
-
get_limits
|
|
274
|
-
draw_scale
|
|
275
|
-
@tracks.each do |track|
|
|
276
|
-
draw_features(track)
|
|
336
|
+
#Writes the svg text to a file
|
|
337
|
+
#* +file+ - the file to which the svg text should be written
|
|
338
|
+
def write(file)
|
|
339
|
+
File.open(file, 'w').write(get_markup)
|
|
340
|
+
end
|
|
277
341
|
end
|
|
278
|
-
@svg.draw
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
def draw
|
|
282
|
-
puts get_markup
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def write(file)
|
|
286
|
-
File.open(file, 'w').write(get_markup)
|
|
287
342
|
end
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
343
|
end
|