Created
April 19, 2012 12:52
-
-
Save hryk/2420798 to your computer and use it in GitHub Desktop.
Calculating Isoelectric point of protein sequences.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| _ = require('underscore'); | |
| EE = require('events').EventEmitter; | |
| ee = new EE(); | |
| isoelectric = {}; | |
| (function(){ | |
| // Constants | |
| var type_p = ['H', 'R', 'K']; | |
| // pk from Bjellqvist, et al. | |
| // Taking into account the decrease in pK differences | |
| // between acids and bases when going from water | |
| // to 8 M urea, a value of 7.5 has been assigned to the | |
| // N-terminal residue. | |
| var pK = { | |
| cterm: { normal: 3.55, D: 4.55, E: 4.75 }, | |
| nterm: { A: 7.59, M: 7.00, S: 6.93, P: 8.36, T: 6.82, V: 7.44, E: 7.70 }, | |
| internal:{ normal: 7.50, D: 4.05, E: 4.45, H: 5.98, C: 9, Y: 10, K: 10, R: 12 }, | |
| }; | |
| // Functions | |
| isoelectric = { | |
| // get charge type of residue | |
| charge_type: function(aa){ | |
| if (_.include(type_p, aa)) { | |
| return 'p'; | |
| } | |
| else { | |
| return 'n'; | |
| } | |
| }, | |
| count_residues: function(seq){ | |
| var counted = []; | |
| // N-term | |
| if (_.isNumber(pK.nterm[seq[0]])) { | |
| counted.push({ | |
| number: 1, | |
| residue: seq[0], | |
| pK: pK.nterm[seq[0]], | |
| type: this.charge_type(seq[0]) | |
| }); | |
| } | |
| else { | |
| counted.push({ | |
| number: 1, | |
| residue: seq[0], | |
| pK: pK.nterm['normal'], | |
| type: this.charge_type(seq[0]) | |
| }); | |
| } | |
| // Internal | |
| var tmp_internal = {}; | |
| for (var i=1;i<seq.length-2;i++) { | |
| if (_.isNumber(pK.internal[seq[i]])) { | |
| if (_.isObject(tmp_internal[seq[i]])) { | |
| tmp_internal[seq[i]].number += 1; | |
| } | |
| else { | |
| tmp_internal[seq[i]] = { | |
| number: 1, | |
| residue: seq[i], | |
| pK: pK.internal[seq[i]], | |
| type: this.charge_type(seq[i]) | |
| }; | |
| } | |
| } | |
| } | |
| _.each(tmp_internal, function(v, k){ | |
| counted.push(v); | |
| }); | |
| // C-term | |
| if (_.isNumber(pK.cterm[seq[seq.length-1]])) { | |
| counted.push({ | |
| number: 1, | |
| residue: seq[seq.length-1], | |
| pK: pK.cterm[seq[seq.length-1]], | |
| type: this.charge_type(seq[seq.length-1]) | |
| }); | |
| } | |
| else { | |
| counted.push({ | |
| number: 1, | |
| residue: seq[seq.length-1], | |
| pK: pK.cterm['normal'] | |
| }); | |
| } | |
| return counted; | |
| }, | |
| // return function of calculating charge of specific pK & type. | |
| charge_func: function(type, pK, number){ | |
| if (type == 'n'){ | |
| return function(ph){ | |
| return -number/(1+Math.pow(10, (pK-ph))); | |
| }; | |
| } | |
| else { | |
| return function(ph){ | |
| return number/(1+Math.pow(10, (ph-pK))); | |
| }; | |
| } | |
| }, | |
| solve: function(charges, callback){ | |
| var that = this; | |
| var bind_object = { | |
| ph: 0.0, | |
| whole_charge: 0.0, | |
| charges: charges, | |
| callback: callback, | |
| pI: NaN, | |
| error: false, | |
| ph_prev: 0.0, | |
| ph_next: 14.0 | |
| }; | |
| var listener = _.bind(function(){ | |
| // Reset whole charge. | |
| this.whole_charge = 0.0; | |
| // Calculate whole charge at pH. | |
| _.each(this.charges, function(func){ | |
| this.whole_charge += func(this.ph); | |
| }, this); | |
| if (this.ph>=14.0){ | |
| console.log('Something is wrong - pH is higher than 14'); | |
| this.error = true; | |
| } | |
| // call decision. | |
| (_.bind(this.callback, this))(); | |
| if (!(this.error == false && _.isNaN(this.pI))) { | |
| console.log('Removing all listeners.. pI:'+this.pI+': netcharge:'+this.whole_charge); | |
| that.pI = this.pI; | |
| ee.removeListener('solve', listener); | |
| } | |
| },bind_object); | |
| ee.on('solve', listener); | |
| var loop = function(){ | |
| setTimeout(function(){ | |
| if (ee.listeners('solve').length > 0){ | |
| ee.emit('solve'); | |
| loop(); | |
| } | |
| }, 5); | |
| }; | |
| loop(); | |
| }, | |
| bisect_algo: function(count){ | |
| var charges = []; | |
| var that = this; | |
| _.each(count, function(residue){ | |
| charges.push(that.charge_func(residue.type, residue.pK, residue.number)); | |
| }); | |
| // infinite loop | |
| return this.solve(charges, function(){ | |
| var e = 0.01; //epsilon means precision [pI = pH ± E] | |
| var temp; | |
| console.log('pH:'+this.ph+', whole_charge:'+this.whole_charge); | |
| if (this.whole_charge < 0) { | |
| temp = this.ph; | |
| this.ph = this.ph-((this.ph-this.ph_prev)/2); | |
| this.ph_next = temp; | |
| } | |
| else { | |
| temp = this.ph; | |
| this.ph = this.ph + ((this.ph_next-this.ph)/2); | |
| this.ph_prev = temp; | |
| } | |
| if ((this.ph-this.ph_prev<e)&&(this.ph_next-this.ph<e)) { | |
| this.pI = this.ph; | |
| } | |
| }); | |
| }, | |
| // naive algorithm from : http://isoelectric.ovh.org/files/practise-isoelectric-point.html | |
| naive_algo: function(count){ | |
| var charges = []; | |
| var that = this; | |
| _.each(count, function(residue){ | |
| charges.push(that.charge_func(residue.type, residue.pK, residue.number)); | |
| }); | |
| // infinite loop | |
| return this.solve(charges, function(){ | |
| console.log('pH:'+this.ph+', whole_charge:'+this.whole_charge); | |
| if (this.whole_charge <= 0) { | |
| // solved! | |
| this.pI = this.ph; | |
| that.pI = this.ph; | |
| } | |
| else { | |
| this.ph += 0.01 | |
| } | |
| }); | |
| } | |
| }; | |
| })(); | |
| (function(){ | |
| // uniprot: O54984 | |
| var seq = 'MAAGVAGWGVEAEEFEDAPDVEPLEPTLSNIIEQRSLKWIFVGGKGGVGKTTCSCSLAVQLSKGRESVLIISTDPAHNISDAFDQKFSKVPTKVKGYDNLFAMEIDPSLGVAELPDEFFEEDNMLSMGKKMMQEAMSAFPGIDEAMSYAEVMRLVKGMNFSVVVFDTAPTGHTLRLLNFPTIVERGLGRLMQIKNQISPFISQMCNMLGLGDMNADQLASKLEETLPVIRSVSEQFKDPEQTTFICVCIAEFLSLYETERLIQELAKCKIDTHNIIVNQLVFPDPEKPCKMCEARHKIQAKYLDQMEDLYEDFHIVKLPLLPHEVRGADKVNTFSALLLEPYKPPSTQ'; | |
| // Initialization (count residues): | |
| var count = isoelectric.count_residues(seq0); | |
| var pI = isoelectric.bisect_algo(count); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment