Apply a color ramp to vector layer using PyQGIS3

Updated answer:

Below is a recipe to apply a graduated renderer based on values in an attribute field, specifying the number of classes and color ramp.

# Set layer name and desired paremeters
layer_name = 'Your_layer_name'
ramp_name = 'Spectral'
value_field = 'Your_field_name'
num_classes = 5
classification_method = QgsClassificationEqualInterval()

#You can use any of these classification method classes:
#QgsClassificationQuantile()
#QgsClassificationEqualInterval()
#QgsClassificationJenks()
#QgsClassificationPrettyBreaks()
#QgsClassificationLogarithmic()
#QgsClassificationStandardDeviation()

layer = QgsProject().instance().mapLayersByName(layer_name)[0]

# change format settings as necessary
format = QgsRendererRangeLabelFormat()
format.setFormat("%1 - %2")
format.setPrecision(2)
format.setTrimTrailingZeroes(True)

default_style = QgsStyle().defaultStyle()
color_ramp = default_style.colorRamp(ramp_name)

renderer = QgsGraduatedSymbolRenderer()
renderer.setClassAttribute(value_field)
renderer.setClassificationMethod(classification_method)
renderer.setLabelFormat(format)
renderer.updateClasses(layer, num_classes)
renderer.updateColorRamp(color_ramp)

layer.setRenderer(renderer)
layer.triggerRepaint()

I will leave the original answer below:

I have been through the same experience before, and (I may be wrong) but as far as I am aware, it is not possible to programmatically set a default color ramp and have it automatically applied. As you discovered, doing setSourceColorRamp() just sets that color ramp in the symbology dialog- it doesn't apply it to the renderer range symbols.

You have to create each range, instantiate QgsSymbol() objects, set colors to them and pass those in to a QgsRendererRange() constructor, together with the range and legend values.

It's a bit hacky, but I knocked out the script below which will create a graduated symbology with 10 classes (like your example above) in a basic spectral color ramp. Just change the layer name to match yours:

layer = QgsProject().instance().mapLayersByName('Your_Layer_Name')[0]
vals = []
fld = 'AREA'
for f in layer.getFeatures():
    vals.append(f[fld])
# If you don't like these colors, change them out for ones you do, using hexcodes,
# RGB codes etc. as long as the items in this list are valid strings you
# can pass to a QColor constructor 
colors = ['#0011FF', '#0061FF', '#00D4FF', '#00FF66', '#00FF00', '#E5FF32', '#FCFC0C', '#FF9F00', '#FF3F00', '#FF0000']
lower = sorted(vals)[0]
upper = sorted(vals)[-1]
step = (upper-lower)/len(colors)
range_list = []
for c in colors:
    cat = [lower, lower+step, c]
    sym = QgsSymbol.defaultSymbol(layer.geometryType())
    sym.setColor(QColor(cat[2]))
    rng = QgsRendererRange(cat[0], cat[1], sym, '{0:.1f}-{1:.1f}'.format(cat[0], cat[1]))
    range_list.append(rng)
    lower = (lower+step)+0.1
renderer = QgsGraduatedSymbolRenderer(fld, range_list)
layer.setRenderer(renderer)
layer.triggerRepaint()

Below is the result of this script run on a sample dataset- IBRA Bioregions of Australia, obtaining the graduation values from the "SHAPE_Area" field.

enter image description here

Based on the comment by @Cushen below, you could obtain a range of color values from an existing styled layer with a graduated ramp of the required number of classes and read those colors into a list object with a simple list comprehension:

styled_layer = iface.activeLayer() # existing layer styled with desired color ramp
colors = [s.color().name() for s in styled_layer.renderer().symbols(QgsRenderContext())]

I've put together a script using bits from @Ben W's answer as well as from this answer this answer to a different question.

This takes the following inputs:

  • Number of Classes (number_classes)
  • Filed to use in the ramp (fld)
  • Existing Color Ramp (colorRampNumber)
    • Optional Alternative: user specified start and end colors to use for a custom color ramp

This generates and applies a color ramp to the specified field of active layer with the number of classes chosen.

The colors are taken from the start and end colors of the specified preexisting ramp, intermediate colors are 'interpolated' thanks to the colour library; this might need to be downloaded.
Alternativly the user can specify the start and end colors themselves (c1 and c2).

Code here:

from qgis.PyQt.QtGui import QColor
import re
import colour
from colour import Color

#to interpolate colors:
def linear_color_interpolation(c1, c2, t):
    r = int(c1.red() + (c2.red() - c1.red()) * t)
    g = int(c1.green() + (c2.green() - c1.green()) * t)
    b = int(c1.blue() + (c2.blue() - c1.blue()) * t)
    return QColor(r, g, b)

layer = iface.activeLayer()
renderer = layer.renderer()
provider = layer.dataProvider()

#Specify inputs:
fld = 'roof_heigh'
colorRampNumber = 4
number_classes = 5

#COLOR RAMP STYLE:
myStyle = QgsStyle().defaultStyle()
defaultColorRampNames = myStyle.colorRampNames()
ramp = myStyle.colorRamp(defaultColorRampNames[colorRampNumber]) #Spectral color ramp


vals = []
for f in layer.getFeatures():
    vals.append(f[fld])
vals = (list(filter(None,vals))) #REMOVE NONE/NULL from list

idx = provider.fieldNameIndex(fld)
max = layer.maximumValue(idx)
min = layer.minimumValue(idx)
interval = (max - min)/(number_classes -1 )

#classes
sum = min
classes = []

for i in range(number_classes):
    tmp = int(round(sum, 0))
    classes.append(tmp)
    sum += interval

t_list = []
init = 0

for i in range(number_classes):
    t_list.append(init)
    init += 1./(number_classes-1)


#FIRST AND LAST COLORS FROM PREDEFINED RAMP
c1 = QColor(ramp.color(1).name())
c2 = QColor(ramp.color(-1).name())

## OR SPECIFY YOUR OWN START AND END COLORS:
#c1 = QColor('blue')
#c2 = QColor('yellow')
#c1 = QColor('#0000ff')
#c2 = QColor('#00ffff')


colors2 = list(Color(c1.name()).range_to(Color(c2.name()), number_classes))
colors3 = [ QColor(element.hex) 
            for element in colors2 ]
colors = [ linear_color_interpolation(c1, c2, t) for t in t_list ]
color_list = [ QgsColorRampShader.ColorRampItem(classes[i], colors3[i])  for i in range(number_classes) ]
# for col in color_list:
#     print (col.color.name())

lower = sorted(vals)[0]
lower = sorted(vals)[1] 
upper = sorted(vals)[-1]
step = (upper-lower)/len(colors)
grades = []

for c in colors:
    cat = [lower, lower+step, c]
    lower = (lower+step)+0.1
    grades.append(cat)
range_list = []

for i in grades:
    sym = QgsSymbol.defaultSymbol(layer.geometryType())
    sym.setColor(QColor(i[2]))
    rng = QgsRendererRange(i[0], i[1], sym, '{0:.1f}-{1:.1f}'.format(i[0], i[1]))
    range_list.append(rng)

renderer = QgsGraduatedSymbolRenderer(fld, range_list)

layer.setRenderer(renderer)
layer.triggerRepaint()

print ('\nCOLOR RAMP: %s' %(str(colorRampNumber)))
print ('COLOR 1: %s COLOR 2: %s' %(ramp.color(1).name(),ramp.color(-1).name()))
print ('MIN: %s MAX:%s' %(str(min), str(max)))
print ('NUMBER OF CLASSES: %s'%(str(number_classes)))
print('*** ALL DONE :D ***')