3
$\begingroup$

I saw a number of related questions to the one I'm about to post; they helped, but none of them solved my problem entirely.

Get the name of a symbol passed to a function

Obtaining the name of a variable as a string

The general question is how to get the name of something (a function, a list...). From the previous questions, I learned that you could use a function with the HoldFirst attribute:

SetAttributes[f, HoldFirst]
f[x_] := SymbolName[Unevaluated@x]

This function works well when it's input is directly the element of which you want to get the name. However, in my case, I have to use Table[] and I want to get the name of multiple time series. For example, I have three time series, ts1, ts2 ts3. I then want to produce two list plots, both with ts1 on the x axis and then respectively one that has ts2 on the y axis and another that has ts3 on the y axis. Here is the code I used:

Table[ 

ListPlot[ Transpose[{ts1["Values"],i["Values"]}]
,Frame->True
,FrameLabel->{"ts1",i}
]

 ,{i,{ts2,ts3}} ]

But the y axis labels, on both plots, are the time series objects, not their names. If I use the function f[_x] that I linked above, I get:

Table[ 

ListPlot[ Transpose[{ts1["Values"],i["Values"]}]
,Frame->True
,FrameLabel->{"ts1",f[i]}
]

 ,{i,{ts2,ts3}} ]

Then the y axis label is just "i"... So what I need is a function that evaluates i "just enough" (forget the imprecise formulation) so that it is replaced by, let's say, ts2, but then holds the form and convert it to a symbol. I do not know how to do that.

Here are three time series if you want to try and mess around with them:

ts1={{3686428800,2},{3686515200,2},{3686601600,1},{3686688000,1.4},{3686774400,1.9},{3686860800,1.8},{3687033600,1.7},{3687120000,1.5},{3687206400,2},{3687379200,2},{3687465600,2},{3687552000,2.2},{3687638400,1.7},{3687724800,1.7},{3687897600,1.7},{3687984000,1.7},{3688243200,2},{3688329600,2},{3688502400,1.7},{3688588800,2.3},{3688675200,1.7},{3688761600,1.7},{3688848000,1.7},{3689020800,1.7},{3689107200,2},{3689193600,1.7},{3689366400,2.4},{3689452800,1.7},{3689539200,0.5},{3689625600,2},{3689712000,1.7},{3689798400,1.7},{3689884800,1.7},{3689971200,1.7},{3690057600,2.1},{3690144000,1.7},{3690230400,2.1},{3690316800,3.4}}

ts2={{3686428800,7.7},{3686515200,12.3},{3686601600,9.5},{3686688000,3.7},{3686774400,5.7},{3686860800,5.1},{3687033600,8.3},{3687120000,8.3},{3687206400,6.1},{3687379200,4.3},{3687465600,5.9},{3687552000,5.8},{3687638400,7.5},{3687724800,3.9},{3687897600,5.9},{3687984000,7.6},{3688243200,8.6},{3688329600,4},{3688502400,6.1},{3688588800,5},{3688675200,10},{3688761600,10.6},{3688848000,7.5},{3689020800,7.2},{3689107200,11.3},{3689193600,10.3},{3689366400,9.2},{3689452800,10.2},{3689539200,8},{3689625600,8.3},{3689712000,7.3},{3689798400,7.7},{3689884800,7.9},{3689971200,7.3},{3690057600,9.3},{3690144000,11.9},{3690230400,13},{3690316800,9.8}}

ts3={{3686428800,0.364583},{3686515200,0.395833},{3686601600,0.604167},{3686688000,0.479167},{3686774400,0.458333},{3686860800,0.416667},{3687033600,0.375},{3687120000,0.416667},{3687206400,0.416667},{3687379200,0.40625},{3687465600,0.385417},{3687552000,0.395833},{3687638400,0.375},{3687724800,0.395833},{3687897600,0.416667},{3687984000,0.364583},{3688243200,0.375},{3688329600,0.333333},{3688502400,0.385417},{3688588800,0.375},{3688675200,0.375},{3688761600,0.354167},{3688848000,0.395833},{3689020800,0.416667},{3689107200,0.416667},{3689193600,0.375},{3689366400,0.458333},{3689452800,0.395833},{3689539200,0.395833},{3689625600,0.395833},{3689712000,0.364583},{3689798400,0.385417},{3689884800,0.375},{3689971200,0.354167},{3690057600,0.385417},{3690144000,0.375},{3690230400,0.520833},{3690316800,0.375}}
$\endgroup$
1

1 Answer 1

4
$\begingroup$

Proposed alternatives

This is a matter of controlling evaluation. You can do this with varying degrees of difficulty using things like HoldFirst, Unevaluated, etc., or you can simply avoid the problem in the first place which is what I greatly prefer.

To do this you can separate the names from the data using indexed objects, Rules, or Associations. Instead of defining ts1 = TimeSeries[. . .] you would write one of the following:

ts[1] = TimeSeries[. . .]

data["ts1"] = TimeSeries[. . .]

ts1[] = TimeSeries[. . .]

rules = {"ts1" -> TimeSeries[. . .], "ts2" -> TimeSeries[. . .]}

asc = <|"ts1" -> TimeSeries[. . .], "ts2" -> TimeSeries[. . .]|>

In each case you can freely pass around a reference (name) for the TimeSeries expression without it automatically evaluating to anything.

You would reference each of these in the respective manner:

Table[Labeled[ts[i], Row[{"ts", i}]], {i, 1, 3}]

Table[Labeled[data[name], name], {name, {"ts1", "ts2", "ts3"}}]

Table[Labeled[ts[], ts], {ts, {ts1, ts2, ts3}}]

Table[Labeled[name /. rules, name], {name, {"ts1", "ts2", "ts3"}}]

Table[Labeled[asc[name], name], {name, {"ts1", "ts2", "ts3"}}]

Self-contained examples

Let me see if I can provide a concrete example using your data.

t = {3686428800, 3686515200, 3686601600, 3686688000, 3686774400, 3686860800, \
3687033600, 3687120000, 3687206400, 3687379200, 3687465600, 3687552000, 3687638400, \
3687724800, 3687897600, 3687984000, 3688243200, 3688329600, 3688502400, 3688588800, \
3688675200, 3688761600, 3688848000, 3689020800, 3689107200, 3689193600, 3689366400, \
3689452800, 3689539200, 3689625600, 3689712000, 3689798400, 3689884800, 3689971200, \
3690057600, 3690144000, 3690230400, 3690316800};

valeurs = {{2,2,1,1.4,1.9,1.8,1.7,1.5,2,2,2,2.2,1.7,1.7,1.7,1.7,2,2,1.7,2.3,1.7,1.7,1.7,1.7,2,1.7,2.4,1.7,0.5,2,1.7,1.7,1.7,1.7,2.1,1.7,2.1,3.4},
{7.7,12.3,9.5,3.7,5.7,5.1,8.3,8.3,6.1,4.3,5.9,5.8,7.5,3.9,5.9,7.6,8.6,4,6.1,5,10,10.6,7.5,7.2,11.3,10.3,9.2,10.2,8,8.3,7.3,7.7,7.9,7.3,9.3,11.9,13,9.8},
{0.364583,0.395833,0.604167,0.479167,0.458333,0.416667,0.375,0.416667,0.416667,0.40625,0.385417,0.395833,0.375,0.395833,0.416667,0.364583,0.375,0.333333,0.385417,0.375,0.375,0.354167,0.395833,0.416667,0.416667,0.375,0.458333,0.395833,0.395833,0.395833,0.364583,0.385417,0.375,0.354167,0.385417,0.375,0.520833,0.375}};

nomsVariables = {ts1, ts2, ts3};

Now:

MapThread[(#1[] = TimeSeries[#2, {t}]) &, {nomsVariables, valeurs}];

Access and labeling of various time series as an illusration:

Labeled[#[], #] & /@ nomsVariables

If nomsVariables is a list of Strings rather than Symbols I recommend that you use the second, fourth or fifth forms shown earlier so as to avoid the need to convert to Symbols:

nomsVariables = {"ts1", "ts2", "ts3"};

MapThread[(data[#1] = TimeSeries[#2, {t}]) &, {nomsVariables, valeurs}]

Labeled[data[#], #] & /@ nomsVariables

The question at face value

To leave no stone unturned I should address the actual question as asked rather than only proposing an alternative. You can HoldForm the individual Symbols in the Table and then ReleaseHold that expression when you need it to resolve to the TimeSeries:

Table[ListPlot[Transpose[{ts1["Values"], ReleaseHold[i]["Values"]}], Frame -> True, 
  FrameLabel -> {"ts1", i}], {i, {HoldForm[ts2], HoldForm[ts3]}}]

This works for the example given but it introduces other question like how to create the list {HoldForm[ts2], HoldForm[ts3]} apart from typing it in. Typically you would start with an expression of held Symbols before they (ts2, ts3, etc.) are assigned values. Another question exists that addresses the use of this form to some degree: Elegant manipulation of the variables list Nevertheless IMHO this should not be used commonly but rather as a special purpose tool.

$\endgroup$
8
  • $\begingroup$ Thank you for your answer. I'm trying out what you proposed by using the indexed objects ts1[]. It is indeed much simpler than messing around with the evaluation. However, I do have another question related to these indexed objects. As I dont have 3, but around 50 times series to define, I'm trying to define them as a bunch, but I get the error message Set::write: Tag Map in (#1[]&)/@{liquide,travail} is Protected.. Here is what I tried: Map[#[] &, Symbol /@ nomsVariables[[;; 2]]] = Map[TimeSeries[#, {t}] &, valeurs[[;; 2]], {1}]. $\endgroup$
    – E Bassal
    Commented Dec 12, 2016 at 19:42
  • $\begingroup$ Where nomsVariables contains the names of all the variables, t contains the different dates and where valeurs contains the different variables (one sublist per variable). $\endgroup$
    – E Bassal
    Commented Dec 12, 2016 at 19:43
  • $\begingroup$ Never mind, I just added an Evaluate...: Evaluate[Map[#[] &, Symbol /@ nomsVariables[[;; 2]]]] = Map[TimeSeries[#, {t}] &, valeurs[[;; 2]], {1}]. $\endgroup$
    – E Bassal
    Commented Dec 12, 2016 at 19:55
  • $\begingroup$ @EBassal give me a minute; I am looking at your example. If you've found a solution in the mean time that's fine. $\endgroup$
    – Mr.Wizard
    Commented Dec 12, 2016 at 19:55
  • 1
    $\begingroup$ @EBassal Please see my update. I hope you find the examples useful, but if not it seems you found what you need. Thanks for the Accept. $\endgroup$
    – Mr.Wizard
    Commented Dec 12, 2016 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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