On Tue, Aug 10, 2010 at 7:39 PM, Benjamin Root <ben.r...@ou.edu> wrote:

> On Tue, Aug 10, 2010 at 7:20 PM, Eric Firing <efir...@hawaii.edu> wrote:
>
>> On 08/10/2010 11:58 AM, Friedrich Romstedt wrote:
>> > 2010/8/10 Eric Firing<efir...@hawaii.edu>:
>> >> On 08/10/2010 10:27 AM, Friedrich Romstedt wrote:
>> >>> So I think it is probably best to code it into the Colormap object
>> >>> itself, so that each and ever derived class can define its own method
>> >>> of how to create a greyscale version.  What do you think about that?
>> >>
>> >> Good idea.  The base class could define a default to_grayscale() method
>> >> that would do the conversion near the very end of the Colormap.__call__
>> >> method if an as_gray attribute, also defined in the base class, is
>> True.
>> >>   No need for getters and setters--let it be a simple attribute.  This
>> >> is much simpler than generating a whole new colormap--instead, just set
>> >> an attribute to switch an existing colormap to gray or back to color.
>>  I
>> >> would leave the switch out of the __init__ args and kwargs.
>> >
>> >> If someone
>> >> wants grey, they can add one more line of code to set the attribute.
>> >
>> > Hmm, one would have to do it for every colormap used.  Also, it would
>> > be not so obvious if using the default colormap.
>> >
>> >> I
>> >> suspect only a small fraction of users will need this.
>> >
>> > I like this, it's a good idea enabling to not repeat all the stuff in
>> > the code.  But hey, wouldn't it be the same to just overload the
>> > __call__ method?
>> >
>> > class GrayColorbar(RgbColorbar):
>> >      """A colorbar returning grayscaled version."""
>> >
>> >      def __call__(self, value):
>> >          """Transforms RgbColorbar's value into grayscale, and returns
>> it.""""
>> >
>> >          rgb = BaseClass.__call__(self, value)
>> >          [do stuff]
>> >          return grayscale
>>
>> Why make a whole new class instead of switching a behavior in an
>> existing class?
>>
>> >
>> > Agreed, one has to this for all the classes, while your solution works
>> > generically in ColormapBase or whatever it's called.
>>
>> I think my solution (with slight modification) is also very compatible
>> with your suggestion below to have an rc param that switches between
>> color and gray.  If as_gray is None, use the rc value; otherwise, let it
>> act as described above.
>>
>> The typical use case is when one wants color initially, but then must
>> regenerate plots in black and white to reduce publication costs.  Your
>> rc suggestion facilitates such switching.
>>
>> >
>> > Another option would be, to wrap the Colormap into a thin layer with
>> > __call__, but this appears way too clumsy and too hacky to me.  It's a
>> > clumsy way of deriving from the class.  Otherwise it's maybe also
>> > nice, because it's generic, for all Colormaps.  __getattr__ and
>> > __setattr__ (iirc) could be used to simulate the wrapped instance
>> > fully.
>>
>> I don't follow you on this--I don't understand at all.
>>
>>
>> >
>> > Is there some layer dealing with colors in the renderers, where the
>> > conversion could also happen?  I'm asking because of displaying color
>> > images etc. and printing them as grayscale.  With this, we would get
>> > rid of the alpha stuff completely, too.
>>
>> I don't understand why you would want to push this down into the
>> renderers instead of keeping it at a higher level.  And I don't know
>> what you mean by "getting rid of the alpha stuff".
>>
>> >
>> > Maybe a general matplotlib.rc switch 'greyscale' would be possible.
>> > It would leave room for tons of improvement, e.g. automatically
>> > setting the color cycle to - -- -. etc., there was some monthes ago
>> > discussion about how to achieve that.  Another advantage: It's zero
>> > loc if set in the config file ;-)
>>
>> Yes, there does seem to be a need for these sorts of switching
>> operations.  Getting back to the colormap question, our discussions have
>> been based on the assumption that an rgb_to_gray function is all that is
>> needed.  But is this true?  Or will users actually need completely
>> different graymaps rather than something resembling a black-and-white
>> photo of a colormap?  If so, then my suggested strategy is useless.
>>
>> Eric
>>
>> >
>> > I think that would be a real neat new feature.
>> >
>> > I agree what's not needed is mixed greyscale and colour display in the
>> > same Figure.
>> >
>> > Bear with me if my ideas are always too radical.
>> >
>> > Friedrich
>>
>>
> I have to agree with Eric on this.  Maybe I am just not understanding
> Friedrich's thought process.
>
> If someone wants a specific greyscale colormapping, then they can make it
> themselves just like any other colormap.  However, it is as a matter of
> convenience and ease to say "hey, I have this colormap that I have been
> using in my code, but I need its greyscale equivalent".
>
> My idea is this.  It appears that all colormappings get a lookup table
> (self._lut) that contains rgba values.   We could also simultaneously
> maintain a second lookup table (initialized only when needed).  Therefore,
> one could take a colormap, switch on the greyscale attribute when desired
> (which would swap the two tables), and switch back over to the color-scale
> with the same amount of ease.
>
> It would be independent of any Colormap subclass because it would be in the
> base class.  My only concern is when do the various drawing elements
> actually use the colormap info?  If I create a b&w figure in one subplot,
> but also a colored figure in another subplot (for whatever reason) using the
> same colormap, would the figure show as expected at render-time?
>
> Thoughts, concerns, comments?
>
> Ben Root
>


Ok,

I have made some code that let's me easily switch between modes and works
quite nicely.  However, something I suspected would happen occurs.  If I
were to use the colormap and ever change the mode  before rendering, *all*
places where that colormap was used is colored according to the mode last
set before rendering.

This could be considered a bug or a feature, depending on one's viewpoint.
I suspect if one really needed independent colormaps, one could use deepcopy
before applying the alternate colormap to the axes.

I am including a patch to  this email for a looking over (be brutal).  Note,
it is hardly ready for inclusion as I am sure there are some other behaviors
I haven't thought of.

Below is a quick example of how to use the new feature.

Enjoy!
Ben Root


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

X, Y = np.mgrid[-10:10, -10:10]
Z = np.abs(X * Y)

cmap = cm.get_cmap()
cmap.grey_mode = True

plt.pcolor(X, Y, Z, cmap=cmap)
plt.show()
Index: matplotlib/lib/matplotlib/colors.py
===================================================================
--- matplotlib/lib/matplotlib/colors.py	(revision 8624)
+++ matplotlib/lib/matplotlib/colors.py	(working copy)
@@ -480,12 +480,29 @@
         """
         self.name = name
         self.N = N
+        
+        # These items are used for determining a color given on a scaled value
+        self._lut = None
         self._rgba_bad = (0.0, 0.0, 0.0, 0.0) # If bad, don't paint anything.
         self._rgba_under = None
         self._rgba_over = None
+
+        # These two dictionaries will contain the color and greyscale
+        # versions of the lookup table.  The contents will be applied
+        # to the above attributes as necessary.
+        self._lut_color = None
+        self._lut_grey = None
+
+        # Switch to greyscale mode?
+        self.grey_mode = False
+        self._grey_used = False     # to help indicate a need to swap
+
+        # Array index to the locations in the lookup table (lut)
+        # for special values of under, over and bad.
         self._i_under = N
         self._i_over = N+1
         self._i_bad = N+2
+
         self._isinit = False
 
 
@@ -503,6 +520,9 @@
         """
 
         if not self._isinit: self._init()
+        self._init_colorstore()
+        if self.grey_mode != self._grey_used : self._swap_colormode()
+
         mask_bad = None
         if not cbook.iterable(X):
             vtype = 'scalar'
@@ -592,6 +612,58 @@
         '''Generate the lookup table, self._lut'''
         raise NotImplementedError("Abstract class only")
 
+    def _swap_colormode(self) :
+        if not self._grey_used :
+            # Swap to grey.
+
+            # Create the _lut_grey dict if needed.
+            if self._lut_grey is None :
+                self._lut_grey = dict(rgba_under=self._color_to_grey(self._lut_color['rgba_over']),
+                                      rgba_over=self._color_to_grey(self._lut_color['rgba_under']),
+                                      rgba_bad=self._color_to_grey(self._lut_color['rgba_bad']),
+                                      lut=self._color_to_grey(self._lut_color['lut']))
+
+            # Swap in the grey info
+            self._lut = self._lut_grey['lut']
+            self._rgba_under = self._lut_grey['rgba_under']
+            self._rgba_over = self._lut_grey['rgba_over']
+            self._rgba_bad = self._lut_grey['rgba_bad']
+
+
+            # We have completed the swap
+            self._grey_used = True
+
+        else :
+            # Swap to color.
+
+            # Swap in the color info
+            self._lut = self._lut_color['lut']
+            self._rgba_under = self._lut_color['rgba_under']
+            self._rgba_over = self._lut_color['rgba_over']
+            self._rgba_bad = self._lut_color['rgba_bad']
+
+            # We have completed the swap
+            self._grey_used = False
+
+    def _init_colorstore(self) :
+        if self._lut_color is None :
+            self._lut_color = dict(lut=self._lut,
+                                   rgba_under=self._rgba_under,
+                                   rgba_over=self._rgba_over,
+                                   rgba_bad=self._rgba_bad)
+
+
+    def _color_to_grey(self, rgba) :
+        """Use ITU-R 601-2 luma transform"""
+        if rgba is not None :
+            rgba = np.atleast_2d(rgba)
+            l = np.sum(rgba[:, :3] * np.array([0.299, 0.587, 0.114]), axis=1)
+            return np.squeeze(np.dstack([l, l, l, rgba[:, 3]]))
+        else :
+            # If I get None, return it in kind
+            return None
+                           
+
     def is_gray(self):
         if not self._isinit: self._init()
         return (np.alltrue(self._lut[:,0] == self._lut[:,1])
------------------------------------------------------------------------------
This SF.net email is sponsored by 

Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev 
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to