Class: Bio::Graphics::Page
- Inherits:
-
Object
- Object
- Bio::Graphics::Page
- Defined in:
- lib/bio/graphics/page.rb
Overview
The Bio::Graphics::Page class represents the page of the final rendered SVG and is the top level container into which Bio::Graphics::Tracks are added. It will contain a scale and all the tracks along with their features. The scale is calculated will start at the genomic co-ordinates of the start of the first feature and stop at the end of the last feature)
Class Method Summary collapse
-
.from_json(args) ⇒ Object
Takes a custom-written json file and uses it to generate an SVG document based on the information in that page.
-
.parse_gff(gff_file) ⇒ Object
Parses a GFF file into an Array of Bio::GFF::GFF3::Record objects * gff_file - a GFF-formatted file * returns - an Array of Bio::GFF::GFF3::Record objects.
- .update_height(height) ⇒ Object
Instance Method Summary collapse
-
#add_track(args) ⇒ Object
adds a new Bio::Graphics::Track object to the current Bio::Graphics::Page object.
- #compute_boundaries(feature) ⇒ Object
-
#draw ⇒ Object
Prints the svg text to STDOUT.
- #draw_circle(args) ⇒ Object
- #draw_directed(args) ⇒ Object
- #draw_down_triangle(args) ⇒ Object
-
#draw_features(track) ⇒ Object
Takes a Bio::Graphics::Track object and does the work to draw features.
-
#draw_generic(args) ⇒ Object
remember presentation info comes from track@args when the track is defined.
- #draw_histogram(args) ⇒ Object
-
#draw_label(args) ⇒ Object
Adds the Bio::Graphics::Primitive objects to the SVGEE object *
args
- an Array of Bio::Graphics::Primitive object. -
#draw_scale ⇒ Object
Adds scale bar to the list of objects to be rendered in the final.
- #draw_span(args) ⇒ Object
- #draw_transcript(args) ⇒ Object
- #draw_up_triangle(args) ⇒ Object
-
#get_limits ⇒ Object
Calculates the Page scale-start and scale-stop position and the nucleotides per pixel for the current Page.
-
#get_markup ⇒ Object
generates the SVG text.
-
#initialize(args) ⇒ Page
constructor
Creates a new Page object.
-
#to_px(num) ⇒ Object
Calculates the pixel value for a given number.
-
#write(file) ⇒ Object
Writes the SVG text to a file.
Constructor Details
#initialize(args) ⇒ Page
Creates a new Page object.
args
-
:height = the minimum height of the rendered page
-
:width = the minimum width of the rendered page
-
:background_color = the background color of the page (default none), can be any SVG colour eg rgb(256,0,0) or #FF0000
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/bio/graphics/page.rb', line 16 def initialize(args) @height = args[:height] @width = args[:width] args[:style] = "background-color:#{args[:background_color]};" if args[:background_color] @svg = SVGEE.new(args) @scale_start = 1.0/0.0 @scale_stop = -1.0/0.0 @tracks = [] #array of track objects with loads of features in it... @nt_per_percent = 1; @num_intervals = args[:number_of_intervals] @track_top = 30 def @svg.update_height(height) @height = height end #def @svg.update_width(width) # @width = width #end end |
Class Method Details
.from_json(args) ⇒ Object
Takes a custom-written json file and uses it to generate an SVG document based on the information in that page.
-
:json a JSON file describing the parameters and files needed to build an SVG document
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/bio/graphics/page.rb', line 39 def self.from_json(args) require 'rubygems' require 'json' data = JSON.parse(File.open(args[:json], 'r').read) p = Page.new(:width => data["Page"]["width"], :height => data["Page"]["height"], :number_of_intervals => data["Page"]["intervals"]) data["Tracks"].each do |track| #prep the track args track_args = track.dup track_args.delete("file") track_args.delete("file_type") track_args = track_args.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo } ##convert any of the pre-made gradient strings in the keys to symbol track_args.each_key do |k| next unless track_args[k].respond_to?(:to_sym) track_args[k] = track_args[k].to_sym if Glyph.gradients.include?(track_args[k].to_sym) end svg_track = p.add_track(track_args) features = [] ##set up the features... case track["file_type"] ##deal with the gff and data files when "gff" groups = {} parentless_features = [] 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 parent_id = gff.attributes.select { |a| a.first == 'Parent' } if parent_id.empty? parentless_features << gff else if groups[parent_id.first.last].nil? groups[parent_id.first.last] = [] groups[parent_id.first.last] << gff else groups[parent_id.first.last] << gff end end end #now flick through the parentless features and add any exons / UTRs parentless_features.each do |plf| require 'pp' #pp parentless_features gff_id = plf.attributes.select { |a| a.first == 'ID' } gff_id = gff_id.first.last exons = [] utrs = [] children = groups[gff_id] || children = [] children.each do |child| if child.feature == 'exon' or child.feature == 'CDS' exons += [child.start, child.end] elsif child.feature =~ /utr/i utrs += [child.start, child.end] end end features << MiniFeature.new(:start => plf.start, :end => plf.end, :exons => exons, :utrs => utrs, :strand => plf.strand, :id => gff_id) end #parentless features end when "data" ##each line is a data feature File.open(track["file"], "r").each do |line| start, stop, value = line.split(/\t/) features << MiniFeature.new(:start => start.to_i, :end => stop.to_i, :segment_height => value.to_f) end end #data end features.each { |f| svg_track.add(f) } end #track end p.write(args[:outfile]) end |
.parse_gff(gff_file) ⇒ Object
Parses a GFF file into an Array of Bio::GFF::GFF3::Record objects
-
gff_file - a GFF-formatted file
-
returns - an Array of Bio::GFF::GFF3::Record objects
111 112 113 114 115 116 117 118 119 |
# File 'lib/bio/graphics/page.rb', line 111 def self.parse_gff(gff_file) require 'bio' a = [] File.open(gff_file).each do |line| next if line =~ /^#/ a << Bio::GFF::GFF3::Record.new(line) end a end |
.update_height(height) ⇒ Object
28 29 30 |
# File 'lib/bio/graphics/page.rb', line 28 def @svg.update_height(height) @height = height end |
Instance Method Details
#add_track(args) ⇒ Object
adds a new Bio::Graphics::Track object to the current Bio::Graphics::Page object
args
-
:glyph = one of Bio::Graphics::Glyphs#glyphs currently
- :generic, :directed, :transcript, :scale, :label, :histogram, :circle, :down_triangle, :up_triangle, :span
-
:stroke_color = the outline colour of the glyphs in the track (default = “black”), can be any SVG colour eg rgb(256,0,0) or #FF0000
-
:fill_color = the fill colour of the glyphs in the track (default = ‘red’), can be any SVG colour eg rgb(256,0,0) or #FF0000, or one of the built in gradient types Bio::Graphics::Glyph#gradients
- :red_white_h, :green_white_h, :blue_white_h, :yellow_white_h, :red_white_radial, :green_white_radial, :blue_white_radial, :yellow_white_radial
-
or a custom definition of a gradient {:type => :radial, :id => :custom, :cx => 5, :cy => 5, :r => 50, :fx => 50, :fy => 50,
:stops => [ { :offset => 0, :color => 'rgb(255,255,255)', :opacity => 0 }, { :offset => 100, :color => 'rgb(0,127,200)', :opacity => 1 }, ]
}
-
:track_height = minimum height for the track, will be modified automatically if more space is needed e.g for overlapping features (default = auto),
-
:name = a displayed name for the track (default = ‘feature_track’)
-
:label = display the name given to the track (default = true),
-
:stroke_width = width in pixels of the outline of the glyphs (default=1)
-
:x_round = x radius of the ellipse used to round off the corners of rectangles (default = 1)
-
:y_round = y radius of the ellipse used to round off the corners of rectangles (default = 1)
:utr_fill_color = the fill colour of the utr part of the glyph (default = ‘black’), can be any SVG colour eg rgb(256,0,0) or #FF0000, or one of the built in gradient types Bio::Graphics::Glyph#gradients
- :red_white_h, :green_white_h, :blue_white_h, :yellow_white_h, :red_white_radial, :green_white_radial, :blue_white_radial, :yellow_white_radial
-
or a custom definition of a gradient {:type => :radial, :id => :custom, :cx => 5, :cy => 5, :r => 50, :fx => 50, :fy => 50,
:stops => [ { :offset => 0, :color => 'rgb(255,255,255)', :opacity => 0 }, { :offset => 100, :color => 'rgb(0,127,200)', :opacity => 1 }, ]
}
-
:utr_stroke = the outline colour of the utr part of the glyph (default = “black”), can be any SVG colour eg rgb(256,0,0) or #FF0000
-
:utr_stroke_width = The width of the outline stroke for the utr part of the glyph (default = 1)
-
:exon_fill_color = the fill colour of the utr part of the glyph (default = ‘red’), can be any SVG colour eg rgb(256,0,0) or #FF0000, or one of the built in gradient types Bio::Graphics::Glyph#gradients or a custom definition of a gradient
- :red_white_h, :green_white_h, :blue_white_h, :yellow_white_h, :red_white_radial, :green_white_radial, :blue_white_radial, :yellow_white_radial
-
or a custom definition of a gradient {:type => :radial, :id => :custom, :cx => 5, :cy => 5, :r => 50, :fx => 50, :fy => 50,
:stops => [ { :offset => 0, :color => 'rgb(255,255,255)', :opacity => 0 }, { :offset => 100, :color => 'rgb(0,127,200)', :opacity => 1 }, ]
-
:exon_stroke = the outline colour of the exon part of the glyph (default = “black”) can be any SVG colour eg rgb(256,0,0) or #FF0000
-
:exon_stroke_width = The width of the outline stroke for the exon part of the glyph (default = 1)
-
:line_color = the colour for the line part that joins the blocks (default = ‘black’) can be any SVG colour eg rgb(256,0,0) or #FF0000
-
:line_width = the width ffor the line part that joins the blocks (default = 1)
-
:exon_style = an arbitrary SVG compliant style string eg “fill-opacity:0.4;”
-
:utr_style = an arbitrary SVG compliant style string eg “fill-opacity:0.4;”
-
:line_style = an arbitrary SVG compliant style string eg “fill-opacity:0.4;”
-
:gap_marker = style of the line between blocks - either angled or straight
returns
a new Bio::Graphics::Track object
-
-
-
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/bio/graphics/page.rb', line 206 def add_track(args) #sort out the colour/gradient options [:fill_color, :exon_fill_color, :utr_fill_color].each do |colour_tag| if Glyph.gradients.include?(args[colour_tag]) @svg.gradient(Glyph.gradient(args[colour_tag])) args[colour_tag] = "url(##{args[colour_tag]})" elsif args[colour_tag].instance_of?(Hash) @svg.gradient(args[colour_tag]) args[colour_tag] = "url(##{args[colour_tag][:id]})" end end @tracks << Track.new(args) return @tracks.last end |
#compute_boundaries(feature) ⇒ Object
244 245 246 247 248 |
# File 'lib/bio/graphics/page.rb', line 244 def compute_boundaries(feature) feat_end = feature.end feat_end += (8 * @nt_per_px_x * feature.id.to_s.length).to_i if feature.id and @nt_per_px_x [feature.start, feat_end] end |
#draw ⇒ Object
Prints the svg text to STDOUT
411 412 413 |
# File 'lib/bio/graphics/page.rb', line 411 def draw puts get_markup end |
#draw_circle(args) ⇒ Object
275 276 277 |
# File 'lib/bio/graphics/page.rb', line 275 def draw_circle(args) Glyph.circle(args).each { |g| @svg.add_primitive(g) } end |
#draw_directed(args) ⇒ Object
271 272 273 |
# File 'lib/bio/graphics/page.rb', line 271 def draw_directed(args) Glyph.directed(args).each { |g| @svg.add_primitive(g) } end |
#draw_down_triangle(args) ⇒ Object
291 292 293 |
# File 'lib/bio/graphics/page.rb', line 291 def draw_down_triangle(args) Glyph.down_triangle(args).each { |g| @svg.add_primitive(g) } end |
#draw_features(track) ⇒ Object
Takes a Bio::Graphics::Track object and does the work to draw features
It examines the the type of track and calculates the required parameters
-
args
- an Array of Bio::Graphics::Track object
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/bio/graphics/page.rb', line 303 def draw_features(track) if [:histogram, "histogram"].include?(track.glyph) #do different stuff for data tracks... y = @track_top + (track.track_height) max = track.max_y ? track.max_y : track.features.sort { |a, b| a.segment_height <=> b.segment_height }.last.segment_height min = 0 if track.label draw_label(:text => track.name, :y => @track_top += 30, :x => 3) end draw_label(:text => max, :x => to_px(@scale_stop - @scale_start) + 5, :y => @track_top + 5) draw_label(:text => min, :x => to_px(@scale_stop - @scale_start) + 5, :y => @track_top + track.track_height + 5) data_interval = max - min data_per_px = track.track_height.to_f / data_interval.to_f track.features.each do |f| x = to_px(f.start - @scale_start) width = to_px((f.end - @scale_start) - (f.start - @scale_start)) height = f.segment_height.to_f * data_per_px y = @track_top + track.track_height - height + 5 #$stderr.puts f.segment_height, data_per_px, data_interval, max, min, "------" self.send("draw_#{track.glyph}", {:x => x, :y => y, :width => width, :height => height}.merge!(track.args)) end @track_top += (track.track_height) + 20 else ##following stuff for the features if track.label draw_label(:text => track.name, :y => @track_top += 30, :x => 3) end track.get_rows(self) ##work out how many rows and which features belong in each row... track.features.each_with_index do |f, index| x = to_px(f.start - @scale_start) #bottom left of feature all_sub_blocks = [] #convert the exon and utr start stops to px start stops and px widths exons = [] if f.exons f.exons.each_slice(2).each do |exon| all_sub_blocks << exon next if exon.nil? exons << [to_px(exon[0] - @scale_start), to_px((exon[1] - @scale_start) - (exon[0] - @scale_start))] end end f.exons = exons utrs = [] if f.utrs f.utrs.each_slice(2).each do |utr| all_sub_blocks << utr next if utr.nil? utrs << [to_px(utr[0] - @scale_start), to_px((utr[1] - @scale_start) - (utr[0] - @scale_start))] end end f.utrs = utrs #if there are any intron like gaps.. get where they would be if not all_sub_blocks.empty? all_sub_blocks = all_sub_blocks.sort { |a, b| a.first <=> b.first } all_sub_blocks.each_index do |i| 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 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))] end end width = to_px((f.end - @scale_start) - (f.start - @scale_start)) if track.min_width and width < track.min_width width = track.min_width end y = @track_top + (track.feature_rows[index] * 2 * track.feature_height) self.send("draw_#{track.glyph}", {:x => x, :y => y, :width => width, :strand => f.strand, :exons => f.exons, :utrs => f.utrs, :block_gaps => f.block_gaps, :height => track.feature_height, :params => f.params }.merge!(track.args)) if f.id draw_label(:y => y, :x => x + width +2, :text => f.id) end end @track_top += (track.feature_height * track.number_rows * 2) + 20 end @height = @track_top + 100 #fudge... @svg.update_height(@height) #@svg.update_width(@width + 200) end |
#draw_generic(args) ⇒ Object
remember presentation info comes from track@args when the track is defined
267 268 269 |
# File 'lib/bio/graphics/page.rb', line 267 def draw_generic(args) #remember presentation info comes from track@args when the track is defined Glyph.generic(args).each { |g| @svg.add_primitive(g) } end |
#draw_histogram(args) ⇒ Object
283 284 285 |
# File 'lib/bio/graphics/page.rb', line 283 def draw_histogram(args) Glyph.generic(args).each { |g| @svg.add_primitive(g) } end |
#draw_label(args) ⇒ Object
Adds the Bio::Graphics::Primitive objects to the SVGEE object
-
args
- an Array of Bio::Graphics::Primitive object
260 261 262 263 264 |
# File 'lib/bio/graphics/page.rb', line 260 def draw_label(args) Glyph.label(:text => args[:text], :x => args[:x], :y => args[:y]).each { |g| @svg.add_primitive(g) } end |
#draw_scale ⇒ Object
Adds scale bar to the list of objects to be rendered in the final
252 253 254 255 256 |
# File 'lib/bio/graphics/page.rb', line 252 def draw_scale Glyph.scale(:start => @scale_start, :stop => @scale_stop, :number_of_intervals => @num_intervals, :page_width => @width).each { |g| @svg.add_primitive(g) } end |
#draw_span(args) ⇒ Object
295 296 297 |
# File 'lib/bio/graphics/page.rb', line 295 def draw_span(args) Glyph.span(args).each { |g| @svg.add_primitive(g) } end |
#draw_transcript(args) ⇒ Object
279 280 281 |
# File 'lib/bio/graphics/page.rb', line 279 def draw_transcript(args) Glyph.transcript(args).each { |g| @svg.add_primitive(g) } end |
#draw_up_triangle(args) ⇒ Object
287 288 289 |
# File 'lib/bio/graphics/page.rb', line 287 def draw_up_triangle(args) Glyph.up_triangle(args).each { |g| @svg.add_primitive(g) } end |
#get_limits ⇒ Object
Calculates the Page scale-start and scale-stop position and the nucleotides per pixel for the current Page
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/bio/graphics/page.rb', line 222 def get_limits @tracks.each do |track| lowest = track.features.sort { |x, y| x.start <=> y.start }.first.start highest = track.features.sort { |x, y| y.end <=> x.end }.first.end @scale_start = lowest if lowest < @scale_start @scale_stop = highest if highest > @scale_stop @nt_per_px_x = (@scale_stop - @scale_start).to_f / @width.to_f end begin old_nt_per_px_x = @nt_per_px_x @tracks.each do |track| highest = track.features.map { |feat| compute_boundaries(feat)[1] }.max if highest > @scale_stop @scale_stop = highest @nt_per_px_x = (@scale_stop - @scale_start).to_f / @width.to_f end end end while (@nt_per_px_x - old_nt_per_px_x).abs > 1 end |
#get_markup ⇒ Object
generates the SVG text
402 403 404 405 406 407 408 409 |
# File 'lib/bio/graphics/page.rb', line 402 def get_markup get_limits draw_scale @tracks.each do |track| draw_features(track) end @svg.draw end |
#to_px(num) ⇒ Object
Calculates the pixel value for a given number
397 398 399 |
# File 'lib/bio/graphics/page.rb', line 397 def to_px(num) (num.to_f / @nt_per_px_x.to_f) end |
#write(file) ⇒ Object
Writes the SVG text to a file
416 417 418 |
# File 'lib/bio/graphics/page.rb', line 416 def write(file) File.open(file, 'w').write(get_markup) end |