From 3cc2958384aa585b8d588803242dec786ec34e0c Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 21 Nov 2024 14:38:59 +0100 Subject: [PATCH] Summary Table: Add user option to set time range on x-axis * Make sure all evenly distributed labels are drawn * Add start and end data --- .../Summary/RimSummaryTable.cpp | 110 +++++++++++++++++- .../Summary/RimSummaryTable.h | 7 +- .../UserInterface/RiuMatrixPlotWidget.cpp | 5 +- 3 files changed, 115 insertions(+), 7 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp index f7953de22d..4e9ce633e0 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp @@ -22,6 +22,7 @@ #include "RiaQDateTimeTools.h" #include "RiaStdStringTools.h" #include "RiaTimeHistoryCurveResampler.h" +#include "RiaTimeTTools.h" #include "Summary/RiaSummaryTools.h" #include "RifSummaryReaderInterface.h" @@ -35,6 +36,7 @@ #include "RiuMatrixPlotWidget.h" #include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiDateEditor.h" #include "cafPdmUiPushButtonEditor.h" #include "cafPdmUiToolButtonEditor.h" #include "cafPdmUiTreeSelectionEditor.h" @@ -105,6 +107,10 @@ RimSummaryTable::RimSummaryTable() CAF_PDM_InitFieldNoDefault( &m_mappingType, "MappingType", "Mapping Type" ); CAF_PDM_InitFieldNoDefault( &m_rangeType, "RangeType", "Range Type" ); + CAF_PDM_InitField( &m_filterTimeSteps, "FilterTimeSteps", false, "Filter Time Steps" ); + CAF_PDM_InitField( &m_startDate, "StartDate", QDateTime::currentDateTime(), "Start Date" ); + CAF_PDM_InitField( &m_endDate, "EndDate", QDateTime::currentDateTime(), "End Date" ); + setLegendsVisible( true ); setAsPlotMdiWindow(); setShowWindow( true ); @@ -145,6 +151,8 @@ void RimSummaryTable::setDefaultCaseAndCategoryAndVectorName() m_vector = *categoryVectors.begin(); } m_tableName = createTableName(); + + initializeDateRange(); } //-------------------------------------------------------------------------------------------------- @@ -158,6 +166,9 @@ void RimSummaryTable::setFromCaseAndCategoryAndVectorName( RimSummaryCase* m_category = category; m_vector = vectorName; m_tableName = createTableName(); + + initializeDateRange(); + onLoadDataAndUpdate(); } @@ -285,7 +296,8 @@ void RimSummaryTable::fieldChangedByUi( const caf::PdmFieldHandle* changedField, } onLoadDataAndUpdate(); } - else if ( changedField == &m_maxTimeLabelCount ) + else if ( changedField == &m_maxTimeLabelCount || changedField == &m_startDate || changedField == &m_endDate || + changedField == &m_filterTimeSteps ) { onLoadDataAndUpdate(); } @@ -316,6 +328,14 @@ void RimSummaryTable::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering dataGroup.add( &m_thresholdValue ); dataGroup.add( &m_excludedRowsUiField ); + caf::PdmUiGroup* timeFilterGroup = dataGroup.addNewGroup( "Time Filter" ); + timeFilterGroup->add( &m_filterTimeSteps ); + timeFilterGroup->add( &m_startDate ); + timeFilterGroup->add( &m_endDate ); + + m_startDate.uiCapability()->setUiReadOnly( !m_filterTimeSteps() ); + m_endDate.uiCapability()->setUiReadOnly( !m_filterTimeSteps() ); + caf::PdmUiGroup* tableSettingsGroup = uiOrdering.addNewGroup( "Table Settings" ); tableSettingsGroup->add( &m_showValueLabels ); m_legendConfig->uiOrdering( "FlagAndColorsOnly", *tableSettingsGroup ); @@ -334,6 +354,32 @@ void RimSummaryTable::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering uiOrdering.skipRemainingFields( true ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_startDate || field == &m_endDate ) + { + if ( auto myAttr = dynamic_cast( attribute ) ) + { + QString dateFormat = "yyyy-MM-dd"; + if ( m_resamplingSelection() == RiaDefines::DateTimePeriod::DECADE || m_resamplingSelection() == RiaDefines::DateTimePeriod::YEAR ) + { + dateFormat = "yyyy"; + } + else if ( m_resamplingSelection() == RiaDefines::DateTimePeriod::MONTH || + m_resamplingSelection() == RiaDefines::DateTimePeriod::QUARTER || + m_resamplingSelection() == RiaDefines::DateTimePeriod::HALFYEAR ) + { + dateFormat = "yyyy-MM"; + } + + myAttr->dateFormat = dateFormat; + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -400,6 +446,7 @@ QList RimSummaryTable::calculateValueOptions( const caf: options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( mappingType ), mappingType ) ); } } + return options; } @@ -674,6 +721,25 @@ std::vector RimSummaryTable::getToplevelSummaryCases() const return summaryCaseMainCollection->topLevelSummaryCases(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::initializeDateRange() +{ + if ( !m_case ) return; + const auto summaryReader = m_case->summaryReader(); + if ( !summaryReader ) return; + + const std::set allResultAddresses = summaryReader->allResultAddresses(); + if ( allResultAddresses.empty() ) return; + + auto timeSteps = summaryReader->timeSteps( *allResultAddresses.begin() ); + if ( timeSteps.empty() ) return; + + m_startDate = RiaQDateTimeTools::fromTime_t( timeSteps.front() ); + m_endDate = RiaQDateTimeTools::fromTime_t( timeSteps.back() ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -700,12 +766,49 @@ void RimSummaryTable::createTableData() const QString vectorName = QString::fromStdString( adr.vectorName() ); const QString categoryName = getCategoryNameFromAddress( adr ); - // Get re-sampled time steps and values - const auto& [resampledTimeSteps, resampledValues] = + // Get resampled time steps and values + auto [resampledTimeSteps, resampledValues] = RiaSummaryTools::resampledValuesForPeriod( adr, timeSteps, values, m_resamplingSelection() ); if ( resampledValues.empty() ) continue; + if ( m_filterTimeSteps() ) + { + auto filterTimeStepsAndValues = []( auto& resampledTimeSteps, auto& resampledValues, time_t startTime, time_t endTime ) + { + auto lowerBound = std::lower_bound( resampledTimeSteps.begin(), resampledTimeSteps.end(), startTime ); + if ( lowerBound != resampledTimeSteps.end() ) + { + const auto baseIndex = lowerBound - resampledTimeSteps.begin(); + + // Use one time step less to make sure the start date is included + const auto startIndex = ( baseIndex > 1 ) ? baseIndex - 1 : 0; + + resampledTimeSteps.erase( resampledTimeSteps.begin(), resampledTimeSteps.begin() + startIndex ); + resampledValues.erase( resampledValues.begin(), resampledValues.begin() + startIndex ); + } + + const auto upperBound = std::upper_bound( resampledTimeSteps.begin(), resampledTimeSteps.end(), endTime ); + if ( upperBound != resampledTimeSteps.end() ) + { + const auto endIndex = ( upperBound - resampledTimeSteps.begin() ) + 1; + + if ( endIndex < (int)resampledTimeSteps.size() ) + { + resampledTimeSteps.erase( resampledTimeSteps.begin() + endIndex, resampledTimeSteps.end() ); + resampledValues.erase( resampledValues.begin() + endIndex, resampledValues.end() ); + } + } + }; + + auto startTime = RiaTimeTTools::fromQDateTime( m_startDate ); + auto endTime = std::max( startTime, RiaTimeTTools::fromQDateTime( m_endDate ) ); + + filterTimeStepsAndValues( resampledTimeSteps, resampledValues, startTime, endTime ); + + if ( resampledValues.empty() ) continue; + } + // Exclude vectors with values BELOW threshold - to include visualization of values equal to threshold! const auto maxRowValue = *std::max_element( resampledValues.begin(), resampledValues.end() ); const auto minRowValue = *std::min_element( resampledValues.begin(), resampledValues.end() ); @@ -722,6 +825,7 @@ void RimSummaryTable::createTableData() std::find_if( resampledValues.rbegin(), resampledValues.rend(), [&]( double value ) { return value > 0.0; } ); const auto firstIdx = static_cast( std::distance( resampledValues.begin(), firstTimeStepItr ) ); const auto lastIdx = resampledValues.size() - static_cast( std::distance( resampledValues.rbegin(), lastTimeStepItr ) ) - 1; + const auto firstTimeStep = hasValueAboveThreshold ? resampledTimeSteps[firstIdx] : invalidTimeStep; const auto lastTimeStep = hasValueAboveThreshold ? resampledTimeSteps[lastIdx] : invalidTimeStep; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h index 9b7db25081..6766efd2a9 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h @@ -72,6 +72,7 @@ class RimSummaryTable : public RimPlotWindow void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override; void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; @@ -94,7 +95,6 @@ class RimSummaryTable : public RimPlotWindow QString createTableName() const; -private: std::pair createLegendMinMaxValues( const double maxTableValue ) const; QString dateFormatString() const; @@ -106,6 +106,7 @@ class RimSummaryTable : public RimPlotWindow QString getCategoryNameFromAddress( const RifEclipseSummaryAddress& address ) const; std::vector getToplevelSummaryCases() const; + void initializeDateRange(); private: // Matrix plot for visualizing table data @@ -133,6 +134,10 @@ class RimSummaryTable : public RimPlotWindow caf::PdmField m_mappingType; caf::PdmField> m_rangeType; + caf::PdmField m_filterTimeSteps; + caf::PdmField m_startDate; + caf::PdmField m_endDate; + private: using VectorData = RimSummaryTableTools::VectorData; using TableData = RimSummaryTableTools::TableData; diff --git a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp index 6fabe6a9bb..f8b7aa49f9 100644 --- a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp @@ -458,10 +458,9 @@ std::map RiuMatrixPlotWidget::createIndexLabelMap( const std::v } std::map indexLabelMap; - for ( size_t i = 0; i < std::min( labels.size(), size_t( maxLabelCount - 1 ) ); ++i ) + for ( size_t i = 0; i < labels.size(); i += increment ) { - auto index = i * increment; - indexLabelMap.emplace( index, labels[index] ); + indexLabelMap.emplace( i, labels[i] ); } indexLabelMap.emplace( labels.size() - 1, labels.back() );