Creating annotation boxes for subplots in a for-loop in Matlab - matlab

I have the following code in Matlab that runs through a for loop, reads data from a file and plots 9 different figures, that correspond to some particular "channels" in my data, so I decided to annotate them in the for loop.
clear
clc
for i=1:9
subplot(3,3,i);
hold on
x = [4 13]; % from your example
y = ([1 1]); % from your example
y2 = ([-0.4 -0.4]);
H=area(x,y,'LineStyle','none',...
'FaceColor',[1 0.949019610881805 0.866666674613953]);
H1=area(x,y2,'LineStyle','none',...
'FaceColor',[1 0.949019610881805 0.866666674613953]);
% Create textbox
annotation('textbox',...
[0.719849840255583 0.603626943005185 0.176316293929713 0.308290155440411],...
'String',{'FABLIGHT04','Channel',i},...
'FontWeight','bold',...
'FontSize',10,...
'FontName','Geneva',...
'FitBoxToText','off',...
'EdgeColor','none');
axis([0 24 -0.4 1])
set(gca,'XTick',[0:1:24])
set(gca,'YTick',[-0.4:0.2:1])
xlabel('Time (s)');
end
Initially it was giving me 9 different figures and the annotation thing worked fine. But I wanted to be able to tile them onto a subplot for easier comparison.
Since I switched over to using subplot, it does not annotate my figure properly. On opening the editing dock and generating the code, I find that matlab is plotting everything first and then just putting the annotation boxes in the same figure, one on top of the other. Looking at the code it generated, it apparently takes this part of the code:
annotation('textbox',...
[0.719849840255583 0.603626943005185 0.176316293929713 0.308290155440411],...
'String',{'FABLIGHT04','Channel',i},...
'FontWeight','bold',...
'FontSize',10,...
'FontName','Geneva',...
'FitBoxToText','off',...
'EdgeColor','none');
and does it as:
annotation(figure1,'textbox'...)
etc etc
So for all 9 text boxes, it puts them onto the same figure. I tried to do S=subplot(3,3,i) then annotation(S,'textbox') etc etc, I have also tried S(i)=subplot(3,3,i) and then annotation(S,'textbox') etc etc but nothing seems to work.
I have also tried to change the location of the box. I can't seem to figure out how to make it smaller either.
Does anyone know how to have annotation boxes in the right subplot in a for loop?
Thanks

I'm afraid annotation objects are properties of figures and NOT axes, as such its harder to customize the position of each annotation objects because no matter how many subplots you have, they are all part of the same figure and you need to specify their position relatively to the figure coordinate system.
Therefore, you can manually set the position of each text box in your code depending on the subplot it belongs to...
Simple example:
clear
clc
close all
figure('Units','normalized'); %// new figure window
for k = 1:2
str = sprintf('Subplot %d',k);
subplot(1,2,k)
plot(rand(1,10));
%// Customize position here
hAnnot(k) = annotation('textbox', [k*.4-.2 .6 .1 .1],...
'String', str,'FontSize',14);
end
Which looks like this:
Its not very elegant but I'm personally not aware of any other option if you do need to use annotations objects. A less cumbersome alternative would be to use a simple text objects, which are properties of axes and therefore much more friendly to position :)
Hope that helps!

Related

How to have diferent markers and line styles while plotting same variable from multiple data files?

How can I have diferent markers or line styles when I am plotting same variable from 8 diferent data files in one figure?
I have got my code that reads multiple excel files and it is perfectly fine with plotting the variable I call for from all 8 diferent excel files.
Although I already have the plot with different colors that I have defined. However, somehow, I cannot define any marker or diferent Line Styles. I have attached my plotting codes below; please also see the figure
ax = gca;
grid on;
hold on
plot(Pin_dBm,Pout_Meas_dbm,"LineWidth",2)
%ax.LineStyleOrder={'-o','-+','-*','-x','-s','-d','-v','->'};
ax.ColorOrder=[1 0 0; 1 0 1; 0 1 0; 0.4660 0.6740 0.1880; 0 0 1; 0.3010 0.7450 0.9330; 0.8500 0.3250 0.0980; 0.9290 0.6940 0.1250]
ylabel('Output Power [dBm]','Color','K')
xlabel('Input Power [dBm]')
title('Output Power comparison - ON mode (0V)', 'Color', 'k')
legend('3F50Sa1','3F100Sa1', '5F50Sa1','5F100Sa1','7F50Sa1','7F100Sa1','9F50Sa1','9F100Sa1','location', 'bestoutside')
To change trace (or marker) properties you have to use the plot handle, not the figure handle, to change line properties like LineWidth and Color.
To grab the plot handle you have to plot like this
hf1=figure(1)
ax = gca;
grid on;
hp1=plot(Pin_dBm,Pout_Meas_dbm)
hp1.LineWidth=2
hp1.Color='r' % red
..
hf1 is the figure handle, not the trace or curve or graph handle.
The figure is the frame containing traces.
You don't have to, this is ok
hf1=figure
but it's good practice to number figures figure(n) as soon as generated, it helps reading code if later on someone has to findout what figure handle belongs to what figure.
now you tell the graph container, the figure with handle hf1 not to remove the 1st trace regardless of what you plot next:
hold(ax1,'on')
and now, with a for loop or one by one, or in any other way you choose, you can add more traces onto same figures changing the properties you choose using a different plot handle
hp2=plot(Pin_dBm2,Pout_Meas_dbm2)
hp2.LineWidth=1.5
hp1.Color='b' % blue
..
and as you mention in your question you can send the same variable updated with different input data or file
update_Pin_dBm;
update_Pout_Meas_dbm;
If you do not update Pin_dBm and-or Pout_Meas_dbm the next plot with different properties may be identical or similar and overlap the previous trace.
hp3=plot(Pin_dBm,Pout_Meas_dbm)
hp3.LineWidth=1
hp1.Color=[0 1 1] % cyan
The figure handle hf1 could still be used to change trace properties, because as the container to the plot, has as children property the handle to the plot. But no one uses what is otherwise a rather long Java-like expression
Note: The term marker is generally used, not for the graph line, the plot, but for the pointers on the graph line that scopes and also MATLAB allows to put, to read a particular (x,y).
If you find this answer useful, would you please be so kind to accept it?
Thanks for reading my answer.

Multiple Subplots with (Sub-)Subplots (MATLAB)

I aim to create 14 subplots with four figures in each subplot. Unfortunately, I do not have any example code to show, as I have not a clue how to go about this. A couple ideas that have popped into my head about how I can go about accomplishing this. One is to create multiple figures separately, then merge them into a single figure. Another is to create subplots with multiple subplots nested inside of them; however, again, I have not a clue how I could go about accomplishing this.
You'll probably find that you are trying to fit too much data onto one figure, and the plots will be too small to see anything of interest. However, a techniques that works, and will give you the option of having individual figures, and combining them into one figure if you wish, is to use individual figures each with a panel on it, then use copyobj to copy to your main figure.
For example,
% Create first figure
hf_sub(1) = figure(1);
hp(1) = uipanel('Parent',hf_sub(1),'Position',[0 0 1 1]);
subplot(2,2,1,'Parent',hp(1));
plot(1:10);
subplot(2,2,2,'Parent',hp(1));
surf(peaks);
subplot(2,2,3,'Parent',hp(1));
membrane;
subplot(2,2,4,'Parent',hp(1));
plot(rand(1,100));
% Create second figure
hf_sub(2) = figure(2);
hp(2) = uipanel('Parent',hf_sub(2),'Position',[0 0 1 1]);
subplot(2,2,1,'Parent',hp(2));
histogram(randn(1,1000));
subplot(2,2,2,'Parent',hp(2));
membrane
subplot(2,2,3,'Parent',hp(2));
surf(peaks)
subplot(2,2,4,'Parent',hp(2));
plot(-(1:10));
% Create combined figure
hf_main = figure(3);
npanels = numel(hp);
hp_sub = nan(1,npanels);
% Copy over the panels
for idx = 1:npanels
hp_sub(idx) = copyobj(hp(idx),hf_main);
set(hp_sub(idx),'Position',[(idx-1)/npanels,0,1/npanels,1]);
end
You may need to be more careful with positioning of the panels, and may want to create the individual figure with their visibility set to off, but the above gives the main idea.

Matlab doesn't save the new dimension of the plot

I'm trying to save a figure with a no-default dimension, but I always obtain the default size plot.
figure
for i=1:6
for j=1:4
subplot(6,4,j+(i-1)*4)
[...]
end
end
w=600; h=800;
set(gcf,'Position',[30 60 w h]);
set(gcf, 'PaperUnits', 'centimeters');
set(gcf,'PaperPositionMode','manual')
print('test','-depsc');
It is mainly a 6-by-4 subplot. I looked for a solution on internet, I found many comments about Position, PaperUnits, PaperPositionMode, but none has worked so far. The only solution that works is when I export as .fig.
What I actually realized, is that after the set(gcf,'Position',[30 60 w h]) the window dimension of the plot is correct, but the subplot are squeezed like when the dimension is the default. If I just insert a pause and manually resize the window (even by almost nothing), the subplots expand nicely within the larger window. But still, with the print command the result is not the desired one.
I tried also with saveas and I got the same result.
Ah, if I manually save the figure, it works perfectly, but, of course, I need to automatize the process!
Thanks for your help!
Although i can't reproduce this behaviour as MATLAB 2014b automatically handles axes resizing, i'll still post an answer, that may need some adjustments.
Basically, what you need to do is :
% Get a handle to your figure object
Myfig=gcf;
% Get all of your figure Children - Warning : if you have a global
% legend in your figure, it will belong to your figure Children and you
% ll have to ignore it
AllChildren=get(Myfig,'Children');
MyAxes=findobj(AllChildren,'type','axes');
% Now you have your axes objects, whose Position attributes should be in
% normalized units. What you need to do now is to store these positions
% before changing the size of your figure, to reapply them after
% resizing (the beauty of normalized positions).
Positions=zeros(size(MyAxes,1),4);
for ii=1:size(MyAxes,1)
Positions(ii,:)=get(MyAxes(ii),'Position');
end
% Resize your figure
w=600;
h=800;
set(gcf,'Position',[30 60 w h]);
% Reuse the positions you stored to resize your subplots
for ii=1:size(MyAxes,1)
set(MyAxes(ii),'Position',Positions(ii,:));
end
This should do the trick.

How to specify the axis size when plotting figures in Matlab?

Suppose that I have 2 figures in MATLAB both of which plot data of size (512x512), however one figure is being plotted by an external program which is sets the axis parameters. The other is being plotted by me (using imagesc). Currently the figures, or rather, the axes are different sizes and my question is, how do I make them equal?.
The reason for my question, is that I would like to export them to pdf format for inclusion in a latex document, and I would like to have them be the same size without further processing.
Thanks in Advance, N
Edit: link to figures
figure 1: (big)
link to smaller figure (i.e. the one whose properties I would like to copy and apply to figure 1)
For this purpose use linkaxes():
% Load some data included with MATLAB
load clown
% Plot a histogram in the first subplot
figure
ax(1) = subplot(211);
hist(X(:),100)
% Create second subplot
ax(2) = subplot(212);
Now link the axes of the two subplots:
linkaxes(ax)
By plotting on the second subplot, the first one will adapt
imagesc(X)
First, you have the following:
Then:
Extending the example to images only:
load clown
figure
imagesc(X)
h(1) = gca;
I = imread('eight.tif');
figure
imagesc(I)
h(2) = gca;
Note that the configurations of the the first handle prevail:
linkaxes(h)
1.Get the handle of your figure and the axes, like this:
%perhaps the easiest way, if you have just this one figure:
myFigHandle=gcf;
myAxHandle=gca;
%if not possible, you have to search for the handles:
myFigHandle=findobj('PropertyName',PropertyValue,...)
%you have to know some property to identify it of course...
%same for the axes!
2.Set the properties, like this:
%set units to pixels (or whatever you prefer to make it easier to compare to the other plot)
set(myFigHandle, 'Units','pixels')
set(myAxHandle, 'Units','pixels')
%set the size:
set(myFigHandle,'Position',[x_0 y_0 width height]) %coordinates on screen!
%set the size of the axes:
set(myAxHandle,'Position',[x_0 y_0 width height]) %coordinates within the figure!
Ok, based on the answer of #Lucius Domitius Ahenoba here is what I came up with:
hgload('fig1.fig'); % figure whose axis properties I would like to copy
hgload('fig2.fig');
figHandles = get(0,'Children');
figHandles = sort(figHandles,1);
ax(1) = findobj(figHandles(1),'type','axes','-not','Tag','legend','-not','Tag','Colorbar');
ax(2) = findobj(figHandles(2),'type','axes','-not','Tag','legend','-not','Tag','Colorbar');
screen_pos1 = get(figHandles(1),'Position');
axis_pos1 = get(ax(1),'Position');
set(figHandles(2),'Position',screen_pos1);
set(ax(2),'Position',axis_pos1);
This is the 'before' result:
and this is the 'after' result:
Almost correct, except that the aspect ratios are still off. Does anybody know how to equalize everything related to the axes? (I realize that I'm not supposed to ask questions when posting answers, however adding the above as a comment was proving a little unwieldy!)

How to create a new figure in MATLAB?

Usually when I plot in MATLAB, it always draws on the same figure. How do I make it draw in a new figure?
I know it is pretty elementary, but I'm not finding it using Google Search.
figure;
plot(something);
or
figure(2);
plot(something);
...
figure(3);
plot(something else);
...
etc.
While doing "figure(1), figure(2),..." will solve the problem in most cases, it will not solve them in all cases. Suppose you have a bunch of MATLAB figures on your desktop and how many you have open varies from time to time before you run your code. Using the answers provided, you will overwrite these figures, which you may not want. The easy workaround is to just use the command "figure" before you plot.
Example: you have five figures on your desktop from a previous script you ran and you use
figure(1);
plot(...)
figure(2);
plot(...)
You just plotted over the figures on your desktop. However the code
figure;
plot(...)
figure;
plot(...)
just created figures 6 and 7 with your desired plots and left your previous plots 1-5 alone.
The other thing to be careful about, is to use the clf (clear figure) command when you are starting a fresh plot. Otherwise you may be plotting on a pre-existing figure (not possible with the figure command by itself, but if you do figure(2) there may already be a figure #2), with more than one axis, or an axis that is placed kinda funny. Use clf to ensure that you're starting from scratch:
figure(N);
clf;
plot(something);
...
As has already been said: figure will create a new figure for your next plots. While calling figure you can also configure it. Example:
figHandle = figure('Name', 'Name of Figure', 'OuterPosition',[1, 1, scrsz(3), scrsz(4)]);
The example sets the name for the window and the outer size of it in relation to the used screen.
Here figHandle is the handle to the resulting figure and can be used later to change appearance and content. Examples:
Dot notation:
figHandle.PaperOrientation = 'portrait';
figHandle.PaperUnits = 'centimeters';
Old Style:
set(figHandle, 'PaperOrientation', 'portrait', 'PaperUnits', 'centimeters');
Using the handle with dot notation or set, options for printing are configured here.
By keeping the handles for the figures with distinc names you can interact with multiple active figures. To set a existing figure as your active, call figure(figHandle). New plots will go there now.
Another common option is when you do want multiple plots in a single window
f = figure;
hold on
plot(x1,y1)
plot(x2,y2)
...
plots multiple data sets on the same (new) figure.
As simple as this-
figure, plot(yourfigure);