Skip to main content
7 of 8
correct my correction :-p
Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k

Inconsistent handling of Dynamic option values; intended, omission, or bug?

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 the Dynamic and use it for the option. And that it will be updated whenever a Dynamic 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]]

enter image description here

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]
]

enter image description here

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.

Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k