Skip to content

Commit

Permalink
[FEATURE] create_ramp() expression function
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed May 29, 2017
1 parent f250bef commit 3419945
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 9 deletions.
1 change: 1 addition & 0 deletions python/core/qgscolorramp.sip
Expand Up @@ -259,6 +259,7 @@ Creates a new QgsColorRamp from a map of properties
};



class QgsLimitedRandomColorRamp : QgsColorRamp
{
%Docstring
Expand Down
8 changes: 8 additions & 0 deletions resources/function_help/json/create_ramp
@@ -0,0 +1,8 @@
{
"name": "create_ramp",
"type": "function",
"description": "Returns a gradient ramp from a map of color strings and steps.",
"arguments": [ {"arg":"map","description":"a map of color strings and steps"},
{"arg":"discrete","optional":true,"description":"declare whether the color ramp is discrete"}],
"examples": [ { "expression":"ramp_color(create_array(map(0,'0,0,0',1,'255,0,0')),1)", "returns":"'255,0,0,255'"} ]
}
16 changes: 13 additions & 3 deletions resources/function_help/json/ramp_color
Expand Up @@ -2,8 +2,18 @@
"name": "ramp_color",
"type": "function",
"description": "Returns a string representing a color from a color ramp.",
"arguments": [ {"arg":"ramp_name","description":"the name of the color ramp as a string, for example 'Spectral'"},
"variants": [
{ "variant": "Saved ramp variant",
"variant_description": "Returns a string representing a color from a saved ramp",
"arguments": [ {"arg":"ramp_name","description":"the name of the color ramp as a string, for example 'Spectral'"},
{"arg":"value","description":"the position on the ramp to select the color from as a real number between 0 and 1"}],
"examples": [ { "expression":"ramp_color('Spectral',0.3)", "returns":"'253,190,115,255'"} ],
"notes": "The color ramps available vary between QGIS installations. This function may not give the expected results if you move your QGIS project between installations."
"examples": [ { "expression":"ramp_color('Spectral',0.3)", "returns":"'253,190,115,255'"} ],
"notes": "The color ramps available vary between QGIS installations. This function may not give the expected results if you move your QGIS project between installations."
},
{ "variant": "Expression-created ramp variant",
"variant_description": "Returns a string representing a color from an expression-created ramp",
"arguments": [ {"arg":"ramp","description":"the color ramp"},
{"arg":"value","description":"the position on the ramp to select the color from as a real number between 0 and 1"}],
"examples": [ { "expression":"ramp_color(create_array(map(0,'0,0,0',1,'255,0,0')),1)", "returns":"'255,0,0,255'"} ]
}]
}
5 changes: 5 additions & 0 deletions src/core/expression/qgsexpression.cpp
Expand Up @@ -18,6 +18,7 @@
#include "qgsexpressionprivate.h"
#include "qgsexpressionnodeimpl.h"
#include "qgsfeaturerequest.h"
#include "qgscolorramp.h"
#include "qgslogger.h"
#include "qgsexpressioncontext.h"
#include "qgsgeometry.h"
Expand Down Expand Up @@ -763,6 +764,10 @@ QString QgsExpression::formatPreviewString( const QVariant &value )
QgsInterval interval = value.value<QgsInterval>();
return tr( "<i>&lt;interval: %1 days&gt;</i>" ).arg( interval.days() );
}
else if ( value.canConvert< QgsGradientColorRamp >() )
{
return tr( "<i>&lt;gradient ramp&gt;</i>" );
}
else if ( value.type() == QVariant::Date )
{
QDate dt = value.toDate();
Expand Down
66 changes: 60 additions & 6 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -40,6 +40,7 @@
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"
#include "qgsrasterbandstats.h"
#include "qgscolorramp.h"

const QString QgsExpressionFunction::helpText() const
{
Expand Down Expand Up @@ -2943,15 +2944,26 @@ static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionCon

QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
{
QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
const QgsColorRamp *mRamp = QgsStyle::defaultStyle()->colorRampRef( rampName );
if ( ! mRamp )
QgsGradientColorRamp expRamp;
const QgsColorRamp *ramp;
if ( values.at( 0 ).canConvert<QgsGradientColorRamp>() )
{
parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
return QColor( 0, 0, 0 ).name();
expRamp = QgsExpressionUtils::getRamp( values.at( 0 ), parent );
ramp = &expRamp;
}
else
{
QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
ramp = QgsStyle::defaultStyle()->colorRampRef( rampName );
if ( ! ramp )
{
parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
return QVariant();
}
}

double value = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
QColor color = mRamp->color( value );
QColor color = ramp->color( value );
return QgsSymbolLayerUtils::encodeColor( color );
}

Expand Down Expand Up @@ -3122,6 +3134,47 @@ static QVariant fncColorPart( const QVariantList &values, const QgsExpressionCon
return QVariant();
}

static QVariant fcnCreateRamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
{
const QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
if ( map.count() < 1 )
{
parent->setEvalErrorString( QObject::tr( "A minimum of two colors is required to create a ramp" ) );
return QVariant();
}

QList< QColor > colors;
QgsGradientStopsList stops;
for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
{
colors << QgsSymbolLayerUtils::decodeColor( it.value().toString() );
if ( !colors.last().isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( it.value().toString() ) );
return QVariant();
}

double step = it.key().toDouble();
if ( it == map.constBegin() )
{
if ( step != 0.0 )
stops << QgsGradientStop( step, colors.last() );
}
else if ( it == map.constEnd() )
{
if ( step != 1.0 )
stops << QgsGradientStop( step, colors.last() );
}
else
{
stops << QgsGradientStop( step, colors.last() );
}
}
bool discrete = values.at( 1 ).toBool();

return QVariant::fromValue( QgsGradientColorRamp( colors.first(), colors.last(), discrete, stops ) );
}

static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
{
QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
Expand Down Expand Up @@ -3825,6 +3878,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "color_rgb" ), 3, fcnColorRgb, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_rgba" ), 4, fncColorRgba, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "ramp_color" ), 2, fcnRampColor, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "create_ramp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "discrete" ), true, false ), fcnCreateRamp, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsl" ), 3, fcnColorHsl, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsla" ), 4, fncColorHsla, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsv" ), 3, fcnColorHsv, QStringLiteral( "Color" ) )
Expand Down
13 changes: 13 additions & 0 deletions src/core/expression/qgsexpressionutils.h
Expand Up @@ -19,6 +19,7 @@

#include "qgsfeature.h"
#include "qgsexpression.h"
#include "qgscolorramp.h"
#include "qgsvectorlayer.h"
#include "qgsproject.h"
#include "qgsrelationmanager.h"
Expand Down Expand Up @@ -291,6 +292,18 @@ class QgsExpressionUtils
return QgsInterval();
}

static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false )
{
if ( value.canConvert<QgsGradientColorRamp>() )
return value.value<QgsGradientColorRamp>();

// If we get here then we can't convert so we just error and return invalid.
if ( report_error )
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to QgsGradientColorRamp" ).arg( value.toString() ) );

return QgsGradientColorRamp();
}

static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
{
if ( value.canConvert<QgsGeometry>() )
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgscolorramp.h
Expand Up @@ -240,6 +240,8 @@ class CORE_EXPORT QgsGradientColorRamp : public QgsColorRamp
QgsStringMap mInfo;
};

Q_DECLARE_METATYPE( QgsGradientColorRamp )

#define DEFAULT_RANDOM_COUNT 10
#define DEFAULT_RANDOM_HUE_MIN 0
#define DEFAULT_RANDOM_HUE_MAX 359
Expand Down
6 changes: 6 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -1010,6 +1010,12 @@ class TestQgsExpression: public QObject

// Color functions
QTest::newRow( "ramp color" ) << "ramp_color('Spectral',0.3)" << false << QVariant( "254,190,116,255" );
QTest::newRow( "create ramp color, wrong parameter" ) << "create_ramp(1)" << true << QVariant();
QTest::newRow( "create ramp color, no color" ) << "create_ramp(map())" << true << QVariant();
QTest::newRow( "create ramp color, one color" ) << "ramp_color(create_ramp(map(0,'0,0,0')),0.5)" << false << QVariant( "0,0,0,255" );
QTest::newRow( "create ramp color, two colors" ) << "ramp_color(create_ramp(map(0,'0,0,0',1,'255,0,0')),0.33)" << false << QVariant( "84,0,0,255" );
QTest::newRow( "create ramp color, four colors" ) << "ramp_color(create_ramp(map(0,'0,0,0',0.33,'0,255,0',0.66,'0,0,255',1,'255,0,0')),0.5)" << false << QVariant( "0,124,131,255" );
QTest::newRow( "create ramp color, discrete" ) << "ramp_color(create_ramp(map(0,'0,0,0',0.33,'0,255,0',0.66,'0,0,255',1,'255,0,0'),true),0.6)" << false << QVariant( "0,255,0,255" );
QTest::newRow( "color rgb" ) << "color_rgb(255,127,0)" << false << QVariant( "255,127,0" );
QTest::newRow( "color rgba" ) << "color_rgba(255,127,0,200)" << false << QVariant( "255,127,0,200" );
QTest::newRow( "color hsl" ) << "color_hsl(100,50,70)" << false << QVariant( "166,217,140" );
Expand Down

0 comments on commit 3419945

Please sign in to comment.