'Take the input RGB array (ny*nx*3) adjust their color values
to given the impression of a shaded relief map with a
specified light source using the elevation (ny*nx).
A new RGB array ((ny*nx*3)) is returned.
Parameters
rgb : array-like
An MxNx3 RGB array, assumed to be in the range of 0 to 1.
elevation : array-like
A 2d array (or equivalent) of the height values used to generate a
shaded map.
fraction : number
Increases or decreases the contrast of the hillshade.  Values
greater than one will cause intermediate values to move closer to
full illumination or shadow (and clipping any values that move
beyond 0 or 1). Note that this is not visually or mathematically
the same as vertical exaggeration.
blend_mode : {\'hsv\', \'overlay\', \'soft\'} or callable, optional
The type of blending used to combine the colormapped data values
with the illumination intensity.  For backwards compatibility, this
defaults to "hsv". Note that for most topographic surfaces,
"overlay" or "soft" appear more visually realistic. If a
user-defined function is supplied, it is expected to combine an
MxNx3 RGB array of floats (ranging 0 to 1) with an MxNx1 hillshade
array (also 0 to 1).  (Call signature `func(rgb, illum, **kwargs)`)
Additional kwargs supplied to this function will be passed on to
the *blend_mode* function.
vert_exag : number, optional
The amount to exaggerate the elevation values by when calculating
illumination. This can be used either to correct for differences in
units between the x-y coordinate system and the elevation
coordinate system (e.g. decimal degrees vs meters) or to exaggerate
or de-emphasize topography.
dx : number, optional
The x-spacing (columns) of the input *elevation* grid.
dy : number, optional
The y-spacing (rows) of the input *elevation* grid.
Additional kwargs are passed on to the *blend_mode* function.
Returns
shaded_rgb : ndarray
An MxNx3 array of floats ranging between 0-1.'

def shade_rgb(self, rgb, elevation, fraction=1.0, blend_mode=u'hsv', vert_exag=1, dx=1, dy=1, **kwargs):

    intensity = self.hillshade(elevation, vert_exag, dx, dy, fraction)
    intensity = intensity[..., np.newaxis]
    lookup = {u'hsv': self.blend_hsv, u'soft': self.blend_soft_light, u'overlay': self.blend_overlay}
    if (blend_mode in lookup):
        blend = lookup[blend_mode](rgb, intensity, **kwargs)
    else:
        try:
            blend = blend_mode(rgb, intensity, **kwargs)
        except TypeError:
            msg = u'"blend_mode"    must    be    callable    or    one    of    {0}'
            raise ValueError(msg.format(lookup.keys))
    if hasattr(intensity, u'mask'):
        mask = intensity.mask[..., 0]
        for i in range(3):
            blend[..., i][mask] = rgb[..., i][mask]
    return blend
