mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Grid Cross Plot: Add regression curves.
This commit is contained in:
parent
e1dacf7617
commit
fdf4309d82
@ -52,6 +52,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNetworkTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaNetworkTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaOpenMPTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaOpenMPTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNumericalTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaNumericalTools.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTextTools.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCE_GROUP_SOURCE_FILES
|
set(SOURCE_GROUP_SOURCE_FILES
|
||||||
@ -101,6 +102,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNetworkTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaNetworkTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaOpenMPTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaOpenMPTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNumericalTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaNumericalTools.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTextTools.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
|
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
|
||||||
|
116
ApplicationLibCode/Application/Tools/RiaRegressionTextTools.cpp
Normal file
116
ApplicationLibCode/Application/Tools/RiaRegressionTextTools.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RiaRegressionTextTools.h"
|
||||||
|
|
||||||
|
#include "ExponentialRegression.hpp"
|
||||||
|
#include "LinearRegression.hpp"
|
||||||
|
#include "LogarithmicRegression.hpp"
|
||||||
|
#include "LogisticRegression.hpp"
|
||||||
|
#include "PolynomialRegression.hpp"
|
||||||
|
#include "PowerFitRegression.hpp"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::generateRegressionText( const regression::LinearRegression& reg )
|
||||||
|
{
|
||||||
|
QString sign = reg.intercept() < 0.0 ? "-" : "+";
|
||||||
|
return QString( "y = %1x %2 %3" ).arg( formatDouble( reg.slope() ) ).arg( sign ).arg( formatDouble( std::fabs( reg.intercept() ) ) ) +
|
||||||
|
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::generateRegressionText( const regression::PolynomialRegression& reg )
|
||||||
|
{
|
||||||
|
QString str = "y = ";
|
||||||
|
|
||||||
|
bool isFirst = true;
|
||||||
|
std::vector<double> coeffs = reg.coeffisients();
|
||||||
|
QStringList parts;
|
||||||
|
for ( size_t i = 0; i < coeffs.size(); i++ )
|
||||||
|
{
|
||||||
|
double coeff = coeffs[i];
|
||||||
|
// Skip zero coeffs
|
||||||
|
if ( coeff != 0.0 )
|
||||||
|
{
|
||||||
|
if ( coeff < 0.0 )
|
||||||
|
parts.append( "-" );
|
||||||
|
else if ( !isFirst )
|
||||||
|
parts.append( "+" );
|
||||||
|
|
||||||
|
if ( i == 0 )
|
||||||
|
{
|
||||||
|
parts.append( QString( "%1" ).arg( formatDouble( std::fabs( coeff ) ) ) );
|
||||||
|
}
|
||||||
|
else if ( i == 1 )
|
||||||
|
{
|
||||||
|
parts.append( QString( "%1x" ).arg( formatDouble( std::fabs( coeff ) ) ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parts.append( QString( " %1x<sup>%2</sup>" ).arg( formatDouble( std::fabs( coeff ) ) ).arg( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + parts.join( " " ) + QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::generateRegressionText( const regression::PowerFitRegression& reg )
|
||||||
|
{
|
||||||
|
return QString( "y = %1 + x<sup>%2</sup>" ).arg( formatDouble( reg.scale() ) ).arg( formatDouble( reg.exponent() ) ) +
|
||||||
|
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::generateRegressionText( const regression::ExponentialRegression& reg )
|
||||||
|
{
|
||||||
|
return QString( "y = %1 * e<sup>%2x</sup>" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
|
||||||
|
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::generateRegressionText( const regression::LogarithmicRegression& reg )
|
||||||
|
{
|
||||||
|
return QString( "y = %1 + %2 * ln(x)" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
|
||||||
|
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaRegressionTextTools::formatDouble( double v )
|
||||||
|
{
|
||||||
|
return QString::number( v, 'g', 2 );
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace regression
|
||||||
|
{
|
||||||
|
class ExponentialRegression;
|
||||||
|
class LinearRegression;
|
||||||
|
class LogarithmicRegression;
|
||||||
|
class PolynomialRegression;
|
||||||
|
class PowerFitRegression;
|
||||||
|
} // namespace regression
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
class RiaRegressionTextTools
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QString generateRegressionText( const regression::LinearRegression& reg );
|
||||||
|
static QString generateRegressionText( const regression::PolynomialRegression& reg );
|
||||||
|
static QString generateRegressionText( const regression::PowerFitRegression& reg );
|
||||||
|
static QString generateRegressionText( const regression::LogarithmicRegression& reg );
|
||||||
|
static QString generateRegressionText( const regression::ExponentialRegression& reg );
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString formatDouble( double v );
|
||||||
|
}; // namespace RiaRegressionTextTools
|
@ -132,6 +132,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RimPressureDepthData.h
|
${CMAKE_CURRENT_LIST_DIR}/RimPressureDepthData.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimEclipseResultDefinitionTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RimEclipseResultDefinitionTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimResultSelectionUi.h
|
${CMAKE_CURRENT_LIST_DIR}/RimResultSelectionUi.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimPlotRectAnnotation.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCE_GROUP_SOURCE_FILES
|
set(SOURCE_GROUP_SOURCE_FILES
|
||||||
@ -263,6 +264,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RimPressureDepthData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimPressureDepthData.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimEclipseResultDefinitionTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimEclipseResultDefinitionTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimResultSelectionUi.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimResultSelectionUi.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimPlotRectAnnotation.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(RESINSIGHT_USE_QT_CHARTS)
|
if(RESINSIGHT_USE_QT_CHARTS)
|
||||||
|
@ -2,6 +2,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.h
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.h
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.h
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotRegressionCurve.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.h
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.h
|
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.h
|
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.h
|
||||||
@ -11,6 +12,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotRegressionCurve.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.cpp
|
||||||
|
@ -210,6 +210,7 @@ void RimGridCrossPlot::reattachAllCurves()
|
|||||||
for ( auto dataSet : m_crossPlotDataSets )
|
for ( auto dataSet : m_crossPlotDataSets )
|
||||||
{
|
{
|
||||||
dataSet->detachAllCurves();
|
dataSet->detachAllCurves();
|
||||||
|
dataSet->detachAllRegressionCurves();
|
||||||
if ( dataSet->isChecked() )
|
if ( dataSet->isChecked() )
|
||||||
{
|
{
|
||||||
dataSet->setParentPlotNoReplot( m_plotWidget );
|
dataSet->setParentPlotNoReplot( m_plotWidget );
|
||||||
@ -336,6 +337,7 @@ void RimGridCrossPlot::detachAllCurves()
|
|||||||
for ( auto dataSet : m_crossPlotDataSets() )
|
for ( auto dataSet : m_crossPlotDataSets() )
|
||||||
{
|
{
|
||||||
dataSet->detachAllCurves();
|
dataSet->detachAllCurves();
|
||||||
|
dataSet->detachAllRegressionCurves();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1026,6 +1028,7 @@ void RimGridCrossPlot::cleanupBeforeClose()
|
|||||||
for ( auto dataSet : m_crossPlotDataSets() )
|
for ( auto dataSet : m_crossPlotDataSets() )
|
||||||
{
|
{
|
||||||
dataSet->detachAllCurves();
|
dataSet->detachAllCurves();
|
||||||
|
dataSet->detachAllRegressionCurves();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_plotWidget )
|
if ( m_plotWidget )
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "RimGridCrossPlotDataSet.h"
|
#include "RimGridCrossPlotDataSet.h"
|
||||||
|
|
||||||
#include "RiaColorTables.h"
|
#include "RiaColorTables.h"
|
||||||
|
#include "RiaColorTools.h"
|
||||||
#include "RiaLogging.h"
|
#include "RiaLogging.h"
|
||||||
|
|
||||||
#include "RifTextDataTableFormatter.h"
|
#include "RifTextDataTableFormatter.h"
|
||||||
@ -30,12 +31,11 @@
|
|||||||
#include "RigEclipseCaseData.h"
|
#include "RigEclipseCaseData.h"
|
||||||
#include "RigEclipseCrossPlotDataExtractor.h"
|
#include "RigEclipseCrossPlotDataExtractor.h"
|
||||||
#include "RigEclipseResultAddress.h"
|
#include "RigEclipseResultAddress.h"
|
||||||
|
|
||||||
#include "RigFormationNames.h"
|
#include "RigFormationNames.h"
|
||||||
#include "RigMainGrid.h"
|
#include "RigMainGrid.h"
|
||||||
|
|
||||||
#include "RiuDraggableOverlayFrame.h"
|
#include "RiuDraggableOverlayFrame.h"
|
||||||
#include "RiuGridCrossQwtPlot.h"
|
#include "RiuGuiTheme.h"
|
||||||
#include "RiuPlotWidget.h"
|
#include "RiuPlotWidget.h"
|
||||||
#include "RiuScalarMapperLegendFrame.h"
|
#include "RiuScalarMapperLegendFrame.h"
|
||||||
|
|
||||||
@ -48,6 +48,7 @@
|
|||||||
#include "RimFormationNames.h"
|
#include "RimFormationNames.h"
|
||||||
#include "RimGridCrossPlot.h"
|
#include "RimGridCrossPlot.h"
|
||||||
#include "RimGridCrossPlotCurve.h"
|
#include "RimGridCrossPlotCurve.h"
|
||||||
|
#include "RimGridCrossPlotRegressionCurve.h"
|
||||||
#include "RimGridView.h"
|
#include "RimGridView.h"
|
||||||
#include "RimProject.h"
|
#include "RimProject.h"
|
||||||
#include "RimRegularLegendConfig.h"
|
#include "RimRegularLegendConfig.h"
|
||||||
@ -63,9 +64,6 @@
|
|||||||
#include "cafProgressInfo.h"
|
#include "cafProgressInfo.h"
|
||||||
#include "cafTitledOverlayFrame.h"
|
#include "cafTitledOverlayFrame.h"
|
||||||
#include "cvfScalarMapper.h"
|
#include "cvfScalarMapper.h"
|
||||||
#include "cvfqtUtils.h"
|
|
||||||
|
|
||||||
#include "qwt_plot.h"
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
@ -129,6 +127,9 @@ RimGridCrossPlotDataSet::RimGridCrossPlotDataSet()
|
|||||||
CAF_PDM_InitFieldNoDefault( &m_crossPlotCurves, "CrossPlotCurves", "Curves" );
|
CAF_PDM_InitFieldNoDefault( &m_crossPlotCurves, "CrossPlotCurves", "Curves" );
|
||||||
m_crossPlotCurves.uiCapability()->setUiTreeHidden( true );
|
m_crossPlotCurves.uiCapability()->setUiTreeHidden( true );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_crossPlotRegressionCurves, "CrossPlotRegressionCurves", "Regression Curves" );
|
||||||
|
// m_crossPlotRegressionCurves.uiCapability()->setUiTreeHidden( true );
|
||||||
|
|
||||||
CAF_PDM_InitField( &m_useCustomColor, "UseCustomColor", false, "Use Custom Color" );
|
CAF_PDM_InitField( &m_useCustomColor, "UseCustomColor", false, "Use Custom Color" );
|
||||||
CAF_PDM_InitField( &m_customColor, "CustomColor", cvf::Color3f( cvf::Color3f::BLACK ), "Custom Color" );
|
CAF_PDM_InitField( &m_customColor, "CustomColor", cvf::Color3f( cvf::Color3f::BLACK ), "Custom Color" );
|
||||||
|
|
||||||
@ -159,43 +160,42 @@ RimGridCrossPlotDataSet::~RimGridCrossPlotDataSet()
|
|||||||
void RimGridCrossPlotDataSet::setCellFilterView( RimGridView* cellFilterView )
|
void RimGridCrossPlotDataSet::setCellFilterView( RimGridView* cellFilterView )
|
||||||
{
|
{
|
||||||
m_cellFilterView = cellFilterView;
|
m_cellFilterView = cellFilterView;
|
||||||
|
|
||||||
auto eclipseView = dynamic_cast<RimEclipseView*>( m_cellFilterView() );
|
auto eclipseView = dynamic_cast<RimEclipseView*>( m_cellFilterView() );
|
||||||
|
if ( !eclipseView ) return;
|
||||||
|
|
||||||
if ( eclipseView )
|
m_groupingProperty->setReservoirView( eclipseView );
|
||||||
|
RigEclipseResultAddress resAddr = eclipseView->cellResult()->eclipseResultAddress();
|
||||||
|
if ( resAddr.isValid() )
|
||||||
{
|
{
|
||||||
m_groupingProperty->setReservoirView( eclipseView );
|
m_grouping = NO_GROUPING;
|
||||||
RigEclipseResultAddress resAddr = eclipseView->cellResult()->eclipseResultAddress();
|
|
||||||
if ( resAddr.isValid() )
|
RimEclipseCase* eclipseCase = eclipseView->eclipseCase();
|
||||||
|
if ( eclipseCase )
|
||||||
{
|
{
|
||||||
m_grouping = NO_GROUPING;
|
m_case = eclipseCase;
|
||||||
|
m_xAxisProperty->setEclipseCase( eclipseCase );
|
||||||
|
m_yAxisProperty->setEclipseCase( eclipseCase );
|
||||||
|
m_groupingProperty->setEclipseCase( eclipseCase );
|
||||||
|
|
||||||
RimEclipseCase* eclipseCase = eclipseView->eclipseCase();
|
if ( eclipseCase->activeFormationNames() )
|
||||||
if ( eclipseCase )
|
|
||||||
{
|
{
|
||||||
m_case = eclipseCase;
|
m_grouping = GROUP_BY_FORMATION;
|
||||||
m_xAxisProperty->setEclipseCase( eclipseCase );
|
m_groupingProperty->legendConfig()->setColorLegend(
|
||||||
m_yAxisProperty->setEclipseCase( eclipseCase );
|
RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::CATEGORY ) );
|
||||||
m_groupingProperty->setEclipseCase( eclipseCase );
|
|
||||||
|
|
||||||
if ( eclipseCase->activeFormationNames() )
|
|
||||||
{
|
|
||||||
m_grouping = GROUP_BY_FORMATION;
|
|
||||||
m_groupingProperty->legendConfig()->setColorLegend(
|
|
||||||
RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::CATEGORY ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_xAxisProperty->setResultType( resAddr.resultCatType() );
|
m_xAxisProperty->setResultType( resAddr.resultCatType() );
|
||||||
m_xAxisProperty->setResultVariable( resAddr.resultName() );
|
m_xAxisProperty->setResultVariable( resAddr.resultName() );
|
||||||
m_yAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
m_yAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
||||||
m_yAxisProperty->setResultVariable( "DEPTH" );
|
m_yAxisProperty->setResultVariable( "DEPTH" );
|
||||||
m_timeStep = eclipseView->currentTimeStep();
|
m_timeStep = eclipseView->currentTimeStep();
|
||||||
|
|
||||||
auto parentPlot = firstAncestorOrThisOfType<RimGridCrossPlot>();
|
auto parentPlot = firstAncestorOrThisOfType<RimGridCrossPlot>();
|
||||||
if ( parentPlot )
|
if ( parentPlot )
|
||||||
{
|
{
|
||||||
parentPlot->setYAxisInverted( true );
|
parentPlot->setYAxisInverted( true );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,6 +217,11 @@ void RimGridCrossPlotDataSet::setParentPlotNoReplot( RiuPlotWidget* parent )
|
|||||||
{
|
{
|
||||||
curve->setParentPlotNoReplot( m_isChecked() ? parent : nullptr );
|
curve->setParentPlotNoReplot( m_isChecked() ? parent : nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ( auto& curve : m_crossPlotRegressionCurves() )
|
||||||
|
{
|
||||||
|
curve->setParentPlotNoReplot( m_isChecked() ? parent : nullptr );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -246,7 +251,7 @@ QString RimGridCrossPlotDataSet::infoText() const
|
|||||||
|
|
||||||
QStringList textLines;
|
QStringList textLines;
|
||||||
textLines += QString( "<b>Case:</b> %1" ).arg( m_case()->caseUserDescription() );
|
textLines += QString( "<b>Case:</b> %1" ).arg( m_case()->caseUserDescription() );
|
||||||
textLines += QString( "<b>Parameters:</b>: %1 x %2" )
|
textLines += QString( "<b>Parameters:</b> %1 x %2" )
|
||||||
.arg( m_xAxisProperty->resultVariableUiShortName() )
|
.arg( m_xAxisProperty->resultVariableUiShortName() )
|
||||||
.arg( m_yAxisProperty->resultVariableUiShortName() );
|
.arg( m_yAxisProperty->resultVariableUiShortName() );
|
||||||
if ( m_timeStep != -1 )
|
if ( m_timeStep != -1 )
|
||||||
@ -359,6 +364,17 @@ void RimGridCrossPlotDataSet::detachAllCurves()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotDataSet::detachAllRegressionCurves()
|
||||||
|
{
|
||||||
|
for ( auto curve : m_crossPlotRegressionCurves() )
|
||||||
|
{
|
||||||
|
curve->detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -525,6 +541,20 @@ void RimGridCrossPlotDataSet::onLoadDataAndUpdate( bool updateParentPlot )
|
|||||||
fillCurveDataInExistingCurves( result );
|
fillCurveDataInExistingCurves( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( m_crossPlotRegressionCurves.size() != m_groupedResults.size() )
|
||||||
|
{
|
||||||
|
destroyRegressionCurves();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_crossPlotRegressionCurves.empty() )
|
||||||
|
{
|
||||||
|
createRegressionCurves( result );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fillCurveDataInExistingRegressionCurves( result );
|
||||||
|
}
|
||||||
|
|
||||||
updateLegendIcons();
|
updateLegendIcons();
|
||||||
|
|
||||||
if ( updateParentPlot )
|
if ( updateParentPlot )
|
||||||
@ -591,6 +621,44 @@ void RimGridCrossPlotDataSet::assignCurveDataGroups( const RigEclipseCrossPlotRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
cvf::Color3f RimGridCrossPlotDataSet::createCurveColor( bool useCustomColor, int colorIndex ) const
|
||||||
|
{
|
||||||
|
if ( useCustomColor )
|
||||||
|
{
|
||||||
|
return m_customColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors();
|
||||||
|
return colors.cycledColor3f( colorIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
cvf::Color3f RimGridCrossPlotDataSet::createCurveColor( const std::vector<double>& tickValues, int groupIndex ) const
|
||||||
|
{
|
||||||
|
if ( tickValues.empty() )
|
||||||
|
{
|
||||||
|
return cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( groupIndex ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( groupIndex < static_cast<int>( tickValues.size() ) )
|
||||||
|
{
|
||||||
|
return cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( tickValues[groupIndex] ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( groupIndex ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -599,16 +667,7 @@ void RimGridCrossPlotDataSet::createCurves( const RigEclipseCrossPlotResult& res
|
|||||||
if ( !groupingEnabled() )
|
if ( !groupingEnabled() )
|
||||||
{
|
{
|
||||||
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
||||||
if ( m_useCustomColor )
|
curve->setColor( createCurveColor( m_useCustomColor(), indexInPlot() ) );
|
||||||
{
|
|
||||||
curve->setColor( m_customColor() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors();
|
|
||||||
int colorIndex = indexInPlot();
|
|
||||||
curve->setColor( colors.cycledColor3f( colorIndex ) );
|
|
||||||
}
|
|
||||||
curve->setSymbolEdgeColor( curve->color() );
|
curve->setSymbolEdgeColor( curve->color() );
|
||||||
curve->setGroupingInformation( indexInPlot(), 0 );
|
curve->setGroupingInformation( indexInPlot(), 0 );
|
||||||
curve->setSamples( result.xValues, result.yValues );
|
curve->setSamples( result.xValues, result.yValues );
|
||||||
@ -628,25 +687,12 @@ void RimGridCrossPlotDataSet::createCurves( const RigEclipseCrossPlotResult& res
|
|||||||
// NB : Make sure iteration of curve and groups are syncronized with createCurves()
|
// NB : Make sure iteration of curve and groups are syncronized with createCurves()
|
||||||
for ( auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it )
|
for ( auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it )
|
||||||
{
|
{
|
||||||
|
auto [groupIndex, values] = *it;
|
||||||
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
||||||
curve->setGroupingInformation( indexInPlot(), it->first );
|
curve->setGroupingInformation( indexInPlot(), groupIndex );
|
||||||
if ( groupingByCategoryResult() )
|
curve->setColor( createCurveColor( tickValues, groupIndex ) );
|
||||||
{
|
|
||||||
curve->setColor( cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( it->first ) ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( it->first < static_cast<int>( tickValues.size() ) )
|
|
||||||
{
|
|
||||||
curve->setColor( cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( tickValues[it->first] ) ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
curve->setColor( cvf::Color3f( legendConfig()->scalarMapper()->mapToColor( it->first ) ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
curve->setSymbolEdgeColor( curve->color() );
|
curve->setSymbolEdgeColor( curve->color() );
|
||||||
curve->setSamples( it->second.xValues, it->second.yValues );
|
curve->setSamples( values.xValues, values.yValues );
|
||||||
curve->setShowInLegend( m_crossPlotCurves.empty() );
|
curve->setShowInLegend( m_crossPlotCurves.empty() );
|
||||||
curve->setLegendEntryText( createAutoName() );
|
curve->setLegendEntryText( createAutoName() );
|
||||||
curve->setCurveAutoAppearance();
|
curve->setCurveAutoAppearance();
|
||||||
@ -688,6 +734,88 @@ void RimGridCrossPlotDataSet::fillCurveDataInExistingCurves( const RigEclipseCro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotDataSet::createRegressionCurves( const RigEclipseCrossPlotResult& result )
|
||||||
|
{
|
||||||
|
auto symbolEdgeColor = RiaColorTools::fromQColorTo3f( RiuGuiTheme::getColorByVariableName( "auxilliaryCurveColor" ) );
|
||||||
|
|
||||||
|
if ( !groupingEnabled() )
|
||||||
|
{
|
||||||
|
RimGridCrossPlotRegressionCurve* curve = new RimGridCrossPlotRegressionCurve();
|
||||||
|
m_crossPlotRegressionCurves.push_back( curve );
|
||||||
|
curve->setColor( createCurveColor( m_useCustomColor(), indexInPlot() ) );
|
||||||
|
curve->setSymbolEdgeColor( symbolEdgeColor );
|
||||||
|
curve->setGroupingInformation( indexInPlot(), 0 );
|
||||||
|
curve->setRangeDefaults( result.xValues, result.yValues );
|
||||||
|
curve->setSamples( result.xValues, result.yValues );
|
||||||
|
curve->setCurveAutoAppearance();
|
||||||
|
curve->updateUiIconFromPlotSymbol();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<double> tickValues;
|
||||||
|
|
||||||
|
if ( !groupingByCategoryResult() )
|
||||||
|
{
|
||||||
|
legendConfig()->scalarMapper()->majorTickValues( &tickValues );
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB : Make sure iteration of curve and groups are syncronized with createCurves()
|
||||||
|
for ( auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it )
|
||||||
|
{
|
||||||
|
auto [groupIndex, values] = *it;
|
||||||
|
|
||||||
|
bool isFirst = m_crossPlotRegressionCurves.empty();
|
||||||
|
|
||||||
|
RimGridCrossPlotRegressionCurve* curve = new RimGridCrossPlotRegressionCurve();
|
||||||
|
m_crossPlotRegressionCurves.push_back( curve );
|
||||||
|
curve->setGroupingInformation( indexInPlot(), groupIndex );
|
||||||
|
curve->setColor( createCurveColor( tickValues, groupIndex ) );
|
||||||
|
curve->setSymbolEdgeColor( symbolEdgeColor );
|
||||||
|
curve->setRangeDefaults( values.xValues, values.yValues );
|
||||||
|
curve->setSamples( values.xValues, values.yValues );
|
||||||
|
curve->setShowInLegend( isFirst );
|
||||||
|
curve->setLegendEntryText( createAutoName() );
|
||||||
|
curve->setCurveAutoAppearance();
|
||||||
|
curve->updateUiIconFromPlotSymbol();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotDataSet::fillCurveDataInExistingRegressionCurves( const RigEclipseCrossPlotResult& result )
|
||||||
|
{
|
||||||
|
if ( !groupingEnabled() )
|
||||||
|
{
|
||||||
|
CVF_ASSERT( m_crossPlotRegressionCurves.size() == 1u );
|
||||||
|
RimGridCrossPlotRegressionCurve* curve = m_crossPlotRegressionCurves[0];
|
||||||
|
curve->setGroupingInformation( indexInPlot(), 0 );
|
||||||
|
curve->updateCurveVisibility();
|
||||||
|
curve->setSamples( result.xValues, result.yValues );
|
||||||
|
curve->updateCurveAppearance();
|
||||||
|
curve->updateUiIconFromPlotSymbol();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NB : Make sure iteration of curve and groups are syncronized with fillCurveDataInExistingCurves()
|
||||||
|
auto curveIt = m_crossPlotRegressionCurves.begin();
|
||||||
|
auto groupIt = m_groupedResults.rbegin();
|
||||||
|
for ( ; curveIt != m_crossPlotRegressionCurves.end() && groupIt != m_groupedResults.rend(); ++curveIt, ++groupIt )
|
||||||
|
{
|
||||||
|
RimGridCrossPlotRegressionCurve* curve = *curveIt;
|
||||||
|
curve->setGroupingInformation( indexInPlot(), groupIt->first );
|
||||||
|
curve->updateCurveVisibility();
|
||||||
|
curve->setSamples( groupIt->second.xValues, groupIt->second.yValues );
|
||||||
|
curve->updateCurveAppearance();
|
||||||
|
curve->updateUiIconFromPlotSymbol();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -697,6 +825,15 @@ void RimGridCrossPlotDataSet::destroyCurves()
|
|||||||
m_crossPlotCurves.deleteChildren();
|
m_crossPlotCurves.deleteChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotDataSet::destroyRegressionCurves()
|
||||||
|
{
|
||||||
|
detachAllRegressionCurves();
|
||||||
|
m_crossPlotRegressionCurves.deleteChildren();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -882,6 +1019,7 @@ void RimGridCrossPlotDataSet::fieldChangedByUi( const caf::PdmFieldHandle* chang
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyCurves();
|
destroyCurves();
|
||||||
|
destroyRegressionCurves();
|
||||||
loadDataAndUpdate( true );
|
loadDataAndUpdate( true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -893,6 +1031,7 @@ void RimGridCrossPlotDataSet::fieldChangedByUi( const caf::PdmFieldHandle* chang
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyCurves();
|
destroyCurves();
|
||||||
|
destroyRegressionCurves();
|
||||||
loadDataAndUpdate( true );
|
loadDataAndUpdate( true );
|
||||||
}
|
}
|
||||||
else if ( changedField == &m_grouping )
|
else if ( changedField == &m_grouping )
|
||||||
@ -914,6 +1053,7 @@ void RimGridCrossPlotDataSet::fieldChangedByUi( const caf::PdmFieldHandle* chang
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyCurves();
|
destroyCurves();
|
||||||
|
destroyRegressionCurves();
|
||||||
loadDataAndUpdate( true );
|
loadDataAndUpdate( true );
|
||||||
}
|
}
|
||||||
else if ( changedField == &m_cellFilterView )
|
else if ( changedField == &m_cellFilterView )
|
||||||
@ -936,12 +1076,17 @@ void RimGridCrossPlotDataSet::childFieldChangedByUi( const caf::PdmFieldHandle*
|
|||||||
{
|
{
|
||||||
if ( changedChildField == &m_yAxisProperty )
|
if ( changedChildField == &m_yAxisProperty )
|
||||||
{
|
{
|
||||||
if ( m_yAxisProperty->resultVariable() == "DEPTH" )
|
bool useInvertedYAxis = m_yAxisProperty->resultVariable() == "DEPTH";
|
||||||
{
|
auto plot = firstAncestorOrThisOfTypeAsserted<RimGridCrossPlot>();
|
||||||
auto plot = firstAncestorOrThisOfTypeAsserted<RimGridCrossPlot>();
|
plot->setYAxisInverted( useInvertedYAxis );
|
||||||
plot->setYAxisInverted( true );
|
triggerPlotNameUpdateAndReplot();
|
||||||
triggerPlotNameUpdateAndReplot();
|
}
|
||||||
}
|
|
||||||
|
if ( changedChildField == &m_xAxisProperty || changedChildField == &m_yAxisProperty )
|
||||||
|
{
|
||||||
|
destroyCurves();
|
||||||
|
destroyRegressionCurves();
|
||||||
|
loadDataAndUpdate( true );
|
||||||
}
|
}
|
||||||
else if ( changedChildField == &m_crossPlotCurves )
|
else if ( changedChildField == &m_crossPlotCurves )
|
||||||
{
|
{
|
||||||
@ -1125,6 +1270,12 @@ void RimGridCrossPlotDataSet::swapAxisProperties( bool updatePlot )
|
|||||||
m_xAxisProperty = yAxisProperties;
|
m_xAxisProperty = yAxisProperties;
|
||||||
|
|
||||||
updateConnectedEditors();
|
updateConnectedEditors();
|
||||||
|
|
||||||
|
for ( auto curve : m_crossPlotRegressionCurves )
|
||||||
|
{
|
||||||
|
curve->swapAxis();
|
||||||
|
}
|
||||||
|
|
||||||
loadDataAndUpdate( updatePlot );
|
loadDataAndUpdate( updatePlot );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1288,6 +1439,32 @@ void RimGridCrossPlotDataSet::updateCurveNames( size_t dataSetIndex, size_t data
|
|||||||
}
|
}
|
||||||
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
|
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < m_crossPlotRegressionCurves.size(); ++i )
|
||||||
|
{
|
||||||
|
QString dataSetName = createAutoName();
|
||||||
|
if ( dataSetName.isEmpty() )
|
||||||
|
{
|
||||||
|
if ( dataSetCount > 1u )
|
||||||
|
dataSetName = QString( "DataSet #%1" ).arg( dataSetIndex + 1 );
|
||||||
|
else
|
||||||
|
dataSetName = "Data Set";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto curve = m_crossPlotRegressionCurves[i];
|
||||||
|
if ( groupingEnabled() )
|
||||||
|
{
|
||||||
|
QString curveGroupName = createGroupName( curve->groupIndex() );
|
||||||
|
curve->setCustomName( curveGroupName + " " + curve->getRegressionTypeString() );
|
||||||
|
curve->setLegendEntryText( dataSetName );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curve->setCustomName( dataSetName + " " + curve->getRegressionTypeString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -1313,29 +1490,26 @@ void RimGridCrossPlotDataSet::performAutoNameUpdate()
|
|||||||
void RimGridCrossPlotDataSet::setDefaults()
|
void RimGridCrossPlotDataSet::setDefaults()
|
||||||
{
|
{
|
||||||
RimProject* project = RimProject::current();
|
RimProject* project = RimProject::current();
|
||||||
if ( project )
|
if ( project && !project->eclipseCases().empty() )
|
||||||
{
|
{
|
||||||
if ( !project->eclipseCases().empty() )
|
RimEclipseCase* eclipseCase = project->eclipseCases().front();
|
||||||
|
m_case = eclipseCase;
|
||||||
|
m_xAxisProperty->setEclipseCase( eclipseCase );
|
||||||
|
m_yAxisProperty->setEclipseCase( eclipseCase );
|
||||||
|
m_groupingProperty->setEclipseCase( eclipseCase );
|
||||||
|
|
||||||
|
m_xAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
||||||
|
m_xAxisProperty->setResultVariable( "PORO" );
|
||||||
|
|
||||||
|
m_yAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
||||||
|
m_yAxisProperty->setResultVariable( "PERMX" );
|
||||||
|
|
||||||
|
m_grouping = NO_GROUPING;
|
||||||
|
if ( eclipseCase->activeFormationNames() )
|
||||||
{
|
{
|
||||||
RimEclipseCase* eclipseCase = project->eclipseCases().front();
|
m_grouping = GROUP_BY_FORMATION;
|
||||||
m_case = eclipseCase;
|
m_groupingProperty->legendConfig()->setColorLegend(
|
||||||
m_xAxisProperty->setEclipseCase( eclipseCase );
|
RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::CATEGORY ) );
|
||||||
m_yAxisProperty->setEclipseCase( eclipseCase );
|
|
||||||
m_groupingProperty->setEclipseCase( eclipseCase );
|
|
||||||
|
|
||||||
m_xAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
|
||||||
m_xAxisProperty->setResultVariable( "PORO" );
|
|
||||||
|
|
||||||
m_yAxisProperty->setResultType( RiaDefines::ResultCatType::STATIC_NATIVE );
|
|
||||||
m_yAxisProperty->setResultVariable( "PERMX" );
|
|
||||||
|
|
||||||
m_grouping = NO_GROUPING;
|
|
||||||
if ( eclipseCase->activeFormationNames() )
|
|
||||||
{
|
|
||||||
m_grouping = GROUP_BY_FORMATION;
|
|
||||||
m_groupingProperty->legendConfig()->setColorLegend(
|
|
||||||
RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::CATEGORY ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1362,6 +1536,8 @@ void RimGridCrossPlotDataSet::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTr
|
|||||||
uiTreeOrdering.add( curve );
|
uiTreeOrdering.add( curve );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uiTreeOrdering.add( &m_crossPlotRegressionCurves );
|
||||||
|
|
||||||
uiTreeOrdering.add( &m_plotCellFilterCollection );
|
uiTreeOrdering.add( &m_plotCellFilterCollection );
|
||||||
|
|
||||||
uiTreeOrdering.skipRemainingChildren( true );
|
uiTreeOrdering.skipRemainingChildren( true );
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
class RifTextDataTableFormatter;
|
class RifTextDataTableFormatter;
|
||||||
class RimCase;
|
class RimCase;
|
||||||
class RimGridCrossPlotCurve;
|
class RimGridCrossPlotCurve;
|
||||||
|
class RimGridCrossPlotRegressionCurve;
|
||||||
class RimGridView;
|
class RimGridView;
|
||||||
class RimEclipseCase;
|
class RimEclipseCase;
|
||||||
class RimEclipseResultCase;
|
class RimEclipseResultCase;
|
||||||
@ -110,6 +111,7 @@ public:
|
|||||||
QString groupTitle() const;
|
QString groupTitle() const;
|
||||||
QString groupParameter() const;
|
QString groupParameter() const;
|
||||||
void detachAllCurves();
|
void detachAllCurves();
|
||||||
|
void detachAllRegressionCurves();
|
||||||
void cellFilterViewUpdated();
|
void cellFilterViewUpdated();
|
||||||
|
|
||||||
RimRegularLegendConfig* legendConfig() const;
|
RimRegularLegendConfig* legendConfig() const;
|
||||||
@ -138,6 +140,8 @@ public:
|
|||||||
void setCustomColor( const cvf::Color3f color );
|
void setCustomColor( const cvf::Color3f color );
|
||||||
void destroyCurves();
|
void destroyCurves();
|
||||||
|
|
||||||
|
void destroyRegressionCurves();
|
||||||
|
|
||||||
size_t visibleCurveCount() const;
|
size_t visibleCurveCount() const;
|
||||||
size_t sampleCount() const;
|
size_t sampleCount() const;
|
||||||
|
|
||||||
@ -149,6 +153,8 @@ protected:
|
|||||||
void createCurves( const RigEclipseCrossPlotResult& result );
|
void createCurves( const RigEclipseCrossPlotResult& result );
|
||||||
void fillCurveDataInExistingCurves( const RigEclipseCrossPlotResult& result );
|
void fillCurveDataInExistingCurves( const RigEclipseCrossPlotResult& result );
|
||||||
QString createGroupName( size_t curveIndex ) const;
|
QString createGroupName( size_t curveIndex ) const;
|
||||||
|
void createRegressionCurves( const RigEclipseCrossPlotResult& result );
|
||||||
|
void fillCurveDataInExistingRegressionCurves( const RigEclipseCrossPlotResult& result );
|
||||||
|
|
||||||
std::map<int, cvf::UByteArray> calculateCellVisibility( RimEclipseCase* eclipseCase ) const;
|
std::map<int, cvf::UByteArray> calculateCellVisibility( RimEclipseCase* eclipseCase ) const;
|
||||||
|
|
||||||
@ -168,6 +174,9 @@ protected:
|
|||||||
bool hasMultipleTimeSteps() const;
|
bool hasMultipleTimeSteps() const;
|
||||||
void filterInvalidCurveValues( RigEclipseCrossPlotResult* result );
|
void filterInvalidCurveValues( RigEclipseCrossPlotResult* result );
|
||||||
|
|
||||||
|
cvf::Color3f createCurveColor( bool useCustomColor, int colorIndex ) const;
|
||||||
|
cvf::Color3f createCurveColor( const std::vector<double>& tickValues, int groupIndex ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
caf::PdmPtrField<RimCase*> m_case;
|
caf::PdmPtrField<RimCase*> m_case;
|
||||||
caf::PdmField<int> m_timeStep;
|
caf::PdmField<int> m_timeStep;
|
||||||
@ -179,7 +188,8 @@ private:
|
|||||||
|
|
||||||
caf::PdmChildField<RimGridCrossPlotDataSetNameConfig*> m_nameConfig;
|
caf::PdmChildField<RimGridCrossPlotDataSetNameConfig*> m_nameConfig;
|
||||||
|
|
||||||
caf::PdmChildArrayField<RimGridCrossPlotCurve*> m_crossPlotCurves;
|
caf::PdmChildArrayField<RimGridCrossPlotCurve*> m_crossPlotCurves;
|
||||||
|
caf::PdmChildArrayField<RimGridCrossPlotRegressionCurve*> m_crossPlotRegressionCurves;
|
||||||
|
|
||||||
std::map<int, RigEclipseCrossPlotResult> m_groupedResults;
|
std::map<int, RigEclipseCrossPlotResult> m_groupedResults;
|
||||||
|
|
||||||
|
@ -0,0 +1,546 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RimGridCrossPlotRegressionCurve.h"
|
||||||
|
|
||||||
|
#include "RiaNumericalTools.h"
|
||||||
|
#include "RiaRegressionTextTools.h"
|
||||||
|
|
||||||
|
#include "RimGridCrossPlot.h"
|
||||||
|
#include "RimGridCrossPlotDataSet.h"
|
||||||
|
#include "RimPlotRectAnnotation.h"
|
||||||
|
|
||||||
|
#include "RimPlotRectAnnotation.h"
|
||||||
|
#include "RiuPlotCurve.h"
|
||||||
|
#include "RiuPlotWidget.h"
|
||||||
|
|
||||||
|
#include "ExponentialRegression.hpp"
|
||||||
|
#include "LinearRegression.hpp"
|
||||||
|
#include "LogarithmicRegression.hpp"
|
||||||
|
#include "PolynomialRegression.hpp"
|
||||||
|
#include "PowerFitRegression.hpp"
|
||||||
|
|
||||||
|
#include "cafPdmUiDoubleSliderEditor.h"
|
||||||
|
#include "cafPdmUiDoubleValueEditor.h"
|
||||||
|
#include "cafPdmUiLineEditor.h"
|
||||||
|
#include "cafPdmUiTextEditor.h"
|
||||||
|
|
||||||
|
#include "cvfMath.h"
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimGridCrossPlotRegressionCurve, "GridCrossPlotRegressionCurve" );
|
||||||
|
|
||||||
|
namespace caf
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
void caf::AppEnum<RimGridCrossPlotRegressionCurve::RegressionType>::setUp()
|
||||||
|
{
|
||||||
|
addItem( RimGridCrossPlotRegressionCurve::RegressionType::LINEAR, "LINEAR", "Linear" );
|
||||||
|
addItem( RimGridCrossPlotRegressionCurve::RegressionType::POLYNOMIAL, "POLYNOMIAL", "Polynomial" );
|
||||||
|
addItem( RimGridCrossPlotRegressionCurve::RegressionType::POWER_FIT, "POWER_FIT", "Power Fit" );
|
||||||
|
addItem( RimGridCrossPlotRegressionCurve::RegressionType::EXPONENTIAL, "EXPONENTIAL", "Exponential" );
|
||||||
|
addItem( RimGridCrossPlotRegressionCurve::RegressionType::LOGARITHMIC, "LOGARITHMIC", "Logarithmic" );
|
||||||
|
setDefault( RimGridCrossPlotRegressionCurve::RegressionType::LINEAR );
|
||||||
|
}
|
||||||
|
}; // namespace caf
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimGridCrossPlotRegressionCurve::RimGridCrossPlotRegressionCurve()
|
||||||
|
: m_dataSetIndex( 0 )
|
||||||
|
, m_groupIndex( 0 )
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Cross Plot Regression Curve", ":/WellLogCurve16x16.png" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_regressionType, "RegressionType", "Type" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_minExtrapolationRangeX, "MinExtrapolationRangeX", "Min" );
|
||||||
|
m_minExtrapolationRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_maxExtrapolationRangeX, "MaxExtrapolationRangeX", "Max" );
|
||||||
|
m_maxExtrapolationRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_polynomialDegree, "PolynomialDegree", 3, "Degree" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_minRangeX, "MinRangeX", "Min X" );
|
||||||
|
m_minRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_maxRangeX, "MaxRangeX", "Max X" );
|
||||||
|
m_maxRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_minRangeY, "MinRangeY", "Min Y" );
|
||||||
|
m_minRangeY.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_maxRangeY, "MaxRangeY", "Max Y" );
|
||||||
|
m_maxRangeY.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_showDataSelectionInPlot, "ShowDataSelectionInPlot", false, "Show In Plot" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_expressionText, "ExpressionText", "Expression" );
|
||||||
|
m_expressionText.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
|
||||||
|
m_expressionText.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
||||||
|
m_expressionText.uiCapability()->setUiReadOnly( true );
|
||||||
|
m_expressionText.xmlCapability()->disableIO();
|
||||||
|
|
||||||
|
setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
|
||||||
|
setSymbol( RiuPlotCurveSymbol::SYMBOL_RECT );
|
||||||
|
setSymbolSize( 6 );
|
||||||
|
setZOrder( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_REGRESSION_CURVE ) );
|
||||||
|
|
||||||
|
m_dataRangeX = { cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE };
|
||||||
|
m_dataRangeY = { cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE };
|
||||||
|
|
||||||
|
auto rectAnnotation = new RimPlotRectAnnotation;
|
||||||
|
rectAnnotation->setName( "Data Selection" );
|
||||||
|
m_rectAnnotations.push_back( rectAnnotation );
|
||||||
|
m_rectAnnotations.uiCapability()->setUiTreeHidden( true );
|
||||||
|
m_rectAnnotations.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
|
||||||
|
setCheckState( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::setGroupingInformation( int dataSetIndex, int groupIndex )
|
||||||
|
{
|
||||||
|
m_dataSetIndex = dataSetIndex;
|
||||||
|
m_groupIndex = groupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::setSamples( const std::vector<double>& xValues, const std::vector<double>& yValues )
|
||||||
|
{
|
||||||
|
CVF_ASSERT( xValues.size() == yValues.size() );
|
||||||
|
|
||||||
|
if ( xValues.empty() || yValues.empty() || !m_plotCurve ) return;
|
||||||
|
|
||||||
|
auto [minX, maxX] = minmax_element( xValues.begin(), xValues.end() );
|
||||||
|
auto [minY, maxY] = minmax_element( yValues.begin(), yValues.end() );
|
||||||
|
|
||||||
|
m_dataRangeX = { *minX, *maxX };
|
||||||
|
m_dataRangeY = { *minY, *maxY };
|
||||||
|
|
||||||
|
auto filterValues = []( const std::vector<double>& x, const std::vector<double>& y, double minX, double maxX, double minY, double maxY )
|
||||||
|
{
|
||||||
|
std::vector<double> filteredX;
|
||||||
|
std::vector<double> filteredY;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < x.size(); i++ )
|
||||||
|
{
|
||||||
|
if ( x[i] >= minX && x[i] <= maxX && y[i] >= minY && y[i] <= maxY )
|
||||||
|
{
|
||||||
|
filteredX.push_back( x[i] );
|
||||||
|
filteredY.push_back( y[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair( filteredX, filteredY );
|
||||||
|
};
|
||||||
|
|
||||||
|
auto [filteredX, filteredY] = filterValues( xValues, yValues, m_minRangeX, m_maxRangeX, m_minRangeY, m_maxRangeY );
|
||||||
|
if ( filteredX.empty() || filteredX.size() != filteredY.size() ) return;
|
||||||
|
|
||||||
|
auto subsampleValues = []( double min, double max, int numSamples )
|
||||||
|
{
|
||||||
|
double step = ( max - min ) / numSamples;
|
||||||
|
|
||||||
|
std::vector<double> subSampledRange( numSamples );
|
||||||
|
for ( int i = 0; i < numSamples; i++ )
|
||||||
|
subSampledRange[i] = min + step * i;
|
||||||
|
subSampledRange.push_back( max );
|
||||||
|
|
||||||
|
return subSampledRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<double> subsampledXValues = subsampleValues( m_minExtrapolationRangeX, m_maxExtrapolationRangeX, 50 );
|
||||||
|
|
||||||
|
auto [outputXValues, outputYValues, regressionText] = calculateRegression( m_regressionType(), filteredX, filteredY, subsampledXValues );
|
||||||
|
|
||||||
|
m_expressionText = regressionText;
|
||||||
|
|
||||||
|
bool useLogarithmicScale = false;
|
||||||
|
m_plotCurve->setSamplesFromXValuesAndYValues( outputXValues, outputYValues, useLogarithmicScale );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::setRangeDefaults( const std::vector<double>& xValues, const std::vector<double>& yValues )
|
||||||
|
{
|
||||||
|
CVF_ASSERT( xValues.size() == yValues.size() );
|
||||||
|
|
||||||
|
if ( xValues.empty() || yValues.empty() ) return;
|
||||||
|
|
||||||
|
auto [minX, maxX] = minmax_element( xValues.begin(), xValues.end() );
|
||||||
|
auto [minY, maxY] = minmax_element( yValues.begin(), yValues.end() );
|
||||||
|
|
||||||
|
m_minRangeX = *minX;
|
||||||
|
m_maxRangeX = *maxX;
|
||||||
|
|
||||||
|
m_minRangeY = *minY;
|
||||||
|
m_maxRangeY = *maxY;
|
||||||
|
|
||||||
|
m_maxExtrapolationRangeX = *maxX;
|
||||||
|
m_minExtrapolationRangeX = *minX;
|
||||||
|
|
||||||
|
m_dataRangeX = { *minX, *maxX };
|
||||||
|
m_dataRangeY = { *minY, *maxY };
|
||||||
|
|
||||||
|
updateRectAnnotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::swapAxis()
|
||||||
|
{
|
||||||
|
std::swap( m_minRangeX, m_minRangeY );
|
||||||
|
std::swap( m_maxRangeX, m_maxRangeY );
|
||||||
|
|
||||||
|
m_maxExtrapolationRangeX = m_maxRangeX;
|
||||||
|
m_minExtrapolationRangeX = m_minRangeX;
|
||||||
|
|
||||||
|
std::swap( m_dataRangeX, m_dataRangeY );
|
||||||
|
|
||||||
|
updateRectAnnotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::setCurveAutoAppearance()
|
||||||
|
{
|
||||||
|
updateCurveAppearance();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
int RimGridCrossPlotRegressionCurve::groupIndex() const
|
||||||
|
{
|
||||||
|
return m_groupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
size_t RimGridCrossPlotRegressionCurve::sampleCount() const
|
||||||
|
{
|
||||||
|
return m_plotCurve ? m_plotCurve->numSamples() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::determineLegendIcon()
|
||||||
|
{
|
||||||
|
if ( !m_plotCurve ) return;
|
||||||
|
|
||||||
|
auto plot = firstAncestorOrThisOfTypeAsserted<RimGridCrossPlot>();
|
||||||
|
int fontSize = plot->legendFontSize();
|
||||||
|
m_plotCurve->setLegendIconSize( QSize( fontSize, fontSize ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::setBlackAndWhiteLegendIcons( bool blackAndWhite )
|
||||||
|
{
|
||||||
|
if ( m_plotCurve )
|
||||||
|
{
|
||||||
|
m_plotCurve->setBlackAndWhiteLegendIcon( blackAndWhite );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::updateZoomInParentPlot()
|
||||||
|
{
|
||||||
|
auto plot = firstAncestorOrThisOfTypeAsserted<RimGridCrossPlot>();
|
||||||
|
plot->calculateZoomRangeAndUpdateQwt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimGridCrossPlotRegressionCurve::createCurveAutoName()
|
||||||
|
{
|
||||||
|
return m_curveName;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimGridCrossPlotRegressionCurve::getRegressionTypeString() const
|
||||||
|
{
|
||||||
|
return m_regressionType().uiText() + " Regression";
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::onLoadDataAndUpdate( bool updateParentPlot )
|
||||||
|
{
|
||||||
|
if ( updateParentPlot )
|
||||||
|
{
|
||||||
|
m_parentPlot->replot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
caf::PdmUiGroup* regressionCurveGroup = uiOrdering.addNewGroup( "Regression Analysis" );
|
||||||
|
regressionCurveGroup->add( &m_regressionType );
|
||||||
|
|
||||||
|
if ( m_regressionType == RegressionType::POLYNOMIAL )
|
||||||
|
{
|
||||||
|
regressionCurveGroup->add( &m_polynomialDegree );
|
||||||
|
}
|
||||||
|
|
||||||
|
regressionCurveGroup->add( &m_expressionText );
|
||||||
|
|
||||||
|
caf::PdmUiGroup* dataSelectionGroup = uiOrdering.addNewGroup( "Data Selection" );
|
||||||
|
dataSelectionGroup->add( &m_minRangeX );
|
||||||
|
dataSelectionGroup->add( &m_maxRangeX );
|
||||||
|
dataSelectionGroup->add( &m_minRangeY );
|
||||||
|
dataSelectionGroup->add( &m_maxRangeY );
|
||||||
|
dataSelectionGroup->add( &m_showDataSelectionInPlot );
|
||||||
|
|
||||||
|
caf::PdmUiGroup* forecastingGroup = uiOrdering.addNewGroup( "Extrapolation" );
|
||||||
|
forecastingGroup->add( &m_minExtrapolationRangeX );
|
||||||
|
forecastingGroup->add( &m_maxExtrapolationRangeX );
|
||||||
|
|
||||||
|
caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup( "Appearance" );
|
||||||
|
RimPlotCurve::appearanceUiOrdering( *appearanceGroup );
|
||||||
|
|
||||||
|
uiOrdering.skipRemainingFields( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
||||||
|
{
|
||||||
|
// Implement an empty method to avoid the base class implementation in RimPlotCurve
|
||||||
|
// The color tag is not used for Grid Cross Plot Curves
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||||
|
QString uiConfigName,
|
||||||
|
caf::PdmUiEditorAttribute* attribute )
|
||||||
|
{
|
||||||
|
if ( field == &m_polynomialDegree )
|
||||||
|
{
|
||||||
|
if ( auto* lineEditorAttr = dynamic_cast<caf::PdmUiLineEditorAttribute*>( attribute ) )
|
||||||
|
{
|
||||||
|
// Polynomial degree should be a positive number.
|
||||||
|
lineEditorAttr->validator = new QIntValidator( 1, 50, nullptr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( field == &m_minRangeX || field == &m_maxRangeX )
|
||||||
|
{
|
||||||
|
if ( auto* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
|
||||||
|
{
|
||||||
|
auto [min, max] = m_dataRangeX;
|
||||||
|
myAttr->m_minimum = RiaNumericalTools::roundToNumSignificantDigits( min, 2 );
|
||||||
|
myAttr->m_maximum = RiaNumericalTools::roundToNumSignificantDigits( max, 2 );
|
||||||
|
myAttr->m_decimals = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( field == &m_minRangeY || field == &m_maxRangeY )
|
||||||
|
{
|
||||||
|
if ( auto* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
|
||||||
|
{
|
||||||
|
auto [min, max] = m_dataRangeY;
|
||||||
|
myAttr->m_minimum = RiaNumericalTools::roundToNumSignificantDigits( min, 2 );
|
||||||
|
myAttr->m_maximum = RiaNumericalTools::roundToNumSignificantDigits( max, 2 );
|
||||||
|
myAttr->m_decimals = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( field == &m_minExtrapolationRangeX || field == &m_maxExtrapolationRangeX )
|
||||||
|
{
|
||||||
|
auto doubleAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
|
||||||
|
if ( doubleAttr )
|
||||||
|
{
|
||||||
|
doubleAttr->m_decimals = 2;
|
||||||
|
doubleAttr->m_numberFormat = caf::PdmUiDoubleValueEditorAttribute::NumberFormat::FIXED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( field == &m_expressionText )
|
||||||
|
{
|
||||||
|
auto myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute );
|
||||||
|
if ( myAttr )
|
||||||
|
{
|
||||||
|
myAttr->wrapMode = caf::PdmUiTextEditorAttribute::NoWrap;
|
||||||
|
myAttr->textMode = caf::PdmUiTextEditorAttribute::HTML;
|
||||||
|
|
||||||
|
QFont font;
|
||||||
|
auto pointSize = font.pointSize();
|
||||||
|
font.setPointSize( pointSize + 2 );
|
||||||
|
myAttr->font = font;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||||
|
{
|
||||||
|
if ( &m_showCurve == changedField )
|
||||||
|
{
|
||||||
|
// RimPlotCurve::fieldChangedByUi always replot, and this is usually unnecessary except for visibility changes
|
||||||
|
RimPlotCurve::fieldChangedByUi( changedField, oldValue, newValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto enforceRange = []( const caf::PdmFieldHandle* changedField, caf::PdmField<double>& minRange, caf::PdmField<double>& maxRange )
|
||||||
|
{
|
||||||
|
if ( &minRange == changedField && minRange > maxRange ) maxRange = minRange;
|
||||||
|
if ( &maxRange == changedField && maxRange < minRange ) minRange = maxRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
enforceRange( changedField, m_minRangeX, m_maxRangeX );
|
||||||
|
enforceRange( changedField, m_minRangeY, m_maxRangeY );
|
||||||
|
|
||||||
|
if ( &m_minRangeX == changedField || &m_maxRangeX == changedField || &m_minRangeY == changedField || &m_maxRangeY == changedField ||
|
||||||
|
&m_showDataSelectionInPlot == changedField )
|
||||||
|
{
|
||||||
|
updateRectAnnotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( &m_minRangeX == changedField || &m_maxRangeX == changedField || &m_minRangeY == changedField || &m_maxRangeY == changedField ||
|
||||||
|
&m_minExtrapolationRangeX == changedField || &m_maxExtrapolationRangeX == changedField || &m_regressionType == changedField ||
|
||||||
|
&m_polynomialDegree == changedField || &m_showDataSelectionInPlot == changedField )
|
||||||
|
{
|
||||||
|
auto dataSet = firstAncestorOrThisOfTypeAsserted<RimGridCrossPlotDataSet>();
|
||||||
|
dataSet->loadDataAndUpdate( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::tuple<std::vector<double>, std::vector<double>, QString>
|
||||||
|
RimGridCrossPlotRegressionCurve::calculateRegression( RimGridCrossPlotRegressionCurve::RegressionType regressionType,
|
||||||
|
const std::vector<double>& xValues,
|
||||||
|
const std::vector<double>& yValues,
|
||||||
|
const std::vector<double>& outputXValues ) const
|
||||||
|
{
|
||||||
|
if ( regressionType == RegressionType::LINEAR )
|
||||||
|
{
|
||||||
|
regression::LinearRegression linearRegression;
|
||||||
|
linearRegression.fit( xValues, yValues );
|
||||||
|
std::vector<double> predictedValues = linearRegression.predict( outputXValues );
|
||||||
|
return { outputXValues, predictedValues, RiaRegressionTextTools::generateRegressionText( linearRegression ) };
|
||||||
|
}
|
||||||
|
else if ( m_regressionType == RegressionType::POLYNOMIAL )
|
||||||
|
{
|
||||||
|
regression::PolynomialRegression polynomialRegression;
|
||||||
|
polynomialRegression.fit( xValues, yValues, m_polynomialDegree );
|
||||||
|
std::vector<double> predictedValues = polynomialRegression.predict( outputXValues );
|
||||||
|
return { outputXValues, predictedValues, RiaRegressionTextTools::generateRegressionText( polynomialRegression ) };
|
||||||
|
}
|
||||||
|
else if ( m_regressionType == RegressionType::POWER_FIT )
|
||||||
|
{
|
||||||
|
auto [filteredTimeSteps, filteredValues] = getPositiveValues( xValues, yValues );
|
||||||
|
if ( filteredTimeSteps.empty() || filteredValues.empty() ) return {};
|
||||||
|
|
||||||
|
regression::PowerFitRegression powerFitRegression;
|
||||||
|
powerFitRegression.fit( filteredTimeSteps, filteredValues );
|
||||||
|
std::vector<double> predictedValues = powerFitRegression.predict( outputXValues );
|
||||||
|
return { outputXValues, predictedValues, RiaRegressionTextTools::generateRegressionText( powerFitRegression ) };
|
||||||
|
}
|
||||||
|
else if ( m_regressionType == RegressionType::EXPONENTIAL )
|
||||||
|
{
|
||||||
|
auto [filteredTimeSteps, filteredValues] = getPositiveValues( xValues, yValues );
|
||||||
|
if ( filteredTimeSteps.empty() || filteredValues.empty() ) return {};
|
||||||
|
|
||||||
|
regression::ExponentialRegression exponentialRegression;
|
||||||
|
exponentialRegression.fit( filteredTimeSteps, filteredValues );
|
||||||
|
std::vector<double> predictedValues = exponentialRegression.predict( outputXValues );
|
||||||
|
return { outputXValues, predictedValues, RiaRegressionTextTools::generateRegressionText( exponentialRegression ) };
|
||||||
|
}
|
||||||
|
else if ( m_regressionType == RegressionType::LOGARITHMIC )
|
||||||
|
{
|
||||||
|
auto [filteredTimeSteps, filteredValues] = getPositiveValues( xValues, yValues );
|
||||||
|
if ( filteredTimeSteps.empty() || filteredValues.empty() ) return {};
|
||||||
|
|
||||||
|
regression::LogarithmicRegression logarithmicRegression;
|
||||||
|
logarithmicRegression.fit( filteredTimeSteps, filteredValues );
|
||||||
|
std::vector<double> predictedValues = logarithmicRegression.predict( outputXValues );
|
||||||
|
return { outputXValues, predictedValues, RiaRegressionTextTools::generateRegressionText( logarithmicRegression ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { {}, {}, "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::pair<std::vector<double>, std::vector<double>> RimGridCrossPlotRegressionCurve::getPositiveValues( const std::vector<double>& xValues,
|
||||||
|
const std::vector<double>& yValues )
|
||||||
|
{
|
||||||
|
std::vector<double> filteredXValues;
|
||||||
|
std::vector<double> filteredYValues;
|
||||||
|
for ( size_t i = 0; i < xValues.size(); i++ )
|
||||||
|
{
|
||||||
|
if ( xValues[i] > 0.0 && yValues[i] > 0.0 )
|
||||||
|
{
|
||||||
|
filteredXValues.push_back( xValues[i] );
|
||||||
|
filteredYValues.push_back( yValues[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair( filteredXValues, filteredYValues );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimGridCrossPlotRegressionCurve::updateRectAnnotation()
|
||||||
|
{
|
||||||
|
if ( !m_rectAnnotations.empty() )
|
||||||
|
{
|
||||||
|
RimPlotRectAnnotation* annotation = m_rectAnnotations[0];
|
||||||
|
annotation->setRangeX( m_minRangeX, m_maxRangeX );
|
||||||
|
annotation->setRangeY( m_minRangeY, m_maxRangeY );
|
||||||
|
annotation->setColor( m_curveAppearance->color() );
|
||||||
|
annotation->setCheckState( m_showDataSelectionInPlot() );
|
||||||
|
|
||||||
|
auto dataSet = firstAncestorOrThisOfType<RimGridCrossPlotDataSet>();
|
||||||
|
if ( dataSet )
|
||||||
|
{
|
||||||
|
QString textLines;
|
||||||
|
textLines += QString( "<b>Case:</b> %1<br>" ).arg( dataSet->caseNameString() );
|
||||||
|
textLines += QString( "<b>%1:</b> %2 - %3<br>" ).arg( dataSet->xAxisName() ).arg( m_minRangeX ).arg( m_maxRangeX );
|
||||||
|
textLines += QString( "<b>%1:</b> %2 - %3<br>" ).arg( dataSet->yAxisName() ).arg( m_minRangeY ).arg( m_maxRangeY );
|
||||||
|
annotation->setText( textLines );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RimPlotCurve.h"
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class RimGridCrossPlotRegressionCurve : public RimPlotCurve
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class RegressionType
|
||||||
|
{
|
||||||
|
LINEAR,
|
||||||
|
POLYNOMIAL,
|
||||||
|
POWER_FIT,
|
||||||
|
EXPONENTIAL,
|
||||||
|
LOGARITHMIC,
|
||||||
|
LOGISTIC
|
||||||
|
};
|
||||||
|
|
||||||
|
RimGridCrossPlotRegressionCurve();
|
||||||
|
~RimGridCrossPlotRegressionCurve() override = default;
|
||||||
|
void setGroupingInformation( int dataSetIndex, int groupIndex );
|
||||||
|
void setSamples( const std::vector<double>& xValues, const std::vector<double>& yValues );
|
||||||
|
void setRangeDefaults( const std::vector<double>& xValues, const std::vector<double>& yValues );
|
||||||
|
|
||||||
|
void setCurveAutoAppearance();
|
||||||
|
int groupIndex() const;
|
||||||
|
size_t sampleCount() const;
|
||||||
|
void determineLegendIcon();
|
||||||
|
void setBlackAndWhiteLegendIcons( bool blackAndWhite );
|
||||||
|
|
||||||
|
QString getRegressionTypeString() const;
|
||||||
|
|
||||||
|
void swapAxis();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateZoomInParentPlot() override;
|
||||||
|
QString createCurveAutoName() override;
|
||||||
|
void onLoadDataAndUpdate( bool updateParentPlot ) override;
|
||||||
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
|
void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||||
|
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||||
|
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||||
|
void updateRectAnnotation();
|
||||||
|
|
||||||
|
std::tuple<std::vector<double>, std::vector<double>, QString>
|
||||||
|
calculateRegression( RimGridCrossPlotRegressionCurve::RegressionType regressionType,
|
||||||
|
const std::vector<double>& xValues,
|
||||||
|
const std::vector<double>& yValues,
|
||||||
|
const std::vector<double>& outputXValues ) const;
|
||||||
|
|
||||||
|
static std::pair<std::vector<double>, std::vector<double>> getPositiveValues( const std::vector<double>& xValues,
|
||||||
|
const std::vector<double>& yValues );
|
||||||
|
|
||||||
|
private:
|
||||||
|
caf::PdmField<caf::AppEnum<RegressionType>> m_regressionType;
|
||||||
|
caf::PdmField<double> m_minRangeX;
|
||||||
|
caf::PdmField<double> m_maxRangeX;
|
||||||
|
caf::PdmField<double> m_minRangeY;
|
||||||
|
caf::PdmField<double> m_maxRangeY;
|
||||||
|
caf::PdmField<bool> m_showDataSelectionInPlot;
|
||||||
|
caf::PdmField<int> m_polynomialDegree;
|
||||||
|
caf::PdmField<QString> m_expressionText;
|
||||||
|
caf::PdmField<double> m_minExtrapolationRangeX;
|
||||||
|
caf::PdmField<double> m_maxExtrapolationRangeX;
|
||||||
|
|
||||||
|
std::pair<double, double> m_dataRangeX;
|
||||||
|
std::pair<double, double> m_dataRangeY;
|
||||||
|
|
||||||
|
int m_dataSetIndex;
|
||||||
|
int m_groupIndex;
|
||||||
|
};
|
@ -26,6 +26,7 @@
|
|||||||
#include "RimEnsembleCurveSet.h"
|
#include "RimEnsembleCurveSet.h"
|
||||||
#include "RimEnsembleCurveSetCollection.h"
|
#include "RimEnsembleCurveSetCollection.h"
|
||||||
#include "RimNameConfig.h"
|
#include "RimNameConfig.h"
|
||||||
|
#include "RimPlotRectAnnotation.h"
|
||||||
#include "RimProject.h"
|
#include "RimProject.h"
|
||||||
#include "RimSummaryCrossPlot.h"
|
#include "RimSummaryCrossPlot.h"
|
||||||
#include "RimSummaryCurve.h"
|
#include "RimSummaryCurve.h"
|
||||||
@ -135,6 +136,8 @@ RimPlotCurve::RimPlotCurve()
|
|||||||
m_additionalDataSources.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
m_additionalDataSources.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
||||||
m_additionalDataSources.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
m_additionalDataSources.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_rectAnnotations, "RectAnnotation", "Plot Rect Annotations" );
|
||||||
|
|
||||||
m_plotCurve = nullptr;
|
m_plotCurve = nullptr;
|
||||||
m_parentPlot = nullptr;
|
m_parentPlot = nullptr;
|
||||||
}
|
}
|
||||||
@ -1137,6 +1140,14 @@ std::vector<RimPlotCurve*> RimPlotCurve::additionalDataSources() const
|
|||||||
return m_additionalDataSources.ptrReferencedObjectsByType();
|
return m_additionalDataSources.ptrReferencedObjectsByType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<RimPlotRectAnnotation*> RimPlotCurve::rectAnnotations() const
|
||||||
|
{
|
||||||
|
return m_rectAnnotations.childrenByType();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "RiuQwtPlotCurveDefines.h"
|
#include "RiuQwtPlotCurveDefines.h"
|
||||||
#include "RiuQwtSymbol.h"
|
#include "RiuQwtSymbol.h"
|
||||||
|
|
||||||
|
#include "cafPdmChildArrayField.h"
|
||||||
#include "cafPdmChildField.h"
|
#include "cafPdmChildField.h"
|
||||||
#include "cafPdmField.h"
|
#include "cafPdmField.h"
|
||||||
#include "cafPdmFieldCvfColor.h"
|
#include "cafPdmFieldCvfColor.h"
|
||||||
@ -39,6 +40,7 @@
|
|||||||
|
|
||||||
class RiuPlotCurve;
|
class RiuPlotCurve;
|
||||||
class RiuPlotWidget;
|
class RiuPlotWidget;
|
||||||
|
class RimPlotRectAnnotation;
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
///
|
///
|
||||||
@ -139,6 +141,8 @@ public:
|
|||||||
bool isSameCurve( const RiuPlotCurve* plotCurve ) const;
|
bool isSameCurve( const RiuPlotCurve* plotCurve ) const;
|
||||||
void deletePlotCurve();
|
void deletePlotCurve();
|
||||||
|
|
||||||
|
std::vector<RimPlotRectAnnotation*> rectAnnotations() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QString createCurveAutoName() = 0;
|
virtual QString createCurveAutoName() = 0;
|
||||||
|
|
||||||
@ -208,7 +212,8 @@ protected:
|
|||||||
|
|
||||||
caf::PdmChildField<RimPlotCurveAppearance*> m_curveAppearance;
|
caf::PdmChildField<RimPlotCurveAppearance*> m_curveAppearance;
|
||||||
|
|
||||||
caf::PdmPtrArrayField<RimPlotCurve*> m_additionalDataSources;
|
caf::PdmPtrArrayField<RimPlotCurve*> m_additionalDataSources;
|
||||||
|
caf::PdmChildArrayField<RimPlotRectAnnotation*> m_rectAnnotations;
|
||||||
|
|
||||||
QPointer<RiuPlotWidget> m_parentPlot;
|
QPointer<RiuPlotWidget> m_parentPlot;
|
||||||
RiuPlotCurve* m_plotCurve;
|
RiuPlotCurve* m_plotCurve;
|
||||||
|
129
ApplicationLibCode/ProjectDataModel/RimPlotRectAnnotation.cpp
Normal file
129
ApplicationLibCode/ProjectDataModel/RimPlotRectAnnotation.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RimPlotRectAnnotation.h"
|
||||||
|
|
||||||
|
#include "RimPlot.h"
|
||||||
|
#include "RimTools.h"
|
||||||
|
|
||||||
|
#include "cafPdmUiDoubleSliderEditor.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimPlotRectAnnotation, "RimPlotRectAnnotation" );
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimPlotRectAnnotation::RimPlotRectAnnotation()
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Plot Rect Annotation", ":/LeftAxis16x16.png" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_minX, "MinX", "Min X" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_maxX, "MaxX", "Max X" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_minY, "MinY", "Min Y" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_maxY, "MaxY", "Max Y" );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_color, "Color", cvf::Color3f( cvf::Color3f::LIGHT_GRAY ), "Color" );
|
||||||
|
CAF_PDM_InitField( &m_transparency, "Transparency", 0.1, "Transparency" );
|
||||||
|
m_transparency.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_text, "Text", "Text" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotRectAnnotation::setRangeX( double minX, double maxX )
|
||||||
|
{
|
||||||
|
m_minX = minX;
|
||||||
|
m_maxX = maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotRectAnnotation::setRangeY( double minY, double maxY )
|
||||||
|
{
|
||||||
|
m_minY = minY;
|
||||||
|
m_maxY = maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::pair<double, double> RimPlotRectAnnotation::rangeX() const
|
||||||
|
{
|
||||||
|
return { m_minX, m_maxX };
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::pair<double, double> RimPlotRectAnnotation::rangeY() const
|
||||||
|
{
|
||||||
|
return { m_minY, m_maxY };
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotRectAnnotation::setColor( const cvf::Color3f& color )
|
||||||
|
{
|
||||||
|
m_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
cvf::Color3f RimPlotRectAnnotation::color() const
|
||||||
|
{
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotRectAnnotation::setTransparency( double transparency )
|
||||||
|
{
|
||||||
|
m_transparency = transparency;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
double RimPlotRectAnnotation::transparency() const
|
||||||
|
{
|
||||||
|
return m_transparency;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotRectAnnotation::setText( const QString& text )
|
||||||
|
{
|
||||||
|
m_text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimPlotRectAnnotation::text() const
|
||||||
|
{
|
||||||
|
return m_text;
|
||||||
|
}
|
62
ApplicationLibCode/ProjectDataModel/RimPlotRectAnnotation.h
Normal file
62
ApplicationLibCode/ProjectDataModel/RimPlotRectAnnotation.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RimCheckableNamedObject.h"
|
||||||
|
|
||||||
|
#include "cafPdmField.h"
|
||||||
|
#include "cafPdmFieldCvfColor.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class RimPlotRectAnnotation : public RimCheckableNamedObject
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RimPlotRectAnnotation();
|
||||||
|
|
||||||
|
void setRangeX( double minX, double maxX );
|
||||||
|
void setRangeY( double minY, double maxY );
|
||||||
|
|
||||||
|
std::pair<double, double> rangeX() const;
|
||||||
|
std::pair<double, double> rangeY() const;
|
||||||
|
|
||||||
|
void setColor( const cvf::Color3f& color );
|
||||||
|
cvf::Color3f color() const;
|
||||||
|
|
||||||
|
void setText( const QString& text );
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
void setTransparency( double transparency );
|
||||||
|
double transparency() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
caf::PdmField<double> m_minX;
|
||||||
|
caf::PdmField<double> m_maxX;
|
||||||
|
caf::PdmField<double> m_minY;
|
||||||
|
caf::PdmField<double> m_maxY;
|
||||||
|
caf::PdmField<cvf::Color3f> m_color;
|
||||||
|
caf::PdmField<double> m_transparency;
|
||||||
|
caf::PdmField<QString> m_text;
|
||||||
|
};
|
@ -19,6 +19,7 @@
|
|||||||
#include "RimSummaryRegressionAnalysisCurve.h"
|
#include "RimSummaryRegressionAnalysisCurve.h"
|
||||||
|
|
||||||
#include "RiaQDateTimeTools.h"
|
#include "RiaQDateTimeTools.h"
|
||||||
|
#include "RiaRegressionTextTools.h"
|
||||||
#include "RiaTimeTTools.h"
|
#include "RiaTimeTTools.h"
|
||||||
|
|
||||||
#include "RimSummaryPlot.h"
|
#include "RimSummaryPlot.h"
|
||||||
@ -366,22 +367,12 @@ QString RimSummaryRegressionAnalysisCurve::curveExportDescription( const RifEcli
|
|||||||
return RimSummaryCurve::curveExportDescription() + "." + m_regressionType().uiText() + "_Regression";
|
return RimSummaryCurve::curveExportDescription() + "." + m_regressionType().uiText() + "_Regression";
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
QString RimSummaryRegressionAnalysisCurve::formatDouble( double v )
|
|
||||||
{
|
|
||||||
return QString::number( v, 'g', 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LinearRegression& reg )
|
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LinearRegression& reg )
|
||||||
{
|
{
|
||||||
QString sign = reg.intercept() < 0.0 ? "-" : "+";
|
return RiaRegressionTextTools::generateRegressionText( reg ) + getXAxisUnitText();
|
||||||
return QString( "y = %1x %2 %3" ).arg( formatDouble( reg.slope() ) ).arg( sign ).arg( formatDouble( std::fabs( reg.intercept() ) ) ) +
|
|
||||||
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ) + getXAxisUnitText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -389,40 +380,7 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::PolynomialRegression& reg )
|
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::PolynomialRegression& reg )
|
||||||
{
|
{
|
||||||
QString str = "y = ";
|
return RiaRegressionTextTools::generateRegressionText( reg ) + getXAxisUnitText();
|
||||||
|
|
||||||
bool isFirst = true;
|
|
||||||
std::vector<double> coeffs = reg.coeffisients();
|
|
||||||
QStringList parts;
|
|
||||||
for ( size_t i = 0; i < coeffs.size(); i++ )
|
|
||||||
{
|
|
||||||
double coeff = coeffs[i];
|
|
||||||
// Skip zero coeffs
|
|
||||||
if ( coeff != 0.0 )
|
|
||||||
{
|
|
||||||
if ( coeff < 0.0 )
|
|
||||||
parts.append( "-" );
|
|
||||||
else if ( !isFirst )
|
|
||||||
parts.append( "+" );
|
|
||||||
|
|
||||||
if ( i == 0 )
|
|
||||||
{
|
|
||||||
parts.append( QString( "%1" ).arg( formatDouble( std::fabs( coeff ) ) ) );
|
|
||||||
}
|
|
||||||
else if ( i == 1 )
|
|
||||||
{
|
|
||||||
parts.append( QString( "%1x" ).arg( formatDouble( std::fabs( coeff ) ) ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parts.append( QString( " %1x<sup>%2</sup>" ).arg( formatDouble( std::fabs( coeff ) ) ).arg( i ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
isFirst = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str + parts.join( " " ) + QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ) + getXAxisUnitText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -430,8 +388,7 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::PowerFitRegression& reg )
|
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::PowerFitRegression& reg )
|
||||||
{
|
{
|
||||||
return QString( "y = %1 + x<sup>%2</sup>" ).arg( formatDouble( reg.scale() ) ).arg( formatDouble( reg.exponent() ) ) +
|
return RiaRegressionTextTools::generateRegressionText( reg ) + getXAxisUnitText();
|
||||||
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ) + getXAxisUnitText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -439,8 +396,7 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::ExponentialRegression& reg )
|
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::ExponentialRegression& reg )
|
||||||
{
|
{
|
||||||
return QString( "y = %1 * e<sup>%2x</sup>" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
|
return RiaRegressionTextTools::generateRegressionText( reg ) + getXAxisUnitText();
|
||||||
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ) + getXAxisUnitText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -448,8 +404,7 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogarithmicRegression& reg )
|
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogarithmicRegression& reg )
|
||||||
{
|
{
|
||||||
return QString( "y = %1 + %2 * ln(x)" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
|
return RiaRegressionTextTools::generateRegressionText( reg ) + getXAxisUnitText();
|
||||||
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ) + getXAxisUnitText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -110,7 +110,6 @@ private:
|
|||||||
static QString generateRegressionText( const regression::LogarithmicRegression& reg );
|
static QString generateRegressionText( const regression::LogarithmicRegression& reg );
|
||||||
static QString generateRegressionText( const regression::ExponentialRegression& reg );
|
static QString generateRegressionText( const regression::ExponentialRegression& reg );
|
||||||
|
|
||||||
static QString formatDouble( double v );
|
|
||||||
static QString getXAxisUnitText();
|
static QString getXAxisUnitText();
|
||||||
|
|
||||||
static void appendTimeSteps( std::vector<time_t>& destinationTimeSteps, const std::set<QDateTime>& sourceTimeSteps );
|
static void appendTimeSteps( std::vector<time_t>& destinationTimeSteps, const std::set<QDateTime>& sourceTimeSteps );
|
||||||
|
@ -108,6 +108,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.h
|
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.h
|
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiuMenuBarBuildTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RiuMenuBarBuildTools.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotRectAnnotation.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCE_GROUP_SOURCE_FILES
|
set(SOURCE_GROUP_SOURCE_FILES
|
||||||
@ -217,6 +218,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiuMenuBarBuildTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiuMenuBarBuildTools.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotRectAnnotation.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(RESINSIGHT_USE_QT_CHARTS)
|
if(RESINSIGHT_USE_QT_CHARTS)
|
||||||
|
@ -19,9 +19,14 @@
|
|||||||
|
|
||||||
#include "RiuQwtPlotCurve.h"
|
#include "RiuQwtPlotCurve.h"
|
||||||
|
|
||||||
|
#include "RiaColorTools.h"
|
||||||
#include "RiaCurveDataTools.h"
|
#include "RiaCurveDataTools.h"
|
||||||
#include "RiaImageTools.h"
|
#include "RiaImageTools.h"
|
||||||
|
|
||||||
|
#include "RimPlotCurve.h"
|
||||||
|
#include "RimPlotRectAnnotation.h"
|
||||||
|
|
||||||
|
#include "RiuQwtPlotRectAnnotation.h"
|
||||||
#include "RiuQwtPlotTools.h"
|
#include "RiuQwtPlotTools.h"
|
||||||
#include "RiuQwtPlotWidget.h"
|
#include "RiuQwtPlotWidget.h"
|
||||||
#include "RiuQwtSymbol.h"
|
#include "RiuQwtSymbol.h"
|
||||||
@ -32,9 +37,11 @@
|
|||||||
#include "qwt_painter.h"
|
#include "qwt_painter.h"
|
||||||
#include "qwt_plot_curve.h"
|
#include "qwt_plot_curve.h"
|
||||||
#include "qwt_plot_intervalcurve.h"
|
#include "qwt_plot_intervalcurve.h"
|
||||||
|
#include "qwt_plot_marker.h"
|
||||||
#include "qwt_point_mapper.h"
|
#include "qwt_point_mapper.h"
|
||||||
#include "qwt_scale_map.h"
|
#include "qwt_scale_map.h"
|
||||||
#include "qwt_symbol.h"
|
#include "qwt_symbol.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
#include "qwt_weeding_curve_fitter.h"
|
#include "qwt_weeding_curve_fitter.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -59,6 +66,8 @@ RiuQwtPlotCurve::RiuQwtPlotCurve( RimPlotCurve* ownerRimCurve, const QString& ti
|
|||||||
m_qwtCurveErrorBars->setSymbol( new QwtIntervalSymbol( QwtIntervalSymbol::Bar ) );
|
m_qwtCurveErrorBars->setSymbol( new QwtIntervalSymbol( QwtIntervalSymbol::Bar ) );
|
||||||
m_qwtCurveErrorBars->setItemAttribute( QwtPlotItem::Legend, false );
|
m_qwtCurveErrorBars->setItemAttribute( QwtPlotItem::Legend, false );
|
||||||
m_qwtCurveErrorBars->setZ( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_ERROR_BARS ) );
|
m_qwtCurveErrorBars->setZ( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_ERROR_BARS ) );
|
||||||
|
|
||||||
|
m_qwtPlotRectAnnotation = new RiuQwtPlotRectAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -70,6 +79,9 @@ RiuQwtPlotCurve::~RiuQwtPlotCurve()
|
|||||||
|
|
||||||
delete m_qwtCurveErrorBars;
|
delete m_qwtCurveErrorBars;
|
||||||
m_qwtCurveErrorBars = nullptr;
|
m_qwtCurveErrorBars = nullptr;
|
||||||
|
|
||||||
|
delete m_qwtPlotRectAnnotation;
|
||||||
|
m_qwtPlotRectAnnotation = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -322,6 +334,30 @@ void RiuQwtPlotCurve::attachToPlot( RiuPlotWidget* plotWidget )
|
|||||||
{
|
{
|
||||||
m_qwtCurveErrorBars->attach( m_plotWidget->qwtPlot() );
|
m_qwtCurveErrorBars->attach( m_plotWidget->qwtPlot() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( m_ownerRimCurve )
|
||||||
|
{
|
||||||
|
auto rectAnnotations = m_ownerRimCurve->rectAnnotations();
|
||||||
|
if ( !rectAnnotations.empty() )
|
||||||
|
{
|
||||||
|
auto [minX, maxX] = rectAnnotations[0]->rangeX();
|
||||||
|
auto [minY, maxY] = rectAnnotations[0]->rangeY();
|
||||||
|
m_qwtPlotRectAnnotation->setInterval( minX, maxX, minY, maxY );
|
||||||
|
QColor brushColor( RiaColorTools::toQColor( rectAnnotations[0]->color() ) );
|
||||||
|
brushColor.setAlphaF( rectAnnotations[0]->transparency() );
|
||||||
|
QBrush brush( brushColor );
|
||||||
|
m_qwtPlotRectAnnotation->setBrush( brush );
|
||||||
|
QColor penColor( RiaColorTools::toQColor( rectAnnotations[0]->color() ) );
|
||||||
|
|
||||||
|
QPen pen( penColor );
|
||||||
|
m_qwtPlotRectAnnotation->setPen( pen );
|
||||||
|
|
||||||
|
m_qwtPlotRectAnnotation->setText( rectAnnotations[0]->text() );
|
||||||
|
m_qwtPlotRectAnnotation->attach( m_plotWidget->qwtPlot() );
|
||||||
|
|
||||||
|
m_qwtPlotRectAnnotation->setVisible( rectAnnotations[0]->isChecked() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -331,6 +367,7 @@ void RiuQwtPlotCurve::detach()
|
|||||||
{
|
{
|
||||||
QwtPlotCurve::detach();
|
QwtPlotCurve::detach();
|
||||||
m_qwtCurveErrorBars->detach();
|
m_qwtCurveErrorBars->detach();
|
||||||
|
m_qwtPlotRectAnnotation->detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
class QwtPlotIntervalCurve;
|
class QwtPlotIntervalCurve;
|
||||||
class RiuQwtPlotWidget;
|
class RiuQwtPlotWidget;
|
||||||
|
class RiuQwtPlotRectAnnotation;
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
//
|
//
|
||||||
@ -99,5 +100,7 @@ protected:
|
|||||||
QwtPlotIntervalCurve* m_qwtCurveErrorBars;
|
QwtPlotIntervalCurve* m_qwtCurveErrorBars;
|
||||||
bool m_showErrorBars;
|
bool m_showErrorBars;
|
||||||
|
|
||||||
|
RiuQwtPlotRectAnnotation* m_qwtPlotRectAnnotation;
|
||||||
|
|
||||||
QPointer<RiuQwtPlotWidget> m_plotWidget;
|
QPointer<RiuQwtPlotWidget> m_plotWidget;
|
||||||
};
|
};
|
||||||
|
@ -67,6 +67,13 @@ int RiuQwtPlotCurveDefines::zDepthForIndex( ZIndex index )
|
|||||||
case RiuQwtPlotCurveDefines::ZIndex::Z_SINGLE_CURVE_OBSERVED:
|
case RiuQwtPlotCurveDefines::ZIndex::Z_SINGLE_CURVE_OBSERVED:
|
||||||
return 500;
|
return 500;
|
||||||
break;
|
break;
|
||||||
|
case RiuQwtPlotCurveDefines::ZIndex::Z_PLOT_RECT_ANNOTATION:
|
||||||
|
return 600;
|
||||||
|
break;
|
||||||
|
case RiuQwtPlotCurveDefines::ZIndex::Z_REGRESSION_CURVE:
|
||||||
|
return 700;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,9 @@ enum class ZIndex
|
|||||||
Z_ENSEMBLE_STAT_CURVE,
|
Z_ENSEMBLE_STAT_CURVE,
|
||||||
Z_SINGLE_CURVE_NON_OBSERVED,
|
Z_SINGLE_CURVE_NON_OBSERVED,
|
||||||
Z_ERROR_BARS,
|
Z_ERROR_BARS,
|
||||||
Z_SINGLE_CURVE_OBSERVED
|
Z_SINGLE_CURVE_OBSERVED,
|
||||||
|
Z_PLOT_RECT_ANNOTATION,
|
||||||
|
Z_REGRESSION_CURVE
|
||||||
};
|
};
|
||||||
|
|
||||||
int zDepthForIndex( ZIndex index );
|
int zDepthForIndex( ZIndex index );
|
||||||
|
214
ApplicationLibCode/UserInterface/RiuQwtPlotRectAnnotation.cpp
Normal file
214
ApplicationLibCode/UserInterface/RiuQwtPlotRectAnnotation.cpp
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RiuQwtPlotRectAnnotation.h"
|
||||||
|
|
||||||
|
#include "RiuGuiTheme.h"
|
||||||
|
#include "RiuQwtPlotCurveDefines.h"
|
||||||
|
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_plot_marker.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include "qwt_symbol.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QRect>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RiuQwtPlotRectAnnotation::RiuQwtPlotRectAnnotation()
|
||||||
|
: QwtPlotItem( QwtText( "PlotRectAnnotation" ) )
|
||||||
|
{
|
||||||
|
setItemAttribute( QwtPlotItem::AutoScale, false );
|
||||||
|
setItemAttribute( QwtPlotItem::Legend, false );
|
||||||
|
|
||||||
|
QColor c( Qt::darkGray );
|
||||||
|
c.setAlpha( 50 );
|
||||||
|
m_brush = QBrush( c );
|
||||||
|
|
||||||
|
m_pen = QPen();
|
||||||
|
m_pen.setColor( Qt::black );
|
||||||
|
m_pen.setWidth( 2 );
|
||||||
|
|
||||||
|
setZ( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_PLOT_RECT_ANNOTATION ) );
|
||||||
|
|
||||||
|
m_textLabel = std::make_unique<QwtPlotMarker>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::setPen( const QPen& pen )
|
||||||
|
{
|
||||||
|
m_pen = pen;
|
||||||
|
itemChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
const QPen& RiuQwtPlotRectAnnotation::pen() const
|
||||||
|
{
|
||||||
|
return m_pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::setBrush( const QBrush& brush )
|
||||||
|
{
|
||||||
|
m_brush = brush;
|
||||||
|
itemChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
const QBrush& RiuQwtPlotRectAnnotation::brush() const
|
||||||
|
{
|
||||||
|
return m_brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::setInterval( double minX, double maxX, double minY, double maxY )
|
||||||
|
{
|
||||||
|
m_intervalX.setMinValue( minX );
|
||||||
|
m_intervalX.setMaxValue( maxX );
|
||||||
|
m_intervalY.setMinValue( minY );
|
||||||
|
m_intervalY.setMaxValue( maxY );
|
||||||
|
|
||||||
|
itemChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::draw( QPainter* painter, const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QRectF& canvasRect ) const
|
||||||
|
{
|
||||||
|
if ( !m_intervalX.isValid() || !m_intervalY.isValid() ) return;
|
||||||
|
|
||||||
|
QPen pen = m_pen;
|
||||||
|
pen.setCapStyle( Qt::FlatCap );
|
||||||
|
|
||||||
|
double x1 = xMap.transform( m_intervalX.minValue() );
|
||||||
|
double x2 = xMap.transform( m_intervalX.maxValue() );
|
||||||
|
|
||||||
|
double y1 = yMap.transform( m_intervalY.minValue() );
|
||||||
|
double y2 = yMap.transform( m_intervalY.maxValue() );
|
||||||
|
|
||||||
|
const bool doAlign = QwtPainter::roundingAlignment( painter );
|
||||||
|
if ( doAlign )
|
||||||
|
{
|
||||||
|
x1 = qRound( x1 );
|
||||||
|
x2 = qRound( x2 );
|
||||||
|
|
||||||
|
y1 = qRound( y1 );
|
||||||
|
y2 = qRound( y2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF r( x1, y1, x2 - x1, y2 - y1 );
|
||||||
|
r = r.normalized();
|
||||||
|
|
||||||
|
if ( m_brush.style() != Qt::NoBrush && x1 != x2 && y1 != y2 )
|
||||||
|
{
|
||||||
|
QwtPainter::fillRect( painter, r, m_brush );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_pen.style() != Qt::NoPen )
|
||||||
|
{
|
||||||
|
painter->setPen( m_pen );
|
||||||
|
|
||||||
|
QwtPainter::drawRect( painter, r );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QRectF RiuQwtPlotRectAnnotation::boundingRect() const
|
||||||
|
{
|
||||||
|
QRectF br = QwtPlotItem::boundingRect();
|
||||||
|
|
||||||
|
if ( m_intervalX.isValid() && m_intervalY.isValid() )
|
||||||
|
{
|
||||||
|
br.setTop( m_intervalY.minValue() );
|
||||||
|
br.setBottom( m_intervalY.maxValue() );
|
||||||
|
br.setLeft( m_intervalX.minValue() );
|
||||||
|
br.setRight( m_intervalX.maxValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
int RiuQwtPlotRectAnnotation::rtti() const
|
||||||
|
{
|
||||||
|
return 5001;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::setText( const QString& text )
|
||||||
|
{
|
||||||
|
QwtText label( text );
|
||||||
|
auto textColor = RiuGuiTheme::getColorByVariableName( "textColor" );
|
||||||
|
label.setColor( textColor );
|
||||||
|
label.setRenderFlags( Qt::AlignLeft );
|
||||||
|
|
||||||
|
m_textLabel->setLabel( label );
|
||||||
|
m_textLabel->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
|
||||||
|
|
||||||
|
m_textLabel->setLineStyle( QwtPlotMarker::NoLine );
|
||||||
|
m_textLabel->setSymbol( new QwtSymbol( QwtSymbol::NoSymbol ) );
|
||||||
|
|
||||||
|
m_textLabel->setValue( m_intervalX.minValue(), m_intervalY.maxValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::attach( QwtPlot* plot )
|
||||||
|
{
|
||||||
|
QwtPlotItem::attach( plot );
|
||||||
|
m_textLabel->attach( plot );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::detach()
|
||||||
|
{
|
||||||
|
QwtPlotItem::detach();
|
||||||
|
m_textLabel->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RiuQwtPlotRectAnnotation::setVisible( bool isVisible )
|
||||||
|
{
|
||||||
|
QwtPlotItem::setVisible( isVisible );
|
||||||
|
m_textLabel->setVisible( isVisible );
|
||||||
|
}
|
69
ApplicationLibCode/UserInterface/RiuQwtPlotRectAnnotation.h
Normal file
69
ApplicationLibCode/UserInterface/RiuQwtPlotRectAnnotation.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2023- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include "qwt_plot_item.h"
|
||||||
|
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QPen>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class QRectF;
|
||||||
|
class QPainter;
|
||||||
|
class QwtPlotMarker;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// Rectangular plot item for annotation areas of a plot.
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class RiuQwtPlotRectAnnotation : public QwtPlotItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RiuQwtPlotRectAnnotation();
|
||||||
|
~RiuQwtPlotRectAnnotation() override = default;
|
||||||
|
|
||||||
|
void setInterval( double minX, double maxX, double minY, double maxY );
|
||||||
|
|
||||||
|
void setPen( const QPen& );
|
||||||
|
const QPen& pen() const;
|
||||||
|
|
||||||
|
void setBrush( const QBrush& );
|
||||||
|
const QBrush& brush() const;
|
||||||
|
|
||||||
|
void setText( const QString& text );
|
||||||
|
|
||||||
|
int rtti() const override;
|
||||||
|
void draw( QPainter* painter, const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QRectF& canvasRect ) const override;
|
||||||
|
QRectF boundingRect() const override;
|
||||||
|
|
||||||
|
void attach( QwtPlot* plot );
|
||||||
|
void detach();
|
||||||
|
void setVisible( bool isVisible ) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QwtInterval m_intervalX;
|
||||||
|
QwtInterval m_intervalY;
|
||||||
|
QPen m_pen;
|
||||||
|
QBrush m_brush;
|
||||||
|
QString m_text;
|
||||||
|
|
||||||
|
std::unique_ptr<QwtPlotMarker> m_textLabel;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user