Module: Lib::Vendor::NexusParserHelper

Included in:
ImportNexusJob
Defined in:
app/helpers/lib/vendor/nexus_parser_helper.rb

Instance Method Summary collapse

Instance Method Details

#create_citation_for(citation, model, id) ⇒ Object



133
134
135
136
137
138
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 133

def create_citation_for(citation, model, id)
  Citation.create!(citation.merge({
    citation_object_type: model,
    citation_object_id: id
  }))
end

#find_matching_descriptor(nxs_chr) ⇒ Hash

properties for the most recently created descriptor, if any, that has the same name and character states as nxs_char.

Returns:

  • (Hash)

    Returns a hash with descriptor and chr_states



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 55

def find_matching_descriptor(nxs_chr)
  descriptors = Descriptor::Qualitative
    .where(project_id: Current.project_id)
    .where(name: nxs_chr.name)
    .order(:name, id: :desc)

  descriptors.each do |tw_d|
    # Require state labels/names from nexus and TW to match.
    # Other operations are conceivable, for instance updating the
    # chr with the new states, but the combinatorics gets very tricky
    # very quickly.

    tw_chr_states = CharacterState
      .where(project_id: Current.project_id)
      .where(descriptor: tw_d)

    if same_state_names_and_labels(nxs_chr.states, tw_chr_states)
      return {
        descriptor: tw_d,
        chr_states: tw_chr_states
      }
    end
  end

  {}
end

#find_matching_otus(names, match_otus_by_name, match_otus_by_taxon) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 33

def find_matching_otus(names, match_otus_by_name, match_otus_by_taxon)
  return {} if !match_otus_by_name && !match_otus_by_taxon

  matches = {}
  if match_otus_by_taxon
    matches = match_otus_by_taxon(names)
  end

  if match_otus_by_name
    remaining_names = names - matches.keys
    if remaining_names.size
      more_matches = match_otus_by_name(remaining_names)
      matches.merge!(more_matches)
    end
  end

  matches
end

#match_otus_by_name(names) ⇒ Hash

the Otu returned is the one created most recently.

Returns:

  • (Hash)

    name matched to Otu by otu name. For those names that match,



97
98
99
100
101
102
103
104
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 97

def match_otus_by_name(names)
  otus = Otu
    .where(project_id: Current.project_id)
    .where(name: names)
    .order(:name, id: :desc)

  otus_to_name_hash(otus, 'name')
end

#match_otus_by_taxon(names) ⇒ Hash

match, the Otu returned is the one created most recently.

Returns:

  • (Hash)

    name matched to Otu by taxon name. For those names that



84
85
86
87
88
89
90
91
92
93
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 84

def match_otus_by_taxon(names)
  otus = Otu
    .joins(:taxon_name)
    .select('otus.*, taxon_names.cached as tname')
    .where(project_id: Current.project_id)
    .where('taxon_names.cached': names)
    .order('taxon_names.cached', id: :desc)

  otus_to_name_hash(otus, 'tname')
end

#otus_to_name_hash(otus, name_attr) ⇒ Object

Assumes otus are ordered by name; only returns the first otu if there are repeats for a given name.



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 108

def otus_to_name_hash(otus, name_attr)
  matches = {}
  previous_name = ''
  otus.each { |o|
    name = o[name_attr]
    if name != previous_name
      matches[name] = o
      previous_name = name
    end
  }

  matches
end

#populate_matrix_with_nexus(nexus_doc_id, parsed_nexus, matrix, options) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 140

def populate_matrix_with_nexus(nexus_doc_id, parsed_nexus, matrix, options)
  nf = parsed_nexus
  m = matrix

  new_otus = []
  new_descriptors = []
  new_states = []

  begin
    if options[:cite_matrix]
      create_citation_for(options[:citation], 'ObservationMatrix', m.id)
    end

    # Find/create OTUs, add them to the matrix as we do so,
    # and add them to an array for reference during coding.
    taxa_names = nf.taxa.collect{ |t| t.name }.sort().uniq
    matched_otus = find_matching_otus(taxa_names,
      options[:match_otu_to_name], options[:match_otu_to_taxonomy_name])

    ObservationMatrix.transaction do
      nf.taxa.each_with_index do |o, i|
        otu = matched_otus[o.name]
        if !otu
          otu = Otu.create!(name: o.name)
          if options[:cite_otus]
            create_citation_for(options[:citation], 'Otu', otu.id)
          end
        end

        new_otus << otu
        ObservationMatrixRow.create!(
          observation_matrix: m, observation_object: otu
        )
      end

      # Find/create descriptors (= nexus characters).
      nf.characters.each_with_index do |nxs_chr, i|
        tw_d = nil
        new_states[i] = {}

        if options[:match_character_to_name]
          r = find_matching_descriptor(nxs_chr)
          tw_d = r[:descriptor]
          if tw_d
            r[:chr_states].each { |twcs|
              new_states[i][twcs.label] = twcs
            }
          end
        end

        if !tw_d
          new_tw_chr_states = []
          nxs_chr.state_labels.each do |nex_state|
            new_tw_chr_states << {
              label: nex_state,
              name: nf.characters[i].states[nex_state].name
            }
          end

          tw_d = Descriptor::Qualitative.create!(name: nxs_chr.name)
          new_tw_chr_states.each { |cs|
            CharacterState.create!(cs.merge({ descriptor: tw_d }))
          }
          if options[:cite_descriptors]
            create_citation_for(options[:citation], 'Descriptor', tw_d.id)
          end

          tw_d.character_states.each do |cs|
            new_states[i][cs.label] = cs
          end
        end

        new_descriptors << tw_d
        ObservationMatrixColumn.create!(
          observation_matrix_id: m.id, descriptor: tw_d
        )
      end

      # Create codings.
      nf.codings[0..nf.taxa.size].each_with_index do |y, i| # y is a rowvector of NexusFile::Coding
        y.each_with_index do |x, j| # x is a NexusFile::Coding
          x.states.each do |z|
            if z != '?'
              o = Observation::Qualitative
                .where(project_id: Current.project_id)
                .find_by(
                  descriptor: new_descriptors[j],
                  observation_object: new_otus[i],
                  character_state: new_states[j][z]
                )
              if o.nil?
                o = Observation::Qualitative.create!(
                  descriptor: new_descriptors[j],
                  observation_object: new_otus[i],
                  character_state: new_states[j][z]
                )
                if options[:cite_observations]
                  create_citation_for(options[:citation], 'Observation', o.id)
                end
              end
            end
          end
        end
      end
    end
  rescue => ex
    ExceptionNotifier.notify_exception(ex,
      data: {
        nexus_document_id: nexus_doc_id,
        matrix_id: matrix.id,
        user_id: Current.user_id,
        project_id: Current.project_id
      }
      .merge(options)
    )
    m.destroy!
    raise
  end
end

#preview_nexus_descriptors(nexus_file, match_descriptor_to_name) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 17

def preview_nexus_descriptors(nexus_file, match_descriptor_to_name)
  descriptor_names = nexus_file.characters.map { |c| c.name }.sort()

  matched_descriptors = {}
  if match_descriptor_to_name
    nexus_file.characters.each { |nxs_chr|
      tw_d = find_matching_descriptor(nxs_chr)[:descriptor]
      if tw_d
        matched_descriptors[nxs_chr.name] = tw_d
      end
    }
  end

  descriptor_names.map { |name| matched_descriptors[name] || name }
end

#preview_nexus_otus(nexus_file, match_otu_to_name, match_otu_to_taxonomy_name) ⇒ Object

!! Some of the code here is run in the context of an ApplicationJob, which doesn’t have sessions_current_project_id or sessions_current_user_id - instead assume that Current.project_id and Current.user_id are set by the caller.



7
8
9
10
11
12
13
14
15
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 7

def preview_nexus_otus(nexus_file, match_otu_to_name,
  match_otu_to_taxonomy_name)

  taxa_names = nexus_file.taxa.map { |t| t.name }.sort()
  matched_otus = find_matching_otus(taxa_names, match_otu_to_name,
    match_otu_to_taxonomy_name)

  taxa_names.map { |name| matched_otus[name] || name }
end

#same_state_names_and_labels(nex_states, tw_states) ⇒ Object



122
123
124
125
126
127
128
129
130
131
# File 'app/helpers/lib/vendor/nexus_parser_helper.rb', line 122

def same_state_names_and_labels(nex_states, tw_states)
  return false if
    nex_states.keys.sort() != tw_states.map{ |s| s.label }.sort()

  tw_states.each do |s|
    return false if nex_states[s.label].name != s.name
  end

  true
end