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.
Related
I have a Matlab function
PlotSubbands(imfx(:,1),wx,3,3,j,j,1);ylabel('Subband');
from TQWT toolbox. eeweb.poly.edu/iselesni/TQWT. When I execute, the function plots 'j' number of plots. (I have not included full code). The function plots the input signal, which is in this case imfx(:,1) for every subplot. And this what I don't want. I tried removing it from the parameters but I got error, 'not enough input arguments'. This is because in the function the first input signal parameters is defined and used. I cannot remove it from there. Appreciate your inputs on the same. Thank you.
The function PlotSubbands include following lines
if isreal(x)
plot((0:N-1)/fs,x/(2*max(abs(x))),'b')
else
plot((0:N-1)/fs, real(x)/(2*max(abs(x))), 'black')
The repeated plotting of input signal is done from these two line. Commenting these lines can solve the problem (If array x does not include imaginary part, then better to comment these lines). However, the to determine the real array, isreal(x) is needed further in the function. So, I defined the value of x here and it solved the repeated plotting issue.
In Matlab I wanted to pass arguments to the plot function by using a struct. This was going well until I wanted to include the DurationTickFormat argument.
In the minimal example below, I get the following error message when trying to plot the second figure:
Error using duration/plot There is no DurationTickFormat property on
the Line class.
clear;
t_dur = days(0);
t_dur(2) = 2;
t_duration = linspace(t_dur(1),t_dur(2),11);
figure;
plot(t_duration,0:10,'Color','k','LineWidth',2,'DurationTickFormat','hh:mm:ss');
% using a struct to pass arguments to the plot function
plotOptions.LineWidth = 2;
plotOptions.DurationTickFormat = 'hh:mm:ss';
figure;
plot(t_duration,0:10,'Color','k',plotOptions);
Any ideas why using a struct to pass arguments doesn't work in this case?
Thanks.
I'm not familiar with R2015a, but I have a good guess. I think when you pass a structure, you explicitly add line properties (lineseries properties in older matlab, I guess with HG1, chartline properties in the newest ones, I'm guessing with HG2). The chartline properties do not include 'DurationTickFormat'. So when you are calling it directly, you are actually telling the plot function to do some stuff (like changing the xlabel accordingly, which is obviously invisible to a line object).
I hope someone familiar with R2015a can either verify or disprove my hypothesis.
Update: from plot options > DurationTickFormat:
DurationTickFormat is not a chart line property. You must set the tick format using the name-value pair argument when creating a plot.
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.
At line 486 in estimateCameraParameters.m the refine function is called as shown below. Where is the source code of that function ?
I have searched all Matlab scripts but could not find it.
There is no documentation on this function either.
Any idea where to look for it ?
Where is refine hiding ?
errors = refine(stereoParams, imagePoints1(:, :, pairsUsed), ...
imagePoints2(:, :, pairsUsed), shouldComputeErrors);
At line 303 there is a short description of this function :
% refine the initial estimate and compute distortion coefficients using
% non-linear least squares minimization
errors = refine(cameraParams, imagePoints, shouldComputeErrors);
Found it: it's in stereoParameters.m
I just needed to start to step through estimateCameraParameters.m with the debugger.
Additional explanation:
http://se.mathworks.com/help/matlab/matlab_oop/ordinary-methods.html
Either of the following statements is correct syntax for calling a
method where obj is an object of the class defining the compute
method:
obj.compute(inc)
compute(obj,inc)
So refine() is a method not a standalone function.
I did not know that it is possible to call a method on an object using method(object) syntax. This was confusing me and I was thinking that refine() is a standalone method not defined within a class.
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.