Colormap that prints nicely in black and white

Hi all,

Don't know if anybody else has found a colormap that is aesthetically pleasing and prints well in black and white. I found one after a lot of Googling. Perhaps useful for plotting figures in journals that charge a lot for colour figures. I got the colormap from: http://ieeexplore.ieee.org/iel5/74/22101/01028735.pdf%3Farnumber%3D1028735

I decided to code it up (see attached text file for the cdict). If anybody finds it useful, maybe it could go into the default colormaps that ship with matplotlib.

cmap.txt (1.11 KB)

Actually, I have been looking at a somewhat related problem. It might be a useful feature in matplotlib.color to provide a function that can take a colormap and produce a grayscale version of it. In my limited amount of research, I have found that one could convert the rgb values into hsv or hsl and use the “value” or “lightness” respectively for the grayscale value. I forget which one was aesthetically better, though.

Ben Root

···

On Fri, Aug 6, 2010 at 3:33 PM, Damon McDougall <D.McDougall@…230…> wrote:

Hi all,

Don’t know if anybody else has found a colormap that is aesthetically pleasing and prints well in black and white. I found one after a lot of Googling. Perhaps useful for plotting figures in journals that charge a lot for colour figures. I got the colormap from: http://ieeexplore.ieee.org/iel5/74/22101/01028735.pdf%3Farnumber%3D1028735

I decided to code it up (see attached text file for the cdict). If anybody finds it useful, maybe it could go into the default colormaps that ship with matplotlib.

Regards,

– Damon


Damon McDougall

Mathematics Institute

University of Warwick

Coventry

CV4 7AL

d.mcdougall@…230…

2010/8/6 Benjamin Root <ben.root@...553...>:

Actually, I have been looking at a somewhat related problem. It might be a
useful feature in matplotlib.color to provide a function that can take a
colormap and produce a grayscale version of it. In my limited amount of
research, I have found that one could convert the rgb values into hsv or hsl
and use the "value" or "lightness" respectively for the grayscale value. I
forget which one was aesthetically better, though.

http://www.pythonware.com/library/pil/handbook/image.htm :

"When from a colour image to black and white, the library uses the
ITU-R 601-2 luma transform:

    L = R * 299/1000 + G * 587/1000 + B * 114/1000
"

That should also be easy to implement.

Friedrich

I am working on a function that can take a Colormap object and return a grayscale form of it. Ideally, I would like to return the same type of Colormap that was provided, but I am wondering if this is necessary. I supposed it is sufficient to just create a LinearSegmentedColormap from the self._lut data?

The problem I see with that approach is that there is still possibly some information loss, particularly with the alpha part of the rgba data. LinearSegmentedColormap has a .from_list() function, but it uses only the rgb part of the rgba array and does not take alpha data.

Is the inability of setting alpha a problem? Or maybe I should use deepcopy() instead?

Thanks,
Ben Root

···

On Mon, Aug 9, 2010 at 3:40 PM, Friedrich Romstedt <friedrichromstedt@…149…> wrote:

2010/8/6 Benjamin Root <ben.root@…55…553…>:

Actually, I have been looking at a somewhat related problem. It might be a

useful feature in matplotlib.color to provide a function that can take a

colormap and produce a grayscale version of it. In my limited amount of

research, I have found that one could convert the rgb values into hsv or hsl

and use the “value” or “lightness” respectively for the grayscale value. I

forget which one was aesthetically better, though.

http://www.pythonware.com/library/pil/handbook/image.htm :

"When from a colour image to black and white, the library uses the

ITU-R 601-2 luma transform:

L = R * 299/1000 + G * 587/1000 + B * 114/1000

"

That should also be easy to implement.

Friedrich

Ah, the list config got me ... (resending to list)

2010/8/10 Benjamin Root <ben.root@...553...>:

I am working on a function that can take a Colormap object and return a
grayscale form of it. Ideally, I would like to return the same type of
Colormap that was provided, but I am wondering if this is necessary. I
supposed it is sufficient to just create a LinearSegmentedColormap from the
self._lut data?

The problem I see with that approach is that there is still possibly some
information loss, particularly with the alpha part of the rgba data.
LinearSegmentedColormap has a .from_list() function, but it uses only the
rgb part of the rgba array and does not take alpha data.

Is the inability of setting alpha a problem? Or maybe I should use
deepcopy() instead?

If you mean me, I really don't know, but I think it is always better
to do things
properly than to publish something done with the attitute "just
working" ....

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?

Friedrich

Ah, the list config got me ... (resending to list)

2010/8/10 Benjamin Root<ben.root@...553...>:

I am working on a function that can take a Colormap object and return a
grayscale form of it. Ideally, I would like to return the same type of
Colormap that was provided, but I am wondering if this is necessary. I
supposed it is sufficient to just create a LinearSegmentedColormap from the
self._lut data?

The problem I see with that approach is that there is still possibly some
information loss, particularly with the alpha part of the rgba data.
LinearSegmentedColormap has a .from_list() function, but it uses only the
rgb part of the rgba array and does not take alpha data.

Is the inability of setting alpha a problem? Or maybe I should use
deepcopy() instead?

If you mean me, I really don't know, but I think it is always better
to do things
properly than to publish something done with the attitute "just
working" ....

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. I suspect only a small fraction of users will need this.

If people really are going to want to fiddle with the conversion function, then the scheme above could easily be extended by allowing the as_gray attribute to be a callable; if it is a callable, then to_grayscale() would use it instead of the default function.

Eric

···

On 08/10/2010 10:27 AM, Friedrich Romstedt wrote:

Friedrich

Interesting ideas, I will try that out tonight.

Ben Root

···

On Tue, Aug 10, 2010 at 4:21 PM, Eric Firing <efiring@…552…229…> wrote:

On 08/10/2010 10:27 AM, Friedrich Romstedt wrote:

Ah, the list config got me … (resending to list)

2010/8/10 Benjamin Root<ben.root@…553…>:

I am working on a function that can take a Colormap object and return a

grayscale form of it. Ideally, I would like to return the same type of

Colormap that was provided, but I am wondering if this is necessary. I

supposed it is sufficient to just create a LinearSegmentedColormap from the

self._lut data?

The problem I see with that approach is that there is still possibly some

information loss, particularly with the alpha part of the rgba data.

LinearSegmentedColormap has a .from_list() function, but it uses only the

rgb part of the rgba array and does not take alpha data.

Is the inability of setting alpha a problem? Or maybe I should use

deepcopy() instead?

If you mean me, I really don’t know, but I think it is always better

to do things

properly than to publish something done with the attitute "just

working" …

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. I

suspect only a small fraction of users will need this.

If people really are going to want to fiddle with the conversion

function, then the scheme above could easily be extended by allowing the

as_gray attribute to be a callable; if it is a callable, then

to_grayscale() would use it instead of the default function.

Eric

Friedrich

2010/8/10 Eric Firing <efiring@...229...>:

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

Agreed, one has to this for all the classes, while your solution works
generically in ColormapBase or whatever it's called.

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.

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.

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 :wink:

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

···

On 08/10/2010 10:27 AM, Friedrich Romstedt wrote:

2010/8/10 Eric Firing<efiring@...229...>:

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 :wink:

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

···

On 08/10/2010 11:58 AM, Friedrich Romstedt wrote:

On 08/10/2010 10:27 AM, Friedrich Romstedt wrote:

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

···

On Tue, Aug 10, 2010 at 7:20 PM, Eric Firing <efiring@…229…> wrote:

On 08/10/2010 11:58 AM, Friedrich Romstedt wrote:

2010/8/10 Eric Firing<efiring@…229…>:

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 :wink:

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

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()

greymode.patch (3.71 KB)

···

On Tue, Aug 10, 2010 at 7:39 PM, Benjamin Root <ben.root@…553…> wrote:

On Tue, Aug 10, 2010 at 7:20 PM, Eric Firing <efiring@…229…> wrote:

On 08/10/2010 11:58 AM, Friedrich Romstedt wrote:

2010/8/10 Eric Firing<efiring@…229…>:

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 :wink:

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

2010/8/11 Eric Firing <efiring@...229...>:

Why make a whole new class instead of switching a behavior in an existing
class?

To my understanding, making object having "behaviours" is usually not
a good idea - I like different classes much more. I believe this is
just a matter of taste, both solutions will work.

But when you think about Ben's last problem with global effects, this
would not happen when using a different colormap instance.

Btw, I think it's undesired to mix colour and b/w in a figure. What
is the use-case? Making one figure in one paper at a time. As soon
as color is in, everything can be color. Maybe we should decide here
clearly by the best design proposal, and leave the use-case question
alone.

My thinking about moving it to the renderers is driven by the question
where the functionality belongs to. When we want to product b/w
plots, this has initially nothing to do with colormaps. It also
applies to lines, scatterplots, images, whatever one can imagine. So
I thought it may be a good idea to apply b/w to the rendered objects
in the end, i.e. LineCollections, QuadMeshs, and so on.

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.

Well, personally I have abandoned this possibility, but just for completeness:

class GrayWrapper:
  def __init__(self, wrapped_colormap):
    self._wrapped_colormap = wrapped_colormap

  def __call__(self, value):
    wrapped_colour = self._wrapped_colormap(value)
    ...
    return turned_into_gray

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".

See above. Here is an example for QuadMesh, it breaks down via
QuadMesh.set_facecolors(),
matplotlib.colors.colorConvert.to_rgba_array(),
ColorConverter.to_rgba(), ColorConverter.to_rgb() (note the missing
'a'), and there it's in principle:

color = tuple(arg[:3])

or some other conversion to a 3-tuple

return color

and just before we could do the rgb->pseudogray conversion

. So in my opinion this is the perfect place to do the color
conversion. I suppose all the other color conversions also break down
to ColorConverter.

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.

No it's not it's just complementary. What we want do here is the b/w
photography.

I'll just hack my matplotlib now to do the LUMA XXX conversion now
always, and will see what it does ...

Friedrich

2010/8/11 Eric Firing <efiring@…706…29…>:

Why make a whole new class instead of switching a behavior in an existing

class?

To my understanding, making object having “behaviours” is usually not

a good idea - I like different classes much more. I believe this is

just a matter of taste, both solutions will work.

But when you think about Ben’s last problem with global effects, this

would not happen when using a different colormap instance.

Btw, I think it’s undesired to mix colour and b/w in a figure. What

is the use-case? Making one figure in one paper at a time. As soon

as color is in, everything can be color. Maybe we should decide here

clearly by the best design proposal, and leave the use-case question

alone.

My thinking here is that I really don’t want to place unnecessary restrictions upon how a user uses a feature. Things should be a modular as possible (which is why I was looking more for a convenience function than anything else).

Why should we have to declare that a user will never need a B&W and color figure? Maybe a user wants to produce both B&W and color versions simultaneously? In my case in particular, it takes about 15 minutes to generate one of my publication-quality images, but only a couple of minutes to save it. It would be beneficial to me to save both b&w and color versions. Another possible use-case would be someone who wants to take a figure that might usually be colored but make a version of it in B&W with color annotations for highlighting purposes.

The point is that I would like to give the users fine-grained control over what they need, especially when the barrier to provide such control is virtually non-existent.

My thinking about moving it to the renderers is driven by the question

where the functionality belongs to. When we want to product b/w

plots, this has initially nothing to do with colormaps. It also

applies to lines, scatterplots, images, whatever one can imagine. So

I thought it may be a good idea to apply b/w to the rendered objects

in the end, i.e. LineCollections, QuadMeshs, and so on.

That would be a nice feature, too. And it would also apply globally across all elements within the figure. I would not object to also having this feature in addition to the ability to control my colormaps.

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.

Well, personally I have abandoned this possibility, but just for completeness:

class GrayWrapper:

    def __init__(self, wrapped_colormap):

            self._wrapped_colormap = wrapped_colormap



    def __call__(self, value):

            wrapped_colour = self._wrapped_colormap(value)

            ...

            return turned_into_gray

Interesting, but I still wonder if it is just better to have a function that returns a grey version of the colormap. Although, one could extend this idea (albeit probably not necessary) to include a variety of different colormap transformations (brighten, darken, invert, etc.).

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”.

See above. Here is an example for QuadMesh, it breaks down via

QuadMesh.set_facecolors(),

matplotlib.colors.colorConvert.to_rgba_array(),

ColorConverter.to_rgba(), ColorConverter.to_rgb() (note the missing

‘a’), and there it’s in principle:

color = tuple(arg[:3])

or some other conversion to a 3-tuple

return color

and just before we could do the rgb->pseudogray conversion
. So in my opinion this is the perfect place to do the color

conversion. I suppose all the other color conversions also break down

to ColorConverter.

But, the alpha information is important. The renderers need it. I am not seeing the rational for completely stripping it out. I can see a rational for being able to modify the alpha, but not for stripping it out.

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.

No it’s not it’s just complementary. What we want do here is the b/w

photography.

Do we want to allow for users to specify their own LUMA conversion coefficients?

I’ll just hack my matplotlib now to do the LUMA XXX conversion now

always, and will see what it does …

Friedrich

Regards,
Ben Root

···

On Wed, Aug 11, 2010 at 11:47 AM, Friedrich Romstedt <friedrichromstedt@…149…> wrote:

http://www.youtube.com/watch?v=aa5eWT-J3v0

Sorry, forgot source code (you cannot run it, though).

Friedrich

test.py (1.4 KB)

I'm currently working on a patch to enable the matplotlib feature
shown in the video. Notice that it's pure matplotlib, no change of
any plot parameters. Unfortunately, or better to say fortunately? I
lost my changes by installing from svn, so I have to redo it, but this
times it's less hacky I believe. I'm reworking colors.ColorConverter
completely but backwards compatible.

The second change applies to cm.ScalarMappable.to_rgba(), to use the
colors.colorConverter for applying the rc gray setting.

Then printing in grayscale will be possible for all features of
matplolib going one of this routes to get their colors, which should
be most. Do you know any more?

To pursue on the ColorConverter class, it seems to me that this has
evolved organically, merging class attributes with module attributes.
Shouldn't this be fixed, by putting the class's methods into module
space?

Ben, I fully agree with you that figures should be able to be saved
both coloured and grayscale. It was a misunderstanding. What I meant
was, that it will not be necessary to display one part of the figure
in colour and the other in grayscale at the same time.

Friedrich

2010/8/11 Friedrich Romstedt <friedrichromstedt@...149...>:

···

http://www.youtube.com/watch?v=aa5eWT-J3v0

“…it will not be necessary…”

I think we are still getting confused here. I was listing off several different kinds of use-cases where one would like to have a mix of grey colormaps and colored colormaps. The reason I mention being able to save a greyscale and a color version of the same figure is in the context of my approach to solving this problem (the swapping out of colormaps). Honestly, I think that your approach is better for dealing with that particular use case.

However, I mention other cases where one is merely wanting a modified version of a particular colormap to use, be it greyscale, or inverse, or brighter/darker, etc. What I envision your solution to be solving would be something like this:

fig = plt.figure()
ax = fig.add_subplot(1, 2, 1)
ax.plot(np.linspace(1, 10, 10), np.linspace(2, 8, 10))
ax.plot(np.linspace(1, 10, 10), np.linspace(4, 9, 10))

ax = fig.add_subplot(1, 2, 2)
ax.set_grey(True)

ax.plot(np.linspace(1, 10, 10), np.linspace(1, 8, 10))

ax.plot(np.linspace(1, 10, 10), np.linspace(3, 7, 10))
ax.plot(np.linspace(1, 10, 10), np.linspace(2, 9, 10))

plt.show()

And see one in color and one as grey and the other as color. This would be a nice feature, but I would settle for it to be at the level of the entire figure.

I think my approach is trying to solve a related, but different problem. My approach is trying to make colormaps more usable and flexible for the users. I would like to ensure that matplotlib does not artificially limit the ability of a user to fully utilize the variety of colormaps available to him.

Ben Root

···

On Mon, Aug 16, 2010 at 4:48 PM, Friedrich Romstedt <friedrichromstedt@…149…> wrote:

Ben, I fully agree with you that figures should be able to be saved

both coloured and grayscale. It was a misunderstanding. What I meant

was, that it will not be necessary to display one part of the figure

in colour and the other in grayscale at the same time.

Friedrich

2010/8/17 Benjamin Root <ben.root@…553…>:

“…it will not be necessary…”

I think we are still getting confused here. I was listing off several

different kinds of use-cases where one would like to have a mix of grey

colormaps and colored colormaps. The reason I mention being able to save a

greyscale and a color version of the same figure is in the context of my

approach to solving this problem (the swapping out of colormaps). Honestly,

I think that your approach is better for dealing with that particular use

case.

Okay, may be you’re right and we should include the usecase you’re

having in mind.

However, I mention other cases where one is merely wanting a modified

version of a particular colormap to use, be it greyscale, or inverse, or

brighter/darker, etc.

Yes, that’s neat.

What I envision your solution to be solving would be

something like this:

fig = plt.figure()

ax = fig.add_subplot(1, 2, 1)

ax.plot(np.linspace(1, 10, 10), np.linspace(2, 8, 10))

ax.plot(np.linspace(1, 10, 10), np.linspace(4, 9, 10))

ax = fig.add_subplot(1, 2, 2)

ax.set_grey(True)

ax.plot(np.linspace(1, 10, 10), np.linspace(1, 8, 10))

ax.plot(np.linspace(1, 10, 10), np.linspace(3, 7, 10))

ax.plot(np.linspace(1, 10, 10), np.linspace(2, 9, 10))

Hmm, that’s much more complicated … For Collections, one could set a

local flag, but it would be nevertheless quite buried in the API …

When setting it in the axes, one has to care about all artists added

later too, and all pathes an artist may sneak into the axes.

I had a thought… and it is based on my admittedly incomplete understanding of matplotlib. Everything that gets drawn is derived from the artist class, right? So, what if there was a ‘grey’ boolean in that base class, and the .draw() function passes that bool down through all the subsequent .draw() calls of its child objects (it could be None by default to accept the parent’s property, or allowed to be explicitly set by the user to override the parent’s value.)

By the time we get to the backends, all the color data should be in a clean, broadcasted rgba form, so it should then be a relatively simple check of the grey flag before writing out the color information.

Admittedly, I would much rather have this flag check done before getting to the backends and through a single point of code. At first, I thought that ColorConverter would be it, but as I now understand it, it is treated more like a utility module rather than an important step in the rendering process. It gets used for things at different points in the matplotlib process.

Maybe I am just going overboard here…

What I’m going to solve is simply a toplevel boolean ‘gray’ switch in

the rcParams. It’s working in an abstract way.

Maybe a complementary approach would be useful. A global switch for

everything, and more fine-tuning control coming from your side?

I think the issue with my approach is that it would only impact things that uses colormaps. Anything that explicitly sets its colors without a colormap will be totally unaffected.

For the “road map”, I cannot put myself under strong pressure with

this, I would say, although being a rather tiny thing, I will finish

it until end of next week.

Can’t wait to see what you have.

Ahh, and shall we name the switch ‘gray’ or ‘grey’

Heh, even matplotlib can’t provide too much precedence here because it tries to cater to both spellings (and I keep flipping back and forth due to a stupid bug in the Ubuntu packaging that packaged a en_UK spell-checker instead of en_US, but my Fedora setup has it right…). I should note that for Colormaps, there is only a “is_gray” function.

Cheers,
Ben Root

···

On Tue, Aug 17, 2010 at 4:19 PM, Friedrich Romstedt <friedrichromstedt@…149…> wrote:

2010/8/18 Benjamin Root <ben.root@...553...>:

I had a thought... and it is based on my admittedly incomplete understanding
of matplotlib. Everything that gets drawn is derived from the artist class,
right? So, what if there was a 'grey' boolean in that base class, and the
.draw() function passes that bool down through all the subsequent .draw()
calls of its child objects (it could be None by default to accept the
parent's property, or allowed to be explicitly set by the user to override
the parent's value.)

It's a neat idea again. I like it very much. I propose the following:

1) As you said, a gray flag in mpl.artist.Artist, which can be
automatically transmitted to the child artists *on render time*.

2) Counting the "grayishness" (single, double, ... :slight_smile: in
mpl.backends.renderer_bases.RendererBase.

3) Evaluating the grayishness in
mpl.backends.renderer_bases.RendererBase.new_gc() [i.e., new graphics
context]. Passing it on to the GraphicsContext as initialisaion
argument. mpl.backends.renderer_bases.GraphicsContextBase has ONLY
ONE COLOUR ARGUMENT, namely .set_foreground(). It seems everythings
breaks down to foreground rendering of pathes and symbols. Indeed, it
uses once again mpl.colors.colorConverter, and I think my refactoring
of this one is not useless at all, but the main point is, it stores an
rgb colour in the end, and in fact *all* rgb colours ever used in any
graphics drawing context. Also for text, etc. pp.

4) Introducing a decorator:

def draw_with_grayishness(fn):
  def decorated(self, renderer):
    if self.is_gray():
      renderer.increase_grayishness()
      fn(self, renderer)
      renderer.decrease_grayishness()
    else:
      fn(self, renderer)
  
  return decorated

This turns on grayishness in the renderer if it is requested by
*self*, which is an Artist.

By the time we get to the backends, all the color data should be in a clean,
broadcasted rgba form, so it should then be a relatively simple check of the
grey flag before writing out the color information.

Mmmh, for some reason colorConverter is used there again, maybe historical.

Admittedly, I would much rather have this flag check done before getting to
the backends and through a single point of code. At first, I thought that
ColorConverter would be it, but as I now understand it, it is treated more
like a utility module rather than an important step in the rendering
process. It gets used for things at different points in the matplotlib
process.

Yes, it's not the only point, there is at least one more,
mpl.collection.Collection.update_scalaramappable(). And there may be
tons of other selfish procedures ... So I agree fully with you.

Maybe I am just going overboard here...

Well, I come with you :slight_smile:

So, the code point would be outside of the Renderer, but in the
GraphicsContext, which is abstract enough to be shared by all
implementations of the rendering. It is passed on to the
implementation's methods as an argument, so its .foreground or
whatever is the same to all rendering implementations.

Friedrich

2010/8/18 Benjamin Root <ben.root@…553…>:

I had a thought… and it is based on my admittedly incomplete understanding

of matplotlib. Everything that gets drawn is derived from the artist class,

right? So, what if there was a ‘grey’ boolean in that base class, and the

.draw() function passes that bool down through all the subsequent .draw()

calls of its child objects (it could be None by default to accept the

parent’s property, or allowed to be explicitly set by the user to override

the parent’s value.)

It’s a neat idea again. I like it very much. I propose the following:

  1. As you said, a gray flag in mpl.artist.Artist, which can be

automatically transmitted to the child artists on render time.

  1. Counting the “grayishness” (single, double, … :slight_smile: in

mpl.backends.renderer_bases.RendererBase.

  1. Evaluating the grayishness in

mpl.backends.renderer_bases.RendererBase.new_gc() [i.e., new graphics

context]. Passing it on to the GraphicsContext as initialisaion

argument. mpl.backends.renderer_bases.GraphicsContextBase has ONLY

ONE COLOUR ARGUMENT, namely .set_foreground(). It seems everythings

breaks down to foreground rendering of pathes and symbols. Indeed, it

uses once again mpl.colors.colorConverter, and I think my refactoring

of this one is not useless at all, but the main point is, it stores an

rgb colour in the end, and in fact all rgb colours ever used in any

graphics drawing context. Also for text, etc. pp.

  1. Introducing a decorator:

def draw_with_grayishness(fn):

    def decorated(self, renderer):

            if self.is_gray():

                    renderer.increase_grayishness()

                    fn(self, renderer)

                    renderer.decrease_grayishness()

            else:

                    fn(self, renderer)



    return decorated

This turns on grayishness in the renderer if it is requested by

self, which is an Artist.

Neat! I have been sticking mainly to the front-end parts of matplotlib with only a vague understanding of the backend/core pieces. I am learning more all the time.

By the time we get to the backends, all the color data should be in a clean,

broadcasted rgba form, so it should then be a relatively simple check of the

grey flag before writing out the color information.

Mmmh, for some reason colorConverter is used there again, maybe historical.

Might be a good idea to try and make a flowchart of some sort and codify where and when certain things should be done and strive for that organization.

Admittedly, I would much rather have this flag check done before getting to

the backends and through a single point of code. At first, I thought that

ColorConverter would be it, but as I now understand it, it is treated more

like a utility module rather than an important step in the rendering

process. It gets used for things at different points in the matplotlib

process.

Yes, it’s not the only point, there is at least one more,

mpl.collection.Collection.update_scalaramappable(). And there may be

tons of other selfish procedures … So I agree fully with you.

Maybe I am just going overboard here…

Well, I come with you :slight_smile:

I hope it isn’t the blind leading the blind here. I tend to get lots of crazy design ideas, especially when dealing with overall architecture, even without fully understanding exactly how things work.

So, the code point would be outside of the Renderer, but in the

GraphicsContext, which is abstract enough to be shared by all

implementations of the rendering. It is passed on to the

implementation’s methods as an argument, so its .foreground or

whatever is the same to all rendering implementations.

Friedrich

Do you have a github account? Maybe we can fork Andrew Straw’s repo and bang on this for a on a separate branch. I have about a week and a half left before I have to divert my full attention to a month-long project.

Maybe we should also start up another thread summarizing some of the ideas that has been passed around in this thread and make a prioritized ToDo list with milestones?

Ben Root

···

On Wed, Aug 18, 2010 at 2:08 PM, Friedrich Romstedt <friedrichromstedt@…149…> wrote: