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.
-
#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 |
#draw ⇒ Object
Prints the svg text to STDOUT
404 405 406 |
# File 'lib/bio/graphics/page.rb', line 404 def draw puts get_markup end |
#draw_circle(args) ⇒ Object
268 269 270 |
# File 'lib/bio/graphics/page.rb', line 268 def draw_circle(args) Glyph.circle(args).each { |g| @svg.add_primitive(g) } end |
#draw_directed(args) ⇒ Object
264 265 266 |
# File 'lib/bio/graphics/page.rb', line 264 def draw_directed(args) Glyph.directed(args).each { |g| @svg.add_primitive(g) } end |
#draw_down_triangle(args) ⇒ Object
284 285 286 |
# File 'lib/bio/graphics/page.rb', line 284 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
296 297 298 299 300 301 302 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 |
# File 'lib/bio/graphics/page.rb', line 296 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 ##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
260 261 262 |
# File 'lib/bio/graphics/page.rb', line 260 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
276 277 278 |
# File 'lib/bio/graphics/page.rb', line 276 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
253 254 255 256 257 |
# File 'lib/bio/graphics/page.rb', line 253 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
245 246 247 248 249 |
# File 'lib/bio/graphics/page.rb', line 245 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
288 289 290 |
# File 'lib/bio/graphics/page.rb', line 288 def draw_span(args) Glyph.span(args).each { |g| @svg.add_primitive(g) } end |
#draw_transcript(args) ⇒ Object
272 273 274 |
# File 'lib/bio/graphics/page.rb', line 272 def draw_transcript(args) Glyph.transcript(args).each { |g| @svg.add_primitive(g) } end |
#draw_up_triangle(args) ⇒ Object
280 281 282 |
# File 'lib/bio/graphics/page.rb', line 280 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| feat_end = feat.end feat_end += (8 * @nt_per_px_x * feat.id.to_s.length).to_i if feat.id feat_end }.max @scale_stop = highest if highest > @scale_stop @nt_per_px_x = (@scale_stop - @scale_start).to_f / @width.to_f end end while (@nt_per_px_x - old_nt_per_px_x).abs > 1 end |
#get_markup ⇒ Object
generates the SVG text
395 396 397 398 399 400 401 402 |
# File 'lib/bio/graphics/page.rb', line 395 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
390 391 392 |
# File 'lib/bio/graphics/page.rb', line 390 def to_px(num) (num.to_f / @nt_per_px_x.to_f) end |
#write(file) ⇒ Object
Writes the SVG text to a file
409 410 411 |
# File 'lib/bio/graphics/page.rb', line 409 def write(file) File.open(file, 'w').write(get_markup) end |