iroki 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3b375398b510f08d8c97c4361a2996788abd2bb
4
- data.tar.gz: b109a3a6bacea94e8aaa32c9d316a1fafb1bb899
3
+ metadata.gz: e95553e4a9cc4572479c11aa9f5701e897e7fbd9
4
+ data.tar.gz: ff5b30ae95cdfb53e2c443877100f55cf3846e67
5
5
  SHA512:
6
- metadata.gz: e92f0e993c5ffe7a1e7c767f33ff888d15ad4ef68695c14c2848c8d18c6f18fb860f3245677be5593bf24d821a786680c9de78be90734a05823301dd8d32f5b6
7
- data.tar.gz: e1336a5681c508bb861dee39a7d4ddebc1137d5f3ef5bc27ca703b9cc2de143ef36e6a90c84f27f35be5230afb69cdf6b0a9d25e1b48575517f485509b73cb8c
6
+ metadata.gz: 538e1db4cdb5201363922f342f0a9ee9fd5100bfd59e0ff2d1e480034ac6591bd2355548b569b5011dbdeb3c34a589f3a811569f3bc65312b8bb6774bb45704f
7
+ data.tar.gz: 363ef46a8ff54ab9858c46d0f6cfdc04f270cb03933ed2378af3a818a9ba3d6ec70a2f1b4d050ebd1da4076f2862eb8a56e2e7e55773bdbccfe1809063c48beb
data/.gitignore CHANGED
@@ -10,3 +10,5 @@
10
10
  *.lock
11
11
  .ruby-gemset
12
12
  newicks
13
+ test_files
14
+ sandbox
data/README.md CHANGED
@@ -100,3 +100,7 @@ Add `newick_to_phyloxml` script.
100
100
  ### 0.0.6 ###
101
101
 
102
102
  Add branch length and bootstraps to `newick_to_phyloxml`.
103
+
104
+ ### 0.0.7 ###
105
+
106
+ Add `reorder_nodes` script.
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # NOTE make sure the newick has no spaces for jsPhyloXML
4
+
5
+ # NOTE for Archaeopteryx, you need <name>#{boot}</name> to show
6
+ # bootsraps, but for jsPhyloXML, just the confidence is needed
7
+
8
+ require "set"
9
+ require "bio"
10
+ require "color"
11
+ require "abort_if"
12
+
13
+ include AbortIf
14
+
15
+ logger.warn { "This is an internal Iroki script. It is not meant for " +
16
+ "general use." }
17
+
18
+ def leaf? tree, node
19
+ tree.children(node).empty?
20
+ end
21
+
22
+ fname = ARGV.first
23
+
24
+ tree_str = File.open(fname, 'rt').read
25
+
26
+ newick = Bio::Newick.new(tree_str, parser: :naive)
27
+
28
+ $tree = newick.tree
29
+
30
+ $xml_start = %q{<phyloxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.phyloxml.org http://www.phyloxml.org/1.10/phyloxml.xsd" xmlns="http://www.phyloxml.org">
31
+ <phylogeny rooted="false">
32
+ <clade>
33
+ }
34
+
35
+ $xml_end = %q{</clade>
36
+ </phylogeny>
37
+ </phyloxml>
38
+ }
39
+
40
+ def leaf? tree, node
41
+ tree.descendents(node).count.zero?
42
+ end
43
+
44
+ def name_and_color node
45
+ m = node.name.match(/(.*)___ryan_([a-fA-F0-9]+)/)
46
+ if m
47
+ name = m[1]
48
+ hex = m[2]
49
+
50
+ col = Color::RGB.by_hex hex
51
+
52
+ [name, col]
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ def make_xml_string descendents, start_node
59
+ while (node = descendents.shift)
60
+ unless $already_added.include? node
61
+ ary = name_and_color(node)
62
+ new_name, col = ary
63
+
64
+ if leaf? $tree, node
65
+ # TODO this will raise something if no dist, rescue it
66
+ dist = $tree.distance(start_node, node)
67
+ dist = 1
68
+
69
+ if ary # then it needs color
70
+ color_xml = %Q{<color>
71
+ <red>#{col.red}</red>
72
+ <green>#{col.green}</green>
73
+ <blue>#{col.blue}</blue>
74
+ </color>
75
+ <property ref="style:font_color" datatype="xsd:token" applies_to="node">##{col.hex}</property>}
76
+ else
77
+ color_xml = ""
78
+ end
79
+
80
+ $xml_start << "<clade>
81
+ <name>#{ary ? new_name : node.name}</name>
82
+ <branch_length>#{dist}</branch_length>
83
+ #{color_xml}
84
+ </clade>\n"
85
+ $already_added << node
86
+ $prev_node = node
87
+ else
88
+ boot = node.bootstrap
89
+ if boot
90
+ boot_xml = %Q{\n<confidence type="bootstrap">#{boot}</confidence>}
91
+ else
92
+ boot_xml = ""
93
+ end
94
+
95
+ # TODO this will raise something if no dist, rescue it
96
+ dist = $tree.distance(start_node, node)
97
+ dist = 1
98
+
99
+ if ary # then it needs color
100
+ color_xml = "<color>
101
+ <red>#{col.red}</red>
102
+ <green>#{col.green}</green>
103
+ <blue>#{col.blue}</blue>
104
+ </color>"
105
+ else
106
+ color_xml = ""
107
+ end
108
+
109
+ $xml_start << "<clade>
110
+ <branch_length>#{dist}</branch_length>
111
+ #{boot_xml}
112
+ #{color_xml}"
113
+
114
+ STDERR.puts "LOG -- recurse"
115
+ make_xml_string $tree.descendents(node), node
116
+ $xml_start << "</clade>\n"
117
+ $already_added << node
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ $already_added = Set.new
124
+
125
+ start_node = $tree.root
126
+
127
+ $descendents = $tree.descendents(start_node)
128
+
129
+ make_xml_string $descendents, start_node
130
+
131
+ puts $xml_start
132
+ puts "#{$xml_end}"
data/exe/reorder_nodes ADDED
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bio"
4
+ require "trollop"
5
+ require "abort_if"
6
+
7
+ include AbortIf
8
+
9
+ module Math
10
+ def self.max ary
11
+ ary.max
12
+ end
13
+
14
+ def self.median ary
15
+ len = ary.length
16
+ if len > 0
17
+ sorted = ary.sort
18
+
19
+ if len.odd?
20
+ sorted[len / 2]
21
+ else
22
+ (sorted[(len-1) / 2] + sorted[len/2]) / 2.0
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.mean ary
28
+ len = ary.length
29
+ if len > 0
30
+ ary.reduce(:+) / len.to_f
31
+ end
32
+ end
33
+
34
+ def self.dist_for_comp metric, ary
35
+ self.send(metric, ary)
36
+ end
37
+
38
+ end
39
+
40
+ class Bio::Tree
41
+ def root_to_node_dist node
42
+ self.distance(self.root, node)
43
+ end
44
+
45
+ def root_to_node_dists nodes
46
+ nodes.map do |node|
47
+ root_to_node_dist node
48
+ end
49
+ end
50
+
51
+ def __to_newick(parents, source, depth, format_leaf,
52
+ options, &block)
53
+ result = []
54
+ if indent_string = __get_option(:indent, options) then
55
+ indent0 = indent_string * depth
56
+ indent = indent_string * (depth + 1)
57
+ newline = "\n"
58
+ else
59
+ indent0 = indent = newline = ''
60
+ end
61
+ out_edges = self.out_edges(source)
62
+ if block_given? then
63
+ out_edges.sort! { |edge1, edge2| yield(edge1[1], edge2[1]) }
64
+ else
65
+ # this sorts within clades
66
+ out_edges.sort! do |edge1, edge2|
67
+ n1 = edge1[1]
68
+ n2 = edge2[1]
69
+ # o1 = edge1[1].order_number
70
+ # o2 = edge2[1].order_number
71
+ d1 = edge1[2].distance
72
+ d2 = edge2[2].distance
73
+ # STDERR.puts
74
+ # STDERR.puts [:hi, edge1[0], edge1[1], d1, edge2[0], edge2[1], d2].inspect
75
+
76
+ n1_leaves = self.leaves(n1)
77
+ n2_leaves = self.leaves(n2)
78
+
79
+ dists_1 = root_to_node_dists n1_leaves
80
+ dists_2 = root_to_node_dists n2_leaves
81
+
82
+ the_dist_1 = Math.dist_for_comp COMP_METHOD, dists_1
83
+ the_dist_2 = Math.dist_for_comp COMP_METHOD, dists_2
84
+
85
+ # TODO check if leaves is empty
86
+ if the_dist_1 && the_dist_2
87
+ # STDERR.puts [:bye, the_dist_1, the_dist_2]
88
+ if LONG_ON_TOP
89
+ the_dist_2 <=> the_dist_1
90
+ else
91
+ the_dist_1 <=> the_dist_2
92
+ end
93
+ elsif the_dist_1 # first has leaves, it is "longer"
94
+ if LONG_ON_TOP
95
+ -1
96
+ else
97
+ 1
98
+ end
99
+ elsif the_dist_2 # second has leaves, second is longer
100
+ if LONG_ON_TOP
101
+ 1
102
+ else
103
+ -1
104
+ end
105
+ else # neither has leaves, use dist
106
+ if d1 and d2 then # check that both dists exist
107
+ if LONG_ON_TOP
108
+ d2 <=> d1
109
+ else
110
+ d1 <=> d2
111
+ end
112
+ else # just use the names
113
+ edge1[1].name.to_s <=> edge2[1].name.to_s
114
+ end
115
+ end
116
+ end
117
+ end
118
+ out_edges.each do |src, tgt, edge|
119
+ if parents.include?(tgt) then
120
+ ;;
121
+ elsif self.out_degree(tgt) == 1 then # target is a leaf?
122
+ # STDERR.puts "what is this? |#{src}| |#{tgt}|"
123
+ result << indent + __send__(format_leaf, tgt, edge, options)
124
+ else # target is an interior node
125
+ # STDERR.puts "recurse |#{src}| |#{tgt}|"
126
+ result <<
127
+ __to_newick([ src ].concat(parents), tgt, depth + 1,
128
+ format_leaf, options) +
129
+ __send__(format_leaf, tgt, edge, options)
130
+ end
131
+ end
132
+ indent0 + "(" + newline + result.join(',' + newline) +
133
+ (result.size > 0 ? newline : '') + indent0 + ')'
134
+ end
135
+ private :__to_newick
136
+ end
137
+
138
+ opts = Trollop.options do
139
+ banner <<-EOS
140
+
141
+ Synopsis
142
+ reorder_nodes [-o order] [-c comparison_method] -i newick.tre > newick.ordered.tre
143
+
144
+ Info
145
+ Given a newick file, reorder the nodes as directed.
146
+
147
+ Option details
148
+ --infile A newick file with a single tree
149
+ --order Order in which to display nodes: increasing or decreasing
150
+ --comparison Method to sort inner nodes: mean, median, max
151
+
152
+ Options
153
+
154
+ EOS
155
+
156
+ opt(:infile,
157
+ "input file",
158
+ type: :string)
159
+
160
+ opt(:order,
161
+ "increasing or decreasing",
162
+ type: :string,
163
+ default: "increasing")
164
+
165
+ opt(:comparison,
166
+ "mean, median, or max",
167
+ type: :string,
168
+ default: "max")
169
+ end
170
+
171
+ abort_unless %w[increasing decreasing].include?(opts[:order]),
172
+ "--order must be one of increasing or decreasing, " +
173
+ "got #{opts[:order]}.\nTry reorder_nodes --help for help."
174
+
175
+ if opts[:order] == "increasing"
176
+ LONG_ON_TOP = true
177
+ else
178
+ LONG_ON_TOP = false
179
+ end
180
+
181
+ abort_unless %w[mean median max].include?(opts[:comparison]),
182
+ "--comparison must be one of mean, median, or max, " +
183
+ "got #{opts[:comparison]}.\n" +
184
+ "Try reorder_nodes --help for help."
185
+
186
+ COMP_METHOD = opts[:comparison]
187
+
188
+ abort_unless opts[:infile],
189
+ "--infile is a required option. " +
190
+ "Try reorder_nodes --help for help."
191
+
192
+ abort_unless File.exists?(opts[:infile]),
193
+ "--infile #{opts[:infile]} does not exist.\n" +
194
+ "Try reorder_nodes --help for help."
195
+
196
+ fname = opts[:infile]
197
+
198
+ tree_str = File.open(fname, 'rt').read
199
+
200
+ # this only will work if there is only one tree
201
+ newick = Bio::Newick.new(tree_str, parser: :naive, indent: false)
202
+
203
+ tree = newick.tree
204
+
205
+ # warn tree_str
206
+ puts tree.newick
data/iroki.gemspec CHANGED
@@ -30,5 +30,6 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  spec.add_runtime_dependency "abort_if", "~> 0.1.0"
32
32
  spec.add_runtime_dependency "bio", "~> 1.5"
33
+ spec.add_runtime_dependency "color", "~> 1.8"
33
34
  spec.add_runtime_dependency "trollop", "~> 2.1", ">= 2.1.2"
34
35
  end
data/lib/iroki/version.rb CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  # Library metadata
20
20
  module Iroki
21
- VERSION = "0.0.6"
21
+ VERSION = "0.0.7"
22
22
  COPYRIGHT = "2015 - 2016 Ryan Moore"
23
23
  CONTACT = "moorer@udel.edu"
24
24
  WEBSITE = "https://github.com/mooreryan/iroki"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iroki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Moore
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-22 00:00:00.000000000 Z
11
+ date: 2016-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: '1.5'
131
+ - !ruby/object:Gem::Dependency
132
+ name: color
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.8'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.8'
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: trollop
133
147
  requirement: !ruby/object:Gem::Requirement
@@ -155,6 +169,8 @@ email:
155
169
  executables:
156
170
  - iroki
157
171
  - newick_to_phyloxml
172
+ - newick_to_phyloxml_color
173
+ - reorder_nodes
158
174
  extensions: []
159
175
  extra_rdoc_files: []
160
176
  files:
@@ -174,6 +190,8 @@ files:
174
190
  - bin/setup
175
191
  - exe/iroki
176
192
  - exe/newick_to_phyloxml
193
+ - exe/newick_to_phyloxml_color
194
+ - exe/reorder_nodes
177
195
  - iroki.gemspec
178
196
  - lib/iroki.rb
179
197
  - lib/iroki/color/color.rb