module Iroki::Main

Public Class Methods

iroki_job(color_branches: nil, color_taxa_names: nil, exact: nil, remove_bootstraps_below: nil, color_map_f: nil, biom_f: nil, single_color: nil, name_map_f: nil, auto_color: nil, display_auto_color_options: nil, newick_f: nil, min_lumin: 35, max_lumin: 70) click to toggle source
# File lib/iroki/main/main.rb, line 140
def self.iroki_job(color_branches: nil,
                   color_taxa_names: nil,
                   exact: nil,
                   remove_bootstraps_below: nil,
                   color_map_f: nil,
                   biom_f: nil,
                   single_color: nil,
                   name_map_f: nil,
                   auto_color: nil,
                   display_auto_color_options: nil,
                   newick_f: nil,
                   min_lumin: 35,
                   max_lumin: 70)

  begin
    out_f = Tempfile.new "foo"

    self.main(color_branches: color_branches,
              color_taxa_names: color_taxa_names,
              exact: exact,
              remove_bootstraps_below: remove_bootstraps_below,
              color_map_f: color_map_f,
              biom_f: biom_f,
              single_color: single_color,
              name_map_f: name_map_f,
              auto_color: auto_color,
              display_auto_color_options: display_auto_color_options,
              newick_f: newick_f,
              out_f: out_f,
              min_lumin: min_lumin,
              max_lumin: max_lumin)
  ensure
    if out_f
      out_f.close
      out_f.unlink
    end
  end
end
main(color_branches: nil, color_taxa_names: nil, exact: nil, remove_bootstraps_below: nil, color_map_f: nil, biom_f: nil, single_color: nil, name_map_f: nil, auto_color: nil, display_auto_color_options: nil, newick_f: nil, out_f: nil, default_color: "black", min_lumin: 35, max_lumin: 70) click to toggle source
# File lib/iroki/main/main.rb, line 179
    def self.main(color_branches: nil,
                  color_taxa_names: nil,
                  exact: nil,
                  remove_bootstraps_below: nil,
                  color_map_f: nil,
                  biom_f: nil,
                  single_color: nil,
                  name_map_f: nil,
                  auto_color: nil,
                  display_auto_color_options: nil,
                  newick_f: nil,
                  out_f: nil,
                  default_color: "black",
                  min_lumin: 35,
                  max_lumin: 70)

      args = method(__method__).parameters.map { |arg| arg[1] }
      AbortIf::logger.info "Args " + args.map { |arg| "#{arg} = #{eval(arg.to_s).inspect}" }.join(', ')

      if display_auto_color_options
        STDERR.puts "\n  Choices for --auto-color ..."
        STDERR.print "    - kelly: up to 19 high contrast colors\n\n#{Iroki::Color::Palette::KELLY_TEXT}\n\n"
        exit
      end

      auto_color_options = ["kelly"]

      abort_if !auto_color.nil? && !auto_color_options.include?(auto_color),
               "'#{auto_color}' is not a valid option. Try iroki --help for help."

      case auto_color
      when nil
        auto_color_hash = nil
      when "kelly"
        auto_color_hash = Iroki::Color::Palette::KELLY
      end

      abort_if single_color && biom_f.nil?,
               "--single-color was passed but no biom file was given"

      abort_if (biom_f || color_map_f) && color_branches.nil? && color_taxa_names.nil?,
               "No coloring options selected."

      newick = check_file newick_f, :newick

      abort_unless valid_newick?(newick_f),
                   "The Newick file doesn't look like a real Newick file"

      abort_if out_f.nil?,
               "--outfile is a required arg. Try iroki --help for help."

      if color_branches || color_taxa_names
        abort_if biom_f.nil? && color_map_f.nil?,
                 "Color options were provided, but no biom file " +
                 "or color map file was provided"
      end

      color_f = nil
      if !biom_f && (color_taxa_names || color_branches)
        color_f = check_file color_map_f, :color_map_f
      end

      check = color_map_f &&
              !color_taxa_names &&
              !color_branches

      abort_if check,
               "A color map file was provided without specifying " +
               "any coloring options"

      abort_if(newick_f &&
               color_map_f.nil? &&
               biom_f.nil? &&
               name_map_f.nil?,
               "Newick file was given but no other files were given")

      abort_if biom_f && !exact,
               "Regex matching cannot be used with a biom file. " +
               "Pass the --exact flag"

      # treeio = Bio::FlatFile.open(Bio::Newick, newick)

      # newick = treeio.next_entry
      str = File.read newick
      newick = Bio::Newick.new str, parser: :iroki

      # Warn if there is extra info in the newick file
      if newick &&
         newick.entry_overrun &&
         !newick.entry_overrun.chomp.empty?

        AbortIf.logger.warn {
          "Extra info (#{newick.entry_overrun}) in newick file " +
            "(#{newick_f}) will be ignored. " +
            "Does your newick file contain multiple trees?"
        }
      end

      tree = newick.tree

      # puts [:tree_first_parsed, tree.newick(indent: false)]

      iroki_to_name = Iroki::Tree.change_names tree


      #################################################################
      # parse name map
      ################

      if name_map_f
        name_map = parse_name_map name_map_f
      else
        name_map = nil
      end

      ################
      # parse name map
      #################################################################

      if name_map_f && color_map_f.nil? && biom_f.nil?
        AbortIf.logger.info "Only renaming was requested."
      end

      #################################################################
      # get color patterns
      ####################

      if biom_f
        samples, counts, is_single_group = Biom.open(biom_f, "rt").parse

        if is_single_group
          biom_patterns = SingleGroupGradient.new(samples,
                                                  counts,
                                                  single_color,
                                                  min_lumin,
                                                  max_lumin).patterns
        else
          abort_if single_color,
                   "--single-color is not compatible with a two " +
                   "group biom file. Please remove that option."

          g1_counts = counts.map(&:first)
          g2_counts = counts.map(&:last)
          biom_patterns = TwoGroupGradient.new(samples,
                                               g1_counts,
                                               g2_counts,
                                               min_lumin,
                                               max_lumin).patterns
        end
      end

      if color_map_f && biom_f
        color_map_patterns = parse_color_map_iroki color_map_f,
                                                   iroki_to_name,
                                                   exact_matching: exact,
                                                   auto_color: auto_color_hash

        # these patterns have the original name for the key, so change
        # the key to the iroki name
        name_to_iroki = iroki_to_name.invert
        biom_patterns_iroki_name = {}
        biom_patterns.each do |name, val|
          biom_patterns_iroki_name[name_to_iroki[name]] = val
        end

        patterns = biom_patterns_iroki_name.merge(color_map_patterns) do |key, oldval, newval|
          new_label = if !newval[:label].nil? && !newval[:label].empty?
                        newval[:label]
                      else
                        oldval[:label]
                      end

          new_branch = if !newval[:branch].nil? && !newval[:branch].empty?
                        newval[:branch]
                      else
                        oldval[:branch]
                      end

          { label: new_label, branch: new_branch }
        end
      elsif color_f
        patterns = parse_color_map_iroki color_f,
                                         iroki_to_name,
                                         exact_matching: exact,
                                         auto_color: auto_color_hash
      elsif biom_f
        patterns = biom_patterns

        # these patterns have the original name for the key, so change
        # the key to the iroki name
        name_to_iroki = iroki_to_name.invert
        h = {}
        patterns.each do |name, val|
          h[name_to_iroki[name]] = val
        end

        patterns = h
      else
        patterns = nil
      end

      # set default color if needed
      if default_color && default_color != "black"

        abort_if !default_color.hex? && !Iroki::Color::COLORS[default_color],
                 "--default-color must be a hex code (don't forget the '#' or a valid color. Got '#{default_color}'."

        Iroki::Color::default_color_tag = { label: Iroki::Color.get_tag(default_color),
                                            branch: Iroki::Color.get_tag(default_color), }
      end



      ####################
      # get color patterns
      #################################################################


      nil_val = { label: "", branch: "" }

      leaves_with_names = tree.leaves.reject { |leaf| leaf.name.nil? }
      if color_taxa_names
        leaves = leaves_with_names.map do |n|
          name = n.name#.clean_name

          if (color = add_color_to_leaf_branch(patterns, name, exact, iroki_to_name))
            name.single_quote + color[:label]
          else
            name.single_quote
          end
        end
      else
        leaves = leaves_with_names.map { |n| n.name.single_quote }
      end

      if color_branches
        total = tree.nodes.count
        n = 0
        tree.collect_node! do |node|
          n += 1
          $stderr.printf "Node: %d of %d\r", n, total

          color_nodes patterns, tree, node, exact, iroki_to_name
        end
      end
      $stderr.puts

      # if remove_bootstraps_below
      #   tree.collect_node! do |node|
      #     if node.bootstrap && node.bootstrap < remove_bootstraps_below
      #       node.bootstrap_string = ""
      #     end

      #     node
      #   end
      # end

      tre_str = tree.newick(indent: false)

      # this hash can be used regardless of whether a name map was used
      silly_iroki_to_name = {}
      iroki_to_name.each do |iname, oldname|
        if name_map && name_map.has_key?(oldname)
          silly_iroki_to_name[iname] = name_map[oldname]
        else
          silly_iroki_to_name[iname] = oldname
        end
      end

      nexus = "#NEXUS
begin taxa;
dimensions ntax=#{leaves.count};
taxlabels
#{leaves.join("\n").gsub(/iroki[0-9]+iroki/, silly_iroki_to_name)}
;
end;

begin trees;
  tree tree_1 = [&R] #{Iroki::Tree.gsub_iroki_newick_string tre_str, silly_iroki_to_name}
end;

#{FIG}"

      File.open(out_f, "w") { |f| f.puts nexus }

      nexus
    end