iroki 0.0.15 → 0.0.16

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: e30a41e17f340205589f09eb78d173bb539126b1
4
- data.tar.gz: 5a9b674ae4df9732e0925d66c98e586c97ef4759
3
+ metadata.gz: 1fb677d25e56e8cd82079e8a1d910c62432f24e6
4
+ data.tar.gz: 6a18a69751a71d0947f630ef3eabe276d1cc0d6c
5
5
  SHA512:
6
- metadata.gz: 21dd23152c6abc8b31a90e6044d18f33d91ad1b8516106b84ec2e7dd4010f470ef16ce35ca3eab2ba06d1e86c4bf0e22a8a50bfce366722ec86147c59b6348be
7
- data.tar.gz: 3396ff6d90f944b6b38f5d5a507922a9ef47f2cbcdc534a387a9cb214cab5c4fb6d220d74af4003be81efd5a74d2119c1e6b250058c3581c5b3eebb37db25f6a
6
+ metadata.gz: 381d8fb761e14bbd4f6be2746a4b6747964c77c80611988efa1e068da7699fbe8cac6416808d0c975a96daebd49563af97678a10b67e26c061a5dbb02d0c76c8
7
+ data.tar.gz: d28bee6b62b0973de7da3daefa58da5883363f913451628c40350a5f77ec2e7ac6228b928d1a78bf6edaf431c65cdf54e689e30878bc1f0731404fc55a0df63b
data/README.md CHANGED
@@ -139,3 +139,8 @@ Add `reorder_nodes` script.
139
139
  ### 0.0.15 ###
140
140
 
141
141
  - `.ruby-version` file was being weird when user didn't have the correct ruby
142
+
143
+ ### 0.0.16 ###
144
+
145
+ - Allow unusual characters in label names ([GitHub issue](https://github.com/mooreryan/iroki/issues/2))
146
+ - Fix no method `clean` bug ([GitHub issue](https://github.com/mooreryan/iroki/issues/3))
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="362.268" height="256" viewBox="0, 0, 362.268, 256">
4
+ <g id="Layer_1">
5
+ <g>
6
+ <text transform="matrix(1, 0, 0, 1, 181.134, 212.5)">
7
+ <tspan x="-144.702" y="-9.5" font-family="Raleway-Thin" font-size="36" fill="#000000">Phylogenetic Tree</tspan>
8
+ <tspan x="-91.458" y="32.5" font-family="Raleway-Thin" font-size="36" fill="#000000">Customizer</tspan>
9
+ </text>
10
+ <text transform="matrix(1, 0, 0, 1, 181.134, 84.5)">
11
+ <tspan x="-129.384" y="50.5" font-family="Raleway-Thin" font-size="144" fill="#000000">Iroki</tspan>
12
+ </text>
13
+ <path d="M14.634,160 L348.634,160" fill-opacity="0" stroke="#000000" stroke-width="1.5"/>
14
+ </g>
15
+ </g>
16
+ </svg>
Binary file
@@ -0,0 +1,3 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 -18 362 274" width="362pt" height="274pt" xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata> Produced by OmniGraffle 6.6 <dc:date>2016-08-08 18:14:28 +0000</dc:date></metadata><defs><font-face font-family="Raleway" font-size="36" panose-1="2 11 2 3 3 1 1 6 0 3" units-per-em="1000" underline-position="-75" underline-thickness="50" slope="0" x-height="528" cap-height="715" ascent="940.00244" descent="-233.99353" font-weight="300" font-stretch="condensed"><font-face-src><font-face-name name="Raleway-Thin"/></font-face-src></font-face><font-face font-family="Raleway" font-size="144" panose-1="2 11 2 3 3 1 1 6 0 3" units-per-em="1000" underline-position="-75" underline-thickness="50" slope="0" x-height="528" cap-height="715" ascent="940.00244" descent="-233.99353" font-weight="300" font-stretch="condensed"><font-face-src><font-face-name name="Raleway-Thin"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><text transform="translate(31.63405 161.5)" fill="black"><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="0" y="34" textLength="42.624">Ph</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="42.12" y="34" textLength="132.48">ylogene</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="174.456" y="34" textLength="46.152">tic </tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="219.6" y="34" textLength="21.6">T</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="237.24" y="34" textLength="11.628">r</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="247.932" y="34" textLength="50.868">ee </tspan></text><text transform="translate(84.87805 203.5)" fill="black"><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="0" y="34" textLength="73.404">Cust</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="72.936" y="34" textLength="78.12">omiz</tspan><tspan font-family="Raleway" font-size="36" font-weight="300" font-stretch="condensed" fill="black" x="150.552" y="34" textLength="32.364">er</tspan></text><text transform="translate(51.63405 -8.5)" fill="black"><tspan font-family="Raleway" font-size="144" font-weight="300" font-stretch="condensed" fill="black" x="0" y="135" textLength="77.904">Ir</tspan><tspan font-family="Raleway" font-size="144" font-weight="300" font-stretch="condensed" fill="black" x="74.16" y="135" textLength="184.608">oki</tspan></text><line x1="14.17608" y1="153" x2="348.17604" y2="153" stroke="black" stroke-linecap="round" stroke-linejoin="miter" stroke-width="1"/></g></g></svg>
data/lib/iroki.rb CHANGED
@@ -19,6 +19,7 @@
19
19
  require "abort_if"
20
20
 
21
21
  require "iroki/biom"
22
+ require "iroki/tree"
22
23
  require "iroki/version"
23
24
 
24
25
  require "iroki/const/const"
@@ -67,7 +67,7 @@ module Iroki
67
67
  assert pattern, "found no pattern"
68
68
 
69
69
  if exact_matching # TODO should this really be everytime?
70
- pattern = pattern.clean
70
+ pattern = pattern#.clean_name
71
71
  else
72
72
  # TODO flag bad regexp
73
73
  pattern = Regexp.new pattern
@@ -127,6 +127,95 @@ module Iroki
127
127
  patterns
128
128
  end
129
129
 
130
+ def parse_color_map_iroki( fname,
131
+ iroki_to_name,
132
+ exact_matching: true,
133
+ auto_color: false)
134
+
135
+
136
+ check_file fname, :color_map
137
+
138
+ name_to_iroki = iroki_to_name.invert
139
+
140
+ patterns = {}
141
+ Object::File.open(fname, "rt").each_line do |line|
142
+ unless line.start_with? "#"
143
+ label_tag = ""
144
+ branch_tag = ""
145
+
146
+ pattern, label_color, branch_color = line.chomp.split "\t"
147
+
148
+ # color = "black" if color.nil? || color.empty?
149
+
150
+ assert pattern, "found no pattern"
151
+
152
+ if exact_matching # TODO should this really be everytime?
153
+ # pattern = pattern.clean_name
154
+ if name_to_iroki.has_key? pattern
155
+ pattern = name_to_iroki[pattern]
156
+ else
157
+ assert false, "String '#{pattern}' has no match in #{name_to_iroki.inspect}"
158
+ end
159
+ else
160
+ # TODO flag bad regexp
161
+ pattern = Regexp.new pattern
162
+ end
163
+
164
+ if color_given?(label_color) && color_given?(branch_color)
165
+ abort_if(has_label_tag?(label_color) &&
166
+ has_label_tag?(branch_color),
167
+ "Label tag specified twice for '#{line}'")
168
+
169
+ abort_if(has_branch_tag?(label_color) &&
170
+ has_branch_tag?(branch_color),
171
+ "Branch tag specified twice for '#{line}'")
172
+ end
173
+
174
+ if color_given?(label_color) && !color_given?(branch_color)
175
+ if (color = has_label_tag? label_color)
176
+ label_tag = Iroki::Color.get_tag color, auto_color
177
+ elsif (color = has_branch_tag? label_color)
178
+ branch_tag = Iroki::Color.get_tag color, auto_color
179
+ else
180
+ label_tag = Iroki::Color.get_tag label_color, auto_color
181
+ branch_tag = Iroki::Color.get_tag label_color, auto_color
182
+ end
183
+ else
184
+ if color_given? label_color
185
+ if (color = has_label_tag? label_color)
186
+ label_tag = Iroki::Color.get_tag color, auto_color
187
+ elsif (color = has_branch_tag? label_color)
188
+ branch_tag = Iroki::Color.get_tag color, auto_color
189
+ else
190
+ label_tag = Iroki::Color.get_tag label_color, auto_color
191
+ end
192
+ end
193
+
194
+ if color_given? branch_color
195
+ if (color = has_branch_tag? branch_color)
196
+ branch_tag = Iroki::Color.get_tag color, auto_color
197
+ elsif (color = has_label_tag? branch_color)
198
+ label_tag = Iroki::Color.get_tag color, auto_color
199
+ else
200
+ branch_tag = Iroki::Color.get_tag branch_color, auto_color
201
+ end
202
+ end
203
+ end
204
+
205
+ # if auto_color
206
+ # patterns[pattern] = "[&!color=\"#{auto_colors[color]}\"]"
207
+ # else
208
+ # patterns[pattern] = Iroki::Color.get_tag color, auto_color
209
+ # end
210
+
211
+ patterns[pattern] = { label: label_tag, branch: branch_tag }
212
+ end
213
+ end
214
+
215
+ patterns
216
+ end
217
+
218
+
130
219
  def parse_name_map fname
131
220
  check_file fname, :name_map
132
221
 
@@ -142,8 +231,8 @@ module Iroki
142
231
  abort_if newname.nil? || newname.empty?,
143
232
  "Column 2 missing for line: #{line.inspect}"
144
233
 
145
- oldname = oldname.clean
146
- newname = newname.clean
234
+ # oldname = oldname.clean_name
235
+ # newname = newname.clean_name
147
236
 
148
237
  abort_if name_map.has_key?(oldname),
149
238
  "#{oldname} is repeated in column 1"
@@ -2,29 +2,53 @@ module Iroki
2
2
  module CoreExt
3
3
  module String
4
4
 
5
+ def has_color?
6
+ self.match(/(.*)(\[&!color="#[0-9A-Fa-f]{6}"\])/)
7
+ end
8
+ alias already_checked? has_color?
9
+
5
10
  def hex?
6
11
  self.match(/^#[0-9A-Fa-f]{6}$/)
7
12
  end
8
13
 
9
14
  def clean
10
- self.strip.gsub(/[^\p{Alnum}_]+/, "_").gsub(/_+/, "_")
15
+ # puts %Q{clean: #{self}, #{self.gsub(/'/, '"')}}
16
+ self.gsub(/'/, '"')
11
17
  end
12
18
 
13
- def has_color?
14
- self.match(/(.*)(\[&!color="#[0-9A-Fa-f]{6}"\])/)
19
+ def single_quote
20
+ if self.match /\A'.*'\Z/
21
+ # puts %Q{single_quote if: #{self}, outputing #{self.dup}}
22
+ self.dup
23
+ else
24
+ # puts %Q{single_quote else: #{self}, returning '#{self.clean}'}
25
+ %Q['#{self.clean}']
26
+ end
15
27
  end
16
- alias already_checked? has_color?
17
28
 
18
29
  def clean_name
19
30
  if (match = self.has_color?)
20
31
  name = match[1]
21
32
  color = match[2]
22
33
 
23
- name.clean + color
34
+ # puts %Q{clean_name if: #{self}, returning #{name.single_quote + color}}
35
+ name.single_quote + color
36
+ # name + color
24
37
  else
25
- self.clean
38
+ # puts %Q{clean_name else: #{self}, returning #{self.single_quote}}
39
+ self.single_quote
26
40
  end
27
41
  end
42
+
43
+ def clean_strict
44
+ self.strip.gsub(/[^\p{Alnum}_]+/, "_").gsub(/_+/, "_")
45
+ end
46
+
47
+
48
+ def has_single_quote?
49
+ self.match(/'/)
50
+ end
51
+
28
52
  end
29
53
  end
30
54
  end
@@ -20,6 +20,121 @@ require "bio"
20
20
  require "set"
21
21
  require "trollop"
22
22
 
23
+ module Bio
24
+ class Tree
25
+ # formats Newick label (unquoted_label or quoted_label)
26
+ def __to_newick_format_label(str, options)
27
+ if __get_option(:parser, options) == :naive then
28
+ return str.to_s
29
+ end
30
+
31
+ str = str.to_s
32
+ if /([\(\)\,\:\[\]\_\'\x00-\x1f\x7f])/ =~ str then
33
+ # quoted_label
34
+ if __get_option(:parser, options) == :iroki
35
+ return str
36
+ else
37
+ return "\'" + str.gsub(/\'/, "\'\'") + "\'"
38
+ end
39
+ end
40
+ # unquoted_label
41
+ return str.gsub(/ /, '_')
42
+ end
43
+ private :__to_newick_format_label
44
+ end
45
+
46
+ class Newick
47
+ # splits string to tokens
48
+ def __parse_newick_tokenize(str, options)
49
+ str = str.chop if str[-1..-1] == ';'
50
+ # http://evolution.genetics.washington.edu/phylip/newick_doc.html
51
+ # quoted_label ==> ' string_of_printing_characters '
52
+ # single quote in quoted_label is '' (two single quotes)
53
+ #
54
+
55
+ if __get_option(:parser, options) == :naive then
56
+ ary = str.split(/([\(\)\,\:\[\]])/)
57
+ ary.collect! { |x| x.strip!; x.empty? ? nil : x }
58
+ ary.compact!
59
+ ary.collect! do |x|
60
+ if /\A([\(\)\,\:\[\]])\z/ =~ x then
61
+ x.intern
62
+ else
63
+ x
64
+ end
65
+ end
66
+ return ary
67
+ end
68
+
69
+ tokens = []
70
+ ss = StringScanner.new(str)
71
+
72
+ while !(ss.eos?)
73
+ if ss.scan(/\s+/) then
74
+ # do nothing
75
+
76
+ elsif ss.scan(/[\(\)\,\:\[\]]/) then
77
+ # '(' or ')' or ',' or ':' or '[' or ']'
78
+ t = ss.matched
79
+ tokens.push t.intern
80
+
81
+ elsif ss.scan(/\'/) then
82
+ # quoted_label
83
+ t = ''
84
+ while true
85
+ if ss.scan(/([^\']*)\'/) then
86
+ t.concat ss[1]
87
+ if ss.scan(/\'/) then
88
+ # single quote in quoted_label
89
+ t.concat ss.matched
90
+ else
91
+ break
92
+ end
93
+ else
94
+ # incomplete quoted_label?
95
+ break
96
+ end
97
+ end #while true
98
+ unless ss.match?(/\s*[\(\)\,\:\[\]]/) or ss.match?(/\s*\z/) then
99
+ # label continues? (illegal, but try to rescue)
100
+ if ss.scan(/[^\(\)\,\:\[\]]+/) then
101
+ t.concat ss.matched.lstrip
102
+ end
103
+ end
104
+ tokens.push t
105
+
106
+ elsif ss.scan(/[^\(\)\,\:\[\]]+/) then
107
+ # unquoted_label
108
+ t = ss.matched.strip
109
+ t.gsub!(/[\r\n]/, '')
110
+
111
+ unless __get_option(:parser, options) == :iroki then
112
+ # unquoted underscore should be converted to blank
113
+ t.gsub!(/\_/, ' ')
114
+ end
115
+ tokens.push t unless t.empty?
116
+
117
+ else
118
+ # unquoted_label in end of string
119
+ t = ss.rest.strip
120
+ t.gsub!(/[\r\n]/, '')
121
+
122
+ unless __get_option(:parser, options) == :iroki then
123
+ # unquoted underscore should be converted to blank
124
+ t.gsub!(/\_/, ' ')
125
+ end
126
+
127
+ tokens.push t unless t.empty?
128
+ ss.terminate
129
+
130
+ end
131
+ end #while !(ss.eos?)
132
+
133
+ tokens
134
+ end
135
+ end
136
+ end
137
+
23
138
  module Iroki
24
139
  module Main
25
140
  def self.main(color_branches: nil,
@@ -56,6 +171,7 @@ module Iroki
56
171
  abort_if single_color && biom_f.nil?,
57
172
  "--single-color was passed but no biom file was given"
58
173
 
174
+ # this should be allowed
59
175
  abort_if biom_f && color_map_f,
60
176
  "--color-map and --biom-file cannot both be specified. Try iroki --help for help."
61
177
 
@@ -92,12 +208,50 @@ module Iroki
92
208
  name_map_f.nil?,
93
209
  "Newick file was given but no other files were given")
94
210
 
95
- # get the color patterns
96
- if color_f
97
- patterns = parse_color_map color_f,
98
- exact_matching: exact,
99
- auto_color: auto_color_hash
211
+ # treeio = Bio::FlatFile.open(Bio::Newick, newick)
212
+
213
+ # newick = treeio.next_entry
214
+ str = File.read newick
215
+ newick = Bio::Newick.new str, parser: :iroki
216
+ tree = newick.tree
217
+
218
+ # puts [:tree_first_parsed, tree.newick(indent: false)]
219
+
220
+ iroki_to_name = Iroki::Tree.change_names tree
221
+
222
+
223
+ #################################################################
224
+ # parse name map
225
+ ################
226
+
227
+ if name_map_f
228
+ name_map = parse_name_map name_map_f
100
229
  else
230
+ name_map = nil
231
+ end
232
+
233
+ if name_map_f && color_map_f.nil? && biom_f.nil? # just name map
234
+ # put node names back
235
+ end
236
+
237
+ ################
238
+ # parse name map
239
+ #################################################################
240
+
241
+ if name_map_f && color_map_f.nil? && biom_f.nil?
242
+ AbortIf.logger.info "Only renaming was requested."
243
+ end
244
+
245
+ #################################################################
246
+ # get color patterns
247
+ ####################
248
+
249
+ if color_f
250
+ patterns = parse_color_map_iroki color_f,
251
+ iroki_to_name,
252
+ exact_matching: exact,
253
+ auto_color: auto_color_hash
254
+ elsif biom_f
101
255
  samples, counts, is_single_group = Biom.open(biom_f, "rt").parse
102
256
 
103
257
  if is_single_group
@@ -107,45 +261,59 @@ module Iroki
107
261
  g2_counts = counts.map(&:last)
108
262
  patterns = TwoGroupGradient.new(samples, g1_counts, g2_counts).patterns
109
263
  end
264
+
265
+ # these patterns have the original name for the key, so change
266
+ # the key to the iroki name
267
+ name_to_iroki = iroki_to_name.invert
268
+ h = {}
269
+ patterns.each do |name, val|
270
+ h[name_to_iroki[name]] = val
271
+ end
272
+
273
+ patterns = h
274
+ else
275
+ patterns = nil
110
276
  end
111
277
 
112
- treeio = Bio::FlatFile.open(Bio::Newick, newick)
278
+ ####################
279
+ # get color patterns
280
+ #################################################################
113
281
 
114
- newick = treeio.next_entry
115
- tree = newick.tree
282
+
283
+ # puts [:tree_after_change_names, tree.newick(indent: false)]
284
+ nil_val = { label: "", branch: "" }
116
285
 
117
286
  # do this first cos everything after will use the "new" names
118
- if name_map_f
119
- name_map = parse_name_map name_map_f
287
+ # if name_map_f
288
+ # name_map = parse_name_map name_map_f
120
289
 
121
- tree.collect_node! do |node|
122
- unless node.name.nil?
123
- # every name is cleaned no matter what
124
- node.name = clean node.name
290
+ # tree.collect_node! do |node|
291
+ # unless node.name.nil?
292
+ # # every name is cleaned no matter what
293
+ # # node.name = node.name.clean_name
125
294
 
126
- if name_map.has_key?(node.name)
127
- node.name = name_map[node.name]
128
- end
129
- end
295
+ # if name_map.has_key?(node.name)
296
+ # node.name = name_map[node.name]
297
+ # end
298
+ # end
130
299
 
131
- node
132
- end
133
- end
300
+ # node
301
+ # end
302
+ # end
134
303
 
135
304
  leaves_with_names = tree.leaves.reject { |leaf| leaf.name.nil? }
136
305
  if color_taxa_names
137
306
  leaves = leaves_with_names.map do |n|
138
- name = n.name.clean_name
307
+ name = n.name#.clean_name
139
308
 
140
- if (color = add_color_to_leaf_branch(patterns, name, exact))
141
- name + color[:label]
309
+ if (color = add_color_to_leaf_branch(patterns, name, exact, iroki_to_name))
310
+ name.single_quote + color[:label]
142
311
  else
143
- name
312
+ name.single_quote
144
313
  end
145
314
  end
146
315
  else
147
- leaves = leaves_with_names.
148
- map { |n| n.name.clean_name }
316
+ leaves = leaves_with_names.map { |n| n.name.single_quote }
149
317
  end
150
318
 
151
319
  if color_branches
@@ -155,35 +323,49 @@ module Iroki
155
323
  n += 1
156
324
  $stderr.printf "Node: %d of %d\r", n, total
157
325
 
158
- color_nodes patterns, tree, node, exact
326
+ color_nodes patterns, tree, node, exact, iroki_to_name
159
327
  end
160
328
  end
161
329
  $stderr.puts
162
330
 
163
- if remove_bootstraps_below
164
- tree.collect_node! do |node|
165
- if node.bootstrap && node.bootstrap < remove_bootstraps_below
166
- node.bootstrap_string = ""
167
- end
168
-
169
- node
331
+ # if remove_bootstraps_below
332
+ # tree.collect_node! do |node|
333
+ # if node.bootstrap && node.bootstrap < remove_bootstraps_below
334
+ # node.bootstrap_string = ""
335
+ # end
336
+
337
+ # node
338
+ # end
339
+ # end
340
+
341
+ tre_str = tree.newick(indent: false)
342
+ # tree.each_node do |node|
343
+ # p [:node, node.name]
344
+ # end
345
+ # puts [:tree_str, tre_str]
346
+ # puts [:iroki_to_name, iroki_to_name]
347
+ # puts [:after_change, Iroki::Tree.gsub_iroki_newick_string(tre_str, iroki_to_name)]
348
+
349
+ # this hash can be used regardless of whether a name map was used
350
+ silly_iroki_to_name = {}
351
+ iroki_to_name.each do |iname, oldname|
352
+ if name_map && name_map.has_key?(oldname)
353
+ silly_iroki_to_name[iname] = name_map[oldname]
354
+ else
355
+ silly_iroki_to_name[iname] = oldname
170
356
  end
171
357
  end
172
358
 
173
-
174
-
175
- tre_str = tree.newick(indent: false).gsub(/'/, '')
176
-
177
359
  nexus = "#NEXUS
178
360
  begin taxa;
179
361
  dimensions ntax=#{leaves.count};
180
362
  taxlabels
181
- #{leaves.join("\n")}
363
+ #{leaves.join("\n").gsub(/iroki[0-9]+iroki/, silly_iroki_to_name)}
182
364
  ;
183
365
  end;
184
366
 
185
367
  begin trees;
186
- tree tree_1 = [&R] #{tre_str}
368
+ tree tree_1 = [&R] #{Iroki::Tree.gsub_iroki_newick_string tre_str, silly_iroki_to_name}
187
369
  end;
188
370
 
189
371
  #{FIG}"
data/lib/iroki/tree.rb ADDED
@@ -0,0 +1,92 @@
1
+ module Iroki
2
+ class Tree
3
+ def self.iroki_name idx
4
+ "iroki#{idx}iroki"
5
+ end
6
+
7
+ # @note The newick standard changes unquoted underscores to spaces
8
+ #
9
+ # @note The reason we have to bother with this is because when the
10
+ # bioruby parser calls the __to_newick method, it does some
11
+ # annoying things to the output and changes the names. Making
12
+ # the names like this lets us easily gsub the names to what they
13
+ # should be after the name map.
14
+ #
15
+ # @param [Bio::Tree] a bio ruby tree object
16
+ #
17
+ # @return [Hash] iroki_name (string) => quoted_orig_name (string)
18
+ def self.change_names tree
19
+ idx = -1
20
+ realname = {}
21
+ tree.each_node do |node|
22
+ if node.name && !node.name.empty?
23
+ idx += 1
24
+
25
+ realname[iroki_name(idx)] = %Q{#{node.name}}
26
+
27
+ node.name = iroki_name(idx)
28
+ end
29
+ end
30
+
31
+ realname
32
+ end
33
+
34
+ def self.combine_hashes h1, h2, nil_val=nil
35
+ h_new = {}
36
+ h1.each do |h1_key, h1_val|
37
+ if h2.has_key? h1_val
38
+ h_new[h1_key] = h2[h1_val]
39
+ else
40
+ h_new[h1_key] = nil_val
41
+ end
42
+ end
43
+
44
+ h_new
45
+ end
46
+
47
+ def self.quoted_vals hash
48
+ # p [:a, hash.values]
49
+ # p [:b, hash.values.map(&:single_quote)]
50
+ hash.values.map(&:single_quote)
51
+ end
52
+
53
+ def self.gsub_iroki_newick_string tre_str, iroki_to_name, name_map=nil
54
+ if name_map
55
+ vals = self.quoted_vals name_map
56
+ name_map_quoted = Hash[name_map.keys.zip(vals)]
57
+
58
+ iroki_to_new_name = self.combine_hashes iroki_to_name, name_map_quoted
59
+ else
60
+ vals = self.quoted_vals iroki_to_name
61
+
62
+ iroki_to_new_name = Hash[iroki_to_name.keys.zip(vals)]
63
+ end
64
+
65
+ tre_str.gsub(/iroki[0-9]+iroki/, iroki_to_new_name)
66
+ end
67
+
68
+ def self.iroki_to_color iroki_to_name, color_map, name_map, nil_val=nil
69
+ if name_map
70
+ old_names = name_map.keys
71
+ new_names = name_map.values
72
+
73
+ color_map_is_for_old_names = color_map.keys.all? { |key| old_names.include? key }
74
+ color_map_is_for_new_names = color_map.keys.all? { |key| new_names.include? key }
75
+
76
+ if color_map_is_for_old_names
77
+ iroki_to_color = self.combine_hashes iroki_to_name, color_map, nil_val
78
+ elsif color_map_is_for_new_names
79
+ iroki_to_new_name = self.combine_hashes iroki_to_name, name_map
80
+
81
+ iroki_to_color = self.combine_hashes iroki_to_new_name, color_map, nil_val
82
+ else # some old, some new
83
+ abort_if true, "The color map has both old and new names in the first column."
84
+ end
85
+
86
+ iroki_to_color
87
+ else # no name map
88
+ self.combine_hashes iroki_to_name, color_map, nil_val
89
+ end
90
+ end
91
+ end
92
+ end
@@ -22,7 +22,7 @@ module Iroki
22
22
  tree.children(node).empty?
23
23
  end
24
24
 
25
- def add_color_to_leaf_branch patterns, node, exact
25
+ def add_color_to_leaf_branch patterns, node, exact, iroki_to_name=nil
26
26
  num_matches = 0
27
27
  color = nil
28
28
  already_matched = false
@@ -37,7 +37,9 @@ module Iroki
37
37
  return nil
38
38
  end
39
39
  else
40
- node_s = node.to_s
40
+ assert iroki_to_name, "iroki_to_name arg is nil"
41
+ assert iroki_to_name[node.to_s], "iroki_to_name is missing #{node.to_s}"
42
+ node_s = iroki_to_name[node.to_s]
41
43
 
42
44
  patterns.each do |pattern, this_color|
43
45
  if node_s =~ pattern
@@ -61,13 +63,15 @@ module Iroki
61
63
  end
62
64
  end
63
65
 
64
- def color_nodes patterns, tree, node, exact
66
+ def color_nodes patterns, tree, node, exact, iroki_to_name
65
67
  # # check if it needs color, if so set the color
66
68
  # color = add_color_to_leaf_branch patterns, node, exact
67
69
 
68
70
  # clean the name no matter what
69
71
  if node.name
70
- node.name = node.name.clean_name
72
+ # puts "before haha: #{node.name}"
73
+ node.name = node.name #.clean_name
74
+ # puts "after haha: #{node.name}"
71
75
  else
72
76
  node.name = nil
73
77
  end
@@ -82,16 +86,18 @@ module Iroki
82
86
 
83
87
  # NOTE: this was originally before cleaning the node name a
84
88
  # couple lines up, does it matter that it is after?
85
- color = add_color_to_leaf_branch patterns, node, exact
89
+ color = add_color_to_leaf_branch patterns, node, exact, iroki_to_name
86
90
 
87
91
  # add color to the name
92
+ # p [:before, node.name]
88
93
  node.name = node.name + color[:branch] if color
94
+ # p [:after, node.name]
89
95
  elsif !leaf?(tree, node)
90
96
  children = tree.children(node) # get the children
91
97
  children_colors = []
92
98
  children.each do |child|
93
99
  # recurse to color the child if needed
94
- color_nodes patterns, tree, child, exact
100
+ color_nodes patterns, tree, child, exact, iroki_to_name
95
101
  children_colors << get_color(child) # add color of the child
96
102
  end
97
103
 
data/lib/iroki/version.rb CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  # Library metadata
20
20
  module Iroki
21
- VERSION = "0.0.15"
21
+ VERSION = "0.0.16"
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.15
4
+ version: 0.0.16
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-08-05 00:00:00.000000000 Z
11
+ date: 2016-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -187,6 +187,13 @@ files:
187
187
  - assets/images/iroki_logo2.idraw
188
188
  - assets/images/iroki_logo2.png
189
189
  - assets/images/iroki_logo2.svg
190
+ - assets/images/iroki_text.graffle
191
+ - assets/images/iroki_text.idraw
192
+ - assets/images/iroki_text.pdf
193
+ - assets/images/iroki_text.png
194
+ - assets/images/iroki_text.svg
195
+ - assets/images/iroki_text_omni.pdf
196
+ - assets/images/iroki_text_omni.svg
190
197
  - bin/console
191
198
  - bin/iroki_docker
192
199
  - bin/setup
@@ -207,6 +214,7 @@ files:
207
214
  - lib/iroki/core_ext/hash/hash.rb
208
215
  - lib/iroki/core_ext/string/string.rb
209
216
  - lib/iroki/main/main.rb
217
+ - lib/iroki/tree.rb
210
218
  - lib/iroki/utils/utils.rb
211
219
  - lib/iroki/version.rb
212
220
  homepage: https://github.com/mooreryan/iroki