matlab zoom callback error associated with text function - matlab

While trying to execute generation of a series of text boxes in a post-zoom callback function in Matlab, a number of errors are generated, the trace of which is unhelpful in diagnosing and resolving the problem. When the text generation is in the main body of code as follows, the code executes properly and there is no issue executing the minimal post-zoom callback function:
string='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
offset=8;
h=figure;
z=zoom(h);
set(z,'ActionPostCallback',#post_callback);
[ax,plt1,plt2]=plotyy(14:20,1:7,15:17,1:3,#bar,#bar)
ylim([0 10]);
hold on;
set(plt2,'FaceColor','r');
xLim=xlim(gca);
for i=xLim(1)+1:xLim(2)-1
text(i,8,string(i-offset+1),'Clipping','on');
end
function post_callback(obj,evd)
xLim = get(evd.Axes,'XLim');
However, if the text box generation is moved to the #post_callback function, a series of errors result:
string='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
offset=8;
h=figure;
z=zoom(h);
set(z,'ActionPostCallback',#post_callback);
[ax,plt1,plt2]=plotyy(14:20,1:7,15:17,1:3,#bar,#bar)
ylim([0 10]);
hold on;
set(plt2,'FaceColor','r');
function post_callback(obj,evd)
xLim = get(evd.Axes,'XLim');
for i=xLim(1)+1:xLim(2)-1
text(i,8,string(i-offset+1),'Clipping','on');
end
Those errors are, as described in this problem:
Warning: An error occurred during the mode callback.
> In uitools.uimode.fireActionPostCallback at 14
In zoom>local2DButtonUpFcn at 1332
In hgfeval at 63
In uitools.uimode.modeWindowButtonUpFcn at 46
In uitools.uimode.setCallbackFcn>localModeWindowButtonUpFcn at 58
Could someone please enlighten me as to the root cause of the errors?

The error seems to be the same. You should try to use the debugger here. Set a breakpoint in your post callback function. However, there are a few problems in your code. Some are implementation issues, some other problems does not do what you ask them too. You seems to have some programming experience, so I guess that most implementation issue are just bugs. I will list problems and solutions.
1) I cry when I see that you use string as a variable. String is an abstract type (obselete in matlab now since later versions uses char vectors). use instead some other name like str or myString.
2) Unless offset and your variable string is not declared global, they will not be inside the scope of post_callback. Different from C or C++, a variable does not become global when defined in "main" (since you do not even define a main method). If you want to use string or offset inside of post_callback, you must define them inside their scope (inside the function).
3) the loop variable i must not be a cell. Use the method from the previous question to convert it to a double vector.
4) The loop variable i must be an integer in:
text(i,8,string(i-offset+1),'Clipping','on');
since string is defined a variable and variable indices must be integers, xLim does not necessary need to be an integer.
5) I do not think text will give the expected output here. What text does is creating a string and linking it to a point on the plot. This means that every time you zoom you will have a new text in the plot. Unless the texts are located at exactly the same place (which may be possible, but will reqire a lot of work) the plot will look really ugly. If possible, place the text strings in the way that you do in example 1 and remove it from post_callback.

Related

How to use a FOR loop in a 'struct' subindex? - MATLAB

I have a struct as shown in picture, and I need to address one of the columns in a FOR loop, as shown. But I keep getting this error:
Function 'subsindex' is not defined for values of class 'struct'.
Error in analisa_arx_teste (line 351)
In my case, what i want is :line 1 represents i = 1, line 2 i =2; So, for features, When I ask for pref_estemod(i).features is to get the values from the field features associated to each model.
I am just starting programming with matlab, so all your help would be appreciated.
Thanks!
for i=pref_estemod(1:npreferred)
[m,n]=size(Training);
features=(pref_estemod(1,i).features);
end
The error lies in i=pref_estemod(1:npreferred).
If you intend to use i for indexing, the syntax is for i=1:npreferred.
1:npreferred itself expands to the horizontal array [1,2,...,npreferred]. = with a leading for is a special syntax combination. It means do the following code with i=1, i=2, ..., i=npreferred. Now I am sure you already know the idea behind for loop. The reason I write all this is to give you the following warning/advise. Do NOT expect the same syntax to work with non-numeric arrays. Because it works in some cases and not others.

Matlab - Expand Figure Temporarily, Then Close

I'm expanding on the question asked at Expand (maximise) subplot figure temporarily — then collapse it back - I tried to post this as a comment to the original post, but I don't have sufficient privileges.
I was using the version in the comments:
function gcaExpandable
set(gca, 'ButtonDownFcn', [...
'set(copyobj(gca, uipanel(''Position'', [0 0 1 1])), ' ...
' ''Units'', ''normal'', ''OuterPosition'', [0 0 1 1], ' ...
' ''ButtonDownFcn'', ''delete(get(gca, ''''Parent''''))''); ']);
end
which worked perfectly in Matlab 2013b. However, I'm now on 2015b and when I try to use that same buttondown function I get the following:
Error using gcaExpandable
Too many input arguments.
Error while evaluating Axes ButtonDownFcn
I don't currently understand what exactly is throwing the error. I've tried to fix it by adding the 'legacy' flag to copyobj based on the documentation:
copyobj(___,'legacy') copies object callback properties and object
application data. This behavior is consistent with versions of copyobj
before MATLAB® release R2014b.
but that doesn't change the behavior at all. If anyone can figure out what's causing the error or how to adapt this very useful function to 2015b it would be greatly helpful! Thanks.
This one works for me on MATLAB R2017a:
set(gca, 'ButtonDownFcn',#(ax,~)set(copyobj(ax,uipanel('Position',[0,0,1,1])),...
'Units','normal', 'OuterPosition',[0,0,1,1],
'ButtonDownFcn',#(co,~)delete(get(co,'parent'))));
You can put this inside a gcaExpandable function as in the OP.
The big difference with the code in the OP is the use of anonymous functions. Callbacks have two input arguments, the first one is the callback object (the thing clicked on), the second one can be ignored, but must be present in the function definition (hence the ~, which signals an ignored parameter).
By using anonymous functions instead of a string to be evaluated, the syntax is clearer (no doubled-up quotes).
Under Octave, the copyobj function works differently. To get the same code to work, you need more than one statement in the callback. For this it is necessary to define the callback function as a regular, named function, and pass its handle as the callback:
function gcaExpandable
set(gca,'ButtonDownFcn',#callback);
function callback(ax,~)
panel = uipanel('Position',[0,0,1,1]);
newax = copyobj(ax,panel);
set(newax,'Units','normal', 'OuterPosition',[0,0,1,1], ...
'ButtonDownFcn',#(~,~)delete(panel))
(The two functions above are defined in the same file gcaExpandable.m.)
Note that the code is also much cleaner this way, there is no advantage to defining it all as a one-liner. This version also works in MATLAB.

Graphic object handle array in embedded matlab function in Simulink in R2014a or newer

For debugging, I have some plots of vectors in an embedded matlab function in Simulink. Up to Matlab R2013b, everything works just fine with the following minimum example code:
function fcn
%#minimum example for plot within for-loop of embedded matlab function
coder.extrinsic('delete');
coder.extrinsic('quiver');
coder.extrinsic('gobjects');
numSteps=4;
persistent hFig;
persistent hVector;
if isempty(hFig)
hFig = figure;
hold on;
hVector=zeros(numSteps,1);
hVector=gobjects(numSteps,1);
for i=1:numSteps
hVector(i) = quiver(0,0,0,0);
end
end
set(0, 'CurrentFigure', hFig);
delete(hVector);
for i=1:numSteps
startInc=[1 1;1 1].*i;
endInc=[2 3;2 -3].*i;
hVector(i) = quiver(startInc(1,:),startInc(2,:),endInc(1,:),endInc(2,:));
end
For the handle array hVector, an initialization is necessary due to its use in the for-loop. However, for an Initialization of a graphics handle object, the function gobjects is needed and in turn the initialization as double with zeros(numSteps,1) becomes necessary, since matlab cannot correctly determine the data type of an output of an extrinsic function.
As I said, this code snippet works just fine if copied to an embedded matlab function block in simulink without anything else in the model.
My problem: Mathworks changed a lot of the plotting functions in R2014a, one of the changes being the datatype of the graphics handles which are no of type quiver for my quiver plot. Thus, the initialization with zeros(numSteps,1) initializes the wrong data type for the handle array. However leaving it out still does not work, because of the problem mentioned above. Neither does a init loop or anything similar compile without errors.
I'd greatly appreciate any help on that issue.
You can try to remove the gobject initialisation and use double() to wrap your call to any matlab graphic object. Ex:
hVector(i) = double( quiver(startInc(1,:),startInc(2,:),endInc(1,:),endInc(2,:)) ) ;
I suggest reading Loren's article about the compatibility issues which can arise when switching to HG2 versions of Matlab.
A quick quote from it which apply more to your issue:
Graphics Functions Return Objects, not Numeric Handles
Prior to R2014b, you could store a set of handles to graphics objects
in an array and then add some numeric data to that array. In R2014b,
that will cause an error.
[...]
If you find yourself really stuck, it is possible to cast object
handles to numeric handles using the double function. You can then
cast the number back to an object handle using the handle function. We
don't recommend this as a long term solution. Be aware that we may
choose to remove this feature in a future version of MATLAB. If we do,
we'll let you know in advance.
Now if you really have to use this solution, note that both functions works on single elements but also on arrays. So
hVector_HG = handle( hVector_Num ) ; %// works if "hVector_Num" is an array of numeric handles
%// and ...
hVector_Num = double( hVector_HG ) ; %// works if "hVector_HG" is an array of HG2 graphic handles
That may simplify the round trips between a format or another if they often become necessary.
Edit:
I put this at the bottom of the post for the moment because the beginning is already accepted answer but please try the following and let me know if it works. It may solve your problem in a better (more future-proof) way.
Another way to initialise an array of handle of a given graphic object is to create one (empty is good enough) and replicate it. For example:
hqNaN = quiver(NaN,NaN) ; %// create an empty quiver
hVector = repmat( hqNaN , numSteps , 1 ) ; %// replicate it in an array
will give you an array hVector containing numSteps HG2 graphic object handles. At this point they all point to the very same object but it is perfectly legal to overwrite each element with a handle of the same type. So a later :
hVector(i) = quiver( ... , etc ... ) ; %// overwrite handle "i" with a new quiver plot handle
will (should) work without problem.
A few things to take care with this approach:
where will the empty quiver be created ?
you may already have a "current" figure and you don't want it to be messed up. If not a new empty plot will be created. So to make sure the empty quiver do not cause problem (just a flicker on the screen), you could wrap it this way:
figure ; hqNaN = quiver(NaN,NaN) ; close(gcf) ;
or you can also park it in a figure (it will be invisible anyway) in case you need to re-use a handle of this type for other array initialisation. Just don't forget that once you close the figure it is on, or you delete the graphic object, the hqNaN variable is still there but it is not the same type of handle any more (so not useful to replicate if you want this type exactly).
What if you do not overwrite all you initial handle array ?
Remember all the initial handles of the array point to the same graphic object. So in case your array contains 12 elements but let's say by mistake you only overwrite 10 of them, then 2 elements will be handles pointing to the same object (which you may already have deleted)). This means that calling:
delete(hVector)
will throw you the annoying:
Error using handle.handle/delete. Invalid or deleted object.
gna gna gna ... luckily you can easily prepare for that by programming defensively and using instead:
delete( hVector(ishandle(hVector)) )
Matlab will do the check automatically and only delete the right handles.

Matlab GUI: referencing an existing object handle using a variable

I am currently working on my matlab final project for school. I consider myself fairly knowledgeable and proficient when it comes to programming.. but Matlab simply has TOO many oddities.
The fundamental question (realized this after finding the answer)! How can I use a variable in a call to a gui handle object
without the name of the variable being used instead of the value?
In other words: Use a variable in a field name (If I had known it was this simple I wouldn't of asked)
My project is building a simple rendition of the age old 'Battleship' game.
My issue: I currently 5 objects (axes) for the ship pieces. They are selected one at a time to be moved into another location(the grid). I am able to use the setpixelposition to move each object after a button click.
Right now under the button click, I have something like this
function btnPlaceShip_Callback(hObject, eventdata, handles)
%Store the current selected ship(passed from an onclick to a label)
ship = get(handles.lblSelectedShip,'string');
%I have tried everything I could think of, but basically I want to achieve the
%following
setpixelposition(handles.ship, [0 250 50 250])
%where the variable 'ship' contains the name of the object.
In other words, the var ship = 'shipAircraftCarrier', and..
setpixelposition(handles.shipAircraftCarrier, [0 250 50 250])
works!(sets the position of the specific ship indicated). Using the variable ship, however, matlab takes the string literally and not for its value. It would be extremely convenient to use the variable instead!
If anyone have any solutions, I would be grateful. I have scoured the web but perhaps I am missing some fundamental understanding of the Matlab GUI stuff - The matlab help documents are very non-descriptive and are not of much help.
As mentioned by others use dynamic fieldnames. Whilst not having the code to test it I believe that simply putting brackets around the ship will substitute the string in to the structure name, thus
setpixelposition(handles.(ship), [0 250 50 250])
Try to avoid the use of eval() if at all possible.
You can do this using the eval function, but you need to be careful about string injections:
setpixelposition(eval(strcat('handles.',ship)), [0 250 50 250])
You can use dynamic fieldnames or getfield. Field indexing using identifiers vs strings is quite similar in Matlab structs and Javascript objects.
Matlab:
fromId = handles.shipAircraftCarrier; %identifier
fromString = handles.('shipAircraftCarrier'); %string
Javascript:
var fromId = handles.shipAircraftCarrier; //identifier
var fromString = handles["shipAircraftCarrier"]; //string

Can you explain this Embedded MATLAB Function error?

I'm having a problem sending a value from a GUI to an Embedded MATLAB Function (EMF) in a Simulink model. I get this value from a slider in my GUI and send it to an EMF block in my model. I can confirm that the value is being transferred correctly from my GUI to my Simulink block, since I can display the value with a display block in my model and see the value change when I change the slider position in my GUI. However I keep getting this error when I run my model:
Could not determine the size of this expression.
Function 'Kastl' (#18.282.283), line 14, column 1:
"f"
This is part of my EMF block code:
function y = input_par(u,fstart)
...
f_end = 1000;
f = fstart:f_end;
...
I believe MikeT is correct: you can't redefine the size of a variable in an embedded function. If you look at this Embedded MATLAB Function documentation page under the subsection Defining Local Variables, it says:
Once you define a variable, you cannot
redefine it to any other type or size
in the function body.
You will have to rework your embedded function such that the variables you declare are not changing size. Since I don't know what you are subsequently doing with the variable f, there's not much more specific help I can give you.
In general, if you absolutely need to use data that changes size, one solution is to pad the data with "garbage" values in order to maintain a constant size. For example:
MAX_ELEMS = 1000; % Define the maximum number of elements in the vector
f = [fstart:MAX_ELEMS nan(1,fstart-1)]; % Create vector and pad with NaNs
In the above example, the variable f will always have 1000 elements (assuming the value of fstart is an integer value less than or equal to 1000). The value NaN is used to pad the vector to the appropriate constant size. Any subsequent code would have to be able to recognize that a value of NaN should be ignored. Depending on what calculations are subsequently done in the embedded function, different pad values might be needed in place of NaN (such as 0, negative values, etc.).
I believe the issue you are running into is that you can't change a parameter during simulation that will cause the dimension of a signal to change. In your example, the code,
f = fstart:f_end;
changes size whenever fstart changes. I think this is what EMF block is complaining about. I don't have any easy workaround for this particular issue, but maybe there's an equivalent way of doing what you want that avoids this issue.