3
$\begingroup$
img= ExampleData[{"TestImage3D", "MRknee"}];    
Manipulate[
colors = {Black, Blue, Purple, Red, Brown, Gray, Green, Orange, Pink,
Cyan, Yellow, White};
w = List @@@ ColorConvert[colors, "RGB"].{0.2989, 0.5870, 0.1140};
opacities = {x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12};
co = Table[AppendTo[colors[[i]], opacities[[i]]], {i, 12}];
colorfn = Evaluate[Blend[{w, co}\[Transpose], #]] &;
Image3D[img, 
ColorFunction -> colorfn], {x1, 0, 1}, {x2, 0, 1}, {x3, 0, 1}, {x4, 
0, 1}, {x5, 0, 1}, {x6, 0, 1}, {x7, 0, 1}, {x8, 0, 1}, {x9, 0, 
1}, {x10, 0, 1}, {x11, 0, 1}, {x12, 0, 1}]

The above code snippet works fine. However, 'AppendTo' adds an element on each iteration. I want to append the opacity values to be appended to the color values only once (during the execution of the Manipulate for the first time) and from the next time onwards (for any change in the parameters x1, x2, ..) it will just replace the last the opacity value.

[

Table[AppendTo[colors[[i]], opacities[[i]]], {i, 12}]

results

{GrayLevel[0, 0], RGBColor[0, 0, 1, 0], RGBColor[0.5, 0, 0.5, 0], 
RGBColor[1, 0, 0, 0], RGBColor[0.6, 0.4, 0.2, 0], GrayLevel[0.5, 0],  
RGBColor[0, 1, 0, 0], RGBColor[1, 0.5, 0, 0], RGBColor[1, 0.5, 0.5, 0], 
RGBColor[0, 1, 1, 0], RGBColor[1, 1, 0, 0], GrayLevel[1, 0]}
(*when it is first called*)

Next iteration ...

{GrayLevel[0, 0, 0], RGBColor[0, 0, 1, 0, 0], RGBColor[0.5, 0, 0.5, 0, 0], 
RGBColor[1, 0, 0, 0, 0], RGBColor[0.6, 0.4, 0.2, 0, 0], GrayLevel[0.5, 0, 0],  
RGBColor[0, 1, 0, 0, 0], RGBColor[1, 0.5, 0, 0, 0], RGBColor[1, 0.5, 0.5, 0, 0], 
RGBColor[0, 1, 1, 0, 0], RGBColor[1, 1, 0, 0, 0], GrayLevel[1, 0, 0]}

and so on. ]

How can I modify the above code to serve the purpose?

$\endgroup$
5
$\begingroup$

The main problem is the use of AppendTo where Append would suffice. You could instead use:

co = MapThread[Append, {colors, opacities}];

Full code:

Okay, cleaner now

img = ExampleData[{"TestImage3D", "MRknee"}];

colors =
 {Black, Blue, Purple, Red, Brown, Gray, Green, Orange, Pink, Cyan, Yellow, White};

vars = Array[α, Length@colors];

w = List @@@ ColorConvert[colors, "RGB"].{0.2989, 0.5870, 0.1140};

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

With[{opa = vars},
  Manipulate[
    Image3D[img, ColorFunction -> makeColorFn[colors, w, opa]],
    Evaluate[Sequence @@ ({#, 0, 1} & /@ vars)]
  ]
]

enter image description here

In the code above With is used to address


An alternative to the way I used makeColorFn above is this:

myBlend[body_][n_] := Blend[body, n]

colorfn = myBlend[{w, MapThread[Append, {colors, vars}]}\[Transpose]];

With[{colorfn = colorfn}, 
  Manipulate[
    Image3D[img, ColorFunction -> colorfn], 
    Evaluate[Sequence @@ ({#, 0, 1} & /@ vars)]
  ]
]

The key here is to inject a color function in a form that is open to evaluation so that it "picks up" the values of α[x]. Function doesn't work here as its body is held. Compare:

Manipulate[Blend[x, #] &, {x, 0, 5}]

Manipulate[myBlend[x], {x, 0, 5}]

enter image description here

I still need With to get colorfn inside Manipulate before it is evaluated and the GUI is built, or the vars variables are not recognized and replaced correctly.

$\endgroup$
  • $\begingroup$ Excellent. That's the power of Mathematica. Thanks a lot. $\endgroup$ – Majis Feb 22 '17 at 13:28
  • 1
    $\begingroup$ @Majis You're welcome. I made one more code adjustment hoping to better show what needs to be inside Manipulate and what does not. $\endgroup$ – Mr.Wizard Feb 22 '17 at 13:46
  • 1
    $\begingroup$ @Majis I thought of another example that I felt I should share. Manipulate and friends are rather tricky and it's important to see multiple examples that work as well as some that don't, IMHO. I hope this one is helpful to you. $\endgroup$ – Mr.Wizard Feb 22 '17 at 18:41

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.