iroki 0.0.15 → 0.0.16

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: 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