Related
I have I have a data file which has 3 columns, 1st column is the field for the data, or you can say different index. 2nd column is the x-axis data, and the 3rd column is the y-axis data. Now I have similar data files for different variables like 8 files. I want to plot all the graph in one figure in MATLAB. For my problem, I am showing only one subplot. This subplot data file should plot 5 "line plots" for 5 indexes (1st column). But when I plot it as subplot it shows only 1 plot. here is my code in the below:
% open Zdiff Odd Mode data file
fid = fopen('Data_test.txt');
% Read data in from csv file
readData = textscan(fid,'%f %f %f','Headerlines',1,'Delimiter',',');
fclose(fid);
% Extract data from readData
index_Data = readData{1,1}(:,1);
% Identify the unique indices
uni_idx=unique(index_Data);
xData = readData{1,2}(:,1);
yData = readData{1,3}(:,1);
% Plot Data
f = figure;
%Top Title for all the subplots
p = uipanel('Parent',f,'BorderType','none');
p.Title = 'Electrical Characteristics';
p.TitlePosition = 'centertop';
p.FontSize = 14;
p.FontWeight = 'bold';
cla; hold on; grid on, box on;
ax1 = subplot(2,4,1,'Parent',p);
% Loop over the indices to plot the corresponding data
for i=1:length(uni_idx)
idx=find(index_Data == uni_idx(i));
plot(xData(idx,1),yData(idx,1))
end
The plot results like below:
When I plot the data as a full figure, the plot is perfect. But as I have lots of data to plot in one figure as subplots, I need to know what is wrong in my subplot code.
Here is my code for the whole figure of the data without the subplot
Before plotting code it is same as before:
% Plot Data
f1 = figure(1);
cla; hold on; grid on;
% Loop over the indices to plot the corresponding data
for i=1:length(uni_idx)
idx=find(index_Data == uni_idx(i));
plot(xData(idx,1),yData(idx,1))
end
The resulting figure is below:
What is wrong with my plotting code in the subplot? Can anyone help me out?
This is your sequence of commands, and what they do:
f = figure;
Creates an empty figure, there are no axes yet defined here.
cla
Clears the current axes, since there is no current axes, it creates one.
hold on
Sets the "hold" property on the current axes
grid on, box on
Sets some other properties of the current axes
ax1 = subplot(2,4,1,'Parent',p);
Creates new axes. Because it overlays the previously created axes, those are deleted.
plot(xData(idx,1),yData(idx,1))
Plots to the current axes (i.e. the one created by subplot). These axes don't have the "hold" property set, so subsequent plot commands will overwrite the data plotted here.
The solution, as suggested by Ander in a comment, is to set the "hold" property of the axes created by subplot. Replace:
cla; hold on; grid on, box on;
ax1 = subplot(2,4,1,'Parent',p);
with:
ax1 = subplot(2,4,1,'Parent',p);
hold on; grid on, box on;
(note that cla is not necessary, since you're drawing to a new, empty figure).
I have an spectral absorbance matrix in xls format which has column 1 as wavelength, and columns 2:3 as the associated absorbance spectra for particles from depth1 in water column. 2:3 are duplicates so they have to be plotted together. Next i have columns 4:5 as once again duplicate absorbance spectra for particles from depth2 in water column. Then data for depth3, depth4 etc. The matrix is 1001 rows by 13 columns.
I would like have 3 subplots (depth1, depth2 and depth3) in one figure with each subplot holding the 2 duplicate spectra of each depth.
I tried to follow the excellent responses to this question but this gives me one line per subplot but i want to plot two lines (duplicate spectra). So I did the following and it works but I can only get 3 subplots:
[num,txt,raw]=xlsread('ANACONDAS2010-ST1.xls');
legendCell=cellstr(txt);
figure
subplot(3,1,1)
plot(num(:,1), num(:,2:3),'r');grid on; box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(2:3)),legend boxoff
subplot(3,1,2)
plot(num(:,1), num(:,4:5),'b');grid on; box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(4:5)), legend boxoff
subplot(3,1,3)
plot(num(:,1), num(:,6:7),'g');grid on; box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(6:7)), legend boxoff
title('STATION 1','fontweight','bold','fontsize',16);
But as you can see this gives me only 1 figure with 3 subplots and the rest od the depths (d4, d5, d6) remain unplotted as i havent been able to specifiy them,
Because my script is long and cumbersome I would have liked to run this through a loop but I couldn't figure out how to do it in spite of battling with the code provided in the 2nd answer which I kind of understood unlike the first one.
Updated answer
Inserted version V2 of the code
Version V2 of the code allows displaying unlimited pairs of data, also it is even simpler than V1.
% Generation of example data
num=1:33;
number_of_data_colums=14;
num=[num' rand(length(num),number_of_data_colums)];
% Generation of legend string
for i=1:number_of_data_colums
legendCell{i}=['Absor. ' num2str(i)];
end
% Get the size of data to be plotted (columns from 2 to ...)
[r,c]=size(num);
n_data=floor((c-1)/2);
% Define the number of data to be plotted in each subplt
data_x_plot=2;
% Consistency check: if the number of column data is not even generate an
% error message and exit
if(n_data*2 ~= (c-1))
error('Number of data columns is not even')
else
% Define the number of subplot of each figure
n_sub_plot=3;
% Subplot and figure counters
s_plot_cnt=1;
fig_cnt=1;
% Create the first figure
figure
% External loop on figures
for i=2:2:n_data*2
% If three subplot have been added to a figure, open a new figure
if(s_plot_cnt == 4)
% The Title is assigne to the first subplot of each figure
title(ax(fig_cnt,1),['STATION ' num2str(fig_cnt)],'fontweight','bold','fontsize',16);
s_plot_cnt=1;
fig_cnt=fig_cnt+1;
figure
end
ax(fig_cnt,s_plot_cnt)=subplot(n_sub_plot,1,s_plot_cnt);
% The indices of columns to be plotted are computed automatically
plot(num(:,1), num(:,i:i+1));
grid on;
box on;
xlabel('Wavelength')
ylabel('Absorbance')
% add legend
legend(legendCell(i-1:i),-1)
% Increment subplot's counter
s_plot_cnt=s_plot_cnt+1;
% legend boxoff
end
end
% Add the last title
title(ax(fig_cnt,1),['STATION ' num2str(fig_cnt)],'fontweight','bold','fontsize',16);
Previous answer and
Version V1 of the code
I'm not sure I've understood your question, nevertheless, if you have 6 pairs of data and you want 3 subplot, you need 2 figures.
I've modified your original script in order to automatically determine the number of figure you need, generate the subplots and plot 2 set of data in each of them.
Updated code - now with legends
% Generation of example data
num=1:33;
num=[num' rand(length(num),12)];
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% UPDATED CODE STARS HERE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Generation of legend string
legendCell{1}='Wavel';
for i=2:13
legendCell{i}=['Absor. ' num2str(i)];
end
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% UPDATED CODE ENDS HERE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Get the size of data to be plotted
[r,c]=size(num);
% Define the number of data to be plotted in each subplt
data_x_plot=2;
% Define the number of subplot of each figure
n_sub_plot=3;
% Evaluate the number of figures to be created
n_fig=(c-1)/(data_x_plot*n_sub_plot);
% Define the index of data columns
idx=[2:2:c-1];
idx=reshape(idx,n_sub_plot,data_x_plot)';
% External loop on figures
for i=1:n_fig
figure
% Internal loop on subplots
for j=1:n_sub_plot
% The subplot indices are computed automatically
ax(i,j)=subplot(n_sub_plot,1,j);
% The indices of columns to be plotted are computed automatically
plot(num(:,1), num(:,idx(i,j):idx(i,j)+1));
grid on;
box on;
xlabel('Wavelength')
ylabel('Absorbance')
% add legend
legend(legendCell(idx(i,j):idx(i,j)+1),-1)
% legend boxoff
end
% The Title is assigne to the first subplot of each figure
title(ax(i,1),['STATION ' num2str(i)],'fontweight','bold','fontsize',16);
end
Given a set of 12 columns of data, this is the output:
Updated graphs, with legends
Maybe you should use Hold to retain current plot when adding new plots.
So your code should be like this:
[num,txt,raw]=xlsread('ANACONDAS2010-ST1.xls');
legendCell=cellstr(txt);
figure
subplot(3,1,1)
plot(num(:,1), num(:,2),'r');grid on;
hold on;
plot(num(:,1), num(:,3),'m');
box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(2:3)),legend boxoff
subplot(3,1,2)
plot(num(:,1), num(:,4),'b');
hold on;
plot(num(:,1), num(:,5),'c');
grid on; box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(4:5)), legend boxoff
subplot(3,1,3)
plot(num(:,1), num(:,6),'g');
hold on;
plot(num(:,1), num(:,7),'k');
grid on; box on; xlabel('Wavelength'), ylabel('Absorbance'),legend(legendCell(6:7)), legend boxoff
title('STATION 1','fontweight','bold','fontsize',16);
I have created two plots on a single GUI file in matlab. I wish to label each plot as follows;
first plot: the label of x axis is position, y axis is concentration:
second plot: the label of x axis is time, y axis is concentration:
The problem is that the second plot is not getting its label
Code:
C = {'k','b','r','g','y',[.5 .6 .7],[.8 .2 .6]}; % Cell array of colorss.
phandles = plot(tott,XX(rown,:),'color',C{ind},'parent',handles.axes2);
hold on
xlabel('time');
ylabel('Concentration (mol/m3)');
title('concentration at given position vs time') axis([tott(1),tott(length(tott)),0,conc])
The xlabel article shows you how to change the labels using the plot handle (in this case your phandles). Get the handle of your 2nd plot and use the following toy example as a reference or post your code for your second plot so I can clarify.
ax1 = subplot(2,1,1);
plot((1:10).^2)
xlabel(ax1,'Population')
ax2 = subplot(2,1,2);
plot((1:10).^3)
The variable returned when calling subplot is the handle for the plot. Essentially if your 2nd handle is called phandles2, then you can simply use:
xlabel(phandles2,'X Axis label for Plot 2');
ylabel(phandles2,'X Axis label for Plot 2');
Please post your code for your 2nd plot for a more detailed answer.
I am having trouble matching my graph with my axis. The first two plots work and the second two do not. I am trying to plot Temperature versus Pressure for two Argo floats and then Salinity versus Pressure. Here is my code:
% First Plot
subplot(221);
plot(float1winter.T,float1winter.P,'b');
hold on;
plot(float1summer.T,float1summer.P,'r');
hold on;
tempAdiff = abs(float1summer.T-float1winter.T)
plot(tempAdiff,float1summer.P,'--k');
hold on;
set(gca,'ydir','reverse');
title('Argo Float #1901440 Temp Profiles');
legend(['float1winter','float1summer','tempAdiff'],{'11-29-2013','07-01-2013','Temperature Difference'},'location','southwest');
xlabel('Temperature (°C)');
ylabel('Pressure');
shg;
% Second Plot
subplot(222);
plot(float2winter.S,float2winter.P,'m');
hold on;
plot(float2summer.S,float2summer.P,'c');
hold on;
set(gca,'ydir','reverse');
title('Argo Float #1901440 Salinity Profiles');
legend(['float2winter','float2summer'],{'11-29-2013','06-02-2013'},'location','southwest');
xlabel('Salinity (psu)');
ylabel('Presure');
shg;
% Third Plot
subplot(223);
% Matrix demensions did not agree bewteen winter and summer profiles. The summer profile was 71 x 2 and the winter was 70 x 2. I tried "reshape"
% and that didn't work. So I changed the vector of float3summer.T to
% float3bsummer.T with an array of 70 x 2
float3bsummer.T = float3summer.T(1:70,1:2);
float3bsummer.P = float3summer.P(1:70,1:2);
plot(float3winter.T,float3winter.P,'Linewidth',1,'color','blue');
hold on;
plot(float3bsummer.T,float3bsummer.P,'Linewidth',1,'color','red');
hold on;
tempdiff = abs(float3bsummer.T-float3winter.T)
plot(tempdiff,float3bsummer.P,'--k');
hold on;
set(gca,'ydir','reverse'); % this line reverses the y-axis so that depth increases downward
title('Argo Float #1901415 Tempearture Profiles');
hold on;
summerfloat = plot(float3bsummer.T,float3bsummer.P,'r');
legend(['float3winter.T','summerfloat','tempdiff'],{'12-03-2013','07-03-2013','Temp Diff'},'location','southeast');
xlabel('Temperature (°C)');
ylabel('Pressure');
axis ([-1,4,0,2000]);
shg;
% Fourth Plot
subplot(224);
plot(float3winter.S,float3winter.P,'g');
% Changed matrix dimensions for Salinity of Summer
float3bsummer.S = float3summer.S(1:70,1:2);
float3bsummer.P = float3summer.P(1:70,1:2);
plot(float3bsummer.S,float3bsummer.P,'.b');
hold on;
set(gca,'ydir','reverse');
title('Argo Float #1901415 Salinity Profiles');
h4 = plot(float3winter.S,float3winter.P,'g');
hold on;
h5 = plot(float3bsummer.S,float3bsummer.P,'.b');
hold on;
legend(['float3winter','float3bsummer.T'],{'12-03-2013','07-03-2013'},'location','southwest');
xlabel('Salinity (psu)');
ylabel('Pressure');
axis ([33.8,34.8,0,2000]);
shg;
% Save File to Desktop
set(gcf,'color','w');
saveas(gcf,'~/Desktop/hw1_figure1.pdf','pdf');![enter image description here][1]
I guess that you're trying to associate the set of strings for your legend, {'11-29-2013','07-01-2013','Temperature Difference'}, with the plots made from the variables ['float1winter','float1summer','tempAdiff'].
However, this isn't how legend works. MATLAB has no way of associating the plot produced by plot(float1winter.T,float1winter.P,'b'); to the string float1winter. If you want to specify which plots go with which legend entries, you need to pass the object handles of the plots to legend, which is easiest done by returning the handles when you plot originally:
h(1) = plot(float1winter.T,float1winter.P,'b');
hold on;
h(2) = plot(float1summer.T,float1summer.P,'r');
h(3) = plot(tempAdiff,float1summer.P,'--k');
legend(h,{'11-29-2013','07-01-2013','Temperature Difference'});
Side note: you only need to call hold on once per axis - so once for each subplot but not after every plot call.
Alternatively, you can not give handles at all; legend will assign the text to the plots in the order that they were plotted:
legend({'11-29-2013','07-01-2013','Temperature Difference'})
Understanding graphics handles allows you a lot more control over plots, especially if you might want to make small adjustments to them. For example, if I decide that I want the first plot to be green rather than blue, then I can just do:
set(h(1),'Color','g');
This will change the plot color and the legend changes to match automagically. To see a list of all the properties of an object, use get with only the handle. You can set more than one property at a time. For example:
get(h(1))
set(h(1),'DisplayName','Winter','LineWidth',3,'Marker','x')
I want to show only the legend for a group of data in MATLAB.
The reason I want to do this is that I want to export the legend to .eps, but I only want the legend, not the plots.
Is there a way to turn off the plots and remove them from the figure, but still show just the legend centered?
This seems to do the trick:
plot(0,0,'k',0,0,'.r') %make dummy plot with the right linestyle
axis([10,11,10,11]) %move dummy points out of view
legend('black line','red dot')
axis off %hide axis
There is probably a lot of whitespace around the legend. You could try to resize the legend by hand, or save the plot and use some other program to set the bounding box of the eps.
The chosen solution by Marcin doesn't work anymore for R2016b because MATLAB's legend will automatically gray out invisible plots like this:
Neither turning off the automatic update of the legend nor changing the TextColor property afterwards fixes this. To see that, try Marcin's modified example:
clear all; close all;
figHandle = figure;
p1 = plot([1:10], [1:10], '+-');
hold on;
p2 = plot([1:10], [1:10]+2, 'o--');
legHandle = legend('text1', 'text2');
%turn off auto update
set(figHandle,'defaultLegendAutoUpdate','off');
set(p1, 'visible', 'off');
set(p2, 'visible', 'off');
set(gca, 'visible', 'off');
%set legend text color to black
legHandle.TextColor = [0 0 0];
The result remains the same. (To avoid throwing my laptop through the window) and fix this without zooming, which might leave fragments of the plot in the way, I wrote a function that fixes the legend and saves it to a file (with frame):
function saveLegendToImage(figHandle, legHandle, ...
fileName, fileType)
%make all contents in figure invisible
allLineHandles = findall(figHandle, 'type', 'line');
for i = 1:length(allLineHandles)
allLineHandles(i).XData = NaN; %ignore warnings
end
%make axes invisible
axis off
%move legend to lower left corner of figure window
legHandle.Units = 'pixels';
boxLineWidth = legHandle.LineWidth;
%save isn't accurate and would swallow part of the box without factors
legHandle.Position = [6 * boxLineWidth, 6 * boxLineWidth, ...
legHandle.Position(3), legHandle.Position(4)];
legLocPixels = legHandle.Position;
%make figure window fit legend
figHandle.Units = 'pixels';
figHandle.InnerPosition = [1, 1, legLocPixels(3) + 12 * boxLineWidth, ...
legLocPixels(4) + 12 * boxLineWidth];
%save legend
saveas(figHandle, [fileName, '.', fileType], fileType);
end
Tips for use:
fileType is a string that specifies a valid argument for saveas(), such as 'tif'.
Use it after you have plotted everything you want to appear in your legend, but without extra stuff. I'm not sure if all potential elements of a plot contain an XData member that isn't empty.
Add other types of displayed things that you want deleted, but are not of type line if there are any.
The resulting image will contain the legend, its box, and a little bit of space around it the legend is smaller than the minimum width (see Minimum Width of Figures in MATLAB under Windows). However, this is usually not the case.
Here is a complete example using the function from above:
clear all; close all;
fig = figure;
p1 = plot([1:10], [1:10], '+-');
hold on;
p2 = plot([1:10], [1:10]+2, 'o--');
legendHandle = legend('myPrettyGraph', 'evenMoreGraphs');
saveLegendToImage(fig, legendHandle, 'testImage', 'tif');
I think that you need to "hide" the elements you don't want in your plot, leaving out only the legend. For example,
clear all; close all;
figure;
p1 = plot([1:10], [1:10], '+-');
hold on;
p2 = plot([1:10], [1:10]+2, 'o--');
legend('text1', 'text2');
set(p1, 'visible', 'off');
set(p2, 'visible', 'off');
set(gca, 'visible', 'off');