Class: SqedDepiction
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- SqedDepiction
- Includes:
- Housekeeping, Shared::IsData, Shared::Notes, Shared::Tags
- Defined in:
- app/models/sqed_depiction.rb
Overview
A SqedDepiction identifies a depiction as sqed (github.com/SpeciesFileGroup/sqed) parsable, and records the metadata required for parsing a stage image.
Instance Attribute Summary collapse
-
#boundary_color ⇒ Symbol
Color of the boundaries in the image, default/recommendation is green.
-
#boundary_finder ⇒ String
Name of the sqed BoundaryFinder class to use, e.g.
-
#has_border ⇒ Boolean
True if the stage image has a border than needs to be detected.
-
#layout ⇒ Symbol
The Sqed layout, like :cross, :equal_cross, :vertical_offset_cross, :internal_box etc.
-
#metadata_map ⇒ Hash
The sqed metadata map, e.g.
-
#rebuild ⇒ Object
Returns the value of attribute rebuild.
-
#result_boundaries ⇒ Hash
A cache for the result.
-
#result_ocr ⇒ Hash
A cache for the ocr result.
-
#specimen_coordinates ⇒ Hash
Not presently used, the specific coordinates bounding the specimen(s) only.
Class Method Summary collapse
- .annotates? ⇒ Boolean
- .clear_stale_progress(sqed_depiction = nil) ⇒ Object
- .is_containable? ⇒ Boolean
- .last_without_data(project_id) ⇒ Object
-
.preprocess_empty(total = 10) ⇒ Integer
Caches section coordinates and ocr text for the first images that don’t have such caches !! does not take into account project or user, just finds and processes.
- .with_collection_object_data ⇒ Object
- .without_collection_object_data ⇒ Object
Instance Method Summary collapse
-
#collecting_event_sections ⇒ Array of symbols
The (named) sections in this depiction that may have collecting event label metadata.
- #depiction_is_of_collection_object ⇒ Object protected
- #extraction_metadata ⇒ Object
- #is_in_progress? ⇒ Boolean
- #nearby_sqed_depictions(before = 5, after = 5, progress = false) ⇒ Object
-
#next_collection_object ⇒ CollectionObject?
The next collection object, by :id, created from the addition of a SqedDepiction.
- #next_sqed_depiction ⇒ Object
-
#next_without_data(progress = false) ⇒ SqedDepiction
The next record in which the collection object has no buffered data.
- #preprocess(force = true) ⇒ Object
- #recalculate ⇒ Object
- #set_invisible_boundary ⇒ Object
- #sqed_metadata_map ⇒ Object protected
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::Notes
#concatenated_notes_string, #reject_notes
Methods included from Shared::Tags
#reject_tags, #tag_with, #tagged?, #tagged_with?
Methods included from Housekeeping
#has_polymorphic_relationship?
Methods inherited from ApplicationRecord
Instance Attribute Details
#boundary_color ⇒ Symbol
Color of the boundaries in the image, default/recommendation is green.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#boundary_finder ⇒ String
Name of the sqed BoundaryFinder class to use, e.g. ‘Sqed::BoundaryFinder::ColorLineFinder’
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#has_border ⇒ Boolean
Returns True if the stage image has a border than needs to be detected.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#layout ⇒ Symbol
The Sqed layout, like :cross, :equal_cross, :vertical_offset_cross, :internal_box etc.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#metadata_map ⇒ Hash
The sqed metadata map, e.g. {0 => :curator_metadata, 1 => :identifier, 2 => :image_registration, 3 => :annotated_specimen }.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#rebuild ⇒ Object
Returns the value of attribute rebuild.
44 45 46 |
# File 'app/models/sqed_depiction.rb', line 44 def rebuild @rebuild end |
#result_boundaries ⇒ Hash
Returns A cache for the result.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#result_ocr ⇒ Hash
Returns A cache for the ocr result.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
#specimen_coordinates ⇒ Hash
Returns Not presently used, the specific coordinates bounding the specimen(s) only.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 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 |
# File 'app/models/sqed_depiction.rb', line 36 class SqedDepiction < ApplicationRecord include Housekeeping include Shared::Tags include Shared::Notes # True?! include Shared::IsData attr_accessor :rebuild belongs_to :depiction has_one :image, through: :depiction has_one :collection_object, through: :depiction, source_type: 'CollectionObject', source: :depiction_object, inverse_of: :sqed_depictions validates_presence_of :depiction validates_presence_of :metadata_map, :boundary_color validates_inclusion_of :layout, in: SqedConfig::LAYOUTS.keys.map(&:to_s) validates_inclusion_of :boundary_finder, in: %w{Sqed::BoundaryFinder::ColorLineFinder Sqed::BoundaryFinder::Cross} validates_inclusion_of :has_border, in: [true, false] validate :depiction_is_of_collection_object accepts_nested_attributes_for :depiction before_validation :set_invisible_boundary, if: -> { layout.presence == 'stage' } def set_invisible_boundary self.boundary_color = 'invisible' end after_save :recalculate, if: -> { rebuild } def self.is_containable? false end def rebuild=(value) @rebuild = value end def recalculate preprocess(true) end def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end delegate :depiction_object, to: :depiction def self.annotates? false end def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end # @return [SqedDepiction] # the next record in which the collection object has no buffered data def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end def is_in_progress? in_progress && in_progress < 5.minutes.ago end def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end # @return [CollectionObject, nil] # the next collection object, by :id, created from the addition of a SqedDepiction def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end # @return [Array of symbols] # the (named) sections in this depiction that may have collecting event label metadata def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end # @return [Integer] # caches section coordinates and ocr text for the first images that don't have such caches !! does not take into account project or user, just finds and processes def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end protected def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end end |
Class Method Details
.annotates? ⇒ Boolean
92 93 94 |
# File 'app/models/sqed_depiction.rb', line 92 def self.annotates? false end |
.clear_stale_progress(sqed_depiction = nil) ⇒ Object
131 132 133 134 135 136 137 138 139 140 |
# File 'app/models/sqed_depiction.rb', line 131 def self.clear_stale_progress(sqed_depiction = nil) SqedDepiction.where('(in_progress < ?)', 5.minutes.ago) .update_all(in_progress: nil) if sqed_depiction SqedDepiction .where(updated_by_id: sqed_depiction.updated_by_id) .update_all(in_progress: nil) end true end |
.is_containable? ⇒ Boolean
68 69 70 |
# File 'app/models/sqed_depiction.rb', line 68 def self.is_containable? false end |
.last_without_data(project_id) ⇒ Object
142 143 144 145 |
# File 'app/models/sqed_depiction.rb', line 142 def self.last_without_data(project_id) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(id: :asc).first : object end |
.preprocess_empty(total = 10) ⇒ Integer
Returns caches section coordinates and ocr text for the first images that don’t have such caches !! does not take into account project or user, just finds and processes.
197 198 199 200 201 202 203 204 205 206 207 |
# File 'app/models/sqed_depiction.rb', line 197 def self.preprocess_empty(total = 10) t = SqedDepiction.arel_table i = 0 while i < total r = SqedDepiction.where(t[:result_ocr].eq(nil).or(t[:result_boundary_coordinates].eq(nil)).to_sql).limit(1).first return i if r.nil? r.preprocess i = i + 1 end i end |
.with_collection_object_data ⇒ Object
96 97 98 99 100 101 102 103 |
# File 'app/models/sqed_depiction.rb', line 96 def self.with_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].not_eq(nil). or(t[:buffered_determinations].not_eq(nil)). or(t[:buffered_other_labels].not_eq(nil)) joins(:collection_object).where(q.to_sql) end |
.without_collection_object_data ⇒ Object
105 106 107 108 109 110 111 112 |
# File 'app/models/sqed_depiction.rb', line 105 def self.without_collection_object_data t = CollectionObject.arel_table q = t[:buffered_collecting_event].eq(nil). and(t[:buffered_determinations].eq(nil)). and(t[:buffered_other_labels].eq(nil)) joins(:collection_object).where(q.to_sql) end |
Instance Method Details
#collecting_event_sections ⇒ Array of symbols
Returns the (named) sections in this depiction that may have collecting event label metadata.
157 158 159 160 |
# File 'app/models/sqed_depiction.rb', line 157 def collecting_event_sections # !! master merge [:collecting_event_labels, :annotated_specimen] & [:metadata_map].values end |
#depiction_is_of_collection_object ⇒ Object (protected)
211 212 213 214 215 |
# File 'app/models/sqed_depiction.rb', line 211 def depiction_is_of_collection_object if depiction errors.add(:depiction, 'must be of a collection object') if !(depiction.depiction_object_type =~ /CollectionObject/) end end |
#extraction_metadata ⇒ Object
80 81 82 83 84 85 86 87 88 |
# File 'app/models/sqed_depiction.rb', line 80 def { boundary_color: boundary_color.to_sym, boundary_finder: boundary_finder&.constantize, has_border:, layout: layout.to_sym, metadata_map: } end |
#is_in_progress? ⇒ Boolean
127 128 129 |
# File 'app/models/sqed_depiction.rb', line 127 def is_in_progress? in_progress && in_progress < 5.minutes.ago end |
#nearby_sqed_depictions(before = 5, after = 5, progress = false) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'app/models/sqed_depiction.rb', line 162 def nearby_sqed_depictions(before = 5, after = 5, progress = false) q = SqedDepiction.where(project_id:) if progress == true SqedDepiction.clear_stale_progress(self) q = q.where(in_progress: nil) end a = q.where('id > ?', id).order(:id).limit(after) b = q.where('id < ?', id).order('id DESC').limit(before) return { before: b, after: a} end |
#next_collection_object ⇒ CollectionObject?
Returns the next collection object, by :id, created from the addition of a SqedDepiction.
149 150 151 152 153 |
# File 'app/models/sqed_depiction.rb', line 149 def next_collection_object object = CollectionObject.joins(:sqed_depictions).where(project_id:).where('sqed_depictions.id > ?', id).where('collection_objects.id <> ?', depiction_object.id).order(:id).first object = CollectionObject.joins(:sqed_depictions).order(:id).first if object.nil? object end |
#next_sqed_depiction ⇒ Object
176 177 178 179 |
# File 'app/models/sqed_depiction.rb', line 176 def next_sqed_depiction sd = SqedDepiction.where(project_id:).where('id > ?', id).order(:id).limit(1) sd.any? ? sd.first : SqedDepiction.where(project_id:).first end |
#next_without_data(progress = false) ⇒ SqedDepiction
Returns the next record in which the collection object has no buffered data.
116 117 118 119 120 121 122 123 124 125 |
# File 'app/models/sqed_depiction.rb', line 116 def next_without_data(progress = false) if progress SqedDepiction.clear_stale_progress(self) object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(in_progress: false, project_id:).order(:id).first : object else object = SqedDepiction.without_collection_object_data.with_project_id(project_id).where('collection_objects.id <> ?', depiction_object.id).where('sqed_depictions.id > ?', id).order(:id).first object.nil? ? SqedDepiction.where(project_id:).order(:id).first : object end end |
#preprocess(force = true) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'app/models/sqed_depiction.rb', line 181 def preprocess(force = true) return true if !File.exist?(depiction.image.image_file.path(:original)) # don't rebuild if not forced and one or both cache is empty if !force if result_ocr.present? || result_boundary_coordinates.present? return true end end # otherwise rebuild result = Vendor::SqedToTaxonworks::Result.new(depiction_id: depiction.id) result.cache_all end |
#recalculate ⇒ Object
76 77 78 |
# File 'app/models/sqed_depiction.rb', line 76 def recalculate preprocess(true) end |
#set_invisible_boundary ⇒ Object
62 63 64 |
# File 'app/models/sqed_depiction.rb', line 62 def set_invisible_boundary self.boundary_color = 'invisible' end |
#sqed_metadata_map ⇒ Object (protected)
217 218 219 |
# File 'app/models/sqed_depiction.rb', line 217 def .inject({}){|hsh, i| hsh.merge(i[0].to_i => i[1].to_sym)} end |