Histo2DFunction.cc 8.8 KB
/*
 * Histo2DFunction.cc
 *
 *  Created on: Feb 01, 2023
 *      Author: AKKODIS
 */
#include "Histo2DFunction.hh"
#include <map>
#include <cmath>
#include <numeric>
#include <algorithm>

namespace plot {

// Basically transforms the data to a matrix by keeping all the values needed later
std::map<int,std::vector<double>> Histo2DFunction::getMatrixValues(double* xData, double* yData, double* zData, int nbData, 
																	Range xRange, Range yRange, int xBinNumber,int yBinNumber)
{
	std::map<int,std::vector<double>> allValues;

	double xMin = xRange.getMin();
	double yMin = yRange.getMin();
	double xMax = xRange.getMax();
	double yMax = yRange.getMax();

	double xBinSize = (xMax - xMin)/xBinNumber;
	double yBinSize = (yMax - yMin)/yBinNumber;

	for (int i(0); i< nbData; ++i){

		if (xData[i] < xMin || yData[i] < yMin || xData[i] >= xMax || yData[i] >= yMax || std::isnan(xData[i]) || std::isnan(yData[i]) || std::isnan(zData[i]) || std::isnan(zData[i]))
			continue;
		
		int xIndex = (xData[i]- xMin)/xBinSize;
		int yIndex = (yData[i]- yMin)/yBinSize;
		int index = xIndex*yBinNumber+yIndex;

		allValues[index].push_back(zData[i]);
	}
	return allValues;
}

// Function that apply smooth, independing on the applied function
void Histo2DFunction::applySmooth(MatrixGrid &matrixGrid, int smoothFactor, int columnSize )
{
	GridPart newGrid;
	MatrixGrid newMatrix;

	int matrixSize = matrixGrid.size();

	for(int i(0); i< matrixSize; ++i ){
		newGrid = matrixGrid[i];

		newGrid.value = 0;
		int compteur = 0;

			for(int j=-smoothFactor+1; j < smoothFactor; j++ ){
				if(i+j*columnSize < 0 || i+j*columnSize > matrixSize)
					continue; 
				
				int columnRef = (i+j*columnSize) / columnSize;

				for (int k=-smoothFactor+1; k < smoothFactor; k++ )
				{
					int currentIndex = i+j*columnSize+k;
					int column = currentIndex/columnSize;
					if(column != columnRef || currentIndex < 0 || currentIndex >= matrixSize)
						continue;
					
					if(!isnan(matrixGrid[currentIndex].value )){
						newGrid.value += matrixGrid[currentIndex].value ;
						compteur++;
					}
				}
			}
			newGrid.value /= compteur;
		newMatrix.push_back(newGrid);
	}
	matrixGrid = newMatrix;
}

// Density function for 2DHistogram
void Density2DFunction::apply(MatrixGrid &matrixGrid,  double* xData, double* yData, double* /*zData*/, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax, int smoothFactor)
{
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,yData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		if (allValues[i].size() > 0)
			matrixGrid[i].value=allValues[i].size();
		
		if(zMax < matrixGrid[i].value)
			zMax = matrixGrid[i].value;
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Normalized density function for 2DHistogram
void NormDensity2DFunction::apply(MatrixGrid &matrixGrid,  double* xData, double* yData, double* /*zData*/, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax, int smoothFactor)
{
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,yData,nbData,xRange,yRange,xBinNumber,yBinNumber);
	int nbRecord = 0;
	for(unsigned int i(0); i < allValues.size();++i){
		nbRecord += allValues[i].size();
	}
	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		if (allValues[i].size() > 0)
			matrixGrid[i].value=1.*allValues[i].size()/nbRecord;
		
		if(zMax < matrixGrid[i].value)
			zMax = matrixGrid[i].value;
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Mean function for 2DHistogram (for each bin)
void Mean2DFunction::apply(MatrixGrid &matrixGrid, double* xData, double* yData,  double* zData, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax,int smoothFactor){
	
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,zData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
        double mean = NAN;
        if (!allValues[i].empty()) {
            int nb = 0;
            for (std::vector<double>::iterator it = allValues[i].begin(); it != allValues[i].end(); ++it){
                if (std::isfinite(*it) && !std::isnan(*it)) {
                    if (std::isnan(mean)) {
                        mean = 0;
                    }
                    mean += *it;
                    nb++;
                }
            }
            if (nb > 0) {
                mean /= nb;
            }
        }        
		matrixGrid[i].value = mean;

        if(zMax < matrixGrid[i].value)
			zMax = matrixGrid[i].value;
		if(zMin > matrixGrid[i].value)
			zMin = matrixGrid[i].value;
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Maximum function for 2DHistogram (for each bin)
void Max2DFunction::apply(MatrixGrid &matrixGrid, double* xData, double* yData,  double* zData, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax,int smoothFactor){
	
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,zData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		double max;
		if (allValues[i].size() >= 1)
		{
			for(unsigned int j(0); j < allValues[i].size();++j){
				if (j == 0)
					max = allValues[i][j];
				if (max < allValues[i][j])
					max = allValues[i][j];
			}
			matrixGrid[i].value= max;
			
			if(zMax < matrixGrid[i].value)
				zMax = matrixGrid[i].value;
			if(zMin > matrixGrid[i].value)
				zMin = matrixGrid[i].value;
		}
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Minimum function for 2DHistogram (for each bin)
void Min2DFunction::apply(MatrixGrid &matrixGrid, double* xData, double* yData,  double* zData, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax,int smoothFactor){
	
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,zData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		double min;
		if (allValues[i].size() >= 1)
		{
			for(unsigned int j(0); j < allValues[i].size();++j){
				if (j == 0)
					min = allValues[i][j];
				if (min > allValues[i][j])
					min = allValues[i][j];
			}
			matrixGrid[i].value= min;
			
			if(zMax < matrixGrid[i].value)
				zMax = matrixGrid[i].value;
			if(zMin > matrixGrid[i].value)
				zMin = matrixGrid[i].value;
		}
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Median function for 2DHistogram (for each bin)
void Median2DFunction::apply(MatrixGrid &matrixGrid, double* xData, double* yData,  double* zData, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax,int smoothFactor){
	
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,zData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		if (allValues[i].size() >= 1)
		{
			std::sort(allValues[i].begin(), allValues[i].end());
			if(allValues.size() %2 == 0)
				matrixGrid[i].value= (allValues[i][allValues[i].size()/2-1] + allValues[i][allValues[i].size()/2])/2;
			else
				matrixGrid[i].value = allValues[i][allValues[i].size()/2];
			
			if(zMax < matrixGrid[i].value)
				zMax = matrixGrid[i].value;
			if(zMin > matrixGrid[i].value)
				zMin = matrixGrid[i].value;
		}
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}

// Standard deviation function for 2DHistogram (for each bin)
void StandardDeviation2DFunction::apply(MatrixGrid &matrixGrid, double* xData, double* yData,  double* zData, int nbData, Range xRange, Range yRange, 
								int xBinNumber,int yBinNumber, double& zMin, double& zMax,int smoothFactor){
	
	zMin = 0;
	zMax = 0;
	std::map<int,std::vector<double>> allValues;
	allValues = getMatrixValues(xData,yData,zData,nbData,xRange,yRange,xBinNumber,yBinNumber);

	for (unsigned int i(0); i < matrixGrid.size(); ++i){
		if (allValues[i].size() >= 1)
		{

			double mean = 0.0;
    		for (double x : allValues[i]) {
				mean += x;
			}
			mean /= allValues[i].size();

			double variance = 0.0;
			for (double x : allValues[i]) {
				variance += (x - mean) * (x - mean);
			}
			variance /= allValues[i].size();
			matrixGrid[i].value = std::sqrt(variance);
			
			if(zMax < matrixGrid[i].value)
				zMax = matrixGrid[i].value;
			if(zMin > matrixGrid[i].value)
				zMin = matrixGrid[i].value;
		}
	}
	if(smoothFactor > 1)
		applySmooth(matrixGrid,smoothFactor,yBinNumber);
}
} /* namespace plot */