Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add value range filtering to cross plot regression curves #10639

Merged
merged 2 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "RimMainPlotCollection.h"

#include "RiaPlotCollectionScheduler.h"
#include "RiaSummaryDefines.h"

#include "PlotBuilderCommands/RicSummaryPlotBuilder.h"

Expand All @@ -42,6 +43,8 @@
#include "RimStimPlanModelPlotCollection.h"
#include "RimSummaryAddress.h"
#include "RimSummaryCrossPlotCollection.h"
#include "RimSummaryCurve.h"
#include "RimSummaryDataSourceStepping.h"
#include "RimSummaryMultiPlot.h"
#include "RimSummaryMultiPlotCollection.h"
#include "RimSummaryPlotCollection.h"
Expand Down Expand Up @@ -176,17 +179,51 @@ RimMainPlotCollection* RimMainPlotCollection::current()
//--------------------------------------------------------------------------------------------------
void RimMainPlotCollection::initAfterRead()
{
std::vector<RimSummaryPlot*> plotsToMove;
for ( auto singlePlot : m_summaryPlotCollection_OBSOLETE()->plots() )
{
plotsToMove.push_back( singlePlot );
std::vector<RimSummaryPlot*> plotsToMove;
for ( auto singlePlot : m_summaryPlotCollection_OBSOLETE()->plots() )
{
plotsToMove.push_back( singlePlot );
}

for ( auto singlePlot : plotsToMove )
{
m_summaryPlotCollection_OBSOLETE()->removePlot( singlePlot );

RicSummaryPlotBuilder::createAndAppendSingleSummaryMultiPlotNoAutoSettings( singlePlot );
}
}

for ( auto singlePlot : plotsToMove )
// Move cross plots into summary plot collection
auto crossPlots = m_summaryCrossPlotCollection_OBSOLETE->plots();
if ( !crossPlots.empty() )
{
m_summaryPlotCollection_OBSOLETE()->removePlot( singlePlot );
auto* summaryMultiPlot = new RimSummaryMultiPlot;
summaryMultiPlot->setMultiPlotTitle( QString( "Multi Plot %1" ).arg( m_summaryMultiPlotCollection->multiPlots().size() + 1 ) );
summaryMultiPlot->setAsPlotMdiWindow();
m_summaryMultiPlotCollection->addSummaryMultiPlot( summaryMultiPlot );

for ( auto crossPlot : crossPlots )
{
m_summaryCrossPlotCollection_OBSOLETE->removePlot( crossPlot );
summaryMultiPlot->addPlot( crossPlot );

RicSummaryPlotBuilder::createAndAppendSingleSummaryMultiPlotNoAutoSettings( singlePlot );
// We want to convert RimSummaryCrossPlot into a RimSummaryPlot. The cross plot is derived from RimSummaryPlot, but we need to
// create a new RimSummaryPlot to be able to store the PDM object as a RimSummaryPlot instead of RimSummaryCrossPlot
auto summaryPlot = new RimSummaryPlot;
summaryMultiPlot->addPlot( summaryPlot );

for ( auto curve : crossPlot->allCurves( RimSummaryDataSourceStepping::Axis::Y_AXIS ) )
{
crossPlot->removeCurve( curve );

if ( curve->summaryCaseX() != nullptr ) curve->setAxisTypeX( RiaDefines::HorizontalAxisType::SUMMARY_VECTOR );

summaryPlot->insertCurve( curve, std::numeric_limits<size_t>::max() );
}

delete crossPlot;
}
}
}

Expand Down
5 changes: 0 additions & 5 deletions ApplicationLibCode/ProjectDataModel/RimProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1422,11 +1422,6 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
uiTreeOrdering.add( m_mainPlotCollection->correlationPlotCollection() );
}

if ( m_mainPlotCollection->summaryCrossPlotCollection() )
{
uiTreeOrdering.add( m_mainPlotCollection->summaryCrossPlotCollection() );
}

if ( m_mainPlotCollection->summaryTableCollection() )
{
uiTreeOrdering.add( m_mainPlotCollection->summaryTableCollection() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "RimSummaryRegressionAnalysisCurve.h"

#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RiaRegressionTextTools.h"
#include "RiaTimeTTools.h"
Expand All @@ -28,6 +29,7 @@
#include "cafPdmUiDateEditor.h"
#include "cafPdmUiLineEditor.h"
#include "cafPdmUiSliderEditor.h"
#include "cafPdmUiSliderTools.h"
#include "cafPdmUiTextEditor.h"

#include "ExponentialRegression.hpp"
Expand Down Expand Up @@ -94,6 +96,12 @@ RimSummaryRegressionAnalysisCurve::RimSummaryRegressionAnalysisCurve()
m_expressionText.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
m_expressionText.uiCapability()->setUiReadOnly( true );
m_expressionText.xmlCapability()->disableIO();

CAF_PDM_InitField( &m_valueRangeX, "ValueRangeX", std::make_pair( 0.0, 0.0 ), "Value Range X" );
m_valueRangeX.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );

CAF_PDM_InitField( &m_valueRangeY, "ValueRangeY", std::make_pair( 0.0, 0.0 ), "Value Range Y" );
m_valueRangeY.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
}

//--------------------------------------------------------------------------------------------------
Expand All @@ -110,11 +118,68 @@ RimSummaryRegressionAnalysisCurve::~RimSummaryRegressionAnalysisCurve()
//--------------------------------------------------------------------------------------------------
void RimSummaryRegressionAnalysisCurve::onLoadDataAndUpdate( bool updateParentPlot )
{
auto xValues = RimSummaryCurve::valuesX();
auto yValues = RimSummaryCurve::valuesY();
auto timeStepsX = RimSummaryCurve::timeStepsX();
auto timeStepsY = RimSummaryCurve::timeStepsY();

if ( xValues.size() != yValues.size() ) return RiaLogging::error( "X value count and Y value count differs." );
if ( xValues.size() != timeStepsX.size() ) return RiaLogging::error( "X value count and X time step count differs." );
if ( xValues.size() != timeStepsY.size() ) return RiaLogging::error( "X value count and Y time step count differs." );
Comment on lines +126 to +128
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never seen this construct before (return void result), but was quite nice...


if ( timeStepsX != timeStepsY )
{
return RiaLogging::error(
"Differences in time steps for X and Y axis detected. This is currently not supported. Make sure that the same "
"case is used for both axis." );
}

if ( axisTypeX() == RiaDefines::HorizontalAxisType::SUMMARY_VECTOR )
{
// NB! Assume that time stamps for X and Y are the same
std::vector<size_t> indicesToRemove;
magnesj marked this conversation as resolved.
Show resolved Hide resolved

// Step 1: Find indices of values which are outside the specified range
for ( size_t i = 0; i < xValues.size(); i++ )
{
if ( xValues[i] < m_valueRangeX().first || xValues[i] > m_valueRangeX().second )
{
indicesToRemove.push_back( i );
}
}

for ( size_t i = 0; i < yValues.size(); i++ )
{
if ( yValues[i] < m_valueRangeY().first || yValues[i] > m_valueRangeY().second )
{
indicesToRemove.push_back( i );
}
}

// Step 2: Sort indices in descending order
std::sort( indicesToRemove.rbegin(), indicesToRemove.rend() );
magnesj marked this conversation as resolved.
Show resolved Hide resolved

// There might be duplicates, remove them
indicesToRemove.erase( std::unique( indicesToRemove.begin(), indicesToRemove.end() ), indicesToRemove.end() );

// Step 3: Remove elements at the specified indices
for ( auto index : indicesToRemove )
{
if ( index < xValues.size() )
{
xValues.erase( xValues.begin() + index );
yValues.erase( yValues.begin() + index );
timeStepsX.erase( timeStepsX.begin() + index );
timeStepsY.erase( timeStepsY.begin() + index );
}
}
}

QString descriptionX;
std::tie( m_timeStepsX, m_valuesX, descriptionX ) = computeRegressionCurve( RimSummaryCurve::timeStepsX(), RimSummaryCurve::valuesX() );
std::tie( m_timeStepsX, m_valuesX, descriptionX ) = computeRegressionCurve( timeStepsX, xValues );

QString descriptionY;
std::tie( m_timeStepsY, m_valuesY, descriptionY ) = computeRegressionCurve( RimSummaryCurve::timeStepsY(), RimSummaryCurve::valuesY() );
std::tie( m_timeStepsY, m_valuesY, descriptionY ) = computeRegressionCurve( timeStepsY, yValues );

m_expressionText = descriptionY;

Expand Down Expand Up @@ -260,6 +325,15 @@ void RimSummaryRegressionAnalysisCurve::defineUiOrdering( QString uiConfigName,
timeSelectionGroup->add( &m_maxTimeStep );
timeSelectionGroup->add( &m_showTimeSelectionInPlot );

if ( axisTypeX() == RiaDefines::HorizontalAxisType::SUMMARY_VECTOR )
{
caf::PdmUiGroup* valueRangeXGroup = uiOrdering.addNewGroup( "Value Range X" );
valueRangeXGroup->add( &m_valueRangeX );

caf::PdmUiGroup* valueRangeYGroup = uiOrdering.addNewGroup( "Value Range Y" );
valueRangeYGroup->add( &m_valueRangeY );
}

caf::PdmUiGroup* forecastingGroup = uiOrdering.addNewGroup( "Forecasting" );
forecastingGroup->add( &m_forecastForward );
forecastingGroup->add( &m_forecastBackward );
Expand Down Expand Up @@ -288,7 +362,8 @@ void RimSummaryRegressionAnalysisCurve::fieldChangedByUi( const caf::PdmFieldHan
RimSummaryCurve::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_regressionType || changedField == &m_polynomialDegree || changedField == &m_forecastBackward ||
changedField == &m_forecastForward || changedField == &m_forecastUnit || changedField == &m_minTimeStep ||
changedField == &m_maxTimeStep || changedField == &m_showTimeSelectionInPlot )
changedField == &m_maxTimeStep || changedField == &m_showTimeSelectionInPlot || changedField == &m_valueRangeX ||
changedField == &m_valueRangeY )
{
loadAndUpdateDataAndPlot();

Expand Down Expand Up @@ -349,6 +424,36 @@ void RimSummaryRegressionAnalysisCurve::defineEditorAttribute( const caf::PdmFie
myAttr->font = font;
}
}
else if ( field == &m_valueRangeX )
{
if ( auto attr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
{
attr->m_decimals = 2;
attr->m_sliderTickCount = 100;

auto values = RimSummaryCurve::valuesX();
if ( !values.empty() )
{
attr->m_minimum = *std::min_element( values.begin(), values.end() );
attr->m_maximum = *std::max_element( values.begin(), values.end() );
}
}
}
else if ( field == &m_valueRangeY )
{
if ( auto attr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
{
attr->m_decimals = 2;
attr->m_sliderTickCount = 100;

auto values = RimSummaryCurve::valuesY();
if ( !values.empty() )
{
attr->m_minimum = *std::min_element( values.begin(), values.end() );
attr->m_maximum = *std::max_element( values.begin(), values.end() );
}
}
}
}

//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -551,6 +656,20 @@ void RimSummaryRegressionAnalysisCurve::updateDefaultValues()
m_minTimeStep = timeSteps.front();
m_maxTimeStep = timeSteps.back();
}

auto allValuesX = RimSummaryCurve::valuesX();
if ( !allValuesX.empty() )
{
m_valueRangeX = std::make_pair( *std::min_element( allValuesX.begin(), allValuesX.end() ),
*std::max_element( allValuesX.begin(), allValuesX.end() ) );
}

auto allValuesY = RimSummaryCurve::valuesY();
if ( !allValuesY.empty() )
{
m_valueRangeY = std::make_pair( *std::min_element( allValuesY.begin(), allValuesY.end() ),
*std::max_element( allValuesY.begin(), allValuesY.end() ) );
}
}

//--------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class RimSummaryRegressionAnalysisCurve : public RimSummaryCurve

static void appendTimeSteps( std::vector<time_t>& destinationTimeSteps, const std::set<QDateTime>& sourceTimeSteps );

private:
caf::PdmField<caf::AppEnum<RegressionType>> m_regressionType;
caf::PdmField<time_t> m_minTimeStep;
caf::PdmField<time_t> m_maxTimeStep;
Expand All @@ -125,6 +126,9 @@ class RimSummaryRegressionAnalysisCurve : public RimSummaryCurve
caf::PdmField<int> m_forecastBackward;
caf::PdmField<caf::AppEnum<ForecastUnit>> m_forecastUnit;

caf::PdmField<std::pair<double, double>> m_valueRangeX;
caf::PdmField<std::pair<double, double>> m_valueRangeY;

caf::PdmPointer<RimTimeAxisAnnotation> m_timeRangeAnnotation;
std::vector<double> m_valuesX;
std::vector<time_t> m_timeStepsX;
Expand Down