Search code examples
rubyhistogramjruby

Using Ruby to construct a histogram from a hash


I am interested in displaying a histogram (output similar to matplotlib and not merely an ASCII 'text' version) from a hash in Ruby. Each hash key should be displayed as the 'label' of each bin with each key's respective value the frequency (y-axis). I attempted to use 'rinruby', but after multiple attempts, the program hangs. I'm using a Windows machine and JRuby 9.1.0.0. The gnuplot gem was rather confusing so I was wondering if anyone could offer a constructive suggestion. Please note that this is not a homework assignment.

# Import the 'bioruby' package
require 'bio'

# Construct a new hash object referenced by the variable 'aaf'
aaf = Hash.new(0)

# Construct a new array object referenced by 'aa'
aa  = []

# Prompt the user for a file name. Wrap the user input code in
# an exception handling block to create a more "robust" solution
begin
    print 'Please enter a file name: '

# Read the keyboard input as a string and remove the newline character.
# The input is summarily referenced by the 'filename' variable
    filename = gets.chomp()

# Display a blank line for formatting purposes
    puts()

# Open and read the file name provided and remove the newlines from the
# sequence file.
    seq = File.new(filename, 'r').read().chomp()

# Catch the exception thrown above, display the string, and return
# control to the 'begin' block for additional user input
rescue
    puts "I'm sorry. I was unable to locate that file."
    retry
end

# Create a new sequence object using the DNA sequence data obtained
# from the file name provided
seq = Bio::Sequence::NA.new(seq)

# Use the 'translate.names' method in the bioruby package to obtain
# the complete name of each amino acid in the 'seq' object and reference
# them via the 'aa' object
aa  = seq.translate.names

# Iterate / Loop over each amino acid name in the 'aa' array object using
# 'name' as a temporary variable. The name of each amino acid is
# associated with the frequency of occurrence. Example: 'Lysine 110' would
# indicate that 110 Lysine residues were contained in the original
# sequence file.
aa.each { |name|
    aaf[name] += 1
}

# Iterate / Loop over the newly populated hash structure while ignoring
# any line (key) that is a blank line (/^$/ is a regular expression anchor
# pattern that checks for the beginning, '^', and end, '$', of a line. The
# line (key) is blank if the 'if' statement returns a boolean result of true.
# A blank line in this instance would indicate the presence of a stop codon.
# Each amino acid and its respective frequency is displayed
aaf.each do |k, v|
    next if "#{k}" =~ /^$/
    print "#{k}", "->", "#{v}\n"
end

Thanks.


Solution

  • For easy charts I will use gnuplot (after dealing with the installation google for it), or ascii charts, using a ruby web framework i will use https://github.com/ankane/chartkick which use java script, but if you would easy thing with only installing a gem and a web browser to get the image:

    ╭─toni@Antonios-MBP  ~/learn/ruby/stackoverflow ‹ruby-2.2.3@stackoverflow› ‹1.7› ‹SBCL 1.3.5›
    ╰─$ gem install googlecharts
    Fetching: googlecharts-1.6.12.gem (100%)
    Successfully installed googlecharts-1.6.12
    Parsing documentation for googlecharts-1.6.12
    Installing ri documentation for googlecharts-1.6.12
    Done installing documentation for googlecharts after 0 seconds
    1 gem installed
    ╭─toni@Antonios-MBP  ~/learn/ruby/stackoverflow ‹ruby-2.2.3@stackoverflow› ‹1.7› ‹SBCL 1.3.5›
    ╰─$ irb
    2.2.3 :001 > require 'googlecharts'
     => true
    2.2.3 :003 > Gchart.bar(:data => [[300, 100, 30, 200], [100, 200, 300, 10]])
     => "http://chart.apis.google.com/chart?chd=s:uPEf,PfuB&cht=bvs&chs=300x200&chxr=0,300,300|1,100,300" 
    

    link to hystogram

    google charts doc

    I think that with ascii chart you can get, good results also

    require 'ascii_charts'
    
    irb(main):087:0> puts AsciiCharts::Cartesian.new({0 => 1, 1 => 3 , 2 => 7, 3 => 15, 4 => 4}, :bar => true, :hide_zero => true).draw
    
    
    15|      *   
    14|      *   
    13|      *   
    12|      *   
    11|      *   
    10|      *   
     9|      *   
     8|      *   
     7|    * *   
     6|    * *   
     5|    * *   
     4|    * * * 
     3|  * * * * 
     2|  * * * * 
     1|* * * * * 
     0+----------
       0 1 2 3 4 
    
    => nil