#include <algorithm>#include <queue>#include "table.hpp"//#include "module.hpp"#include "cls_orange.hpp"#include "cls_example.hpp"#include "ppp/heatmap.ppp"#include "px/externs.px"#ifdef _MSC_VER#pragma warning (disable : 4786 4114 4018 4267 4244)#endifDEFINE_TOrangeVector_classDescription(PHeatmap,"THeatmapList",true,ORANGENE_API)/* Expands the bitmap Each pixel in bitmap 'smmp' is replaced by a square with given 'cellWidth' and 'cellHeight' The original bitmaps width and height are given by arguments 'width' and 'height' Beside returning the bitmap, the function return its size in bytes (argument '&size'). Due to alignment of rows to 4 bytes, this does not necessarily equal cellWidth * cellHeight * width * height.*/unsignedchar*bitmap2string(constint&cellWidth,constint&cellHeight,constint&firstRow,constint&nRows,long&size,float*intensity,constint&width,constint&height,constfloat&absLow,constfloat&absHigh,constfloat&gamma,boolgrid){constintlineWidth=width*cellWidth;constintfill=(4-lineWidth&3)&3;constintrowSize=lineWidth+fill;size=rowSize*nRows*cellHeight;unsignedchar*res=newunsignedchar[size];unsignedchar*resi=res;if(grid&&((cellHeight<3)||(cellWidth<3)))grid=false;intline=firstRow;intlline=firstRow+nRows;intensity+=firstRow*width;if(gamma==1.0){constfloatcolorFact=249.0/(absHigh-absLow);for(;line<lline;line++){intxpoints;unsignedchar*thisline=resi;for(xpoints=width;xpoints--;intensity++){unsignedcharcol;if(*intensity==UNKNOWN_F)col=255;elseif(*intensity<absLow)col=253;elseif(*intensity>absHigh)col=254;elsecol=int(floor(colorFact*(*intensity-absLow)));for(intinpoints=cellWidth;inpoints--;*(resi++)=col);if(grid)resi[-1]=252;}resi+=fill;for(xpoints=grid?cellHeight-2:cellHeight-1;xpoints--;resi+=rowSize)memcpy(resi,thisline,lineWidth);if(grid){memset(resi,252,rowSize);resi+=rowSize;}}}else{constfloatcolorBase=(absLow+absHigh)/2;constfloatcolorFact=2/(absHigh-absLow);for(;line<lline;line++){unsignedchar*thisline=resi;intxpoints;for(xpoints=width;xpoints--;intensity++){unsignedcharcol;if(*intensity==UNKNOWN_F)col=255;elseif(*intensity<absLow)col=253;elseif(*intensity>absHigh)col=254;else{floatnorm=colorFact*(*intensity-colorBase);if((norm>-0.008)&&(norm<0.008))norm=125;elsenorm=124.5*(1+(norm<0?-exp(gamma*log(-norm)):exp(gamma*log(norm))));if(norm<0)col=0;elseif(norm>249)col=249;elsecol=int(floor(norm));}for(intinpoints=cellWidth;inpoints--;*(resi++)=col);if(grid)resi[-1]=252;}resi+=fill;for(xpoints=grid?cellHeight-2:cellHeight-1;xpoints--;resi+=rowSize)memcpy(resi,thisline,lineWidth);if(grid){memset(resi,252,rowSize);resi+=rowSize;}}}returnres;}classCompareIndicesWClass{public:constvector<float>&centers;constvector<int>&classes;CompareIndicesWClass(constvector<float>&acen,constvector<int>&acl):centers(acen),classes(acl){};booloperator()(constint&i1,constint&i2){return(classes[i1]<classes[i2])||((classes[i1]==classes[i2])&&(centers[i1]<centers[i2]));}};classCompareIndicesClass{public:constvector<int>&classes;CompareIndicesClass(constvector<int>&acl):classes(acl){};booloperator()(constint&i1,constint&i2){returnclasses[i1]<classes[i2];}};classCompareIndices{public:constvector<float>&centers;CompareIndices(constvector<float>&acen):centers(acen){};booloperator()(constint&i1,constint&i2){returncenters[i1]<centers[i2];}};WRAPPER(ExampleTable);THeatmap::THeatmap(constint&h,constint&w,PExampleTableex):cells(newfloat[h*w]),averages(newfloat[h]),height(h),width(w),examples(ex),exampleIndices(newTIntList()){}THeatmap::~THeatmap(){deletecells;deleteaverages;}unsignedchar*THeatmap::heatmap2string(constint&cellWidth,constint&cellHeight,constint&firstRow,constint&nRows,constfloat&absLow,constfloat&absHigh,constfloat&gamma,boolgrid,long&size)const{returnbitmap2string(cellWidth,cellHeight,firstRow,nRows,size,cells,width,height,absLow,absHigh,gamma,grid);}unsignedchar*THeatmap::averages2string(constint&cellWidth,constint&cellHeight,constint&firstRow,constint&nRows,constfloat&absLow,constfloat&absHigh,constfloat&gamma,boolgrid,long&size)const{returnbitmap2string(cellWidth,cellHeight,firstRow,nRows,size,averages,1,height,absLow,absHigh,gamma,grid);}floatTHeatmap::getCellIntensity(constint&y,constint&x)const{if((y<0)||(y>=height))raiseError("row index out of range");if((x<0)||(y>=height))raiseError("column index out of range");returncells[y*width+x];}floatTHeatmap::getRowIntensity(constint&y)const{if((y<0)||(y>=height))raiseError("row index out of range");returnaverages[y];}voidTHeatmap::getPercentileInterval(constfloat&lowperc,constfloat&highperc,float&min,float&max)const{::getPercentileInterval(cells,width*height,lowperc,highperc,min,max);}THeatmapConstructor::THeatmapConstructor(){}THeatmapConstructor::THeatmapConstructor(PExampleTabletable,PHeatmapConstructorbaseHeatmap,boolnoSorting,booldisregardClass):sortedExamples(newTExampleTable(table,1)),// lock, but do not copyfloatMap(),classBoundaries(),lineCenters(),nColumns(table->domain->attributes->size()),nRows(table->numberOfExamples()),nClasses(0){TExampleTable&etable=table.getReference();if(baseHeatmap&&(etable.numberOfExamples()!=baseHeatmap->sortedExamples->numberOfExamples()))raiseError("'baseHeatmap has a different number of spots");TExampleTable&esorted=sortedExamples.getReference();boolhaveBase=baseHeatmap;PITERATE(TVarList,ai,etable.domain->attributes)if((*ai)->varType!=TValue::FLOATVAR)raiseError("data contains a discrete attribute '%s'",(*ai)->get_name().c_str());if(etable.domain->classVar&&!disregardClass){if(etable.domain->classVar->varType!=TValue::INTVAR)raiseError("class attribute is not discrete");nClasses=etable.domain->classVar->noOfValues();if(!haveBase)for(inti=nClasses+1;i;i--)classBoundaries.push_back(0);}else{nClasses=0;classBoundaries.push_back(0);classBoundaries.push_back(nRows);}vector<float*>tempFloatMap;vector<float>tempLineCenters;vector<float>tempLineAverages;vector<int>classes;tempFloatMap.reserve(nRows);tempLineCenters.reserve(nRows);if(!haveBase)sortIndices.reserve(nRows);boolpushSortIndices=!haveBase&&(!noSorting||nClasses);try{// Extract the data from the table, compute the centers and fill the sortIndicesEITERATE(ei,etable){if(pushSortIndices)sortIndices.push_back(sortIndices.size());float*i_floatMap=newfloat[nColumns];tempFloatMap.push_back(i_floatMap);if(nClasses){TValue&classVal=(*ei).getClass();constinttClass=classVal.isSpecial()?nClasses:classVal.intV;classes.push_back(tClass);classBoundaries[tClass+1]++;}if(nColumns>1){TExample::const_iteratoreii((*ei).begin());floatsumBri=0.0;floatsumBriX=0.0;intsumX=0;intN=0;floatthismax=-1e30f;floatthismin=1e30f;float*rai=i_floatMap;for(intxpoint=0;xpoint<nColumns;rai++,eii++,xpoint++){if((*eii).isSpecial()){*rai=UNKNOWN_F;}else{*rai=(*eii).floatV;sumBri+=*rai;sumBriX+=*rai*xpoint;sumX+=xpoint;N+=1;if(*rai>thismax)thismax=*rai;if(*rai<thismin)thismin=*rai;}}tempLineAverages.push_back(N?sumBri/N:UNKNOWN_F);tempLineCenters.push_back(N&&(thismax!=thismin)?(sumBriX-thismin*sumX)/(sumBri-thismin*N):UNKNOWN_F);}else{TValueval=*((*ei).begin());if(val.isSpecial()){*i_floatMap=UNKNOWN_F;tempLineAverages.push_back(UNKNOWN_F);tempLineCenters.push_back(UNKNOWN_F);}else{*i_floatMap=val.floatV;tempLineAverages.push_back(val.floatV);tempLineCenters.push_back(val.floatV);}}}if(haveBase){sortIndices=baseHeatmap->sortIndices;classBoundaries=baseHeatmap->classBoundaries;}else{if(nClasses)for(vector<int>::iteratorcbi(classBoundaries.begin()+1),cbe(classBoundaries.end());cbi!=cbe;*cbi+=cbi[-1],cbi++);if(!noSorting){if(nClasses){CompareIndicesWClasscompare(tempLineCenters,classes);sort(sortIndices.begin(),sortIndices.end(),compare);}else{CompareIndicescompare(tempLineCenters);sort(sortIndices.begin(),sortIndices.end(),compare);}}elseif(nClasses){// stable sort by classes onlyvector<int>mcb(classBoundaries);inti=0;sortIndices.resize(classes.size());for(vector<int>::const_iteratorci(classes.begin()),ce(classes.end());ci!=ce;sortIndices[mcb[*(ci++)]++]=i++);}}floatMap.reserve(nRows);lineCenters.reserve(nRows);lineAverages.reserve(nRows);if(sortIndices.size()){ITERATE(vector<int>,si,sortIndices){esorted.addExample(etable[*si]);lineCenters.push_back(tempLineCenters[*si]);lineAverages.push_back(tempLineAverages[*si]);floatMap.push_back(tempFloatMap[*si]);tempFloatMap[*si]=NULL;}}else{sortedExamples=mlnewTExampleTable(PExampleGenerator(etable),false);// just references to examples, not copieslineCenters=tempLineCenters;lineAverages=tempLineAverages;floatMap=tempFloatMap;}}catch(...){ITERATE(vector<float*>,tfmi,tempFloatMap)delete*tfmi;ITERATE(vector<float*>,fmi,floatMap)delete*fmi;throw;}}THeatmapConstructor::~THeatmapConstructor(){ITERATE(vector<float*>,fmi,floatMap)delete*fmi;}PHeatmapListTHeatmapConstructor::operator()(constfloat&unadjustedSqueeze,float&abslow,float&abshigh){abshigh=-1e30f;abslow=1e30f;PHeatmapListhml=newTHeatmapList;int*spec=newint[nColumns];for(intclassNo=0,ncl=nClasses?nClasses:1;classNo<ncl;classNo++){constintclassBegin=classBoundaries[classNo];constintclassEnd=classBoundaries[classNo+1];if(classBegin==classEnd){THeatmap*hm=newTHeatmap(0,nColumns,sortedExamples);hml->push_back(hm);hm->exampleIndices->push_back(classBegin);hm->exampleIndices->push_back(classBegin);continue;}intnLines=int(floor(0.5+(classEnd-classBegin)*unadjustedSqueeze));if(!nLines)nLines++;constfloatsqueeze=float(nLines)/(classEnd-classBegin);THeatmap*hm=newTHeatmap(nLines,nColumns,sortedExamples);hml->push_back(hm);float*fmi=hm->cells;float*ami=hm->averages;floatinThisRow=0;float*ri,*fri;int*si;intxpoint;vector<float>::const_iteratorlavi(lineAverages.begin());intexampleIndex=classBegin;hm->exampleIndices->push_back(exampleIndex);for(vector<float*>::iteratorrowi=floatMap.begin()+classBegin,rowe=floatMap.begin()+classEnd;rowi!=rowe;nLines--,inThisRow-=1.0,ami++,fmi+=nColumns){for(xpoint=nColumns,ri=fmi,si=spec;xpoint--;*(ri++)=0.0,*(si++)=0);*ami=0.0;intnDefinedAverages=0;for(;(rowi!=rowe)&&((inThisRow<1.0)||(nLines==1));inThisRow+=squeeze,rowi++,exampleIndex++,lavi++){for(xpoint=nColumns,fri=*rowi,ri=fmi,si=spec;xpoint--;fri++,ri++,si++)if(*fri!=UNKNOWN_F){*ri+=*fri;(*si)++;}if(*lavi!=UNKNOWN_F){*ami+=*lavi;nDefinedAverages++;}}hm->exampleIndices->push_back(exampleIndex);for(xpoint=nColumns,si=spec,ri=fmi;xpoint--;ri++,si++){if(*si){*ri=*ri/*si;if(*ri<abslow)abslow=*ri;if(*ri>abshigh)abshigh=*ri;}else*ri=UNKNOWN_F;}*ami=nDefinedAverages?*ami/nDefinedAverages:UNKNOWN_F;}}deletespec;returnhml;}unsignedchar*THeatmapConstructor::getLegend(constint&width,constint&height,constfloat&gamma,long&size)const{float*fmp=newfloat[width],*fmpi=fmp;floatwi1=width-1;for(intwi=0;wi<width;*(fmpi++)=(wi++)/wi1);unsignedchar*legend=bitmap2string(1,height,0,1,size,fmp,width,1,0,1,gamma,false);deletefmp;returnlegend;}