Skip to content

Commit

Permalink
[FEATURE] Add spacing option for vector layer bar chart diagrams
Browse files Browse the repository at this point in the history
Allows for user-controlled spacing between each bar in the chart.

Sponsored by SLYR
  • Loading branch information
nyalldawson committed Nov 21, 2019
1 parent c42789d commit 49dcc2c
Show file tree
Hide file tree
Showing 9 changed files with 396 additions and 101 deletions.
82 changes: 82 additions & 0 deletions python/core/auto_generated/qgsdiagramrenderer.sip.in
Expand Up @@ -407,6 +407,88 @@ Constructor for QgsDiagramSettings

double minimumSize;

double spacing() const;
%Docstring
Returns the spacing between diagram contents.

Spacing units can be retrieved by calling spacingUnit().

.. seealso:: :py:func:`setSpacing`

.. seealso:: :py:func:`spacingUnit`

.. seealso:: :py:func:`spacingMapUnitScale`

.. versionadded:: 3.12
%End

void setSpacing( double spacing );
%Docstring
Sets the ``spacing`` between diagram contents.

Spacing units are set via setSpacingUnit().

.. seealso:: :py:func:`spacing`

.. seealso:: :py:func:`setSpacingUnit`

.. seealso:: :py:func:`setSpacingMapUnitScale`

.. versionadded:: 3.12
%End

void setSpacingUnit( QgsUnitTypes::RenderUnit unit );
%Docstring
Sets the ``unit`` for the content spacing.

.. seealso:: :py:func:`spacingUnit`

.. seealso:: :py:func:`setSpacing`

.. seealso:: :py:func:`setSpacingMapUnitScale`

.. versionadded:: 3.12
%End

QgsUnitTypes::RenderUnit spacingUnit() const;
%Docstring
Returns the units for the content spacing.

.. seealso:: :py:func:`setSpacingUnit`

.. seealso:: :py:func:`spacing`

.. seealso:: :py:func:`spacingMapUnitScale`

.. versionadded:: 3.12
%End

void setSpacingMapUnitScale( const QgsMapUnitScale &scale );
%Docstring
Sets the map unit ``scale`` for the content spacing.

.. seealso:: :py:func:`spacingMapUnitScale`

.. seealso:: :py:func:`setSpacing`

.. seealso:: :py:func:`setSpacingUnit`

.. versionadded:: 3.12
%End

const QgsMapUnitScale &spacingMapUnitScale() const;
%Docstring
Returns the map unit scale for the content spacing.

.. seealso:: :py:func:`setSpacingMapUnitScale`

.. seealso:: :py:func:`spacing`

.. seealso:: :py:func:`spacingUnit`

.. versionadded:: 3.12
%End

void readXml( const QDomElement &elem );
%Docstring
Reads diagram settings from XML
Expand Down
17 changes: 17 additions & 0 deletions src/app/qgsdiagramproperties.cpp
Expand Up @@ -84,6 +84,10 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
// get rid of annoying outer focus rect on Mac
mDiagramOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );

mBarSpacingSpinBox->setClearValue( 0 );
mBarSpacingUnitComboBox->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );

mDiagramFontButton->setMode( QgsFontButton::ModeQFont );

mDiagramTypeComboBox->blockSignals( true );
Expand Down Expand Up @@ -341,6 +345,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
}

mBarWidthSpinBox->setValue( settingList.at( 0 ).barWidth );
mBarSpacingSpinBox->setValue( settingList.at( 0 ).spacing() );
mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() );
mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() );

mIncreaseSmallDiagramsCheck->setChecked( settingList.at( 0 ).minimumSize != 0 );
mIncreaseMinimumSizeSpinBox->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() );
Expand Down Expand Up @@ -534,6 +541,9 @@ void QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged( int index )
{
mBarWidthLabel->show();
mBarWidthSpinBox->show();
mBarSpacingLabel->show();
mBarSpacingSpinBox->show();
mBarSpacingUnitComboBox->show();
mBarOptionsFrame->show();
mAttributeBasedScalingRadio->setChecked( true );
mFixedSizeRadio->setEnabled( false );
Expand All @@ -546,6 +556,9 @@ void QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged( int index )
{
mBarWidthLabel->hide();
mBarWidthSpinBox->hide();
mBarSpacingLabel->hide();
mBarSpacingSpinBox->hide();
mBarSpacingUnitComboBox->hide();
mBarOptionsFrame->hide();
mLinearlyScalingLabel->setText( tr( "Scale linearly between 0 and the following attribute value / diagram size:" ) );
mSizeLabel->setText( tr( "Size" ) );
Expand Down Expand Up @@ -794,6 +807,10 @@ void QgsDiagramProperties::apply()

ds.barWidth = mBarWidthSpinBox->value();

ds.setSpacing( mBarSpacingSpinBox->value() );
ds.setSpacingUnit( mBarSpacingUnitComboBox->unit() );
ds.setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );

QgsDiagramRenderer *renderer = nullptr;
if ( mFixedSizeRadio->isChecked() )
{
Expand Down
16 changes: 11 additions & 5 deletions src/core/diagram/qgshistogramdiagram.cpp
Expand Up @@ -61,18 +61,20 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsFeature &feature, const QgsRen
maxValue = s.minimumSize;
}

const double spacing = c.convertToPainterUnits( s.spacing(), s.spacingUnit(), s.spacingMapUnitScale() );

switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
case QgsDiagramSettings::Down:
mScaleFactor = ( ( is.upperSize.width() - is.lowerSize.height() ) / ( is.upperValue - is.lowerValue ) );
size.scale( s.barWidth * s.categoryAttributes.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
size.scale( s.barWidth * s.categoryAttributes.size() + spacing * std::max( 0, s.categoryAttributes.size() - 1 ), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
break;

case QgsDiagramSettings::Right:
case QgsDiagramSettings::Left:
mScaleFactor = ( ( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) );
size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryAttributes.size(), Qt::IgnoreAspectRatio );
size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryAttributes.size() + spacing * std::max( 0, s.categoryAttributes.size() - 1 ), Qt::IgnoreAspectRatio );
break;
}

Expand Down Expand Up @@ -116,19 +118,21 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributes &attributes, const
maxValue = std::max( attributes.at( i ).toDouble(), maxValue );
}

const double spacing = c.convertToPainterUnits( s.spacing(), s.spacingUnit(), s.spacingMapUnitScale() );

switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
case QgsDiagramSettings::Down:
mScaleFactor = maxValue / s.size.height();
size.scale( s.barWidth * s.categoryColors.size(), s.size.height(), Qt::IgnoreAspectRatio );
size.scale( s.barWidth * s.categoryColors.size() + spacing * std::max( 0, s.categoryAttributes.size() - 1 ), s.size.height(), Qt::IgnoreAspectRatio );
break;

case QgsDiagramSettings::Right:
case QgsDiagramSettings::Left:
default: // just in case...
mScaleFactor = maxValue / s.size.width();
size.scale( s.size.width(), s.barWidth * s.categoryColors.size(), Qt::IgnoreAspectRatio );
size.scale( s.size.width(), s.barWidth * s.categoryColors.size() + spacing * std::max( 0, s.categoryAttributes.size() - 1 ), Qt::IgnoreAspectRatio );
break;
}

Expand Down Expand Up @@ -164,6 +168,8 @@ void QgsHistogramDiagram::renderDiagram( const QgsFeature &feature, QgsRenderCon
double currentOffset = 0;
double scaledWidth = sizePainterUnits( s.barWidth, s, c );

const double spacing = c.convertToPainterUnits( s.spacing(), s.spacingUnit(), s.spacingMapUnitScale() );

double baseX = position.x();
double baseY = position.y();

Expand Down Expand Up @@ -199,6 +205,6 @@ void QgsHistogramDiagram::renderDiagram( const QgsFeature &feature, QgsRenderCon
break;
}

currentOffset += scaledWidth;
currentOffset += scaledWidth + spacing;
}
}
7 changes: 7 additions & 0 deletions src/core/qgsdiagramrenderer.cpp
Expand Up @@ -219,6 +219,10 @@ void QgsDiagramSettings::readXml( const QDomElement &elem )
lineSizeUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "lineSizeType" ) ) );
lineSizeScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "lineSizeScale" ) ) );

mSpacing = elem.attribute( QStringLiteral( "spacing" ) ).toDouble();
mSpacingUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "spacingUnit" ) ) );
mSpacingMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "spacingUnitScale" ) ) );

//label placement method
if ( elem.attribute( QStringLiteral( "labelPlacementMethod" ) ) == QLatin1String( "Height" ) )
{
Expand Down Expand Up @@ -327,6 +331,9 @@ void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc
categoryElem.setAttribute( QStringLiteral( "minScaleDenominator" ), QString::number( maximumScale ) );
categoryElem.setAttribute( QStringLiteral( "maxScaleDenominator" ), QString::number( minimumScale ) );
categoryElem.setAttribute( QStringLiteral( "opacity" ), QString::number( opacity ) );
categoryElem.setAttribute( QStringLiteral( "spacing" ), QString::number( mSpacing ) );
categoryElem.setAttribute( QStringLiteral( "spacingUnit" ), QgsUnitTypes::encodeUnit( mSpacingUnit ) );
categoryElem.setAttribute( QStringLiteral( "spacingUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSpacingMapUnitScale ) );

//diagram size unit type and scale
categoryElem.setAttribute( QStringLiteral( "sizeType" ), QgsUnitTypes::encodeUnit( sizeType ) );
Expand Down
71 changes: 71 additions & 0 deletions src/core/qgsdiagramrenderer.h
Expand Up @@ -467,6 +467,71 @@ class CORE_EXPORT QgsDiagramSettings
//! Scale diagrams smaller than mMinimumSize to mMinimumSize
double minimumSize = 0.0;

/**
* Returns the spacing between diagram contents.
*
* Spacing units can be retrieved by calling spacingUnit().
*
* \see setSpacing()
* \see spacingUnit()
* \see spacingMapUnitScale()
*
* \since QGIS 3.12
*/
double spacing() const { return mSpacing; }

/**
* Sets the \a spacing between diagram contents.
*
* Spacing units are set via setSpacingUnit().
*
* \see spacing()
* \see setSpacingUnit()
* \see setSpacingMapUnitScale()
*
* \since QGIS 3.12
*/
void setSpacing( double spacing ) { mSpacing = spacing; }

/**
* Sets the \a unit for the content spacing.
* \see spacingUnit()
* \see setSpacing()
* \see setSpacingMapUnitScale()
*
* \since QGIS 3.12
*/
void setSpacingUnit( QgsUnitTypes::RenderUnit unit ) { mSpacingUnit = unit; }

/**
* Returns the units for the content spacing.
* \see setSpacingUnit()
* \see spacing()
* \see spacingMapUnitScale()
* \since QGIS 3.12
*/
QgsUnitTypes::RenderUnit spacingUnit() const { return mSpacingUnit; }

/**
* Sets the map unit \a scale for the content spacing.
* \see spacingMapUnitScale()
* \see setSpacing()
* \see setSpacingUnit()
*
* \since QGIS 3.12
*/
void setSpacingMapUnitScale( const QgsMapUnitScale &scale ) { mSpacingMapUnitScale = scale; }

/**
* Returns the map unit scale for the content spacing.
* \see setSpacingMapUnitScale()
* \see spacing()
* \see spacingUnit()
*
* \since QGIS 3.12
*/
const QgsMapUnitScale &spacingMapUnitScale() const { return mSpacingMapUnitScale; }

//! Reads diagram settings from XML
void readXml( const QDomElement &elem );
//! Writes diagram settings to XML
Expand All @@ -479,6 +544,12 @@ class CORE_EXPORT QgsDiagramSettings
*/
QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const SIP_FACTORY;

private:

double mSpacing = 0;
QgsUnitTypes::RenderUnit mSpacingUnit;
QgsMapUnitScale mSpacingMapUnitScale;

};

/**
Expand Down

0 comments on commit 49dcc2c

Please sign in to comment.