1
$\begingroup$

I'm developing a demonstration that allows students to explore the location of a point on a number line simultaneously at various scales. I'll show a very simplified version here to get to the nub of my problem.

The Integers scale, has a range of {-30,30}. It's length is 60 units. n is restricted to that range.

The Tenths scale, having a length of 10 units, should also contain or display `n``.

The image shows the screen display when n = 13.2...

scales

The upper marker can be moved by clicking and dragging. Whenever the marker moves to a different interval, of {-30,-20},{-20,-10},{-10,0},{0,10},{10,20},{20,30} the range of the lower scale is updated. This is fine. But the marker on the bottom scale cannot be dragged.

Here's the code:

Manipulate[
 DynamicModule[{n = 10.123},
  Column[{
    HorizontalGauge[Dynamic@n, {-30, 30},
     ImageSize -> {600, Automatic}],
    If[show > 1,
     Dynamic@HorizontalGauge[Dynamic@n, bounds[n, 10],
       GaugeFaceStyle -> RGBColor[1., 0.83, 0.67],
       ImageSize -> {600, Automatic}], ""]}]], 
 {{show, 2, "show to"}, {1 -> "Integers", 2 -> "Tenths"}},
 Initialization :> (
   bounds[m_, r_] :=
    Module[{z = Round[m, r]},
     Which[
      (z >= 0 \[And] m <= z) \[Or] (z < 0 \[And] m <= z), {z - r, z},
      (z >= 0 \[And] m > z) \[Or] (z < 0 \[And] m > z), {z, z + r},
      True, "error"]])]

I've tried placing and removing Dynamic on the critical line,

 Dynamic@HorizontalGauge[Dynamic@n, bounds[n, 10]

to no avail. I have not been able to both (1) allow the bottom marker to be draggable and (2) automatically reset the range of the lower scale (when a value from the upper scale goes outside of the current range on the bottom scale.

I've looked at various postings on Dyanmic (542 postings have used the tag "Dynamic"!) but haven't been able to solve the problem. Frankly, I continue to find the behavior of Dynamic mystifying. For instance why does the following not work?

         HorizontalGauge[Dynamic@k, bounds[Dynamic@k, 10]

I've also tried defining n as an invisible control (ControlType->None) with only limited success.

Any help would be appreciated.


Update

Kuba has provided a very workable solution to the above formulation. However, I would like to be able to extend it beyond two scales. Here is the current version of the code, based on Kuba's contribution:

DynamicModule[
 {n = 10.123, m = 10.123, p = 10.123},
 Manipulate[
  Refresh[Print@RandomReal[];
   Column[{
     (*Integer Scale*)
     HorizontalGauge[Dynamic[n, (n = m = #) &], {-30, 30},
      BaseStyle -> 16,
      GaugeFaceStyle -> White,
      ScalePadding -> .04,
      (*ScaleRanges\[Rule]bounds[n,10],*)       
      ScaleRangeStyle -> 
       If[show > 1, RGBColor[1., 0.83, 0.67], White]
         ScaleDivisions -> {10, 2},
      ImageSize -> w
      ],
     (*Tenths Scale*)
     Dynamic@If[show > 1,
       Dynamic[
        HorizontalGauge[Dynamic[n, (n = p = #) &], bounds[m, 10],
         GaugeMarkers -> Blue,
         BaseStyle -> 14,
         ScalePadding -> .04,
         GaugeFaceStyle -> RGBColor[1., 0.83, 0.67],

         (*ScaleRanges\[Rule]bounds[Dynamic@z,1],*)        
         ScaleRangeStyle -> 
          If[show > 2, RGBColor[0.8, 0.75, 1.], 
           RGBColor[1., 0.83, 0.67]],
         ImageSize -> {600, Automatic}],

        TrackedSymbols :> {m}], ""],

     (*Hundredths Scale*)
     Dynamic@If[show > 2,
       Dynamic[HorizontalGauge[Dynamic[n], bounds[p, 1],
         BaseStyle -> 14,
         GaugeFaceStyle -> RGBColor[0.8, 0.75, 1.],
         ScalePadding -> .04,
         (*ScaleRanges\[Rule]bounds[x,.1],*)

         ScaleRangeStyle -> 
          If[show > 3, RGBColor[0.96, 1., 0.31], 
           RGBColor[0.8, 0.75, 1.]],
         ScaleDivisions -> {5, 4},

         ImageSize -> {600, Automatic}],
        TrackedSymbols :> {p}], ""]
     }], None],

  {{show, 3, "show to"}, {1 -> "Integers", 2 -> "Tenths", 
    3 -> "Hundredths"(*,4\[Rule]"Thousandths",
    5\[Rule]"Ten-Thousandths"*)}},

  Initialization :> (
    w = {600, Automatic};
    bounds[m_, r_] :=
     Module[{z = Round[m, r]},
      Which[(z >= 0 \[And] m <= z) \[Or] (z < 0 \[And] m <= z), {z - 
         r, z}, (z >= 0 \[And] m > z) \[Or] (z < 0 \[And] m > z), {z, 
        z + r}, True, "error"]])]]

When run, it looks like this:

hundredths

If we slide the upper marker, it will update the range of the middle scale, as required, but it does not update the range of the bottom scale. The general goal is to have any marker control the ranges of all the scales beneath it.

BTW, I plan to add two extra scales, for thousandths, and ten-thousandths. That's why the solution needs to be general.

$\endgroup$
  • $\begingroup$ I decided to use time to improve performance. Unfortunately this postpones explanation :/. Good luck :) $\endgroup$ – Kuba Feb 25 '15 at 21:17
1
$\begingroup$

Few notes: try to avoid Manipulate for complex things. When you have multiple controllers (of the same variable) inside body of Manipulate it triggers evaluation unless you use nested Dynamic/Refresh.

Moreover, referring your last example, take a look at: Function[{m, r}, Round[m, r]][Dynamic[5.5], 1].


DynamicModule[{n = 10.123, interval = {10, 20}},


Manipulate[
(*1*) Refresh[

       Column[{
(*2*)   HorizontalGauge[ Dynamic[n, (n = #; interval = bounds[#, 10]) &], {-30, 30}, 
                      ImageSize -> {600, Automatic}],
(*3*)   Dynamic @ If[show > 1,
(*4*)                Dynamic[miniG[interval] , TrackedSymbols :> {interval}],
                     ""]
       }]
   ,
   None],

  {{show, 2, "show to"}, {1 -> "Integers", 2 -> "Tenths"}}, 
  Initialization :> (
      bounds[m_, r_] :=  Module[{z = Round[m, r]}, 
        Which[(z >= 0 ∧ m <= z) ∨ (z < 0 ∧ m <= z), {z -  r, z},
              (z >= 0 ∧ m > z) ∨ (z < 0 ∧ m > z), {z, z + r}, 
              True, "error"]];
(*5*) miniG[int_] :=  miniG[int] =  HorizontalGauge[Dynamic[n], int, 
                                     ImageSize -> {600, Automatic}];

   )]

 ]

enter image description here

(loading explanation)

$\endgroup$
  • $\begingroup$ This seems to offer more general solution (which is great because I want to add additional scales), but the lower marker sometimes jambs, sitting immobile while the upper marker is being dragged. $\endgroup$ – DavidC Feb 25 '15 at 21:43

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.