In answering Dynamic ClipPlanes calculated from current ViewPoint Kuba and I got into a brief exchange regarding how Option values wrapped in Dynamic
should be handled. For background John Fultz wrote:
Front end options, which includes all box options, can take
Dynamic
heads. That basically means that the FE will compute the value of theDynamic
and use it for the option. And that it will be updated whenever aDynamic
dependency updates.
It would therefore appear advantageous for Option values that become Box options to preserve a Dynamic
head, and indeed many do, however some do not. For example:
gr3D = Graphics3D[{}, MapAt[Dynamic, 2] /@ Options @ Graphics3DBox];
Tally[Head /@ Values @ Options @ ToBoxes @ gr3D]
{{Dynamic, 51}, {DynamicBox, 6}}
All but six Options pass their Dynamic
values; these six allow conversion to DynamicBox
:
Cases[Options @ ToBoxes @ gr3D, _[op_, _DynamicBox] :> op]
{AxesLabel, AxesStyle, ClipPlanes, Epilog, PlotLabel, Prolog}
Should these six Options also pass Dynamic
values or is there a design intent that they do not?
(Observations in 10.1.0 under Windows, in case this behavior is version dependent.)
Further consideration
It is worth noting that in the case of expressions which are explicitly displayed a DynamicBox
"works" because it is an active element in the front end, therefore e.g. a dynamic value of PlotLabel
updates appropriately:
Slider[Dynamic[x], {0, 1}]
Graphics3D[Ball[], PlotLabel -> Dynamic[x]]
However something that is not explicitly displayed, such as a style directive, would seem an inappropriate place for a DynamicBox
expression, and it does indeed produce an error message:
x = Red;
Graphics[Disk[], AxesStyle -> Dynamic[x]]
(* shown by clicking the "+" next to the error frame *)
An improperly formatted directive with head DynamicBox was encountered.
In the case of AxesStyle
I think conversion to DynamicBox
is simply a mistake.
This can be bypassed by use of a RawBoxes
wrapper, which if respected prevents processing during Box conversion.
(* Thanks to Kuba for the concise example *)
ColorSlider @ Dynamic[x]
Graphics[
Disk[],
Axes -> True,
BaseStyle -> AbsoluteThickness[3],
AxesStyle -> RawBoxes @ Dynamic[x]
]
The case of AxesLabel
is somewhat ambiguous as its elements are explicitly displayed, therefore individual Dynamic
labels being converted into DynamicBox
expressions might be appropriate. However there are problems.
In version 10.1.0 under Windows this initially works but closing the Notebook in which it resides hangs the FrontEnd:
(* THIS CODE MAY HANG THE FRONT-END
ColorSlider @ Dynamic[x]
Graphics[Disk[],
Axes -> True,
AxesLabel -> Dynamic[x]
]
*)
This likewise works initially but hangs the FrontEnd on close:
(* THIS CODE MAY HANG THE FRONT-END
ColorSlider @ Dynamic[x]
Graphics[Disk[],
Axes -> True,
AxesLabel -> {Dynamic[x]}
]
*)
Adding RawBoxes
to a bare Dynamic
does not work right:
ColorSlider @ Dynamic[x]
Graphics[Disk[],
Axes -> True,
AxesLabel -> RawBoxes @ Dynamic[x]
]
An unknown box name (RGBColor) was sent as the BoxForm for the expression. Check the format rules for the expression.
This implies an explanation for Box conversion: in GraphicsBox
the value of AxesLabel
needs to be in Box form. Attempting this conversion inside our force-fed Dynamic
once again produces an initial result but hangs on close:
(* THIS CODE MAY HANG THE FRONT-END
ColorSlider @ Dynamic[x]
Graphics[Disk[],
Axes -> True,
AxesLabel -> RawBoxes @ Dynamic @ ToBoxes @ x
]
*)
There clearly seems to be a bug (in 10.1.0) with the use of dynamic values in AxesLabel.