Using Dynamic as a pattern to retrieve a Position from a list?

I have a manually entered table of model numbers and their associated parameters. I want to be able to select a model number using a PopupMenu and then retrieve the parameters associated with that model number for further processing. If I use one of the model numbers directly, it returns the position correctly, but if I use the Dynamic that returns that same model number I just get empty curly brackets?

If you want to retrieve the parameters, you’ll have to “dig in” to the structure of data. That would be easier if you used an Association, so maybe start by structuring your data like this:

keyedData = Association[First@# -> Rest@# & /@ data]

Keep your popup as it is:

PopupMenu[Dynamic[model], modelNumbers]

Now, wherever you want to see the parameters associated with the selected model number, put this expression there:

Dynamic[keyedData[model]]

Cool, Eric, thank you! Elegant approach. Learned even more!
But this assuming a table data format structure?, or can this be used for formats?

I don’t understand the question.

Thank you Eric! Solved my problem, but I must admit that I now have a headache trying to understand all those cryptic symbols in the Association and will need to do some homework! I also still do not understand how the data is structured without invoking that Association and why Dynamic[model] does not match the entries for the model numbers in the table?

BOOKMARK

First off, here’s a lesson: Mathematica has often already thought of what you want to do, and so checking the documentation before you get too far into your own implementation is a good idea. I dug into PopupMenu a bit, and what I implemented above is actually built-in functionality.

We still need structured data, but we don’t even need an Association:

keyedData = (Rest@# -> First@#) & /@ data

Now create your popup like this:

PopupMenu[Dynamic[model], keyedData, data[[1, 1]]]

You can skip the third argument if you want; it’s just a default.

Now, wherever you evaluate this:

Dynamic[model]

you’ll get the parameters (the elements of the row after the model number that was selected). If you look at the documentation for PopupMenu, check out the third and fourth variants.

Sorry for the cryptic notation. I can walk you through it a bit. First, I looked at your data, which is just a list of lists. You indicated that there is a bit of implicit structure: the first element of each “row” is a model number (i.e. some sort of key) and the other elements are parameters (i.e. just data associated to the model number).

{{4154, 0.4, 0.5, 0.01, 0.65}, {4144, 0.3, 0.6, 0.11, 0.54}, {4146, 0.2, 0.7, 0.21, 0.63}, {4147, 0.1, 0.8, 0.31, 0.62}, {4148, 0.11, 0.9, 0.41, 0.61}}

An Association is just a list of key-value pairs (similar to but much more flexible than hash maps or dictionaries in other languages). The representation of a single key-value pair uses a structure called a Rule. You can create a Rule like this: Rule[x,y], but there is a nice shortcut: x->y. Associations are basically just a list of such Rules. So, what I wanted (in my original implementation) is a list that looks like this:

{4154 -> {0.4, 0.5, 0.01, 0.65}, 4144 -> {0.3, 0.6, 0.11, 0.54}, 4146 -> {0.2, 0.7, 0.21, 0.63}, 4147 -> {0.1, 0.8, 0.31, 0.62}, 4148 -> {0.11, 0.9, 0.41, 0.61}}

Then I just wrapped it up in an Association,

modelNumberData=Association[...the list goes here...]

which gives

<|4154 -> {0.4, 0.5, 0.01, 0.65}, 4144 -> {0.3, 0.6, 0.11, 0.54}, 4146 -> {0.2, 0.7, 0.21, 0.63}, 4147 -> {0.1, 0.8, 0.31, 0.62}, 4148 -> {0.11, 0.9, 0.41, 0.61}|>

and bingo, we can access stuff with a key, like this:

modelNumberData[4154]

which gives

{0.4, 0.5, 0.01, 0.65}

The <| and |> are just shorthand for Association.

But I don’t want to type in the list (“…the list goes here…” bit) by hand. What I want is to split each “row” into a pair whose first element is the first of the pair and whose “tail” is a list that will be the second element of the pair. And by “pair”, I really mean Rule. Mathematica has the functions that I need built in: First and Rest. So, for each row, I want:

Rule[First[row],Rest[row]]

Mathematica also has a function called Map that applies a given function to every element of a list. Well, each row of your data is an element of a list, so if I can just turn that Rule expression into a function, I can Map it over your data. Well, Mathematica has many ways to specify a function, and one is Function (I know, such crazy names, eh?). You can use Function with named arguments, or with positional arguments (look up Slot in the documentation), and I chose positional arguments. Well, I only need one argument, so the positional aspect isn’t really apparent, but anyway, it looks like this:

Function[Rule[First[#], Rest[#]]]

Putting this all together, I was able to restructure your data by evaluating this:

Map[Function[Rule[First[#], Rest[#]]], data]

Hmm. That doesn’t look like what I originally posted. Well, there are nice shortcuts and syntactic sugar that shorten things. The arrow, -> is infix notation for Rule, so a->b is the same as Rule[a,b]. So, we can simplify our Function: Function[First@# -> Rest@#]. The ampersand is postfix notation for Function, so we can reduce further: (First@# -> Rest@#) &. The parentheses aren’t necessary, but they can sometimes help you keep track of things. Finally, Map also has an infix notation: /@, and so we finally arrive at (First@# -> Rest@#) & /@ data.

As for your other questions:

I also still do not understand how the data is structured without invoking that Association and why Dynamic[model] does not match the entries for the model numbers in the table

I’m actually not sure what you’re asking. Dynamic can be confusing. It basically sets up a particular part of an output to be automatially updated. The output of Dynamic[model] will just look like whatever the current value of model is, but it’ll be a special thing such that if model’s value changes, that part of your notebook will automatically change to reflect the new value. But to your question, Dynamic[model] does match the entries in your table. Or at least it seems that way to me, so I must be misunderstanding your question.

As for not understanding “how the data is structured”, I again must be just not understanding what you’re getting at. Do you mean “how” as in “the process for creating the data”? If so, well, that’s what the code I wrote does, so you’ll need to try to understand that code. Or do you mean “how the data is structured” as in “what is the structure of the data”? You can just look at it and inspect it. This seems obvious, so I guess I just don’t know what you’re asking.

Thank you for walking me through all of that, Eric, still so much to learn and absorb. The actual table I am using is a bit larger and was copied from a paper. I used the menu Insert → Table/Matrix → New… to create the empty table of the proper size and then manually entered the data from the paper. I do now appreciate and understand the utility of using an Association, but from the documentation I thought I would need to re-enter all of the data again to create that. Now I see how it can simply be done after the fact and quite “simply”. The bit I still do not understand is why, if I use Dynamic[model] as the pattern to search for in Position the output is { }, but if I use that actual current value of Dynamic[model], e.g., 4147 I get the output {{4}}. Why the difference? It’s not critical given your elegant solution, but I’m curious to understand.

test 2.nb (8.95 KB)

Hmm. I think you must be referring to code that you haven’t posted here. The code you posted has no usage of Position. You might be getting {} for Position because when you run your code fresh there is no value assigned to model yet. But that’s just speculation. I’d need to see the code your talking about.

Oh, sorry, I didn’t see the attachment. Let me look.

Okay, I think you’re referring to this:

modelPosition = Position[modelNumbers, Dynamic[model]]

I don’t think that I yet fully grok how Dynamic works in every situation, but here’s what I think is happening. The subexpression that Position is searching for is Dynamic[model]. Now, Dynamic[model] is it’s own expression, it doesn’t evaluate to the value of model. It displays the current value of model, but it doesn’t “simplify” to just model.

Position[{a, b, c}, Dynamic[a]] (*gives {}*)
Position[{Dynamic[a], b, c}, Dynamic[a]] (*gives {{1}}*)

You get the above results regardless of whether a has been assigned a value yet.

Here are two alternatives:

modelPosition = Dynamic[Position[modelNumbers, model]]
(*This sets up modelPosition to be a Dynamic expression.*)

Dynamic[modelPosition = Position[modelNumbers, model]]
(*This sets up a Dynamic expression, and the update that happens
is that the variable modelPosition gets reset depending on the new value of model.*)

Visually, you won’t be able to distinguish the two, but if you evaluate one and then look at FullForm[modelPosition] and then evaluate the other and look at FullForm[modelPosition] again, you can see the difference.

“…It displays the current value of model, but it doesn’t “simplify” to just model…” explains it sufficiently for me. Thanks once again for all the hand holding on this!

Hi Eric -

I’m still struggling with this. Your last suggestion for obtaining a Dynamic modelPosition yields the correct number, but it is inside two sets of curly brackets {{ }}, which “cannot be used as a part specification”. Also, I don’t see any difference between modelPosition = Dynamic[Position[modelNumbers, model]] and Dynamic[modelPosition = Position[modelNumbers, model]] using FullForm as you suggest? How do I “extract” that number between the curly brackets to use as a rowIndex so I can get the values of the coefficients I need for further calculation from the model I have selected as in the example where I have explicitly entered row 3? This seems like it should be so simple. Thanks again!

Test program.nb (6.14 KB)

How do I … get the values of the coefficients I need for further calculation from the model I have selected

I answered this above. I went back and added BOOKMARK to the post that answers this. Just do a text search of “bookmark” on this page to find it.

How do I “extract” that number between the curly brackets to use as a rowIndex…

Well, it’s funny you used the work “extract”. Mathematica has a function Extract that works in conjunction with Position. You don’t need this, however, if you just go find my previous answer. But for future use, you should definitely go read the documentation on Extract.

I don’t see any difference between modelPosition = Dynamic[Position[modelNumbers, model]] and Dynamic[modelPosition = Position[modelNumbers, model]] using FullForm

Okay, because of the order in which you’re doing things in your notebook, it might not be obvious. But here’s a simple notebook to illustrate the difference between the two ways of doing it. I don’t know how this is going to end up displaying on this webpage–you should experiment withing Mathematica itself.

Eric - I believe I have followed your instructions but still end up with the same problem of the correct dynamic position being enclosed in {{ }}, and I cannot extract just the enclosed number to use further. I have added comments to the attached program that I think explains what I have done at each step following your instructions. I’m sorry to bother you once more but I keep getting stuck here. Would you be kind enough to insert the magic steps at the end to make this finally work? Many thanks again!

Test program.nb (36.8 KB)

In your notebook, you have this:

keyedData = (First@# -> Rest@#) & /@ data

I suggested (find my BOOKMARK) this:

keyedData = (Rest@# -> First@#) & /@ data

This difference is necessary because it allows us to take advantage of some nice behavior in PopupMenu.

In your notebook you have this:

PopupMenu[Dynamic[model], modelNumbers]

That doesn’t use the keyedData at all, which was the whole point of creating keyedData. I suggested this:

PopupMenu[Dynamic[model], keyedData, data[[1, 1]]]

Looking at it now, I’d probably rename “model” to something more descriptive, but whatever.

Once you’ve made these changes (and evaluated them), you can use this:

Dynamic[model]

to see the value of the paramters for the key selected by your PopupMenu.

Thanks again, Eric. In your very first reply you had used:

keyedData = Association[First@# -> Rest@# & /@ data] 

but when you started explaining this in more detail following BOOKMARK you started with an “inverted” and simplified form:

keyedData = (Rest@# -> First@#) & /@ data

The further details, however, all showed the model numbers as keys and you ended that reply with “…so we finally arrive at (First@# → Rest@#) & /@ data.” I was confused as to which to use. I did goof with the PopupMenu when I left out the keyedData. The new version attached now works as you indicated and produces the appropriate list of values as output, but now I can’t figure out how to get each of those values assigned to the individual coefficients? I hope this will be the last time I will pester you and greatly appreciate all your patience.

Test program.nb (5.4 KB)

I’m sorry, but I don’t understand your question. Can you post the desired output?

Okay, I re-opened one of your earlier notebooks, and I see a bunch of coef1= assignments, so that must be what you’re referring to. But I still don’t understand what you’re actually after. Each of those assignments overrides the previous one. And I suspect that there is some subsequent step that you’re going to want to take once you have your coefficients. So, if you can just jump to the “punchline” and tell me where this is going, there may be a much better way to get there. Like, maybe the coefficients need to be the dynamic bit. Or maybe we can just create a static structure and index into it with helper functions. Or maybe there is a different question here altogether that deserves a separate post. As I see it, we’ve “solved” your original question about how to dynamically extract the pararmaters from a row of data.