I have a GUI handle list_h that is populated using a variable named tracks which is a [1xN] cell array. Since, each string within the list_h is assigned a value from 1:N I have been able to devise a for loop that can check which item has been selected from list_h, which works fine.
I was hoping I could extend upon this and be able to select an item from my list_h and be able to extract the string using the String property within list_h, but I am getting an error:
Undefined function 'eq' for input arguments of type 'cell'.
Error in guiPlay (line 13)
if i == list_value
Error while evaluating uicontrol Callback
I was also hoping I could get the full path to each item in list_h, since each item is a reference to an actual .wav file located on my hard drive? I figured this would be a case of concatenating the each item with its corresponding path if this is possible?
Here is the callback function that attempts to extract each list item's string:
function guiPlay(play_toggle_h, evt, list_h)
global predict_valence
button_value = get(play_toggle_h, 'Value');
list_value = set(list_h, 'Value');
N = length(predict_valence);
if button_value == 1
set(play_toggle_h, 'String', 'Pause');
for i=1:N
if i == list_value
track = get(list_h, 'String');
disp(track)
end
end
elseif button_value == 0
set(play_toggle_h, 'String', 'Play');
end
Just for debugging I have used the disp function to display the item.
Related
I have an object called TestData() that handles data processing and places it in a file in a specified format. One of the properties is data, which is stored as an array of type double. Here is the object and its constructor:
classdef TestData
properties
metaData = []; % stores meta data in Nx2 array
data = []; % stores data in PxQ array
colLabels = []; % labels columns
colUnits = []; % provides units
metaPrint % used to print metaData
temp % debugging purposes only
end
methods
%****************************************************************************%
%Function: TestData
%Purpose: Constructor used to allocate data arrays
%****************************************************************************%
function this = TestData() %constructor
this.metaPrint = [];
this.temp = [];
end %TestData()
The data that is placed into the object comes from a .m file external to the object, like so:
myTestData=TestData; % Generate an instance of the object
% Data
ErrorLine1 = zeros([length(ErrorLine')+2 1]); % Empty Vector to store 11X1
ErrorLine data
ErrorLine1(2:end-1) = ErrorLine(1:end);
mat = [Avec' Bvec' Invec' Ovec' ErrorLine1 PercentErrorOD'];
myTestData.data = mat;
So, when I set myTestData.data = mat this places the data in the object, but then calls the getter and setter functions for that object. One of the principle reasons for using these functions is to filter the data and determine if it is the correct type of data (in this case, the format would need to be double). When I try this in the code, however, it doesn't seem to work. Here is what I have written for the getter:
function data = get.data(this)
data = this.data;
end %getData
And the setter:
function this = set.data(this, data)
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data)); %#ok<STISA>
disp(i)
if any(i == 0)
disp("WE HAVE A ZERO")
msg = "Data in object's 'data' property is not of type double";
error(msg);
else
this.data = data;
disp('Hi from setter')
end
end % set.data
If I run the strcmp and any functionality through the command window it works! When I run it from the editor, though, it always displays the "Hi from setter" string, even if I change "double" in the compare to "string." So, I am just not sure why it is not entering the if statement.
If there is anything that you can see in my code that could be modified to make it more efficient please let me know. Also, if there is anything else I can do my best. Thanks in advance!
In your setter, you have this line:
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data));
But note that here you have not yet done this.data = data. When you test this.data, you test the old value of the property, not the value you want to assign. You need to test data.
Instead of using strcmp on the result of class, you can better test with isa. Furthermore, unless data is a cell array or a struct array, each of the elements will always be of the same class. You don't need to iterate over the whole array to test its type, just look at the type of the array itself. In the case of the cell array and the struct array, the indexing has to be different to extract elements. So, data(n) will always have the same type as data. Thus your setter can be written as:
function this = set.data(this, data)
if ~isa(data,'double')
error('WRONG!')
end
this.data = data;
end
Another issue with the code: if any(i == 0). any collapses one dimension of the input array. So if i is a 2D matrix, then the output is a row vector. Each element will be true if any of the elements in the given column is true. The if statement is only true if all elements of the given expression are nonzero. That means that all columns must have at least one 0 value for this expression to trigger.
Instead, do if any(i(:)==0). Here we make i into a column vector (this doesn't copy data, it's efficient), and thus any will return a single (scalar) value. If you have MATLAB R2018b, then you also do if any(i,'all'), which is equivalent.
You'll often see code doing if any(any(i==0)), but this fails if i happens to have three or more dimensions. It is also inefficient, the forms above are better.
I wanted to ask how values in MATLAB are returned? Are they copied or passed by reference?
take a look at this example with matrix A:
function main
A = foo(10);
return;
end
function [resultMatrix] = foo(count)
resultMatrix = zeros(count, count);
return;
end
Does the copy operation take place when function returns matrix and assigns it to variable A ?
MATLAB uses a system known as copy-on-write in which a copy of the data is only made when it is necessary (i.e. when the data is modified). When returning a variable from a function, it is not modified between when it was created inside of the function and when it was stored in a different variable by the calling function. So in your case, you can think of the variable as being passed by reference. Once the data is modified, however, a copy will be made
You can check this behavior using format debug which will actually tell us the memory location of the data (detailed more in this post)
So if we modify your code slightly so that we print the memory location of each variable we can track when a copy is made
function main()
A = foo(10);
% Print the address of the variable A
fprintf('Address of A in calling function: %s\n', address(A));
% Modify A
B = A + 1;
% Print the address of the variable B
fprintf('Address of B in calling function: %s\n', address(B));
end
function result = foo(count)
result = zeros(count);
% Print the address of the variable inside of the function
fprintf('Address of result in foo: %s\n', address(result));
end
function loc = address(x)
% Store the current display format
fmt = get(0, 'format');
% Turn on debugging display and parse it
format debug
loc = regexp(evalc('disp(x)'), '(?<=pr\s*=\s*)[a-z0-9]*', 'match', 'once');
% Revert the display format to what it was
format(fmt);
end
And this yields the following (or similar) output
Address of result in foo: 7f96d9d591c0
Address of A in calling function: 7f96d9d591c0
Address of B in calling function: 7f96d9c74400
As a side-note, you don't need to explicitly use return in your case since the function will naturally return when it encounters the end. return is only necessary when you need to use it to alter the flow of your program and exit a function pre-maturely.
On MATLAB R2014b, when you have a struct (or custom class) having a field that is a scalar categorical, when displaying the struct it will show [1x1 categorical] instead of what I want to achieve as shown below.
MWE:
struct.field = categorical({'category'})
Output:
struct =
field: [1x1 categorical]
My desired output:
struct =
field: category
or:
struct =
field: category [1x1 categorical]
I want this, because I'm writing some classes that have a categorical property that is always scalar; because I know this by definition, I don't need the objects' category to be displayed as [1x1 categorical]. When displaying the custom objects, I'd like it to show the category instead.
I could overload disp in my class methods, but then I'd need to rewrite a lot of displaying code from disp itself instead of merely changing the way a scalar categorical in a struct field shows.
Any ideas on how to achieve this? If your answer involves overloading disp in the class definition, then I want to see how you could display the object's other properties like a normal disp(obj) would, in addition to displaying the categorical property the way I want. Any ideas or thoughts you have might help me write my own answer, so please share any.
After playing around with this for a while, I think I finally have something that works for displaying these scalar categorical values within a custom class.
The basic idea is that I overload the get method for the property that is holding the categorical. I can then check the call stack to see what is trying to get the value of the variable. If it's our overloaded disp method (which is called any time we want to display our class), then I return the category name if it's only a scalar categorical. Otherwise, I return the value of the property itself (as a categorical).
It's definitely not the most elegant due to it's reliance on dbstack but it seems to work quite well.
classdef categoryclass < handle
properties
a = categorical({'category'});
end
methods
% Get Method for "a" property
function res = get.a(self)
% Get the call stack to determine *what* called this
stack = dbstack();
methodname = sprintf('%s.disp', class(self));
% If it is a scalar and it was called by our overloaded display
% method, then return the category name
if isscalar(self.a) && isa(self.a, 'categorical') && ...
strcmp(methodname, stack(end).name)
res = categories(self.a);
res = res{1};
% Otherwise return just the value itself
else
res = self.a;
end
end
% This ensure that disp() shows up in the stack
function disp(self)
% Simply call the built-in display function
builtin('disp', self);
end
end
end
Now if we try this out.
cls = categoryclass()
categoryclass with properties:
a: 'category'
Check that when we request the value we actually get a categorical.
class(cls.a)
ans =
categorical
Now change the value of it.
cls.a = categorical({'another category'})
categoryclass with properties:
a: 'another category'
Now use two categories
cls.a = categorical({'one', 'two'})
categoryclass with properties:
a: [1x2 categorical]
NOTE: This only appears to be an issue in R2014b and R2015a. It was fixed in all later releases.
It's been a while, but today I needed this again. I thought of another way to display scalar categorical variables. The following example class does the trick.
classdef dispfmtTest < matlab.mixin.Copyable
properties
prop = categorical(1) % default value is a scalar categorical
end
methods
function dispfmt(obj) % dispfmtTest object to display format
obj.prop = char(obj.prop); % convert to char type
end
function disp(self)
obj = copy(self); % copy is provided by superclass
dispfmt(obj)
disp#matlab.mixin.Copyable(obj) % call superclass disp
delete(obj)
end
end
end
The dispfmtTest class is a subclass of matlab.mixin.Copyable, which is in turn a subclass of handle. It provides the copy method to the disfmtTest class, which is used to temporarily create a copy of which the value of property prop is changed to whatever desired display format in method dispfmt. Then, the modified copy of the object is displayed using the regular disp function as provided by matlab.mixin.Copyable.
Demo
Running obj = dispfmtTest yields
d =
dispfmtTest with properties:
prop: '1'
and class(d.prop) yields
ans =
categorical
This is the behaviour as I expected. Support for array properties can be achieved too using isscalar.
function [ muln, varargout ] = my_mul( varargin )
%MY_MUL This function is used to multiply numbers.
% My_mul function multiplies array of entered numbers, and outputs single
% solution.
% For example: my_mul(12, 2, 3, 5) gives ans = 360
if nargout >=1
disp('Error, wrong number of output arguments');
varargout{1} = 0;
return
end
if nargin <= 1
disp('Error, small number of input argumnets');
return
else
muln = 1;
for i = 1:nargin
muln = muln*varargin{i};
end
end
end
Hi, everyone, I'm just doing my assignment for uni and have a qiuck question.
How can I make this function to give an error if it is called with more than one output.(It meant to give only one) Thanks!
In your function definition, you have defined your function to allow for an unlimited number of outputs. The keyword varargout is a place-holder for a variable number of outputs.
As you have stated in your question, you only want one possible output which in your case looks to be muln. So if you simply remove varargout from your function definition, MATLAB should automatically throw an error if too many outputs are requested
function muln = my_mul(varargin)
If you ever do need to use varargout but want to place constraints on how many outputs are provided for any given scenario, you can check the number of output arguments that were requested using nargout and then throw an error with the error function.
if nargout > 4
error('my_mul:TooManyOutputs', 'Too many outputs requested');
end
My opinion is that if a return value is expected the function needs to throw. Otherwise the caller (function calling this function) will expect everything to be ok. Note that disp('Error') gives information to the developer, but it does not give the program any indication on what happens. More importantly, the information does not give any indication of where the error occurs. This can force the developer to do heavy debugging just to find the error, which is completely unnecessary.
The use of variable output arguments should only be used in case a different number of output arguments should be expected. An example is some customized plot function
function varargout = myplot(varargin)
filename = '';
idx = find(strcmp(varargin,'filename'));
if (~isempty(idx) && length(varargin)<idx+1 && ~ischar(varargin{idx+1}))
error('filename property must be followed by a directory');
elseif(~isempty(idx))
filename = varargin{idx+1};
varargin([idx,idx+1]) = [];
end
h = plot(varargin{:});
varagout{1} = h;
if (~isempty(idx))
save(filename, h);
end
varagout{2} = filename;
This function works as plot except it saves the figure to file in case a filename is specified. In case the developer needs the handle it will be returned and in case the developer wants the save directory it can be returned as well. None of these arguments are necessary though. The developer may want to use this function as a standard plot function and this means that the user may want to call myplot as myplot(x,y);which does not return a value. Further note that even if 'filename' is not specified, the function can still return 2 outputs. The second output may be an empty array of char, but two outputs for the caller will never cause a crash.
Also, note that no further error handling is required. The only unchecked crashes are in plot and save. How this is handled may be different for different users and this means that it only is reasonable to let the user catch the error and handle it (as he would have done if save or plot would have thrown).
Apart from this you may also want to have a check so that the number of output variables are within the correct range (in this case 0,1 or 2 outputs).
my source code:
function void = find_edge()
path_io = 'io_find_edge\';
format = '.jpg';
list_img = ['Parent_006.jpg'; 'Parent_007.jpg'; 'Parent_008.jpg'; 'Parent_009.jpg'; 'Parent_010.jpg'];
list_filter = {'sobel', 'canny', 'prewitt', 'roberts', 'log'};
for index = 1:size(list_img)
img_name = list_img(index, 1:10);
img = rgb2gray(imread([path_io img_name format]));
for filter = list_filter
imwrite(edge(img, filter), [img_name '_' filter format], 'jpeg');
end
end
error:
Undefined function 'power' for input arguments of type 'cell'.
Error in edge (line 420)
cutoff = (thresh).^2;
Error in find_edge (line 15)
x = edge(img, filter);
thanks!
Inside the inner for loop, filter will be a cell with only one entry containing the current filter name. Still it is a cell array, so the edge function returns an error. You will can access the content of filter, i.e. the string with the current filter name, by using filter{:}.
I think you also have an error in constructing the file name. I assume you want to use filter instead of list_filter to create the filename, right?
Thus:
imwrite(edge(img, filter{:}), [img_name '_' filter{:} format], 'jpeg');
PS: as #thewaywewalk remarked in a comment, filter is the name of a function. It is not advisable to use it as a variable name, as then the filter function won't work anymore. I suggest to rename it to e.g. current_filter.