Revision: 6975
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6975&view=rev
Author: jswhit
Date: 2009-03-14 13:22:32 +0000 (Sat, 14 Mar 2009)
Log Message:
-----------
added 'lightsource' class to colors module, shading_example.py
to illustrate it's usage to create shaded relief maps with imshow.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/colors.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/shading_example.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-03-13 17:13:49 UTC (rev 6974)
+++ trunk/matplotlib/CHANGELOG 2009-03-14 13:22:32 UTC (rev 6975)
@@ -1,3 +1,7 @@
+2009-03-14 Added 'lightsource' class to colors module for
+ creating shaded relief maps. shading_example.py
+ added to illustrate usage. - JSW
+
2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and
Chris Barker. - EF
Added: trunk/matplotlib/examples/pylab_examples/shading_example.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/shading_example.py
(rev 0)
+++ trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-14
13:22:32 UTC (rev 6975)
@@ -0,0 +1,28 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from matplotlib.colors import lightsource
+
+# example showing how to make shaded relief plots
+# like mathematica
+# (http://reference.wolfram.com/mathematica/ref/ReliefPlot.html )
+# or Generic Mapping Tools
+# (http://gmt.soest.hawaii.edu/gmt/doc/gmt/html/GMT_Docs/node145.html)
+
+# test data
+X,Y=np.mgrid[-5:5:0.1,-5:5:0.1]
+Z=X+np.sin(X**2+Y**2)
+# creat light source object.
+ls = lightsource(azdeg=270,altdeg=20)
+# shade data, creating an rgb array.
+rgb = ls.shade(Z,plt.cm.copper)
+# plot un-shaded and shaded images.
+plt.figure(figsize=(12,5))
+plt.subplot(121)
+plt.imshow(Z,cmap=plt.cm.copper)
+plt.title('imshow')
+plt.xticks([]); plt.yticks([])
+plt.subplot(122)
+plt.imshow(rgb)
+plt.title('imshow with shading')
+plt.xticks([]); plt.yticks([])
+plt.show()
Modified: trunk/matplotlib/lib/matplotlib/colors.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-13 17:13:49 UTC (rev
6974)
+++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:22:32 UTC (rev
6975)
@@ -900,3 +900,130 @@
# compatibility with earlier class names that violated convention:
normalize = Normalize
no_norm = NoNorm
+
+def rgb_to_hsv(arr):
+ """
+ convert rgb values in a numpy array to hsv values
+ input and output arrays should have shape (M,N,3)
+ """
+ out = np.empty_like(arr)
+ arr_max = arr.max(-1)
+ delta = arr.ptp(-1)
+ s = delta / arr_max
+ s[delta==0] = 0
+ # red is max
+ idx = (arr[:,:,0] == arr_max)
+ out[idx, 0] = (arr[idx, 1] - arr[idx, 2]) / delta[idx]
+ # green is max
+ idx = (arr[:,:,1] == arr_max)
+ out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0] ) / delta[idx]
+ # blue is max
+ idx = (arr[:,:,2] == arr_max)
+ out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1] ) / delta[idx]
+ out[:,:,0] = (out[:,:,0]/6.0) % 1.0
+ out[:,:,1] = s
+ out[:,:,2] = arr_max
+ return out
+
+def hsv_to_rgb(hsv):
+ """
+ convert hsv values in a numpy array to rgb values
+ both input and output arrays have shape (M,N,3)
+ """
+ h = hsv[:,:,0]; s = hsv[:,:,1]; v = hsv[:,:,2]
+ r = np.empty_like(h); g = np.empty_like(h); b = np.empty_like(h)
+ i = (h*6.0).astype(np.int)
+ f = (h*6.0) - i
+ p = v*(1.0 - s)
+ q = v*(1.0 - s*f)
+ t = v*(1.0 - s*(1.0-f))
+ idx = i%6 == 0
+ r[idx] = v[idx]; g[idx] = t[idx]; b[idx] = p[idx]
+ idx = i == 1
+ r[idx] = q[idx]; g[idx] = v[idx]; b[idx] = p[idx]
+ idx = i == 2
+ r[idx] = p[idx]; g[idx] = v[idx]; b[idx] = t[idx]
+ idx = i == 3
+ r[idx] = p[idx]; g[idx] = q[idx]; b[idx] = v[idx]
+ idx = i == 4
+ r[idx] = t[idx]; g[idx] = p[idx]; b[idx] = v[idx]
+ idx = i == 5
+ r[idx] = v[idx]; g[idx] = p[idx]; b[idx] = q[idx]
+ idx = s == 0
+ r[idx] = v[idx]; g[idx] = v[idx]; b[idx] = v[idx]
+ return np.array((r,g,b)).T
+
+class lightsource(object):
+ """
+ Create a light source coming from the specified azimuth and elevation.
+ Angles are in degrees, with the azimuth measured
+ clockwise from south and elevation up from the zero plane of the surface.
+ The :meth:`shade` is used to produce rgb values for a shaded relief image
+ given a data array.
+ """
+ def __init__(self,azdeg=315,altdeg=45,\
+ hsv_min_val=0,hsv_max_val=1,hsv_min_sat=1,hsv_max_sat=0):
+ """
+ Specify the azimuth (measured clockwise from south) and altitude
+ (measured up from the plane of the surface) of the light source
+ in degrees.
+
+ The color of the resulting image will be darkened
+ by moving the (s,v) values (in hsv colorspace) toward
+ (hsv_min_sat, hsv_min_val) in the shaded regions, or
+ lightened by sliding (s,v) toward
+ (hsv_max_sat hsv_max_val) in regions that are illuminated.
+ The default extremes are chose so that completely shaded points
+ are nearly black (s = 1, v = 0) and completely illuminated points
+ are nearly white (s = 0, v = 1).
+ """
+ self.azdeg = azdeg
+ self.altdeg = altdeg
+ self.hsv_min_val = hsv_min_val
+ self.hsv_max_val = hsv_max_val
+ self.hsv_min_sat = hsv_min_sat
+ self.hsv_max_sat = hsv_max_sat
+
+ def shade(self,data,cmap):
+ """
+ Take the input data array, convert to HSV values in the
+ given colormap, then adjust those color values
+ to given the impression of a shaded relief map with a
+ specified light source.
+ RGBA values are returned, which can then be used to
+ plot the shaded image with imshow.
+ """
+ # 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.
+ # convert alt, az to radians
+ az = self.azdeg*np.pi/180.0
+ alt = self.altdeg*np.pi/180.0
+ # gradient in x and y directions
+ dx, dy = np.gradient(data)
+ 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)*np.cos(-az -\
+ aspect - 0.5*np.pi)
+ # rescale to interval -1,1
+ # +1 means maximum sun exposure and -1 means complete shade.
+ intensity = (intensity - intensity.min())/(intensity.max() -
intensity.min())
+ intensity = 2.*intensity - 1.
+ # convert to rgb, then rgb to hsv
+ rgb = cmap((data-data.min())/(data.max()-data.min()))
+ hsv = rgb_to_hsv(rgb[:,:,0:3])
+ # modify hsv values to simulate illumination.
+ hsv[:,:,1] =
np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity>0),\
+ (1.-intensity)*hsv[:,:,1]+intensity*self.hsv_max_sat,
hsv[:,:,1])
+ hsv[:,:,2] = np.where(intensity > 0, (1.-intensity)*hsv[:,:,1] +\
+ intensity*self.hsv_max_val, hsv[:,:,2])
+ hsv[:,:,1] =
np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity<0),\
+ (1.+intensity)*hsv[:,:,1]-intensity*self.hsv_min_sat,
hsv[:,:,1])
+ hsv[:,:,2] = np.where(intensity < 0, (1.+intensity)*hsv[:,:,1] -\
+ intensity*self.hsv_min_val, hsv[:,:,2])
+ hsv[:,:,1:] = np.where(hsv[:,:,1:]<0.,0,hsv[:,:,1:])
+ hsv[:,:,1:] = np.where(hsv[:,:,1:]>1.,1,hsv[:,:,1:])
+ # convert modified hsv back to rgb.
+ rgb[:,:,0:3] = hsv_to_rgb(hsv)
+ return rgb
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins