Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Is it possible to create a logarithmic slider similar to this one that responds to a change of the variable value?

That is, when the slider is moved, the variable value should update. When the variable value is changed separately, the slider position should update too.

The ultimate aim is to use this in Manipulate and have both a text input and a logarithmic slider input for the same parameter.


The post I linked to does not address changing the slider position when the variable is changed elsewhere.

share|improve this question

3 Answers 3

up vote 17 down vote accepted

A reliable composition of elements

Perhaps something like this? (Edit: Fixed to work with Autorun.) Note that the InputField label is editable, similar to a normal Manipulator. One can also add an additional InputField[Dynamic @ x] if a regular InputField is desired.

Manipulate[
 x,
 {{x, 1.}, 1., 100.,
  Row[{Slider[Dynamic[Log10[#], (x = 10^#) &], Log10[#2]], " ", 
     InputField[#, Appearance -> "Frameless", BaseStyle -> "Label"]}] &}
 ]

Autorun of Manipulate

It's not a Manipulator, so no animator/input field. That's harder, since they (and the label) are built into the front-end implementation of a Manipulator. A Trigger and InputField could be added to simulate a Manipulator, I suppose.


A proper hack

All right, Kuba, you asked for it. :)

This is based on some spelunking of undocumented functions. The section titles reflect my feeling that the first is the best and a very good way to go. (These UI/Manipulate questions never seem to generate much interest in this SE community. This one wasn't particularly hard, but it did take some time to go through the details. I hope someone will find it useful, which is much more rewarding to me that "upvotes." In fact, I hope the first one is even more useful.)

The code is long, mainly because I worked out how the options to Manipulator are passed to the internal function. I put it at the end. I wrote a function logManipulator that works (almost exactly) like Manipulator (one unimportant thing was left undone).

{logManipulator[Dynamic[x], {1., 100.}], InputField[Dynamic@x]}

Mathematica graphics

The OP mentioned using it in a Manipulate with an input field. My original answer put the editable field as a label, just as a Manipulator does. However if a separate InputField is desired, that it as easy as adding a line to Manipulate for it.

To use logManipulator in Manipulate, one needs to pass a pure Function as with any custom control. Note: the animation below was produce with Export via Autorun, which interpolates x linearly between 10.^-5 and 10.; the animator, however, when run, interpolates linearly between their logarithms, and the slider moves with constant speed (more or less).

Manipulate[
 Plot[t Sin[1/t], {t, -x, x}, PlotRange -> x, ImagePadding -> 10],
 {x, 10.^-5, 10., 
  logManipulator[##, Appearance -> {"Labeled", "Open"}, AnimationDirection -> Backward] &},
 {{x, 1.}, Number, InputField},
 AutorunSequencing -> {1}
 ]

Autorun of Manipulate

One can enter a value for x in the InputField (note the position of the slider):

Mathematica graphics

Code dump

The elements and options of Manipulator are nearly each passed as separate arguments to FEPrivate`FrontEndResource["FEExpressions", "Manipulator04"][..]. Only the animator elements in AppearanceElements -> {..} are passed together as a list. Some of the options are passed in other places. Since the Manipulator is wrapped in a DynamicBox, I used With to inject the values. I've given the arguments names that correspond more or less to the names of the elements or options. I hope that is enough of a hint as to how it works. The basis for the code was the output cell of a simple Manipulator[Dynamic[x]] (which can be inspected with the menu command "Cell > Show Expression").

ClearAll[logManipulator];
With[{smallerRule = {Large -> Medium, Medium -> Small, Small -> Tiny}},
 logManipulator[Dynamic[x_], range_: {1, 10}, 
   OptionsPattern[Manipulator]] := With[{
    logrange = Log10[range],
    imagesize = OptionValue[ImageSize] /. Automatic -> Medium,
    inputfieldsize = 
     OptionValue[ImageSize] /. Automatic -> Medium /. smallerRule,
    enabled = OptionValue[Enabled],
    continuousaction = OptionValue[ContinuousAction],
    appearance = 
     First[Cases[OptionValue[Appearance], 
        Tiny | Small | Medium | Large] /. {} -> {Automatic}],
    labeled = ! FreeQ[OptionValue[Appearance], "Labeled"] || ! 
       FreeQ[OptionValue[AppearanceElements], "InlineInputField"],
    opener = 
     OptionValue[AppearanceElements] /. {Automatic -> True, 
       All -> True, None -> False, 
       l_List :> (Cases[l, Except["InlineInputField"]] =!= {})},
    inputfield = 
     MatchQ[OptionValue[AppearanceElements], Automatic | All] ||
      ! FreeQ[OptionValue[AppearanceElements], "InputField"],
    appearanceelements = 
     OptionValue[AppearanceElements] /. {Automatic -> All, None -> {},
        l_List :> Cases[l, Except["InlineInputField" | "InputField"]]},
    autoaction = OptionValue[AutoAction],
    exclusions = OptionValue[Exclusions]},
   ReleaseHold@MakeExpression[
     PaneBox[
      DynamicModuleBox[{
        Typeset`open$$ = ! FreeQ[OptionValue[Appearance], "Open"],
            Typeset`paused$$ = OptionValue[PausedTime],
        Typeset`rate$$ = OptionValue[AnimationRate],
            Typeset`dir$$ = OptionValue[AnimationDirection]},
       StyleBox[
        DynamicBox[
         FEPrivate`FrontEndResource["FEExpressions", "Manipulator04"][
          Dynamic[x],
          Dynamic[Log10[x], (x = 10^#) & ],
          logrange,
          imagesize,
          inputfieldsize,
          enabled,
          continuousaction,
          appearance,
          labeled,
          opener,
          inputfield,
          appearanceelements ,
          autoaction,
          exclusions,
          Dynamic[Typeset`open$$],
              Dynamic[Typeset`paused$$],
          Dynamic[Typeset`rate$$],
              Dynamic[Typeset`dir$$]]],
        DynamicUpdating -> True],
       DynamicModuleValues :> {}],
      BaselinePosition -> (OptionValue[BaselinePosition] /. Automatic -> Baseline),
      ImageMargins -> OptionValue[ImageMargins]],
     StandardForm]]
 ]
share|improve this answer
    
Maybe you can post that solution involving cell edition you've mentioned on chat? I will certainly upvote it. –  Kuba Jul 19 '13 at 19:03
    
I do find it useful! I thought you will only post information which box to edit in the cell, I'm impressed. Unfortunately I can't upvote twice. –  Kuba Jul 20 '13 at 17:35
    
Thanks! I figure coding it could be worked out, only I wasn't motivated to do it until you asked. I'm glad you find it useful. –  Michael E2 Jul 20 '13 at 17:37
    
The Michael as I know him ;) +1 –  Stefan Jul 20 '13 at 23:17
2  
Amazing that you went so deep into undocumented functions! –  Ted Ersek Jul 21 '13 at 0:49

with manipulate

Manipulate[
           Framed@y,

           Column@{Slider[Dynamic[Log[10, y], (y = 10^#) &], {1, 3}], 
                   InputField[Dynamic@y]}
          ]

single slider

y=10;    
{
 Slider[Dynamic[Log[10, y], (y = 10^#) &], {1, 3}], 
 Dynamic@y
}

Of course, here base is 10 but if it is what You are looking for, I can extend this.

share|improve this answer
    
You need to read more carefully: "When the variable value is changed separately, the slider position should update too." –  halirutan Jul 12 '13 at 13:16
1  
@halirutan Have You tried that? Works for me. Try to set y=123 for example after some sliding done. –  Kuba Jul 12 '13 at 13:16
1  
Indeed, I haven't tried. I just looked shortly over your code and saw that you haven't used any text input as asked by Szabolcs. Therefore, and for the simplicity of the approach (which I'm sure Szabolcs would have found by himself) I assumed you missed that part. I'm sorry, I didn't mean to be rude. I was in a hurry and just wanted to tell you, that you missed some parts of the question. –  halirutan Jul 12 '13 at 15:58
    
I'm still not sure whether this is all Szabolcs wanted. Lets wait for a comment of him and if it really is, you can count on my upvote for your answer. –  halirutan Jul 12 '13 at 16:00
    
@halirutan ah, indeed, You're right I have missed "text" part ;) Please take a look at update. –  Kuba Jul 12 '13 at 17:06

Here there are two variables x and y that are coupled together by the If statements. So you can change the slider x and it changes the y value or you can change the input box y and it also changes the x. The log character of the slider and box are given by the z=10^x function, which means that the slider value is the log of z.

xOld = 0; yOld = 0;
Manipulate[If[10^xOld != 10^x, y = x; xOld = x];
           If[10^yOld != 10^y, x = y; yOld = y]; z = 10^x, {x, 1, 10}, {y}]

enter image description here

This basically extends Michael Pilat's answer to the linked question to the case of two controls (the slider and the input box).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.