Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4529 from alexbruy/stats-panel
fix bugs related to statistical dock (fix #16117, #16118, #16119)
  • Loading branch information
alexbruy committed May 11, 2017
2 parents 7ba28ec + e0d4e37 commit 72c8335
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 62 deletions.
224 changes: 168 additions & 56 deletions src/app/qgsstatisticalsummarydockwidget.cpp
Expand Up @@ -17,9 +17,11 @@
#include "qgsmaplayerregistry.h"
#include "qgisapp.h"
#include "qgsmapcanvas.h"

#include <QTableWidget>
#include <QAction>
#include <QSettings>
#include <QMenu>

QList< QgsStatisticalSummary::Statistic > QgsStatisticalSummaryDockWidget::mDisplayStats =
QList< QgsStatisticalSummary::Statistic > () << QgsStatisticalSummary::Count
Expand Down Expand Up @@ -76,6 +78,7 @@ static QgsExpressionContext _getExpressionContext( const void* context )
QgsStatisticalSummaryDockWidget::QgsStatisticalSummaryDockWidget( QWidget *parent )
: QgsDockWidget( parent )
, mLayer( nullptr )
, mStatisticsMenu( nullptr )
{
setupUi( this );

Expand All @@ -95,28 +98,12 @@ QgsStatisticalSummaryDockWidget::QgsStatisticalSummaryDockWidget( QWidget *paren
connect( mButtonRefresh, SIGNAL( clicked( bool ) ), this, SLOT( refreshStatistics() ) );
connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ), this, SLOT( layersRemoved( QStringList ) ) );

QSettings settings;
Q_FOREACH ( QgsStatisticalSummary::Statistic stat, mDisplayStats )
{
QAction* action = new QAction( QgsStatisticalSummary::displayName( stat ), mOptionsToolButton );
action->setCheckable( true );
bool checked = settings.value( QString( "/StatisticalSummaryDock/checked_%1" ).arg( stat ), true ).toBool();
action->setChecked( checked );
action->setData( stat );
mStatsActions.insert( stat, action );
connect( action, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mOptionsToolButton->addAction( action );
}
mStatisticsMenu = new QMenu( mOptionsToolButton );
mOptionsToolButton->setMenu( mStatisticsMenu );

//count of null values statistic:
QAction* nullCountAction = new QAction( tr( "Missing (null) values" ), mOptionsToolButton );
nullCountAction->setCheckable( true );
bool checked = settings.value( QString( "/StatisticalSummaryDock/checked_missing_values" ), true ).toBool();
nullCountAction->setChecked( checked );
nullCountAction->setData( MISSING_VALUES );
mStatsActions.insert( MISSING_VALUES, nullCountAction );
connect( nullCountAction, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mOptionsToolButton->addAction( nullCountAction );
mFieldType = DataType::Numeric;
mPreviousFieldType = DataType::Numeric;
refreshStatisticsMenu();
}

QgsStatisticalSummaryDockWidget::~QgsStatisticalSummaryDockWidget()
Expand All @@ -132,39 +119,34 @@ void QgsStatisticalSummaryDockWidget::refreshStatistics()
return;
}

// non numeric field?
bool isNumeric = true;
QVariant::Type fieldType = QVariant::Double;
// determine field type
mFieldType = DataType::Numeric;
if ( !mFieldExpressionWidget->isExpression() )
{
QString field = mFieldExpressionWidget->currentField();
fieldType = mLayer->fields().field( mLayer->fields().fieldNameIndex( field ) ).type();
if ( fieldType == QVariant::String || fieldType == QVariant::Date || fieldType == QVariant::DateTime )
{
isNumeric = false;
}
mFieldType = fieldType( mFieldExpressionWidget->currentField() );
}

bool selectedOnly = mSelectedOnlyCheckBox->isChecked();

if ( isNumeric )
if ( mFieldType != mPreviousFieldType )
{
updateNumericStatistics( selectedOnly );
refreshStatisticsMenu();
mPreviousFieldType = mFieldType;
}
else

bool selectedOnly = mSelectedOnlyCheckBox->isChecked();

switch ( mFieldType )
{
switch ( fieldType )
{
case QVariant::String:
updateStringStatistics( selectedOnly );
break;
case QVariant::Date:
case QVariant::DateTime:
updateDateTimeStatistics( selectedOnly );
break;
default:
break;
}
case DataType::Numeric:
updateNumericStatistics( selectedOnly );
break;
case DataType::String:
updateStringStatistics( selectedOnly );
break;
case DataType::DateTime:
updateDateTimeStatistics( selectedOnly );
break;
default:
break;
}
}

Expand Down Expand Up @@ -234,15 +216,26 @@ void QgsStatisticalSummaryDockWidget::updateStringStatistics( bool selectedOnly
return;
}

QList< QgsStringStatisticalSummary::Statistic > statsToDisplay;
QgsStringStatisticalSummary::Statistics statsToCalc = 0;
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, mDisplayStringStats )
{
if ( mStatsActions.value( stat )->isChecked() )
{
statsToDisplay << stat;
statsToCalc |= stat;
}
}

QgsStringStatisticalSummary stats;
stats.setStatistics( QgsStringStatisticalSummary::All );
stats.setStatistics( statsToCalc );
stats.calculateFromVariants( values );

mStatisticsTable->setRowCount( mDisplayStringStats.count() );
mStatisticsTable->setRowCount( statsToDisplay.count() );
mStatisticsTable->setColumnCount( 2 );

int row = 0;
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, mDisplayStringStats )
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, statsToDisplay )
{
addRow( row, QgsStringStatisticalSummary::displayName( stat ),
stats.statistic( stat ).toString(),
Expand Down Expand Up @@ -280,19 +273,37 @@ void QgsStatisticalSummaryDockWidget::layerChanged( QgsMapLayer *layer )

void QgsStatisticalSummaryDockWidget::statActionTriggered( bool checked )
{
refreshStatistics();
QAction* action = dynamic_cast<QAction*>( sender() );
int stat = action->data().toInt();

QString settingsKey;
switch ( mFieldType )
{
case DataType::Numeric:
settingsKey = "numeric";
break;
case DataType::String:
settingsKey = "string";
break;
case DataType::DateTime:
settingsKey = "datetime";
break;
default:
break;
}


QSettings settings;
if ( stat >= 0 )
{
settings.setValue( QString( "/StatisticalSummaryDock/checked_%1" ).arg( stat ), checked );
settings.setValue( QString( "/StatisticalSummaryDock/%1_%2" ).arg( settingsKey ).arg( stat ), checked );
}
else if ( stat == MISSING_VALUES )
{
settings.setValue( QString( "/StatisticalSummaryDock/checked_missing_values" ).arg( stat ), checked );
settings.setValue( QString( "/StatisticalSummaryDock/numeric_missing_values" ), checked );
}

refreshStatistics();
}

void QgsStatisticalSummaryDockWidget::layersRemoved( const QStringList& layers )
Expand Down Expand Up @@ -322,15 +333,26 @@ void QgsStatisticalSummaryDockWidget::updateDateTimeStatistics( bool selectedOnl
return;
}

QList< QgsDateTimeStatisticalSummary::Statistic > statsToDisplay;
QgsDateTimeStatisticalSummary::Statistics statsToCalc = 0;
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, mDisplayDateTimeStats )
{
if ( mStatsActions.value( stat )->isChecked() )
{
statsToDisplay << stat;
statsToCalc |= stat;
}
}

QgsDateTimeStatisticalSummary stats;
stats.setStatistics( QgsDateTimeStatisticalSummary::All );
stats.setStatistics( statsToCalc );
stats.calculate( values );

mStatisticsTable->setRowCount( mDisplayDateTimeStats.count() );
mStatisticsTable->setRowCount( statsToDisplay.count() );
mStatisticsTable->setColumnCount( 2 );

int row = 0;
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, mDisplayDateTimeStats )
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, statsToDisplay )
{
QString value = ( stat == QgsDateTimeStatisticalSummary::Range
? tr( "%1 seconds" ).arg( stats.range().seconds() )
Expand Down Expand Up @@ -361,3 +383,93 @@ void QgsStatisticalSummaryDockWidget::addRow( int row, const QString& name, cons
mStatisticsTable->setItem( row, 1, valueItem );
}

void QgsStatisticalSummaryDockWidget::refreshStatisticsMenu()
{
mStatisticsMenu->clear();
mStatsActions.clear();

QSettings settings;
switch ( mFieldType )
{
case DataType::Numeric:
{
Q_FOREACH ( QgsStatisticalSummary::Statistic stat, mDisplayStats )
{
QAction *action = new QAction( QgsStatisticalSummary::displayName( stat ), mStatisticsMenu );
action->setCheckable( true );
bool checked = settings.value( QString( "StatisticalSummaryDock/numeric_%1" ).arg( stat ), true ).toBool();
action->setChecked( checked );
action->setData( stat );
mStatsActions.insert( stat, action );
connect( action, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mStatisticsMenu->addAction( action );
}

//count of null values statistic
QAction *nullCountAction = new QAction( tr( "Missing (null) values" ), mStatisticsMenu );
nullCountAction->setCheckable( true );
bool checked = settings.value( QString( "StatisticalSummaryDock/numeric_missing_values" ), true ).toBool();
nullCountAction->setChecked( checked );
nullCountAction->setData( MISSING_VALUES );
mStatsActions.insert( MISSING_VALUES, nullCountAction );
connect( nullCountAction, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mStatisticsMenu->addAction( nullCountAction );

break;
}
case DataType::String:
{
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, mDisplayStringStats )
{
QAction *action = new QAction( QgsStringStatisticalSummary::displayName( stat ), mStatisticsMenu );
action->setCheckable( true );
bool checked = settings.value( QString( "StatisticalSummaryDock/string_%1" ).arg( stat ), true ).toBool();
action->setChecked( checked );
action->setData( stat );
mStatsActions.insert( stat, action );
connect( action, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mStatisticsMenu->addAction( action );
}
break;
}
case DataType::DateTime:
{
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, mDisplayDateTimeStats )
{
QAction *action = new QAction( QgsDateTimeStatisticalSummary::displayName( stat ), mStatisticsMenu );
action->setCheckable( true );
bool checked = settings.value( QString( "StatisticalSummaryDock/datetime_%1" ).arg( stat ), true ).toBool();
action->setChecked( checked );
action->setData( stat );
mStatsActions.insert( stat, action );
connect( action, SIGNAL( triggered( bool ) ), this, SLOT( statActionTriggered( bool ) ) );
mStatisticsMenu->addAction( action );
}
break;
}
default:
break;
}
}

QgsStatisticalSummaryDockWidget::DataType QgsStatisticalSummaryDockWidget::fieldType( const QString &fieldName )
{
QgsField field = mLayer->fields().field( fieldName );
if ( field.isNumeric() )
{
return DataType::Numeric;
}

switch ( field.type() )
{
case QVariant::String:
return DataType::String;
case QVariant::Date:
case QVariant::DateTime:
return DataType::DateTime;
default:
break;
}

return DataType::Numeric;
}
21 changes: 15 additions & 6 deletions src/app/qgsstatisticalsummarydockwidget.h
Expand Up @@ -23,12 +23,7 @@
#include "qgsdatetimestatisticalsummary.h"
#include "qgsdockwidget.h"

class QgsBrowserModel;
class QModelIndex;
class QgsDockBrowserTreeView;
class QgsLayerItem;
class QgsDataItem;
class QgsBrowserTreeFilterProxyModel;
class QMenu;

/** A dock widget which displays a statistical summary of the values in a field or expression
*/
Expand Down Expand Up @@ -60,7 +55,18 @@ class APP_EXPORT QgsStatisticalSummaryDockWidget : public QgsDockWidget, private

private:

//! Enumeration of supported statistics types
enum DataType
{
Numeric, //!< Numeric fields: int, double, etc
String, //!< String fields
DateTime //!< Date and DateTime fields
};

QgsVectorLayer* mLayer;
QMenu *mStatisticsMenu;
DataType mFieldType;
DataType mPreviousFieldType;

QMap< int, QAction* > mStatsActions;
static QList< QgsStatisticalSummary::Statistic > mDisplayStats;
Expand All @@ -71,6 +77,9 @@ class APP_EXPORT QgsStatisticalSummaryDockWidget : public QgsDockWidget, private
void updateStringStatistics( bool selectedOnly );
void updateDateTimeStatistics( bool selectedOnly );
void addRow( int row, const QString& name, const QString& value, bool showValue );
void refreshStatisticsMenu();
DataType fieldType( const QString &fieldName );

};

#endif // QGSSTATISTICALSUMMARYDOCKWIDGET_H

0 comments on commit 72c8335

Please sign in to comment.