#4185 Implement data export for Grid Cross Plot

This commit is contained in:
Gaute Lindkvist
2019-03-11 11:39:23 +01:00
parent 6008b8a45d
commit e72f57072c
15 changed files with 432 additions and 134 deletions

View File

@@ -17,6 +17,7 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RimGridCrossPlot.h"
#include "RifEclipseDataTableFormatter.h"
#include "RiuGridCrossQwtPlot.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuQwtPlotTools.h"
@@ -28,6 +29,7 @@
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "cafProgressInfo.h"
#include "cvfAssert.h"
#include "qwt_legend.h"
@@ -520,6 +522,45 @@ void RimGridCrossPlot::swapAllAxisProperties()
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlot::asciiTitleForPlotExport(int curveSetIndex) const
{
if ((size_t)curveSetIndex < m_crossPlotCurveSets.size())
{
return m_crossPlotCurveSets[curveSetIndex]->createAutoName();
}
return "Data invalid";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlot::asciiDataForPlotExport(int curveSetIndex) const
{
if ((size_t)curveSetIndex < m_crossPlotCurveSets.size())
{
QString asciiData;
QTextStream stringStream(&asciiData);
RifEclipseDataTableFormatter formatter(stringStream);
formatter.setCommentPrefix("");
formatter.setTableRowPrependText("");
formatter.setTableRowLineAppendText("");
formatter.setColumnSpacing(3);
m_crossPlotCurveSets[curveSetIndex]->exportFormattedData(formatter);
formatter.tableCompleted();
return asciiData;
}
else
{
return "Data invalid and may have been deleted.";
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -70,8 +70,10 @@ public:
void performAutoNameUpdate() override;
void updateCurveNamesAndPlotTitle();
void swapAllAxisProperties();
QString asciiTitleForPlotExport(int curveSetIndex) const;
QString asciiDataForPlotExport(int curveSetIndex) const;
RiuGridCrossQwtPlot* qwtPlot() const;
public:
// Rim2dPlotInterface overrides
void updateAxisScaling() override;
@@ -112,6 +114,7 @@ private:
caf::PdmChildArrayField<RimGridCrossPlotCurveSet*> m_crossPlotCurveSets;
QPointer<RiuGridCrossQwtPlot> m_qwtPlot;
};

View File

@@ -42,6 +42,7 @@ public:
~RimGridCrossPlotCurve() override = default;
void setGroupingInformation(int curveSetIndex, int groupIndex);
void setSamples(const std::vector<double>& xValues, const std::vector<double>& yValues);
void updateCurveAppearance() override;
int groupIndex() const;

View File

@@ -21,6 +21,8 @@
#include "RiaColorTables.h"
#include "RiaLogging.h"
#include "RifEclipseDataTableFormatter.h"
#include "RigActiveCellInfo.h"
#include "RigActiveCellsResultAccessor.h"
#include "RigCaseCellResultCalculator.h"
@@ -44,11 +46,14 @@
#include "RimRegularLegendConfig.h"
#include "RimTools.h"
#include "cafCategoryMapper.h"
#include "cafColorTable.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiSliderEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "cafProgressInfo.h"
#include "cvfScalarMapper.h"
#include "cvfqtUtils.h"
#include <QString>
@@ -210,7 +215,11 @@ QString RimGridCrossPlotCurveSet::createAutoName() const
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotCurveSet::groupTitle() const
{
return QString("Grouping by %1").arg(groupParameter());
if (m_grouping != NO_GROUPING)
{
return QString("Grouped by %1").arg(groupParameter());
}
return "";
}
//--------------------------------------------------------------------------------------------------
@@ -410,6 +419,7 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot)
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& result)
{
m_groupedResults.clear();
if (!groupingEnabled())
{
const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors();
@@ -422,11 +432,10 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res
curve->updateCurveAppearance();
curve->updateUiIconFromPlotSymbol();
m_crossPlotCurves.push_back(curve);
m_groupedResults[0] = result;
}
else
{
std::map<int, std::pair<std::vector<double>, std::vector<double>>> groupedResults;
std::vector<double> tickValues;
if (groupingByCategoryResult())
@@ -438,8 +447,13 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res
? static_cast<int>(result.groupValuesContinuous[i])
: result.groupValuesDiscrete[i];
groupedResults[categoryNum].first.push_back(result.xValues[i]);
groupedResults[categoryNum].second.push_back(result.yValues[i]);
m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]);
m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]);
if (!result.groupValuesContinuous.empty())
m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]);
if (!result.groupValuesDiscrete.empty())
m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]);
}
}
else
@@ -450,13 +464,17 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res
{
auto upperBoundIt = std::lower_bound(tickValues.begin(), tickValues.end(), result.groupValuesContinuous[i]);
int upperBoundIndex = static_cast<int>(upperBoundIt - tickValues.begin());
int lowerBoundIndex = std::min((int) tickValues.size() - 2, std::max(0, upperBoundIndex - 1));
groupedResults[lowerBoundIndex].first.push_back(result.xValues[i]);
groupedResults[lowerBoundIndex].second.push_back(result.yValues[i]);
int categoryNum = std::min((int) tickValues.size() - 2, std::max(0, upperBoundIndex - 1));
m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]);
m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]);
if (!result.groupValuesContinuous.empty())
m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]);
if (!result.groupValuesDiscrete.empty())
m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]);
}
}
for (auto it = groupedResults.rbegin(); it != groupedResults.rend(); ++it)
for (auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it)
{
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
curve->setGroupingInformation(indexInPlot(), it->first);
@@ -468,9 +486,9 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res
{
curve->setColor(cvf::Color3f(legendConfig()->scalarMapper()->mapToColor(tickValues[it->first])));
}
curve->setSamples(it->second.first, it->second.second);
curve->setSamples(it->second.xValues, it->second.yValues);
curve->showLegend(m_crossPlotCurves.empty());
curve->setLegendEntryTitle(createAutoName());
curve->setLegendEntryText(createAutoName());
curve->updateCurveAppearance();
curve->updateUiIconFromPlotSymbol();
m_crossPlotCurves.push_back(curve);
@@ -478,6 +496,26 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotCurveSet::createGroupName(size_t groupIndex) const
{
if (groupingByCategoryResult())
{
return legendConfig()->categoryNameFromCategoryValue(groupIndex);
}
else
{
std::vector<double> tickValues;
legendConfig()->scalarMapper()->majorTickValues(&tickValues);
double lowerLimit = tickValues[groupIndex];
double upperLimit =
groupIndex + 1u < tickValues.size() ? tickValues[groupIndex + 1u] : std::numeric_limits<double>::infinity();
return QString("%1 [%2, %3]").arg(groupParameter()).arg(lowerLimit).arg(upperLimit);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -786,6 +824,56 @@ void RimGridCrossPlotCurveSet::swapAxisProperties(bool updatePlot)
loadDataAndUpdate(updatePlot);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridCrossPlotCurveSet::exportFormattedData(RifEclipseDataTableFormatter& formatter) const
{
if (m_groupedResults.empty())
return;
if (m_grouping != NO_GROUPING)
{
std::vector<RifEclipseOutputTableColumn> header = {RifEclipseOutputTableColumn("X"),
RifEclipseOutputTableColumn("Y"),
RifEclipseOutputTableColumn("Group Index"),
RifEclipseOutputTableColumn("Group Description")};
formatter.header(header);
}
else
{
std::vector<RifEclipseOutputTableColumn> header = {RifEclipseOutputTableColumn("X"), RifEclipseOutputTableColumn("Y")};
formatter.header(header);
}
caf::ProgressInfo progress(m_groupedResults.size(), "Gathering Data Points");
for (auto it = m_groupedResults.begin(); it != m_groupedResults.end(); ++it)
{
int groupIndex = it->first;
RigEclipseCrossPlotResult res = it->second;
for (size_t i = 0; i < it->second.xValues.size(); ++i)
{
if (m_grouping() == NO_GROUPING)
{
formatter.add(res.xValues[i]);
formatter.add(res.yValues[i]);
}
else
{
QString groupName = createGroupName(groupIndex);
formatter.add(res.xValues[i]);
formatter.add(res.yValues[i]);
formatter.add(groupIndex);
formatter.add(groupName);
}
formatter.rowCompleted();
}
progress.incrementProgress();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -809,29 +897,17 @@ void RimGridCrossPlotCurveSet::updateCurveNames(size_t curveSetIndex, size_t cur
if (curveSetName.isEmpty())
{
if (curveSetCount > 1u)
curveSetName = QString("Curve #%1").arg(curveSetIndex + 1);
curveSetName = QString("Curve Set #%1").arg(curveSetIndex + 1);
else
curveSetName = "Curve";
curveSetName = "Curve Set";
}
auto curve = m_crossPlotCurves[i];
if (groupingEnabled())
{
if (groupingByCategoryResult())
{
curve->setCustomName(legendConfig()->categoryNameFromCategoryValue(curve->groupIndex()));
}
else
{
std::vector<double> tickValues;
legendConfig()->scalarMapper()->majorTickValues(&tickValues);
size_t catIndex = (size_t) curve->groupIndex();
double lowerLimit = tickValues[catIndex];
double upperLimit = catIndex + 1u < tickValues.size()
? tickValues[catIndex + 1u] : std::numeric_limits<double>::infinity();
curve->setCustomName(QString("%1 [%2, %3]").arg(groupParameter()).arg(lowerLimit).arg(upperLimit));
}
curve->setLegendEntryTitle(curveSetName);
QString curveGroupName = createGroupName(curve->groupIndex());
curve->setCustomName(curveGroupName);
curve->setLegendEntryText(curveSetName);
}
else
{

View File

@@ -18,6 +18,7 @@
#pragma once
#include "RigGridCrossPlotCurveGrouping.h"
#include "RigEclipseCrossPlotDataExtractor.h"
#include "RimCheckableNamedObject.h"
#include "RimNameConfig.h"
@@ -34,7 +35,7 @@
#include <QList>
#include <map>
struct RigEclipseCrossPlotResult;
class RifEclipseDataTableFormatter;
class RimCase;
class RimGridCrossPlotCurve;
class RimGridView;
@@ -114,12 +115,14 @@ public:
bool groupingByCategoryResult() const;
bool groupingEnabled() const;
void swapAxisProperties(bool updatePlot);
void exportFormattedData(RifEclipseDataTableFormatter& formatter) const;
protected:
void initAfterRead() override;
void onLoadDataAndUpdate(bool updateParentPlot);
void createCurves(const RigEclipseCrossPlotResult& result);
QString createGroupName(size_t curveIndex) const;
std::map<int, cvf::UByteArray> calculateCellVisibility(RimEclipseCase* eclipseCase) const;
@@ -137,6 +140,7 @@ protected:
bool hasMultipleTimeSteps() const;
private:
caf::PdmPtrField<RimCase*> m_case;
caf::PdmField<int> m_timeStep;
caf::PdmPtrField<RimGridView*> m_cellFilterView;
@@ -148,4 +152,6 @@ private:
caf::PdmChildField<RimGridCrossPlotCurveSetNameConfig*> m_nameConfig;
caf::PdmChildArrayField<RimGridCrossPlotCurve*> m_crossPlotCurves;
std::map<int, RigEclipseCrossPlotResult> m_groupedResults;
};

View File

@@ -96,8 +96,8 @@ 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_InitFieldNoDefault(&m_legendEntryText, "LegendDescription", "Legend Name", "", "", "");
m_legendEntryText.uiCapability()->setUiHidden(true);
CAF_PDM_InitField(&m_isUsingAutoName, "AutoName", true, "Auto Name", "", "", "");
@@ -219,9 +219,21 @@ void RimPlotCurve::setCustomName(const QString& customName)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::setLegendEntryTitle(const QString& legendEntryTitle)
QString RimPlotCurve::legendEntryText() const
{
m_legendEntryTitle = legendEntryTitle;
if (!m_legendEntryText().isEmpty())
{
return m_legendEntryText;
}
return m_customCurveName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::setLegendEntryText(const QString& legendEntryText)
{
m_legendEntryText = legendEntryText;
}
//--------------------------------------------------------------------------------------------------
@@ -378,9 +390,9 @@ void RimPlotCurve::updateCurveName()
m_curveName = m_customCurveName;
}
if (!m_legendEntryTitle().isEmpty())
if (!m_legendEntryText().isEmpty())
{
m_qwtPlotCurve->setTitle(m_legendEntryTitle);
m_qwtPlotCurve->setTitle(m_legendEntryText);
}
else
{

View File

@@ -78,7 +78,8 @@ public:
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);
QString legendEntryText() const;
void setLegendEntryText(const QString& legendEntryText);
void updateCurveVisibility(bool updateParentPlot);
void updateLegendEntryVisibilityAndPlotLegend();
@@ -127,7 +128,7 @@ protected:
caf::PdmField<bool> m_showLegend;
QString m_symbolLabel;
caf::PdmField<int> m_symbolSize;
caf::PdmField<QString> m_legendEntryTitle;
caf::PdmField<QString> m_legendEntryText;
caf::PdmField<bool> m_isUsingAutoName;
caf::PdmField<cvf::Color3f> m_curveColor;