Class: ObservationMatrix

Inherits:
ApplicationRecord show all
Includes:
Housekeeping, Shared::Citations, Shared::DataAttributes, Shared::Identifiers, Shared::IsData, Shared::Notes, Shared::Tags
Defined in:
app/models/observation_matrix.rb

Overview

A view to a set of observations.

Instance Method Summary collapse

Methods included from Shared::IsData

#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_destroyable?, #is_editable?, #is_in_use?, #is_in_users_projects?, #metamorphosize, #similar

Methods included from Shared::DataAttributes

#import_attributes, #internal_attributes, #keyword_value_hash, #reject_data_attributes

Methods included from Shared::Notes

#concatenated_notes_string, #reject_notes

Methods included from Shared::Tags

#reject_tags, #tag_with, #tagged?, #tagged_with?

Methods included from Shared::Identifiers

#identified?, #next_by_identifier, #previous_by_identifier, #reject_identifiers

Methods included from Shared::Citations

#cited?, #mark_citations_for_destruction, #nomenclature_date, #origin_citation_source_id, #reject_citations, #requires_citation?, #sources_by_topic_id

Methods included from Housekeeping

#has_polymorphic_relationship?

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Method Details

#cell_countObject



69
70
71
# File 'app/models/observation_matrix.rb', line 69

def cell_count
  observation_matrix_rows.count * observation_matrix_columns.count 
end

#character_statesObject



65
66
67
# File 'app/models/observation_matrix.rb', line 65

def character_states
  CharacterState.joins(descriptor: [:observation_matrices]).merge(descriptors)
end

#continuous_descriptorsObject



39
40
41
# File 'app/models/observation_matrix.rb', line 39

def continuous_descriptors
  descriptors.where(type: 'Descriptor::Continuous')
end

#gene_descriptorsObject



51
52
53
# File 'app/models/observation_matrix.rb', line 51

def gene_descriptors
  descriptors.where(type: 'Descriptor::Gene')
end

#is_media_matrix?Boolean

Returns:

  • (Boolean)


73
74
75
76
77
78
# File 'app/models/observation_matrix.rb', line 73

def is_media_matrix?
  observation_matrix_columns.each do |c|
    return false unless c.descriptor.type == 'Descriptor::Media'
  end
  true
end

#media_descriptorsObject



47
48
49
# File 'app/models/observation_matrix.rb', line 47

def media_descriptors
  descriptors.where(type: 'Descriptor::Media')
end

#media_observationsObject



125
126
127
# File 'app/models/observation_matrix.rb', line 125

def media_observations
  Observation.in_observation_matrix(id).where(type: 'Observation::Media')
end

#observation_depictionsObject



129
130
131
132
133
134
135
136
# File 'app/models/observation_matrix.rb', line 129

def observation_depictions
  Depiction.select('depictions.*, observations.descriptor_id, observations.otu_id, observations.collection_object_id, sources.id AS source_id, sources.cached_author_string, sources.year, sources.cached AS source_cached')
      .joins("INNER JOIN observations ON observations.id = depictions.depiction_object_id")
      .joins("INNER JOIN images ON depictions.image_id = images.id")
      .joins("LEFT OUTER JOIN citations ON citations.citation_object_id = images.id AND citations.citation_object_type = 'Image' AND citations.is_original IS TRUE")
      .joins("LEFT OUTER JOIN sources ON citations.source_id = sources.id")
      .where(depiction_object: media_observations).order('depictions.position')
end

#observationsObject



121
122
123
# File 'app/models/observation_matrix.rb', line 121

def observations
  Observation.in_observation_matrix(id)
end

#observations_hashHash

Returns a hash of hashes of arrays with the coding objects nicely organized

descriptor_id1 =>{row_object_global_id => [observation1, observation2], descriptor_id: nil}

was `codings_mx` in mx where this: “likely should add scope and merge with above, though this seems to be slower”.

Returns:

  • (Hash)

    a hash of hashes of arrays with the coding objects nicely organized

    descriptor_id1 =>{row_object_global_id => [observation1, observation2], descriptor_id: nil}
    

    was `codings_mx` in mx where this: “likely should add scope and merge with above, though this seems to be slower”



226
227
228
229
230
# File 'app/models/observation_matrix.rb', line 226

def observations_hash
  h = Hash.new{|hash, key| hash[key] = Hash.new{|hash2, key2| hash2[key2] = Array.new}} 
  observations.each {|o| h[o.descriptor_id][o.observation_object_global_id].push(o) }
  h
end

#observations_in_grid(options = {}) ⇒ Hash

Derived from mx code. TODO: optimize by returning only observations with Otu range, not just Chr range (? still relevant ?)

:position attribute starts at 1

Grid starts at 0!!

Returns:

  • (Hash)

    grid: [columns][observations] rows: [row_object.GlobalId, row_object.GlobalId] (Klass) columns: [descriptor.id, desriptor.id]



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
# File 'app/models/observation_matrix.rb', line 145

def observations_in_grid(options = {})
  opts = {
    row_start:  1,
    row_end: 'all',
    col_start: 1,
    col_end: 'all'
  }.merge!(options.symbolize_keys)

  return false if (opts[:row_start] == 0) || (opts[:col_start] == 0) # catch problems with forgetting index starts at 1

  rows = []  # y axis
  cols = []  # x axis
  r = []
  if opts[:row_end] == 'all'
    r = observation_matrix_rows.order('observation_matrix_rows.position')
  else
    r = observation_matrix_rows.where("observation_matrix_rows.position >= ? and observation_matrix_rows.position <= ?", opts[:row_start], opts[:row_end]).order('observation_matrix_rows.position')
  end
  
  return false if r.size == 0

  rows = r.collect{|i| i.row_object.to_global_id}

  if opts[:col_end] == 'all'
    cols = descriptors.order('observation_matrix_columns.position').pluck(:id) # all descriptors
  else
    cols = observation_matrix_rows.
      where("observation_matrix_columns.position >= ? and observation_matrix_columns.position <= ?", opts[:col_start], opts[:col_end]).
      order('observation_matrix_columns.position').
      pluck(:descriptor_id)  # self.chrs.within_mx_range(opts[:chr_start], opts[:chr_end])
  end

  return false if cols.size == 0

  grid = Array.new(cols.size){Array.new(rows.size){Array.new}}

  # Dump the observations into bins
  Observation.by_descriptors_and_rows(cols, rows).each do |o|
    i = o.observation_object.to_global_id
    if rows.index(i)
      grid[cols.index(o.descriptor_id)][rows.index(i)].push(o) 
    end
  end
  
  {grid: grid, rows: rows, cols: cols }
end

#polymorphic_cells_for_descriptor(symbol_start: 0, descriptor_id:) ⇒ Object

Used soley as a indexing method for nexml output Original code in mx

Parameters:

  • descriptor_id (Descriptor)
  • symbol_start (Integer) (defaults to: 0)

    # takes :chr => Chr, :symbol_start => Int

Returns:

  • Hash 1 => [character_state.id, charater_state.id]



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'app/models/observation_matrix.rb', line 198

def polymorphic_cells_for_descriptor(symbol_start: 0, descriptor_id:)
  symbol_start ||= 0
  cells = Hash.new{|hash, key| hash[key] = Array.new}

  observations.where(descriptor_id: descriptor_id).each do |o|
    cells[o.observation_object_global_id].push(
      o.qualitative? ? o.character_state_id : "#{o.descriptor_id}_#{o.presence_absence? ? '1' : '0'}"
    )
  end

  r = Hash.new{|hash, key| hash[key] = Array.new}
  i = 0
  cells.keys.each do |k|
    if r # must be some other idiom
      if cells[k].size > 1
        r[symbol_start + i] = cells[k].sort 
        i += 1
      end
    end
  end
  r 
end

#presence_absence_descriptorsObject



35
36
37
# File 'app/models/observation_matrix.rb', line 35

def presence_absence_descriptors
  descriptors.where(type: 'Descriptor::PresenceAbsence')
end

#qualitative_descriptorsObject



31
32
33
# File 'app/models/observation_matrix.rb', line 31

def qualitative_descriptors
  descriptors.where(type: 'Descriptor::Qualitative')
end

#reorder_columns(by = 'reindex') ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/models/observation_matrix.rb', line 105

def reorder_columns(by = 'reindex')
  case by
  when 'reindex'
    observation_matrix_columns.order('observation_matrix_columns.position').each.with_index do |c,i|
      c.update_column(:position, i)
    end
  when 'name'
    observation_matrix_columns.order('descriptors.name').each.with_index do |c,i|
      c.update_column(:position, i)
    end
  else
    return false
  end
  true
end

#reorder_rows(by = 'reindex') ⇒ Boolean

Returns reorders all rows and returns true or false.

Returns:

  • (Boolean)

    reorders all rows and returns true or false



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'app/models/observation_matrix.rb', line 82

def reorder_rows(by = 'reindex')
  case by
  when 'reindex'
    observation_matrix_rows.order('observation_matrix_rows.position').each.with_index do |r,i|
      r.update_column(:position, i)
    end
  when 'nomenclature'
    objects = []
    observation_matrix_rows.each do |r|
      objects.push [r,  TaxonName.self_and_ancestors_of(r.current_taxon_name).order('taxon_name_hierarchies.generations DESC').pluck(:name).to_s]
      #objects.push [r, r.current_taxon_name.ancestor_ids] # TODO: probably not correct, a quick and dirty attempt
    end

    objects.sort!{|a, b| a[1] <=> b[1]} # add internal loop on name
    objects.each_with_index do |r,i|
      r[0].update_column(:position, i)
    end
  else
    return false
  end
  true
end

#sample_descriptorsObject



43
44
45
# File 'app/models/observation_matrix.rb', line 43

def sample_descriptors
  descriptors.where(type: 'Descriptor::Sample')
end

#symbol_descriptorsObject

As handled in export/parsing by external tools !! Note order() is applied !!



61
62
63
# File 'app/models/observation_matrix.rb', line 61

def symbol_descriptors
  descriptors.where(type: ['Descriptor::PresenceAbsence', 'Descriptor::Qualitative']).order('observation_matrix_columns.position')
end

#working_descriptorsObject



55
56
57
# File 'app/models/observation_matrix.rb', line 55

def working_descriptors
  descriptors.where(type: 'Descriptor::Working')
end