#include #include #include #include "AxesNode.hh" #include "AxisLegendManager.hh" #include "ParamMgr.hh" #include "ParamsNode.hh" #include "PlPlotUtil.hh" #include "PlotFunction.hh" #include "PlotLogger.hh" #include "PlotOutput.hh" #include "TimeUtil.hh" #include "fonctions/fourier/DiscreteFourierTransform.cc" #include "fonctions/fourier/DiscreteFourierTransform.hh" #include #include #include #include #include "DefaultTimeAxisDecorator.hh" #include "TimeAxisDecorator.hh" using namespace AMDA::Parameters; using namespace AMDA::Info; namespace plot { QSASConfig *PlotFunction::qsasconfig = NULL; PlotFunction::PlotFunction(AMDA::Parameters::ParameterManager &manager, boost::shared_ptr panel, TimeAxisDecorator *timeAxisDecorator) : PanelPlotOutput(manager, panel), function(PlotFunction::Function::NONE), abscisse("Time. ", "(s)", Abscisse::Abscisse_Type::TIME) { LOG4CXX_DEBUG(gLogger, "PlotFunction::Function to apply " << function); setTimeAxisDecorator(std::shared_ptr(timeAxisDecorator)); } PlotFunction::~PlotFunction() { if (qsasconfig != NULL) { free(qsasconfig); qsasconfig = nullptr; } } void PlotFunction::createParameters(std::list &usedParametersId_) { for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(it->_originalParamId); // Time Sampling to resample the origin param const double timeSampling = originalParam->getDataWriterTemplate()->getMinSampling(); // Use max Gap in order to interpolate and deleting holes const int gap = 1000000; // Resample the origin param to cearte a new one ParameterSPtr usedParam = createSampledParameter(originalParam, timeSampling, gap); // Add the created parameter to list of usedParametersId_ if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedParam->getId()); // Add the created parameter to Series and Spectro std::vector::iterator ity; for (ity = it->getYSeriePropertiesList().begin(); ity != it->getYSeriePropertiesList().end(); ++ity) { ity->setParamId(usedParam->getId()); if (!PlotFunction::isFourier()) { ity->setXAxisId(X_AXIS_ID1); } else { ity->setXAxisId(X_AXIS_ID); } } if (it->getSpectroProperties() != nullptr) { PlotFunction::isSpectro = true; it->getSpectroProperties()->setParamId(usedParam->getId()); it->getSpectroProperties()->setYAxisId(X_AXIS_ID); } } } void PlotFunction::writeContext(ContextFileWriter &writer, AMDA::Parameters::TimeIntervalList::iterator /*currentTimeInterval*/) { writer.startElement("panel"); _panel->writeContext(_pls, writer); writer.startElement("parameters"); for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(it->_originalParamId); // Retrieve ParamInfo Manager ParamMgr *piMgr = ParamMgr::getInstance(); ParamInfoSPtr paramInfo = piMgr->getParamInfoFromId(it->_originalParamId); double resol = originalParam->getDataWriterTemplate()->getMinSampling(); std::string resolstr = std::to_string(resol); writer.startElement("parameter"); writer.addAttribute("id", paramInfo->getName().c_str()); writer.addAttribute("name", paramInfo->getName().c_str()); writer.addAttribute("shortname", paramInfo->getShortName().c_str()); writer.addAttribute("MinSampling", resolstr.c_str()); writer.addAttribute("unit", paramInfo->getUnits().c_str()); } writer.endElement(); writer.endElement(); } void PlotFunction::applyFunction() { for (auto parameter : _parameterAxesList) { SeriesProperties lSeries; for (auto lSeries : parameter.getYSeriePropertiesList()) { plot::ParameterData &data = (*_pParameterValues)[lSeries.getParamId()]; for (auto lIndex : lSeries.getIndexList(_pParameterValues)) { PlotFunction::compute(lIndex, data, &lSeries, nullptr, parameter._originalParamId); } } if (parameter.getSpectroProperties() != nullptr) { plot::ParameterData &data = (*_pParameterValues)[parameter.getSpectroProperties()->getParamId()]; PlotFunction::compute(AMDA::Common::ParameterIndexComponent(-1, -1), data, nullptr, parameter.getSpectroProperties().get(), parameter._originalParamId); } } } void PlotFunction::setAxisRange() { double minValue = 0; double maxValue = 0; /************************************** X AXIS RANGE *********************************************/ PlotFunction::getMinMax(xValuesMap, &minValue, &maxValue); boost::shared_ptr xAxis = nullptr; if (!PlotFunction::isFourier() && !PlotFunction::isSpectro) { xAxis = _panel->getAxis(X_AXIS_ID1); } else { xAxis = _panel->getAxis(X_AXIS_ID); } Range lAxisRange = xAxis->Axis::getRange(); /* * here we should use pow10 in case if min and max are computed as log values */ if (abscisseScale == Axis::Scale::LOGARITHMIC) { minValue = pow10(minValue); maxValue = pow10(maxValue); lAxisRange._extend = false; } lAxisRange.setMin(minValue); lAxisRange.setMax(maxValue); xAxis->setRange(lAxisRange); xAxis->_used = true; /************************************** Y AXIS RANGE *********************************************/ PlotFunction::getMinMax(yValuesMap, &minValue, &maxValue); boost::shared_ptr lYAxis = _panel->getAxis(Y_AXIS_ID); lAxisRange = lYAxis->Axis::getRange(); if (ordonneeScale == Axis::Scale::LOGARITHMIC) { minValue = pow10(minValue); maxValue = pow10(maxValue); lAxisRange._extend = false; } lAxisRange.setMin(minValue); lAxisRange.setMax(maxValue); lYAxis->setRange(lAxisRange); lYAxis->_used = true; } void PlotFunction::drawSeries(double startDate, double stopDate, int intervalIndex, std::string pParamId, SeriesProperties &pSerie, AMDA::Common::ParameterIndexComponent pParamIndex, ParameterAxes ¶m, bool moreThanOneSerieForAxis) { std::string id = std::to_string(pSerie.getId()) + "_" + pSerie.getParamId() + "_" + std::to_string(pParamIndex.getDim1Index()); std::vector xValues = xValuesMap[id]; std::vector yValues = yValuesMap[id]; double *coloredComputedValues = NULL; int nbValues = yValues.size(); double *yValuesTemp = &yValues[0]; double *xValuesTemp = &xValues[0]; PanelPlotOutput::drawSeries(startDate, stopDate, intervalIndex, pParamId, pSerie, pParamIndex, param, moreThanOneSerieForAxis); // draw serie Color lineColor = getSerieLineColor(pSerie, moreThanOneSerieForAxis); Color symbolColor = getSerieSymbolColor(pSerie, lineColor); drawSymbols( pSerie.getSymbolProperties().getType(), pSerie.getSymbolProperties().getSize(), 1., symbolColor, nbValues, xValuesTemp, yValuesTemp, coloredComputedValues); drawLines( pSerie.getLineProperties().getType(), pSerie.getLineProperties().getStyle(), pSerie.getLineProperties().getWidth(), lineColor, nbValues, xValuesTemp, yValuesTemp, coloredComputedValues); PanelPlotOutput::addSerieToParamsLegend(pSerie, pParamIndex, pParamId, lineColor, symbolColor, startDate, stopDate, intervalIndex); } void PlotFunction::drawSeriesForSpectro(double startDate, double stopDate, int intervalIndex) { for (auto parameter : _parameterAxesList) { if (parameter.getSpectroProperties() != nullptr) { std::string pramId = parameter.getSpectroProperties()->getParamId(); std::vector xValues = xValuesMap[pramId]; std::vector yValues = yValuesMap[pramId]; plot::SeriesProperties *pSerie = new plot::SeriesProperties(); double *coloredComputedValues = NULL; int nbValues = yValues.size(); double *yValuesTemp = &yValues[0]; double *xValuesTemp = &xValues[0]; pSerie->setXAxisId(X_AXIS_ID); pSerie->setYAxisId(Y_AXIS_ID); PanelPlotOutput::drawSeries(startDate, stopDate, intervalIndex, "", *pSerie, AMDA::Common::ParameterIndexComponent(-1, -1), parameter, false); Color lineColor(0, 0, 255); Color symbolColor = getSerieSymbolColor(*pSerie, lineColor); drawSymbols( pSerie->getSymbolProperties().getType(), pSerie->getSymbolProperties().getSize(), 1., symbolColor, nbValues, xValuesTemp, yValuesTemp, coloredComputedValues); drawLines( pSerie->getLineProperties().getType(), pSerie->getLineProperties().getStyle(), 3.0, lineColor, nbValues, xValuesTemp, yValuesTemp, coloredComputedValues); } } } void PlotFunction::configureAxisLegend() { if (!PlotFunction::isFourier() && !PlotFunction::isSpectro) { AxisLegendManager::configureYAxisLegendForSeries(this); } else if (!PlotFunction::isFourier() && PlotFunction::isSpectro) { AxisLegendManager::configureYAxisLegendForSpectro(this); for (auto parameter : _parameterAxesList) { boost::shared_ptr lYAxis = _panel->getAxis(Y_AXIS_ID); AxisLegendManager::setAxisLegendForSpectro(this, lYAxis, parameter.getSpectroProperties()->getParamId()); } } else if (PlotFunction::isFourier()) { boost::shared_ptr lYAxis = _panel->getAxis(Y_AXIS_ID); std::vector colorsLegendsSeriesFFT; if (!PlotFunction::isSpectro) { AxisLegendManager::configureYAxisLegendForSeries(this); for (std::size_t u = 0; u < lYAxis->_legend.getLabels().size(); u++) colorsLegendsSeriesFFT.push_back(lYAxis->_legend.getLabels()[u]._color); lYAxis->_legend.clearLabels(); } for (std::size_t pIndex = 0; pIndex < _parameterAxesList.size(); pIndex++) { ParameterAxes parameter = _parameterAxesList[pIndex]; AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(parameter._originalParamId); // Retrieve ParamInfo Manager ParamMgr *piMgr = ParamMgr::getInstance(); ParamInfoSPtr paramInfo = piMgr->getParamInfoFromId(parameter._originalParamId); std::string unit = AxisLegendManager::getTransformedUnits(paramInfo->getUnits()); unit = "[" + unit + "]#u2"; if (PlotFunction::isSpectro) { Label label(lYAxis->_legend.getFont(), lYAxis->_legend.getColor()); label._text = unit; lYAxis->_legend.setLabel(label); } else { Color compLegendColor = colorsLegendsSeriesFFT[pIndex]; Label label(lYAxis->_legend.getFont(), compLegendColor); label._text = unit; lYAxis->_legend.pushLabel(label); } } } } void PlotFunction::getMinMax(std::map> dataMap, double *minToFill, double *maxToFill) { double maxValue = INT_MIN; double minValue = INT_MAX; std::map>::iterator it; for (it = dataMap.begin(); it != dataMap.end(); it++) { std::vector data = it->second; double max_x = *max_element(data.begin(), data.end()); double min_x = *min_element(data.begin(), data.end()); if (max_x > maxValue) maxValue = max_x; if (min_x < minValue) minValue = min_x; } minValue = minValue - abs(minValue) * 0.01; maxValue = maxValue + abs(maxValue) * 0.01; *minToFill = minValue; *maxToFill = maxValue; } void PlotFunction::compute(AMDA::Common::ParameterIndexComponent pParamIndex, plot::ParameterData &data, SeriesProperties *pSerie, SpectroProperties *pSpectro, std::string paramOriginID) { std::vector xValues; std::vector yValues; if (pSpectro != nullptr) { ParameterSPtr p = _parameterManager.getParameter(pSpectro->getParamId()); boost::shared_ptr rightTableSPtr; AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(p->getInfoId()); if (paramInfo != nullptr) rightTableSPtr = paramInfo->getTable(pSpectro->getRelatedDim()); for (auto index : pSpectro->getIndexes()) { AMDA::Info::t_TableBound crtBound; if (pSpectro->getRelatedDim() == 0) { crtBound = rightTableSPtr->getBound(&_parameterManager, index.getDim1Index()); xValues.push_back((crtBound.min + crtBound.max) / 2.0); } else { crtBound = rightTableSPtr->getBound(&_parameterManager, index.getDim2Index()); xValues.push_back((crtBound.min + crtBound.max) / 2.0); } double sum = 0.0; for (int i = 0; i < data.getSize(); ++i) { sum += data.getValues(index, 0)[i]; } if (function == PlotFunction::Function::AVG) sum /= data.getSize(); yValues.push_back(sum); } } else { for (int index_time = 0; index_time < data.getSize(); index_time++) { double time = data.getTimes()[index_time]; xValues.push_back(time); double valueTemp = data.getValues(pParamIndex, 0)[index_time]; yValues.push_back(valueTemp); } if (function == PlotFunction::Function::SUM) { double sum = std::accumulate(yValues.begin(), yValues.end(), 0); yValues.assign(yValues.size(), sum); } if (function == PlotFunction::Function::AVG) { double sum = std::accumulate(yValues.begin(), yValues.end(), 0); yValues.assign(yValues.size(), sum); const double taille = yValues.size(); transform(yValues.begin(), yValues.end(), yValues.begin(), [taille](double &c) { return c / taille; }); } } if (function == PlotFunction::Function::FFT || function == PlotFunction::Function::DFT) { AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(paramOriginID); const double timeSampling = originalParam->getDataWriterTemplate()->getMinSampling(); LOG4CXX_DEBUG(gLogger, "Fourier:: Signal Size = " << yValues.size()); DiscreteFourierTransform DFT(yValues, timeSampling); const bool computeFFT = (function == PlotFunction::Function::FFT); DFT.compute(computeFFT); std::vector> phasors = DFT.getPhasors(); yValues = DFT.computeDSP(phasors); if (computeFFT) LOG4CXX_DEBUG(gLogger, "FFT Next Power of 2 = " << yValues.size() << " " << DFT.highestPowerof2(8211)); if (abscisse.getType() == Abscisse::Abscisse_Type::FREQUENCY) xValues = DFT.getFreq(phasors, 1.0 / timeSampling); // DFT.getFrequences(); else xValues = DFT.getPeriods(phasors, 1.0 / timeSampling); // DFT.getFrequences(); } PlotFunction::applyScale(xValues, yValues); std::string id = ""; if (pSerie != nullptr) { id = std::to_string(pSerie->getId()) + "_" + pSerie->getParamId() + "_" + std::to_string(pParamIndex.getDim1Index()); } else { id = pSpectro->getParamId(); } PlotFunction::xValuesMap[id] = xValues; PlotFunction::yValuesMap[id] = yValues; } void PlotFunction::applyScale(std::vector &vectX, std::vector &vectY) { std::vector xtemp; std::vector ytemp; for (std::size_t i = 0; i < vectX.size(); i++) { double xValue = vectX[i]; double yValue = vectY[i]; if (abscisseScale == Axis::Scale::LOGARITHMIC) { if (xValue <= 0) { LOG4CXX_DEBUG(gLogger, xValue << " Negative value found, no log calculated"); xValue = NaN; } else xValue = log10(xValue); } if (ordonneeScale == Axis::Scale::LOGARITHMIC) { if (yValue <= 0) { LOG4CXX_DEBUG(gLogger, yValue << " Negative value found, no log calculated"); yValue = NaN; } else yValue = log10(yValue); } xtemp.push_back(xValue); ytemp.push_back(yValue); } vectX = xtemp; vectY = ytemp; } void PlotFunction::drawStartDate(std::string _timeFormat, double startTime, double stopTime) { Font font(_panel->getFont()); Bounds lPanelBounds(_panel->getBoundsInPlPage()); PLFLT lXMin, lXMax, lYMin, lYMax; _pls->gvpd(lXMin, lXMax, lYMin, lYMax); float lPosition = 0.0; // display it one line above the main panel bottom border : float disp = -1; long int lTime = static_cast(startTime); tm *lTimeTm = gmtime(&lTime); char lTimeChr[80]; // Format date. strftime(lTimeChr, 80, getPlStartTimeFormat(_timeFormat, startTime, stopTime) .c_str(), lTimeTm); PLFLT mxmin, mxmax, mymin, mymax; plgspa(&mxmin, &mxmax, &mymin, &mymax); float x_subpage_per_mm = 1. / (mxmax - mxmin); LOG4CXX_DEBUG(gLogger, "Start date to draw : " << lTimeChr); // Set font PlPlotUtil::setPlFont(font); PLFLT dateWidthInMm; dateWidthInMm = plstrl(lTimeChr); // set viewport for start date : _pls->vpor(lXMin, lXMax, lPanelBounds._y, lPanelBounds._y + lPanelBounds._height); lPosition = 0.; if (dateWidthInMm * x_subpage_per_mm > lXMin - lPanelBounds._x) lPosition = (dateWidthInMm * x_subpage_per_mm - lXMin + lPanelBounds._x) / (lXMax - lXMin); _pls->mtex("b", disp, lPosition, 1., lTimeChr); // restore viewport : _pls->vpor(lXMin, lXMax, lYMin, lYMax); } void PlotFunction::preparePlotArea(double startTime, double stopTime, int intervalIndex) { PlotFunction::applyFunction(); PlotFunction::setAxisRange(); if (!PlotFunction::isFourier()) { boost::shared_ptr xAxis = _panel->getAxis(X_AXIS_ID1); getTimeAxisDecorator()->configure(this, dynamic_cast(xAxis.get()), startTime, stopTime, _pParameterValues); _pls->timefmt(getTimeAxisDecorator()->getPlFormat().c_str()); } PlotFunction::configureAxisLegend(); PanelPlotOutput::preparePlotArea(startTime, stopTime, intervalIndex); } /** * @brief draw the plot for the current time interval */ bool PlotFunction::draw(double startTime, double stopTime, int intervalIndex, bool /*isFirstInterval*/, bool /*isLastInterval*/) { // Sets panel plplot viewport, draw background & title for the panel _panel->draw(_pls); fillBackground(_pls); // Compute nb series to draw by y axis std::map nbSeriesByYAxisMap = getNbSeriesByYAxis(); SeriesProperties lSeries; // Draw series for parameters. for (auto parameter : _parameterAxesList) { for (auto lSeries : parameter.getYSeriePropertiesList()) { for (auto lIndex : lSeries.getIndexList(_pParameterValues)) { bool moreThanOneSerieForYAxis = false; if (lSeries.hasYAxis()) moreThanOneSerieForYAxis = (nbSeriesByYAxisMap[lSeries.getYAxisId()] > 1); // Draw (configure) window for this series. drawSeries(startTime, stopTime, intervalIndex, parameter._originalParamId, lSeries, lIndex, parameter, moreThanOneSerieForYAxis); } } } if (!PlotFunction::isFourier() && !PlotFunction::isSpectro) { TimeAxis *timeAxis = dynamic_cast(_panel->getAxis(X_AXIS_ID1).get()); PlotFunction::drawStartDate(timeAxis->_timeFormat, startTime, stopTime); } PlotFunction::drawSeriesForSpectro(startTime, stopTime, intervalIndex); PlotFunction::writeToFileDebug(); return true; } void PlotFunction::writeToFileDebug() { std::ofstream file("plotFunction_results.txt"); std::map> ::iterator it; for (it = xValuesMap.begin(); it != xValuesMap.end(); it++) { file << it->first << std::endl; std::vector tempY = yValuesMap[it->first]; std::vector tempX = it->second; for (std::size_t index = 0; index < tempX.size(); index++) { double x = tempX[index]; double y = tempY[index]; file << std::fixed << x << " " << std::fixed << y << std::endl; } } file.close(); } }