// // Programmer: Craig Stuart Sapp // Creation Date: Sat Jul 1 02:48:55 PDT 2006 // Last Modified: Tue Jul 4 06:53:48 PDT 2006 // Last Modified: Mon Aug 21 04:06:54 PDT 2006 (added polycorrelation plots) // Last Modified: Sat May 12 04:49:15 PDT 2007 (added gradient coloring) // Last Modified: Sat May 12 09:23:11 PDT 2007 (added smoothing) // Last Modified: Sun May 13 00:07:45 PDT 2007 (added data plotting) // Last Modified: Sat Aug 18 21:54:01 PDT 2007 (added bi-feature plotting) // Filename: ...sig/examples/all/hicor.cpp // Web Address: http://sig.sapp.org/examples/museinfo/hicor/hicor.cpp // Syntax: C++; museinfo // // Description: Generate a hierarchical correlation plot from a // pair of number sequences. // #include "Array.h" #include "Options.h" #include "PixelColor.h" #include #include #include #ifndef OLDCPP using namespace std; #include #include #else #include #include #endif #define COLOR_BW 0 #define COLOR_HUE 1 #define SHAPE_TRIANGLE 0 #define SHAPE_RECTANGLE 1 // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void calculateAverage (Array >& correlations, Array& a); void calculateCorrelations (Array >& correlations, Array& a, Array& b); double pearsonCorrelation (int size, double* a, double* b); double getMean (int size, double* a); void printImageTriangle (Array >& correlation); void printImageRectangle (Array >& correlation); void printCorrelationPixel (double value, int style); double average (int size, double* data); void normalizeAverageData (Array >& correlations); double getStandardDeviation (double mean, Array& data); int logScale (int level, int maxlevel, double factor); void calculateAverageDifference(Array >& correlations, Array& a, Array& b); void makeSineArch (Array& arch, int size); void makeRamp (Array& ramp, int size); void calculateArchCorrelations(Array >& correlations, Array& a); void calculateRampCorrelations(Array >& correlations, Array& a); void calculateGradient (Array >& gradient, Array >& correlations); int getGradient (Array >& scape, int row, int col); void smoothSequence (Array& sequence, double gain); void unsmoothSequence (Array& sequence, double gain); void printDataPlot (Array& a, Array& b, int height, int gridlines); void printBiCorrelationPixel(double value, double valueB, int style); void printBiImageTriangle (Array >& correlation, Array >& correlationB); void printBiImageRectangle (Array >& correlation, Array >& correlationB); // User interface variables: Options options; int dataq = 0; // debug: display input data only with -d int correlq = 0; // debug: display correlations with -c int colortype = COLOR_BW; // used with various color options int plotshape = SHAPE_TRIANGLE; // used with -r option int averageq = 0; // used with -a option int diffq = 0; // display average differences with -d option int condiffq = 0; // display contoured differences, --cd option int column = 0; // used with -n option (for averaging) int logq = 0; // used with -g option double logfactor = 1500; // used with -f option int flipq = 0; // flip the data from tempo to duration int polyq = 0; // used with -p option int archq = 0; // used with -A option int rampq = 0; // used with -R option int maxheight = -1; // used with --height option int gradientq = 0; // used with -G option double smooth = 0.0; // used with -S option int hline = 0; // used with -H option int plotq = 0; // used with -P option int unsmoothq = 0; // used with -U option int bifeature = 0; // used with -b option int bgval = 80; // no interface to user yet ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { // process the command-line options checkOptions(options, argc, argv); double aval; double bval; Array a; Array b; a.setSize(100000); a.setGrowth(100000); a.setSize(0); b.setSize(100000); b.setGrowth(100000); b.setSize(0); ifstream infile; string filename = ""; if (options.getArgCount() <= 0) { filename = ""; } else { filename = options.getArg(1); infile.open(filename.c_str(), ios::in); } if (!infile.is_open()) { cerr << "Cannot open file for reading: " << filename << endl; exit(1); } char templine[4096]; if (averageq) { while (!infile.eof()) { infile.getline(templine, 4096, '\n'); if (infile.eof() && (strcmp(templine, "") == 0)) { break; } else if (sscanf(templine, "%lf\t%lf", &aval, &bval) == 2) { if (flipq) { aval = 60.0 / aval; bval = 60.0 / bval; } a.append(aval); b.append(bval); } else if (sscanf(templine, "%lf", &aval) == 1) { if (flipq) { aval = 60.0 / aval; } a.append(aval); b.append(aval); } } } else { while (!infile.eof()) { infile.getline(templine, 4096, '\n'); if (infile.eof() && (strcmp(templine, "") == 0)) { break; } else { if (sscanf(templine, "%lf\t%lf", &aval, &bval) == 2) { if (flipq) { aval = 60.0 / aval; bval = 60.0 / bval; } a.append(aval); b.append(bval); } else if (sscanf(templine, "%lf", &aval) == 1) { if (flipq) { aval = 60.0 / aval; } a.append(aval); b.append(aval); } } } } if (smooth != 0.0) { if (!unsmoothq) { smoothSequence(a, smooth); smoothSequence(b, smooth); } else { unsmoothSequence(a, smooth); unsmoothSequence(b, smooth); } } int i, j; if (dataq) { for (i=0; i > correlations; Array > correlationsB; correlations.setSize(a.getSize()); correlationsB.setSize(a.getSize()); for (i=0; i > gradient; if (gradientq) { calculateGradient(gradient, correlations); switch (plotshape) { case SHAPE_RECTANGLE: printImageRectangle(gradient); break; case SHAPE_TRIANGLE: default: printImageTriangle(gradient); } } else { if (bifeature) { switch (plotshape) { case SHAPE_RECTANGLE: printBiImageRectangle(correlations, correlationsB); break; case SHAPE_TRIANGLE: default: printBiImageTriangle(correlations, correlationsB); } } else { switch (plotshape) { case SHAPE_RECTANGLE: printImageRectangle(correlations); break; case SHAPE_TRIANGLE: default: printImageTriangle(correlations); } } } if (plotq) { printDataPlot(a, b, plotq, hline); } return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printDataPlot -- print an input data plot underneath the scape. // void printDataPlot(Array& a, Array& b, int height, int gridlines) { PixelColor pc; pc.setColor(255,0,0); int i, j; int rows = height; int cols = a.getSize() * 2; Array > plotregion; plotregion.setSize(rows); plotregion.allowGrowth(0); for (i=0; i 0: if (gridlines > 0) { for (j=0; j maxx) { maxx = a[i]; } } double i1; double i2; int x1; int x2; int k; int xlow; int xhi; for (j=0; j= rows) { i = rows-1; } plotregion[i][2*j].setColor(0,0,255); if (j < a.getSize()-1) { i2 = (a[j+1] - minn)/(maxx - minn) * rows; x1 = rows - int(i1) - 1; x2 = rows - int(i2) - 1; if (x1 < 0) { x1 = 0; } if (x1 >= rows) { x1 = rows-1; } if (x2 < 0) { x2 = 0; } if (x2 >= rows) { x2 = rows-1; } if (x1 < x2) { xlow = x1; xhi = x2; } else { xlow = x2; xhi = x1; } for (k=xlow+1; k >& correlation, Array >& correlationB) { string background = options.getString("background"); int maxcolumn = correlation.getSize() * 2; int maxrow = (correlation.getSize()-1) * 2; cout << "P3\n"; cout << maxcolumn << " " << maxrow << "\n"; cout << "255\n"; int i, j; int ii; int datawidth; int bgwidth; for (i=0; i >& correlation) { string background = options.getString("background"); int maxcolumn = correlation.getSize() * 2; int maxrow = (correlation.getSize()-1) * 2; cout << "P3\n"; cout << maxcolumn << " " << maxrow << "\n"; cout << "255\n"; int i, j; int ii; int datawidth; int bgwidth; for (i=0; i >& correlation) { PixelColor background; background.setColor(options.getString("background")); int maxcolumn = correlation.getSize() * 2; int maxrow = (correlation.getSize()) * 2; int startrow = 0; if (maxheight > 0 && maxheight < correlation.getSize()) { startrow = correlation.getSize() - maxheight; maxrow = (maxheight) * 2; } cout << "P3\n"; cout << maxcolumn << " " << maxrow + plotq << "\n"; cout << "255\n"; int i, j; Array > mainplot; mainplot.setSize(maxrow); mainplot.allowGrowth(0); for (i=0; i 0) { if ((correlation.getSize() - i - 1 + 1) % hline == 0) { bgline = 1; } else { bgline = 0; } } ii = i; if (logq) { ii = logScale(i, correlation.getSize(), logfactor); } datawidth = correlation[ii].getSize(); bgwidth = (maxcolumn - datawidth * 2)/2; xxx for (j=0; j >& correlation, Array >& correlationB) { int maxcolumn = correlation.getSize() * 2; int maxrow = (correlation.getSize()-1) * 2; if (maxheight > 0 && maxheight < maxrow) { maxrow = maxheight; } cout << "P3\n"; cout << maxcolumn << " " << maxrow << "\n"; cout << "255\n"; int i, j; int datawidth; int jstretch; for (i=0; i >& correlation) { int maxcolumn = correlation.getSize() * 2; int maxrow = (correlation.getSize()-1) * 2; if (maxheight > 0 && maxheight < maxrow) { maxrow = maxheight; } cout << "P3\n"; cout << maxcolumn << " " << maxrow << "\n"; cout << "255\n"; int i, j; int datawidth; int jstretch; for (i=0; i 0) { pc.setColor(255,0,0); } else if (value < 0) { pc.setColor(0,0,255); } else { pc.setColor(255,255,255); } } else if (condiffq) { if (value > 0.210) { pc.setColor(252,41,41); } // red else if (value > 0.150) { pc.setColor(252,41,210); } // pink else if (value > 0.090) { pc.setColor(255,144,41); } // orange else if (value > 0.030) { pc.setColor(223,250,35); } // yellow else if (value > -0.030) { pc.setColor(239,239,239); } // whiteish else if (value > -0.090) { pc.setColor(148,247,138); } // green else if (value > -0.150) { pc.setColor(82,246,221); } // lt blue else if (value > -0.210) { pc.setColor(36,59,227); } // dk blue else if (value <= -0.210) { pc.setColor(80,4,184); } // violet } } else { // print gradient colors switch (int(value+0.1)) { case 6: pc.setColor(80,4,184); break; // violet case 5: pc.setColor(36,59,227); break; // dk blue case 4: pc.setColor(82,246,221); break; // lt blue case 3: pc.setColor(148,247,138); break; // green case 2: pc.setColor(223,250,35); break; // yellow case 1: pc.setColor(255,144,41); break; // orange case 0: pc.setColor(252,41,41); break; // red default: pc.setColor(255,255,255); break; // white (invalid option) } pc.invert(); pc = pc / 4.0; pc.invert(); if (int(value+0.1) == 0) { pc.setColor(255,0,0); } } cout << " "; pc.writePpm3(cout); cout << " "; // repeat the cell for a square image cout << " "; pc.writePpm3(cout); cout << " "; } ////////////////////////////// // // calculateAverage -- // void calculateAverage(Array >& correlations, Array& a) { int i, j; double *aa; int rowsize; int corelsize; for (i=0; i >& correlations) { int i, j; double mean = 0.0; for (i=0; i& data) { double sum = 0.0; double value; int i; for (i=0; i >& correlations, Array& a, Array& b) { int i, j; double *aa; double *bb; double aval = 1.0; double bval = 1.0; int rowsize; int corelsize; for (i=0; i >& correlations, Array& a, Array& b) { int i, j; double *aa; double *bb; int rowsize; int corelsize; for (i=0; i 1) { column = 1; } dataq = opts.getBoolean("data"); correlq = opts.getBoolean("correlation"); if (opts.getBoolean("hue")) { colortype = COLOR_HUE; } if ((rampq || archq) && opts.getBoolean("gradient")) { gradientq = 1; } if (opts.getBoolean("rectangle")) { plotshape = SHAPE_RECTANGLE; } } ////////////////////////////// // // makeSineArch -- generate a sqrt sine half-cycle arch of the // specified length. // void makeSineArch(Array& arch, int size) { arch.setSize(size); arch.allowGrowth(0); if (size == 1) { arch[0] = 0; return; } int i; double freq = 2.0 * M_PI / ((size-1) * 2.0); for (i=0; i& ramp, int size) { ramp.setSize(size); ramp.allowGrowth(0); if (size == 1) { ramp[0] = 0; } double factor = 1.0 / (size - 1.0); int i; for (i=0; i >& correlations, Array& a) { Array arch; int i, j; double *aa; double *bb; int rowsize; int corelsize; for (i=0; i >& gradient, Array >& correlations) { int i, j; int colsize; gradient.setSize(correlations.getSize()); gradient.allowGrowth(0); for (i=0; i >& scape, int row, int col) { int rows = scape.getSize(); int cols = scape[row].getSize(); int output = 0; double ax = scape[row][col]; /* When the rows are indexedfrom the bottom: // to the right if (col + 1 < cols) { if (ax < scape[row][col+1]) { output = 1; } } // to the upper right if (row + 1 < rows && col < cols-1) { if (ax < scape[row+1][col]) { output = 2; } } // to the upper left if (row + 1 < rows && col - 1 >= 0) { if (ax < scape[row+1][col-1]) { output = 3; } } // to the left if (col - 1 >= 0) { if (ax < scape[row][col-1]) { output = 4; } } // to the lower left if (row - 1 >= 0) { if (ax < scape[row-1][col]) { output = 5; } } // to the lower right if (row - 1 >= 0 && col + 1 < cols+1) { if (ax < scape[row-1][col]+1) { output = 6; } } */ // when the rows are indexed from the top: // to the right if (col + 1 < cols) { if (ax < scape[row][col+1]) { output = 1; ax = scape[row][col+1]; } } // to the upper right if (row - 1 >= 0 && col < cols-1) { if (ax < scape[row-1][col]) { output = 2; ax = scape[row-1][col]; } } // to the upper left if (row - 1 >= 0 && col - 1 >= 0) { if (ax < scape[row-1][col-1]) { output = 3; ax = scape[row-1][col-1]; } } // to the left if (col - 1 >= 0) { if (ax < scape[row][col-1]) { output = 4; ax = scape[row][col-1]; } } // to the lower left if (row + 1 < rows) { if (ax < scape[row+1][col]) { output = 5; ax = scape[row+1][col]; } } // to the lower right if (row + 1 < rows && col + 1 < cols+1) { if (ax < scape[row+1][col+1]) { output = 6; ax = scape[row+1][col+1]; } } return output; } ////////////////////////////// // // smoothSequence -- smooth the sequence with a // symmetric exponential smoothing filter (applied in the forward // and reverse directions with the specified input gain. // // Difference equation for smoothing: y[n] = k * x[n] + (1-k) * y[n-1] // void smoothSequence(Array& sequence, double gain) { double oneminusgain = 1.0 - gain; int i; int ssize = sequence.getSize(); // reverse filtering first for (i=ssize-2; i>=0; i--) { sequence[i] = gain*sequence[i] + oneminusgain*sequence[i+1]; } // then forward filtering for (i=1; i& sequence, double gain) { Array smoothed = sequence; smoothSequence(smoothed, gain); int i; for (i=0; i >& correlations, Array& a) { Array ramp; int i, j; double *aa; double *bb; int rowsize; int corelsize; for (i=0; i