Animating gene expression
#include "visual/Whiteboard.h"
#include "base/FileParser.h"
#include "base/CommandLineParser.h"
#include "base/FileParser.h"
#include "base/SVector.h"
#include "visual/Color.h"
#include "visual/Compounds.h"
#include <iostream>
// Draw one gene
void DrawOne(const string & o, int index, const svec< svec < double > > & val, const svec<string> & name)
{
double x_offset = 20;
double y_offset = 20;
int i, j;
ns_whiteboard::whiteboard board;
double x_max = 550. + 2* x_offset;
double y_max = 220.;
Box b;
double x = 0.;
double y = 0.;
board.Add( new ns_whiteboard::rect( ns_whiteboard::xy_coords(0, 0),
ns_whiteboard::xy_coords(x_max + 2*x_offset, y_max + 2*y_offset),
color(0.99, 0.99, 0.99)) );
// Look for spacers in the data
for (i=0; i<name.isize(); i++) {
if (name[i] == "delim") {
x = 0.;
y += 30.;
continue;
}
if (name[i] == "empty") {
x += 45.;
continue;
}
const svec<double> & vv = val[i];
double mean = 0.;
for (j=0; j<vv.isize(); j++)
mean += vv[j];
mean /= (double)vv.isize();
double v = (vv[index] - mean) / 5.;
// Get color gradient
color cc = GradientMult(v, color(0., 0., 0.99), color(0.99, 0., 0.), color(0.99, 0.99, 0.99));
// Paint
board.Add( new ns_whiteboard::rect( ns_whiteboard::xy_coords(x + x_offset, y_offset + y + 18),
ns_whiteboard::xy_coords(x + x_offset + 36, y + y_offset),
cc) );
// Draw the box
b.Draw(board,
ns_whiteboard::xy_coords(x + x_offset, y_offset + y + 18),
ns_whiteboard::xy_coords(x + x_offset + 36, y + y_offset));
// Fill in the gene name
board.Add( new ns_whiteboard::text( ns_whiteboard::xy_coords(x + x_offset + 3, y_offset + y + 5),
name[i], black, 14., "Times-Roman", 0, true));
x += 45.;
}
// Display & save
ofstream out(o.c_str());
ns_whiteboard::ps_display display(out, x_max + 2 * x_offset, y_max + 2 * y_offset);
board.DisplayOn(&display);
}
// Smooth out values
void Smooth(svec<double> & d, int mul)
{
int i, j;
for (j=0; j<500; j++) {
svec<double> tmp;
tmp.resize(d.isize(), 0.);
for (i=0; i<d.isize(); i++) {
if (i == 0 || i+1 == d.isize() || i % mul == 0) {
tmp[i] = d[i];
continue;
}
tmp[i] = (d[i] + d[i-1] + d[i+1])/3.;
}
d = tmp;
}
}
int main( int argc, char** argv )
{
// Utilities for command line parsing
commandArg<string> iStringO("-i","input file");
commandArg<string> aStringO("-o","outfile (post-script)");
commandLineParser P(argc,argv);
P.SetDescription("Color HOX genes by expression");
P.registerArg(iStringO);
P.registerArg(aStringO);
P.parse();
string o = P.GetStringValueFor(aStringO);
string inFile = P.GetStringValueFor(iStringO);
// File parser utility
FlatFileParser parser;
int i, j;
parser.Open(inFile);
svec<string> name;
svec< svec < double > > val;
// Let's interpolate between the data points for smoother transitions
int mul = 20;
int num = 0;
while(parser.ParseLine()) {
if (parser.GetItemCount() < 1) {
name.push_back("delim");
svec<double> dd;
val.push_back(dd);
continue;
}
if (parser.GetItemCount() == 1 && parser.AsString(0) == "-") {
name.push_back("empty");
svec<double> dd;
val.push_back(dd);
continue;
}
// NOTE: some hard-coded parameters
string n = parser.AsString(20);
cout << n << endl;
name.push_back(n);
svec<double> d;
for (i=1; i<10; i++) {
d.push_back(parser.AsFloat(i));
for (j=0; j<mul-1; j++)
d.push_back(0.);
}
Smooth(d, mul);
num = d.isize();
val.push_back(d);
}
int k = 1000;
// Let's draw one file per frame. Use 'convert' to make an animated gif
for (i=0; i<num; i++) {
char out[256];
sprintf(out, "%s%d.ps", o.c_str(), k);
DrawOne(out, i, val, name);
k++;
}
return 0;
}
Result: