3
$\begingroup$

I have designed some custom colormaps. I also want to use the inbuilt colormaps as well. The user will be given a choice to select whether to use a built-in colormap or a custom one. Based on the selection the corresponding drop-down menu will be displayed and the user should be able to select the desired colormap.

Below is what I am up to now.

makeColorFn[colors_, opacities_, vars_] := 
 Transpose[{vars, MapThread[Append, {colors, opacities}]}] /. 
  body_ :> (Blend[body, #] &)

getcolors[n_, colorspace_] := (
  a = 0.8 +1.2 n;
  points = 
   N[Transpose[
     Table[{Sqrt[1 - t^2] Cos[a \[Pi] t], 
       Sqrt[1 - t^2] Sin[a \[Pi] t], t}, {t, -1, 1, 2/(n - 1)}]]];
  pointsscaled = Rescale[points];
  Switch[colorspace,
   "LAB", 
   LABColor @@@ 
    Transpose[{Rescale[points[[3]]], points[[1]], points[[2]]}],
   "LUV", 
   LUVColor @@@ 
    Transpose[{Rescale[points[[3]]], points[[1]], points[[2]]}],
   "LCH", 
   LCHColor @@@ 
    Transpose[{pointsscaled[[3]], pointsscaled[[1]], 
      pointsscaled[[2]]}]
   ]
  )

Manipulate[
 colors = getcolors[n, colorspace];
 opacities = ConstantArray[1., n];
 keyintensities = Table[i, {i, 0, 1, 1/(n - 1)}];
 Switch[colormap, 0, ColorData[builtincolormap, "Image"], 1, 
  ImageCrop[
   ArrayPlot[{Range[0, 1, 1/255]}, Frame -> False, 
    AspectRatio -> Full, ImageSize -> {261, 32}, 
    ColorFunction -> 
     makeColorFn[colors, opacities, keyintensities]]]], {{colormap, 0,
    "Color Map"}, {0 -> "Built-in", 1 -> "Custom"}, 
  ControlType -> RadioButtonBar},
 {{builtincolormap, "CMYKColors", 
   "Built-in Color Map"}, {"CMYKColors",
   "BlueGreenYellow", "DarkRainbow",  "VisibleSpectrum"}},
 {{n, 3, "Number of Colors"}, 2, 20, 1, 
  ControlType -> PopupMenu}, {{colorspace, "LAB", 
   "Color Space"}, {"LAB", "LUV", "LCH"}},
 ControlPlacement -> Left]

The code is working fine. However, my problem is that I cannot dynamically control the visibility of the controls for built-in and the custom color functions. How can I control the output such that only the corresponding controls will be visible dynamically?

[Bonus: It will be a bonus to display the custom colormaps in the same way as the built-in colormaps are displayed.]

$\endgroup$
3
$\begingroup$

I'd suggest moving away from Manipulate if you're serious about creating a GUI. It's easy for easy stuff, but gets tricky fast. Here's a simple example using DynamicModule, which is much more flexible. I've added two useful functions and encapsulated the body of getcolors in a Module.

makeColorFn[colors_, opacities_, vars_] := 
 Transpose[{vars, MapThread[Append, {colors, opacities}]}] /. 
  body_ :> (Blend[body, #] &)

getcolors[n_, colorspace_] := Module[{a},
   a = 0.8 + 1.2 n;
   points = 
    N[Transpose[
      Table[{Sqrt[1 - t^2] Cos[a \[Pi] t], 
        Sqrt[1 - t^2] Sin[a \[Pi] t], t}, {t, -1, 1, 2/(n - 1)}]]];
   pointsscaled = Rescale[points];
   Switch[
    colorspace,
    "LAB",
    LABColor @@@ 
     Transpose[{Rescale[points[[3]]], points[[1]], points[[2]]}], 
    "LUV", LUVColor @@@ 
     Transpose[{Rescale[points[[3]]], points[[1]], points[[2]]}], 
    "LCH", LCHColor @@@ 
     Transpose[{pointsscaled[[3]], pointsscaled[[1]], 
       pointsscaled[[2]]}]
    ]
   ];
colorMapImage[colors_, opacities_, keyintensities_] := ImageCrop[
   ArrayPlot[{Range[0, 1, 1/255]},
    Frame -> False,
    AspectRatio -> Full,
    ImageSize -> {350, 65},
    ColorFunction -> makeColorFn[colors, opacities, keyintensities]]
   ];
linSpace[x0_, xf_, n_] := Range[x0, xf, (xf - x0)/(n - 1)];

DynamicModule[
 {a = 0, n = 3, colorspace = "LAB", builtin = "CMYKColors"},
 Column[{
   SetterBar[Dynamic@a, {0 -> "Built-in", 1 -> "Dynamic"}],
   PaneSelector[{
     0 -> Panel@Column[{
         PopupMenu[
          Dynamic@builtin, {"CMYKColors", "BlueGreenYellow", 
           "DarkRainbow", "VisibleSpectrum"}],
         Dynamic@ColorData[builtin, "Image"]
         }],
     1 -> Panel@Column[{
         Row[{PopupMenu[Dynamic@n, Range[5] + 1], 
           SetterBar[Dynamic@colorspace, {"LAB", "LUV", "LCH"}]}],
         Dynamic@
          colorMapImage[getcolors[n, colorspace], 
           ConstantArray[1., n], linSpace[0, 1, n]]}]
     }, Dynamic@a]
   }]
 ]

You can play with the sizes and alignment, but this should get you started. I'm not sure what you mean by, "It will be a bonus to display the custom colormaps in the same way as the built-in colormaps are displayed."

$\endgroup$
  • 1
    $\begingroup$ Thanks for your answer. It's working perfectly fine. BY "the same way", I mean to say that I want to be able to use the custom color maps using the command like "ColorData[custom,"Image"]". Maybe, the custom color maps need to be included in the existing color maps. However, the custom color maps are structured in a different way that the built-in colormaps. Therefore, I am not sure whether they can be used in the same way as I am willing. $\endgroup$ – Majis May 18 '17 at 9:18
  • $\begingroup$ @Majis, you might be interested in this discussion. $\endgroup$ – N.J.Evans May 18 '17 at 12:25
  • 1
    $\begingroup$ Thanks, I got your point on this matter. $\endgroup$ – Majis May 18 '17 at 12:50
2
$\begingroup$

Here is a way to do it with a Manipulate expression.

Manipulate[
  colors = getcolors[n, colorspace];
  opacities = ConstantArray[1., n];
  keyintensities = Table[i, {i, 0, 1, 1/(n - 1)}];
  Switch[colormap,
    0, Panel @ Column@
         {Spacer[{410, 0}],
          Control[
            {{builtincolormap, "CMYKColors", "Built-in Color Map"},
             {"CMYKColors", "BlueGreenYellow", "DarkRainbow", "VisibleSpectrum"}}],
          Dynamic @ ColorData[builtincolormap, "Image"]},
    1, Panel[Column[
         {Spacer[{410, 0}],
          Control[{{n, 3, "Number of Colors"}, 2, 20, 1, ControlType -> PopupMenu}], 
          Control[{{colorspace, "LAB", "Color Space"}, {"LAB", "LUV", "LCH"}}],
          Dynamic @
            ArrayPlot[{Range[0, 1, 1/255]},
              Frame -> False, 
              AspectRatio -> 1/6, 
              ImageSize -> 261,
              ColorFunction -> makeColorFn[colors, opacities, keyintensities]]}]]],
  {{colormap, 0, "Color Map"}, {0 -> "Built-in", 1 -> "Custom"}, RadioButtonBar},
  FrameMargins -> None]

built_in

custom

Update

The code given above is good enough to illustrate a solution to the OP's problem, but not as robust one would want for use in a real application. This version of the GUI localizes all the variables is more suitable for real-application use.

Manipulate[
  colors = getcolors[n, colorspace];
  opacities = ConstantArray[1., n];
  keyintensities = Table[i, {i, 0, 1, 1/(n - 1)}];
  Switch[colormap,
    0, 
    Panel[
      Column[
        {Spacer[{410, 0}],
         Control[
           {{builtincolormap, builtincolormap, "Built-in Color Map"},
           {"CMYKColors", "BlueGreenYellow", "DarkRainbow", "VisibleSpectrum"}}],
         Dynamic @ ColorData[builtincolormap, "Image"]}]],
    1, 
    Panel[
      Column[
        {Spacer[{410, 0}],
         Control[{{n, n, "Number of Colors"}, 2, 20, 1, ControlType -> PopupMenu}],
         Control[{
           {colorspace, colorspace, "Color Space"}, {"LAB", "LUV", "LCH"}}],
         Dynamic @
           ArrayPlot[{Range[0, 1, 1/255]},
             Frame -> False, AspectRatio -> 1/6, ImageSize -> 261,
             ColorFunction -> makeColorFn[colors, opacities, keyintensities]]}]]],
  {{n, 3}, None},
  {colors, None},
  {opacities, None},
  {keyintensities, None},
  {{colorspace, "LAB"}, None},
  {{builtincolormap, "CMYKColors"}, None},
  {{colormap, 0, "Color Map"}, {0 -> "Built-in", 1 -> "Custom"}, RadioButtonBar},
  TrackedSymbols :> {builtincolormap, colormap, n, colorspace},
  FrameMargins -> None]
$\endgroup$
  • $\begingroup$ Thanks for your answer also and your code is working fine as well. Moreover, I actually want the choices to be displayed in the way that you have shown (unlike @N.J.Evans). However, as Evans have suggested avoiding 'Manipulate', can you be able to bypass 'Manipulate' and still get a similar interface? $\endgroup$ – Majis May 18 '17 at 9:28
  • $\begingroup$ @Majis. I see no reason to avoid using Manipulate is this case. What I would recommend is localizing the global variables that you use and which I did not change because I thought you were only interested in GUI issues and not in more general dynamic front-end programming issues. I will update the answer showing how to localize the variables. Note that the updated version has an additional advantage that the settings made on each pane persist when the user switches back and forth between the two. $\endgroup$ – m_goldberg May 20 '17 at 23:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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