Skip to content

Commit 3419945

Browse files
committedMay 29, 2017
[FEATURE] create_ramp() expression function
1 parent f250bef commit 3419945

File tree

8 files changed

+108
-9
lines changed

8 files changed

+108
-9
lines changed
 

‎python/core/qgscolorramp.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ Creates a new QgsColorRamp from a map of properties
259259
};
260260

261261

262+
262263
class QgsLimitedRandomColorRamp : QgsColorRamp
263264
{
264265
%Docstring
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "create_ramp",
3+
"type": "function",
4+
"description": "Returns a gradient ramp from a map of color strings and steps.",
5+
"arguments": [ {"arg":"map","description":"a map of color strings and steps"},
6+
{"arg":"discrete","optional":true,"description":"declare whether the color ramp is discrete"}],
7+
"examples": [ { "expression":"ramp_color(create_array(map(0,'0,0,0',1,'255,0,0')),1)", "returns":"'255,0,0,255'"} ]
8+
}

‎resources/function_help/json/ramp_color

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@
22
"name": "ramp_color",
33
"type": "function",
44
"description": "Returns a string representing a color from a color ramp.",
5-
"arguments": [ {"arg":"ramp_name","description":"the name of the color ramp as a string, for example 'Spectral'"},
5+
"variants": [
6+
{ "variant": "Saved ramp variant",
7+
"variant_description": "Returns a string representing a color from a saved ramp",
8+
"arguments": [ {"arg":"ramp_name","description":"the name of the color ramp as a string, for example 'Spectral'"},
69
{"arg":"value","description":"the position on the ramp to select the color from as a real number between 0 and 1"}],
7-
"examples": [ { "expression":"ramp_color('Spectral',0.3)", "returns":"'253,190,115,255'"} ],
8-
"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."
10+
"examples": [ { "expression":"ramp_color('Spectral',0.3)", "returns":"'253,190,115,255'"} ],
11+
"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."
12+
},
13+
{ "variant": "Expression-created ramp variant",
14+
"variant_description": "Returns a string representing a color from an expression-created ramp",
15+
"arguments": [ {"arg":"ramp","description":"the color ramp"},
16+
{"arg":"value","description":"the position on the ramp to select the color from as a real number between 0 and 1"}],
17+
"examples": [ { "expression":"ramp_color(create_array(map(0,'0,0,0',1,'255,0,0')),1)", "returns":"'255,0,0,255'"} ]
18+
}]
919
}

‎src/core/expression/qgsexpression.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "qgsexpressionprivate.h"
1919
#include "qgsexpressionnodeimpl.h"
2020
#include "qgsfeaturerequest.h"
21+
#include "qgscolorramp.h"
2122
#include "qgslogger.h"
2223
#include "qgsexpressioncontext.h"
2324
#include "qgsgeometry.h"
@@ -763,6 +764,10 @@ QString QgsExpression::formatPreviewString( const QVariant &value )
763764
QgsInterval interval = value.value<QgsInterval>();
764765
return tr( "<i>&lt;interval: %1 days&gt;</i>" ).arg( interval.days() );
765766
}
767+
else if ( value.canConvert< QgsGradientColorRamp >() )
768+
{
769+
return tr( "<i>&lt;gradient ramp&gt;</i>" );
770+
}
766771
else if ( value.type() == QVariant::Date )
767772
{
768773
QDate dt = value.toDate();

‎src/core/expression/qgsexpressionfunction.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "qgsrasterlayer.h"
4141
#include "qgsvectorlayer.h"
4242
#include "qgsrasterbandstats.h"
43+
#include "qgscolorramp.h"
4344

4445
const QString QgsExpressionFunction::helpText() const
4546
{
@@ -2943,15 +2944,26 @@ static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionCon
29432944

29442945
QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
29452946
{
2946-
QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2947-
const QgsColorRamp *mRamp = QgsStyle::defaultStyle()->colorRampRef( rampName );
2948-
if ( ! mRamp )
2947+
QgsGradientColorRamp expRamp;
2948+
const QgsColorRamp *ramp;
2949+
if ( values.at( 0 ).canConvert<QgsGradientColorRamp>() )
29492950
{
2950-
parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2951-
return QColor( 0, 0, 0 ).name();
2951+
expRamp = QgsExpressionUtils::getRamp( values.at( 0 ), parent );
2952+
ramp = &expRamp;
29522953
}
2954+
else
2955+
{
2956+
QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2957+
ramp = QgsStyle::defaultStyle()->colorRampRef( rampName );
2958+
if ( ! ramp )
2959+
{
2960+
parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2961+
return QVariant();
2962+
}
2963+
}
2964+
29532965
double value = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2954-
QColor color = mRamp->color( value );
2966+
QColor color = ramp->color( value );
29552967
return QgsSymbolLayerUtils::encodeColor( color );
29562968
}
29572969

@@ -3122,6 +3134,47 @@ static QVariant fncColorPart( const QVariantList &values, const QgsExpressionCon
31223134
return QVariant();
31233135
}
31243136

3137+
static QVariant fcnCreateRamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3138+
{
3139+
const QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
3140+
if ( map.count() < 1 )
3141+
{
3142+
parent->setEvalErrorString( QObject::tr( "A minimum of two colors is required to create a ramp" ) );
3143+
return QVariant();
3144+
}
3145+
3146+
QList< QColor > colors;
3147+
QgsGradientStopsList stops;
3148+
for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
3149+
{
3150+
colors << QgsSymbolLayerUtils::decodeColor( it.value().toString() );
3151+
if ( !colors.last().isValid() )
3152+
{
3153+
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( it.value().toString() ) );
3154+
return QVariant();
3155+
}
3156+
3157+
double step = it.key().toDouble();
3158+
if ( it == map.constBegin() )
3159+
{
3160+
if ( step != 0.0 )
3161+
stops << QgsGradientStop( step, colors.last() );
3162+
}
3163+
else if ( it == map.constEnd() )
3164+
{
3165+
if ( step != 1.0 )
3166+
stops << QgsGradientStop( step, colors.last() );
3167+
}
3168+
else
3169+
{
3170+
stops << QgsGradientStop( step, colors.last() );
3171+
}
3172+
}
3173+
bool discrete = values.at( 1 ).toBool();
3174+
3175+
return QVariant::fromValue( QgsGradientColorRamp( colors.first(), colors.last(), discrete, stops ) );
3176+
}
3177+
31253178
static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
31263179
{
31273180
QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
@@ -3825,6 +3878,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
38253878
<< new QgsStaticExpressionFunction( QStringLiteral( "color_rgb" ), 3, fcnColorRgb, QStringLiteral( "Color" ) )
38263879
<< new QgsStaticExpressionFunction( QStringLiteral( "color_rgba" ), 4, fncColorRgba, QStringLiteral( "Color" ) )
38273880
<< new QgsStaticExpressionFunction( QStringLiteral( "ramp_color" ), 2, fcnRampColor, QStringLiteral( "Color" ) )
3881+
<< new QgsStaticExpressionFunction( QStringLiteral( "create_ramp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "discrete" ), true, false ), fcnCreateRamp, QStringLiteral( "Color" ) )
38283882
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsl" ), 3, fcnColorHsl, QStringLiteral( "Color" ) )
38293883
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsla" ), 4, fncColorHsla, QStringLiteral( "Color" ) )
38303884
<< new QgsStaticExpressionFunction( QStringLiteral( "color_hsv" ), 3, fcnColorHsv, QStringLiteral( "Color" ) )

‎src/core/expression/qgsexpressionutils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "qgsfeature.h"
2121
#include "qgsexpression.h"
22+
#include "qgscolorramp.h"
2223
#include "qgsvectorlayer.h"
2324
#include "qgsproject.h"
2425
#include "qgsrelationmanager.h"
@@ -291,6 +292,18 @@ class QgsExpressionUtils
291292
return QgsInterval();
292293
}
293294

295+
static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false )
296+
{
297+
if ( value.canConvert<QgsGradientColorRamp>() )
298+
return value.value<QgsGradientColorRamp>();
299+
300+
// If we get here then we can't convert so we just error and return invalid.
301+
if ( report_error )
302+
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to QgsGradientColorRamp" ).arg( value.toString() ) );
303+
304+
return QgsGradientColorRamp();
305+
}
306+
294307
static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
295308
{
296309
if ( value.canConvert<QgsGeometry>() )

‎src/core/qgscolorramp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ class CORE_EXPORT QgsGradientColorRamp : public QgsColorRamp
240240
QgsStringMap mInfo;
241241
};
242242

243+
Q_DECLARE_METATYPE( QgsGradientColorRamp )
244+
243245
#define DEFAULT_RANDOM_COUNT 10
244246
#define DEFAULT_RANDOM_HUE_MIN 0
245247
#define DEFAULT_RANDOM_HUE_MAX 359

‎tests/src/core/testqgsexpression.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,12 @@ class TestQgsExpression: public QObject
10101010

10111011
// Color functions
10121012
QTest::newRow( "ramp color" ) << "ramp_color('Spectral',0.3)" << false << QVariant( "254,190,116,255" );
1013+
QTest::newRow( "create ramp color, wrong parameter" ) << "create_ramp(1)" << true << QVariant();
1014+
QTest::newRow( "create ramp color, no color" ) << "create_ramp(map())" << true << QVariant();
1015+
QTest::newRow( "create ramp color, one color" ) << "ramp_color(create_ramp(map(0,'0,0,0')),0.5)" << false << QVariant( "0,0,0,255" );
1016+
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" );
1017+
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" );
1018+
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" );
10131019
QTest::newRow( "color rgb" ) << "color_rgb(255,127,0)" << false << QVariant( "255,127,0" );
10141020
QTest::newRow( "color rgba" ) << "color_rgba(255,127,0,200)" << false << QVariant( "255,127,0,200" );
10151021
QTest::newRow( "color hsl" ) << "color_hsl(100,50,70)" << false << QVariant( "166,217,140" );

0 commit comments

Comments
 (0)
Please sign in to comment.