Hey John and the rest of the MPL gang:
I've made the changes you suggested, but the problem is looking to be
deeper than it seemed. I'm also moving this conversation to
matplotlib-devel, since that's probably the more appropriate place for
it.
This updated patch allows for the creation of colormaps with various
alphas, but there is likely more work to be done so that mpl can
consistently make use of it (because it seems like all built-in cmaps
are RGB, not RGBA).
In trying to come up with an example that exercises the new
capabilities, I found out that methods like scatter and countourf modify
the colormap you give them and reset all of the alpha values to 1.
I think this is because inside collections, we pass self._alpha, which
is the Artist._alpha, and 1.0 by default, when making calls such
as:
_colors.colorConverter.to_rgba_array(c, self._alpha)
...Thus resetting all of alpha values.
I was able to get around this by allowing collections to take on an
alpha value of None, and then passing alpha=None to scatter and
countourf, for example. There are probably other places where such a
change should be done, unless someone has a better idea for how do do
this. I updated examples/pylab/plot_scatter.py to show off the new
capability.
Another thing that I was unable to get around is that if you now make a
plot using the same colormap but omit the alpha=None parameter, or set
it to something other than None, it will reset the alpha values on the
previous plot:
figure(2)
c = scatter(theta, r, c=colors, s=area,cmap=myColormap,alpha=None)
will do the right thing, but calling scatter without alpha=None
figure(3)
d = scatter(theta, r, c=colors, s=area,cmap=myColormap)
or
d = scatter(theta, r, c=colors, s=area,cmap=myColormap, alpha=.5)
will reset all of the alpha values in myColormap to 1 or .5.
You can do c.cmap._init() to reset its original alpha values, and if you
force a redraw on figure(2) (by panning or zooming on it, for example),
it will look right again. However, if you go and fiddle with figure(3)
(pan/zoom), and come back to figure(2), panning or zooming will
cause all of the alpha values will be reset again.
I'm not sure if it would be worth it to make a copy of the colormap to
prevent this from happening. Anyone have thoughts on this?
(the full example of this is commented with FIXME: in polar_scatter.py)
best,
Paul Ivanov
John Hunter, on 2008-11-23 07:36, wrote:
> On Sun, Nov 23, 2008 at 2:01 AM, Paul Ivanov <[EMAIL PROTECTED]> wrote:
>> I took a stab at it, how does this look?
>>
>> I also took the liberty of adding alpha to LinearSegmentedColormap and
>> updated its docstring changing two somewhat ambiguous uses of the word
>> 'entry' with 'key' and 'value'.
>
> Hey Paul,
>
> Thanks for taking this on. I haven't tested this but I read the patch
> and have some inline comments below. Some additional comments:
>
> * the patch should include a section in the CHANGELOG and
> API_CHANGES letting people know what is different.
>
> * you should run examples/tests/backend_driver.py and make sure all
> the examples still run, checking the output of some of the mappable
> types (images, scaltter, pcolor...)
>
> * it would be nice to have an example in the examples dir which
> exercises the new capabilities.
>
> See also, in case you haven't,
> http://matplotlib.sourceforge.net/devel/coding_guide.html, which
> covers some of this in more detail.
>
> Thanks again! Comments below:
>
> Index: lib/matplotlib/colors.py
> ===================================================================
> --- lib/matplotlib/colors.py (revision 6431)
> +++ lib/matplotlib/colors.py (working copy)
> @@ -452,7 +452,7 @@
> self._isinit = False
>
>
> - def __call__(self, X, alpha=1.0, bytes=False):
> + def __call__(self, X, alpha=None, bytes=False):
> """
> *X* is either a scalar or an array (of any dimension).
> If scalar, a tuple of rgba values is returned, otherwise
> @@ -466,9 +466,10 @@
> """
> You need to document what alpha can be here: what does None mean, can
> it be an array, scalar, etc...
>
> if not self._isinit: self._init()
> - alpha = min(alpha, 1.0) # alpha must be between 0 and 1
> - alpha = max(alpha, 0.0)
> - self._lut[:-3, -1] = alpha
> + if alpha:
>
> I prefer to explicitly use "if alpha is None", since there are other
> things that would test False (0, [], '') that you probably don't mean.
>
> + alpha = min(alpha, 1.0) # alpha must be between 0 and 1
> + alpha = max(alpha, 0.0)
>
> You should be able to use np.clip(alpha, 0, 1) here, but we should
> consider instead raising for illegal alpha values since this will be
> more helpful to the user. I realize some of this is inherited code
> from before your changes, but we can improve it while making this
> patch.
>
> + self._lut[:-3, -1] = alpha
> mask_bad = None
> if not cbook.iterable(X):
> vtype = 'scalar'
> @@ -558,9 +559,10 @@
> def __init__(self, name, segmentdata, N=256):
> """Create color map from linear mapping segments
>
> - segmentdata argument is a dictionary with a red, green and blue
> - entries. Each entry should be a list of *x*, *y0*, *y1* tuples,
> - forming rows in a table.
> + segmentdata argument is a dictionary with red, green and blue
> + keys. An optional alpha key is also supported. Each value
> + should be a list of *x*, *y0*, *y1* tuples, forming rows in a
> + table.
>
> Example: suppose you want red to increase from 0 to 1 over
> the bottom half, green to do the same over the middle half,
> @@ -606,6 +608,8 @@
> self._lut[:-3, 0] = makeMappingArray(self.N,
> self._segmentdata['red'])
> self._lut[:-3, 1] = makeMappingArray(self.N,
> self._segmentdata['green'])
> self._lut[:-3, 2] = makeMappingArray(self.N,
> self._segmentdata['blue'])
> + if self._segmentdata.has_key('alpha'):
> + self._lut[:-3, 3] = makeMappingArray(self.N,
> self._segmentdata['blue'])
>
> Is this what you meant? I think you would use 'alpha' rather than
> 'blue' here, no?
>
> self._isinit = True
> self._set_extremes()
>
> @@ -664,11 +668,10 @@
>
>
> def _init(self):
> - rgb = np.array([colorConverter.to_rgb(c)
> + rgba = np.array([colorConverter.to_rgba(c)
> for c in self.colors], np.float)
> self._lut = np.zeros((self.N + 3, 4), np.float)
> - self._lut[:-3, :-1] = rgb
> - self._lut[:-3, -1] = 1
> + self._lut[:-3] = rgba
> self._isinit = True
> self._set_extremes()
Index: CHANGELOG
===================================================================
--- CHANGELOG (revision 6445)
+++ CHANGELOG (working copy)
@@ -1,3 +1,8 @@
+2008-11-24 Added alpha capability for ListedColormap and
+ LinearSegmentedColormap. Changed default Colormap.__call__
+ alpha value to None. Collections.set_alpha accepts None
+ See
+ examples/pylab/plot_scatter.py - PI
2008-11-24 Fix crash in log ticking. - MGD
2008-11-20 Added static helper method BrokenHBarCollection.span_where
Index: doc/api/api_changes.rst
===================================================================
--- doc/api/api_changes.rst (revision 6445)
+++ doc/api/api_changes.rst (working copy)
@@ -8,6 +8,10 @@
Changes for 0.98.x
==================
+* Changed :meth:`matplotlib.colors.Colormap.__call__` default ``alpha=None``
+ :meth:`matplotlib.colors.LinearSegmentedColormap.__init__` ``segmentdata``
+ supports optional ``"alpha"`` key
+ :meth:`matplotlib.collections.Collection.set_alpha` now also accepts ``None``
* Font lookup now uses a nearest-neighbor approach rather than an
exact match. Some fonts may be different in plots, but should be
Index: lib/matplotlib/colors.py
===================================================================
--- lib/matplotlib/colors.py (revision 6445)
+++ lib/matplotlib/colors.py (working copy)
@@ -452,7 +452,7 @@
self._isinit = False
- def __call__(self, X, alpha=1.0, bytes=False):
+ def __call__(self, X, alpha=None, bytes=False):
"""
*X* is either a scalar or an array (of any dimension).
If scalar, a tuple of rgba values is returned, otherwise
@@ -460,15 +460,16 @@
are integers, then they are used as indices into the array.
If they are floating point, then they must be in the
interval (0.0, 1.0).
- Alpha must be a scalar.
+ Alpha must be a scalar between 0 and 1 or None.
If bytes is False, the rgba values will be floats on a
0-1 scale; if True, they will be uint8, 0-255.
"""
if not self._isinit: self._init()
- alpha = min(alpha, 1.0) # alpha must be between 0 and 1
- alpha = max(alpha, 0.0)
- self._lut[:-3, -1] = alpha
+ if alpha is not None:
+ if alpha < 0.0 or alpha > 1.0:
+ raise ValueError("alpha must be in range 0-1")
+ self._lut[:-3, -1] = alpha
mask_bad = None
if not cbook.iterable(X):
vtype = 'scalar'
@@ -558,9 +559,10 @@
def __init__(self, name, segmentdata, N=256):
"""Create color map from linear mapping segments
- segmentdata argument is a dictionary with a red, green and blue
- entries. Each entry should be a list of *x*, *y0*, *y1* tuples,
- forming rows in a table.
+ segmentdata argument is a dictionary with red, green and blue
+ keys. An optional alpha key is also supported. Each value
+ should be a list of *x*, *y0*, *y1* tuples, forming rows in a
+ table.
Example: suppose you want red to increase from 0 to 1 over
the bottom half, green to do the same over the middle half,
@@ -606,6 +608,9 @@
self._lut[:-3, 0] = makeMappingArray(self.N, self._segmentdata['red'])
self._lut[:-3, 1] = makeMappingArray(self.N, self._segmentdata['green'])
self._lut[:-3, 2] = makeMappingArray(self.N, self._segmentdata['blue'])
+ if self._segmentdata.has_key('alpha'):
+ self._lut[:-3, 3] = makeMappingArray(self.N,
+ self._segmentdata['alpha'])
self._isinit = True
self._set_extremes()
@@ -664,11 +669,10 @@
def _init(self):
- rgb = np.array([colorConverter.to_rgb(c)
+ rgba = np.array([colorConverter.to_rgba(c)
for c in self.colors], np.float)
self._lut = np.zeros((self.N + 3, 4), np.float)
- self._lut[:-3, :-1] = rgb
- self._lut[:-3, -1] = 1
+ self._lut[:-3] = rgba
self._isinit = True
self._set_extremes()
Index: lib/matplotlib/collections.py
===================================================================
--- lib/matplotlib/collections.py (revision 6445)
+++ lib/matplotlib/collections.py (working copy)
@@ -414,12 +414,12 @@
def set_alpha(self, alpha):
"""
Set the alpha tranparencies of the collection. *alpha* must be
- a float.
+ a float or None.
- ACCEPTS: float
+ ACCEPTS: float or None
"""
- try: float(alpha)
- except TypeError: raise TypeError('alpha must be a float')
+ try: alpha==None or float(alpha)
+ except TypeError: raise TypeError('alpha must be a float or None')
else:
artist.Artist.set_alpha(self, alpha)
try:
Index: examples/pylab_examples/polar_scatter.py
===================================================================
--- examples/pylab_examples/polar_scatter.py (revision 6445)
+++ examples/pylab_examples/polar_scatter.py (working copy)
@@ -1,18 +1,46 @@
#!/usr/bin/env python
# a polar scatter plot; size increases radially in this example and
# color increases with angle (just to verify the symbols are being
-# scattered correctlu). In a real example, this would be wasting
-# dimensionlaity of the plot
-from pylab import *
+# scattered correctly). In a real example, this would be wasting
+# dimensionality of the plot
+import numpy as np
+from matplotlib.colors import ListedColormap
+from matplotlib.pyplot import figure, show, scatter, subplot, title
+figure(1)
N = 150
-r = 2*rand(N)
-theta = 2*pi*rand(N)
-area = 200*r**2*rand(N)
+r = 2*np.random.rand(N)
+theta = 2*np.pi*np.random.rand(N)
+area = 200*r**2*np.random.rand(N)
colors = theta
ax = subplot(111, polar=True)
c = scatter(theta, r, c=colors, s=area)
c.set_alpha(0.75)
+figure(2)
+# this is an all black colormap, with varying transparency
+# the plot should have points with colors from white: completely
+# transparent; to gray: semi-transparent, to black: completely opaque.
+my_rgba_array= np.array( [
+ [ 0., 0., 0., 0.0],
+ [ 0., 0., 0., 0.25],
+ [ 0., 0., 0., 0.5],
+ [ 0., 0., 0., 0.75],
+ [ 0., 0., 0., 1.0]])
+myColormap = ListedColormap(my_rgba_array)
+ax = subplot(111, polar=True)
+title("""black colormap, with varying transparency,
+ there should be levels of gray, not just black and white""",
+ color='red', verticalalignment='top',)
+# N.B. alpha=None is required to use the colormap alpha values,
+# not passing alpha=None will reset the colormap alpha values to 1.0
+c = scatter(theta, r, c=colors,s=area,cmap=myColormap, alpha=None)
+
+# FIXME: uncommenting this will break the transparency on the plot above.
+#figure(3)
+#ax = subplot(111, polar=True)
+#d = scatter(theta, r, c=colors, s=area,cmap=myColormap)
+##c.cmap._init() #fixes figure(2) only until redraw in figure(3)
+
#savefig('polar_test2')
show()
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users