From 2a20f84f1fe0efabb3be44e9f7abcfcc67af699a Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Wed, 25 Sep 2019 17:48:19 +0200 Subject: [PATCH] #4732 Support error bars for observed RFT data (#4760) * #4732 Fix missing refresh for ensemble RFT * WIP * #4732 Fix missing refresh for ensemble RFT * WIP * Make sure Observed RFT data is loaded on startup * Make error bars work for RFT plots * #4761 Add labels with formation and value/error to observed data points * Changes after review --- .../Application/RiaApplication.cpp | 5 ++ .../FileInterface/RifEclipseRftAddress.h | 5 +- .../RifReaderEnsembleStatisticsRft.cpp | 3 +- .../FileInterface/RifReaderFmuRft.cpp | 32 ++++++++ .../FileInterface/RifReaderFmuRft.h | 2 + .../ProjectDataModel/Flow/RimWellRftPlot.cpp | 18 ++++- .../ProjectDataModel/Flow/RimWellRftPlot.h | 6 ++ .../RimObservedFmuRftData.cpp | 12 +++ .../ProjectDataModel/RimObservedFmuRftData.h | 3 +- .../ProjectDataModel/RimWellLogCurve.cpp | 1 + .../ProjectDataModel/RimWellLogRftCurve.cpp | 65 ++++++++++++--- .../ProjectDataModel/RimWellLogRftCurve.h | 3 + .../UserInterface/RiuQwtPlotCurve.cpp | 80 +++++++++++++++---- .../UserInterface/RiuQwtPlotCurve.h | 15 +++- .../UserInterface/RiuQwtSymbol.cpp | 33 ++++---- ApplicationCode/UserInterface/RiuQwtSymbol.h | 15 ++-- 16 files changed, 240 insertions(+), 58 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index b6c7eadda6..11b14f5691 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -56,6 +56,7 @@ #include "RimIdenticalGridCaseGroup.h" #include "RimMainPlotCollection.h" #include "RimObservedDataCollection.h" +#include "RimObservedFmuRftData.h" #include "RimObservedSummaryData.h" #include "RimOilField.h" #include "RimPltPlotCollection.h" @@ -492,6 +493,10 @@ bool RiaApplication::loadProject( const QString& projectFileName, observedData->createRftReaderInterface(); observedData->updateMetaData(); } + for ( RimObservedFmuRftData* observedFmuData : oilField->observedDataCollection()->allObservedFmuRftData() ) + { + observedFmuData->createRftReaderInterface(); + } oilField->fractureDefinitionCollection()->loadAndUpdateData(); oilField->fractureDefinitionCollection()->createAndAssignTemplateCopyForNonMatchingUnit(); diff --git a/ApplicationCode/FileInterface/RifEclipseRftAddress.h b/ApplicationCode/FileInterface/RifEclipseRftAddress.h index a5dc3c4700..8fa807829f 100644 --- a/ApplicationCode/FileInterface/RifEclipseRftAddress.h +++ b/ApplicationCode/FileInterface/RifEclipseRftAddress.h @@ -46,7 +46,8 @@ public: PRESSURE_P10, PRESSURE_P50, PRESSURE_P90, - PRESSURE_MEAN + PRESSURE_MEAN, + PRESSURE_ERROR }; public: @@ -83,4 +84,4 @@ private: bool operator==( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second ); -bool operator<( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second ); \ No newline at end of file +bool operator<( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second ); diff --git a/ApplicationCode/FileInterface/RifReaderEnsembleStatisticsRft.cpp b/ApplicationCode/FileInterface/RifReaderEnsembleStatisticsRft.cpp index 57f1e6a03a..e5eca145ba 100644 --- a/ApplicationCode/FileInterface/RifReaderEnsembleStatisticsRft.cpp +++ b/ApplicationCode/FileInterface/RifReaderEnsembleStatisticsRft.cpp @@ -82,7 +82,8 @@ void RifReaderEnsembleStatisticsRft::values( const RifEclipseRftAddress& rftAddr rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_MEAN || rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P10 || rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P50 || - rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P90 ); + rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P90 || + rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_ERROR ); auto it = m_cachedValues.find( rftAddress ); if ( it == m_cachedValues.end() ) diff --git a/ApplicationCode/FileInterface/RifReaderFmuRft.cpp b/ApplicationCode/FileInterface/RifReaderFmuRft.cpp index 44deed5a63..1178affcba 100644 --- a/ApplicationCode/FileInterface/RifReaderFmuRft.cpp +++ b/ApplicationCode/FileInterface/RifReaderFmuRft.cpp @@ -138,6 +138,33 @@ bool RifReaderFmuRft::directoryContainsFmuRftData( const QString& filePath ) return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RifReaderFmuRft::labels( const RifEclipseRftAddress& rftAddress ) +{ + std::vector formationLabels; + + if ( m_allWellObservations.empty() ) + { + load(); + } + + auto it = m_allWellObservations.find( rftAddress.wellName() ); + if ( it != m_allWellObservations.end() ) + { + const std::vector& observations = it->second.observations; + for ( const Observation& observation : observations ) + { + formationLabels.push_back( QString( "%1 - Pressure: %2 +/- %3" ) + .arg( observation.formation ) + .arg( observation.pressure ) + .arg( observation.pressureError ) ); + } + } + return formationLabels; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -162,9 +189,11 @@ std::set RifReaderFmuRft::eclipseRftAddresses() RifEclipseRftAddress tvdAddress( wellName, dateTime, RifEclipseRftAddress::TVD ); RifEclipseRftAddress mdAddress( wellName, dateTime, RifEclipseRftAddress::MD ); RifEclipseRftAddress pressureAddress( wellName, dateTime, RifEclipseRftAddress::PRESSURE ); + RifEclipseRftAddress pressureErrorAddress( wellName, dateTime, RifEclipseRftAddress::PRESSURE_ERROR ); allAddresses.insert( tvdAddress ); allAddresses.insert( mdAddress ); allAddresses.insert( pressureAddress ); + allAddresses.insert( pressureErrorAddress ); } } } @@ -202,6 +231,9 @@ void RifReaderFmuRft::values( const RifEclipseRftAddress& rftAddress, std::vecto case RifEclipseRftAddress::PRESSURE: values->push_back( observation.pressure ); break; + case RifEclipseRftAddress::PRESSURE_ERROR: + values->push_back( observation.pressureError ); + break; default: CAF_ASSERT( false && "Wrong channel type sent to Fmu RFT reader" ); } diff --git a/ApplicationCode/FileInterface/RifReaderFmuRft.h b/ApplicationCode/FileInterface/RifReaderFmuRft.h index 843f472452..f0b7cc9dbb 100644 --- a/ApplicationCode/FileInterface/RifReaderFmuRft.h +++ b/ApplicationCode/FileInterface/RifReaderFmuRft.h @@ -68,6 +68,8 @@ public: static QStringList findSubDirectoriesWithFmuRftData( const QString& filePath ); static bool directoryContainsFmuRftData( const QString& filePath ); + std::vector labels( const RifEclipseRftAddress& rftAddress ); + std::set eclipseRftAddresses() override; void values( const RifEclipseRftAddress& rftAddress, std::vector* values ) override; diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp index ee3e9dcfce..5ec14955f6 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp @@ -82,6 +82,7 @@ RimWellRftPlot::RimWellRftPlot() CAF_PDM_InitField( &m_showStatisticsCurves, "ShowStatisticsCurves", true, "Show Statistics Curves", "", "", "" ); CAF_PDM_InitField( &m_showEnsembleCurves, "ShowEnsembleCurves", true, "Show Ensemble Curves", "", "", "" ); + CAF_PDM_InitField( &m_showErrorInObservedData, "ShowErrorObserved", true, "Show Observed Data Error", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_wellLogPlot_OBSOLETE, "WellLog", "Well Log", "", "", "" ); m_wellLogPlot_OBSOLETE.uiCapability()->setUiHidden( true ); @@ -111,6 +112,11 @@ RimWellRftPlot::RimWellRftPlot() m_selectedTimeSteps.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_selectedTimeSteps.uiCapability()->setAutoAddingOptionFromValue( false ); + CAF_PDM_InitFieldNoDefault( &m_wellPathCollection, "WellPathCollection", "Well Path Collection", "", "", "" ); + m_wellPathCollection.uiCapability()->setUiHidden( true ); + m_wellPathCollection.xmlCapability()->disableIO(); + m_wellPathCollection = RiaApplication::instance()->project()->activeOilField()->wellPathCollection(); + m_nameConfig->setCustomName( "RFT Plot" ); m_trackLegendsHorizontal = true; @@ -796,7 +802,8 @@ void RimWellRftPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, syncCurvesFromUiSelection(); this->updateConnectedEditors(); } - else if ( changedField == &m_showStatisticsCurves || changedField == &m_showEnsembleCurves ) + else if ( changedField == &m_showStatisticsCurves || changedField == &m_showEnsembleCurves || + changedField == &m_showErrorInObservedData ) { updateFormationsOnPlot(); syncCurvesFromUiSelection(); @@ -824,6 +831,7 @@ void RimWellRftPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering.add( &m_wellPathNameOrSimWellName ); uiOrdering.add( &m_showStatisticsCurves ); uiOrdering.add( &m_showEnsembleCurves ); + uiOrdering.add( &m_showErrorInObservedData ); bool showingEnsembleData = false; for ( const RifDataSourceForRftPlt& dataSource : m_selectedSources() ) @@ -973,6 +981,14 @@ void RimWellRftPlot::initAfterRead() RimWellLogPlot::initAfterRead(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimWellRftPlot::showErrorBarsForObservedData() const +{ + return m_showErrorInObservedData(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h index 19170d31b5..ca197886e8 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h @@ -42,6 +42,7 @@ class RimEclipseResultCase; class RimWellLogCurve; class RimWellLogFileChannel; class RimWellPath; +class RimWellPathCollection; class RiuWellRftPlot; class RigEclipseCaseData; class RiaRftPltCurveDefinition; @@ -84,6 +85,8 @@ public: void deleteCurvesAssosicatedWithObservedData( const RimObservedFmuRftData* observedFmuRftData ); + bool showErrorBarsForObservedData() const; + protected: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, @@ -134,11 +137,14 @@ private: caf::PdmField m_branchDetection; caf::PdmField m_showStatisticsCurves; caf::PdmField m_showEnsembleCurves; + caf::PdmField m_showErrorInObservedData; caf::PdmField> m_selectedSources; caf::PdmField> m_selectedTimeSteps; + caf::PdmPtrField m_wellPathCollection; + caf::PdmField m_showPlotTitle_OBSOLETE; caf::PdmChildField m_wellLogPlot_OBSOLETE; diff --git a/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.cpp b/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.cpp index e5ea7dbca1..05682de84c 100644 --- a/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.cpp +++ b/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.cpp @@ -97,3 +97,15 @@ std::vector RimObservedFmuRftData::wells() const } return std::vector(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimObservedFmuRftData::labels( const RifEclipseRftAddress& rftAddress ) +{ + if ( m_fmuRftReader.p() ) + { + return const_cast( m_fmuRftReader.p() )->labels( rftAddress ); + } + return {}; +} diff --git a/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.h b/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.h index b70220a0ac..987e31db5b 100644 --- a/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.h +++ b/ApplicationCode/ProjectDataModel/RimObservedFmuRftData.h @@ -38,8 +38,7 @@ public: bool hasWell( const QString& wellPathName ) const; std::vector wells() const; - - std::vector> derivedWellPathTvdMd( const QString& wellPathName ) const; + std::vector labels( const RifEclipseRftAddress& rftAddress ); private: cvf::ref m_fmuRftReader; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 5473dd7900..ceb73bb719 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -47,6 +47,7 @@ RimWellLogCurve::RimWellLogCurve() CAF_PDM_InitObject( "WellLogCurve", ":/WellLogCurve16x16.png", "", "" ); m_qwtPlotCurve->setXAxis( QwtPlot::xTop ); + m_qwtPlotCurve->setErrorBarsXAxis( QwtPlot::xTop ); m_qwtPlotCurve->setYAxis( QwtPlot::yLeft ); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp index 02ad7a9741..e90df8c497 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp @@ -47,6 +47,7 @@ #include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPlotTools.h" +#include "RimWellRftPlot.h" #include "RiuQwtPlotCurve.h" #include "RiuWellLogTrack.h" @@ -81,6 +82,7 @@ void caf::AppEnum::setUp() addItem( RifEclipseRftAddress::PRESSURE_P50, "PRESSURE_P50", "P50: Pressure" ); addItem( RifEclipseRftAddress::PRESSURE_P90, "PRESSURE_P90", "P90: Pressure" ); addItem( RifEclipseRftAddress::PRESSURE_MEAN, "PRESSURE_MEAN", "Mean: Pressure" ); + addItem( RifEclipseRftAddress::PRESSURE_ERROR, "PRESSURE_ERROR", "Error: Pressure" ); setDefault( RifEclipseRftAddress::NONE ); } } // namespace caf @@ -376,9 +378,14 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot ) firstAncestorOrThisOfType( wellLogPlot ); CVF_ASSERT( wellLogPlot ); - std::vector measuredDepthVector = measuredDepthValues(); - std::vector tvDepthVector = tvDepthValues(); - std::vector values = xValues(); + RimWellRftPlot* rftPlot = dynamic_cast( wellLogPlot ); + bool showErrorBarsInObservedData = rftPlot ? rftPlot->showErrorBarsForObservedData() : false; + + std::vector measuredDepthVector = measuredDepthValues(); + std::vector tvDepthVector = tvDepthValues(); + std::vector values = xValues(); + std::vector errors = errorValues(); + std::vector perPointLabels; if ( values.empty() || values.size() != tvDepthVector.size() ) { @@ -402,7 +409,8 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot ) else if ( m_observedFmuRftData ) { // TODO: Read unit system somewhere for FMU RFT Data - unitSystem = RiaEclipseUnitTools::UNITS_METRIC; + unitSystem = RiaEclipseUnitTools::UNITS_METRIC; + perPointLabels = this->perPointLabels(); } else { @@ -441,9 +449,13 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot ) if ( wellLogPlot->depthType() == RimWellLogPlot::MEASURED_DEPTH ) { - m_qwtPlotCurve->setSamples( m_curveData->xPlotValues().data(), - m_curveData->measuredDepthPlotValues( displayUnit ).data(), - static_cast( m_curveData->xPlotValues().size() ) ); + m_qwtPlotCurve->showErrorBars( showErrorBarsInObservedData ); + m_qwtPlotCurve->setPerPointLabels( perPointLabels ); + m_qwtPlotCurve->setSamplesFromXValuesAndYValues( m_curveData->xPlotValues(), + m_curveData->measuredDepthPlotValues( displayUnit ), + errors, + false, + RiuQwtPlotCurve::ERROR_ALONG_Y_AXIS ); RimWellLogTrack* wellLogTrack; firstAncestorOrThisOfType( wellLogTrack ); @@ -472,9 +484,13 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot ) } else { - m_qwtPlotCurve->setSamples( m_curveData->xPlotValues().data(), - m_curveData->trueDepthPlotValues( displayUnit ).data(), - static_cast( m_curveData->xPlotValues().size() ) ); + m_qwtPlotCurve->showErrorBars( showErrorBarsInObservedData ); + m_qwtPlotCurve->setPerPointLabels( perPointLabels ); + m_qwtPlotCurve->setSamplesFromXValuesAndYValues( m_curveData->xPlotValues(), + m_curveData->trueDepthPlotValues( displayUnit ), + errors, + false, + RiuQwtPlotCurve::ERROR_ALONG_Y_AXIS ); } m_qwtPlotCurve->setLineSegmentStartStopIndices( m_curveData->polylineStartStopIndices() ); @@ -648,6 +664,19 @@ void RimWellLogRftCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedFie } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimWellLogRftCurve::perPointLabels() const +{ + if ( m_observedFmuRftData() ) + { + RifEclipseRftAddress address( m_wellName(), m_timeStep, RifEclipseRftAddress::PRESSURE ); + return m_observedFmuRftData()->labels( address ); + } + return {}; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -833,6 +862,22 @@ std::vector RimWellLogRftCurve::xValues() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimWellLogRftCurve::errorValues() +{ + RifReaderRftInterface* reader = rftReader(); + std::vector errorValues; + + if ( reader ) + { + RifEclipseRftAddress errorAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::PRESSURE_ERROR ); + reader->values( errorAddress, &errorValues ); + } + return errorValues; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h index f67ba136ec..4f89c5f38f 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h @@ -95,6 +95,8 @@ protected: const QVariant& oldValue, const QVariant& newValue ) override; + std::vector perPointLabels() const; + private: RifReaderRftInterface* rftReader() const; @@ -105,6 +107,7 @@ private: std::vector sortedIndicesInRftFile(); std::vector xValues(); + std::vector errorValues(); std::vector tvDepthValues(); std::vector measuredDepthValues(); diff --git a/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp b/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp index 63919c6c45..5e9bc93a50 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp @@ -73,20 +73,21 @@ RiuQwtPlotCurve::~RiuQwtPlotCurve() {} //-------------------------------------------------------------------------------------------------- void RiuQwtPlotCurve::setSamplesFromXValuesAndYValues( const std::vector& xValues, const std::vector& yValues, - const std::vector& yErrorValues, - bool keepOnlyPositiveValues ) + const std::vector& errorValues, + bool keepOnlyPositiveValues, + ErrorAxis errorAxis ) { CVF_ASSERT( xValues.size() == yValues.size() ); CVF_ASSERT( yErrorValues.empty() || yErrorValues.size() == xValues.size() ); - bool showErrorBars = m_showErrorBars && !yErrorValues.empty(); + bool showErrorBars = m_showErrorBars && !errorValues.empty(); QPolygonF points; QVector errorIntervals; std::vector> filteredIntervals; { std::vector filteredYValues; std::vector filteredXValues; - std::vector filteredYErrorValues; + std::vector filteredErrorValues; { auto intervalsOfValidValues = RiaCurveDataTools::calculateIntervalsOfValidValues( yValues, @@ -96,7 +97,7 @@ void RiuQwtPlotCurve::setSamplesFromXValuesAndYValues( const std::vector RiaCurveDataTools::getValuesByIntervals( xValues, intervalsOfValidValues, &filteredXValues ); if ( showErrorBars ) - RiaCurveDataTools::getValuesByIntervals( yErrorValues, intervalsOfValidValues, &filteredYErrorValues ); + RiaCurveDataTools::getValuesByIntervals( errorValues, intervalsOfValidValues, &filteredErrorValues ); filteredIntervals = RiaCurveDataTools::computePolyLineStartStopIndices( intervalsOfValidValues ); } @@ -107,11 +108,20 @@ void RiuQwtPlotCurve::setSamplesFromXValuesAndYValues( const std::vector { points << QPointF( filteredXValues[i], filteredYValues[i] ); - if ( showErrorBars && filteredYValues[i] != DOUBLE_INF && filteredYErrorValues[i] != DOUBLE_INF ) + if ( showErrorBars && filteredYValues[i] != DOUBLE_INF && filteredErrorValues[i] != DOUBLE_INF ) { - errorIntervals << QwtIntervalSample( filteredXValues[i], - filteredYValues[i] - filteredYErrorValues[i], - filteredYValues[i] + filteredYErrorValues[i] ); + if ( errorAxis == ERROR_ALONG_Y_AXIS ) + { + errorIntervals << QwtIntervalSample( filteredXValues[i], + filteredYValues[i] - filteredErrorValues[i], + filteredYValues[i] + filteredErrorValues[i] ); + } + else + { + errorIntervals << QwtIntervalSample( filteredYValues[i], + filteredXValues[i] - filteredErrorValues[i], + filteredXValues[i] + filteredErrorValues[i] ); + } } } } @@ -119,7 +129,18 @@ void RiuQwtPlotCurve::setSamplesFromXValuesAndYValues( const std::vector this->setSamples( points ); this->setLineSegmentStartStopIndices( filteredIntervals ); - if ( showErrorBars ) m_errorBars->setSamples( errorIntervals ); + if ( showErrorBars ) + { + m_errorBars->setSamples( errorIntervals ); + if ( errorAxis == ERROR_ALONG_Y_AXIS ) + { + m_errorBars->setOrientation( Qt::Vertical ); + } + else + { + m_errorBars->setOrientation( Qt::Horizontal ); + } + } } //-------------------------------------------------------------------------------------------------- @@ -285,11 +306,21 @@ void RiuQwtPlotCurve::drawSymbols( QPainter* painter, const RiuQwtSymbol* sym = dynamic_cast( &symbol ); - if ( sym && !sym->label().isEmpty() ) + if ( sym ) { - for ( auto& pt : pointsToDisplay ) + if ( m_perPointLabels.size() == pointsToDisplay.size() ) { - sym->renderSymbolLabel( painter, pt ); + for ( int i = 0; i < (int)pointsToDisplay.size(); ++i ) + { + sym->renderSymbolLabel( painter, pointsToDisplay[i], m_perPointLabels[i] ); + } + } + else if ( !sym->globalLabel().isEmpty() ) + { + for ( auto& pt : pointsToDisplay ) + { + sym->renderSymbolLabel( painter, pt, sym->globalLabel() ); + } } } } @@ -318,7 +349,10 @@ void RiuQwtPlotCurve::setSymbolSkipPixelDistance( float distance ) void RiuQwtPlotCurve::attach( QwtPlot* plot ) { QwtPlotItem::attach( plot ); - if ( m_showErrorBars ) m_errorBars->attach( plot ); + if ( m_showErrorBars ) + { + m_errorBars->attach( plot ); + } m_attachedToPlot = plot; } @@ -362,6 +396,24 @@ void RiuQwtPlotCurve::setErrorBarsColor( QColor color ) m_errorBars->setSymbol( newSymbol ); } +//-------------------------------------------------------------------------------------------------- +/// Set the Qwt X-Axis (QwtPlot::xBottom or QwtPlot::xTop). +/// This is important to make sure the x-axis interval is set correctly. +/// WellLogPlots use top-axis and Summary uses bottom axis. +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotCurve::setErrorBarsXAxis( int axis ) +{ + m_errorBars->setXAxis( axis ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotCurve::setPerPointLabels( const std::vector& labels ) +{ + m_perPointLabels = labels; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuQwtPlotCurve.h b/ApplicationCode/UserInterface/RiuQwtPlotCurve.h index 8a5653c05c..908462217c 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotCurve.h +++ b/ApplicationCode/UserInterface/RiuQwtPlotCurve.h @@ -48,6 +48,12 @@ class RiuErrorBarsQwtPlotCurve; class RiuQwtPlotCurve : public QwtPlotCurve { public: + enum ErrorAxis + { + ERROR_ALONG_X_AXIS, + ERROR_ALONG_Y_AXIS + }; + enum CurveInterpolationEnum { INTERPOLATION_POINT_TO_POINT, @@ -83,8 +89,9 @@ public: void setSamplesFromXValuesAndYValues( const std::vector& xValues, const std::vector& yValues, - const std::vector& yErrorValues, - bool keepOnlyPositiveValues ); + const std::vector& errorValues, + bool keepOnlyPositiveValues, + ErrorAxis errorAxis = ERROR_ALONG_Y_AXIS ); void setSamplesFromDatesAndYValues( const std::vector& dateTimes, const std::vector& yValues, @@ -108,6 +115,8 @@ public: void clearErrorBars(); void showErrorBars( bool show ); void setErrorBarsColor( QColor color ); + void setErrorBarsXAxis( int axis ); + void setPerPointLabels( const std::vector& labels ); void setAppearance( LineStyleEnum lineStyle, CurveInterpolationEnum interpolationType, @@ -145,4 +154,6 @@ private: QwtPlotIntervalCurve* m_errorBars; QwtPlot* m_attachedToPlot; bool m_blackAndWhiteLegendIcon; + + std::vector m_perPointLabels; }; diff --git a/ApplicationCode/UserInterface/RiuQwtSymbol.cpp b/ApplicationCode/UserInterface/RiuQwtSymbol.cpp index f2f63941b1..3aeee2cb64 100644 --- a/ApplicationCode/UserInterface/RiuQwtSymbol.cpp +++ b/ApplicationCode/UserInterface/RiuQwtSymbol.cpp @@ -28,7 +28,7 @@ //-------------------------------------------------------------------------------------------------- RiuQwtSymbol::RiuQwtSymbol( PointSymbolEnum riuStyle, const QString& label, LabelPosition labelPosition ) : QwtSymbol( QwtSymbol::NoSymbol ) - , m_label( label ) + , m_globalLabel( label ) , m_labelPosition( labelPosition ) { QwtSymbol::Style style = QwtSymbol::NoSymbol; @@ -133,34 +133,33 @@ RiuQwtSymbol::RiuQwtSymbol( PointSymbolEnum riuStyle, const QString& label, Labe void RiuQwtSymbol::renderSymbols( QPainter* painter, const QPointF* points, int numPoints ) const { QwtSymbol::renderSymbols( painter, points, numPoints ); - - if ( !m_label.isEmpty() ) - { - for ( int i = 0; i < numPoints; i++ ) - { - auto position = points[i]; - // renderSymbolLabel(painter, position); - } - } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQwtSymbol::renderSymbolLabel( QPainter* painter, const QPointF& position ) const +void RiuQwtSymbol::renderSymbolLabel( QPainter* painter, const QPointF& position, const QString& label ) const { QSize symbolSize = QwtSymbol::size(); QRect symbolRect( position.x(), position.y(), symbolSize.width(), symbolSize.height() ); - QRect labelRect = labelBoundingRect( painter, symbolRect ); - painter->drawText( labelRect.topLeft(), m_label ); + QRect labelRect = labelBoundingRect( painter, symbolRect, label ); + painter->drawText( labelRect.topLeft(), label ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQwtSymbol::setLabel( const QString& label ) +QString RiuQwtSymbol::globalLabel() const { - m_label = label; + return m_globalLabel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtSymbol::setGlobalLabel( const QString& label ) +{ + m_globalLabel = label; } //-------------------------------------------------------------------------------------------------- @@ -212,7 +211,7 @@ RiuQwtSymbol::PointSymbolEnum RiuQwtSymbol::cycledSymbolStyle( int indexLevel ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QRect RiuQwtSymbol::labelBoundingRect( const QPainter* painter, const QRect& symbolRect ) const +QRect RiuQwtSymbol::labelBoundingRect( const QPainter* painter, const QRect& symbolRect, const QString& label ) const { CVF_ASSERT( painter ); @@ -221,7 +220,7 @@ QRect RiuQwtSymbol::labelBoundingRect( const QPainter* painter, const QRect& sym int symbolWidth = symbolRect.width(); int symbolHeight = symbolRect.height(); - int labelWidth = painter->fontMetrics().width( m_label ); + int labelWidth = painter->fontMetrics().width( label ); int labelHeight = painter->fontMetrics().height(); QPoint labelPosition; diff --git a/ApplicationCode/UserInterface/RiuQwtSymbol.h b/ApplicationCode/UserInterface/RiuQwtSymbol.h index 0ed04780ac..fef336b985 100644 --- a/ApplicationCode/UserInterface/RiuQwtSymbol.h +++ b/ApplicationCode/UserInterface/RiuQwtSymbol.h @@ -61,14 +61,11 @@ public: }; RiuQwtSymbol( PointSymbolEnum riuStyle, const QString& label, LabelPosition labelPosition = LabelAboveSymbol ); - void renderSymbols( QPainter* painter, const QPointF* points, int numPoints ) const override; - void renderSymbolLabel( QPainter* painter, const QPointF& position ) const; - QString label() const - { - return m_label; - } - void setLabel( const QString& label ); + void renderSymbolLabel( QPainter* painter, const QPointF& position, const QString& label ) const; + QString globalLabel() const; + + void setGlobalLabel( const QString& label ); void setLabelPosition( LabelPosition labelPosition ); @@ -76,9 +73,9 @@ public: static PointSymbolEnum cycledSymbolStyle( int indexLevel ); private: - QRect labelBoundingRect( const QPainter* painter, const QRect& symbolRect ) const; + QRect labelBoundingRect( const QPainter* painter, const QRect& symbolRect, const QString& label ) const; private: - QString m_label; + QString m_globalLabel; LabelPosition m_labelPosition; };