3
$\begingroup$

I am trying to build a HorizontalGauge control for use in a Manipulate. The gauge should enable the user to select a day of the month. The following code seems to work fine (with one exception, noted below):

 MyGauge :=
  HorizontalGauge[
    #1, #2,
    GaugeFrameStyle -> Gray,
    GaugeFaceStyle -> LightOrange,
    (*GaugeLabels\[Rule]Automatic,*)
    GaugeLabels -> Placed[#1, Above],
    ScaleDivisions -> {8, 6}
  ] &;

Manipulate[
 Floor[dim],
 {{dim, 1, "Day in month"}, 1, 31, MyGauge}
]

This code successfully produces the following gauge:

enter image description here

The problem I am having relates to the label. Note that the value shown includes a fractional part, when I would really like to display just the integer part.

I have tried various workarounds:

  • Use of GaugeLabels->Automatic (* Same value as above *)
  • Explicit use of Floor[#1] (* Results in display of ⌊value⌋ *)
  • Adding an explicit integer increment as a fourth arguments to the Manipulate control description (* Error *)

Note that the normal behavior of HorizontalGauges has the behavior I desire as the default:

HorizontalGauge[98.6, {0, 150}, GaugeLabels -> Automatic]

enter image description here

My question is: How can I produce a HorizontalGauge label that displays an integer version of its first argument? More generally, is it possible to display arbitrary functional transformations on the input arguments in the GaugeLabels?

$\endgroup$
6
$\begingroup$

Edit to add details of Echo to find out why this is the case

I think the issue here is getting the Round/Floor/other function in the right level of the expression. I played around with Map in a few positions of the label, and this seems to do what you want:

myGauge := 
  HorizontalGauge[#1, #2, 
    GaugeFrameStyle -> Gray, 
    GaugeFaceStyle -> LightOrange,
    GaugeLabels -> Placed[Floor /@ #1, Above], 
    ScaleDivisions -> {8, 6}] &;

Manipulate[Floor[dim], {{dim, 1, "Day in month"}, 1, 31, myGauge}]

IntegerLabel

To see the reason for this, you can use Echo (if you are using version 10.3 or above). Echo lets you have an extra formatted output cell that doesn't affect the evaluation of your original code. So to see what's happening, I changed the gauge function to this:

myGauge := HorizontalGauge[#1, #2, 
  GaugeFrameStyle -> Gray, 
  GaugeFaceStyle -> LightOrange, 
  GaugeLabels -> Echo[
    Placed[Floor /@ #1, Above], 
    "Gauge label: ", 
    FullForm
  ], 
  ScaleDivisions -> {8, 6}
] &;

When used in the manipulate you will then get an extra cell output of Gauge label: Placed[Dynamic[Floor[dim$$]],Above]

If we remove the /@ from it (so not mapping, just using Floor), the output is Gauge label: Placed[Floor[Dynamic[dim$$]],Above].

Floor is not designed to work on Dynamic objects (it only evaluates numerically on integers, reals etc) so that is why you do not get the expected output in the original code.

$\endgroup$
  • $\begingroup$ It works all right, thanks. Can you tell me why my naive solution doesn't work? In particular, why does ⌊value⌋ show up if I leave off the "/"? $\endgroup$ – Spencer Rugaber Nov 30 '16 at 20:35
  • $\begingroup$ If you are using version 10.3 or above you can use Echo to see what the internal evaluation of the GaugeLabel is. I will edit my answer to add the details, but essentially the answer is that the label gets wrapped in Dynamic before evaluating so in your original code you were getting Floor[Dynamic[number]] rather than Dynamic[Floor[number]] $\endgroup$ – lowriniak Dec 1 '16 at 9:55
1
$\begingroup$

I can't see any easy way to directly do what you ask for with a Manipulate expression, but it becomes very easy when the function, DynmacicModule, that lurks behind Manipulate is used. This allows us to use the 2nd argument of Dynamic to constrain the values to integers.

DynamicModule[{val = 1},
  HorizontalGauge[Dynamic[val, (val = Round[#]) &], {1, 31},
    GaugeFrameStyle -> Gray,
    GaugeFaceStyle -> LightOrange,
    GaugeLabels -> Placed[Dynamic[Style[val, 20]], Above],
    ScaleDivisions -> {8, 6},
    ImageSize -> Large]]

gauge

Note that with this approach, not only is the label shown as a integer, but the gauge marker now moves in unit steps.

This approach can, of course, be used with a Manipulate expression inside it.

DynamicModule[{val = 1},
  Manipulate[
    Style[val, 20],
    Row[
      {Style["Day of the Month ", 14],
       HorizontalGauge[Dynamic[val, (val = Round[#]) &], {1, 31},
         GaugeFrameStyle -> Gray,
         GaugeFaceStyle -> LightOrange,
         GaugeLabels -> Placed[Dynamic[Style[val, 16]], Above],
         ScaleDivisions -> {8, 6},
         ImageSize -> 400]}]]]

combo

Update

Spencer Rugaber has found a way to use my approach directly in a Manipulate expression; he simply initializes val with the Initialization option. See his comment below.

$\endgroup$
  • $\begingroup$ Thanks for the insight. It led me to play with your second version by removing the DynamicModule: Manipulate[ Style[valy, 20], Row[{ Style["Day of the Month ", 14], HorizontalGauge[ Dynamic[valy, (valy = Round[#1]) &], {1, 31}, GaugeFrameStyle -> Gray, GaugeFaceStyle -> LightOrange, GaugeLabels -> Placed[Dynamic[Style[valy, 16]], Above], ScaleDivisions -> {8, 6}, ImageSize -> 400 ] }], Initialization :> (valy = 1;) ] This seems to work fine. Is there a reason why the DynamicModule is necessary? $\endgroup$ – Spencer Rugaber Dec 1 '16 at 15:16
  • $\begingroup$ @SpencerRugaber. Two ways of doing the same thing. I used DynamicModule to initialize the variable val. Since you initialized var it by means of Initialization, you did implicitly what I did explicitly. Mathematica transforms a Manipulate expression into a DynamicModule expression and stuff the Initialization option become local variables initialized in the explicit way I did it. $\endgroup$ – m_goldberg Dec 1 '16 at 15:40
  • $\begingroup$ @m_goldberg: I have a follow-up question on this: When I try your code, things look and work the way they should, except I get some strange little "jumps" at certain values where the position of various elements, and the vertical size of the image changes slightly from one value to the next. I can't really find any rhyme or reason for this behavior (observed on Win7 x64). Do you see this too? Is this a bug, or is there some way to fix this? $\endgroup$ – Pirx Dec 1 '16 at 15:40
  • $\begingroup$ @Pirx. I don't see it on OS X. $\endgroup$ – m_goldberg Dec 1 '16 at 15:51
  • $\begingroup$ This is really strange: I found that it's the gauge itself the rendering of which changes depending on the position of the marker. I can see the ticks jumping by a pixel or so to the left or right, and the tickmark labels moving up or down slightly. This happens only for certain values. In addition, the display is really slow, and lags substantially behind the mouse position. If I move at perhaps one tick per second, things move along alright, but if I move 10 ticks in one second, the marker pretty much remains frozen and then jumps 10 ticks. Oh well... $\endgroup$ – Pirx Dec 1 '16 at 16:14

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.