Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Lightsource enhancements #3291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Sep 29, 2014
Merged
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ee99cf5
Refactored LightSource.shade_rgb into three separate functions
joferkington Jul 21, 2014
4faa454
Added support for vertical exag and non-uniform spacing to LightSource
joferkington Jul 21, 2014
a1af495
Added new blending modes to LightSource for more realistic rendering
joferkington Jul 21, 2014
ed5cd76
Updated shading example to show new styles and added exmaple DEM from…
joferkington Jul 22, 2014
0db6341
Make the "fraction" kwarg behave as it did before recent LightSource …
joferkington Jul 23, 2014
52434ff
Strip whitespace and strict PEP8 compliance
joferkington Jul 23, 2014
108eac7
Avoid potential divide by zero in LightSource.hillshade
joferkington Jul 23, 2014
f374383
Fix calculation of aspect for hillshading.
joferkington Jul 25, 2014
3c9cacf
Make clipping work properly for effectively planar surfaces
joferkington Jul 25, 2014
51e9a6c
Added tests for LightSource functionality
joferkington Jul 26, 2014
31a4239
Added example of using the custom hillshading on a 3D surface plot
joferkington Jul 26, 2014
b3e2e3d
PEP8 fixes
joferkington Jul 26, 2014
bdbc7df
Avoid leaking file descriptors in tests and examples
joferkington Jul 26, 2014
71cb786
Added more examples
joferkington Sep 26, 2014
4afed00
Fixed hillshading problems with masked elevation arrays
joferkington Sep 27, 2014
abf8b87
Added array comparison tests for shaded relief
joferkington Sep 27, 2014
ba1f492
Strict PEP8 compliance for printed arrays
joferkington Sep 27, 2014
ab40a2f
Added *vmin* and *vmax* arguments to LightSource.shade
joferkington Sep 27, 2014
9fce26c
Added LightSource changes summary to CHANGELOG
joferkington Sep 27, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Strip whitespace and strict PEP8 compliance
  • Loading branch information
joferkington committed Jul 23, 2014
commit 52434ff91ab6ab31b09b14ee187a0fede11b049d
46 changes: 24 additions & 22 deletions lib/matplotlib/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1457,15 +1457,16 @@ def hsv_to_rgb(hsv):

return rgb


class LightSource(object):
"""
Create a light source coming from the specified azimuth and elevation.
Angles are in degrees, with the azimuth measured
clockwise from north and elevation up from the zero plane of the surface.

The :meth:`shade` is used to produce "shaded" rgb values for a data array.
:meth:`shade_rgb` can be used to combine an rgb image with
The :meth:`shade_rgb`
:meth:`shade_rgb` can be used to combine an rgb image with
The :meth:`shade_rgb`
The :meth:`hillshade` produces an illumination map of a surface.
"""
def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1,
Expand All @@ -1486,7 +1487,7 @@ def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1,

Notes
-----
For backwards compatibility, the parameters *hsv_min_val*,
For backwards compatibility, the parameters *hsv_min_val*,
*hsv_max_val*, *hsv_min_sat*, and *hsv_max_sat* may be supplied at
initialization as well. However, these parameters will only be used if
"blend_mode='hsv'" is passed into :meth:`shade` or :meth:`shade_rgb`.
Expand All @@ -1502,12 +1503,12 @@ def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1,
def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.):
"""
Calculates the illumination intensity for a surface using the defined
azimuth and elevation for the light source.
azimuth and elevation for the light source.

Imagine an artificial sun placed at infinity in some azimuth and
elevation position illuminating our surface. The parts of the surface
that slope toward the sun should brighten while those sides facing away
should become darker.
should become darker.

Parameters
----------
Expand Down Expand Up @@ -1549,8 +1550,8 @@ def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.):
dy, dx = np.gradient(vert_exag * elevation, dy, dx)
slope = 0.5 * np.pi - np.arctan(np.hypot(dx, dy))
aspect = np.arctan2(dx, dy)
intensity = (np.sin(alt) * np.sin(slope)
+ np.cos(alt) * np.cos(slope)
intensity = (np.sin(alt) * np.sin(slope)
+ np.cos(alt) * np.cos(slope)
* np.cos(az - aspect))

# Apply contrast stretch
Expand All @@ -1565,10 +1566,10 @@ def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.):

return intensity

def shade(self, data, cmap, norm=None, blend_mode='hsv',
def shade(self, data, cmap, norm=None, blend_mode='hsv',
vert_exag=1, dx=1, dy=1, fraction=1, **kwargs):
"""
Combine colormapped data values with an illumination intensity map
Combine colormapped data values with an illumination intensity map
(a.k.a. "hillshade") of the values.

Parameters
Expand All @@ -1587,7 +1588,7 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv',
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,
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
Expand All @@ -1610,8 +1611,8 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv',
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.
Additional kwargs are passed on to the *blend_mode* function.
Additional kwargs are passed on to the *blend_mode* function.

Returns
-------
rgba : ndarray
Expand All @@ -1621,14 +1622,14 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv',
norm = Normalize(vmin=data.min(), vmax=data.max())

rgb0 = cmap(norm(data))
rgb1 = self.shade_rgb(rgb0, elevation=data, blend_mode=blend_mode,
rgb1 = self.shade_rgb(rgb0, elevation=data, blend_mode=blend_mode,
vert_exag=vert_exag, dx=dx, dy=dy,
fraction=fraction, **kwargs)
# Don't overwrite the alpha channel, if present.
rgb0[..., :3] = rgb1[..., :3]
return rgb0

def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv',
def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv',
vert_exag=1, dx=1, dy=1, **kwargs):
"""
Take the input RGB array (ny*nx*3) adjust their color values
Expand All @@ -1652,7 +1653,7 @@ def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv',
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,
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
Expand All @@ -1669,8 +1670,8 @@ def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv',
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.
Additional kwargs are passed on to the *blend_mode* function.

Returns
-------
shaded_rgb : ndarray
Expand All @@ -1682,9 +1683,9 @@ def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv',

# Blend the hillshade and rgb data using the specified mode
lookup = {
'hsv':self.blend_hsv,
'soft':self.blend_soft_light,
'overlay':self.blend_overlay,
'hsv': self.blend_hsv,
'soft': self.blend_soft_light,
'overlay': self.blend_overlay,
}
if blend_mode in lookup:
return lookup[blend_mode](rgb, intensity, **kwargs)
Expand Down Expand Up @@ -1794,7 +1795,7 @@ def blend_soft_light(self, rgb, intensity):
rgb : ndarray
An MxNx3 RGB array representing the combined images.
"""
return 2 * intensity * rgb + (1 - 2 * intensity) * rgb**2
return 2 * intensity * rgb + (1 - 2 * intensity) * rgb**2

def blend_overlay(self, rgb, intensity):
"""
Expand All @@ -1816,6 +1817,7 @@ def blend_overlay(self, rgb, intensity):
high = 1 - 2 * (1 - intensity) * (1 - rgb)
return np.where(rgb <= 0.5, low, high)


def from_levels_and_colors(levels, colors, extend='neither'):
"""
A helper routine to generate a cmap and a norm instance which
Expand Down