iroki 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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