/* * InstantPlot.cc * * Created on: 29 oct. 2013 * Author: CS */ #include #include #include #include "InstantPlot.hh" #include "ParamsNode.hh" #include "AxesNode.hh" #include "PlotLogger.hh" #include "PlotOutput.hh" #include "TimeUtil.hh" #include "ParamMgr.hh" #include "AxisLegendManager.hh" using namespace AMDA::Parameters; using namespace AMDA::Info; namespace plot { InstantPlot::InstantPlot(AMDA::Parameters::ParameterManager& manager, boost::shared_ptr panel) : PanelPlotOutput(manager, panel), _time(0), _prevTime(0), _nextTime(0), _originalParamId("") { } InstantPlot::~InstantPlot() { } void InstantPlot::createParameters(std::list& usedParametersId_) { if (_originalParamId.empty()) return; // Fill usedParameterId_ list with the only used parameter // We do not want any resampling on the parameter AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(_originalParamId); if (std::find (usedParametersId_.begin(),usedParametersId_.end(),originalParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(originalParam->getId()); // Force use of normalized parameter id _originalParamId = originalParam->getId(); AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(originalParam->getInfoId()); if (paramInfo != nullptr) { if (_iSerieProperties != nullptr) { boost::shared_ptr tableSPtr; if (paramInfo != nullptr) tableSPtr = paramInfo->getTable(0); if ((tableSPtr != nullptr) && (tableSPtr->isVariable(&_parameterManager))) { for (std::map::iterator it = tableSPtr->getTableParams(&_parameterManager).begin(); it != tableSPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); _iSerieProperties->addTableParam(tableParamKey, originalTableParam->getId()); } //Add table parameters to parameters list for (std::map::iterator it = _iSerieProperties->getTableParams().begin(); it != _iSerieProperties->getTableParams().end(); ++it) { std::string tableParamId = it->second; if (std::find (usedParametersId_.begin(),usedParametersId_.end(),tableParamId) == usedParametersId_.end()) usedParametersId_.push_back(tableParamId); } } } else if (_iSpectroProperties != nullptr) { boost::shared_ptr table0SPtr; boost::shared_ptr table1SPtr; if (paramInfo != nullptr) { table0SPtr = paramInfo->getTable(0); table1SPtr = paramInfo->getTable(1); } if ((table0SPtr != nullptr) && table0SPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = table0SPtr->getTableParams(&_parameterManager).begin(); it != table0SPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); _iSpectroProperties->addTable0Param(tableParamKey, originalTableParam->getId()); } //Add table parameters to parameters list for (std::map::iterator it = _iSpectroProperties->getTable0Params().begin(); it != _iSpectroProperties->getTable0Params().end(); ++it) { std::string tableParamId = it->second; if (std::find (usedParametersId_.begin(),usedParametersId_.end(),tableParamId) == usedParametersId_.end()) usedParametersId_.push_back(tableParamId); } } if ((table1SPtr != nullptr) && table1SPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = table1SPtr->getTableParams(&_parameterManager).begin(); it != table1SPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); _iSpectroProperties->addTable1Param(tableParamKey, originalTableParam->getId()); } //Add table parameters to parameters list for (std::map::iterator it = _iSpectroProperties->getTable1Params().begin(); it != _iSpectroProperties->getTable1Params().end(); ++it) { std::string tableParamId = it->second; if (std::find (usedParametersId_.begin(),usedParametersId_.end(),tableParamId) == usedParametersId_.end()) usedParametersId_.push_back(tableParamId); } } } } } /** * @overload PanelPlotOutput::preparePlotArea() */ void InstantPlot::preparePlotArea(double startTime, double stopTime, int intervalIndex) { LOG4CXX_DEBUG(gLogger, "InstantPlot::preparePlotArea"); // for test, dump plot properties const char* lBuildType=getenv("BUILD_TYPE"); if(lBuildType && std::string(lBuildType) == "Debug") { std::ofstream out("instantPlot.txt"); dump(out); out.close(); } if (_iSerieProperties != nullptr) { /* * Sequence for an instant series */ // Configure range of series and color. configureSeriesAxis(); // Configure axis legend configureSeriesAxisLegend(); // Configure params legend configureParamsLegend(startTime,stopTime,intervalIndex); } else if (_iSpectroProperties != nullptr) { /* * Sequence for an instant spectro */ // Configure range of spectro axis. configureSpectroAxis(); // Configure axis legend configureSpectroAxisLegend(); } // check instant "cut" time validity if ((_time == 0) || (_time < startTime) || (_time > stopTime)) { double middleTime = (startTime + stopTime) / 2; LOG4CXX_WARN(gLogger, "InstantPlot::preparePlotArea invalid \"cut\" time : " << _time << " replaced by middle time : " << middleTime); _time = middleTime; } // If panel title is empty, replace it with start and end date. if (_panel->getTitle()->_text.empty() || _panel->_updateTitleOnNextInterval) { //Title must be updated during the next interval plot _panel->_updateTitleOnNextInterval = true; // Set start date and end date. std::string lTimeFormat("%Y/%m/%d %H:%M:%S"); long int lStartTime = static_cast(_time); tm * lStartTimeTm = gmtime(&lStartTime); char lStartTimeChr[80]; // Format date. strftime(lStartTimeChr, 80, lTimeFormat.c_str(), lStartTimeTm); std::string lStartTimeStr= lStartTimeChr; lStartTimeStr += '.'+std::to_string(_time -lStartTime ).substr(2,3); _panel->setTitleText((const char*)lStartTimeStr.c_str()); } PanelPlotOutput::preparePlotArea(startTime,stopTime,intervalIndex); } /* * Dumps properties for test. */ void InstantPlot::dump(std::ostream& out_){ PanelPlotOutput::dump(out_); std::string prefix = "instantplot."; if (_iSerieProperties != nullptr) _iSerieProperties->dump(out_,prefix); if (_iSpectroProperties != nullptr) _iSpectroProperties->dump(out_,prefix); } /** * @brief Retrieve ConstantLine informations for a given serieId and constantId. */ ConstantLine * InstantPlot::getConstantLineFromSerieId (int serieId, int constantId) { if (_iSerieProperties == nullptr) return NULL; // Look for serieId correspondence if (_iSerieProperties->getId() == serieId) { if (_iSerieProperties->getTableOnXAxis()) { boost::shared_ptr yAxis(_panel->getAxis(_iSerieProperties->getYAxisId())); // Look for constantId correspondence for (auto constantLine : yAxis->_constantLines) { if (constantLine->getId() == constantId) { return constantLine.get(); } } } else { boost::shared_ptr xAxis(_panel->getAxis(_iSerieProperties->getXAxisId())); // Look for constantId correspondence for (auto constantLine : xAxis->_constantLines) { if (constantLine->getId() == constantId) { return constantLine.get(); } } } } // ConstantId not found, we throw an exception std::stringstream lError; lError << "InstantPlot::getConstantLineFromSerieId : Unable to find constantId='" << constantId << "' for serieId='" << serieId << "'"; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); return NULL; } /** * @brief Retrieve values for a given serieId. */ void InstantPlot::getSerieParameterValues(int serieId, double **xValues, double **yValues, int *nbValues) { *nbValues = 0; if (_iSerieProperties == nullptr) return; if (_iSerieProperties->getId() == serieId) { // Retrieve parameter informations and param Table if it exists ParameterSPtr p = _parameterManager.getParameter(_originalParamId); AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(p->getInfoId()); boost::shared_ptr paramTable; if (paramInfo) paramTable = paramInfo->getTable(0); ParameterData& paramData = (*_pParameterValues)[_originalParamId]; *nbValues = paramData.getDim1Size(); // Build valueData and tableData double valueData[*nbValues]; double tableData[*nbValues]; double valueMin = DBL_MAX; double valueMax = -DBL_MAX; double tableMin = DBL_MAX; double tableMax = -DBL_MAX; double tableValue = 0; AMDA::Info::t_TableBound crtBound; for (int i = 0; i < *nbValues; ++i) { double value = paramData.getInterpolatedValue(_time, AMDA::Common::ParameterIndexComponent(i),_prevTime, _nextTime); valueData[i] = value; valueMin = std::min (valueMin,value); valueMax = std::max (valueMax,value); if (paramTable) { if (!paramTable->isVariable(&_parameterManager)) crtBound = paramTable->getBound(&_parameterManager, i); else { std::map> paramsTableData; for (std::map::iterator it = _iSerieProperties->getTableParams().begin(); it != _iSerieProperties->getTableParams().end(); ++it) { ParameterData& data = (*_pParameterValues)[it->second]; double valIdx = data.indexOf(_time); std::vector paramTableValues; for (int j = 0; j < data.getDim1Size(); ++j) { double* values = data.getValues(AMDA::Common::ParameterIndexComponent(j), valIdx); paramTableValues.push_back((*values)); } paramsTableData[it->first] = paramTableValues; } crtBound = paramTable->getBound(&_parameterManager, i, ¶msTableData); } tableValue = (crtBound.min + crtBound.max) /2; } else { tableValue = i; } tableData [i] = tableValue; tableMin = std::min (tableMin,tableValue); tableMax = std::max (tableMax,tableValue); } //Attach valueData and tableData x / y value depending on table values associated axe if (_iSerieProperties->getTableOnXAxis()) { *xValues = _panel->getAxis (_iSerieProperties->getXAxisId())->getComputedValues( tableData, *nbValues, tableMin, tableMax); *yValues = _panel->getAxis (_iSerieProperties->getYAxisId())->getComputedValues( valueData, *nbValues, valueMin, valueMax); // If table values decrease, change values order if ((*xValues) [0] > (*xValues) [(*nbValues) -1]) { double swapX [*nbValues]; double swapY [*nbValues]; for (int i=0; i<*nbValues; i++) { swapX [i] = (*xValues) [*nbValues - 1 - i]; swapY [i] = (*yValues) [*nbValues - 1 - i]; } for (int i=0; i<*nbValues; i++) { (*xValues) [i] = swapX [i]; (*yValues) [i] = swapY [i]; } } } else { *xValues = _panel->getAxis (_iSerieProperties->getXAxisId())->getComputedValues( valueData, *nbValues, valueMin, valueMax); *yValues = _panel->getAxis (_iSerieProperties->getYAxisId())->getComputedValues( tableData, *nbValues, tableMin, tableMax); // If table values decrease, change values order if ((*yValues) [0] > (*yValues) [(*nbValues) -1]) { double swapX [*nbValues]; double swapY [*nbValues]; for (int i=0; i<*nbValues; i++) { swapX [i] = (*xValues) [*nbValues - 1 - i]; swapY [i] = (*yValues) [*nbValues - 1 - i]; } for (int i=0; i<*nbValues; i++) { (*xValues) [i] = swapX [i]; (*yValues) [i] = swapY [i]; } } } } } /** * @brief Merge, sort and remove duplicate from 2 arrays in a vector */ void InstantPlot::mergeAndSortTime ( double *values1Table, int values1Nb, double *values2Table, int values2Nb, std::vector &valuesTableMerged) { // Build 2 vectors std::vector v1(values1Table, values1Table + values1Nb); std::vector v2(values2Table, values2Table + values2Nb); // Populate resulting vector valuesTableMerged.insert( valuesTableMerged.end(), v1.begin(), v1.end() ); valuesTableMerged.insert( valuesTableMerged.end(), v2.begin(), v2.end() ); // Sort and remove duplicates for the resulting vector sort (valuesTableMerged.begin(), valuesTableMerged.end()); valuesTableMerged.erase( unique( valuesTableMerged.begin(), valuesTableMerged.end() ), valuesTableMerged.end() ); } /** * @brief Return or compute an interpolated value */ double InstantPlot::getInterpolatedValue (double *valuesData, double *valuesTable, int valuesNb, double atTableValue) { // get index of first time after given time_ if(isnan(atTableValue)){ return nan(""); } double *pTable = valuesTable; for(int t=0; t= atTableValue){ if (t == 0) { return nan(""); } else { double v1 = valuesData [t-1]; double v2 = valuesData [t]; double d1 = valuesTable [t-1]; double d2 = valuesTable [t]; // Return a linear interpolation of the value for the index return (v1 + (v2-v1) * (atTableValue-d1)/(d2-d1)); } } pTable++; } return nan(""); } /** * @brief Compute if two ligne segments intersects */ bool InstantPlot::intersect ( double xi, double y1i, double y2i, double xj, double y1j, double y2j, double *xInter) { // Simply checks if segment are above or below the other if ( ((y1i >= y2i) && (y1j >= y2j)) ||( (y1i <= y2i) && (y1j <= y2j)) ) { return false; } // Computes intersection point : // Compute a and b (y = a * x + b) for each segment double a1 = (y1j - y1i) / (xj - xi); double b1 = y1i - a1 * xi ; double a2 = (y2j - y2i) / (xj - xi); double b2 = y2i - a2 * xi ; // Compute intersection point (a1*x+b1 = a2*x+b2) *xInter = (b2-b1) / (a1-a2); return true; } /** * @brief Compute and add intersections time to the vector if intersections exist */ void InstantPlot::addIntersectionTable (double *values1Data, double *values1Table, int values1Nb, double *values2Data, double *values2Table, int values2Nb, std::vector &valuesTableMerged) { if (valuesTableMerged.empty() == true) return; // For each table segment compute intersection if it exists std::vector intersectionTable; double xi = valuesTableMerged [0]; double y1i = getInterpolatedValue (values1Data, values1Table, values1Nb, xi); double y2i = getInterpolatedValue (values2Data, values2Table, values2Nb, xi); for (size_t t=1; t &valuesTableMerged, bool colorGreaterSpecified, Color& colorGreater, bool colorLessSpecified, Color& colorLess) { // Get X and Y axis. boost::shared_ptr lXAxis(_panel->getAxis(_iSerieProperties->getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(_iSerieProperties->getYAxisId())); Range lXRange = getXAxisRange (*_iSerieProperties, lXAxis); Range lYRange = getYAxisRange (*_iSerieProperties, lYAxis); _pls->wind(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); PLFLT x[4], y[4], deltai, deltaj; Color curColor; Color lInitialColor = changeColor(_pls, colorGreater, _panel->_page->_mode); for ( size_t i = 0; i < (valuesTableMerged.size() - 1); i++ ) { x[0] = valuesTableMerged[i]; x[1] = x[0]; x[2] = valuesTableMerged[i+1]; x[3] = x[2]; y[0] = getInterpolatedValue (values1Data, values1Table, values1Nb, valuesTableMerged[i]); y[1] = getInterpolatedValue (values2Data, values2Table, values2Nb, valuesTableMerged[i]); y[2] = getInterpolatedValue (values2Data, values2Table, values2Nb, valuesTableMerged[i+1]); y[3] = getInterpolatedValue (values1Data, values1Table, values1Nb, valuesTableMerged[i+1]); deltai = y[1] - y[0]; deltaj = y[2] - y[3]; // Set fill color depending on segment position if ( ((deltai > 0) && (fabs(deltai) > fabs(deltaj))) || ((deltaj > 0) && (fabs(deltaj) > fabs(deltai))) ) { // s1 above s2 if (colorGreaterSpecified == true) { curColor = colorGreater; } else { continue; } } else if ( ((deltai < 0) && (fabs(deltai) > fabs(deltaj))) || ((deltaj < 0) && (fabs(deltaj) > fabs(deltai))) ) { // s1 under s2 if (colorLessSpecified == true) { curColor = colorLess; } else { continue; } } else { // Colinear segments, no fill required continue; } // Fill polygon using the given color changeColor(_pls, curColor, _panel->_page->_mode); if (_iSerieProperties->getTableOnXAxis()) _pls->fill(4, x, y); else _pls->fill(4, y, x); } // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } void InstantPlot::drawFills(double startDate, double stopDate) { if (_iSerieProperties == nullptr) return; PanelPlotOutput::drawFills(startDate, stopDate); LOG4CXX_DEBUG(gLogger, "InstantPlot::drawFillArea"); double *values1Data = NULL; double *values1Table = NULL; int values1Nb = 0; double values2Data [2]; double values2Table [2]; double *values1X = NULL; double *values1Y = NULL; std::vector valuesTableMerged; // Drawing Fill Area located between Serie and Constant (horizontal) line for (auto fillSerieConstant : _panel->_fillSerieConstants) { // Retrieve serie parameter values for serieId getSerieParameterValues (fillSerieConstant->getSerieId(), &values1X, &values1Y, &values1Nb); if (_iSerieProperties->getTableOnXAxis()) { values1Table = values1X; values1Data = values1Y; } else { values1Table = values1Y; values1Data = values1X; } // Retrieve constantLine informations for these fill ConstantLine *constantLine = getConstantLineFromSerieId ( fillSerieConstant->getSerieId(), fillSerieConstant->getConstantId()); // Build values2 values2Time array with 2 values : yConst & (first value, last value) for serie values2Data [0] = convertYAxisValue (constantLine->getValue()); values2Data [1] = convertYAxisValue (constantLine->getValue()); values2Table [0] = values1Table [0]; values2Table [1] = values1Table [values1Nb-1]; // Logarithmic scale for X ? // already done ! int values2Nb = 2; if (_iSerieProperties->getTableOnXAxis()) { // Logarithmic scale for Y ? if (_panel->getAxis(_iSerieProperties->getYAxisId())->_scale == Axis::Scale::LOGARITHMIC) { values2Data [0] = log10 (values2Data [0]); values2Data [1] = log10 (values2Data [1]); } } else { // Logarithmic scale for X ? if (_panel->getAxis(_iSerieProperties->getXAxisId())->_scale == Axis::Scale::LOGARITHMIC) { values2Data [0] = log10 (values2Data [0]); values2Data [1] = log10 (values2Data [1]); } } // Build time vector by merging existing times and computing intersections, and draw it ! mergeAndSortTime ( values1Table, values1Nb, values2Table, values2Nb, valuesTableMerged); addIntersectionTable (values1Data, values1Table, values1Nb, values2Data, values2Table, values2Nb, valuesTableMerged); drawFillArea ( values1Data, values1Table, values1Nb, values2Data, values2Table, values2Nb, valuesTableMerged, fillSerieConstant->isColorGreaterSpecified(), fillSerieConstant->getColorGreater(), fillSerieConstant->isColorLessSpecified(), fillSerieConstant->getColorLess()); delete [] values1Data; delete [] values1Table; } } void InstantPlot::drawSeries(double startDate, double stopDate, int intervalIndex, std::string pParamId, SeriesProperties& pSeries, AMDA::Common::ParameterIndexComponent pParamIndex, ParameterAxes& param, bool moreThanOneSerieForAxis, bool& noData) { if (_iSerieProperties == nullptr) return; PanelPlotOutput::drawSeries(startDate, stopDate, intervalIndex, pParamId, pSeries, pParamIndex, param, moreThanOneSerieForAxis); LOG4CXX_DEBUG(gLogger, "InstantPlot::drawSeries"); double* xValues = NULL; double* yValues = NULL; int nbValues; getSerieParameterValues (_iSerieProperties->getId(), &xValues, &yValues, &nbValues); if (noData && (nbValues > 0)) { for (int i = 0; i < nbValues; ++i) { if (!isNAN(xValues[i]) && !isNAN(yValues[i])) { noData = false; } } } Color lineColor = getSerieLineColor(pSeries, moreThanOneSerieForAxis); Color symbolColor = getSerieSymbolColor(pSeries, lineColor); drawSymbols( pSeries.getSymbolProperties().getType(), pSeries.getSymbolProperties().getSize(), 1., symbolColor, nbValues, xValues, yValues); drawLines( pSeries.getLineProperties().getType(), pSeries.getLineProperties().getStyle(), pSeries.getLineProperties().getWidth(), lineColor, nbValues, xValues, yValues); //add serie to the params legend addSerieToParamsLegend(*_iSerieProperties,pParamIndex,param._originalParamId, lineColor,symbolColor,startDate,stopDate, intervalIndex); //delete data delete [] xValues; delete [] yValues; } void InstantPlot::configureSeriesAxis() { if (_iSerieProperties == nullptr) //nothing to do return; LOG4CXX_DEBUG(gLogger, "InstantPlot::configureSeriesAxis"); /////////////////////////////////////////////////////////////////////////// // Retrieve X and Y axis /////////////////////////////////////////////////////////////////////////// boost::shared_ptr lXAxis = _panel->getAxis(_iSerieProperties->getXAxisId()); if (lXAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSeriesAxis" << ": X axis with id '" << _iSerieProperties->getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lXAxis->_used = true; boost::shared_ptr lYAxis = _panel->getAxis(_iSerieProperties->getYAxisId()); if (lYAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSeriesAxis" << ": Y axis with id '" << _iSerieProperties->getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lYAxis->_used = true; if (_iSerieProperties->getTableOnXAxis()) { configureTableAxis (lXAxis, false, 0); configureDataAxis (lYAxis, false); } else { configureTableAxis (lYAxis, false, 0); configureDataAxis (lXAxis, false); } } void InstantPlot::configureTableAxis (boost::shared_ptr axisSPtr, bool isSpectro, int relatedDim) { /////////////////////////////////////////////////////////////////////////// // Configure range for table axis. /////////////////////////////////////////////////////////////////////////// ParameterSPtr p = _parameterManager.getParameter(_originalParamId); int dimSize; if (relatedDim == 0) dimSize = (*_pParameterValues)[_originalParamId].getDim1Size(); else dimSize = (*_pParameterValues)[_originalParamId].getDim2Size(); //set axis range Range lAxisRange = axisSPtr->Axis::getRange(); AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(p->getInfoId()); if (isnan(lAxisRange.getMin()) && isnan(lAxisRange.getMax())) { boost::shared_ptr tableSPtr; if (paramInfo != nullptr) tableSPtr = paramInfo->getTable(relatedDim); if (tableSPtr == nullptr) { LOG4CXX_DEBUG(gLogger, "No table defined => use index"); lAxisRange.setMin(std::min(0.,lAxisRange.getMin())); lAxisRange.setMax(std::max((double)dimSize,lAxisRange.getMax())); } else { AMDA::Info::t_TableBound crtBound; if (!tableSPtr->isVariable(&_parameterManager)) { for (int i = 0; i < dimSize; ++i) { crtBound = tableSPtr->getBound(&_parameterManager, i); if (isSpectro) { if (!isNAN(crtBound.min)) lAxisRange.setMin(std::min(crtBound.min,lAxisRange.getMin())); if (!isNAN(crtBound.max)) lAxisRange.setMax(std::max(crtBound.max,lAxisRange.getMax())); } else { if (!isNAN(crtBound.min) && !isNAN(crtBound.max)) lAxisRange.setMin(std::min((crtBound.min+ crtBound.max) / 2.0,lAxisRange.getMin())); if (!isNAN(crtBound.min) && !isNAN(crtBound.max)) lAxisRange.setMax(std::max((crtBound.min+ crtBound.max) / 2.0,lAxisRange.getMax())); } } } else { std::map relatedTableParam; if (isSpectro) { switch (relatedDim) { case 0 : relatedTableParam = _iSpectroProperties->getTable0Params(); break; case 1 : relatedTableParam = _iSpectroProperties->getTable1Params(); break; } } else { relatedTableParam = _iSerieProperties->getTableParams(); } std::map> paramsTableData; for (std::map::iterator it = relatedTableParam.begin(); it != relatedTableParam.end(); ++it) { ParameterData& data = (*_pParameterValues)[it->second]; double valIdx = data.indexOf(_time); std::vector paramTableValues; for (int i = 0; i < data.getDim1Size(); ++i) { double* values = data.getValues(AMDA::Common::ParameterIndexComponent(i), valIdx); paramTableValues.push_back((*values)); } paramsTableData[it->first] = paramTableValues; } for (int i = 0; i < dimSize; ++i) { crtBound = tableSPtr->getBound(&_parameterManager, i, ¶msTableData); if (isSpectro) { if (!isNAN(crtBound.min)) lAxisRange.setMin(std::min(crtBound.min,lAxisRange.getMin())); if (!isNAN(crtBound.max)) lAxisRange.setMax(std::max(crtBound.max,lAxisRange.getMax())); } else { if (!isNAN(crtBound.min) && !isNAN(crtBound.max)) lAxisRange.setMin(std::min((crtBound.min+ crtBound.max) / 2.0,lAxisRange.getMin())); if (!isNAN(crtBound.min) && !isNAN(crtBound.max)) lAxisRange.setMax(std::max((crtBound.min+ crtBound.max) / 2.0,lAxisRange.getMax())); } } } } } //do not extend the axis lAxisRange._extend = false; axisSPtr->setRange(lAxisRange); LOG4CXX_DEBUG(gLogger, "Table axis range : min = " << lAxisRange.getMin() << ", max = " << lAxisRange.getMax()); } void InstantPlot::configureDataAxis (boost::shared_ptr axisSPtr, bool isSpectro) { int dim1Size = (*_pParameterValues)[_originalParamId].getDim1Size(); int dim2Size = (*_pParameterValues)[_originalParamId].getDim2Size(); /////////////////////////////////////////////////////////////////////////// // Configure range axis /////////////////////////////////////////////////////////////////////////// Range lAxisRange(axisSPtr->getRange()); // If user didn't set a range, calculate range automatically (based on parameters values). if (!lAxisRange.isSet()) { double instantTimeMin = NAN; double instantTimeMax = NAN; ParameterData& data = (*_pParameterValues)[_originalParamId]; if (isSpectro) { for (int i = 0; i < dim1Size; ++i) { for (int j = 0; j < dim2Size; ++j) { double valIdx = data.getInterpolatedValue(_time, AMDA::Common::ParameterIndexComponent(i,j),_prevTime, _nextTime); if (!isNAN(valIdx)) { if (isNAN(instantTimeMax) || (valIdx > instantTimeMax)) instantTimeMax = valIdx; if (isNAN(instantTimeMin) || (valIdx < instantTimeMin)) instantTimeMin = valIdx; } } } } else { for (int i = 0; i < dim1Size; ++i) { double valIdx = data.getInterpolatedValue(_time, AMDA::Common::ParameterIndexComponent(i),_prevTime, _nextTime); if (!isNAN(valIdx)) { if (isNAN(instantTimeMax) || (valIdx > instantTimeMax)) instantTimeMax = valIdx; if (isNAN(instantTimeMin) || (valIdx < instantTimeMin)) instantTimeMin = valIdx; } } } //do not extend the axis lAxisRange._extend = false; lAxisRange.setMin(instantTimeMin); lAxisRange.setMax(instantTimeMax); fixRange(lAxisRange, axisSPtr->_scale == Axis::Scale::LOGARITHMIC); axisSPtr->setRange(lAxisRange); } LOG4CXX_DEBUG(gLogger, "Data axis range : min = " << lAxisRange.getMin() << ", max = " << lAxisRange.getMax()); } void InstantPlot::configureSeriesAxisLegend () { if (_iSerieProperties == nullptr) return; std::string yAxisId = _iSerieProperties->getYAxisId(); boost::shared_ptr lYAxis = _panel->getAxis(yAxisId); if (lYAxis.get() == nullptr) { std::stringstream lError; lError << "TimePlot::configureSeriesAxis" << ": Y axis with id '" << yAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } std::string xAxisId = _iSerieProperties->getXAxisId(); boost::shared_ptr lXAxis = _panel->getAxis(xAxisId); if (lXAxis.get() == nullptr) { std::stringstream lError; lError << "TimePlot::configureSeriesAxis" << ": Y axis with id '" << xAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } if (_iSerieProperties->getTableOnXAxis()) { configureTableAxisLegend(lXAxis,0); configureDataAxisLegend(lYAxis, false); } else { configureTableAxisLegend(lYAxis,0); configureDataAxisLegend(lXAxis, false); } } void InstantPlot::configureTableAxisLegend(boost::shared_ptr axisSPtr, int relatedDim) { AMDA::Common::ParameterIndexComponentList indexes; AxisLegendManager::setAxisLegendForTable(this, axisSPtr, _originalParamId, _originalParamId, indexes, relatedDim); } void InstantPlot::configureDataAxisLegend(boost::shared_ptr axisSPtr, bool isSpectro) { if (isSpectro) { AxisLegendManager::setAxisLegendForSpectro(this, axisSPtr, _originalParamId); } else { AxisLegendManager::AxisParamsComponents axisParamsComponents; axisParamsComponents[_originalParamId].push_back(ParameterIndexComponentColor(-1,-1, axisSPtr->_color)); AxisLegendManager::setAxisLegendForSeries(this, axisSPtr, axisParamsComponents); } } void InstantPlot::drawSpectro(double startDate, double stopDate, std::string pParamId, SpectroProperties& pSpectro, bool& noData) { if (_iSpectroProperties == nullptr) return; PanelPlotOutput::drawSpectro(startDate, stopDate, pParamId, pSpectro); LOG4CXX_DEBUG(gLogger, "InstantPlot::drawSpectro"); //get parameter data and info ParameterSPtr p = _parameterManager.getParameter(pParamId); ParameterData& data = (*_pParameterValues)[pParamId]; boost::shared_ptr tableOnXSPtr; boost::shared_ptr tableOnYSPtr; int dimOnXSize = 0.; int dimOnYSize = 0.; std::map paramsOnX; std::map paramsOnY; AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(p->getInfoId()); if (_iSpectroProperties->getDimOnXAxis() == 0) { if (paramInfo != nullptr) { tableOnXSPtr = paramInfo->getTable(0); tableOnYSPtr = paramInfo->getTable(1); } dimOnXSize = data.getDim1Size(); dimOnYSize = data.getDim2Size(); paramsOnX = _iSpectroProperties->getTable0Params(); paramsOnY = _iSpectroProperties->getTable1Params(); } else { if (paramInfo != nullptr) { tableOnXSPtr = paramInfo->getTable(1); tableOnYSPtr = paramInfo->getTable(0); } dimOnXSize = data.getDim2Size(); dimOnYSize = data.getDim1Size(); paramsOnX = _iSpectroProperties->getTable1Params(); paramsOnY = _iSpectroProperties->getTable0Params(); } //get axis boost::shared_ptr lXAxis = _panel->getAxis(_iSpectroProperties->getXAxisId()); boost::shared_ptr lYAxis = _panel->getAxis(_iSpectroProperties->getYAxisId()); boost::shared_ptr lZAxis = _panel->getColorAxis(); //Check dimensions if ((dimOnXSize <= 0) || (dimOnYSize <= 0)) { LOG4CXX_INFO(gLogger, "InstantPlot::drawSpectro - No data to plot"); return; } MatrixGrid matrixGrid; for (int i = 0; i < dimOnXSize; ++i) { GridPart part; if (tableOnXSPtr == nullptr) { //no table defined => use index part.x[0] = i; part.x[1] = i+1; } else { if (!tableOnXSPtr->isVariable(&_parameterManager)) { part.x[0] = tableOnXSPtr->getBound(&_parameterManager, i).min; part.x[1] = tableOnXSPtr->getBound(&_parameterManager, i).max; } else { std::map> paramsTableData; for (std::map::iterator it = paramsOnX.begin(); it != paramsOnX.end(); ++it) { ParameterData& data = (*_pParameterValues)[it->second]; double valIdx = data.indexOf(_time); std::vector paramTableValues; for (int k = 0; k < data.getDim1Size(); ++k) { double* values = data.getValues(AMDA::Common::ParameterIndexComponent(k), valIdx); paramTableValues.push_back((*values)); } paramsTableData[it->first] = paramTableValues; } part.x[0] = tableOnXSPtr->getBound(&_parameterManager, i, ¶msTableData).min; part.x[1] = tableOnXSPtr->getBound(&_parameterManager, i, ¶msTableData).max; } } if (std::isnan(part.x[0]) || std::isnan(part.x[1])) { continue; } if (lXAxis->_scale == Axis::Scale::LOGARITHMIC) { if ((part.x[0] <= 0) || (part.x[1] <= 0)) { continue; } part.x[0] = log10(part.x[0]); part.x[1] = log10(part.x[1]); } for (int j = 0; j < dimOnYSize; ++j) { if (tableOnYSPtr == nullptr) { //no table defined => use index part.y[0] = j; part.y[1] = j+1; } else { if (!tableOnYSPtr->isVariable(&_parameterManager)) { part.y[0] = tableOnYSPtr->getBound(&_parameterManager, j).min; part.y[1] = tableOnYSPtr->getBound(&_parameterManager, j).max; } else { std::map> paramsTableData; for (std::map::iterator it = paramsOnY.begin(); it != paramsOnY.end(); ++it) { ParameterData& data = (*_pParameterValues)[it->second]; double valIdx = data.indexOf(_time); std::vector paramTableValues; for (int k = 0; k < data.getDim1Size(); ++k) { double* values = data.getValues(AMDA::Common::ParameterIndexComponent(k), valIdx); paramTableValues.push_back((*values)); } paramsTableData[it->first] = paramTableValues; } part.y[0] = tableOnYSPtr->getBound(&_parameterManager, j, ¶msTableData).min; part.y[1] = tableOnYSPtr->getBound(&_parameterManager, j, ¶msTableData).max; } } if (std::isnan(part.y[0]) || std::isnan(part.y[1])) { continue; } if (lYAxis->_scale == Axis::Scale::LOGARITHMIC) { if ((part.y[0] <= 0) || (part.y[1] <= 0)) { continue; } part.y[0] = log10(part.y[0]); part.y[1] = log10(part.y[1]); } part.isColorIndex = false; if (_iSpectroProperties->getDimOnXAxis() == 0) { part.value = data.getInterpolatedValue(_time, AMDA::Common::ParameterIndexComponent(i,j),_prevTime, _nextTime); } else { part.value = data.getInterpolatedValue(_time, AMDA::Common::ParameterIndexComponent(j,i),_prevTime, _nextTime); } if (!isNAN(part.value)) noData = false; matrixGrid.push_back(part); } } //get specific colors for min / max values Color minValColor = lZAxis->getMinValColor(); Color maxValColor = lZAxis->getMaxValColor(); //draw spectro drawMatrix(matrixGrid, _iSpectroProperties->getMin(), _iSpectroProperties->getMax(), minValColor, maxValColor, lZAxis->_color._colorMapIndex); } void InstantPlot::configureSpectroAxis() { if (_iSpectroProperties == nullptr) return; LOG4CXX_DEBUG(gLogger, "InstantPlot::configureSpectroAxis"); /////////////////////////////////////////////////////////////////////////// // Retrieve X, Y and Z axis /////////////////////////////////////////////////////////////////////////// boost::shared_ptr lXAxis = _panel->getAxis(_iSpectroProperties->getXAxisId()); if (lXAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSpectroAxis" << ": X axis with id '" << _iSpectroProperties->getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lXAxis->_used = true; boost::shared_ptr lYAxis = _panel->getAxis(_iSpectroProperties->getYAxisId()); if (lYAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSpectroAxis" << ": Y axis with id '" << _iSpectroProperties->getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lYAxis->_used = true; boost::shared_ptr lZAxis = _panel->getAxis(_iSpectroProperties->getZAxisId()); if (lZAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSpectroAxis" << ": Z axis with id '" << _iSpectroProperties->getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lZAxis->_used = true; if (_iSpectroProperties->getDimOnXAxis() == 0) { configureTableAxis (lXAxis, true, 0); configureTableAxis (lYAxis, true, 1); configureDataAxis (lZAxis, true); } else { configureTableAxis (lXAxis, true, 1); configureTableAxis (lYAxis, true, 0); configureDataAxis (lZAxis, true); } } void InstantPlot::configureSpectroAxisLegend () { if (_iSpectroProperties == nullptr) return; LOG4CXX_DEBUG(gLogger, "InstantPlot::configureSpectroAxisLegend"); //get X axis std::string xAxisId = _iSpectroProperties->getXAxisId(); boost::shared_ptr lXAxis = _panel->getAxis(xAxisId); if (lXAxis.get() == nullptr) { std::stringstream lError; lError << "TimePlot::configureSpectroAxisLegend" << ": X axis with id '" << xAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } //get y axis std::string yAxisId = _iSpectroProperties->getYAxisId(); boost::shared_ptr lYAxis = _panel->getAxis(yAxisId); if (lYAxis.get() == nullptr) { std::stringstream lError; lError << "TimePlot::configureSpectroAxisLegend" << ": Y axis with id '" << yAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } //get z axis std::string zAxisId = _iSpectroProperties->getZAxisId(); boost::shared_ptr lZAxis = _panel->getAxis(zAxisId); if (lZAxis.get() == nullptr) { std::stringstream lError; lError << "InstantPlot::configureSpectroAxisLegend" << ": Z axis with id '" << zAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } if (_iSpectroProperties->getDimOnXAxis() == 0) { configureTableAxisLegend(lXAxis,0); configureTableAxisLegend(lYAxis,1); configureDataAxisLegend(lZAxis, true); } else { configureTableAxisLegend(lXAxis,1); configureTableAxisLegend(lYAxis,0); configureDataAxisLegend(lZAxis, true); } } /** * @overload PanelPlotOutput::getSerieParamsLegendString Get the instant serie legend */ std::string InstantPlot::getSerieParamsLegendString(SeriesProperties &/*rSeriesProperties*/, AMDA::Common::ParameterIndexComponent& /*index*/, std::string /*originalParamId*/) { if (_iSerieProperties == nullptr) return ""; // Retrieve ParamInfo Manager ParamMgr *piMgr =ParamMgr::getInstance(); // Build parameter text legend depending on the availability of paramInfo // for Y and X component // Try to retrieve informations from paramInfo for table component ParameterSPtr p = _parameterManager.getParameter(_originalParamId); ParamInfoSPtr paramInfo = piMgr->getParamInfoFromId(p->getInfoId()); std::string tableLegendText; if (paramInfo) { boost::shared_ptr tableSPtr = paramInfo->getTable(0); if (tableSPtr) { tableLegendText = tableSPtr->getName(&_parameterManager); } else { tableLegendText = "Table indexes"; } } // Build parameter text legend depending on the availability of paramInfo std::string dataLegendText; if (paramInfo) { dataLegendText = paramInfo->getShortName(); } else { dataLegendText = _originalParamId; } // Data always depends on table, no inversion even if table not on x axis std::stringstream paramLegendText; paramLegendText << dataLegendText << " = f(" << tableLegendText << ")"; return paramLegendText.str(); } /** * @overload PanelPlotOutput::configureParamsLegend Configure params legend for an instant plot. */ void InstantPlot::configureParamsLegend(double startTime, double stopTime, int intervalIndex) { LOG4CXX_DEBUG(gLogger, "InstantPlot::configureParamsLegend"); _panel->_paramsLegendProperties.resetPlot(); if (_iSerieProperties == nullptr) return; //for the legend configuration, we don't need to know the line and symbol colors Color fakeColor(0,0,0); AMDA::Common::ParameterIndexComponent index(-1,-1); addSerieToParamsLegend(*_iSerieProperties,index, _originalParamId,fakeColor, fakeColor,startTime,stopTime, intervalIndex); } /** * @brief Override PanelPlotOutput:draw * draw the plot for the current time interval */ bool InstantPlot::draw(double startTime, double stopTime, int intervalIndex, bool /*isFirstInterval*/, bool /*isLastInterval*/) { LOG4CXX_DEBUG(gLogger, "InstantPlot::draw"); _panel->_paramsLegendProperties.resetPlot(); // Sets panel plplot viewport, draw background & title for the panel _panel->draw(_pls); bool noData = true; if (!_originalParamId.empty()) { //Set pointer to ParameterData list if (_pParameterValues == NULL) { std::stringstream lError; lError << "PanelPlotOutput::draw - Pointer to parameterValues is not set"; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } // Compute panel XY ratio used for angular conversions computePanelPlotXYRatio(); // Draw fill area between parameter and constant or between parameters drawFills (startTime, stopTime); if (_iSerieProperties != nullptr) { // Draw series for parameters. ParameterAxes param; drawSeries(startTime, stopTime, intervalIndex, _originalParamId, *_iSerieProperties, AMDA::Common::ParameterIndexComponent(-1,-1), param, false, noData); } else if (_iSpectroProperties != nullptr) { drawSpectro(startTime, stopTime, _originalParamId, *_iSpectroProperties, noData); } // Draw additionnal objects for this series. drawAdditionalObjects(); //Draw parameter legend drawParamsLegend(); //Draw text legends drawTextLegends(); return !noData; } else { _panel->drawEmptyPanel(_pls); return true; } } /** * @brief Override drawAdditionalObjects * draw additional objects */ void InstantPlot::drawAdditionalObjects() { if (_iSpectroProperties != nullptr) { boost::shared_ptr lXAxis(_panel->getAxis(_iSpectroProperties->getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(_iSpectroProperties->getYAxisId())); if ((lXAxis != nullptr) && (lYAxis != nullptr)) { Range lXRange = lXAxis->getRange(); Range lYRange = lYAxis->getRange(); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); if (!lXAxis->_additionalObjDrawn) drawXConstantLines (lXAxis, lPlWindow); if (!lYAxis->_additionalObjDrawn) drawYConstantLines (lYAxis, lPlWindow); if (!lXAxis->_additionalObjDrawn || !lYAxis->_additionalObjDrawn) drawTextPlots (lXAxis, lYAxis, lPlWindow, _panel->_textPlots); lXAxis->_additionalObjDrawn = true; lYAxis->_additionalObjDrawn = true; } } if (_iSerieProperties != nullptr) { boost::shared_ptr lXAxis(_panel->getAxis(_iSerieProperties->getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(_iSerieProperties->getYAxisId())); if ((lXAxis != nullptr) && (lYAxis != nullptr)) { Range lXRange = lXAxis->getRange(); Range lYRange = lYAxis->getRange(); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); if (!lXAxis->_additionalObjDrawn) drawXConstantLines (lXAxis, lPlWindow); if (!lYAxis->_additionalObjDrawn) drawYConstantLines (lYAxis, lPlWindow); if (!lXAxis->_additionalObjDrawn || !lYAxis->_additionalObjDrawn) drawTextPlots (lXAxis, lYAxis, lPlWindow, _panel->_textPlots); lXAxis->_additionalObjDrawn = true; lYAxis->_additionalObjDrawn = true; } } } void InstantPlot::writeContext(ContextFileWriter &writer, AMDA::Parameters::TimeIntervalList::iterator currentTimeInterval) { PanelPlotOutput::writeContext(writer, currentTimeInterval); if (!isStandalone()) return; writer.startElement("instantTimeNav"); writer.addAttribute("prevTime", std::to_string(_prevTime).c_str()); writer.addAttribute("nextTime", std::to_string(_nextTime).c_str()); writer.endElement(); } } /* namespace plot */