Message Boards Message Boards

[✓] Choose dates dynamically with a Slider?

GROUPS:

I would like to select a date from a list of dates using a slider, and show the chosen date right underneath the slider in the form of a date string.. Take for instance the following simple list:

list={{2000, 1, 3}, {2000, 1, 4}, {2000, 1, 5}, {2000, 1, 6}, {2000, 1, 7}, {2000, 1, 10}, {2000, 1, 11}, {2000, 1, 12}, {2000, 1, 13}, {2000, 1, 14}}

So I could for instance choose with the slider the third element of this list, which is {2000, 1,5}, and then convert this with the command DateString[DatObject[{2000, 1, 7}]] to the data string "Wed 5 Jan 2000". Now I want this date string shown underneath the slider instead of the usual number, which in this case would be 3.

The slider would be for instance:

Slider[Dynamic[m],{1,10,1}

The problem is now that Dynamic[m] is not accepted by Part. With the command

list[[Dynamic[m]]]

one gets an error message that the result from the slider cannot be used as a part specification. How do I solve this problem? Thanks in advance for your help.

POSTED BY: Laurens Wachters
Answer
2 months ago

Laurens,

Put the Dynamic on the outside of the list, not in the part specification:

Dynamic[list[[m]]]

Putting it together you get:

Column[{Slider[Dynamic[m], {1, 10, 1}], 
  Dynamic[DateString[DateObject[list[[m]]]]]}]

Regards,

Neil

POSTED BY: Neil Singer
Answer
2 months ago

Dynamic then should be an outer wrapper not the inner:

list={
    {2000,1,3},{2000,1,4},{2000,1,5},{2000,1,6},{2000,1,7},
    {2000,1,10},{2000,1,11},{2000,1,12},{2000,1,13},{2000,1,14}};

Method 1 - indexed variable

Column[{
    Slider[Dynamic[m],{1,10,1}],
    Dynamic[DateString[DateObject[list[[m]]]]]}]

enter image description here

Method 2 - list of variables

Column[{
    Slider[Dynamic[m],{DateString[DateObject[#]]&/@list}],
    Dynamic[m]}]

Method 3 - localized variable

Manipulate[DateString[DateObject[m]], {m, list, Slider}]
POSTED BY: Vitaliy Kaurov
Answer
2 months ago

Thanks a lot for your advice. I have learnt a bit on Dynamic by now. But I am now stuck with Dynamic applied on FinancialData. I have made the following small program that should become a part of a cdf for analyzing the course of stock prices in which the user would be able to switch from stock to stock

p="ge";
Column[{DynamicModule[InputField[Dynamic[p]], 
Dynamic[ListLinePlot[FinancialData[p,{2017,10,1}][[All,2]]]]}]

This program does work, but after its evaluation my PC becomes awfully slow. Why is this, and would there be a remedy for it? I have a PC with an Intel i5 processor and 8 MB memory. Mathematica and its kernel don't seem to use very much of them, according to the windows 10 task manager. Another question is why in the result the input field and the plot are shown in a row and not in a column.

POSTED BY: Laurens Wachters
Answer
2 months ago

Laurens,

Your posted code did not have matching delimiters but I got the same behavior (once fixing it) because the FinancialData call is time consuming.

I fixed it one way (the easy way --- but more limiting) with this code by using a Manipulate.

Manipulate[
 ListLinePlot[FinancialData[p, {2017, 10, 1}][[All, 2]]], {p, "ge"}, 
 ControlType -> InputField]

You can use Dynamic directly but you must handle more details this way:

DynamicModule[{p, plotfun, plot}, p = "ge"; 
 plotfun[a_, b_] := 
  plot = ListLinePlot[FinancialData[a, {2017, 10, 1}][[All, 2]]]; 
 plotfun[p, p]; 
 Column[{InputField[Dynamic[p, {Automatic, plotfun}], String], 
   Dynamic[plot]}]]

The way this works is to make the variables p, plotfun (the function for plotting), and the plot itself local . This is so we do not mess with global variables (although you can make them global if you want). I define a function to make the plot called "plotfun" so I can call it two times -- once at initialization so we start with a default plot and once in operation. Note that I used String as the second argument to InputField so we do not need to deal with the quotation marks. I use the optional arguments to Dynamic {fstart,f,fend}. Read about these but I defined them to be {Automatic, plotfun} -- during editing the inputfield MMA automatically updates the variable "p" but at the end (when you hit tab or return) it runs the function "plotfun" (which updates our plot --- only once!!! so we do not bring the machine to its knees repeatedly getting financial data.

Regards

Neil

POSTED BY: Neil Singer
Answer
2 months ago

Dear Neil, Thanks a lot for your advice. By now I have got some experience with Dynamic. But I should say that sometimes it turns out that I still do not understand it all. Therefore, I would like to learn some more about Dynamic. On the internet I found a book "Dynamic Interactivity" that in fact I found more helpful than the Help in Mathematica itself. But I can only get the book in PDF-format. Do you know if I could get it as a notebook? Maybe you know some other books that might be helpful to get a deeper insight in Dynamic? Using your above approach I was able to build a quite useful program for my research into the behavior of stock prices. But now I got stuck with a CDF derived from it. I hope you can help me. Basically the program looks like this:

   DynamicModule[{a, b, c, d, p1 = "GE", p2 = "MSFT", list1, list2, 
     listfun1, listfun2, listt, start, end, relprice, x, y, xpart, ypart,
      imagesize},
    listfun1[a_, b_] := list1 = FinancialData[a, "OHLCV", {2016, 1, 1}];
    listfun1[p1, p1];
    listfun2[c_, d_] := list2 = FinancialData[c, "OHLCV", {2016, 1, 1}];
    listfun2[p2, p2];
    Panel[
     Column[{
       (*Choice of the 2 stocks*)
       Row[{TextCell["                 Stock 1:  "], 
         InputField[Dynamic[p1, {Automatic, listfun1}], String, 
          FieldSize -> 4], 
         TextCell["                      Compare with stock 2:  "],
         InputField[Dynamic[p2, {Automatic, listfun2}], String, 
          FieldSize -> 4]}],

       (*Choice of the time interval*)
       listt = list1[[All, 1]];
       IntervalSlider[{Dynamic[start], Dynamic[end]}, {1, Length[listt], 
         1}, ImageSize -> {500, 20}, Method -> "Stop", 
        MinIntervalSize -> 1],
       Dynamic[start];
       Dynamic[end];

       Row[{Dynamic[DateString[DateObject[listt[[start]]]]], 
         TextCell[
          "                                                              \
                                                     "],
         Dynamic[DateString[DateObject[listt[[end]]]]]}],
(*Choice of quantities to be plotted*)     
  Row[{
         TextCell["      "],
         Dynamic[
          RadioButton[
           Dynamic[y], {" price of stock 1 ", list1[[All, 2, 4]]}]],
         TextCell[" price stock 1 "],
         Dynamic[
          RadioButton[
           Dynamic[y], {" price of stock 2" , list2[[All, 2, 4]]}]],
         TextCell[" price stock 2 "],
         Dynamic[
          RadioButton[
           Dynamic[y], {"quotient stock prices 1 and 2" , 
            list1[[All, 2, 4]]/list2[[All, 2, 4]]  }]], 
         TextCell[" quotient stock prices 1 and 2"]}],

       xpart = Dynamic[Range[start, end]];
       ypart = Dynamic[y[[2]][[start ;; end]]];

       Dynamic[
        ListLinePlot[
         Partition[Riffle[Range[start, end], y[[2]][[start ;; end]]], 2],
          ImageSize -> 700]]

       }]]]

This code works real nice. But when I convert this to a CDF, it turns out no longer possible to switch to another stock. It is for instance not possible to change from GE to BA. For some reason the content of the input field for this cannot be changed anymore. Might this be caused by something in the code, or is this something inherent in CDF's?

POSTED BY: Laurens Wachters
Answer
18 days ago

Laurens,

You made many good improvements! Once you work everything out you may want to open it in its own window (although in a CDF I am not sure what that would do)

Your problem is that you are not correctly handling all of your states when you change stock names.

Your code is

InputField[Dynamic[p1, {Automatic, listfun1}], String, FieldSize -> 4]

This will run listfun1 and change the stock name (although your syntax is a bit dangerous and confusing here -- I would use listfun1[#]& and make listfun1 and listfun2 functions of one variable -- although it does work the way it is)

The problem is that this code updates the value of the list1 variable, however, it does nothing to all the other variables that depend on list1 (listt, start, end, y). I recommend that you make your listfun1 and listfun2 functions update all of the variables that you need and everything will update properly when you tab out of the field. Also, you may want to add Selectable->False to your textcells so that you can't edit them and can tab over them (they will select as a whole but you can't click on them or go inside). Here is a quick hack that "fixes" list1fun but not list2fun -- I did not verify that all settings are updating properly but this should give you the general idea -- when you change something you must change everything that depends on it in a consistent way. I tried to make minimal changes although you may want to consider some reorganization that will simplify the code. For example, testing for strings in y[[1]] is not the cleanest code -- maybe consider returning just 1,2, or 3 and create some other variable with your strings and plots -- but you have to think this through to see if it causes other issues.

DynamicModule[{a, b, c, d, p1 = "GE", p2 = "MSFT", list1, list2, 
  listfun1, listfun2, listt, start, end, relprice, x, 
  y = {" price of stock 1 ", {}}, xpart, ypart, imagesize}, 
 listfun1[a_] := 
  Module[{}, list1 = FinancialData[a, "OHLCV", {2016, 1, 1}]; 
   listt = list1[[All, 1]]; 
   y[[2]] = 
    Switch[y[[1]], " price of stock 1 ", list1[[All, 2, 4]], 
     " price of stock 2", list2[[All, 2, 4]], 
     "quotient stock prices 1 and 2", 
     list1[[All, 2, 4]]/list2[[All, 2, 4]]]; 
   start = Round[Length[listt]* 0.25]; 
   end = Round[Length[listt]* 0.75]];
 listfun1[p1];
 listfun2[c_, d_] := list2 = FinancialData[c, "OHLCV", {2016, 1, 1}];
 listfun2[p2, p2];
 Panel[Column[{(*Choice of the 2 stocks*)
    Row[{TextCell["                 Stock 1:  ", Selectable -> False],
       InputField[Dynamic[p1, {Automatic, listfun1[#] &}], String, 
       FieldSize -> 4], 
      TextCell["                      Compare with stock 2:  ", 
       Selectable -> False], 
      InputField[Dynamic[p2, {Automatic, listfun2}], String, 
       FieldSize -> 4]}],(*Choice of the time interval*)

    IntervalSlider[{Dynamic[start], Dynamic[end]}, {1, Length[listt], 
      1}, ImageSize -> {500, 20}, Method -> "Stop", 
     MinIntervalSize -> 1], Dynamic[start];
    Dynamic[end];
    Row[{Dynamic[DateString[DateObject[listt[[start]]]]], 
      TextCell[
       "                                                                                                                   "\
, Selectable -> False], 
      Dynamic[DateString[
        DateObject[
         listt[[end]]]]]}],(*Choice of quantities to be plotted*)
    Row[{TextCell["      ", Selectable -> False], 
      Dynamic[RadioButton[
        Dynamic[y], {" price of stock 1 ", list1[[All, 2, 4]]}]], 
      TextCell[" price stock 1 ", Selectable -> False], 
      Dynamic[RadioButton[
        Dynamic[y], {" price of stock 2", list2[[All, 2, 4]]}]], 
      TextCell[" price stock 2 ", Selectable -> False], 
      Dynamic[RadioButton[
        Dynamic[y], {"quotient stock prices 1 and 2", 
         list1[[All, 2, 4]]/list2[[All, 2, 4]]}]], 
      TextCell[" quotient stock prices 1 and 2", 
       Selectable -> False]}], xpart = Dynamic[Range[start, end]];
    ypart = Dynamic[y[[2]][[start ;; end]]];
    Dynamic[
     ListLinePlot[
      Partition[Riffle[Range[start, end], y[[2]][[start ;; end]]], 2],
       ImageSize -> 700]]}]]]

I hope this helps.

Regards,

Neil

POSTED BY: Neil Singer
Answer
17 days ago

Dear Neil, Thanks a lot for your quick reply, and for your nice words. Unfortunately, the problem has not been solved yet. The CDF derived from your code will also not allow a change of stock. Anyway, I don't quite understand in what respect the code you added/changed could improve things. The only change in behavior that I found is that with my original code after changing the name of stock 1 or stock 2 all radio buttons are turned off, and with your code sometimes they stay on. Even the annoying blue bar accross the next text field that is shown after changing the name of one of the two stocks remained with your code.

It might be good for the sake of clarity to give you here the concepts behind my code: 1. Using FinancialData I fetch for all dates between Januari 1 2016 and yesterday the price data of two chosen stocks and put them in list1 and list2. 2. From list1 I get a list of all the dates and put them in listt. Using this I make the interval slider, and using this I define start and end. 3. With any of the radiobuttons I derive from list1 and/or list2 an appropiate list y. In the very basic example that I sent you only price 1 price 2 and price 1 / price 2 are shown, but I have developed some other possible lists. 4. Using start and end I derive from list y the partial list ypart, and also a list xpart. 5. After riffling xpart and ypart and partitioning the result I make the final plot. 6. In the plot I also show a whole lot of additional lines. I did not show these in my basic example. Their definitions depend on xpart, ypart, start and end. But it all works well. The only problem I am left wth is that in the CDF the Input fields of of the stock names refuse to work. But this is also the case with the code you suggested. I hope this explanation is clear enough.

As I wrote you yesterday I still feel myself a nitwit as to the use of Mathematica. It is therefore that I am looking for a real good systematic book on it. I have studied "The elementary introduction to the Wolfram Language". It is certainly useful, but it is not enough for me. For instance, I still don't understand completely the reasoning behind the code that you suggested. And also Dynamic remains sometimes an enigma for me. I thought maybe the Mathematica Cookbook might be useful, but I have read that it is kind of outdated by now. Is there anything else you can recommend?

To be more specific, I give you here a few examples of questions about your code proposals that I am stuck with: a. Why does the following combination work

listfun1 [a_,b_] := list1 = FinancialData [a,"OHLCV",{2016,1,1}];
listfun1[p1,p1];
listfun1 [c_,d_] := list2 = FinancialData [c,"OHLCV",{2016,1,1}];
listfun2[p2,p2];

and not

listfun1[a_] := list1 = FinancialData [a,"OHLCV",{2016,1,1}];
listfun1[p1]; 
listfun2[b_] := list2 = FinancialData [b,"OHLCV",{2016,1,1}];
listfun2[p2];

b. How should I interpret the following code of yours:

listfun1[a_]:= Module[ {} , list1 = FinancialData[a,"OHLCV",{2016,1,1}];
listt = list1[[All,1]];
y[[2]] = Switch[y[[1]],
" price of stock 1 ",list1[[All,2,4]],
" price of stock 2",list2[[All,2,4]],
"quotient stock prices 1 and 2",list1[[All,2,4]]/list2[[All,2,4]]];
start = Round[Length[listt]*0.25];
end = Round[Length[listt]*0.75]] ; 

What is for instance the purpose of the empty list in the begin of the module, and why do you need the Switch together with the radiobuttons? You may conclude that I hate to use code that I don't really understand.

I realize that I may bother you too much with my questions. I am sorry, but maybe you can help me to become a bit more proficient in writing Mathematica code. Anyway, thanks a lot for all the help you gave me sofar. Best regards, Laurens

POSTED BY: Updating Name
Answer
17 days ago

Laurens,

I can't help you with CDF reader -- I've never used it. I would talk to Wolfram Tech support and ask why it does not work in CDF but works in WMA. From the documentation it does say that CDF has some limitations -- maybe entering data is one of them??

Maybe CloudDeployment or some other approach is better? I really do not know but they should be able to help you with this. Or a Wolfram employee on this forum?

As to the posted code -- I suggest we have a call to discuss the details -- email me at "neils" at the domain in my profile and we can discuss the code.

Regards

POSTED BY: Neil Singer
Answer
16 days ago

Group Abstract Group Abstract