#4157 Grid Cross Plot: Make categorisation legend more like ensemble legend

This commit is contained in:
Gaute Lindkvist 2019-03-04 15:35:48 +01:00
parent be95eefd69
commit ac7eccee88
19 changed files with 623 additions and 192 deletions

View File

@ -27,10 +27,11 @@ void RiaGridCrossPlotCurveNameHelper::addCurveSet(RimGridCrossPlotCurveSet* curv
m_caseNameSet.insert(curveSet->caseNameString());
m_axisVariablesSet.insert(curveSet->axisVariableString());
m_timeStepSet.insert(curveSet->timeStepString());
for (QString categoryName : curveSet->categoryStrings())
for (auto category : curveSet->categoryStrings())
{
m_categoryNameSet.insert(categoryName);
m_categoriesSet.insert(category);
}
m_curveSets.push_back(curveSet);
}
@ -41,7 +42,7 @@ void RiaGridCrossPlotCurveNameHelper::applyCurveNames()
{
for (auto curveSet : m_curveSets)
{
curveSet->updateCurveNames(m_caseNameSet.size() > 1u, m_axisVariablesSet.size() > 1u, m_timeStepSet.size() > 1u, m_categoryNameSet.size() > 1u);
curveSet->updateCurveNames(m_caseNameSet.size() > 1u, m_axisVariablesSet.size() > 1u, m_timeStepSet.size() > 1u, m_categoriesSet.size() > 1u);
}
}
@ -53,6 +54,6 @@ void RiaGridCrossPlotCurveNameHelper::reset()
m_caseNameSet.clear();
m_axisVariablesSet.clear();
m_timeStepSet.clear();
m_categoryNameSet.clear();
m_categoriesSet.clear();
m_curveSets.clear();
}

View File

@ -35,8 +35,8 @@ private:
std::set<QString> m_caseNameSet;
std::set<QString> m_axisVariablesSet;
std::set<QString> m_timeStepSet;
std::set<QString> m_categoryNameSet;
std::set<QString> m_categoriesSet;
std::vector<RimGridCrossPlotCurveSet*> m_curveSets;
};

View File

@ -19,7 +19,7 @@
#include "RiaGridCrossPlotCurveNameHelper.h"
#include "RiuSummaryQwtPlot.h"
#include "RiuGridCrossQwtPlot.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuQwtPlotTools.h"
@ -106,6 +106,14 @@ int RimGridCrossPlot::indexOfCurveSet(const RimGridCrossPlotCurveSet* curveSet)
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridCrossPlotCurveSet*> RimGridCrossPlot::curveSets() const
{
return m_crossPlotCurveSets.childObjects();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -168,7 +176,7 @@ void RimGridCrossPlot::reattachCurvesToQwtAndReplot()
curveSet->setParentQwtPlotNoReplot(m_qwtPlot);
}
}
m_qwtPlot->replot();
updateAxisDisplay();
}
}
@ -188,7 +196,10 @@ QString RimGridCrossPlot::createAutoName() const
QStringList dataSets;
for (auto curveSet : m_crossPlotCurveSets)
{
dataSets += curveSet->createAutoName();
if (curveSet->isChecked())
{
dataSets += curveSet->createAutoName();
}
}
if (!dataSets.isEmpty())
{
@ -298,7 +309,7 @@ QWidget* RimGridCrossPlot::createViewWidget(QWidget* mainWindowParent)
{
if (!m_qwtPlot)
{
m_qwtPlot = new RiuQwtPlot(this, mainWindowParent);
m_qwtPlot = new RiuGridCrossQwtPlot(this, mainWindowParent);
for (auto curveSet : m_crossPlotCurveSets)
{
@ -468,6 +479,14 @@ void RimGridCrossPlot::updateCurveNamesAndPlotTitle()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuGridCrossQwtPlot* RimGridCrossPlot::qwtPlot() const
{
return m_qwtPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -476,7 +495,10 @@ QString RimGridCrossPlot::xAxisParameterString() const
QStringList xAxisParams;
for (auto curveSet : m_crossPlotCurveSets)
{
xAxisParams.push_back(curveSet->xAxisName());
if (curveSet->isChecked())
{
xAxisParams.push_back(curveSet->xAxisName());
}
}
xAxisParams.removeDuplicates();
@ -497,7 +519,10 @@ QString RimGridCrossPlot::yAxisParameterString() const
QStringList yAxisParams;
for (auto curveSet : m_crossPlotCurveSets)
{
yAxisParams.push_back(curveSet->yAxisName());
if (curveSet->isChecked())
{
yAxisParams.push_back(curveSet->yAxisName());
}
}
yAxisParams.removeDuplicates();

View File

@ -31,7 +31,7 @@
class RimPlotAxisProperties;
class RimGridCrossPlotCurveSet;
class RiuQwtPlot;
class RiuGridCrossQwtPlot;
class RimGridCrossPlotNameConfig : public RimNameConfig
{
@ -56,6 +56,8 @@ public:
RimGridCrossPlotCurveSet* createCurveSet();
int indexOfCurveSet(const RimGridCrossPlotCurveSet* curveSet) const;
std::vector<RimGridCrossPlotCurveSet*> curveSets() const;
QWidget* viewWidget() override;
QImage snapshotWindowContent() override;
@ -69,6 +71,7 @@ public:
void performAutoNameUpdate() override;
void updateCurveNamesAndPlotTitle();
RiuGridCrossQwtPlot* qwtPlot() const;
public:
// Rim2dPlotInterface overrides
void updateAxisScaling() override;
@ -97,7 +100,7 @@ protected:
void updateAxisInQwt(RiaDefines::PlotAxis axisType);
void updateAxisFromQwt(RiaDefines::PlotAxis axisType);
std::pair<double, double> getAxisRangeFromData(RiaDefines::PlotAxis axisType);
private:
caf::PdmField<bool> m_showLegend;
caf::PdmField<int> m_legendFontSize;
@ -108,7 +111,7 @@ private:
caf::PdmChildArrayField<RimGridCrossPlotCurveSet*> m_crossPlotCurveSets;
QPointer<RiuQwtPlot> m_qwtPlot;
QPointer<RiuGridCrossQwtPlot> m_qwtPlot;
RiaGridCrossPlotCurveNameHelper m_curveNameHelper;
};

View File

@ -48,7 +48,6 @@ CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurve, "GridCrossPlotCurve");
RimGridCrossPlotCurve::RimGridCrossPlotCurve()
: m_curveSetIndex(0)
, m_categoryIndex(0)
, m_categoryCount(0)
{
CAF_PDM_InitObject("Cross Plot Points", ":/WellLogCurve16x16.png", "", "");
@ -60,19 +59,10 @@ RimGridCrossPlotCurve::RimGridCrossPlotCurve()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurve::setCategoryInformation(int curveSetIndex, int categoryIndex, int categoryCount)
void RimGridCrossPlotCurve::setCategoryInformation(int curveSetIndex, int categoryIndex)
{
m_curveSetIndex = curveSetIndex;
m_categoryIndex = categoryIndex;
m_categoryCount = categoryCount;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurve::setUseContrastColors(bool useContrastColors)
{
m_useContrastColors = useContrastColors;
m_categoryIndex = categoryIndex;
}
//--------------------------------------------------------------------------------------------------
@ -90,7 +80,7 @@ void RimGridCrossPlotCurve::setSamples(const std::vector<double>& xValues, const
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurve::updateCurveAppearance()
{
determineColorAndSymbol();
determineSymbol();
RimPlotCurve::updateCurveAppearance();
}
@ -105,30 +95,10 @@ int RimGridCrossPlotCurve::categoryIndex() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurve::determineColorAndSymbol()
void RimGridCrossPlotCurve::determineSymbol()
{
if (m_useContrastColors)
{
const caf::ColorTable& colors = RiaColorTables::categoryPaletteColors();
int colorIndex = m_categoryIndex + m_curveSetIndex; // Offset cycle for each curve set
setColor(colors.cycledColor3f(colorIndex));
int numColors = (int)colors.size();
// Retain same symbol until we've gone full cycle in colors
int symbolIndex = m_categoryIndex / numColors;
RiuQwtSymbol::PointSymbolEnum symbol = RiuQwtSymbol::cycledSymbolStyle(m_curveSetIndex, symbolIndex);
setSymbol(symbol);
}
else
{
const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors();
cvf::Color3ub cycledBaseColor = colors.cycledColor3ub(m_curveSetIndex);
caf::ColorTable hueConstColTable = RiaColorTables::createBrightnessBasedColorTable(cycledBaseColor, m_categoryCount);
setColor(hueConstColTable.cycledColor3f(m_categoryIndex));
RiuQwtSymbol::PointSymbolEnum symbol = RiuQwtSymbol::cycledFilledSymbolStyle(m_curveSetIndex);
setSymbol(symbol);
}
RiuQwtSymbol::PointSymbolEnum symbol = RiuQwtSymbol::cycledFilledSymbolStyle(m_curveSetIndex);
setSymbol(symbol);
}
//--------------------------------------------------------------------------------------------------

View File

@ -40,15 +40,14 @@ class RimGridCrossPlotCurve : public RimPlotCurve
public:
RimGridCrossPlotCurve();
~RimGridCrossPlotCurve() override = default;
void setCategoryInformation(int curveSetIndex, int categoryIndex, int categoryCount);
void setUseContrastColors(bool useContrastColors);
void setCategoryInformation(int curveSetIndex, int categoryIndex);
void setSamples(const std::vector<double>& xValues, const std::vector<double>& yValues);
void updateCurveAppearance() override;
int categoryIndex() const;
protected:
void determineColorAndSymbol();
void determineSymbol();
void updateZoomInParentPlot() override;
void updateLegendsInPlot() override;
QString createCurveAutoName() override;
@ -56,9 +55,7 @@ protected:
void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override;
private:
int m_curveSetIndex;
int m_categoryIndex;
int m_categoryCount;
bool m_useContrastColors;
int m_curveSetIndex;
int m_categoryIndex;
};

View File

@ -18,16 +18,20 @@
#include "RimGridCrossPlotCurveSet.h"
#include "RiaApplication.h"
#include "RiaColorTables.h"
#include "RiaLogging.h"
#include "RigActiveCellInfo.h"
#include "RigActiveCellsResultAccessor.h"
#include "RigCaseCellResultCalculator.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseCrossPlotDataExtractor.h"
#include "RigFormationNames.h"
#include "RigMainGrid.h"
#include "RiuGridCrossQwtPlot.h"
#include "RimCase.h"
#include "RimEclipseCase.h"
#include "RimEclipseView.h"
@ -36,10 +40,14 @@
#include "RimGridCrossPlotCurve.h"
#include "RimGridView.h"
#include "RimProject.h"
#include "RimRegularLegendConfig.h"
#include "RimTools.h"
#include "cafColorTable.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiSliderEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "cvfScalarMapper.h"
#include <QString>
@ -89,9 +97,6 @@ RimGridCrossPlotCurveSet::RimGridCrossPlotCurveSet()
m_categoryProperty.uiCapability()->setUiHidden(true);
m_categoryProperty.uiCapability()->setUiTreeChildrenHidden(true);
CAF_PDM_InitField(&m_categoryBinCount, "CategoryBinCount", 2, "Number of Data Groups", "", "", "");
m_categoryBinCount.uiCapability()->setUiEditorTypeName(caf::PdmUiSliderEditor::uiEditorTypeName());
CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "Name", "", "", "");
m_nameConfig = new RimGridCrossPlotCurveSetNameConfig(this);
m_nameConfig.uiCapability()->setUiTreeHidden(true);
@ -100,6 +105,12 @@ RimGridCrossPlotCurveSet::RimGridCrossPlotCurveSet()
CAF_PDM_InitFieldNoDefault(&m_crossPlotCurves, "CrossPlotCurves", "Curves", "", "", "");
m_crossPlotCurves.uiCapability()->setUiTreeHidden(true);
CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendConfig", "", "", "", "");
m_legendConfig = new RimRegularLegendConfig();
m_legendConfig->setColorRange(RimRegularLegendConfig::CATEGORY);
m_legendConfig->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER);
m_legendConfig->setTickNumberFormat(RimRegularLegendConfig::AUTO);
setDefaults();
}
@ -189,23 +200,36 @@ QString RimGridCrossPlotCurveSet::createAutoName() const
if (m_nameConfig->addCategorization)
{
if (m_categorization() == TIME_CATEGORIZATION)
{
nameTags += QString("Grouped by Time");
}
else if (m_categorization() == FORMATION_CATEGORIZATION)
{
nameTags += QString("Grouped by formations");
}
else if (m_categorization() == RESULT_CATEGORIZATION && m_categoryProperty->hasResult())
{
nameTags += QString("Grouped by %1").arg(m_categoryProperty->resultVariableUiShortName());
}
QString catTitle = categoryTitle();
if (!catTitle.isEmpty()) nameTags += catTitle;
}
return nameTags.join(", ");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotCurveSet::categoryTitle() const
{
if (hasCategoryResult())
{
if (m_categorization() == TIME_CATEGORIZATION)
{
return QString("Time Steps");
}
else if (m_categorization() == FORMATION_CATEGORIZATION)
{
return QString("Formations");
}
else if (m_categorization() == RESULT_CATEGORIZATION && m_categoryProperty->hasResult())
{
return QString("%1").arg(m_categoryProperty->resultVariableUiShortName());
}
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -228,6 +252,14 @@ void RimGridCrossPlotCurveSet::cellFilterViewUpdated()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimRegularLegendConfig* RimGridCrossPlotCurveSet::legendConfig()
{
return m_legendConfig;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -281,12 +313,12 @@ QString RimGridCrossPlotCurveSet::timeStepString() const
//--------------------------------------------------------------------------------------------------
std::vector<QString> RimGridCrossPlotCurveSet::categoryStrings() const
{
std::vector<QString> categoryNames;
for (auto categoryIndexNamePair : m_categoryNames)
std::vector<QString> catStrings;
for (auto curve : m_crossPlotCurves())
{
categoryNames.push_back(categoryIndexNamePair.second);
catStrings.push_back(m_legendConfig->categoryNameFromCategoryValue(curve->categoryIndex()));
}
return categoryNames;
return catStrings;
}
//--------------------------------------------------------------------------------------------------
@ -338,28 +370,87 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot)
std::map<int, cvf::UByteArray> timeStepCellVisibilityMap = calculateCellVisibility(eclipseCase);
updateLegend();
RigEclipseCrossPlotResult result = RigEclipseCrossPlotDataExtractor::extract(
eclipseCase->eclipseCaseData(), m_timeStep(), xAddress, yAddress, m_categorization(), catAddress, m_categoryBinCount, timeStepCellVisibilityMap);
eclipseCase->eclipseCaseData(), m_timeStep(), xAddress, yAddress, m_categorization(), catAddress, timeStepCellVisibilityMap);
m_categoryNames = result.categoryNameMap;
for (const auto& sampleCategory : result.categorySamplesMap)
{
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
curve->setCategoryInformation(indexInPlot(), sampleCategory.first, (int)result.categorySamplesMap.size());
curve->setUseContrastColors(m_categorization() == FORMATION_CATEGORIZATION);
curve->setSamples(sampleCategory.second.first, sampleCategory.second.second);
curve->updateCurveAppearance();
curve->updateUiIconFromPlotSymbol();
createCurves(result);
m_crossPlotCurves.push_back(curve);
}
if (updateParentPlot)
{
triggerPlotNameUpdateAndReplot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& result)
{
if (m_categorization == NO_CATEGORIZATION)
{
const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors();
int colorIndex = indexInPlot();
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
curve->setColor(colors.cycledColor3f(colorIndex));
curve->setCategoryInformation(indexInPlot(), 0);
curve->setSamples(result.xValues, result.yValues);
curve->updateCurveAppearance();
curve->updateUiIconFromPlotSymbol();
m_crossPlotCurves.push_back(curve);
}
else
{
std::map<int, std::pair<std::vector<double>, std::vector<double>>> categorizedResults;
std::vector<double> tickValues;
if (m_categorization == TIME_CATEGORIZATION || m_categorization == FORMATION_CATEGORIZATION)
{
for (size_t i = 0; i < result.xValues.size(); ++i)
{
categorizedResults[result.catValuesDiscrete[i]].first.push_back(result.xValues[i]);
categorizedResults[result.catValuesDiscrete[i]].second.push_back(result.yValues[i]);
}
}
else
{
m_legendConfig->scalarMapper()->majorTickValues(&tickValues);
for (size_t i = 0; i < result.xValues.size(); ++i)
{
auto upperBoundIt = std::lower_bound(tickValues.begin(), tickValues.end(), result.catValuesContinuous[i]);
int upperBoundIndex = static_cast<int>(upperBoundIt - tickValues.begin());
int lowerBoundIndex = std::min((int) tickValues.size() - 2, std::max(0, upperBoundIndex - 1));
categorizedResults[lowerBoundIndex].first.push_back(result.xValues[i]);
categorizedResults[lowerBoundIndex].second.push_back(result.yValues[i]);
}
}
for (auto it = categorizedResults.rbegin(); it != categorizedResults.rend(); ++it)
{
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
curve->setCategoryInformation(indexInPlot(), it->first);
if (m_categorization == RESULT_CATEGORIZATION)
{
curve->setColor(cvf::Color3f(m_legendConfig->scalarMapper()->mapToColor(tickValues[it->first])));
}
else
{
curve->setColor(cvf::Color3f(m_legendConfig->scalarMapper()->mapToColor(it->first)));
}
curve->setSamples(it->second.first, it->second.second);
curve->showLegend(m_crossPlotCurves.empty());
curve->setLegendEntryTitle(createAutoName());
curve->updateCurveAppearance();
curve->updateUiIconFromPlotSymbol();
m_crossPlotCurves.push_back(curve);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -414,7 +505,6 @@ void RimGridCrossPlotCurveSet::defineUiOrdering(QString uiConfigName, caf::PdmUi
{
caf::PdmUiGroup* categoryGroup = uiOrdering.addNewGroup("Data Grouping Property");
m_categoryProperty->uiOrdering(uiConfigName, *categoryGroup);
categoryGroup->add(&m_categoryBinCount);
}
caf::PdmUiGroup* xAxisGroup = uiOrdering.addNewGroup("X-Axis Property");
@ -457,8 +547,25 @@ void RimGridCrossPlotCurveSet::fieldChangedByUi(const caf::PdmFieldHandle* chang
{
loadDataAndUpdate(true);
}
else if (changedField == &m_categorization || changedField == &m_categoryBinCount)
else if (changedField == &m_categorization)
{
if (m_categorization == TIME_CATEGORIZATION)
{
m_legendConfig->setColorRange(RimRegularLegendConfig::NORMAL);
m_legendConfig->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER);
}
else if (m_categorization == FORMATION_CATEGORIZATION)
{
m_legendConfig->setColorRange(RimRegularLegendConfig::CATEGORY);
m_legendConfig->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER);
}
else
{
m_legendConfig->setColorRange(RimRegularLegendConfig::NORMAL);
m_legendConfig->setMappingMode(RimRegularLegendConfig::LINEAR_DISCRETE);
}
loadDataAndUpdate(true);
}
else if (changedField == &m_cellFilterView)
@ -467,6 +574,7 @@ void RimGridCrossPlotCurveSet::fieldChangedByUi(const caf::PdmFieldHandle* chang
}
else if (changedField == &m_isChecked)
{
updateLegend();
triggerPlotNameUpdateAndReplot();
}
}
@ -529,6 +637,96 @@ QList<caf::PdmOptionItemInfo> RimGridCrossPlotCurveSet::calculateValueOptions(co
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurveSet::updateLegend()
{
m_legendConfig->setTitle(categoryTitle());
RimGridCrossPlot* parent;
this->firstAncestorOrThisOfTypeAsserted(parent);
if (parent->qwtPlot())
{
if (m_categorization() != NO_CATEGORIZATION && m_case() && isChecked() && legendConfig()->showLegend())
{
if (m_categorization() == FORMATION_CATEGORIZATION)
{
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(m_case());
RigFormationNames* formationNames = eclipseCase->eclipseCaseData()->activeFormationNames();
const std::vector<QString>& categoryNames = formationNames->formationNames();
m_legendConfig->setNamedCategories(categoryNames);
m_legendConfig->setAutomaticRanges(0, categoryNames.size() - 1, 0, categoryNames.size() - 1);
}
else if (m_categorization() == TIME_CATEGORIZATION)
{
QStringList timeStepNames = m_case->timeStepStrings();
std::vector<QString> categoryNames;
for (auto name : timeStepNames)
{
categoryNames.push_back(name);
}
m_legendConfig->setNamedCategories(categoryNames);
m_legendConfig->setAutomaticRanges(0, categoryNames.size() - 1, 0, categoryNames.size() - 1);
}
else if (m_categoryProperty->eclipseResultAddress().isValid())
{
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(m_case());
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
CVF_ASSERT(caseData);
if (!caseData) return;
RigCaseCellResultsData* cellResultsData = caseData->results(RiaDefines::MATRIX_MODEL);
CVF_ASSERT(cellResultsData);
double globalMin, globalMax;
double globalPosClosestToZero, globalNegClosestToZero;
cellResultsData->minMaxCellScalarValues(m_categoryProperty->eclipseResultAddress(), globalMin, globalMax);
cellResultsData->posNegClosestToZero(
m_categoryProperty->eclipseResultAddress(), globalPosClosestToZero, globalNegClosestToZero);
double localMin, localMax;
double localPosClosestToZero, localNegClosestToZero;
if (m_categoryProperty->hasDynamicResult() && m_timeStep != -1)
{
cellResultsData->minMaxCellScalarValues(m_categoryProperty->eclipseResultAddress(), m_timeStep, localMin, localMax);
cellResultsData->posNegClosestToZero(
m_categoryProperty->eclipseResultAddress(), m_timeStep, localPosClosestToZero, localNegClosestToZero);
}
else
{
localMin = globalMin;
localMax = globalMax;
localPosClosestToZero = globalPosClosestToZero;
localNegClosestToZero = globalNegClosestToZero;
}
CVF_ASSERT(m_legendConfig);
m_legendConfig->setClosestToZeroValues(
globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero);
m_legendConfig->setAutomaticRanges(globalMin, globalMax, localMin, localMax);
}
parent->qwtPlot()->addOrUpdateCurveSetLegend(this);
}
else
{
parent->qwtPlot()->removeCurveSetLegend(this);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGridCrossPlotCurveSet::hasCategoryResult() const
{
return m_categorization == FORMATION_CATEGORIZATION || m_categorization == TIME_CATEGORIZATION || m_categorization == RESULT_CATEGORIZATION;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -547,7 +745,7 @@ void RimGridCrossPlotCurveSet::triggerPlotNameUpdateAndReplot()
void RimGridCrossPlotCurveSet::updateCurveNames(bool applyCaseName,
bool applyAxisVariables,
bool applyTimeStep,
bool applyCategories)
bool applyCategory)
{
for (auto curve : m_crossPlotCurves())
{
@ -568,16 +766,30 @@ void RimGridCrossPlotCurveSet::updateCurveNames(bool applyCaseName,
nameTags += timeStepString();
}
if (applyCategories)
if (applyCategory && m_categorization != NO_CATEGORIZATION)
{
QString categoryName = m_categoryNames[curve->categoryIndex()];
if (!categoryName.isEmpty())
if (m_categorization == RESULT_CATEGORIZATION)
{
nameTags += categoryName;
std::vector<double> tickValues;
m_legendConfig->scalarMapper()->majorTickValues(&tickValues);
size_t catIndex = (size_t) curve->categoryIndex();
double lowerLimit = tickValues[catIndex];
double upperLimit = catIndex + 1u < tickValues.size()
? tickValues[catIndex + 1u] : std::numeric_limits<double>::infinity();
nameTags += QString("%1 [%2, %3]").arg(categoryTitle()).arg(lowerLimit).arg(upperLimit);
}
else
{
nameTags += m_legendConfig->categoryNameFromCategoryValue(curve->categoryIndex());
}
}
curve->setCustomName(nameTags.join(", "));
if (m_categorization != NO_CATEGORIZATION)
{
curve->setLegendEntryTitle(createAutoName());
}
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
}
}
@ -631,15 +843,24 @@ void RimGridCrossPlotCurveSet::defineEditorAttribute(const caf::PdmFieldHandle*
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute)
{
if (field == &m_categoryBinCount)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurveSet::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/)
{
if (m_categorization() != NO_CATEGORIZATION)
{
auto myAttr = dynamic_cast<caf::PdmUiSliderEditorAttribute*>(attribute);
if (myAttr)
{
myAttr->m_minimum = 2;
myAttr->m_maximum = 50;
}
uiTreeOrdering.add(m_legendConfig());
}
for (auto curve : m_crossPlotCurves())
{
uiTreeOrdering.add(curve);
}
uiTreeOrdering.skipRemainingChildren(true);
}
CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurveSetNameConfig, "RimGridCrossPlotCurveSetNameConfig");
@ -655,7 +876,7 @@ RimGridCrossPlotCurveSetNameConfig::RimGridCrossPlotCurveSetNameConfig(RimNameCo
CAF_PDM_InitField(&addCaseName, "AddCaseName", false, "Add Case Name", "", "", "");
CAF_PDM_InitField(&addAxisVariables, "AddAxisVariables", true, "Add Axis Variables", "", "", "");
CAF_PDM_InitField(&addTimestep, "AddTimeStep", false, "Add Time Step", "", "", "");
CAF_PDM_InitField(&addCategorization, "AddCategorization", false, "Add Data Categorization", "", "", "");
CAF_PDM_InitField(&addCategorization, "AddCategorization", true, "Add Data Categorization", "", "", "");
setCustomName("");
}

View File

@ -34,11 +34,13 @@
#include <QList>
#include <map>
struct RigEclipseCrossPlotResult;
class RimCase;
class RimGridCrossPlotCurve;
class RimGridView;
class RimEclipseCase;
class RimEclipseResultDefinition;
class RimRegularLegendConfig;
class QwtPlot;
class QwtPlotCurve;
class QString;
@ -83,8 +85,11 @@ public:
int indexInPlot() const;
QString createAutoName() const override;
QString categoryTitle() const;
void detachAllCurves();
void cellFilterViewUpdated();
RimRegularLegendConfig* legendConfig();
std::vector< RimGridCrossPlotCurve*> curves() const;
@ -93,12 +98,16 @@ public:
QString timeStepString() const;
std::vector<QString> categoryStrings() const;
void updateCurveNames(bool applyCaseName, bool applyAxisVariables, bool applyTimeStep, bool applyCategories);
void updateCurveNames(bool applyCaseName, bool applyAxisVariables, bool applyTimeStep, bool applyCategory);
void updateLegend();
bool hasCategoryResult() const;
protected:
void initAfterRead() override;
void onLoadDataAndUpdate(bool updateParentPlot);
void createCurves(const RigEclipseCrossPlotResult& result);
std::map<int, cvf::UByteArray> calculateCellVisibility(RimEclipseCase* eclipseCase) const;
void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override;
@ -111,6 +120,8 @@ protected:
void setDefaults();
void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override;
void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override;
private:
caf::PdmPtrField<RimCase*> m_case;
caf::PdmField<int> m_timeStep;
@ -119,11 +130,9 @@ private:
caf::PdmChildField<RimEclipseResultDefinition*> m_xAxisProperty;
caf::PdmChildField<RimEclipseResultDefinition*> m_yAxisProperty;
caf::PdmChildField<RimEclipseResultDefinition*> m_categoryProperty;
caf::PdmField<int> m_categoryBinCount;
caf::PdmChildField<RimGridCrossPlotCurveSetNameConfig*> m_nameConfig;
caf::PdmChildArrayField<RimGridCrossPlotCurve*> m_crossPlotCurves;
std::map<int, QString> m_categoryNames;
caf::PdmChildField<RimRegularLegendConfig*> m_legendConfig;
};

View File

@ -96,6 +96,9 @@ RimPlotCurve::RimPlotCurve()
CAF_PDM_InitFieldNoDefault(&m_customCurveName, "CurveDescription", "Custom Name", "", "", "");
m_customCurveName.uiCapability()->setUiHidden(true);
CAF_PDM_InitFieldNoDefault(&m_legendEntryTitle, "LegendDescription", "Legend Name", "", "", "");
m_legendEntryTitle.uiCapability()->setUiHidden(true);
CAF_PDM_InitField(&m_isUsingAutoName, "AutoName", true, "Auto Name", "", "", "");
CAF_PDM_InitField(&m_curveColor, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", "");
@ -213,6 +216,14 @@ void RimPlotCurve::setCustomName(const QString& customName)
m_customCurveName = customName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::setLegendEntryTitle(const QString& legendEntryTitle)
{
m_legendEntryTitle = legendEntryTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -354,9 +365,9 @@ void RimPlotCurve::setCurveVisiblity(bool visible)
}
//--------------------------------------------------------------------------------------------------
///
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle()
void RimPlotCurve::updateCurveName()
{
if (m_isUsingAutoName)
{
@ -367,7 +378,23 @@ void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle()
m_curveName = m_customCurveName;
}
m_qwtPlotCurve->setTitle(m_curveName);
if (!m_legendEntryTitle().isEmpty())
{
m_qwtPlotCurve->setTitle(m_legendEntryTitle);
}
else
{
m_qwtPlotCurve->setTitle(m_curveName);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle()
{
updateCurveName();
updateLegendEntryVisibilityAndPlotLegend();
}
@ -375,17 +402,8 @@ void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle()
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::updateCurveNameNoLegendUpdate()
{
if (m_isUsingAutoName)
{
m_curveName = this->createCurveAutoName();
}
else
{
m_curveName = m_customCurveName;
}
m_qwtPlotCurve->setTitle(m_curveName);
{
updateCurveName();
updateLegendEntryVisibilityNoPlotUpdate();
}

View File

@ -71,12 +71,15 @@ public:
bool isCurveVisible() const;
void setCurveVisiblity(bool visible);
void updateCurveName();
void updateCurveNameAndUpdatePlotLegendAndTitle();
void updateCurveNameNoLegendUpdate();
QString curveName() const { return m_curveName; }
virtual QString curveExportDescription(const RifEclipseSummaryAddress& address = RifEclipseSummaryAddress()) const { return m_curveName; }
void setCustomName(const QString& customName);
void setLegendEntryTitle(const QString& legendEntryTitle);
void updateCurveVisibility(bool updateParentPlot);
void updateLegendEntryVisibilityAndPlotLegend();
void updateLegendEntryVisibilityNoPlotUpdate();
@ -124,7 +127,8 @@ protected:
caf::PdmField<bool> m_showLegend;
QString m_symbolLabel;
caf::PdmField<int> m_symbolSize;
caf::PdmField<QString> m_legendEntryTitle;
caf::PdmField<bool> m_isUsingAutoName;
caf::PdmField<cvf::Color3f> m_curveColor;
caf::PdmField<int> m_curveThickness;

View File

@ -31,6 +31,7 @@
#include "RimEnsembleCurveSetColorManager.h"
#include "RimEclipseView.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGridCrossPlotCurveSet.h"
#include "RimIntersectionCollection.h"
#include "RimStimPlanColors.h"
#include "RimViewLinker.h"
@ -256,6 +257,13 @@ void RimRegularLegendConfig::fieldChangedByUi(const caf::PdmFieldHandle* changed
{
ensembleCurveSet->onLegendDefinitionChanged();
}
RimGridCrossPlotCurveSet* crossPlotCurveSet;
firstAncestorOrThisOfType(crossPlotCurveSet);
if (crossPlotCurveSet)
{
crossPlotCurveSet->loadDataAndUpdate(true);
}
}
//--------------------------------------------------------------------------------------------------
@ -439,6 +447,14 @@ void RimRegularLegendConfig::updateLegend()
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimRegularLegendConfig::setTickNumberFormat(NumberFormatType numberFormat)
{
m_tickNumberFormat = numberFormat;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -861,6 +877,9 @@ QList<caf::PdmOptionItemInfo> RimRegularLegendConfig::calculateValueOptions(cons
this->firstAncestorOrThisOfType(ensembleCurveSet);
if (ensembleCurveSet) hasEnsembleCurveSetParent = true;
RimGridCrossPlotCurveSet* crossPlotCurveSet = nullptr;
this->firstAncestorOrThisOfType(crossPlotCurveSet);
bool isCategoryResult = false;
{
RimEclipseCellColors* eclCellColors = nullptr;
@ -873,7 +892,8 @@ QList<caf::PdmOptionItemInfo> RimRegularLegendConfig::calculateValueOptions(cons
if ( ( eclCellColors && eclCellColors->hasCategoryResult())
|| ( gmCellColors && gmCellColors->hasCategoryResult())
|| ( eclCellEdgColors && eclCellEdgColors->hasCategoryResult())
|| ( ensembleCurveSet && ensembleCurveSet->currentEnsembleParameterType() == EnsembleParameter::TYPE_TEXT) )
|| ( ensembleCurveSet && ensembleCurveSet->currentEnsembleParameterType() == EnsembleParameter::TYPE_TEXT)
|| ( crossPlotCurveSet && crossPlotCurveSet->hasCategoryResult()))
{
isCategoryResult = true;
}
@ -886,8 +906,12 @@ QList<caf::PdmOptionItemInfo> RimRegularLegendConfig::calculateValueOptions(cons
// This is an app enum field, see cafInternalPdmFieldTypeSpecializations.h for the default specialization of this type
std::vector<MappingType> mappingTypes;
mappingTypes.push_back(LINEAR_DISCRETE);
mappingTypes.push_back(LINEAR_CONTINUOUS);
mappingTypes.push_back(LOG10_CONTINUOUS);
if (!crossPlotCurveSet)
{
mappingTypes.push_back(LINEAR_CONTINUOUS);
mappingTypes.push_back(LOG10_CONTINUOUS);
}
mappingTypes.push_back(LOG10_DISCRETE);
if (isCategoryResult)

View File

@ -103,6 +103,8 @@ public:
ColorRangesType colorRange() { return m_colorRangeMode();}
void setMappingMode(MappingType mappingType);
MappingType mappingMode() { return m_mappingMode();}
void setTickNumberFormat(NumberFormatType numberFormat);
void disableAllTimeStepsRange(bool doDisable);
void setAutomaticRanges(double globalMin, double globalMax, double localMin, double localMax);

View File

@ -40,12 +40,9 @@ RigEclipseCrossPlotResult RigEclipseCrossPlotDataExtractor::extract(RigEclipseCa
const RigEclipseResultAddress& yAddress,
RigGridCrossPlotCurveCategorization categorizationType,
const RigEclipseResultAddress& catAddress,
int categoryBinCount,
std::map<int, cvf::UByteArray> timeStepCellVisibilityMap)
{
RigEclipseCrossPlotResult result;
RigEclipseCrossPlotResult::CategorySamplesMap& categorySamplesMap = result.categorySamplesMap;
RigEclipseCrossPlotResult::CategoryNameMap& categoryNameMap = result.categoryNameMap;
RigCaseCellResultsData* resultData = caseData->results(RiaDefines::MATRIX_MODEL);
RigFormationNames* activeFormationNames = resultData->activeFormationNames();
@ -68,7 +65,6 @@ RigEclipseCrossPlotResult RigEclipseCrossPlotDataExtractor::extract(RigEclipseCa
{
resultData->ensureKnownResultLoaded(catAddress);
catValuesForAllSteps = &resultData->cellScalarResults(catAddress);
catBinSorter.reset(new RigEclipseResultBinSorter(*catValuesForAllSteps, categoryBinCount));
}
std::set<int> timeStepsToInclude;
@ -119,61 +115,38 @@ RigEclipseCrossPlotResult RigEclipseCrossPlotDataExtractor::extract(RigEclipseCa
double xValue = xAccessor.cellScalarGlobIdx(globalCellIdx);
double yValue = yAccessor.cellScalarGlobIdx(globalCellIdx);
int category = 0;
if (xValue == HUGE_VAL || yValue == HUGE_VAL) continue;
result.xValues.push_back(xValue);
result.yValues.push_back(yValue);
if (categorizationType == TIME_CATEGORIZATION)
{
category = timeStep;
result.catValuesDiscrete.push_back(timeStep);
}
else if (categorizationType == FORMATION_CATEGORIZATION && activeFormationNames)
else if (categorizationType == FORMATION_CATEGORIZATION)
{
CVF_ASSERT(activeFormationNames);
int category = 0;
size_t i(cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T);
if (mainGrid->ijkFromCellIndex(globalCellIdx, &i, &j, &k))
{
category = activeFormationNames->formationIndexFromKLayerIdx(k);
}
result.catValuesDiscrete.push_back(category);
}
else if (catAccessor && catBinSorter)
else if (categorizationType == RESULT_CATEGORIZATION)
{
double catValue = catAccessor->cellScalarGlobIdx(globalCellIdx);
category = catBinSorter->binNumber(catValue);
}
if (xValue != HUGE_VAL && yValue != HUGE_VAL)
{
categorySamplesMap[category].first.push_back(xValue);
categorySamplesMap[category].second.push_back(yValue);
double catValue = HUGE_VAL;
if (catAccessor)
{
catValue = catAccessor->cellScalarGlobIdx(globalCellIdx);
}
result.catValuesContinuous.push_back(catValue);
}
}
}
}
std::vector<QDateTime> timeStepDates = resultData->timeStepDates();
QString timeFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates(timeStepDates);
for (const auto& sampleCategory : categorySamplesMap)
{
QString categoryName;
if (categorizationType == TIME_CATEGORIZATION && categorySamplesMap.size() > 1u)
{
if (sampleCategory.first < static_cast<int>(timeStepDates.size()))
{
categoryName = RiaQDateTimeTools::toStringUsingApplicationLocale(timeStepDates[sampleCategory.first], timeFormatString);
}
}
else if (categorizationType == FORMATION_CATEGORIZATION && activeFormationNames)
{
categoryName = activeFormationNames->formationNameFromKLayerIdx(sampleCategory.first);
}
else if (catBinSorter)
{
std::pair<double, double> binRange = catBinSorter->binRange(sampleCategory.first);
categoryName = QString("%1 [%2, %3]")
.arg(catAddress.m_resultName)
.arg(binRange.first)
.arg(binRange.second);
}
categoryNameMap.insert(std::make_pair(sampleCategory.first, categoryName));
}
return result;
}

View File

@ -33,13 +33,10 @@ class QString;
struct RigEclipseCrossPlotResult
{
typedef std::pair<std::vector<double>, std::vector<double>> ResultXYValues;
typedef std::map<int, ResultXYValues> CategorySamplesMap;
typedef std::map<int, QString> CategoryNameMap;
CategorySamplesMap categorySamplesMap;
CategoryNameMap categoryNameMap;
std::vector<double> xValues;
std::vector<double> yValues;
std::vector<double> catValuesContinuous;
std::vector<int> catValuesDiscrete;
};
class RigEclipseCrossPlotDataExtractor
@ -51,6 +48,5 @@ public:
const RigEclipseResultAddress& yAddress,
RigGridCrossPlotCurveCategorization categorizationType,
const RigEclipseResultAddress& categoryAddress,
int categoryBinCount,
std::map<int, cvf::UByteArray> timeStepCellVisibilityMap);
};

View File

@ -37,6 +37,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuSelectionChangedHandler.h
${CMAKE_CURRENT_LIST_DIR}/Riu3dSelectionManager.h
${CMAKE_CURRENT_LIST_DIR}/RiuSimpleHistogramWidget.h
${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuTextDialog.h
${CMAKE_CURRENT_LIST_DIR}/RiuTimeStepChangedHandler.h
@ -118,6 +119,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuSelectionChangedHandler.cpp
${CMAKE_CURRENT_LIST_DIR}/Riu3dSelectionManager.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuSimpleHistogramWidget.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuTextDialog.cpp
${CMAKE_CURRENT_LIST_DIR}/RiuTimeStepChangedHandler.cpp
@ -185,6 +187,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuWellLogPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuWellLogTrack.h
${CMAKE_CURRENT_LIST_DIR}/RiuRecentFileActionProvider.h
${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuTofAccumulatedPhaseFractionsPlot.h
${CMAKE_CURRENT_LIST_DIR}/RiuQwtScalePicker.h

View File

@ -0,0 +1,140 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RiuGridCrossQwtPlot.h"
#include "RiuCvfOverlayItemWidget.h"
#include "RiuWidgetDragger.h"
#include "RimGridCrossPlot.h"
#include "RimGridCrossPlotCurveSet.h"
#include "RimRegularLegendConfig.h"
#include "cafTitledOverlayFrame.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuGridCrossQwtPlot::RiuGridCrossQwtPlot(RimViewWindow* ownerViewWindow, QWidget* parent /*= nullptr*/)
: RiuQwtPlot(ownerViewWindow, parent)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuGridCrossQwtPlot::addOrUpdateCurveSetLegend(RimGridCrossPlotCurveSet* curveSetToShowLegendFor)
{
RiuCvfOverlayItemWidget* overlayWidget = nullptr;
auto it = m_legendWidgets.find(curveSetToShowLegendFor);
if (it == m_legendWidgets.end() || it->second == nullptr)
{
overlayWidget = new RiuCvfOverlayItemWidget(this);
new RiuWidgetDragger(overlayWidget);
m_legendWidgets[curveSetToShowLegendFor] = overlayWidget;
}
else
{
overlayWidget = it->second;
}
if (overlayWidget)
{
caf::TitledOverlayFrame* overlayItem = curveSetToShowLegendFor->legendConfig()->titledOverlayFrame();
overlayItem->setRenderSize(overlayItem->preferredSize());
overlayWidget->updateFromOverlayItem(curveSetToShowLegendFor->legendConfig()->titledOverlayFrame());
}
this->updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuGridCrossQwtPlot::removeCurveSetLegend(RimGridCrossPlotCurveSet* curveSetToShowLegendFor)
{
auto it = m_legendWidgets.find(curveSetToShowLegendFor);
if (it != m_legendWidgets.end())
{
if (it->second != nullptr) it->second->deleteLater();
m_legendWidgets.erase(it);
}
this->updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuGridCrossQwtPlot::updateLayout()
{
QwtPlot::updateLayout();
updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuGridCrossQwtPlot::updateLegendLayout()
{
const int spacing = 5;
int startMarginX = this->canvas()->pos().x() + spacing;
int startMarginY = this->canvas()->pos().y() + spacing;
int xpos = startMarginX;
int ypos = startMarginY;
int maxColumnWidth = 0;
RimGridCrossPlot* crossPlot = dynamic_cast<RimGridCrossPlot*>(ownerPlotDefinition());
if (!crossPlot) return;
std::set<QString> legendTypes;
for (RimGridCrossPlotCurveSet* curveSet : crossPlot->curveSets())
{
if (!curveSet->isChecked() || !curveSet->legendConfig()->showLegend()) continue;
auto pairIt = m_legendWidgets.find(curveSet);
if (pairIt != m_legendWidgets.end())
{
RiuCvfOverlayItemWidget* overlayWidget = pairIt->second;
// Show only one copy of each legend type
if (!legendTypes.count(curveSet->categoryTitle()))
{
if (ypos + overlayWidget->height() + spacing > this->canvas()->height())
{
xpos += spacing + maxColumnWidth;
ypos = startMarginY;
maxColumnWidth = 0;
}
overlayWidget->show();
overlayWidget->move(xpos, ypos);
ypos += pairIt->second->height() + spacing;
maxColumnWidth = std::max(maxColumnWidth, pairIt->second->width());
legendTypes.insert(curveSet->categoryTitle());
}
}
}
}

View File

@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RiuInterfaceToViewWindow.h"
#include "RiuQwtPlot.h"
#include "cafPdmPointer.h"
#include <QPointer>
class RimGridCrossPlotCurveSet;
class RiuCvfOverlayItemWidget;
//==================================================================================================
//
//
//
//==================================================================================================
class RiuGridCrossQwtPlot : public RiuQwtPlot
{
Q_OBJECT;
public:
RiuGridCrossQwtPlot(RimViewWindow* ownerViewWindow, QWidget* parent = nullptr);
void addOrUpdateCurveSetLegend(RimGridCrossPlotCurveSet* curveSetToShowLegendFor);
void removeCurveSetLegend(RimGridCrossPlotCurveSet* curveSetToShowLegendFor);
protected:
void updateLayout() override;
void updateLegendLayout();
private:
std::map<caf::PdmPointer<RimGridCrossPlotCurveSet>, QPointer<RiuCvfOverlayItemWidget>> m_legendWidgets;
};

View File

@ -143,7 +143,7 @@ void RiuSummaryQwtPlot::addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet* c
overlayWidget->show();
}
this->updateEnsembleLegendLayout();
this->updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
@ -159,7 +159,7 @@ void RiuSummaryQwtPlot::removeEnsembleCurveSetLegend(RimEnsembleCurveSet* curveS
m_ensembleLegendWidgets.erase(it);
}
this->updateEnsembleLegendLayout();
this->updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
@ -215,13 +215,13 @@ void RiuSummaryQwtPlot::setDefaults()
void RiuSummaryQwtPlot::updateLayout()
{
QwtPlot::updateLayout();
updateEnsembleLegendLayout();
updateLegendLayout();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuSummaryQwtPlot::updateEnsembleLegendLayout()
void RiuSummaryQwtPlot::updateLegendLayout()
{
const int spacing = 5;
int startMarginX = this->canvas()->pos().x() + spacing;

View File

@ -23,15 +23,8 @@
#include "cafPdmPointer.h"
#include "qwt_plot.h"
#include <QPointer>
class QwtInterval;
class QwtPlotZoomer;
class RimGridCrossPlot;
class RimSummaryPlot;
class RimEnsembleCurveSet;
class RiuCvfOverlayItemWidget;
@ -59,7 +52,7 @@ protected:
void setDefaults();
void updateLayout() override;
private:
void updateEnsembleLegendLayout();
void updateLegendLayout();
std::map<caf::PdmPointer<RimEnsembleCurveSet>, QPointer<RiuCvfOverlayItemWidget>> m_ensembleLegendWidgets;
};