On Tue, Aug 10, 2010 at 7:39 PM, Benjamin Root <[email protected]> wrote:
> On Tue, Aug 10, 2010 at 7:20 PM, Eric Firing <[email protected]> wrote:
>
>> On 08/10/2010 11:58 AM, Friedrich Romstedt wrote:
>> > 2010/8/10 Eric Firing<[email protected]>:
>> >> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel