Skip to content

Instantly share code, notes, and snippets.

@Carreau
Created March 23, 2014 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Carreau/9723659 to your computer and use it in GitHub Desktop.
Save Carreau/9723659 to your computer and use it in GitHub Desktop.

Actin Threadmilling

This is a proof of concept of a live simlation of actin threadmilling using Mike Bostock D3 javascript library.

Dark monomers (and left pool)a re ADP actin, light monomer (and right pool) are APT actin. Middle pool should be ATP + profiline, that for now only participate on the regeneration of ATD into ATP.

The simulation is quite fast, but one should still be able to see rare addition of monomer to the pointed end, and monomer detaching from the pointed end.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 900,
height = 500,
spf =400,
kalapha = 2,
totalmonomer = 140;
var fill = d3.scale.category10();
var delta = 300;
var nodes = [],
foci = [{x: width/2-delta, y: 100}, {x: width/2+delta, y: 100}, {x: width/2, y: 350},
{x: width/2, y:20} ];
pools = {
'a': {
x:100,
y:100,
pool : []
},
'b': {
x:150,
y:150,
pool : []
},
'c': {
x:250,
y:250,
pool : []
},
}
var ft = function(from,to){
var monom = pools[from].pool.shift();
if(!monom) return
monom.id = to
pools[to].pool.push(monom)
}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.nodes(nodes)
.links([])
.linkStrength(function(){return 0})
.chargeDistance(100)
.charge(function(o,i){return (o.id==factinid)? -0: -15})
.gravity(-0.0)
.size([width, height])
.on("tick", tick);
var node = svg.selectAll("rect");
function tick(e) {
var k = .035 * kalapha* e.alpha;
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
var dx=o.dx||0;
var dy=o.dy||0;
if(o.id == factinid){
//k= 0.1*e.alpha
}
try{
ddy = (foci[o.id].y+dy - o.y) * k;
ddx = (foci[o.id].x+dx - o.x) * k;
//dmax = 0.60
//if(Math.abs(ddy) > dmax){ ddy = ddy/Math.abs(ddy)*dmax}
//if(Math.abs(ddx) > dmax){ ddx = ddx/Math.abs(ddx)*dmax}
o.y += ddy;
o.x += ddx;
} catch (e){
}
});
node
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.style("fill", function(d) {
if (d.atp){
return d3.rgb(fill(d.id*0)).brighter(1);
} else {
return d3.rgb(fill(d.id*0)).darker(0.5);
}
}
)
.style("stroke", function(d) { return d3.rgb(fill(d.id)).darker(2); });
}
var subset = [[],[],[]]
actinpool = [];
adppool = [];
adpid = 0;
atppool = [];
atpid = 1;
factinid = 2;
profilinepool = [];
profilineid = 3;
var renumberThreadmill = function(actin){
actin.forEach(function(o,i){
o.dx=(i-actin.length/2)*8;
o.dy=o.parity*5
})
}
var hydrolyse = function(monomer){
monomer.atp=false;
}
var addToBarbedEnd = function(monomer){
if(!monomer) return
monomer.id = factinid;
var lastm = actinpool[actinpool.length-1]||{}
monomer.parity = (lastm.parity==-1)?1:-1
actinpool.push(monomer)
renumberThreadmill(actinpool)
}
var addToPointedEnd = function(monomer){
if(!monomer) return
monomer.id = factinid;
var firstm = actinpool[0]||{}
monomer.parity = (firstm.parity==1)?-1:1;
actinpool.unshift(monomer)
renumberThreadmill(actinpool)
}
//setInterval(function(){
//console.log('>>>>> ', actinpool.length+ adppool.length+ atppool.length)
//},100)
var removeBarbedEnd = function(){
var monomer = actinpool.pop();
if(!monomer) return;
monomer.dx = 0
monomer.dy = 0
if(monomer.atp){
monomer.id = atpid
atppool.push(monomer)
} else {
monomer.id = adpid
adppool.push(monomer)
}
renumberThreadmill(actinpool)
return monomer
}
setInterval(removeBarbedEnd, 1.907*spf)
var removePointedEnd = function(){
if(Math.random() < 0.10) {
var rd= Math.random()*atppool.length
if (rd > 4*totalmonomer/5){
addAtpToPointedEnd();
} else if (rd > 3*totalmonomer/5){
addAdpToPointedEnd();
}
return
}
var monomer = actinpool.shift();
if(!monomer) return;
monomer.dx = 0
monomer.dy = 0
if(monomer.atp){
monomer.id = atpid
atppool.push(monomer)
} else {
monomer.id = adpid
adppool.push(monomer)
}
renumberThreadmill(actinpool)
return monomer
}
var fromPoolToPool = function(from, to, proba, transform){
var rnd = Math.random()
if(rnd < proba*from.length){
monomer = from.shift();
if(!monomer) return;
transform(monomer);
to.push(monomer)
}
}
// slow atp regeneration
reg = function(){fromPoolToPool(adppool, atppool, 0.00, function(m){m.id=atpid, m.atp=true });}
setInterval(reg, 1.0*spf)
// fast atp regeneration
reg = function(){fromPoolToPool(adppool, profilinepool, 41.0/1000, function(m){m.id=profilineid});}
setInterval(reg, 1.0*spf)
reg = function(){fromPoolToPool(profilinepool, atppool, 20.0/1000, function(m){m.id=atpid, m.atp=true});}
setInterval(reg, 1.0*spf)
reg = function(){fromPoolToPool(atppool, adppool, 0.00, function(m){m.id=adpid, m.atp=false });}
setInterval(reg, 1.0*spf)
//slow atp hydrolysis
setInterval(function(){
return
var rd = Math.random()*atppool.length;
if(rd > 0.25*totalmonomer){
var matp = atppool.shift()
matp.atp=false;
matp.id = adpid;
adppool.push(matp);
}
}, 0.3*spf)
setInterval(function(){
var rd = Math.random()*atppool.length;
if(rd > totalmonomer/20){
var monomer = atppool.shift();
addToBarbedEnd(monomer)
}
}, 0.45*spf)
setInterval(function(){
monomer = removePointedEnd()
}, 1.00*spf)
// fast hydrolyse in actin filament
setInterval(function(){
var index = ~~(Math.random() * actinpool.length-7)
for(var i= index; i>0; i--){
if(actinpool[index] && actinpool[index].atp==true){
hydrolyse(actinpool[index])
return
}
}
},0.36*spf)
// addAtpPointed
var addAtpToPointedEnd = function(){
var monomer = atppool.shift();
console.log('adding to pointed end');
addToPointedEnd(monomer);
}
// adddtpPointed
var addAdpToPointedEnd = function(){
var monomer = adppool.shift();
console.log('adding to pointed end (ADP)');
addToPointedEnd(monomer);
}
//setInterval(addAtpToPointedEnd, 4*1000);
var addmon = function(){
var monom = {id: ~~(Math.random() * foci.length), atp:true, weight:0}
//nowhere.push(monom)
nodes.push(monom);
var roll = Math.random();
if(roll < 0.3){
monom.atp=true;
monom.id = atpid;
atppool.push(monom);
} else if( roll < 0.6){
addToBarbedEnd(monom);
} else {
monom.atp=false;
monom.id = adpid;
adppool.push(monom);
}
force.start();
node = node.data(nodes);
node.enter().append("rect")
.attr("class", "node")
.attr("width", 18)
.attr("height", 8)
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.style("fill", function(d) { return fill(d.id); })
.style("stroke", function(d) { return d3.rgb(fill(d.id)).darker(2); })
.call(force.drag);
};
setInterval( function(){force.start()} , 600)
for( var i=0; i<totalmonomer; i++){
addmon();
}
setTimeout(function(){ location.reload()}, 60*1000)
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment