#2778 Observed error bars. Display error bars in the same color as data points

This commit is contained in:
Bjørn Erik Jensen
2018-05-25 11:10:03 +02:00
parent 14a5fd4009
commit 403e1759f9
10 changed files with 166 additions and 23 deletions

View File

@@ -159,6 +159,7 @@ void RifCsvUserData::buildTimeStepsAndMappings()
RifEclipseSummaryAddress sumAddress = ci.summaryAddress; RifEclipseSummaryAddress sumAddress = ci.summaryAddress;
m_allResultAddresses.push_back(sumAddress); m_allResultAddresses.push_back(sumAddress);
if (sumAddress.isErrorResult()) m_allErrorAddresses.insert(sumAddress);
m_mapFromAddressToTimeStepIndex[sumAddress] = m_timeSteps.size() - 1; m_mapFromAddressToTimeStepIndex[sumAddress] = m_timeSteps.size() - 1;
m_mapFromAddressToResultIndex[sumAddress] = columnIndex; m_mapFromAddressToResultIndex[sumAddress] = columnIndex;

View File

@@ -143,6 +143,9 @@ RifEclipseSummaryAddress RifEclipseSummaryAddress::importedAddress(const std::st
std::string RifEclipseSummaryAddress::uiText() const std::string RifEclipseSummaryAddress::uiText() const
{ {
std::string text; std::string text;
if (m_isErrorResult) text += "ERR:";
text += m_quantityName; text += m_quantityName;
switch(this->category()) switch(this->category())
{ {
@@ -227,7 +230,7 @@ std::string RifEclipseSummaryAddress::uiText(RifEclipseSummaryAddress::SummaryId
case RifEclipseSummaryAddress::INPUT_LGR_NAME: return lgrName(); case RifEclipseSummaryAddress::INPUT_LGR_NAME: return lgrName();
case RifEclipseSummaryAddress::INPUT_SEGMENT_NUMBER: return std::to_string(wellSegmentNumber()); case RifEclipseSummaryAddress::INPUT_SEGMENT_NUMBER: return std::to_string(wellSegmentNumber());
case RifEclipseSummaryAddress::INPUT_AQUIFER_NUMBER: return std::to_string(aquiferNumber()); case RifEclipseSummaryAddress::INPUT_AQUIFER_NUMBER: return std::to_string(aquiferNumber());
case RifEclipseSummaryAddress::INPUT_VECTOR_NAME: return quantityName() + (m_isErrorResult ? " (err)" : ""); case RifEclipseSummaryAddress::INPUT_VECTOR_NAME: return quantityName();
} }
return ""; return "";
} }

View File

@@ -31,6 +31,17 @@ const std::vector<RifEclipseSummaryAddress>& RifSummaryReaderInterface::allResul
return m_allResultAddresses; return m_allResultAddresses;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifSummaryReaderInterface::errorAddress(const RifEclipseSummaryAddress& resultAddress) const
{
RifEclipseSummaryAddress errAddr = resultAddress;
errAddr.setAsErrorResult();
return m_allErrorAddresses.find(errAddr) != m_allErrorAddresses.end() ? errAddr : RifEclipseSummaryAddress();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -38,6 +38,7 @@ class RifSummaryReaderInterface : public cvf::Object
public: public:
bool hasAddress(const RifEclipseSummaryAddress& resultAddress) const; bool hasAddress(const RifEclipseSummaryAddress& resultAddress) const;
const std::vector<RifEclipseSummaryAddress>& allResultAddresses() const; const std::vector<RifEclipseSummaryAddress>& allResultAddresses() const;
RifEclipseSummaryAddress errorAddress(const RifEclipseSummaryAddress& resultAddress) const;
virtual const std::vector<time_t>& timeSteps(const RifEclipseSummaryAddress& resultAddress) const = 0; virtual const std::vector<time_t>& timeSteps(const RifEclipseSummaryAddress& resultAddress) const = 0;
@@ -50,5 +51,6 @@ public:
static std::vector<QDateTime> fromTimeT(const std::vector<time_t>& timeSteps); static std::vector<QDateTime> fromTimeT(const std::vector<time_t>& timeSteps);
protected: protected:
std::vector<RifEclipseSummaryAddress> m_allResultAddresses; std::vector<RifEclipseSummaryAddress> m_allResultAddresses; // Result and error addresses
std::set<RifEclipseSummaryAddress> m_allErrorAddresses; // Error addresses
}; };

View File

@@ -20,6 +20,7 @@
#include "RimEnsembleCurveSet.h" #include "RimEnsembleCurveSet.h"
#include "RimEnsembleCurveSetCollection.h" #include "RimEnsembleCurveSetCollection.h"
#include "RimSummaryCrossPlot.h"
#include "RimSummaryCurve.h" #include "RimSummaryCurve.h"
#include "RimSummaryCurveCollection.h" #include "RimSummaryCurveCollection.h"
#include "RimSummaryCurveFilter.h" #include "RimSummaryCurveFilter.h"
@@ -110,6 +111,8 @@ RimPlotCurve::RimPlotCurve()
CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Contribute To Legend", "", "", ""); CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Contribute To Legend", "", "", "");
CAF_PDM_InitField(&m_showErrorBars, "ShowErrorBars", true, "Show Error Bars", "", "", "");
m_qwtPlotCurve = new RiuRimQwtPlotCurve(this); m_qwtPlotCurve = new RiuRimQwtPlotCurve(this);
m_parentQwtPlot = nullptr; m_parentQwtPlot = nullptr;
@@ -170,7 +173,11 @@ void RimPlotCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, con
{ {
updateLegendEntryVisibilityAndPlotLegend(); updateLegendEntryVisibilityAndPlotLegend();
} }
else if (changedField == &m_showErrorBars)
{
m_qwtPlotCurve->showErrorBars(m_showErrorBars);
updateCurveAppearance();
}
if (m_parentQwtPlot) m_parentQwtPlot->replot(); if (m_parentQwtPlot) m_parentQwtPlot->replot();
} }
@@ -362,6 +369,9 @@ void RimPlotCurve::appearanceUiOrdering(caf::PdmUiOrdering& uiOrdering)
uiOrdering.add(&m_curveThickness); uiOrdering.add(&m_curveThickness);
uiOrdering.add(&m_lineStyle); uiOrdering.add(&m_lineStyle);
uiOrdering.add(&m_curveInterpolation); uiOrdering.add(&m_curveInterpolation);
if(isCrossPlotCurve()) m_showErrorBars = false;
else uiOrdering.add(&m_showErrorBars);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -464,6 +474,20 @@ void RimPlotCurve::updateCurveAppearance()
m_qwtPlotCurve->setStyle(curveStyle); m_qwtPlotCurve->setStyle(curveStyle);
m_qwtPlotCurve->setSymbol(symbol); m_qwtPlotCurve->setSymbol(symbol);
m_qwtPlotCurve->setSymbolSkipPixelDistance(m_symbolSkipPixelDistance()); m_qwtPlotCurve->setSymbolSkipPixelDistance(m_symbolSkipPixelDistance());
m_qwtPlotCurve->setErrorBarsColor(curveColor);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimPlotCurve::isCrossPlotCurve() const
{
RimSummaryCrossPlot* crossPlot = nullptr;
this->firstAncestorOrThisOfType(crossPlot);
if (crossPlot) return true;
return false;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -101,6 +101,7 @@ public:
void setZOrder(double z); void setZOrder(double z);
virtual void updateCurveAppearance(); virtual void updateCurveAppearance();
bool isCrossPlotCurve() const;
protected: protected:
@@ -135,7 +136,7 @@ protected:
caf::PdmField<cvf::Color3f> m_curveColor; caf::PdmField<cvf::Color3f> m_curveColor;
caf::PdmField<int> m_curveThickness; caf::PdmField<int> m_curveThickness;
caf::PdmField<float> m_symbolSkipPixelDistance; caf::PdmField<float> m_symbolSkipPixelDistance;
caf::PdmField<bool> m_showErrorBars;
caf::PdmField< caf::AppEnum< PointSymbolEnum > > m_pointSymbol; caf::PdmField< caf::AppEnum< PointSymbolEnum > > m_pointSymbol;
caf::PdmField< caf::AppEnum< LineStyleEnum > > m_lineStyle; caf::PdmField< caf::AppEnum< LineStyleEnum > > m_lineStyle;

View File

@@ -457,7 +457,18 @@ void RimSummaryCurve::onLoadDataAndUpdate(bool updateParentPlot)
{ {
if (plot->timeAxisProperties()->timeMode() == RimSummaryTimeAxisProperties::DATE) if (plot->timeAxisProperties()->timeMode() == RimSummaryTimeAxisProperties::DATE)
{ {
m_qwtPlotCurve->setSamplesFromTimeTAndYValues(curveTimeStepsY, curveValuesY, isLogCurve); auto reader = summaryCaseY()->summaryReader();
auto errAddress = reader->errorAddress(summaryAddressY());
if (errAddress.isValid())
{
std::vector<double> errValues;
reader->values(errAddress, &errValues);
m_qwtPlotCurve->setSamplesFromTimeTAndYValues(curveTimeStepsY, curveValuesY, errValues, isLogCurve);
}
else
{
m_qwtPlotCurve->setSamplesFromTimeTAndYValues(curveTimeStepsY, curveValuesY, isLogCurve);
}
} }
else else
{ {
@@ -492,6 +503,8 @@ void RimSummaryCurve::onLoadDataAndUpdate(bool updateParentPlot)
updateZoomInParentPlot(); updateZoomInParentPlot();
m_parentQwtPlot->replot(); m_parentQwtPlot->replot();
} }
m_qwtPlotCurve->showErrorBars(m_showErrorBars);
} }
if (updateParentPlot) updateQwtPlotAxis(); if (updateParentPlot) updateQwtPlotAxis();
@@ -594,18 +607,6 @@ void RimSummaryCurve::appendOptionItemsForSummaryAddresses(QList<caf::PdmOptionI
} }
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryCurve::isCrossPlotCurve() const
{
RimSummaryCrossPlot* crossPlot = nullptr;
this->firstAncestorOrThisOfType(crossPlot);
if (crossPlot) return true;
return false;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -97,8 +97,6 @@ private:
RimSummaryCase* summaryCase, RimSummaryCase* summaryCase,
RimSummaryFilter* summaryFilter); RimSummaryFilter* summaryFilter);
bool isCrossPlotCurve() const;
private: private:
// Y values // Y values
caf::PdmPtrField<RimSummaryCase*> m_yValuesSummaryCase; caf::PdmPtrField<RimSummaryCase*> m_yValuesSummaryCase;

View File

@@ -24,7 +24,9 @@
#include "qwt_date.h" #include "qwt_date.h"
#include "qwt_point_mapper.h" #include "qwt_point_mapper.h"
#include "qwt_painter.h" #include "qwt_painter.h"
#include "qwt_plot_intervalcurve.h"
#include "qwt_scale_map.h"
#include "qwt_interval_symbol.h"
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
@@ -39,6 +41,13 @@ RiuLineSegmentQwtPlotCurve::RiuLineSegmentQwtPlotCurve(const QString &title)
this->setRenderHint(QwtPlotItem::RenderAntialiased, true); this->setRenderHint(QwtPlotItem::RenderAntialiased, true);
m_symbolSkipPixelDistance = 10.0f; m_symbolSkipPixelDistance = 10.0f;
m_errorBars = new QwtPlotIntervalCurve();
m_errorBars->setStyle(QwtPlotIntervalCurve::CurveStyle::NoCurve);
m_errorBars->setSymbol(new QwtIntervalSymbol(QwtIntervalSymbol::Bar));
m_showErrorBars = true;
m_attachedToPlot = nullptr;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -46,20 +55,25 @@ RiuLineSegmentQwtPlotCurve::RiuLineSegmentQwtPlotCurve(const QString &title)
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
RiuLineSegmentQwtPlotCurve::~RiuLineSegmentQwtPlotCurve() RiuLineSegmentQwtPlotCurve::~RiuLineSegmentQwtPlotCurve()
{ {
delete m_errorBars;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setSamplesFromXValuesAndYValues(const std::vector<double>& xValues, const std::vector<double>& yValues, bool keepOnlyPositiveValues) void RiuLineSegmentQwtPlotCurve::setSamplesFromXValuesAndYValues(const std::vector<double>& xValues, const std::vector<double>& yValues, const std::vector<double>& yErrorValues, bool keepOnlyPositiveValues)
{ {
CVF_ASSERT(xValues.size() == yValues.size()); CVF_ASSERT(xValues.size() == yValues.size());
CVF_ASSERT(yErrorValues.empty() || yErrorValues.size() == xValues.size());
bool showErrorBars = m_showErrorBars && !yErrorValues.empty();
QPolygonF points; QPolygonF points;
QVector<QwtIntervalSample> errorIntervals;
std::vector< std::pair<size_t, size_t> > filteredIntervals; std::vector< std::pair<size_t, size_t> > filteredIntervals;
{ {
std::vector<double> filteredYValues; std::vector<double> filteredYValues;
std::vector<double> filteredXValues; std::vector<double> filteredXValues;
std::vector<double> filteredYErrorValues;
{ {
auto intervalsOfValidValues = RigCurveDataTools::calculateIntervalsOfValidValues(yValues, keepOnlyPositiveValues); auto intervalsOfValidValues = RigCurveDataTools::calculateIntervalsOfValidValues(yValues, keepOnlyPositiveValues);
@@ -67,18 +81,36 @@ void RiuLineSegmentQwtPlotCurve::setSamplesFromXValuesAndYValues(const std::vect
RigCurveDataTools::getValuesByIntervals(yValues, intervalsOfValidValues, &filteredYValues); RigCurveDataTools::getValuesByIntervals(yValues, intervalsOfValidValues, &filteredYValues);
RigCurveDataTools::getValuesByIntervals(xValues, intervalsOfValidValues, &filteredXValues); RigCurveDataTools::getValuesByIntervals(xValues, intervalsOfValidValues, &filteredXValues);
if(showErrorBars) RigCurveDataTools::getValuesByIntervals(yErrorValues, intervalsOfValidValues, &filteredYErrorValues);
filteredIntervals = RigCurveDataTools::computePolyLineStartStopIndices(intervalsOfValidValues); filteredIntervals = RigCurveDataTools::computePolyLineStartStopIndices(intervalsOfValidValues);
} }
points.reserve(static_cast<int>(filteredXValues.size())); points.reserve(static_cast<int>(filteredXValues.size()));
errorIntervals.reserve(static_cast<int>(filteredXValues.size()));
for ( size_t i = 0; i < filteredXValues.size(); i++ ) for ( size_t i = 0; i < filteredXValues.size(); i++ )
{ {
points << QPointF(filteredXValues[i], filteredYValues[i]); points << QPointF(filteredXValues[i], filteredYValues[i]);
if (showErrorBars)
{
errorIntervals << QwtIntervalSample(filteredXValues[i], filteredYValues[i] - filteredYErrorValues[i], filteredYValues[i] + filteredYErrorValues[i]);
}
} }
} }
this->setSamples(points); this->setSamples(points);
this->setLineSegmentStartStopIndices(filteredIntervals); this->setLineSegmentStartStopIndices(filteredIntervals);
if(showErrorBars) m_errorBars->setSamples(errorIntervals);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setSamplesFromXValuesAndYValues(const std::vector<double>& xValues, const std::vector<double>& yValues, bool keepOnlyPositiveValues)
{
setSamplesFromXValuesAndYValues(xValues, yValues, std::vector<double>(), keepOnlyPositiveValues);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -86,7 +118,7 @@ void RiuLineSegmentQwtPlotCurve::setSamplesFromXValuesAndYValues(const std::vect
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setSamplesFromDatesAndYValues(const std::vector<QDateTime>& dateTimes, const std::vector<double>& yValues, bool keepOnlyPositiveValues) void RiuLineSegmentQwtPlotCurve::setSamplesFromDatesAndYValues(const std::vector<QDateTime>& dateTimes, const std::vector<double>& yValues, bool keepOnlyPositiveValues)
{ {
setSamplesFromXValuesAndYValues(RiuLineSegmentQwtPlotCurve::fromQDateTime(dateTimes), yValues, keepOnlyPositiveValues); setSamplesFromXValuesAndYValues(RiuLineSegmentQwtPlotCurve::fromQDateTime(dateTimes), yValues, std::vector<double>(), keepOnlyPositiveValues);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -94,7 +126,15 @@ void RiuLineSegmentQwtPlotCurve::setSamplesFromDatesAndYValues(const std::vector
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setSamplesFromTimeTAndYValues(const std::vector<time_t>& dateTimes, const std::vector<double>& yValues, bool keepOnlyPositiveValues) void RiuLineSegmentQwtPlotCurve::setSamplesFromTimeTAndYValues(const std::vector<time_t>& dateTimes, const std::vector<double>& yValues, bool keepOnlyPositiveValues)
{ {
setSamplesFromXValuesAndYValues(RiuLineSegmentQwtPlotCurve::fromTime_t(dateTimes), yValues, keepOnlyPositiveValues); setSamplesFromXValuesAndYValues(RiuLineSegmentQwtPlotCurve::fromTime_t(dateTimes), yValues, std::vector<double>(), keepOnlyPositiveValues);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setSamplesFromTimeTAndYValues(const std::vector<time_t>& dateTimes, const std::vector<double>& yValues, const std::vector<double>& yErrorValues, bool keepOnlyPositiveValues)
{
setSamplesFromXValuesAndYValues(RiuLineSegmentQwtPlotCurve::fromTime_t(dateTimes), yValues, yErrorValues, keepOnlyPositiveValues);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -201,6 +241,46 @@ void RiuLineSegmentQwtPlotCurve::setSymbolSkipPixelDistance(float distance)
m_symbolSkipPixelDistance = distance >= 0.0f ? distance: 0.0f; m_symbolSkipPixelDistance = distance >= 0.0f ? distance: 0.0f;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::attach(QwtPlot *plot)
{
QwtPlotItem::attach(plot);
if(m_showErrorBars) m_errorBars->attach(plot);
m_attachedToPlot = plot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::detach()
{
QwtPlotItem::detach();
m_errorBars->detach();
m_attachedToPlot = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::showErrorBars(bool show)
{
m_showErrorBars = show;
if (m_showErrorBars && m_attachedToPlot) m_errorBars->attach(m_attachedToPlot);
else m_errorBars->detach();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve::setErrorBarsColor(QColor color)
{
QwtIntervalSymbol* newSymbol = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
newSymbol->setPen(QPen(color));
m_errorBars->setSymbol(newSymbol);
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -20,6 +20,9 @@
#pragma once #pragma once
#include "qwt_plot_curve.h" #include "qwt_plot_curve.h"
#include "qwt_plot_intervalcurve.h"
class RiuErrorBarsQwtPlotCurve;
//================================================================================================== //==================================================================================================
// //
@@ -50,6 +53,11 @@ public:
void setSamplesFromXValuesAndYValues(const std::vector<double>& xValues, void setSamplesFromXValuesAndYValues(const std::vector<double>& xValues,
const std::vector<double>& yValues, const std::vector<double>& yValues,
bool keepOnlyPositiveValues); bool keepOnlyPositiveValues);
void setSamplesFromXValuesAndYValues(const std::vector<double>& xValues,
const std::vector<double>& yValues,
const std::vector<double>& yErrorValues,
bool keepOnlyPositiveValues);
void setSamplesFromDatesAndYValues(const std::vector<QDateTime>& dateTimes, void setSamplesFromDatesAndYValues(const std::vector<QDateTime>& dateTimes,
const std::vector<double>& yValues, const std::vector<double>& yValues,
@@ -59,10 +67,20 @@ public:
const std::vector<double>& yValues, const std::vector<double>& yValues,
bool keepOnlyPositiveValues); bool keepOnlyPositiveValues);
void setSamplesFromTimeTAndYValues(const std::vector<time_t>& dateTimes,
const std::vector<double>& yValues,
const std::vector<double>& yErrorValues,
bool keepOnlyPositiveValues);
void setLineSegmentStartStopIndices(const std::vector< std::pair<size_t, size_t> >& lineSegmentStartStopIndices); void setLineSegmentStartStopIndices(const std::vector< std::pair<size_t, size_t> >& lineSegmentStartStopIndices);
void setSymbolSkipPixelDistance(float distance); void setSymbolSkipPixelDistance(float distance);
void attach(QwtPlot *plot);
void detach();
void showErrorBars(bool show);
void setErrorBarsColor(QColor color);
protected: protected:
virtual void drawCurve(QPainter* p, int style, virtual void drawCurve(QPainter* p, int style,
const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QwtScaleMap& xMap, const QwtScaleMap& yMap,
@@ -83,4 +101,8 @@ private:
private: private:
std::vector< std::pair<size_t, size_t> > m_polyLineStartStopIndices; std::vector< std::pair<size_t, size_t> > m_polyLineStartStopIndices;
float m_symbolSkipPixelDistance; float m_symbolSkipPixelDistance;
bool m_showErrorBars;
QwtPlotIntervalCurve* m_errorBars;
QwtPlot* m_attachedToPlot;
}; };