diadem 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e43300c479c268f5db7b16b84b3b807e449757ad
4
+ data.tar.gz: 3a930a150873d4b004cb0d677992c98c0e4c2c4e
5
+ SHA512:
6
+ metadata.gz: 17de7bc9c431c7917fb3136fc01ef8aace5a4ae383f615971ec3be8525d85dd722775ec05e6b259d2f869648a52b66c3eda14d9b2ee0cfe2d8db6d1a7c2609af
7
+ data.tar.gz: ffd5b0ace3d2cbb6f761d5e329afe3c961e96ca8e3311d4e68000b79af23e8423b9105bb2931f9d4ed1019b17a4e2c5eec120e1526426e194f0c10a2ef40cdc9
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ /gold_standards
19
+ /*.png
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'mspire', :github => 'princelab/mspire', :branch => 'master'
4
+
5
+ # Specify your gem's dependencies in diadem.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2013 Brigham Young University
2
+ Authored by: John T. Prince with guidance from John C. Price
3
+
4
+ Please contact the authors if you would like to make arrangements to obtain
5
+ the software under a different license.
6
+
7
+ This program is free software: you can redistribute it and/or modify it under
8
+ the terms of the GNU General Public License as published by the Free Software
9
+ Foundation, either version 3 of the License, or (at your option) any later
10
+ version.
11
+
12
+ This program is distributed in the hope that it will be useful, but WITHOUT
13
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15
+ details.
16
+
17
+ You should have received a copy of the GNU General Public License along with
18
+ this program. If not, see <http://www.gnu.org/licenses/>.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Diadem
2
+
3
+ Tools for performing mass isotopomer distribution analysis (MIDA). Basically,
4
+ this is dynamic isotope analysis useful for mass spectrometry experiments
5
+ involving protein turnover.
6
+
7
+ ## Installation
8
+
9
+ NOTE: requires ruby >= 2.0
10
+
11
+ Until the Mercury7 algorithm is implemented you will need the fftw3 gem
12
+ installed. It depends on the fftw3 library. On Ubuntu/Debian, it's as easy
13
+ as this:
14
+
15
+ sudo apt-get install libfftw3-dev
16
+
17
+ Then
18
+
19
+ sudo gem install diadem
20
+
21
+ ## Examples
22
+
23
+ Run diadem-cubic.rb from the commandline with no args to get help:
24
+
25
+ diadem-cubic.rb
26
+
27
+ ## LICENSE
28
+
29
+ GNU Public License version 3 (see LICENSE.txt). Please contact the authors for
30
+ consideration of releasing the software under different terms.
31
+
32
+ ## Acronym
33
+
34
+ Diadem stands for Dynamic Isotope Analysis DEMystified or maybe Dynamic Isotope
35
+ Analysis DEMarcated.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
10
+
11
+ require 'rdoc/task'
12
+ Rake::RDocTask.new do |rdoc|
13
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
14
+
15
+ rdoc.rdoc_dir = 'rdoc'
16
+ rdoc.title = "rubabel #{version}"
17
+ rdoc.rdoc_files.include('README*')
18
+ rdoc.rdoc_files.include('lib/**/*.rb')
19
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'diadem/cubic'
4
+
5
+ Diadem::Cubic.run(ARGV)
data/diadem.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'diadem/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "diadem"
8
+ spec.version = Diadem::VERSION
9
+ spec.authors = ["John Prince"]
10
+ spec.email = ["jtprince@gmail.com"]
11
+ spec.description = %q{Dynamic isotope analysis for mass spectrometry isotope experiments. Calculates and visualizes varying isotope ratios and allows the user fine control over incorporation rates.}
12
+ spec.summary = %q{Dynamic isotope analysis for mass spectrometry isotope experiments}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ [
22
+ ["mspire", "~> 0.10.0"],
23
+ ["fftw3", "~> 0.3"],
24
+ ].each do |args|
25
+ spec.add_dependency(*args)
26
+ end
27
+
28
+ [
29
+ ["bundler", "~> 1.3"],
30
+ ["rake"],
31
+ ["rspec", "~> 2.13.0"],
32
+ ["rdoc", "~> 3.12"],
33
+ ["simplecov"],
34
+ ["gnuplot", "~> 2.6.2"],
35
+ ].each do |args|
36
+ spec.add_development_dependency(*args)
37
+ end
38
+
39
+ end
@@ -0,0 +1,159 @@
1
+ require 'matrix'
2
+
3
+ require "diadem/version"
4
+ require "diadem/enrichment"
5
+ require "diadem/distribution"
6
+ require 'mspire/molecular_formula'
7
+ require 'mspire/isotope/distribution'
8
+
9
+ module Diadem
10
+ class Calculator
11
+ # a match (a regex or a String of length 1) that indicates which amino
12
+ # acid should be modified, diff_formula is an Mspire::MolecularFormula
13
+ # object, gain is whether the molecular formula is added or subtracted
14
+ # (boolean, default true). static is boolean, default true. match_block
15
+ # by default will merely return the thing being matched (which is good
16
+ # behavior for static mods)
17
+ Modification = Struct.new(:match, :diff_formula, :gain, :static, :match_block) do
18
+ def initialize(*args, &_match_block)
19
+ (_char, _formula, _gain, _static) = args
20
+ _gain.nil? && ( _gain=true )
21
+ _static.nil? && ( _static=true )
22
+ _match_block.nil? && (_match_block=Diadem::Calculator::Modification::STATIC_MATCH_BLOCK)
23
+ super(_char, _formula, _gain, _static, _match_block)
24
+ end
25
+
26
+ # the arithmetic sign as a symbol: :+ or :-
27
+ def sign
28
+ gain ? :+ : :-
29
+ end
30
+ end
31
+
32
+ class Modification
33
+ VAR_MATCH_BLOCK = lambda(&:upcase)
34
+ STATIC_MATCH_BLOCK = lambda {|match| match }
35
+
36
+ MF = Mspire::MolecularFormula
37
+ OXIDIZED_METHIONINE = Modification.new('m', MF['O'], &VAR_MATCH_BLOCK)
38
+ # aka methylcarboxamido
39
+ CARBAMIDOMETHYL = Modification.new('C', MF['C2H3NO'])
40
+
41
+ DEFAULT_STATIC_MODS = [CARBAMIDOMETHYL]
42
+ DEFAULT_VAR_MODS = [OXIDIZED_METHIONINE]
43
+ DEFAULT_MODS = DEFAULT_STATIC_MODS + DEFAULT_VAR_MODS
44
+ end
45
+
46
+
47
+ Info = Struct.new(:orig_aaseq, :clean_aaseq, :formula, :penetration, :masses, :mods)
48
+
49
+ class Polynomial < Array ; end
50
+
51
+ class << self
52
+ # from http://rosettacode.org/wiki/Polynomial_regression#Ruby. Returns
53
+ # a Polynomial object
54
+ def polyfit(x, y, degree)
55
+ x_data = x.map {|xi| (0..degree).map { |pow| (xi**pow).to_f } }
56
+
57
+ mx = Matrix[*x_data]
58
+ my = Matrix.column_vector(y)
59
+
60
+ Diadem::Calculator::Polynomial.new( ((mx.t * mx).inv * mx.t * my).transpose.to_a[0] )
61
+ end
62
+
63
+ # returns new isotopes, properly enriched.
64
+ def enrich_isotope(isotopes, mass_number, fraction=1.0)
65
+ new_isotopes = isotopes.map(&:dup)
66
+ leftover_fraction = 1.0 - fraction
67
+ new_isotopes.each {|isot| isot.relative_abundance *= leftover_fraction }
68
+ isot_to_enrich = new_isotopes.find {|isot| isot.mass_number == mass_number }
69
+ isot_to_enrich.relative_abundance += fraction
70
+ new_isotopes
71
+ end
72
+
73
+ # related intensities
74
+ def distributions_to_polynomials(enrichments, distributions, num=5, degree=2)
75
+ distributions.map {|dist| dist.intensities[0,num] }.transpose.each_with_index.map do |ar, m|
76
+ polyfit(enrichments, ar, degree)
77
+ end
78
+ end
79
+ end
80
+
81
+ # returns spectra objects. The isotope_table handed in will not be altered
82
+ def initialize(element=:H, mass_number=2, penetration_table=Enrichment::AA_TABLE, isotope_table=Mspire::Isotope::BY_ELEMENT, round=false)
83
+ @round = round
84
+ @penetration_table, @element, @mass_number = penetration_table, element, mass_number
85
+ @isotope_table = dup_isotope_table(isotope_table)
86
+ end
87
+
88
+ def dup_isotope_table(table)
89
+ table.each.with_object({}) do |(key,val), new_table|
90
+ new_table[key] = val.map {|obj| obj.dup }
91
+ end
92
+ end
93
+
94
+ def max_penetration_fraction(aaseq, formula)
95
+ penetration = aaseq.each_char.inject(0.0) do |sum, aa|
96
+ sum + ( @penetration_table[aa] || 0.0 )
97
+ end
98
+ penetration = penetration.round if @round
99
+ @info.penetration = penetration
100
+ penetration.to_f / formula[@element]
101
+ end
102
+
103
+ # returns [formula_adjusted_for_mods, aaseq_with_no_mods]
104
+ def calculate_formula(aaseq_with_mods, mods)
105
+ mods.group_by(&:char).each do |modchar, mod|
106
+ aaseq_with_mods.each_char do |char|
107
+ if char == modchar
108
+ end
109
+ end
110
+ end
111
+
112
+
113
+ Mspire::MolecularFormula.from_aaseq(aaseq)
114
+ end
115
+
116
+ # Returns [distributions, info]. Interprets lowercase m as singly oxidized methionine.
117
+ def calculate_isotope_distributions(aaseq, enrichments, normalize_type: :total, mods: Diadem::Calculator::Modification::DEFAULT_MODS)
118
+ @info = Info.new
119
+ pct_cutoff = nil
120
+
121
+ mf = Mspire::MolecularFormula
122
+ aaseq_up = aaseq
123
+ subtract_formula = mf.new
124
+ add_formula = mf.new
125
+ matched_mods = []
126
+ mods.each do |mod|
127
+ delta_formula = mod.gain ? add_formula : subtract_formula
128
+ aaseq_up = aaseq_up.gsub(mod.match) do |match|
129
+ matched_mods << [match, mod]
130
+ delta_formula.add!(mod.diff_formula)
131
+ mod.match_block.call(match)
132
+ end
133
+ end
134
+ @info.mods = matched_mods
135
+
136
+ formula = mf.from_aaseq(aaseq_up)
137
+ formula += add_formula
138
+ formula -= subtract_formula
139
+ @info.formula = formula
140
+
141
+ max_pen_frac = max_penetration_fraction(aaseq_up, formula)
142
+
143
+ orig_isotopes = @isotope_table[@element]
144
+
145
+ distributions = enrichments.map do |enrich_frac|
146
+ effective_fraction = max_pen_frac * enrich_frac
147
+ @isotope_table[@element] = Diadem::Calculator.enrich_isotope(orig_isotopes, @mass_number, effective_fraction)
148
+ spectrum = formula.isotope_distribution_spectrum(normalize_type, pct_cutoff, @isotope_table)
149
+ @isotope_table[@element] = orig_isotopes
150
+ @info.masses = spectrum.mzs unless @info.masses
151
+ Diadem::Distribution.new( spectrum.intensities )
152
+ end
153
+ [distributions, @info]
154
+ end
155
+ end
156
+ end
157
+
158
+
159
+
@@ -0,0 +1,55 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ module Diadem
5
+ module Cubic
6
+ module Commandline
7
+
8
+ class << self
9
+ def parse(argv)
10
+ make_range = ->(start,stop,step) { Range.new(start, stop).step(step) }
11
+
12
+ start = 0.0
13
+ stop = 0.1
14
+ step = 0.002
15
+ opt = OpenStruct.new( {
16
+ carbamidomethyl: true,
17
+ oxidized_met: true,
18
+ element: :H,
19
+ mass_number: 2,
20
+ range: make_range[ start, stop, step ],
21
+ degree: 3,
22
+ header: true,
23
+ num_isotopomers: 5,
24
+ } )
25
+
26
+ parser = OptionParser.new do |op|
27
+ prog = File.basename($0)
28
+ op.banner = "usage: #{prog} <AASEQ> ..."
29
+ op.separator " or: #{prog} <aaseqs>.csv"
30
+ op.separator " <aaseqs>.csv is a single column of AA sequences (no header)"
31
+ op.separator ""
32
+ op.separator "output: tab delimited to stdout if AASEQ"
33
+ op.separator " <aaseqs>#{Diadem::Cubic::FILE_EXT} if csv input"
34
+ op.separator ""
35
+ op.separator "options:"
36
+ op.on("-e", "--element <#{opt.element}>", "element with isotopic label") {|v| opt.element = v.to_sym }
37
+ op.on("-m", "--mass-number <#{opt.mass_number}>", Integer, "the labeled element mass number") {|v| opt.mass_number = v }
38
+ op.on("--no-carbamidomethyl", "do not use this mod by default") { opt.carbamidomethyl = false }
39
+ op.on("--range <start:stop:step>", "the underlying input values (#{[start, stop, step].join(':')})") {|v| opt.range = make_range[ *v.split(':') ] }
40
+ op.on("--degree <#{opt.degree}>", Integer, "the degree polynomial") {|v| opt.degree = v }
41
+ op.on("--num-isotopomers <#{opt.num_isotopomers}>", Integer, "the number of isotopomers to calculate") {|v| opt.num_isotopomers = v }
42
+ op.on("--no-header", "don't print a header line") {|v| opt.header = false }
43
+ end
44
+ parser.parse!(argv)
45
+ if argv.size == 0
46
+ puts parser
47
+ exit
48
+ end
49
+ [argv, opt]
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,84 @@
1
+ require 'diadem/cubic/commandline'
2
+ require 'diadem/calculator'
3
+ require 'csv'
4
+
5
+ module Diadem
6
+ module Cubic
7
+
8
+ Isotope = Struct.new(:element, :mass_number)
9
+ Peptide = Struct.new(:aaseq, :isotope, :enrichments)
10
+ Enrichment = Struct.new(:fraction, :distribution)
11
+
12
+ FILE_EXT = '.cubic.csv'
13
+ class << self
14
+ # returns the filename of the output if given a filename, or nil
15
+ def run(argv)
16
+ (argv, opt) = Diadem::Cubic::Commandline.parse(argv)
17
+ opt.isotope = Diadem::Cubic::Isotope.new( opt.element, opt.mass_number )
18
+ opt.delim = ","
19
+ (out, aaseqs) =
20
+ if is_filename?(argv.first)
21
+ arg = argv.first
22
+ base = arg.chomp(File.extname(arg))
23
+ [File.open(base + FILE_EXT, 'w'), CSV.read(arg).map(&:first)]
24
+ else
25
+ [$stdout, argv]
26
+ end
27
+ calc = Diadem::Calculator.new( *opt.isotope.values )
28
+
29
+ if opt.header
30
+ cats = %w(sequence mods formula mass n)
31
+ isotopomers = *opt.num_isotopomers.times.map {|n| "M#{n}" }
32
+ cats.push(*isotopomers)
33
+ isotopomers.each do |label|
34
+ (opt.degree).downto(0) do |coeff|
35
+ cats << [label, "coeff", coeff].join("_")
36
+ end
37
+ end
38
+ out.puts cats.join(opt.delim)
39
+ end
40
+
41
+ aaseqs.each do |aaseq|
42
+ # we cannot ensure the base 0% has been included in the range, so
43
+ # calculate it separately
44
+ mods = []
45
+ if opt.carbamidomethyl
46
+ mods << Diadem::Calculator::Modification::CARBAMIDOMETHYL
47
+ end
48
+ if opt.oxidized_met
49
+ mods << Diadem::Calculator::Modification::OXIDIZED_METHIONINE
50
+ end
51
+
52
+
53
+ (distributions, info) = calc.calculate_isotope_distributions(aaseq, opt.range.dup, mods: mods)
54
+ polynomials = Diadem::Calculator.distributions_to_polynomials(opt.range.to_a, distributions, opt.num_isotopomers, opt.degree)
55
+
56
+ zero_pct_dist =
57
+ if opt.range.first == 0.0
58
+ distributions.first
59
+ else
60
+ (dists, info) = calc.calculate_isotope_distributions(aaseq, [0.0])
61
+ zero_pct_dist = dists.first
62
+ end
63
+
64
+ modinfo = info.mods.map {|match, mod| "#{match}:#{mod.sign}#{mod.diff_formula}" }.join(' ')
65
+ line = [aaseq, modinfo, info.formula, info.formula.mass.round(6), info.penetration]
66
+ line.push *zero_pct_dist.intensities[0,opt.num_isotopomers].map {|v| v.round(6) }
67
+ polynomials.each do |coeffs|
68
+ line.push *coeffs.reverse
69
+ end
70
+ out.puts line.join(opt.delim)
71
+ end
72
+ if out.respond_to?(:path)
73
+ out.close
74
+ out.path
75
+ end
76
+ end
77
+
78
+ def is_filename?(arg)
79
+ arg.include?('.')
80
+ end
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Diadem
3
+ class Distribution
4
+ attr_accessor :intensities
5
+
6
+ def initialize(intensities)
7
+ @intensities = intensities
8
+ end
9
+
10
+ # returns self
11
+ def resize!(num)
12
+ newar = @intensities.dup
13
+ to_pad = num - @intensities.size
14
+ unless to_pad <= 0
15
+ to_pad.times { newar << 0.0 }
16
+ end
17
+ @intensities.replace( newar[0,num] )
18
+ self
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+
2
+ module Diadem
3
+ module Enrichment
4
+ AA_TABLE = {
5
+ 'A' => 4,
6
+ 'R' => 3.43,
7
+ 'N' => 1.89,
8
+ 'D' => 1.89,
9
+ 'C' => 1.62,
10
+ 'E' => 3.95,
11
+ 'Q' => 3.95,
12
+ 'G' => 2.06,
13
+ 'H' => 2.88,
14
+ 'I' => 1,
15
+ 'L' => 0.6,
16
+ 'K' => 0.54,
17
+ 'M' => 1.12,
18
+ 'F' => 0.32,
19
+ 'P' => 2.59,
20
+ 'S' => 2.61,
21
+ 'T' => 0.2,
22
+ 'Y' => 0.42,
23
+ 'W' => 0.0,
24
+ 'V' => 0.56,
25
+ }
26
+ end
27
+ end
28
+
29
+
30
+
@@ -0,0 +1,63 @@
1
+ require 'mspire/molecular_formula'
2
+ require 'mspire/isotope'
3
+ require 'fftw3'
4
+
5
+ module Diadem
6
+
7
+ class IsotopeDistribution
8
+ DEFAULT_ISOTOPE_TABLE = Mspire::Isotope::BY_ELEMENT
9
+
10
+ # should always add up to 1
11
+ attr_accessor :intensities
12
+ # should be inclusive of last value
13
+ attr_accessor :nucleon_start
14
+ def initialize(intensities=[], nucleon_start=0)
15
+ @intensities, @nucleon_start = intensities, nucleon_start
16
+ end
17
+
18
+ def nucleon_end
19
+ nucleon_start + intensities.size - 1
20
+ end
21
+
22
+ class << self
23
+
24
+ def from_formula(formula)
25
+ Mspire::MolecularFormula[formula].isotope_distribution
26
+ end
27
+
28
+ # returns a new distribution, uses equal weights if none given
29
+ def average(distributions, weights=nil)
30
+ weights ||= Array.new(distributions.size, 1)
31
+ min_nucleon_num = distributions.map(&:nucleon_start).min
32
+ max_nucleon_num = distributions.map(&:nucleon_end).max
33
+
34
+ new_intensity_arrays = distributions.zip(weights).map do |dist, weight|
35
+ new_pcts = dist.intensities.dup
36
+ right_pad = max_nucleon_num - dist.nucleon_end
37
+ left_pad = dist.nucleon_start - min_nucleon_num
38
+ [[right_pad, new_pcts.size], [left_pad, 0]].each do |pad, loc|
39
+ new_pcts[loc,0] = Array.new(pad, 0.0)
40
+ end
41
+ new_pcts.map! {|v| v * weight }
42
+ new_pcts
43
+ end
44
+
45
+ summed_intensities = new_intensity_arrays.transpose.map do |col|
46
+ col.reduce(:+)
47
+ end
48
+
49
+ new_dist = self.new(summed_intensities, min_nucleon_num)
50
+ new_dist.normalize!
51
+ end
52
+ end
53
+
54
+ # normalizes intensity values and returns self
55
+ def normalize!(normalize_to=1.0)
56
+ sum = intensities.reduce(:+)
57
+ intensities.map! {|v| (v.to_f/sum)*normalize_to }
58
+ self
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,6 @@
1
+ module Diadem
2
+ class IsotopeIncorporationTable
3
+ def initialize(element, isotope)
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module Diadem
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'csv'
3
+
4
+ require 'diadem/calculator'
5
+
6
+ Isotope = Struct.new(:element, :mass_number)
7
+ Peptide = Struct.new(:aaseq, :isotope, :enrichments)
8
+ Enrichment = Struct.new(:fraction, :distribution)
9
+
10
+ # returns [fractions, [array_of_intensity1s, array_of_intensity2s ...]
11
+ def transpose_enrichments(peptide)
12
+ fractions = peptide.enrichments.map(&:fraction)
13
+ [fractions, peptide.enrichments.map(&:distribution).transpose]
14
+ end
15
+
16
+
17
+ describe 'calculating enrichments' do
18
+
19
+ it 'makes distributions' do
20
+
21
+ rows = CSV.read("gold_standards/output_tabular.csv")
22
+ mida_peptides = []
23
+ read_enrichments = false
24
+ rows.each_with_index do |row,i|
25
+ if row.compact.size == 0
26
+ read_enrichments = false
27
+ elsif read_enrichments
28
+ row.map!(&:to_f)
29
+ mida_peptides.last.enrichments << Enrichment.new( row[0], row[1..-1] )
30
+ elsif row[0] =~ /\AIsotope=/
31
+ (mass_number_s, element_s) = row[0].split('=').last.each_char.to_a
32
+ isotope = Isotope.new(element_s.to_sym, mass_number_s.to_i)
33
+ aaseq = rows[i-1].first.split(/\s+/).first
34
+ mida_peptides << Peptide.new(aaseq, isotope, [])
35
+ read_enrichments = true
36
+ end
37
+ end
38
+ #mida_peptides.reject! {|me| me.aaseq.include?('m') }
39
+
40
+ [true, false].each do |round|
41
+ my_peptides = mida_peptides.map do |mida_peptide|
42
+
43
+ (element, mass_number) = mida_peptide.isotope.values
44
+
45
+ calc = Diadem::Calculator.new(element, mass_number, Diadem::Enrichment::AA_TABLE, Mspire::Isotope::BY_ELEMENT, round)
46
+ fractions = mida_peptide.enrichments.map(&:fraction)
47
+ (distributions, info) = calc.calculate_isotope_distributions(mida_peptide.aaseq, fractions)
48
+
49
+ my_peptide = Peptide.new( mida_peptide.aaseq, mida_peptide.isotope )
50
+ my_peptide.enrichments = distributions.zip(fractions).map do |distribution, fractions|
51
+ Enrichment.new( fractions, distribution.resize!(7) )
52
+ end
53
+ my_peptide
54
+ end
55
+
56
+ $PLOT = false
57
+ if $PLOT
58
+ require 'gnuplot'
59
+ mida_peptides.zip(my_peptides) do |mida, mine|
60
+ plottype = 'png'
61
+ base = mida.aaseq + "-ROUND:#{round}"
62
+ plotfile = base + ".#{plottype}"
63
+ mi = mida.isotope
64
+
65
+ Gnuplot.open do |gp|
66
+ Gnuplot::Plot.new(gp) do |plot|
67
+
68
+ plot.title [mida.aaseq, "el:#{mi.element}", "massnum:#{mi.mass_number}", "round:#{round}"].join(" ")
69
+ plot.terminal plottype
70
+ plot.output plotfile
71
+ plot.xlabel "label fraction"
72
+ plot.ylabel "relative intensity"
73
+ plot.yrange "[0:0.5]"
74
+
75
+ plot.data = []
76
+
77
+ mida_fracs_and_int_ars = transpose_enrichments(mida)
78
+
79
+ byu_fracs_and_ints_ars = transpose_enrichments(mine)
80
+ [:mida, mida_fracs_and_int_ars, :byu, byu_fracs_and_ints_ars].each_slice(2) do |name, (fracs, int_ars)|
81
+ int_ars.each_with_index do |ints, mnum|
82
+ plot.data << Gnuplot::DataSet.new( [fracs, ints] ) {|ds| ds.title = "#{name}-M#{mnum}"; ds.with = "lines" }
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
94
+
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'csv'
3
+
4
+ require 'diadem/cubic'
5
+
6
+ describe Diadem::Cubic do
7
+ specify 'using an input file' do
8
+ filename = Diadem::Cubic.run( [TESTFILES + "/input.csv"], )
9
+ File.basename(filename).should == 'input.cubic.csv'
10
+ rows = CSV.read(filename)
11
+ rows.first.should == %w(sequence mods formula mass n M0 M1 M2 M3 M4 M0_coeff_3 M0_coeff_2 M0_coeff_1 M0_coeff_0 M1_coeff_3 M1_coeff_2 M1_coeff_1 M1_coeff_0 M2_coeff_3 M2_coeff_2 M2_coeff_1 M2_coeff_0 M3_coeff_3 M3_coeff_2 M3_coeff_1 M3_coeff_0 M4_coeff_3 M4_coeff_2 M4_coeff_1 M4_coeff_0)
12
+ rows.size.should == 4
13
+ lrow = rows.last
14
+ # these are verified
15
+ lrow[0,10].should == ["NEVHCmLGQSTCEMIR", "C:+C2H3NO C:+C2H3NO m:+O", "C77H129N25O28S4", "1979.832173", "32.56", "0.298777", "0.293168", "0.213061", "0.114555", "0.051392"]
16
+ # the below values are not verified for complete accuracy, but are frozen.
17
+ # I *have* verified that my polyfit gives exactly the same as numpy.polyfit
18
+ # I *have* verified that my fits give nearly the identical result when the
19
+ # formula is used to calculate the function and compared with the raw
20
+ # data.
21
+ coeff_exp = ["-392.23934817385657", "96.69007230820951", "-8.611345775533028", "0.2941872043446288", "274.6030329923823", "-32.519634396959496", "-1.9819130901305437", "0.3015660872075071", "349.4058191339298", "-74.1471126522828", "2.8594996757768354", "0.2129971981087685", "101.51558561078951", "-45.23875117790308", "3.95095594421288", "0.1114045333664326", "-125.24493326823091", "0.15596911712410133", "2.5230711874760186", "0.04912040472741169"]
22
+ lrow[10..-1].zip( coeff_exp ) do |mine, csv|
23
+ mine.to_f.should be_within(1e-5).of(csv.to_f)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ require 'diadem/isotope_distribution'
4
+
5
+
6
+ #describe Diadem::IsotopeDistribution do
7
+ #before do
8
+ #@dists =
9
+ #[[1,2,1], 1,
10
+ #[2, 1, 1], 2,
11
+ #[4], 6
12
+ #].each_slice(2).map do |ints, start|
13
+ #Diadem::IsotopeDistribution.new( ints, start ).normalize!
14
+ #end
15
+ #end
16
+
17
+ #specify 'average with equal weights' do
18
+ #output = Diadem::IsotopeDistribution.average(@dists)
19
+ #[0.083, 0.333, 0.167, 0.083, 0.0, 0.333].zip(output.intensities) do |act, exp|
20
+ #act.should be_within(0.002).of(exp)
21
+ #end
22
+ #output.nucleon_start.should == 1
23
+ #output.nucleon_end.should == 6
24
+ #end
25
+
26
+ #specify 'average with unequal weights' do
27
+ #output = Diadem::IsotopeDistribution.average(@dists, [1,1,10])
28
+ #[0.021, 0.083, 0.042, 0.021, 0.0, 0.833].zip(output.intensities) do |act, exp|
29
+ #act.should be_within(0.002).of(exp)
30
+ #end
31
+ #output.nucleon_start.should == 1
32
+ #output.nucleon_end.should == 6
33
+ #end
34
+
35
+ #specify 'normalize!' do
36
+ #output = Diadem::IsotopeDistribution.new([2,2,2,2], 3).normalize!
37
+ #output.nucleon_start.should == 3
38
+ #output.intensities.should == [0.25, 0.25, 0.25, 0.25]
39
+ #end
40
+ #end
@@ -0,0 +1,27 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ require 'rspec'
5
+
6
+ require 'rspec/core/formatters/progress_formatter'
7
+ # doesn't say so much about pending guys
8
+ class QuietPendingFormatter < RSpec::Core::Formatters::ProgressFormatter
9
+ def example_pending(example)
10
+ output.print pending_color('*')
11
+ end
12
+ end
13
+
14
+ require 'rspec/core/formatters/documentation_formatter'
15
+ class QuietPendingDocFormatter < RSpec::Core::Formatters::DocumentationFormatter
16
+ def example_pending(example)
17
+ output.puts pending_color( "<pending>: #{example.execution_result[:pending_message]}" )
18
+ end
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.treat_symbols_as_metadata_keys_with_true_values = true
23
+ config.formatter = QuietPendingDocFormatter
24
+ config.color = true
25
+ end
26
+
27
+ TESTFILES = File.dirname(__FILE__) + "/testfiles"
@@ -0,0 +1,3 @@
1
+ LGADmEDLR,
2
+ NEVHTMLGQSTEEIR,
3
+ NEVHCmLGQSTCEMIR,
@@ -0,0 +1,4 @@
1
+ sequence,mods,formula,mass,n,M0,M1,M2,M3,M4,M0_coeff_3,M0_coeff_2,M0_coeff_1,M0_coeff_0,M1_coeff_3,M1_coeff_2,M1_coeff_1,M1_coeff_0,M2_coeff_3,M2_coeff_2,M2_coeff_1,M2_coeff_0,M3_coeff_3,M3_coeff_2,M3_coeff_1,M3_coeff_0,M4_coeff_3,M4_coeff_2,M4_coeff_1,M4_coeff_0
2
+ LGADmEDLR,m:+O,C41H70N12O17S,1034.47026,19.540000000000003,0.556753,0.283781,0.115285,0.033992,0.008188,-271.9669543025388,83.87707865863915,-10.465171001547173,0.5549760242624675,447.26750757706844,-95.6467773946335,4.1767024133301724,0.2886473523635921,6.84299765300193,-28.68989673734115,4.13419674326592,0.11197392177809003,-142.35794452920663,15.157584520461455,1.7045563652845814,0.03326539309479602,-77.519961106925,17.24516248866918,0.37336969361968486,0.008718956309883851
3
+ NEVHTMLGQSTEEIR,,C71H118N22O27S,1742.825748,32.35,0.377313,0.332051,0.182291,0.074572,0.024703,-489.95684055041977,121.08399596787066,-10.824527731710008,0.3716306301733113,396.4694223063598,-53.6786513841365,-1.3631060138342357,0.34307099404888625,463.833104592279,-104.37963257827352,5.26331279186841,0.18182473265187887,26.202644313310657,-39.45052607309262,4.745738877395441,0.0692194335651921,-228.23593191536418,19.192095667466113,2.023880307456716,0.022424872233935855
4
+ NEVHCmLGQSTCEMIR,C:+C2H3NO C:+C2H3NO m:+O,C77H129N25O28S4,1979.832173,32.56,0.298777,0.293168,0.213061,0.114555,0.051392,-392.23934817385657,96.69007230820951,-8.611345775533028,0.2941872043446288,274.6030329923823,-32.519634396959496,-1.9819130901305437,0.3015660872075071,349.4058191339298,-74.1471126522828,2.8594996757768354,0.2129971981087685,101.51558561078951,-45.23875117790308,3.95095594421288,0.1114045333664326,-125.24493326823091,0.15596911712410133,2.5230711874760186,0.04912040472741169
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: diadem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - John Prince
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mspire
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: fftw3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 2.13.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 2.13.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rdoc
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '3.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '3.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: gnuplot
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 2.6.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 2.6.2
125
+ description: Dynamic isotope analysis for mass spectrometry isotope experiments. Calculates
126
+ and visualizes varying isotope ratios and allows the user fine control over incorporation
127
+ rates.
128
+ email:
129
+ - jtprince@gmail.com
130
+ executables:
131
+ - diadem-cubic.rb
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - .gitignore
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - bin/diadem-cubic.rb
141
+ - diadem.gemspec
142
+ - lib/diadem/calculator.rb
143
+ - lib/diadem/cubic.rb
144
+ - lib/diadem/cubic/commandline.rb
145
+ - lib/diadem/distribution.rb
146
+ - lib/diadem/enrichment.rb
147
+ - lib/diadem/isotope_distribution.rb
148
+ - lib/diadem/isotope_incorporation_table.rb
149
+ - lib/diadem/version.rb
150
+ - spec/diadem/calculator_spec.rb
151
+ - spec/diadem/cubic_spec.rb
152
+ - spec/diadem/isotope_distribution_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/testfiles/input.csv
155
+ - spec/testfiles/input.cubic.csv
156
+ homepage: ''
157
+ licenses:
158
+ - MIT
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.0.3
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Dynamic isotope analysis for mass spectrometry isotope experiments
180
+ test_files:
181
+ - spec/diadem/calculator_spec.rb
182
+ - spec/diadem/cubic_spec.rb
183
+ - spec/diadem/isotope_distribution_spec.rb
184
+ - spec/spec_helper.rb
185
+ - spec/testfiles/input.csv
186
+ - spec/testfiles/input.cubic.csv
187
+ has_rdoc: