MATLAB: How to get the clicked values relative to a figure position rather than figure axis

178 views Asked by At

As some background, what I am trying to do is add an inset figure to a current plot. I've got most of this done. Here is a code sample:

h = figure(1); %Arbitrary figure #1
plot(990000:1000000,990000:1000000,'--r');

g = figure(2); %Arbitary figure #2
plot(randn(100,1),randn(100,1),'.k');

figure(3); %Figure to combine the above two figures
new_fig=gcf;
main_fig = findobj(h,'Type','axes');
h_main = copyobj(main_fig,new_fig);
set(h_main,'Position',get(main_fig,'Position'))
inset_fig = findobj(g,'Type','axes');
h_inset = copyobj(inset_fig,new_fig);
ax=get(main_fig,'Position');

inset_size = 0.3;
X = 0.2; %Left position of inset hard-coded in
Y = 0.6; %Bottom position of inset hard-coded in

set(h_inset,'Position', [X Y inset_size inset_size])  

close(h); close(g);

In the above code sample, I am just setting the X and Y position of the inset figure manually as X = 0.2 and Y = 0.6.

However, the tricky part that I am stuck on is that I want the X and Y position to be determined by the user. I want the user to be able to click on the figure somewhere and this clicked point becomes the center point of the inset.

Unfortunately, ginput does not work quite the way I want it to because [x,y] = ginput(1) returns values x and y which are relative to the figure axis. Here is a code sample:

h = figure(1); %Arbitrary figure #1
plot(990000:1000000,990000:1000000,'--r');
[x,y] = ginput(1);

As you can see here, x and y will be on the order of 10^5 because they are referenced to the plot axis. So the (x,y) from ginput does not match the (X,Y) for setting the position of a figure.

Any ideas how to convert (x,y) to (X,Y)?

EDIT: I tried doing the following scaling and it "almost" works but does not quite work, any ideas on how to improve are appreciated:

h = figure(1); %Arbitrary figure #1
plot(990000:1000000,990000:1000000,'--r');
[x,y] = ginput(1);

limx = xlim;
limy = ylim;

g = figure(2); %Arbitary figure #2
plot(randn(100,1),randn(100,1),'.k');

figure(3); %Figure to combine the above two figures
new_fig=gcf;
main_fig = findobj(h,'Type','axes');
h_main = copyobj(main_fig,new_fig);
set(h_main,'Position',get(main_fig,'Position'))
inset_fig = findobj(g,'Type','axes');
h_inset = copyobj(inset_fig,new_fig);
ax=get(main_fig,'Position');

inset_size = 0.3;
% X = 0.2; %Left position of inset hard-coded in
% Y = 0.6; %Bottom position of inset hard-coded in

%CONVERT ginput (x,y) to axis position (X,Y)
X = (x-min(limx))/diff(limx)*ax(3);
Y = (y-min(limy))/diff(limy)*ax(4);

set(h_inset,'Position', [X Y inset_size inset_size])  

close(h); close(g);
1

There are 1 answers

0
EBH On

I would use a small function to convert the units from 'normalized' to 'data':

ax2norm = @(x,y,ax) [...
    ax.Position(3)*((x-ax.XLim(1))./range(ax.XLim))+ ax.Position(1)...
    ax.Position(4)*((y-ax.YLim(1))./range(ax.YLim))+ ax.Position(2)];
 %  white area * ((value - axis min)  / axis length)  + gray area

where x and y are the normalized coordinates and ax is the axes handle to convert to its data units.

The example below is similar to what you want to achieve but is more concise and general:

% create the inset:
insetFig = figure('Visible','off');
plot(randn(100,2),'.k')
temp_ax = gca;

% create the main figure:
mainFig = figure;
plot(1:10,1:10,'--r')
main_ax = gca;

% get position for inset:
inset_size = 0.3;
[x,y] = ginput(1);
XY = ax2norm(x,y,main_ax);

% copy the inset to the position:
inset_ax = copyobj(temp_ax,mainFig);
close(insetFig);
set(inset_ax,'Position', [XY-inset_size/2 inset_size inset_size])  

In particular, here are the main changes:

  1. I don't create a third figure, but copy the inset into the main one
  2. I first make the inset plot within an invisible figure, then get the position from the user and after copying it I also close it
  3. I use gca to get the axes handles as it is much faster than findobj

Some of these changes may not fit your situation, but none of them is crucial for the example to work. The essence of the answer is the function above.