Class | Bio::RestrictionEnzyme::Analysis |
In: |
lib/bio/util/restriction_enzyme/analysis.rb
lib/bio/util/restriction_enzyme/analysis_basic.rb |
Parent: | Object |
See cut_without_permutations instance method
# File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 20 20: def self.cut_without_permutations( sequence, *args ) 21: self.new.cut_without_permutations( sequence, *args ) 22: end
See main documentation for Bio::RestrictionEnzyme
cut takes into account permutations of cut variations based on competitiveness of enzymes for an enzyme cutsite or enzyme bindsite on a sequence.
Example:
FIXME add output
Bio::RestrictionEnzyme::Analysis.cut('gaattc', 'EcoRI')
_same as:_
Bio::RestrictionEnzyme::Analysis.cut('gaattc', 'g^aattc')
Arguments
Returns: | Bio::RestrictionEnzyme::Fragments object populated with Bio::RestrictionEnzyme::Fragment objects. (Note: unrelated to Bio::RestrictionEnzyme::Range::SequenceRange::Fragments) or a Symbol containing an error code |
# File lib/bio/util/restriction_enzyme/analysis.rb, line 45 45: def cut( sequence, *args ) 46: view_ranges = false 47: 48: args.select { |i| i.class == Hash }.each do |hsh| 49: hsh.each do |key, value| 50: if key == :view_ranges 51: unless ( value.kind_of?(TrueClass) or value.kind_of?(FalseClass) ) 52: raise ArgumentError, "view_ranges must be set to true or false, currently #{value.inspect}." 53: end 54: view_ranges = value 55: end 56: end 57: end 58: 59: res = cut_and_return_by_permutations( sequence, *args ) 60: return res if res.class == Symbol 61: # Format the fragments for the user 62: fragments_for_display( res, view_ranges ) 63: end
See main documentation for Bio::RestrictionEnzyme
Bio::RestrictionEnzyme.cut is preferred over this!
USE AT YOUR OWN RISK
This is a simpler version of method cut. cut takes into account permutations of cut variations based on competitiveness of enzymes for an enzyme cutsite or enzyme bindsite on a sequence. This does not take into account those possibilities and is therefore faster, but less likely to be accurate.
This code is mainly included as an academic example without having to wade through the extra layer of complexity added by the permutations.
Example:
FIXME add output
Bio::RestrictionEnzyme::Analysis.cut_without_permutations('gaattc', 'EcoRI')
_same as:_
Bio::RestrictionEnzyme::Analysis.cut_without_permutations('gaattc', 'g^aattc')
Arguments
Returns: | Bio::RestrictionEnzyme::Fragments object populated with Bio::RestrictionEnzyme::Fragment objects. (Note: unrelated to Bio::RestrictionEnzyme::Range::SequenceRange::Fragments) |
# File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 54 54: def cut_without_permutations( sequence, *args ) 55: return fragments_for_display( {} ) if !sequence.kind_of?(String) or sequence.empty? 56: sequence = Bio::Sequence::NA.new( sequence ) 57: 58: # create_enzyme_actions returns two seperate array elements, they're not 59: # needed separated here so we put them into one array 60: enzyme_actions = create_enzyme_actions( sequence, *args ).flatten 61: return fragments_for_display( {} ) if enzyme_actions.empty? 62: 63: # Primary and complement strands are both measured from '0' to 'sequence.size-1' here 64: sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 ) 65: 66: # Add the cuts to the sequence_range from each enzyme_action 67: enzyme_actions.each do |enzyme_action| 68: enzyme_action.cut_ranges.each do |cut_range| 69: sequence_range.add_cut_range(cut_range) 70: end 71: end 72: 73: # Fill in the source sequence for sequence_range so it knows what bases 74: # to use 75: sequence_range.fragments.primary = sequence 76: sequence_range.fragments.complement = sequence.forward_complement 77: 78: # Format the fragments for the user 79: fragments_for_display( {0 => sequence_range} ) 80: end
Creates an array of EnzymeActions based on the DNA sequence and supplied enzymes.
Arguments
Returns: | Array with the first element being an array of EnzymeAction objects that sometimes_cut, and are subject to competition. The second is an array of EnzymeAction objects that always_cut and are not subject to competition. |
# File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 119 119: def create_enzyme_actions( sequence, *args ) 120: all_enzyme_actions = [] 121: 122: args.each do |enzyme| 123: enzyme = Bio::RestrictionEnzyme.new(enzyme) unless enzyme.class == Bio::RestrictionEnzyme::DoubleStranded 124: 125: # make sure pattern is the proper size 126: # for more info see the internal documentation of 127: # Bio::RestrictionEnzyme::DoubleStranded.create_action_at 128: pattern = Bio::Sequence::NA.new( 129: Bio::RestrictionEnzyme::DoubleStranded::AlignedStrands.align( 130: enzyme.primary, enzyme.complement 131: ).primary 132: ).to_re 133: 134: find_match_locations( sequence, pattern ).each do |offset| 135: all_enzyme_actions << enzyme.create_action_at( offset ) 136: end 137: end 138: 139: # FIXME VerticalCutRange should really be called VerticalAndHorizontalCutRange 140: 141: # * all_enzyme_actions is now full of EnzymeActions at specific locations across 142: # the sequence. 143: # * all_enzyme_actions will now be examined to see if any EnzymeActions may 144: # conflict with one another, and if they do they'll be made note of in 145: # indicies_of_sometimes_cut. They will then be remove FIXME 146: # * a conflict occurs if another enzyme's bind site is compromised do due 147: # to another enzyme's cut. Enzyme's bind sites may overlap and not be 148: # competitive, however neither bind site may be part of the other 149: # enzyme's cut or else they do become competitive. 150: # 151: # Take current EnzymeAction's entire bind site and compare it to all other 152: # EzymeAction's cut ranges. Only look for vertical cuts as boundaries 153: # since trailing horizontal cuts would have no influence on the bind site. 154: # 155: # If example Enzyme A makes this cut pattern (cut range 2..5): 156: # 157: # 0 1 2|3 4 5 6 7 158: # +-----+ 159: # 0 1 2 3 4 5|6 7 160: # 161: # Then the bind site (and EnzymeAction range) for Enzyme B would need it's 162: # right side to be at index 2 or less, or it's left side to be 6 or greater. 163: 164: competition_indexes = Set.new 165: 166: all_enzyme_actions[0..-2].each_with_index do |current_enzyme_action, i| 167: next if competition_indexes.include? i 168: next if current_enzyme_action.cut_ranges.empty? # no cuts, some enzymes are like this (ex. CjuI) 169: 170: all_enzyme_actions[i+1..-1].each_with_index do |comparison_enzyme_action, j| 171: j += (i + 1) 172: next if competition_indexes.include? j 173: next if comparison_enzyme_action.cut_ranges.empty? # no cuts 174: 175: if (current_enzyme_action.right <= comparison_enzyme_action.cut_ranges.min_vertical) or 176: (current_enzyme_action.left > comparison_enzyme_action.cut_ranges.max_vertical) 177: # no conflict 178: else 179: competition_indexes += [i, j] # merge both indexes into the flat set 180: end 181: end 182: end 183: 184: sometimes_cut = all_enzyme_actions.values_at( *competition_indexes ) 185: always_cut = all_enzyme_actions 186: always_cut.delete_if {|x| sometimes_cut.include? x } 187: 188: [sometimes_cut, always_cut] 189: end
See cut instance method
Arguments
May also supply a Hash with the key ":max_permutations" to specificy how many permutations are allowed - a value of 0 indicates no permutations are allowed.
Returns: | Hash Keys are a permutation ID, values are SequenceRange objects that have cuts applied. |
also may return the Symbol ’:sequence_empty’, ’:no_cuts_found’, or ’:too_many_permutations‘
# File lib/bio/util/restriction_enzyme/analysis.rb, line 78 78: def cut_and_return_by_permutations( sequence, *args ) 79: my_hash = {} 80: maximum_permutations = nil 81: 82: hashes_in_args = args.select { |i| i.class == Hash } 83: args.delete_if { |i| i.class == Hash } 84: hashes_in_args.each do |hsh| 85: hsh.each do |key, value| 86: case key 87: when :max_permutations, 'max_permutations', :maximum_permutations, 'maximum_permutations' 88: maximum_permutations = value.to_i unless value == nil 89: when :view_ranges 90: else 91: raise ArgumentError, "Received key #{key.inspect} in argument - I only know the key ':max_permutations' and ':view_ranges' currently. Hash passed: #{hsh.inspect}" 92: end 93: end 94: end 95: 96: if !sequence.kind_of?(String) or sequence.empty? 97: logger.warn "The supplied sequence is empty." if defined?(logger) 98: return :sequence_empty 99: end 100: sequence = Bio::Sequence::NA.new( sequence ) 101: 102: enzyme_actions, initial_cuts = create_enzyme_actions( sequence, *args ) 103: 104: if enzyme_actions.empty? and initial_cuts.empty? 105: logger.warn "This enzyme does not make any cuts on this sequence." if defined?(logger) 106: return :no_cuts_found 107: end 108: 109: # * When enzyme_actions.size is equal to '1' that means there are no permutations. 110: # * If enzyme_actions.size is equal to '2' there is one 111: # permutation ("[0, 1]") 112: # * If enzyme_actions.size is equal to '3' there are two 113: # permutations ("[0, 1, 2]") 114: # * and so on.. 115: if maximum_permutations and enzyme_actions.size > 1 116: if (enzyme_actions.size - 1) > maximum_permutations.to_i 117: logger.warn "More permutations than maximum, skipping. Found: #{enzyme_actions.size-1} Max: #{maximum_permutations.to_i}" if defined?(logger) 118: return :too_many_permutations 119: end 120: end 121: 122: if enzyme_actions.size > 1 123: permutations = permute(enzyme_actions.size) 124: 125: permutations.each do |permutation| 126: previous_cut_ranges = [] 127: # Primary and complement strands are both measured from '0' to 'sequence.size-1' here 128: sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 ) 129: 130: # Add the cuts to the sequence_range from each enzyme_action contained 131: # in initial_cuts. These are the cuts that have no competition so are 132: # not subject to permutations. 133: initial_cuts.each do |enzyme_action| 134: enzyme_action.cut_ranges.each do |cut_range| 135: sequence_range.add_cut_range(cut_range) 136: end 137: end 138: 139: permutation.each do |id| 140: enzyme_action = enzyme_actions[id] 141: 142: # conflict is false if the current enzyme action may cut in it's range. 143: # conflict is true if it cannot due to a previous enzyme action making 144: # a cut where this enzyme action needs a whole recognition site. 145: conflict = false 146: 147: # If current size of enzyme_action overlaps with previous cut_range, don't cut 148: # note that the enzyme action may fall in the middle of a previous enzyme action 149: # so all cut locations must be checked that would fall underneath. 150: previous_cut_ranges.each do |cut_range| 151: next unless cut_range.class == Bio::RestrictionEnzyme::Range::VerticalCutRange # we aren't concerned with horizontal cuts 152: previous_cut_left = cut_range.range.first 153: previous_cut_right = cut_range.range.last 154: 155: # Keep in mind: 156: # * The cut location is to the immediate right of the base located at the index. 157: # ex: at^gc -- the cut location is at index 1 158: # * The enzyme action location is located at the base of the index. 159: # ex: atgc -- 0 => 'a', 1 => 't', 2 => 'g', 3 => 'c' 160: # method create_enzyme_actions has similar commentary if interested 161: if (enzyme_action.right <= previous_cut_left) or 162: (enzyme_action.left > previous_cut_right) or 163: (enzyme_action.left > previous_cut_left and enzyme_action.right <= previous_cut_right) # in between cuts 164: # no conflict 165: else 166: conflict = true 167: end 168: end 169: 170: next if conflict == true 171: enzyme_action.cut_ranges.each { |cut_range| sequence_range.add_cut_range(cut_range) } 172: previous_cut_ranges += enzyme_action.cut_ranges 173: end # permutation.each 174: 175: # Fill in the source sequence for sequence_range so it knows what bases 176: # to use 177: sequence_range.fragments.primary = sequence 178: sequence_range.fragments.complement = sequence.forward_complement 179: my_hash[permutation] = sequence_range 180: end # permutations.each 181: 182: else # if enzyme_actions.size == 1 183: # no permutations, just do it 184: sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 ) 185: initial_cuts.each { |enzyme_action| enzyme_action.cut_ranges.each { |cut_range| sequence_range.add_cut_range(cut_range) } } 186: sequence_range.fragments.primary = sequence 187: sequence_range.fragments.complement = sequence.forward_complement 188: my_hash[0] = sequence_range 189: end 190: 191: my_hash 192: end
Returns an Array of the match indicies of a RegExp to a string.
Example:
find_match_locations('abccdefeg', /[ce]/) # => [2,3,5,7]
Arguments
Returns: | Array with indicies of match locations |
# File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 202 202: def find_match_locations( string, re ) 203: md = string.match( re ) 204: locations = [] 205: counter = 0 206: while md 207: # save the match index relative to the original string 208: locations << (counter += md.begin(0)) 209: # find the next match 210: md = string[ (counter += 1)..-1 ].match( re ) 211: end 212: locations 213: end
Take the fragments from SequenceRange objects generated from add_cut_range and return unique results as a Bio::RestrictionEnzyme::Analysis::Fragment object.
Arguments
Returns: | Bio::RestrictionEnzyme::Analysis::Fragments object populated with Bio::RestrictionEnzyme::Analysis::Fragment objects. |
# File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 93 93: def fragments_for_display( hsh, view_ranges=false ) 94: ary = Fragments.new 95: return ary unless hsh 96: 97: hsh.each do |permutation_id, sequence_range| 98: sequence_range.fragments.for_display.each do |fragment| 99: if view_ranges 100: ary << Bio::RestrictionEnzyme::Fragment.new(fragment.primary, fragment.complement, fragment.p_left, fragment.p_right, fragment.c_left, fragment.c_right) 101: else 102: ary << Bio::RestrictionEnzyme::Fragment.new(fragment.primary, fragment.complement) 103: end 104: end 105: end 106: 107: ary.uniq! unless view_ranges 108: 109: ary 110: end
Returns permutation orders for a given number of elements.
Examples:
permute(0) # => [[0]] permute(1) # => [[0]] permute(2) # => [[1, 0], [0, 1]] permute(3) # => [[2, 1, 0], [2, 0, 1], [1, 2, 0], [0, 2, 1], [1, 0, 2], [0, 1, 2]] permute(4) # => [[3, 2, 1, 0], [3, 2, 0, 1], [3, 1, 2, 0], [3, 0, 2, 1], [3, 1, 0, 2], [3, 0, 1, 2], [2, 3, 1, 0], [2, 3, 0, 1], [1, 3, 2, 0], [0, 3, 2, 1], [1, 3, 0, 2], [0, 3, 1, 2], [2, 1, 3, 0], [2, 0, 3, 1], [1, 2, 3, 0], [0, 2, 3, 1], [1, 0, 3, 2], [0, 1, 3, 2], [2, 1, 0, 3], [2, 0, 1, 3], [1, 2, 0, 3], [0, 2, 1, 3], [1, 0, 2, 3], [0, 1, 2, 3]]
Arguments
Returns: | Array of Array objects with different possible permutation orders. See examples. |
# File lib/bio/util/restriction_enzyme/analysis.rb, line 232 232: def permute(count, permutations = [[0]]) 233: return permutations if count <= 1 234: new_arrays = [] 235: new_array = [] 236: 237: (permutations[0].size + 1).times do |n| 238: new_array.clear 239: permutations.each { |a| new_array << a.dup } 240: new_array.each { |e| e.insert(n, permutations[0].size) } 241: new_arrays += new_array 242: end 243: 244: permute(count-1, new_arrays) 245: end