Matlab rotate3D and buttondownfcn incompatibility - matlab

Hi everyone and thanks in advance for all your help.
I'm currently working on a UI in matlab that includes 4 differents axes to show various info. Basicly, I have MRI data (so 3D data) that I want to show. I use 1 axe to show 3 perpendicular plane that split the data at its center (axeMain), and 3 other axes that shows the planes individually (axeX,axeY and axeZ). I have a main axe on wich I want to make rotations possible (only on the main axis system) and I want to be able to select coordinate on the 3 other axe (those with 1 plane only). I also unable translations but that is out of scope for my problem.
So basicly, I have no problem selecting my coordinates (using the buttondownfcn on my planes) on all of the 3 axes and I also have no problem using rotate3D on the mainAxe. HOWEVER, if I try to have both to work at the same time, the buttondownfcn doesn't work anymore. I don't understand why it's doing this (I have some ideas but that's about it) and I have no idea how to work around it. Basicly my code for those functions are like this :
rotate3d(handles.axisMain);
%some other code, setting up other UI stuff
%allow selection on the 3 static plains.
set([handles.axeX,handles.axeY,handles.axeZ], 'buttondownfcn', #getCoord);
So my question is basicly : why wont those 2 functions don't work together and how to work around that problem, ideally with minimal code change?
Thanks.
EDIT : this is a print screen of my current interface. I want to be able to select coordinate using ONLY on the 3 last axes (containing only 1 plane in each of them). I also want to be able to rotate images ONLY on the first axe (the one with 3 planes). Hope this clarify.
I would also like to note this : following my tests, I found that the mouse click would not raise at all if the rotate3D is activated. The problem is not in the logic I use to get the coordinates itself, but in the click event not being fired.
Also, I am aware that the event is not on the surface that I try to print. The actual code is like this :
set(h, 'buttondownfcn', #getCoord);
set(h,'HitTest','on');
where h is the handle of a surface and each surfaces are processed this way.

I have found the exact solution!
Exploring the code for rotate3d(hAxe,'on') , i have found that they key line is getuimode(hFig,'Exploration.Rotate3d') wich returns uitools.uimode that contains ButtonDownFilter and ModeStateData methods.
Finally i have solved the problem in the following way:
rotate3d(hAxe,'on')
uiMode = getuimode(hFig,'Exploration.Rotate3d');
uiMode.ButtonDownFilter = #mycallback;
where:
hAxe is the handle to the axes object
hFig is the handle to the figure object
#mycallback is the callback that lets buttondownfcn and rotate3d works together as in the example of Matlab's help
So, you have to tag the object that you want to not be ignored:
set(hAxe,'tag','DoNotIgnore')
And write the callback:
function [flag] = mycallback(obj,event_obj)
% If the tag of the object is 'DoNotIgnore', then return true
objTag = obj.Tag;
if strcmpi(objTag,'DoNotIgnore')
flag = true;
else
flag = false;
end

maybe
set(handles.axisMain, 'buttondownfcn', #getCoord);

Related

Matlab : different data cursor in a same graph

I would like to call 2 different cursor in a same graph, is it possible ? I have 2 graph in a figure (using sublopt). And in the first graph, I have 3 different courb like this :
subplot(2,1,1)
plot(x_new, y2, 'r')
hold on
[hAx,hLine1,hLine2] = plotyy(x_new,y1,x_new,y3);
For the moment, I call only one cursor for my figure (so for my 2 graphics, the cursor is the same) like this :
dcm_obj = datacursormode(fig);
set(dcm_obj,'UpdateFcn',#cursorcallback);
My second problem : when I want to remove the cursor on my coubr, I can't, it stays on the graph.
Thank you in advance,
Best regards
You can add and remove cursors using the context menu interface on the figure itself (by right-clicking).
This can also be done programmatically using dcm_obj.createDataTip, dcm_obj.removeDataCursor and dcm_obj.removeAllDataCursors() but the functionality is not officially documented. There is, however, a good guide to it at http://undocumentedmatlab.com/blog/controlling-plot-data-tips

MATLAB Bar Graph Plotting Over Axes

I have a troubling problem that I've been trying to figure out for quite a while now and I just have no clue why it's happening. I have a self-coded GUI and I have a panel on the main GUI figure. On this panel I have an axes and whenever I plot a bar graph on that axes and try to edit its view with either yLim() or axis(), the axes will be resized to the dimensions I want, but the bar graph will not chop off at the edge of the axes and it will continue to run off the page. After playing around with it for a while in debug mode, I have found out that if I change the axes' parent from the panel it's on to the main figure, the bar graph will properly display only what is inside the axes borders like I want it to. I don't want to use changing the axes' parent as a permanent solution since I have several different panels I want to go between and having an axes on the main figure instead of the panel wouldn't work but I'd like to know if anybody knows why this is happening and how I can fix it.
For example, this code produces the problem I'm experiencing:
mainFig = figure('Units','characters',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
axesPanel = uipanel('bordertype','etchedin',...
'Parent',mainFig,...
'Title','Axes Panel');
mainAxes = axes('parent',axesPanel,...
'Units','characters');
bar(mainAxes,1:10,1:10)
ylim(mainAxes,[6 10])
And if the axes' parent is changed to be the figure, the problem doesn't exist. This line of code does that:
set(mainAxes,'parent',mainFig)
Thanks for any help or information as to why this is happening!
Just in case anybody else was having this same problem, I contacted MATLAB Technical Support and I was told that this was a bug on MATLAB's end that is being fixed in the next release(R2014b). They said that if you are having the problem I described in my original question, that in order to make the bar graph appear within the axes' boundaries at the moment, that you can edit the figure's 'Renderer' property and set it to either 'opengl' or 'zbuffer'. I have tested this and both options work so hopefully that helps :)
And just for extra clarification if it is needed, all I needed to change from my original code was:
mainFig = figure('Units','characters',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
To this:
mainFig = figure('Units','characters',...
'Renderer','opengl',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
And now the bar graph behaves as it should.

Adding text annotation to figure programmatically

I would like to add text annotation to a figure from a GUI made with GUIDE. First I plot some data, than when the user clicks on a checkbox I call the text function in the event handler like this:
text(obj.XData(q), obj.YData(q)+10, int2str(q), 'Units', 'pixels');
obj is the line object itself, q is a counter for each point in the plot. It runs without errors, but nothing happens. I suppose I should 'refresh' the axis somehow, but refresh command doesn't help and I haven't found anything in the documentation.
Edit: I have found out that my code was wrong: pixel units correspond to a coordinate system where the origin is the lower-left corner of my axis control, what is not the same as my data coordinate system. I fixed this problem with ds2nfu, and when I paint before plotting everything is fine. But after plotting I see nothing. Is it possible that there is some kind of z-order problem with annotations?
As I mentioned in the comments, you should use the normalized units to place things in the same coordinate system as the data.
Now for the other problem. I'm not sure if this is a z-order issue, but if it is, you can bring the text to the front using UISTACK:
hText = text(x,y,'str');
uistack(hText, 'top')

Does Matlab execute a callback when a plot is zoomed/resized/redrawn?

In Matlab, I would like to update the data plotted in a set of axes when the user zooms into the plot window. For example, suppose I want to plot a particular function that is defined analytically. I would like to update the plot window with additional data when the user zooms into the traces, so that they can examine the function with arbitrary resolution.
Does Matlab provide hooks to update the data when the view changes? (Or simply when it is redrawn?)
While I have yet to find one generic "redraw" callback to solve this question, I have managed to cobble together a group of four callbacks* that seem to achieve this goal in (almost?) all situations. For a given axes object ax = gca(),
1. Setup the zoom callback function as directed by #Jonas:
set(zoom(ax),'ActionPostCallback',#(x,y) myCallbackFcn(ax));
2. Setup a pan callback function:
set(pan(ax),'ActionPostCallback',#(x,y) myCallbackFcn(ax));
3. Setup a figure resize callback function:
set(getParentFigure(ax),'ResizeFcn',#(x,y) myCallbackFcn(ax));
4. Edit: this one no longer works in R2014b, but is only needed if you add, e.g., a colorbar to the figure (which changes the axis position without changing the figure size or axis zoom/pan). I've not looked for a replacement. Finally, setup an undocumented property listener for the axes position property itself. There is one important trick here: We must hold onto the handle to the handle.listener object as once it's deleted (or leaves scope), it removes the callback. The UserData property of the axes object itself is a nice place to stash it in many cases.
hax = handle(ax);
hprop = findprop(hax,'Position');
h = handle.listener(hax,hprop,'PropertyPostSet',#(x,y) myCallbackFcn(ax));
set(ax,'UserData',h);
In all these cases I've chosen to discard the default callback event arguments and instead capture the axis in question within an anonymous function. I've found this to be much more useful than trying to cope with all the different forms of arguments that propagate through these disparate callback scenarios.
*Also, with so many different callback sources flying around, I find it invaluable to have a recursion check at the beginning of myCallbackFcn to ensure that I don't end up in an infinite loop.
Yes, it does. The ZOOM mode object has the following callbacks:
ButtonDownFilter
ActionPreCallback
ActionPostCallback
The latter two are executed either just before or just after the zoom function. You could set your update function in ActionPostCallback, where you'd update the plot according to the new axes limits (the handle to the axes is passed as the second input argument to the callback).

MATLAB: impoint getPosition strange behaviour

I have a question about the values returned by getPosition. Below is my code. It lets the user set 10 points on a given image:
figure ,imshow(im);
colorArray=['y','m','c','r','g','b','w','k','y','m','c'];
pointArray = cell(1,10);
% Construct boundary constraint function
fcn = makeConstrainToRectFcn('impoint',get(gca,'XLim'),get(gca,'YLim'));
for i = 1:10
p = impoint(gca);
% Enforce boundary constraint function using setPositionConstraintFcn
setPositionConstraintFcn(p,fcn);
setColor(p,colorArray(1,i));
pointArray{i}=p;
getPosition(p)
end
When I start to set points on the image I get results like [675.000 538.000], which means that the x part of the coordinate is 675 and the y part is 538, right? This is what the MATLAB documentation says, but since the image is 576*120 (as displayed in the window) this is not logical.
It seemed to me like, somehow, getPosition returns the y coordinate first. I need some clarification on this.
Thanks for help
I just tried running your code in MATLAB 7.8.0 (R2009a) and had no problems with image sizes of either 576-by-120 or 120-by-576 (I was unsure which orientation you were using). If I left click inside the image, it places a new movable point. It did not allow me to place any points outside the image.
One small bug I found was that if you left-click in the image, then drag the mouse pointer outside the image while still holding the left button down, it will place the movable point outside the image and won't display it, displaying a set of coordinates that are not clipped to the axes rectangle.
I'm not sure of what could be your problem. Perhaps it's a bug with whatever MATLAB version you are using. I would suggest either restarting MATLAB, or clearing all variables from the workspace (except for the image data im).
Might be worth checking to see which renderer you are using (Painter or OpenGL), a colleague showed me some wierd behaviour with point picking when using the OpenGL renderer which went away when using the Painter renderer.
Your code uses the Image Processing Toolbox, which I don't have, so this is speculation. The coordinate system is probably set to the figure window (or maybe even the screen), not the image.
To test this, try clicking points outside the image to see if you can find the origin.