How can I get the name of a MATLAB variable as a string?

I would like to convert the name of my MATLAB variable to a string so that, for example, I can plot a variable and then use the name of the variable as a title for the plot. Is there a way to do this without having to store the name of the variable along with the data?

 採用された回答

MathWorks Support Team
MathWorks Support Team 2018 年 1 月 29 日

18 投票

There is no direct way to get the name of a variable as a string, but there is a function called "inputname" that will return the name of a variable that was input into a function:
Using this, you can create a short function that, given a variable, will output the name of it as a string, as in the following example:
 
function out = getVarName(var)
out = inputname(1);
end
As long as the file is included on the MATLAB path, you can use the function in the following way:
 
>> x = 1:10; % example data
>> plot(x)
>> title(getVarName(x))
 

6 件のコメント

Walter Roberson
Walter Roberson 2018 年 2 月 13 日
This would be the same as title('x') so there would not be any obvious benefit to this.
inputname() can only be used when what is passed to the function is a plain variable with no indexing at all. It is not useful to call with respect to variables in the current workspace, in that in each case you would need the plain name of the variable to pass to the getVarName call, and if you know the plain name of the variable then you might as well just put it in '' instead of calling a function to do that.
inputname() is really only useful for knowing the name a variable of a parameter that was passed into the current routine. And it is not transitive: you cannot say
function test(x)
parents_name_for_x = getVarName(x)
to find out what name the caller used: you would have to use plain
function test(x)
parents_name_for_x = inputname(1)
broken_arrow
broken_arrow 2021 年 9 月 17 日
編集済み: MathWorks Support Team 2021 年 10 月 20 日
In my eyes, even if you know a variable by its plain name, the advantage of the inputname function over a conventional string is that with inputname you can keep track of variable name changes (which regularly happen during development) more easily. Taking the above example
>> title(getVarName(x)) "vs" title("x")
if you replace x by potato in your code (e. g. via the "auto rename" feature), the former will still give the correct title (since auto rename will include the (x) argument) and the latter will not (of course this is no problem as long as you remember there was that one line where you used the name as a string and replace it manually - which a perfect programmer will always do ;).
My main problem is that inputname currently does not work with structs (and thus also not with dynamic field names https://de.mathworks.com/help/matlab/matlab_prog/generate-field-names-from-variables.html ).I agree with Frieder there are situations (like debugging or plotting) where it is very handy to be able to access the variable name. In the workaround by Jan, you still have to introduce a separate name string (which is technically redundant to the field name).
@MathWorks Support Team: If you read this, would you consider expanding inputname to also work with structs (including dynamic field names)? This would be heplful. Thank you.
Walter Roberson
Walter Roberson 2021 年 9 月 18 日
Good point about the refactoring.
would you consider expanding inputname to also work with structs
My model of what is happening is that MATLAB has two slightly different varieties of values being passed around:
  1. Names that resolve to a simple unindexed variable; in this case, the variable name can be determined by input number with inputname(). And such variables are eligible for in-place operations if the reference count is right.
  2. Everything else is a computed location. All the same information is passed along except the variable name. If I understand correctly, such values are not eligible for in-place operations even if the could potentially have been interpreted as what computer science calls an "lvalue".
If my model is correct, then when you reference a field from a struct, whether statically or dynamically, you fall into case 2, where the value is passed in anonymously (and, I think is not eligible for in-place operations.)
(In computing, an "lvalue" is an expression that designates a location that can be written into. Basically any simple variable and any indexed variable, whether indexed by field or () or {} indexing, or chains of such indexing; in C and similar languages, it includes pointer operations.)
Remembering that the syntax
abc.defg
is an abbreviation for
abc(1,1).defg
then it is not immediately obvious that it would be justifiable to attach a name to abc.defg but not to abc(1).defg .And that implies that arguably as well as just the resolved field name, you need the entire list of struct indices to be available -- so, for example, the name received by inputname() might be abc(4,17,11).defg . Is that reasonable?
Or perhaps the 1-trimmed version of the indexing, so abc(4,17,1,1) would be trimmed to abc(4,17) but abc(4,17,1,2) would get the full abc(4,17,1,2) ? If so, then should abc(1).defg be trimmed to abc.defg ? The answer to that in general has to be "no", because if abc is a non-scalar struct then abc(1).defg refers to only a single entry but abc.defg is structure-expansion. the first of which is implicitly abc(1,1).defg . But for scalar struct then trimming is potentially possible... but then you have to keep in mind that there are techniques for assigning into the struct after it is passed in, so if you just go by the fact of it being scalar at the time it was passed in, then you would be generating a potentially misleading inputname()
So... a question becomes what you are going to do with these names ?
I think it is a useful feature for functions to be able to tell the user more clearly which parameter has a problem. For example, it is useful to have a function be able to report, "parameter 7, 'z', must be a real uint8 non-scalar vector" where the 'z' here refers to what the user passed in rather than to the function's internal name for the variable.
And if the user passed in (say) double(z) ? It might be incorrect to tell that user that z must be (etc) as z might already be that, but that the operation being performed on z might have a result that is no longer qualifying. So the ideal message would contain "double(z)" . Or contain eig(V'*X*V) as the text if that is passed in.
Similarily, if the reason to want the name is for user reference, then if a dynamic field name is being used, then does it make sense to give the resolved field name, or does it make sense to give the text equivalent of what was being passed? Should the user see abc.defg or should the user see abc.(field7) as the inputname? Or, more likely, abc.(fieldnames{7}) ?
Thus, I would suggest that if Mathworks were to enhance inputname(), that it should do so in the direction of providing the text of the argument that was passed in that position. I have no idea how difficult this would be for Mathworks to do.
I think there would be other uses for having that text, such as greatly enhancing the dreaded "index 2 is out of range" that does not give you any information about which of the several indexing operations is being referred to.
broken_arrow
broken_arrow 2021 年 9 月 18 日
編集済み: broken_arrow 2021 年 9 月 18 日
Alas I'm not familiar with the way Matlab handles variables internally ;) But I do agree that improving inputname to be able to return a string containing the plain text of any given function input expression would be "fair enough" (evaluation of dynamic field name expressions can be done with a separate input argument to the respective function if necessary). Let's see if we get a response from @MathWorks Support Team here. If not, I'll file a feature request.
Walter Roberson
Walter Roberson 2021 年 9 月 18 日
Perhaps a new function, something like
inputexpression(3)
and maybe something like
inputlocation(5)
except I am not really happy with the function name inputlocation . inputreference() maybe ??
Semantics:
inputreference() applied to an input that was a name and a chain of indexing expressions, would result in the name and the sequence of fieldnames and numeric indices needed to get to the endpoint... assuming that nothing in the chain had been modified since the call.
Now... suppose you have
struct('abc', def(7)).abc(3)
passed as a parameter. Then the result is a field name, and so you would like to be able to get the field reference. But it is not a variable that is being referenced, it is the result of a function call. This has been legal for a small number of releases. The result of any function call can have dot indexing applied to it. If you look at this hack, it is effectively calling def(7) and indexing at 3, which would be nice as def(7)(3) but that is not permitted syntax.. but you can use the intermediate struct to implement it !
So what should hypothetical inputreference() return in such a case? Empty because there is no ultimate name to index off of? Or something like "_anonymous.abc(3)" ?
... I'm still not sure what the use case would be for returning this information? What would you do with it?
If the idea is that you would like to be able to find out the "address" of an input and examine what is there... then remember that it is legal to use assignin() to modify things in the calling workspace.
assignin('caller', 'abc' [struct('def', []); VariableThatReceivedParameter])
and now the information that VariableThatReceivedParameter came from abc(1).def is out of date, and the value you are looking at now lives at abc(2).def -- which is an operation that did not require changing the memory location or reference count of what used to be at abc(1).def because each field of each structure array member has its own independent reference count and memory address...
If the question is "what was the chain of references that got to this location"? then that chain might no longer refer to the same thing. If you ask "What chain of references would you use at the moment to reach this location"? then the answer might be that it has been unlinked from the variable already...
So, again, what would you do with the information?
Walter Roberson
Walter Roberson 2021 年 9 月 18 日
For example, would it perhaps make sense to instead implement a more general call, something like parent(), that returned a list of all the places that had a reference to this memory address?
abc = [1 5 9]
parent(abc(2)) --> probably "abc"
def.ghi.jkl = [2 4 6]
m = def.ghi;
parent(def.ghi.jkl(3)) --> probably ["def.ghi.jkl", "m.jkl"] %all places!
function myfun(X)
parent(X(1))
end
myfun(def.ghi.jkl) --> ["X"] at least -- but maybe also "caller::def.ghi.jkl" ?
or if the caller is a named function then should "caller" be replaced with the function name? And if it is a subfunction then should > chaining be used? "MyProgram>localfun1>subfun>def.ghi.jkl" ?

サインインしてコメントする。

その他の回答 (2 件)

Jan
Jan 2018 年 2 月 13 日

8 投票

Try to avoid this whenever it is possible. The names of the variables should not carry important information. If names really matter, store them explicitly in the data, e.g. as struct:
Data(1).name = 'Level 1';
Data(1).value = 4711;
Data(2).name = 'Level 2';
Data(2).value = 31415;
Now you can access the name of the data, but are not restricted to specific names for the data. You can even create a temporary object:
yourFunction(struct('name', 'hello', 'value', 15))
With inputname this would fail, because the temporary object does not have a name of the variable.
Frieder Wittmann
Frieder Wittmann 2019 年 3 月 15 日
編集済み: Frieder Wittmann 2019 年 3 月 15 日

7 投票

@OP: I also think this would be very useful. For other programs like R it is standard to use the variable name for the title and xlabel, unless of course it is defined explicitly.
It might be bad practice for production code, but for quick data exploration and sharing it would be VERY useful to have a function like
function h = quickPlot(x,y)
xLabelName = inputname(1)
ylabelName =inputname(2)
figure()
plot(x,y)
xlabel(xLabelName)
title(ylabelName)
ylim(1.1 * [min(y),max(y)])
end
This works for
xx = 1:10
yy = 1:10
quickPlot(xx,yy)
but not for structs, e.g.
s.xx = 1:10
s.yy = 1:10
quickPlot(s.xx,s.yy)

カテゴリ

ヘルプ センター および File ExchangeProgramming についてさらに検索

製品

リリース

R2017b

タグ

タグが未入力です。

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by