2

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);
EBH
  • 10,350
  • 3
  • 34
  • 59
Darcy
  • 619
  • 2
  • 5
  • 15
  • What does “almost works” mean? – Cris Luengo Jan 13 '19 at 17:02
  • If you try the code sample I have above, you will see that the insert is added to the plot but the center of the insert does not line up with where the user clicked. I want the center of the insert to be added exactly where the user clicked. The example I have above puts it somewhere in the vicinity but it seems to depend on the size of the figure and other factors. – Darcy Jan 16 '19 at 17:58

1 Answers1

1

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.

EBH
  • 10,350
  • 3
  • 34
  • 59