/* MELODIC - Multivariate exploratory linear optimized decomposition into independent components melreport.h - report generation Christian F. Beckmann, FMRIB Image Analysis Group Copyright (C) 1999-2007 University of Oxford */ /* CCOPYRIGHT */ #ifndef __MELODICREPORT_h #define __MELODICREPORT_h #include "newimage/newimageall.h" #include "utils/log.h" #include "melpca.h" #include "meloptions.h" #include "meldata.h" #include "melgmix.h" #include "melodic.h" #include "newmatap.h" #include "newmatio.h" #include <time.h> #include <strstream> #include "libvis/miscplot.h" #include "libvis/miscpic.h" #include "utils/options.h" using namespace Utilities; using namespace NEWIMAGE; using namespace MISCPLOT; using namespace MISCPIC; namespace Melodic{ class MelodicReport{ public: MelodicReport(MelodicData &pmelodat, MelodicOptions &popts, Log &plogger): melodat(pmelodat), opts(popts), logger(plogger){ if( bool(opts.genreport.value()) ){ const time_t tmptime = time(NULL); report.makeDir(logger.appendDir("report"),"00index.html"); report << "<HTML><HEAD><link REL=stylesheet TYPE=text/css href=file:" + (string) getenv("FSLDIR") +"/doc/fsl.css>" << "<TITLE>MELODIC report</TITLE></HEAD><BODY>" << endl <<endl; loghtml.setDir(report.getDir(),"log.html"); loghtml << "<HTML><HEAD><link REL=stylesheet TYPE=text/css href=file:" + (string) getenv("FSLDIR") +"/doc/fsl.css>" << "<TITLE>MELODIC report</TITLE></HEAD><BODY>" << endl <<endl; navigator.setDir(report.getDir(),"nav.html"); head.setDir(report.getDir(),"head.html"); navigator << "<link REL=stylesheet TYPE=text/css href=file:"+ (string) getenv("FSLDIR") +"/doc/fsl.css>" << endl; head << "<link REL=stylesheet TYPE=text/css href=file:"+ (string) getenv("FSLDIR") +"/doc/fsl.css>" << endl; head <<"<TABLE BORDER=0><TR>" << endl <<" <TD ALIGN=CENTER WIDTH=100%>"<< endl <<"<TABLE BORDER=0>"<< endl <<"<tr><td align=center><font size=+3><b>MELODIC Report</b>"<< endl <<"</font><tr><td valign=center align=center> <p>"<< endl << report.getDir() << "/" << report.getLogFileName() << "<br>" << ctime(&tmptime) << "</tr>"<< endl <<"<tr valign=bottom><td align=center>"<< endl << "</tr></table>" << endl << "<TD ALIGN=RIGHT>" << endl << "<a href=http://www.fmrib.ox.ac.uk/fsl target=_top>" << endl << "<IMG BORDER=0 SRC=file:"<< getenv("FSLDIR") << "/doc/images/fsl-logo-big.jpg WIDTH=165></a>" << endl << "</TD>"<<endl<<"</TR></TABLE> <hr>"<<endl; if(opts.guireport.value()==""){ report <<"<OBJECT data=head.html></OBJECT>" << endl; loghtml <<"<OBJECT data=head.html></OBJECT>" << endl; }else{ report <<"<OBJECT data="<<opts.guireport.value()<< "></OBJECT>"<< endl; loghtml <<"<OBJECT data="<<opts.guireport.value()<< "></OBJECT>"<< endl; } report << "<IFRAME height=80px width=100% src=nav.html frameborder=0></IFRAME><p>"<< endl; loghtml << "<IFRAME height=100px width=100% src=nav.html frameborder=0></IFRAME><p>" <<"<pre>../melodic.log</pre>" <<endl; navigator <<"<CENTER><TABLE BORDER=0><TR>" << endl <<"<TD ALIGN=CENTER WIDTH=100%><FONT SIZE=-1>"<<endl <<"<A HREF=\"00index.html\" target=\"_top\">Main</A> - "; // if(opts.guireport.value()=="") // navigator << "<A HREF=\"log.html\" target=\"_top\">Log</A> - "; navigator <<"Components: "; navigator.flush(); } } ~MelodicReport(){ if( bool(opts.genreport.value()) ){ report << "<HR><CENTER><FONT SIZE=1>This page produced automatically by " << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC</A> Version " << version << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - " << "FMRIB Software Library</A>.</FONT></CENTER>" << endl << "</BODY></HTML>" <<endl; loghtml << "<HR><CENTER><FONT SIZE=1>This page produced automatically by " << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC</A> Version " << version << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - " << "FMRIB Software Library</A>.</FONT></CENTER>" << endl << "</BODY></HTML>" <<endl; navigator << "</FONT></TD>"<<endl<<"</TR></TABLE></CENTER><hr>" <<endl; } } inline void analysistxt(){ if( bool(opts.genreport.value()) ){ report << "<b>Analysis methods</b> <br>"<<endl; report << "Analysis was carried out using MELODIC (Multivariate Exploratory Linear Decomposition into Independent Components) Version "<< version <<", part of FSL (FMRIB's Software Library, <A HREF=\"http://www.fmrib.ox.ac.uk/fsl/\">www.fmrib.ox.ac.uk/fsl</A>), an implementation for the estimation of a Probabilistic Independent Component Analysis model [Beckmann 2004]."<<endl; report << "The following melodic pre-processing was applied to the input data file: "<< endl; if(opts.use_mask.value()) report << " masking of non-brain voxels;"; report << " voxel-wise de-meaning of the data;" << endl; if(opts.varnorm.value()) report << " normalisation of the voxel-wise variance; "; report << "<br>"<<endl; report << " Pre-processed data was whitened and projected into a " << melodat.get_mix().Ncols()<< "-dimensional subspace using "; if(melodat.get_PPCA().Storage()>0){ report << "probabilistic Principal Component Analysis where the number of dimensions was estimated using "; if(opts.pca_est.value() == string("lap")) report << "the Laplace approximation to the Bayesian evidence of the model order [Minka 2000, Beckmann 2004]. " << endl; else if(opts.pca_est.value() == string("bic")) report << "the <em> Bayesian Information Criterion</em> (BIC) [Kass 1993]. " << endl; else if(opts.pca_est.value() == string("mdl")) report << "<em> Minimum Description Length</em> (MDL) [Rissanen 1978]. " << endl; else if(opts.pca_est.value() == string("aic")) report << "the <em> Akaike Information Criterion</em> (AIC) [Akaike 1969]. " << endl; else report << "a committee of approximations to Bayesian the model order [Beckmann 2004]. " << endl; } else report << "Principal Component Analysis. "; report << " The whitened observations were decomposed into a set of time-courses and spatial maps by optimising for non-Gaussian spatial source distributions using a fixed-point iteration technique [Hyvärinen 1999]. " << endl; report << "Estimated Component maps were divided by the standard deviation of the residual noise"; if(opts.perf_mm.value()) report << " and thresholded by fitting a mixture model to the histogram of intensity values [Beckmann 2004]. <p>" << endl; else report <<".<p>" << endl; refstxt(); } } inline void refstxt(){ if( bool(opts.genreport.value()) ){ report << "<b>References</b> <br>"<<endl; report << "[Hyvärinen 1999] A. Hyvärinen. Fast and Robust Fixed-Point Algorithms for Independent Component Analysis. IEEE Transactions on Neural Networks 10(3):626-634, 1999.<br> " << endl; report << "[Beckmann 2004] C.F. Beckmann and S.M. Smith. Probabilistic Independent Component Analysis for Functional Magnetic Resonance Imaging. IEEE Transactions on Medical Imaging 23(2):137-152 2004. <br>" << endl; if(melodat.get_PPCA().Storage()>0){ report << "[Everson 2000] R. Everson and S. Roberts. Inferring the eigenvalues of covariance matrices from limited, noisy data. IEEE Trans Signal Processing, 48(7):2083-2091, 2000<br>"<<endl; report << "[Tipping 1999] M.E. Tipping and C.M.Bishop. Probabilistic Principal component analysis. J Royal Statistical Society B, 61(3), 1999. <br>" << endl; /* report << "[Beckmann 2001] C.F. Beckmann, J.A. Noble and S.M. Smith. Investigating the intrinsic dimensionality of FMRI data for ICA. In Seventh Int. Conf. on Functional Mapping of the Human Brain, 2001. <br>" << endl;*/ if(opts.pca_est.value() == string("lap")) report << "[Minka 2000] T. Minka. Automatic choice of dimensionality for PCA. Technical Report 514, MIT Media Lab Vision and Modeling Group, 2000. <BR>"<< endl; else if(opts.pca_est.value() == string("bic")) report << "[Kass 1995] R.E. Kass and A. E. Raftery. Bayes factors. Journal of the American Statistical Association, 90:733-795, 1995 <br>" << endl; else if(opts.pca_est.value() == string("mdl")) report << "[Rissanen 1978]. J. Rissanen. Modelling by shortest data description. Automatica, 14:465-471, 1978. <br>" << endl; else if(opts.pca_est.value() == string("aic")) report << "[Akaike 1974]. H. Akaike. A new look at statistical model identification. IEEE Transactions on Automatic Control, 19:716-723, 1974. <br>" << endl; else report << "[Minka 2000]. T. Minka. Automatic choice of dimensionality for PCA. Technical Report 514, MIT Media Lab Vision and Modeling Group, 2000. <BR>" << endl; } } } inline void addtxt(string what){ if( bool(opts.genreport.value()) ){ report << what << endl; } } inline void addpar(string what){ if( bool(opts.genreport.value()) ){ report << "<p>" << what << endl; } } inline void addlink(string where, string what){ if( bool(opts.genreport.value()) ){ navigator << "<A HREF=\"" << where << " \"target=\"_top\"> " << what << "</A> "; navigator.flush(); } } inline void addpic(string what, string link = ""){ if( bool(opts.genreport.value()) ){ if( link.length() > 0) report << "<A HREF=\"" << link << "\"> "; report << "<img BORDER=0 SRC=\"" << what<< ".png\"><p>"; if( link.length() > 0) report << "</A> "; } } inline string getDir(){ return report.getDir(); } void IC_rep(MelGMix &mmodel, int cnum, int dim, Matrix ICstats); void IC_simplerep(string prefix, int cnum, int dim); void PPCA_rep(); void Smode_rep(); private: MelodicData &melodat; MelodicOptions &opts; Log &logger; Log report; Log navigator; Log head; Log loghtml; Log IChtml; Log IChtml2; void IC_rep_det(MelGMix &mmodel, int cnum, int dim); string int2str(int n){ ostrstream os; // os.fill(' '); // os.width(width); os.setf(ios::internal, ios::adjustfield); os << n << '\0'; return os.str(); } string float2str(float f, int width, int prec, int scientif){ ostrstream os; int redw = int(std::abs(std::log10(std::abs(f))))+1; if(width>0) os.width(width); if(scientif>0) os.setf(ios::scientific); os.precision(redw+std::abs(prec)); os.setf(ios::internal, ios::adjustfield); os << f << '\0'; return os.str(); } }; } #endif