require 'erb'
require 'fileutils'
require 'forwardable'
require 'json'
require 'genevalidator'
require 'genevalidator/output'
require 'genevalidator/version'
module GeneValidator
# produce GV results from a JSON previously produced from GV
class JsonToGVResults
class << self
extend Forwardable
def_delegators GeneValidator, :opt
def init
@opt = opt
@config = {
html_path: "#{@opt[:json_file]}.html",
plot_dir: "#{@opt[:json_file]}.html/files/json",
aux: File.expand_path(File.join(File.dirname(__FILE__), '../../aux')),
filename: File.basename(@opt[:json_file]),
output_max: 2500,
run_no: 0
}
@json_array = load_json_file
end
def run
init
GeneValidator.create_output_folder(@config[:html_path], @config[:aux])
@json_array.each do |row|
@config[:run_no] += 1
create_json_file(row)
output_html = output_filename
generate_html_header(output_html) unless File.exist?(output_html)
generate_html_query(output_html, row)
end
html_footer
calculate_overall_score
end
def load_json_file
json_contents = File.read(File.expand_path(@opt[:json_file]))
JSON.load(json_contents)
end
def create_json_file(row)
@json_file = File.join(@config[:plot_dir],
"#{@config[:filename]}_#{row['idx']}.json")
File.open(@json_file, 'w') { |f| f.write(row.to_json) }
end
def output_filename
i = (@config[:run_no].to_f / @config[:output_max]).ceil
File.join(@config[:html_path], "results#{i}.html")
end
def generate_html_header(output_html)
return if File.exist?(output_html)
json_header_template = File.join(@config[:aux], 'json_header.erb')
template_contents = File.open(json_header_template, 'r').read
erb = ERB.new(template_contents, 0, '>')
File.open(output_html, 'w+') { |f| f.write(erb.result(binding)) }
end
def generate_html_query(output_html, row)
@row = row
json_query_template = File.join(@config[:aux], 'json_query.erb')
template_contents = File.open(json_query_template, 'r').read
erb = ERB.new(template_contents, 0, '>')
File.open(output_html, 'a') { |f| f.write(erb.result(binding)) }
end
# Add footer to all output files
def html_footer
no_of_output_files = (@config[:run_no].to_f / @config[:output_max]).ceil
output_files = []
(1..no_of_output_files).each { |i| output_files << "results#{i}.html" }
write_html_footer(no_of_output_files, output_files)
end
def write_html_footer(no_of_output_files, output_files)
turn_off_automated_sorting
json_footer_template = File.join(@config[:aux], 'json_footer.erb')
template_contents = File.open(json_footer_template, 'r').read
erb = ERB.new(template_contents, 0, '>')
(1..no_of_output_files).each do |i|
results_html = File.join(@config[:html_path], "results#{i}.html")
File.open(results_html, 'a+') { |f| f.write(erb.result(binding)) }
end
end
# By default, on page load, the results are automatically sorted by the
# index. However since the whole idea is that users would sort by JSON,
# this is not wanted here.
def turn_off_automated_sorting
script_file = File.join(@config[:html_path],
'files/js/genevalidator.compiled.min.js')
original_content = File.read(script_file)
# removes the automatic sort on page load
updated_content = original_content.gsub(',sortList:[[0,0]]', '')
File.open("#{script_file}.tmp", 'w') { |f| f.puts updated_content }
FileUtils.mv("#{script_file}.tmp", script_file)
end
def calculate_overall_score
scores = []
@json_array.each { |row| scores << row['overall_score'] }
plot_dir = File.join(@config[:html_path], 'files/json')
less = generate_evaluation(scores)
Output.create_overview_json(scores, plot_dir, less, less)
end
def generate_evaluation(scores)
no_of_queries = scores.length
good_scores = scores.count { |s| s >= 75 }
bad_scores = scores.count { |s| s < 75 }
nee = calculate_no_quries_with_no_evidence # nee = no evidence
good_pred = (good_scores == 1) ? 'One' : "#{good_scores} are"
bad_pred = (bad_scores == 1) ? 'One' : "#{bad_scores} are"
eval = 'Overall Query Score Evaluation:
' \
"#{no_of_queries} predictions were validated, from which there" \
' were:
' \
"#{good_pred} good prediction(s),
" \
"#{bad_pred} possibly weak prediction(s).
"
return eval if nee == 0
eval << "#{nee} could not be evaluated due to the lack of" \
' evidence.
'
eval
end
# calculate number of queries that had warnings for all validations.
def calculate_no_quries_with_no_evidence
all_warnings = 0
@json_array.each do |row|
status = row['validations'].map { |_, h| h['status'] }
if status.count { |r| r == 'warning' } == status.length
all_warnings += 1
end
end
all_warnings
end
end
end
end