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 +4 -4
- data/.gitignore +2 -0
- data/README.md +4 -0
- data/exe/newick_to_phyloxml_color +132 -0
- data/exe/reorder_nodes +206 -0
- data/iroki.gemspec +1 -0
- data/lib/iroki/version.rb +1 -1
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e95553e4a9cc4572479c11aa9f5701e897e7fbd9
|
4
|
+
data.tar.gz: ff5b30ae95cdfb53e2c443877100f55cf3846e67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 538e1db4cdb5201363922f342f0a9ee9fd5100bfd59e0ff2d1e480034ac6591bd2355548b569b5011dbdeb3c34a589f3a811569f3bc65312b8bb6774bb45704f
|
7
|
+
data.tar.gz: 363ef46a8ff54ab9858c46d0f6cfdc04f270cb03933ed2378af3a818a9ba3d6ec70a2f1b4d050ebd1da4076f2862eb8a56e2e7e55773bdbccfe1809063c48beb
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -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
data/lib/iroki/version.rb
CHANGED
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.
|
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-
|
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
|