I am creating a program where the user can select multiple files to plot and compare data. The program can properly graph the data, the problem I have encountered is within the legend.
I tried posting an image, however I do not have a high enough reputation. So I will try to explain the graph in detail. Two sets of points are plotted (two matrices of different sizes). The curves are labeled by the user, and in this example they are: "PS, Cs" and "PS, Po."
The program successfully plots the "PS, Cs" curve with the red squares then plots the "PS, Po" with the blue circles however the legend continues to show the red squares for both sets of points. Below is the loop within the code that does the plotting.
fig = small_group_struct;
mystyles = {'bo','rs','go'};
mat_len = size(small_group_struct,2);
for q = 1:mat_len
plotstyle = mystyles{mod(q,mat_len)+1};
semilogy(1:size(small_group_struct(1).values),small_group_struct(q).values,plotstyle);
hold all;
[~,~,~,current_entries] = legend;
legend([current_entries {small_group_struct(q).name}]);
end
hold off;
%legend(small_group_struct.values,{small_group_struct.name});
Other threads that I have seen suggested putting the plot command into a handle but since each set of points is a nxm matrix of different sizes, the program does not like this.
Also, as mentioned at the beginning the user will select the number of files and while this is typically two, it will not always be the case and why I am trying to plot it within a for loop.
Any suggestions and comments would be greatly appreciated.
EDIT: I now have a high enough reputation to post images, so here is a screenshot of the graph
You can use handles to specify what labels go with what data in the legend.
You say that "each set of points is a nxm matrix of different sizes." Plotting an mxn matrix creates n line objects and returns n handles. You can keep track of all of these handles and assign labels to them when you create the legend.
Here's an example:
% Cell array of data. Each element is a different size.
data = {rand(100, 1), rand(150, 2)};
styles = {'ro', 'gs'};
% Vector to store the handles to the line objects in.
h = [];
figure
hold on
for t = 1:length(data)
% plots the data and stores the handle or handles to the line object.
h = [h; semilogx(data{t}, styles{t})];
end
% There are three strings in the legend because a total of three columns of data are
% plotted. One column of data is from the first element of data, two columns of data
% are from the second element of data.
strings = {'data1' ,'data2', 'data3'};
legend(h,strings)
You might want to do something different with the legend but hopefully this will get you started.
Related
I have a plot in which there are a few noise components. I am planning to select data from that plot preferably above a threshold in my case I am planning to keep it at 2.009 on the Y axis. And plot the lines going only above it. And if anything is below that i would want to plot it as 0.
as we can see in the figure
t1=t(1:length(t)/5);
t2=t(length(t)/5+1:2*length(t)/5);
t3=t(2*length(t)/5+1:3*length(t)/5);
t4=t(3*length(t)/5+1:4*length(t)/5);
t5=t(4*length(t)/5+1:end);
X=(length(prcdata(:,4))/5);
a = U(1 : X);
b = U(X+1: 2*X);
c = U(2*X+1 : 3*X);
d = U(3*X+1 : 4*X);
e = U(4*X+1 : 5*X);
figure;
subplot (3,2,2)
plot(t1,a);
subplot (3,2,3)
plot(t2,b);
subplot(3,2,4)
plot(t3,c);
subplot(3,2,5)
plot(t4,d);
subplot(3,2,6)
plot(t5,e);
subplot(3,2,1)
plot(t,prcdata(:,5));
figure;
A=a(a>2.009,:);
plot (t1,A);
This code splits the data (in the image into 5 every 2.8 seconds, I am planning to use the thresholding in first 2.8 seconds. Also I had another code but I am just not sure if it works as it took a long time to be analysed
figure;
A=a(a>2.009,:);
plot (t1,A);
for k=1:length(a)
if a(k)>2.009
plot(t1,a(k)), hold on
else
plot(t1,0), hold on
end
end
hold off
The problem is that you are trying to plot potentially several thousand times and adding thousands of points onto a plot which causes severe memory and graphical issues on your computer. One thing you can do is pre process all of the information and then plot it all at once which will take significantly less time.
figure
threshold = 2.009;
A=a>threshold; %Finds all locations where the vector is above your threshold
plot_vals = a.*A; %multiplies by logical vector, this sets invalid values to 0 and leaves valid values untouched
plot(t1,plot_vals)
Because MATLAB is a highly vectorized language, this format will not only be faster to compute due to a lack of for loops, it is also much less intensive on your computer as the graphics engine does not need to process thousands of points individually.
The way MATLAB handles plots is with handles to each line. When you plot a vector, MATLAB is able to simply store the vector in one address and call it once when plotting. However, when each point is called individually, MATLAB has to store each point in a separate location in memory and call all of them individually and graphically handle each point completely separately.
Per request here is the edit
plot(t1(A),plot_vals(A))
I'm fairly new to Matlab so any help would be appreciated.
I'm trying to write a function using simple logic operators to create a number of 2D scatter graphs, the problem I've been having is that I cannot work out how to use a input from the user (the number of figures) to actually create that number of figures.
*edit (Just for the sake of clarity I'm plotting multiple sets of data ie columns on each figure but the important bit is that there will be multiple figures as the user specifies how many figures they want, this is the bit I cannot understand. I understand how to use hold on to plot more than one graph on each figure but how do I vary the number of figures depending on the input of the user?)
The user inputs are a matrix with dimensions 4000x30 (this will remain constant for my use) and the number of figures (this will change from 1-30) to plot from this data set. Each column represents a different sensor so the columns represent 1 set of data each.
The simpler the answer the better as I'm not a very experienced coder.
Thanks
GibGib
See if this works for you:
Data = rand(40,30); %// Just a small data set for testing.
%// Ask user how many figures are desired
prompt = {'Enter desired number of figures:'};
dlg_title = 'Input';
num_lines = 1;
def = {'5'};
NumFigures = inputdlg(prompt,dlg_title,num_lines,def);
%// Get # of figures. If the entry is not valid (i.e. remainder of division 30/entry is not 0), ask again.
while rem(size(Data,2),str2double(NumFigures{1})) ~= 0
NumFigures = inputdlg(prompt,dlg_title,num_lines,def);
end
NumFigures = str2double(NumFigures{1}); %// Convert to number
ColPerFig = size(Data,2)/NumFigures; %// Number of columns to plot per figure
ColStart = 1:ColPerFig:size(Data,2) %// Indices of the starting columns to plot
ColStart looks like this:
ColStart =
1 7 13 19 25
So its easier in the loop to index into Data and fetch the appropriate values.
%// Plot
for k = 1:NumFigures;
hFig(k) = figure;
plot(Data(:,ColStart(k):ColStart(k)+ColPerFig-1));
end
Ok, it seems like what you are asking is that you have this data matrix M, where the user defines U, and you to plot U number of plots where each plot is the 2D scatter of U columns that corresponds to M?
in that case, will this do?
figure;
hold on %is optional depending how you want your plot
for i = 1:U
plot(M(:,i))
end
If this is not what you are looking for, please specify your question further.
I am trying to plot 3 vectors onto matlab GUI in a serial object's callback.
I want to plot this on axes handle but the problem is it only plot last vector;
plot(handles.axes1,sensor1,'r');
plot(handles.axes1,sensor2,'b');
plot(handles.axes1,sensor3,'g');
I searched on internet and find that this issue can be solved with hold on and hold of feature so I tried this
plot(handles.axes1,sensor1,'r');
hold on ;
plot(handles.axes1,sensor2,'b');
plot(handles.axes1,sensor3,'g');
hold off;
but in this case a new figure is opened(dont know why) and again only the last plot is drawn.
I am stucked. If any one have idea of what would be the issue?
Thanks
I'm not sure why your first try using "hold" didn't work. Seems like it should have.
But in any case, you can get the desired behavior in a single command:
plot(handles.axes1,length(sensor1),sensor1,'r',...
length(sensor2),sensor2,'b',...
length(sensor3),sensor3,'g');
This specifies both an X = length(sensor_) and a Y = sensor_ to the plot command. When you only give plot a Y input, it assumes an X of length(Y). But you can't combine multiple traces in a single plot command by giving only the Y input for each, because it will try to treat the inputs as X,Y pairs.
As the vectors are the same length we can simply combine them as the columns of a matrix and then plot the matrix
plot(handles.axes1,[sensor1',sensor2',sensor3'])
However these will have the default colour order. Without specifying x values setting colors within the plot command is tricky. However (luckily) the default order starts:
blue,green,red...
so swapping the column order will plot the lines with the colours requested
plot(handles.axes1,[sensor2',sensor3',sensor1'])
(this assumes the vectors are rows, if they are columns don't transpose them)
Problem
Running out of memory when running the scatter plot function with large arrays as inputs (6.7E6 elements).
Approach
I have two large sets of data in cells with size (n x 1).
xCell = cell(n,1);
yCell = cell(n,1);
The data inside of the cells are multiple arrays of variable size (VariableSize x 1). I concatenate all of the arrays from each cell into one array each.
% Combine cells into one array
x = cat(1,xCell{:});
y = cat(1,yCell{:});
% Clear unnecessary variables
clear xCell yCell
I end up with two arrays x and y with the same size (6.7E6 elements) ready as inputs for a scatter plot. After executing my code, I end up with a memory error.
Output
??? Out of memory. Type HELP MEMORY for your options.
I have maxed out the amount of heap space available for my computer and I have nothing else running on the computer.
Objective
I would like to load only parts (sub-arrays) of the data at a time while creating the scatter plot and conserving the fact that the smaller sub-arrays are all part of only one larger series.
you can use tools such as cloudPlot and plot(Big) from the FEX. cloudPlot will help visualize the distribution of a 2-dimensional dataset. It is especially helpful when looking at extremely large datasets where a regular plot(x,y,'.') will just fill the plot with a solid color because the measurement points overlap each other. plot(Big) intercepts data going into a plot and reduces it to the smallest possible set that looks identical given the number of pixels available on the screen. It then updates the data as a user zooms or pans. This is useful when a user must plot a very large amount of data and explore it visually.
See more here on how to visualize distributions of 2d data.
I have a Matlab figure I want to use in a paper. This figure contains multiple cdfplots.
Now the problem is that I cannot use the markers because the become very dense in the plot.
If i want to make the samples sparse I have to drop some samples from the cdfplot which will result in a different cdfplot line.
How can I add enough markers while maintaining the actual line?
One method is to get XData/YData properties from your curves follow solution (1) from #ephsmith and set it back. Here is an example for one curve.
y = evrnd(0,3,100,1); %# random data
%# original data
subplot(1,2,1)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
%# reduced data
subplot(1,2,2)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
xdata = get(h,'XData');
ydata = get(h,'YData');
set(h,'XData',xdata(1:5:end));
set(h,'YData',ydata(1:5:end));
Another method is to calculate empirical CDF separately using ECDF function, then reduce the results before plotting with PLOT.
y = evrnd(0,3,100,1); %# random data
[f, x] = ecdf(y);
%# original data
subplot(1,2,1)
plot(x,f,'*')
%# reduced data
subplot(1,2,2)
plot(x(1:5:end),f(1:5:end),'r*')
Result
I know this is potentially unnecessary given MATLAB's built-in functions (in the Statistics Toolbox anyway) but it may be of use to other viewers who do not have access to the toolbox.
The empirical CMF (CDF) is essentially the cumulative sum of the empirical PMF. The latter is attainable in MATLAB via the hist function. In order to get a nice approximation to the empirical PMF, the number of bins must be selected appropriately. In the following example, I assume that 64 bins is good enough for your data.
%# compute a histogram with 64 bins for the data points stored in y
[f,x]=hist(y,64);
%# convert the frequency points in f to proportions
f = f./sum(f);
%# compute the cumulative sum of the empirical PMF
cmf = cumsum(f);
Now you can choose how many points you'd like to plot by using the reduced data example given by yuk.
n=20 ; % number of total data markers in the curve graph
M_n = round(linspace(1,numel(y),n)) ; % indices of markers
% plot the whole line, and markers for selected data points
plot(x,y,'b-',y(M_n),y(M_n),'rs')
verry simple.....
try reducing the marker size.
x = rand(10000,1);
y = x + rand(10000,1);
plot(x,y,'b.','markersize',1);
For publishing purposes I tend to use the plot tools on the figure window. This allow you to tweak all of the plot parameters and immediately see the result.
If the problem is that you have too many data points, you can:
1). Plot using every nth sample of the data. Experiment to find an n that results in the look you want.
2). I typically fit curves to my data and add a few sparsely placed markers to plots of the fits to differentiate the curves.
Honestly, for publishing purposes I have always found that choosing different 'LineStyle' or 'LineWidth' properties for the lines gives much cleaner results than using different markers. This would also be a lot easier than trying to downsample your data, and for plots made with CDFPLOT I find that markers simply occlude the stairstep nature of the lines.