Skip to content

Commit

Permalink
Add an option via a button in the categorized symbol renderer widget …
Browse files Browse the repository at this point in the history
…to delete

unused categories from the model/view. I.e. any categories which are not matched
in the attribute field or expression used to categorize the layer.
  • Loading branch information
benwirf committed Feb 17, 2025
1 parent 88383c3 commit 245a43b
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Applies the color ramp passed on by the color ramp button

void deleteCategories();
void deleteAllCategories();
void deleteUnusedCategories();

void showSymbolLevels();

Expand Down Expand Up @@ -123,6 +124,13 @@ Changes the selected symbols alone for the change button, if there is a selectio
void applyChangeToSymbol();
%Docstring
Applies current symbol to selected categories, or to all categories if none is selected
%End

QList<QVariant> layerUniqueValues( QString attrName );
%Docstring
Returns the list of unique values in the widget's layer.

Called by :py:func:`~QgsCategorizedSymbolRendererWidget.addCategories` and :py:func:`~QgsCategorizedSymbolRendererWidget.deleteUnusedCategories`
%End

virtual QList<QgsSymbol *> selectedSymbols();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Applies the color ramp passed on by the color ramp button

void deleteCategories();
void deleteAllCategories();
void deleteUnusedCategories();

void showSymbolLevels();

Expand Down Expand Up @@ -123,6 +124,13 @@ Changes the selected symbols alone for the change button, if there is a selectio
void applyChangeToSymbol();
%Docstring
Applies current symbol to selected categories, or to all categories if none is selected
%End

QList<QVariant> layerUniqueValues( QString attrName );
%Docstring
Returns the list of unique values in the widget's layer.

Called by :py:func:`~QgsCategorizedSymbolRendererWidget.addCategories` and :py:func:`~QgsCategorizedSymbolRendererWidget.deleteUnusedCategories`
%End

virtual QList<QgsSymbol *> selectedSymbols();
Expand Down
88 changes: 59 additions & 29 deletions src/gui/symbology/qgscategorizedsymbolrendererwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ QgsCategorizedSymbolRendererWidget::QgsCategorizedSymbolRendererWidget( QgsVecto
connect( btnAddCategories, &QAbstractButton::clicked, this, &QgsCategorizedSymbolRendererWidget::addCategories );
connect( btnDeleteCategories, &QAbstractButton::clicked, this, &QgsCategorizedSymbolRendererWidget::deleteCategories );
connect( btnDeleteAllCategories, &QAbstractButton::clicked, this, &QgsCategorizedSymbolRendererWidget::deleteAllCategories );
connect( btnDeleteUnusedCategories, &QAbstractButton::clicked, this, &QgsCategorizedSymbolRendererWidget::deleteUnusedCategories );
connect( btnAddCategory, &QAbstractButton::clicked, this, &QgsCategorizedSymbolRendererWidget::addCategory );

connect( btnColorRamp, &QgsColorRampButton::colorRampChanged, this, &QgsCategorizedSymbolRendererWidget::applyColorRamp );
Expand Down Expand Up @@ -899,35 +900,8 @@ void QgsCategorizedSymbolRendererWidget::changeCategorySymbol()

void QgsCategorizedSymbolRendererWidget::addCategories()
{
const QString attrName = mExpressionWidget->currentField();
const int idx = mLayer->fields().lookupField( attrName );
QList<QVariant> uniqueValues;
if ( idx == -1 )
{
// Lets assume it's an expression
QgsExpression *expression = new QgsExpression( attrName );
QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
<< QgsExpressionContextUtils::atlasScope( nullptr )
<< QgsExpressionContextUtils::layerScope( mLayer );

expression->prepare( &context );
QgsFeatureIterator fit = mLayer->getFeatures();
QgsFeature feature;
while ( fit.nextFeature( feature ) )
{
context.setFeature( feature );
const QVariant value = expression->evaluate( &context );
if ( uniqueValues.contains( value ) )
continue;
uniqueValues << value;
}
}
else
{
uniqueValues = qgis::setToList( mLayer->uniqueValues( idx ) );
}
QString attrName = mExpressionWidget->currentField();
QList<QVariant> uniqueValues = layerUniqueValues( attrName );

// ask to abort if too many classes
if ( uniqueValues.size() >= 1000 )
Expand Down Expand Up @@ -1093,6 +1067,62 @@ void QgsCategorizedSymbolRendererWidget::deleteAllCategories()
emit widgetChanged();
}

void QgsCategorizedSymbolRendererWidget::deleteUnusedCategories()
{
if ( !mRenderer )
return;
QString attrName = mExpressionWidget->currentField();
QList<QVariant> uniqueValues = layerUniqueValues( attrName );

const QgsCategoryList catList = mRenderer->categories();

QList<int> unusedIndexes;

for ( int i = 0; i < catList.size(); ++i )
{
QgsRendererCategory cat = catList.at( i );
if ( !uniqueValues.contains( cat.value() ) )
{
unusedIndexes.append( i );
}
}
mModel->deleteRows( unusedIndexes );
emit widgetChanged();
}

QList<QVariant> QgsCategorizedSymbolRendererWidget::layerUniqueValues( QString attrName )
{
const int idx = mLayer->fields().lookupField( attrName );
QList<QVariant> uniqueValues;
if ( idx == -1 )
{
// Lets assume it's an expression
QgsExpression *expression = new QgsExpression( attrName );
QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
<< QgsExpressionContextUtils::atlasScope( nullptr )
<< QgsExpressionContextUtils::layerScope( mLayer );

expression->prepare( &context );
QgsFeatureIterator fit = mLayer->getFeatures();
QgsFeature feature;
while ( fit.nextFeature( feature ) )
{
context.setFeature( feature );
const QVariant value = expression->evaluate( &context );
if ( uniqueValues.contains( value ) )
continue;
uniqueValues << value;
}
}
else
{
uniqueValues = qgis::setToList( mLayer->uniqueValues( idx ) );
}
return uniqueValues;
}

void QgsCategorizedSymbolRendererWidget::addCategory()
{
if ( !mModel )
Expand Down
8 changes: 8 additions & 0 deletions src/gui/symbology/qgscategorizedsymbolrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class GUI_EXPORT QgsCategorizedSymbolRendererWidget : public QgsRendererWidget,

void deleteCategories();
void deleteAllCategories();
void deleteUnusedCategories();

void showSymbolLevels();

Expand Down Expand Up @@ -235,6 +236,13 @@ class GUI_EXPORT QgsCategorizedSymbolRendererWidget : public QgsRendererWidget,
//! Applies current symbol to selected categories, or to all categories if none is selected
void applyChangeToSymbol();

/**
* Returns the list of unique values in the widget's layer.
*
* Called by addCategories() and deleteUnusedCategories()
*/
QList<QVariant> layerUniqueValues( QString attrName );

QList<QgsSymbol *> selectedSymbols() override;
QgsCategoryList selectedCategoryList();
void refreshSymbolView() override;
Expand Down
24 changes: 16 additions & 8 deletions src/ui/qgscategorizedsymbolrendererwidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>424</width>
<width>471</width>
<height>368</height>
</rect>
</property>
Expand All @@ -25,7 +25,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="QgsFieldExpressionWidget" name="mExpressionWidget" native="true">
<widget class="QgsFieldExpressionWidget" name="mExpressionWidget">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
Expand Down Expand Up @@ -155,6 +155,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeleteUnusedCategories">
<property name="text">
<string>Delete Unused</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
Expand Down Expand Up @@ -202,19 +209,19 @@
<customwidget>
<class>QgsFieldExpressionWidget</class>
<extends>QWidget</extends>
<header location="global">qgsfieldexpressionwidget.h</header>
<header>qgsfieldexpressionwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsColorRampButton</class>
<class>QgsSymbolButton</class>
<extends>QToolButton</extends>
<header>qgscolorrampbutton.h</header>
<container>1</container>
<header>qgssymbolbutton.h</header>
</customwidget>
<customwidget>
<class>QgsSymbolButton</class>
<class>QgsColorRampButton</class>
<extends>QToolButton</extends>
<header>qgssymbolbutton.h</header>
<header>qgscolorrampbutton.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
Expand All @@ -230,6 +237,7 @@
</tabstops>
<resources>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
</resources>
<connections/>
</ui>

0 comments on commit 245a43b

Please sign in to comment.