Skip to content

Commit 3e05bd8

Browse files
authored
Merge pull request #4501 from alexbruy/statistics-by-type
Statistics panel: show only relevant statistics depending on the field type
2 parents 931bf32 + 391cb73 commit 3e05bd8

File tree

2 files changed

+182
-56
lines changed

2 files changed

+182
-56
lines changed

src/app/qgsstatisticalsummarydockwidget.cpp

+166-56
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <QTableWidget>
2424
#include <QAction>
25+
#include <QMenu>
2526

2627
QList< QgsStatisticalSummary::Statistic > QgsStatisticalSummaryDockWidget::sDisplayStats =
2728
QList< QgsStatisticalSummary::Statistic > () << QgsStatisticalSummary::Count
@@ -92,28 +93,12 @@ QgsStatisticalSummaryDockWidget::QgsStatisticalSummaryDockWidget( QWidget *paren
9293
connect( mButtonRefresh, &QAbstractButton::clicked, this, &QgsStatisticalSummaryDockWidget::refreshStatistics );
9394
connect( QgsProject::instance(), static_cast<void ( QgsProject::* )( const QStringList & )>( &QgsProject::layersWillBeRemoved ), this, &QgsStatisticalSummaryDockWidget::layersRemoved );
9495

95-
QgsSettings settings;
96-
Q_FOREACH ( QgsStatisticalSummary::Statistic stat, sDisplayStats )
97-
{
98-
QAction *action = new QAction( QgsStatisticalSummary::displayName( stat ), mOptionsToolButton );
99-
action->setCheckable( true );
100-
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/checked_%1" ).arg( stat ), true ).toBool();
101-
action->setChecked( checked );
102-
action->setData( stat );
103-
mStatsActions.insert( stat, action );
104-
connect( action, &QAction::triggered, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
105-
mOptionsToolButton->addAction( action );
106-
}
96+
mStatisticsMenu = new QMenu( mOptionsToolButton );
97+
mOptionsToolButton->setMenu( mStatisticsMenu );
10798

108-
//count of null values statistic:
109-
QAction *nullCountAction = new QAction( tr( "Missing (null) values" ), mOptionsToolButton );
110-
nullCountAction->setCheckable( true );
111-
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/checked_missing_values" ), true ).toBool();
112-
nullCountAction->setChecked( checked );
113-
nullCountAction->setData( MISSING_VALUES );
114-
mStatsActions.insert( MISSING_VALUES, nullCountAction );
115-
connect( nullCountAction, &QAction::triggered, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
116-
mOptionsToolButton->addAction( nullCountAction );
99+
mFieldType = DataType::Numeric;
100+
mPreviousFieldType = DataType::Numeric;
101+
refreshStatisticsMenu();
117102
}
118103

119104
QgsStatisticalSummaryDockWidget::~QgsStatisticalSummaryDockWidget()
@@ -129,39 +114,34 @@ void QgsStatisticalSummaryDockWidget::refreshStatistics()
129114
return;
130115
}
131116

132-
// non numeric field?
133-
bool isNumeric = true;
134-
QVariant::Type fieldType = QVariant::Double;
117+
// determine field type
118+
mFieldType = DataType::Numeric;
135119
if ( !mFieldExpressionWidget->isExpression() )
136120
{
137-
QString field = mFieldExpressionWidget->currentField();
138-
fieldType = mLayer->fields().field( mLayer->fields().lookupField( field ) ).type();
139-
if ( fieldType == QVariant::String || fieldType == QVariant::Date || fieldType == QVariant::DateTime )
140-
{
141-
isNumeric = false;
142-
}
121+
mFieldType = fieldType( mFieldExpressionWidget->currentField() );
143122
}
144123

145-
bool selectedOnly = mSelectedOnlyCheckBox->isChecked();
146-
147-
if ( isNumeric )
124+
if ( mFieldType != mPreviousFieldType )
148125
{
149-
updateNumericStatistics( selectedOnly );
126+
refreshStatisticsMenu();
127+
mPreviousFieldType = mFieldType;
150128
}
151-
else
129+
130+
bool selectedOnly = mSelectedOnlyCheckBox->isChecked();
131+
132+
switch ( mFieldType )
152133
{
153-
switch ( fieldType )
154-
{
155-
case QVariant::String:
156-
updateStringStatistics( selectedOnly );
157-
break;
158-
case QVariant::Date:
159-
case QVariant::DateTime:
160-
updateDateTimeStatistics( selectedOnly );
161-
break;
162-
default:
163-
break;
164-
}
134+
case DataType::Numeric:
135+
updateNumericStatistics( selectedOnly );
136+
break;
137+
case DataType::String:
138+
updateStringStatistics( selectedOnly );
139+
break;
140+
case DataType::DateTime:
141+
updateDateTimeStatistics( selectedOnly );
142+
break;
143+
default:
144+
break;
165145
}
166146
}
167147

@@ -231,15 +211,26 @@ void QgsStatisticalSummaryDockWidget::updateStringStatistics( bool selectedOnly
231211
return;
232212
}
233213

214+
QList< QgsStringStatisticalSummary::Statistic > statsToDisplay;
215+
QgsStringStatisticalSummary::Statistics statsToCalc = 0;
216+
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, sDisplayStringStats )
217+
{
218+
if ( mStatsActions.value( stat )->isChecked() )
219+
{
220+
statsToDisplay << stat;
221+
statsToCalc |= stat;
222+
}
223+
}
224+
234225
QgsStringStatisticalSummary stats;
235-
stats.setStatistics( QgsStringStatisticalSummary::All );
226+
stats.setStatistics( statsToCalc );
236227
stats.calculateFromVariants( values );
237228

238-
mStatisticsTable->setRowCount( sDisplayStringStats.count() );
229+
mStatisticsTable->setRowCount( statsToDisplay.count() );
239230
mStatisticsTable->setColumnCount( 2 );
240231

241232
int row = 0;
242-
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, sDisplayStringStats )
233+
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, statsToDisplay )
243234
{
244235
addRow( row, QgsStringStatisticalSummary::displayName( stat ),
245236
stats.statistic( stat ).toString(),
@@ -277,19 +268,36 @@ void QgsStatisticalSummaryDockWidget::layerChanged( QgsMapLayer *layer )
277268

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

274+
QString settingsKey;
275+
switch ( mFieldType )
276+
{
277+
case DataType::Numeric:
278+
settingsKey = QStringLiteral( "numeric" );
279+
break;
280+
case DataType::String:
281+
settingsKey = QStringLiteral( "string" );
282+
break;
283+
case DataType::DateTime:
284+
settingsKey = QStringLiteral( "datetime" );
285+
break;
286+
default:
287+
break;
288+
}
289+
284290
QgsSettings settings;
285291
if ( stat >= 0 )
286292
{
287-
settings.setValue( QStringLiteral( "StatisticalSummaryDock/checked_%1" ).arg( stat ), checked );
293+
settings.setValue( QStringLiteral( "StatisticalSummaryDock/%1_%2" ).arg( settingsKey ).arg( stat ), checked );
288294
}
289295
else if ( stat == MISSING_VALUES )
290296
{
291-
settings.setValue( QStringLiteral( "StatisticalSummaryDock/checked_missing_values" ).arg( stat ), checked );
297+
settings.setValue( QStringLiteral( "StatisticalSummaryDock/numeric_missing_values" ), checked );
292298
}
299+
300+
refreshStatistics();
293301
}
294302

295303
void QgsStatisticalSummaryDockWidget::layersRemoved( const QStringList &layers )
@@ -319,15 +327,27 @@ void QgsStatisticalSummaryDockWidget::updateDateTimeStatistics( bool selectedOnl
319327
return;
320328
}
321329

330+
QList< QgsDateTimeStatisticalSummary::Statistic > statsToDisplay;
331+
QgsDateTimeStatisticalSummary::Statistics statsToCalc = 0;
332+
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, sDisplayDateTimeStats )
333+
{
334+
if ( mStatsActions.value( stat )->isChecked() )
335+
{
336+
statsToDisplay << stat;
337+
statsToCalc |= stat;
338+
}
339+
}
340+
341+
322342
QgsDateTimeStatisticalSummary stats;
323-
stats.setStatistics( QgsDateTimeStatisticalSummary::All );
343+
stats.setStatistics( statsToCalc );
324344
stats.calculate( values );
325345

326-
mStatisticsTable->setRowCount( sDisplayDateTimeStats.count() );
346+
mStatisticsTable->setRowCount( statsToDisplay.count() );
327347
mStatisticsTable->setColumnCount( 2 );
328348

329349
int row = 0;
330-
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, sDisplayDateTimeStats )
350+
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, statsToDisplay )
331351
{
332352
QString value = ( stat == QgsDateTimeStatisticalSummary::Range
333353
? tr( "%1 seconds" ).arg( stats.range().seconds() )
@@ -358,3 +378,93 @@ void QgsStatisticalSummaryDockWidget::addRow( int row, const QString &name, cons
358378
mStatisticsTable->setItem( row, 1, valueItem );
359379
}
360380

381+
void QgsStatisticalSummaryDockWidget::refreshStatisticsMenu()
382+
{
383+
mStatisticsMenu->clear();
384+
mStatsActions.clear();
385+
386+
QgsSettings settings;
387+
switch ( mFieldType )
388+
{
389+
case DataType::Numeric:
390+
{
391+
Q_FOREACH ( QgsStatisticalSummary::Statistic stat, sDisplayStats )
392+
{
393+
QAction *action = new QAction( QgsStatisticalSummary::displayName( stat ), mStatisticsMenu );
394+
action->setCheckable( true );
395+
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/numeric_%1" ).arg( stat ), true ).toBool();
396+
action->setChecked( checked );
397+
action->setData( stat );
398+
mStatsActions.insert( stat, action );
399+
connect( action, &QAction::toggled, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
400+
mStatisticsMenu->addAction( action );
401+
}
402+
403+
//count of null values statistic
404+
QAction *nullCountAction = new QAction( tr( "Missing (null) values" ), mStatisticsMenu );
405+
nullCountAction->setCheckable( true );
406+
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/numeric_missing_values" ), true ).toBool();
407+
nullCountAction->setChecked( checked );
408+
nullCountAction->setData( MISSING_VALUES );
409+
mStatsActions.insert( MISSING_VALUES, nullCountAction );
410+
connect( nullCountAction, &QAction::toggled, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
411+
mStatisticsMenu->addAction( nullCountAction );
412+
413+
break;
414+
}
415+
case DataType::String:
416+
{
417+
Q_FOREACH ( QgsStringStatisticalSummary::Statistic stat, sDisplayStringStats )
418+
{
419+
QAction *action = new QAction( QgsStringStatisticalSummary::displayName( stat ), mStatisticsMenu );
420+
action->setCheckable( true );
421+
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/string_%1" ).arg( stat ), true ).toBool();
422+
action->setChecked( checked );
423+
action->setData( stat );
424+
mStatsActions.insert( stat, action );
425+
connect( action, &QAction::toggled, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
426+
mStatisticsMenu->addAction( action );
427+
}
428+
break;
429+
}
430+
case DataType::DateTime:
431+
{
432+
Q_FOREACH ( QgsDateTimeStatisticalSummary::Statistic stat, sDisplayDateTimeStats )
433+
{
434+
QAction *action = new QAction( QgsDateTimeStatisticalSummary::displayName( stat ), mStatisticsMenu );
435+
action->setCheckable( true );
436+
bool checked = settings.value( QStringLiteral( "StatisticalSummaryDock/datetime_%1" ).arg( stat ), true ).toBool();
437+
action->setChecked( checked );
438+
action->setData( stat );
439+
mStatsActions.insert( stat, action );
440+
connect( action, &QAction::toggled, this, &QgsStatisticalSummaryDockWidget::statActionTriggered );
441+
mStatisticsMenu->addAction( action );
442+
}
443+
break;
444+
}
445+
default:
446+
break;
447+
}
448+
}
449+
450+
QgsStatisticalSummaryDockWidget::DataType QgsStatisticalSummaryDockWidget::fieldType( const QString &fieldName )
451+
{
452+
QgsField field = mLayer->fields().field( mLayer->fields().lookupField( fieldName ) );
453+
if ( field.isNumeric() )
454+
{
455+
return DataType::Numeric;
456+
}
457+
458+
switch ( field.type() )
459+
{
460+
case QVariant::String:
461+
return DataType::String;
462+
case QVariant::Date:
463+
case QVariant::DateTime:
464+
return DataType::DateTime;
465+
default:
466+
break;
467+
}
468+
469+
return DataType::Numeric;
470+
}

src/app/qgsstatisticalsummarydockwidget.h

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgsdockwidget.h"
2525
#include "qgis_app.h"
2626

27+
class QMenu;
2728
class QgsBrowserModel;
2829
class QModelIndex;
2930
class QgsDockBrowserTreeView;
@@ -61,6 +62,14 @@ class APP_EXPORT QgsStatisticalSummaryDockWidget : public QgsDockWidget, private
6162

6263
private:
6364

65+
//! Enumeration of supported statistics types
66+
enum DataType
67+
{
68+
Numeric, //!< Numeric fields: int, double, etc
69+
String, //!< String fields
70+
DateTime //!< Date and DateTime fields
71+
};
72+
6473
QgsVectorLayer *mLayer = nullptr;
6574

6675
QMap< int, QAction * > mStatsActions;
@@ -74,6 +83,13 @@ class APP_EXPORT QgsStatisticalSummaryDockWidget : public QgsDockWidget, private
7483
void addRow( int row, const QString &name, const QString &value, bool showValue );
7584

7685
QgsExpressionContext createExpressionContext() const override;
86+
87+
void refreshStatisticsMenu();
88+
DataType fieldType( const QString &fieldName );
89+
90+
QMenu *mStatisticsMenu = nullptr;
91+
DataType mFieldType;
92+
DataType mPreviousFieldType;
7793
};
7894

7995
#endif // QGSSTATISTICALSUMMARYDOCKWIDGET_H

0 commit comments

Comments
 (0)