2020-02-12 09:48:25 -06:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright (C) 2020 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 "RiuGroupedBarChartBuilder.h"
|
|
|
|
|
|
|
|
#include "RiaColorTables.h"
|
|
|
|
|
|
|
|
#include "qwt_column_symbol.h"
|
|
|
|
#include "qwt_legend.h"
|
|
|
|
#include "qwt_painter.h"
|
|
|
|
#include "qwt_plot.h"
|
|
|
|
#include "qwt_plot_barchart.h"
|
2020-02-17 03:40:18 -06:00
|
|
|
#include "qwt_plot_scaleitem.h"
|
2020-02-12 09:48:25 -06:00
|
|
|
#include "qwt_scale_draw.h"
|
2020-02-17 03:40:18 -06:00
|
|
|
#include "qwt_scale_widget.h"
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// Overriding to avoid one-pixel overlap of bars.
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
class RiuAvoidPixelOverlapColumnSymbol : public QwtColumnSymbol
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RiuAvoidPixelOverlapColumnSymbol( Style style )
|
|
|
|
: QwtColumnSymbol( style )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void draw( QPainter* painter, const QwtColumnRect& rect ) const override
|
|
|
|
{
|
|
|
|
painter->save();
|
|
|
|
|
|
|
|
switch ( this->style() )
|
|
|
|
{
|
|
|
|
case QwtColumnSymbol::Box:
|
|
|
|
{
|
|
|
|
switch ( this->frameStyle() )
|
|
|
|
{
|
|
|
|
case QwtColumnSymbol::NoFrame:
|
|
|
|
{
|
|
|
|
QRectF r = rect.toRect();
|
|
|
|
if ( QwtPainter::roundingAlignment( painter ) )
|
|
|
|
{
|
|
|
|
r.setLeft( qRound( r.left() ) );
|
|
|
|
r.setRight( qRound( r.right() ) );
|
|
|
|
r.setTop( qRound( r.top() ) );
|
|
|
|
r.setBottom( qRound( r.bottom() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
painter->fillRect( r,
|
|
|
|
this->palette()
|
|
|
|
.window() ); // This line here is the difference. Qwt adds a 1 to width and height.
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
QwtColumnSymbol::drawBox( painter, rect );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// Overridden ScaleDraw to add labels for med and min ticks, and to add newlines to get the
|
|
|
|
/// tick texts on different height according to tick level
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
class RiuBarChartScaleDraw : public QwtScaleDraw
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RiuBarChartScaleDraw( const std::map<double, std::pair<QwtScaleDiv::TickType, QString>>& posTickTypeAndTexts )
|
|
|
|
: m_posTickTypeAndTexts( posTickTypeAndTexts )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Override to add new lines to the labels according to the tick level
|
|
|
|
|
|
|
|
QwtText label( double v ) const override
|
|
|
|
{
|
|
|
|
auto posTypeTextPairIt = m_posTickTypeAndTexts.find( v );
|
|
|
|
if ( posTypeTextPairIt != m_posTickTypeAndTexts.end() )
|
|
|
|
{
|
|
|
|
if ( this->alignment() == BottomScale )
|
|
|
|
{
|
|
|
|
if ( posTypeTextPairIt->second.first == QwtScaleDiv::MediumTick )
|
|
|
|
{
|
|
|
|
return "\n" + posTypeTextPairIt->second.second;
|
|
|
|
}
|
|
|
|
else if ( posTypeTextPairIt->second.first == QwtScaleDiv::MajorTick )
|
|
|
|
{
|
|
|
|
return "\n\n" + posTypeTextPairIt->second.second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return posTypeTextPairIt->second.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( this->alignment() == LeftScale )
|
|
|
|
{
|
|
|
|
if ( posTypeTextPairIt->second.first == QwtScaleDiv::MediumTick )
|
|
|
|
{
|
|
|
|
return posTypeTextPairIt->second.second + " ";
|
|
|
|
}
|
|
|
|
else if ( posTypeTextPairIt->second.first == QwtScaleDiv::MajorTick )
|
|
|
|
{
|
|
|
|
return posTypeTextPairIt->second.second + " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return posTypeTextPairIt->second.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return posTypeTextPairIt->second.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return "X"; // Just for debugging
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override to draw text labels at medium and minor ticks also
|
|
|
|
|
|
|
|
void draw( QPainter* painter, const QPalette& palette ) const override
|
|
|
|
{
|
|
|
|
QwtScaleDraw::draw( painter, palette );
|
|
|
|
|
|
|
|
if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
|
|
|
|
{
|
|
|
|
painter->save();
|
|
|
|
painter->setPen( palette.color( QPalette::Text ) );
|
|
|
|
|
|
|
|
const QList<double>& mediumTicks = scaleDiv().ticks( QwtScaleDiv::MediumTick );
|
|
|
|
|
|
|
|
for ( int i = 0; i < mediumTicks.count(); i++ )
|
|
|
|
{
|
|
|
|
const double v = mediumTicks[i];
|
|
|
|
if ( scaleDiv().contains( v ) ) drawLabel( painter, mediumTicks[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<double>& minorTicks = scaleDiv().ticks( QwtScaleDiv::MinorTick );
|
|
|
|
|
|
|
|
for ( int i = 0; i < minorTicks.count(); i++ )
|
|
|
|
{
|
|
|
|
const double v = minorTicks[i];
|
|
|
|
if ( scaleDiv().contains( v ) ) drawLabel( painter, minorTicks[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::map<double, std::pair<QwtScaleDiv::TickType, QString>> m_posTickTypeAndTexts;
|
|
|
|
bool m_hasMinorTickText;
|
|
|
|
bool m_hasMediumTickText;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void drawBackbone( QPainter* ) const override {}
|
|
|
|
};
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
RiuGroupedBarChartBuilder::RiuGroupedBarChartBuilder( Qt::Orientation orientation )
|
|
|
|
: m_orientation( orientation )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
void RiuGroupedBarChartBuilder::addBarEntry( const QString& majorTickText,
|
|
|
|
const QString& midTickText,
|
|
|
|
const QString& minTickText,
|
|
|
|
const double sortValue,
|
|
|
|
const QString& legendText,
|
2020-02-17 03:40:18 -06:00
|
|
|
const QString& barText,
|
2020-02-12 09:48:25 -06:00
|
|
|
const double value )
|
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
m_sortedBarEntries.insert(
|
|
|
|
BarEntry( majorTickText, midTickText, minTickText, sortValue, legendText, barText, value ) );
|
2020-02-12 09:48:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
void RiuGroupedBarChartBuilder::addBarChartToPlot( QwtPlot* plot )
|
|
|
|
{
|
|
|
|
const double majGroupSpacing = 1.6;
|
|
|
|
const double midGroupSpacing = 0.5;
|
|
|
|
const double minGroupSpacing = 0.2;
|
|
|
|
|
|
|
|
std::set<QString> majTickTexts;
|
|
|
|
std::set<QString> midTickTexts;
|
|
|
|
std::set<QString> minTickTexts;
|
|
|
|
|
|
|
|
double currentBarPosition = 1.0;
|
|
|
|
double currentMajGroupStartPos = 1.0;
|
|
|
|
double currentMidGroupStartPos = 1.0;
|
|
|
|
double currentMinGroupStartPos = 1.0;
|
|
|
|
|
|
|
|
QString previousMajText;
|
|
|
|
QString previousMidText;
|
|
|
|
QString previousMinText;
|
|
|
|
|
|
|
|
std::map<QString, QVector<QPointF>> legendToBarPointsMap;
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
std::map<double, std::pair<QwtScaleDiv::TickType, QString>> groupPositionedAxisTexts;
|
|
|
|
std::map<double, std::pair<QwtScaleDiv::TickType, QString>> positionedBarLabels;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
QList<double> majTickPositions;
|
|
|
|
QList<double> midTickPositions;
|
|
|
|
QList<double> minTickPositions;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
auto addGroupTickText = [&]( double groupStartPos, QString tickText, QList<double>& groupTickPosList )
|
|
|
|
{
|
|
|
|
if( tickText.isEmpty() ) return;
|
|
|
|
|
|
|
|
double tickPos = midPoint( groupStartPos, currentBarPosition );
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
QwtScaleDiv::TickType ttyp = (&groupTickPosList == &majTickPositions ) ? QwtScaleDiv::MajorTick
|
|
|
|
: ( &groupTickPosList == &midTickPositions ) ? QwtScaleDiv::MediumTick
|
2020-02-14 09:27:44 -06:00
|
|
|
: QwtScaleDiv::MinorTick;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
// Make sure we do not get ticks of different level exactly at the same spot,
|
|
|
|
// so that the drawing is able to distinguish
|
|
|
|
|
|
|
|
if( ttyp == QwtScaleDiv::MinorTick ) tickPos += 2e-4;
|
|
|
|
if( ttyp == QwtScaleDiv::MediumTick ) tickPos += 1e-4;
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
groupPositionedAxisTexts[tickPos] = { ttyp, tickText };
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
groupTickPosList.push_back( tickPos );
|
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
// Loop over entries, calculate tick positions and bar positions as we go
|
|
|
|
|
2020-02-12 09:48:25 -06:00
|
|
|
for ( const BarEntry& barDef : m_sortedBarEntries )
|
|
|
|
{
|
2020-02-14 09:27:44 -06:00
|
|
|
bool hasAnyMajTics = !majTickTexts.empty();
|
2020-02-12 09:48:25 -06:00
|
|
|
auto majInsertResult = majTickTexts.insert( barDef.m_majTickText );
|
|
|
|
bool isStartingNewMajGroup = majInsertResult.second;
|
2020-02-14 09:27:44 -06:00
|
|
|
bool isFinishingMajGroup = isStartingNewMajGroup && hasAnyMajTics;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
if ( isFinishingMajGroup )
|
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
addGroupTickText( currentMajGroupStartPos, previousMajText, majTickPositions );
|
|
|
|
addGroupTickText( currentMidGroupStartPos, previousMidText, midTickPositions );
|
|
|
|
addGroupTickText( currentMinGroupStartPos, previousMinText, minTickPositions );
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
currentBarPosition += majGroupSpacing;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isStartingNewMajGroup )
|
|
|
|
{
|
|
|
|
previousMajText = barDef.m_majTickText;
|
|
|
|
previousMidText = "";
|
|
|
|
previousMinText = "";
|
|
|
|
|
|
|
|
midTickTexts.clear();
|
|
|
|
minTickTexts.clear();
|
|
|
|
|
|
|
|
currentMajGroupStartPos = currentBarPosition;
|
|
|
|
currentMidGroupStartPos = currentBarPosition;
|
|
|
|
currentMinGroupStartPos = currentBarPosition;
|
|
|
|
}
|
|
|
|
|
2020-02-14 09:27:44 -06:00
|
|
|
bool hasAnyMidTics = !midTickTexts.empty();
|
2020-02-12 09:48:25 -06:00
|
|
|
auto midInsertResult = midTickTexts.insert( barDef.m_midTickText );
|
|
|
|
bool isStartingNewMidGroup = midInsertResult.second;
|
2020-02-14 09:27:44 -06:00
|
|
|
bool isFinishingMidGroup = isStartingNewMidGroup && hasAnyMidTics;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
if ( isFinishingMidGroup )
|
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
addGroupTickText( currentMidGroupStartPos, previousMidText, midTickPositions );
|
|
|
|
addGroupTickText( currentMinGroupStartPos, previousMinText, minTickPositions );
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
currentBarPosition += midGroupSpacing;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isStartingNewMidGroup )
|
|
|
|
{
|
|
|
|
previousMidText = barDef.m_midTickText;
|
|
|
|
previousMinText = "";
|
|
|
|
|
|
|
|
minTickTexts.clear();
|
|
|
|
|
|
|
|
currentMidGroupStartPos = currentBarPosition;
|
|
|
|
currentMinGroupStartPos = currentBarPosition;
|
|
|
|
}
|
|
|
|
|
2020-02-14 09:27:44 -06:00
|
|
|
bool hasAnyMinTics = !minTickTexts.empty();
|
2020-02-12 09:48:25 -06:00
|
|
|
auto minInsertResult = minTickTexts.insert( barDef.m_minTickText );
|
|
|
|
bool isStartingNewMinGroup = minInsertResult.second;
|
2020-02-14 09:27:44 -06:00
|
|
|
bool isFinishingMinGroup = minInsertResult.second && hasAnyMinTics;
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
if ( isFinishingMinGroup )
|
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
addGroupTickText( currentMinGroupStartPos, previousMinText, minTickPositions );
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
currentBarPosition += minGroupSpacing;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isStartingNewMinGroup )
|
|
|
|
{
|
|
|
|
previousMinText = barDef.m_minTickText;
|
|
|
|
currentMinGroupStartPos = currentBarPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert bar value in correct set of colored bars
|
|
|
|
|
|
|
|
auto legendToBarPointsPair = legendToBarPointsMap.find( barDef.m_legendText );
|
|
|
|
|
|
|
|
QVector<QPointF>* barPoints = nullptr;
|
|
|
|
|
|
|
|
if ( legendToBarPointsPair == legendToBarPointsMap.end() )
|
|
|
|
{
|
|
|
|
barPoints = &( legendToBarPointsMap[barDef.m_legendText] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
barPoints = &( legendToBarPointsPair->second );
|
|
|
|
}
|
|
|
|
|
|
|
|
barPoints->push_back( {currentBarPosition, barDef.m_value} );
|
2020-02-17 03:40:18 -06:00
|
|
|
if ( !barDef.m_barText.isEmpty() )
|
|
|
|
{
|
|
|
|
positionedBarLabels[currentBarPosition] = {QwtScaleDiv::MinorTick, barDef.m_barText};
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
|
|
|
|
// Increment the bar position for the next bar
|
|
|
|
currentBarPosition += 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add group tick texts for the last groups
|
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
if ( !previousMajText.isEmpty() )
|
|
|
|
{
|
|
|
|
addGroupTickText( currentMajGroupStartPos, previousMajText, majTickPositions );
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
if ( !previousMidText.isEmpty() )
|
|
|
|
{
|
|
|
|
addGroupTickText( currentMidGroupStartPos, previousMidText, midTickPositions );
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
if ( !previousMinText.isEmpty() )
|
|
|
|
{
|
|
|
|
addGroupTickText( currentMinGroupStartPos, previousMinText, minTickPositions );
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
}
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
// Create QwtBarCharts for each of the legend groups
|
|
|
|
|
2020-02-12 09:48:25 -06:00
|
|
|
int idx = 0;
|
|
|
|
for ( const auto& legendToBarPointsPair : legendToBarPointsMap )
|
|
|
|
{
|
|
|
|
addQwtBarChart( plot,
|
|
|
|
legendToBarPointsPair.second,
|
|
|
|
legendToBarPointsPair.first,
|
|
|
|
RiaColorTables::summaryCurveDefaultPaletteColors().cycledQColor( idx ) );
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
// Set up the axis to contain group texts and tick marks
|
2020-02-12 09:48:25 -06:00
|
|
|
{
|
2020-02-17 03:40:18 -06:00
|
|
|
QwtPlot::Axis axis = QwtPlot::xBottom;
|
|
|
|
if ( m_orientation == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
axis = QwtPlot::yLeft;
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
QwtScaleDiv groupAxisScaleDiv( 0, currentBarPosition );
|
|
|
|
{
|
|
|
|
if ( majTickPositions.size() ) groupAxisScaleDiv.setTicks( QwtScaleDiv::MajorTick, majTickPositions );
|
|
|
|
if ( midTickPositions.size() ) groupAxisScaleDiv.setTicks( QwtScaleDiv::MediumTick, midTickPositions );
|
|
|
|
if ( minTickPositions.size() ) groupAxisScaleDiv.setTicks( QwtScaleDiv::MinorTick, minTickPositions );
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
if ( m_orientation == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
groupAxisScaleDiv.invert();
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
RiuBarChartScaleDraw* scaleDrawer = new RiuBarChartScaleDraw( groupPositionedAxisTexts );
|
2020-02-12 09:48:25 -06:00
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
plot->setAxisScaleDraw( axis, scaleDrawer );
|
|
|
|
plot->setAxisScaleDiv( axis, groupAxisScaleDiv );
|
2020-02-12 09:48:25 -06:00
|
|
|
}
|
|
|
|
|
2020-02-17 03:40:18 -06:00
|
|
|
// Add texts on the bars inside the plot
|
|
|
|
{
|
|
|
|
QwtScaleDraw::Alignment alignment = QwtScaleDraw::TopScale;
|
|
|
|
if ( m_orientation == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
alignment = QwtScaleDraw::RightScale;
|
|
|
|
}
|
|
|
|
|
|
|
|
QwtScaleDiv barTextScaleDiv( 0, currentBarPosition );
|
|
|
|
{
|
|
|
|
QList<double> onBarTickPositions;
|
|
|
|
|
|
|
|
for ( const auto& doubleStuffPair : positionedBarLabels )
|
|
|
|
{
|
|
|
|
onBarTickPositions.push_back( doubleStuffPair.first );
|
|
|
|
}
|
|
|
|
|
|
|
|
barTextScaleDiv.setTicks( QwtScaleDiv::MinorTick, onBarTickPositions );
|
|
|
|
if ( m_orientation == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
barTextScaleDiv.invert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RiuBarChartScaleDraw* barTextScaleDrawer = new RiuBarChartScaleDraw( positionedBarLabels );
|
|
|
|
barTextScaleDrawer->setAlignment( alignment );
|
|
|
|
|
|
|
|
QwtPlotScaleItem* barTextScale = new QwtPlotScaleItem( alignment, 0.0 );
|
|
|
|
barTextScale->setScaleDraw( barTextScaleDrawer );
|
|
|
|
barTextScale->setScaleDiv( barTextScaleDiv );
|
|
|
|
barTextScale->attach( plot );
|
|
|
|
barTextScale->setZ( 1000 );
|
|
|
|
}
|
2020-02-12 09:48:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
void RiuGroupedBarChartBuilder::addQwtBarChart( QwtPlot* plot,
|
|
|
|
const QVector<QPointF>& posAndValue,
|
|
|
|
const QString& legendText,
|
|
|
|
const QColor& barColor )
|
|
|
|
{
|
|
|
|
QPalette palette;
|
|
|
|
palette.setColor( QPalette::Window, barColor );
|
|
|
|
palette.setColor( QPalette::Dark, barColor );
|
|
|
|
|
|
|
|
RiuAvoidPixelOverlapColumnSymbol* barStyle = new RiuAvoidPixelOverlapColumnSymbol( QwtColumnSymbol::Box );
|
|
|
|
barStyle->setPalette( palette );
|
|
|
|
barStyle->setFrameStyle( QwtColumnSymbol::NoFrame );
|
|
|
|
barStyle->setLineWidth( 0 );
|
|
|
|
|
|
|
|
QwtPlotBarChart* barChart = new QwtPlotBarChart( legendText );
|
|
|
|
barChart->setSamples( posAndValue );
|
|
|
|
barChart->setLegendMode( QwtPlotBarChart::LegendChartTitle );
|
|
|
|
barChart->setLayoutPolicy( QwtPlotAbstractBarChart::ScaleSamplesToAxes );
|
|
|
|
barChart->setLayoutHint( 1.0 );
|
|
|
|
barChart->setSymbol( barStyle );
|
|
|
|
barChart->setOrientation( m_orientation );
|
|
|
|
barChart->attach( plot );
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
RiuGroupedBarChartBuilder::BarEntry::BarEntry()
|
|
|
|
: m_sortValue( std::numeric_limits<double>::infinity() )
|
|
|
|
, m_value( std::numeric_limits<double>::infinity() )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2020-02-17 03:40:18 -06:00
|
|
|
RiuGroupedBarChartBuilder::BarEntry::BarEntry( const QString& majorTickText,
|
|
|
|
const QString& midTickText,
|
|
|
|
const QString& minTickText,
|
|
|
|
const double sortValue,
|
|
|
|
const QString& legendText,
|
|
|
|
const QString& barText,
|
|
|
|
const double value )
|
2020-02-12 09:48:25 -06:00
|
|
|
: m_majTickText( majorTickText )
|
|
|
|
, m_midTickText( midTickText )
|
|
|
|
, m_minTickText( minTickText )
|
|
|
|
, m_sortValue( sortValue )
|
|
|
|
, m_legendText( legendText )
|
2020-02-17 03:40:18 -06:00
|
|
|
, m_barText( barText )
|
2020-02-12 09:48:25 -06:00
|
|
|
, m_value( value )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
bool RiuGroupedBarChartBuilder::BarEntry::operator<( const BarEntry& other ) const
|
|
|
|
{
|
|
|
|
if ( m_majTickText != other.m_majTickText ) return m_majTickText < other.m_majTickText;
|
|
|
|
if ( m_midTickText != other.m_midTickText ) return m_midTickText < other.m_midTickText;
|
|
|
|
if ( m_minTickText != other.m_minTickText ) return m_minTickText < other.m_minTickText;
|
|
|
|
|
|
|
|
if ( m_sortValue != other.m_sortValue )
|
|
|
|
{
|
|
|
|
return m_sortValue > other.m_sortValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_legendText != other.m_legendText ) return m_legendText < other.m_legendText;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|