Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Suppose I'm writing a function that takes a color as a parameter; for example:

drawShape[color_] := Graphics[{Style[Disk[], color]}];

But if the caller inputs an invalid color, bad things happen:

Bad

So I want to use a pattern to define drawShape only for values that are actually colors. Conceptually,

drawShape[color_Color] := ...

The problem is that unlike (say) Lists, Integers, Reals, Complexes, or Graphicses, color objects do not share a Color head. That is,

In[1]:= Red // Head
Out[1]= RGBColor
In[2]:= Hue[0.5] // Head
Out[2]= Hue
In[3]:= GrayLevel[0.5] // Head
Out[3]= GrayLevel
In[4]:= CMYKColor[0, 1, 1, 1/2] // Head
Out[4]= CMYKColor
In[4]:= Opacity[0.5, Purple] // Head
Out[4]= Opacity
In[5]:= Transparent // Head
Out[5]= GrayLevel

So that won't work. I also don't see any ColorQ function, with which I could write drawShape[color_ ? ColorQ] := ....

How can I write a pattern that matches any valid color object? Is there a more robust way than just testing for each of these heads?

share|improve this question
add comment

2 Answers 2

up vote 19 down vote accepted
colorQ = Quiet @ Check[Blend @ {#, Red}; True, False] &;

colorQ /@ {Red, Hue[0.5], GrayLevel[0.5], CMYKColor[0, 1, 1, 1/2], Opacity[0.5, Purple]}
{True, True, True, True, True}
colorQ /@ {17, 1.3, Pi, "not a color", {1, 2, 3}, Hue["bad arg"]}
{False, False, False, False, False, False}

You would use: drawShape[color_?colorQ] := . . .


Inspired by kguler's comment this might also be formulated as:

colorQ = Quiet[Head@Darker@# =!= Darker] &;

Or:

colorQ = FreeQ[Quiet@Darker@#, Darker] &;

Edit: Darker works on entire Image and Graphics objects and therefore the two forms immediately above will incorrectly return True in these cases. Blend solution is still valid.

share|improve this answer
3  
Nice. I particularly like that it can distinguish between Opacity[0.5, Purple] and Opacity[0.5]. –  Simon Woods Nov 30 '12 at 11:40
3  
Neat! (Darker@#;True or Lighter@#;True work as well.) –  kguler Nov 30 '12 at 14:10
    
@kguler Good idea! –  Mr.Wizard Nov 30 '12 at 14:15
    
@kguler I added a couple of other versions based on your comment. –  Mr.Wizard Nov 30 '12 at 17:23
    
That's very useful (+1), I should put one of these tests into my answer here as well. –  Jens Nov 30 '12 at 19:14
add comment

I think that the following catches all color heads.

Clear[test];
test[x : (_CMYKColor | _Hue | _RGBColor)] := "good"
test[else_] := "bad"

Let's try it

test[Red]
(* Out: "good" *)

test[red]
(* Out: "bad" *)
share|improve this answer
1  
test[GrayLevel[0.5]] "bad". Obviously you can just test the heads against all you think of, but that's not robust if you forget one or if Wolfram adds another. –  Mechanical snail Nov 30 '12 at 1:38
2  
Note that this will fail for malformed or incomplete color directives, e.g. RGBColor[1]. +1 nevertheless, but see my answer for a more robust method. –  Mr.Wizard Nov 30 '12 at 2:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.