How to use histogram handler in matlab - matlab

I am trying to accumulate several histogram outputs into a cell array, but it seems that it's impossible to plot or do anything after the first execution of a single histogram command, because it's only an handle to deleted Histogram.
>> x = randn(10000,1);
>> h = histogram(x);
>> h
h =
handle to deleted Histogram
>> whos h
Name Size Bytes Class Attributes
h 1x1 104 matlab.graphics.chart.primitive.Histogram
I am aware that it's possible to write the histogram upon its calculation to a file, How do I save histogram to file in matlab?. Though I am trying to accumulate it into a cell array for later analysis.

This is due to the BeingDeleted property of histogram which can be read-only so you cannot change it.
However, you can copy the properties in another struct for later use. Modify your code as follows:
x = randn(10000,1);
h = histogram(x);
prop = properties(h);
for i = 1:length(prop)
newh.(prop{i}) = h.(prop{i});
end
Now all the properties of h are stored in newh which will remain there even after you close the histogram figure.

As has been suggested in comments, the proper way to do this, if all you need is the histogram values, is to use histcounts:
x = randn(10000,1);
[N,edges] = histcounts(x);
this way you can collect all bins x and y values (edges and N, respectively), and plot them later with bar. Here is a demonstration with a comparison between the results:
subplot 121
h = histogram(x)
title('histogram')
subplot 122
b = bar(edges(1:end-1),N,'FaceColor',lines(1),...
'FaceAlpha',0.6)
title('bar')
If it is important to show the histogram in the exact same way that histogarm does, you can set some more properties of bar.

Related

How to make a set on plot in Matlab like on the photo - Perceptron

I have a problem to make a set and show like on this photo in attachment.
Where:
Points must to be random in the range of:
Principle to set:
This is first part of exercise about perceptron. Without this I can't make other parts.
There is my code:
clc;
close all;
clear all;
I=400;
x1=-1+rand(I/2,1)+1;
X = [0+rand(I,1)*(2*pi) [-1+rand(I/2,1)+1;
(-1+rand(I/2,1)+1)] ]
Y = [ones((I/2),1)*sin(-1); ones(I/2,1)];
a = X(1:I/2,1);
b = X(1:I/2,2);
c = X(I/2:I,1);
d = X(I/2:I,2);
plot( a, b, 'bx');
hold on;
plot( c, d, 'go');
So you already figured out how to generate the random coordinates within the area of the plot:
N = 400;
x1 = rand(N,1)*(2*pi);
x2 = rand(N,1)*2-1;
Next, you want to find the subset of points that satisfy the equation (this is the set for which y==-1):
I = abs(sin(x1)) > abs(x2);
I is a logical array, with true values where the condition is satisfied. You can use I to index into another array. For example, You can create the vector y like this:
y = ones(N,1);
y(I) = -1;
But you don't really need y to create the plot. You were already plotting two subsets, simply make the subsets using I as index, instead of 1:N/2:
plot(x1(I),x2(I),'bx');
hold on
plot(x1(~I),x2(~I),'go');
The result is a plot exactly like in the question, except with x and o markers instead of . markers.

Why is contour sorting the data in the contour matrix C?

I have a function f(x,y) and I would like to draw the level curves of f with respect to a fixed vector
v=(v1,...,vn) % not sorted
using a meshgrid [X,Y].
This can be done using the function [C,h]=contour(X,Y,f,v).
But then, when I want to recover the data of each level curve, I found that C has sorted my vector v in an increasing way.
I would like to recover C in such a way that it keeps my fixed order of v.
This can be done using a loop over the components on v, one by one, using
[Ci,hi]=contour(X,Y,f,[vi,vi])
but I have found it inefficient, when taking the number of components of v large enough (Lets say, 10000 components).
How can I recover the original unsorted vector v from C(with the corresponding information given by C)?
I think it is easiest to sort the contour levels yourself in advance using
[w,iv,iw] = unique(v)
This will sort your data in v and only keep unique values. iv and iw are index vectors that allow you to redo the sorting from v --> w on any other data set, because w = v(iv) and v = w(iw).
Now use w instead of v to plot your contours. You can then use iw to
'unsort' the data in C. If necessary, take a look at Contour Properties > Contour Matrix for the specifications of C.
I suspect the answer to your question is that MATLAB applies unique to the contour levels before tracking the contours.
I'm not sure that recovering the unsorted vector is going to be helpful since there is not necessarily a single contour line/loop at each level. So in general this contour matrix must be processed in a loop at some point I believe.
Depending on what you intend to do with the contour line data subsequently what I have done in the past may be useful. (I have basically copied the code verbatim from a function I wrote a while ago.)
This code creates a mask matrix which enables me to extract all the points for each level from the contour matrix:
% Create the contours
[c, ch] = contour(X, Y, f, v);
% Create a mask for the contour matrix for each level.
l = numel(v);
n = size(c,2);
cmask = false(l,n);
fCtrNotLoop = false(1,l);
% Don't think this is possible without a loop...
ii = 1;
while ii < n
m = c(2,ii);
cmask(v == c(1,ii), ii+1:ii+m) = true;
% Remove duplicate point of loops.
if all(c(:,ii+1)==c(:,ii+m))
cmask(v == c(1,ii), ii+m) = false;
else
fCtrNotLoop(lvls == c(1,ii)) = true;
end
ii = ii + m + 1;
end
(You may or may not want to remove duplicate points that close loops -- I needed to for my application.)
Then to get the points in the contour(s) at level v(jj) use something like:
pts = c(:,cmask(jj,:));
With a slight modification you could use cmask to reorder your contour matrix: change ii+1:ii+m in the cmask(...) = true line to ii:ii+m and remove the duplicate points if statement. Then loop through each level to populate a copy of c:
% WARNING: Untested code follows!
cnew = c;
kk = 1;
for jj = 1 : l
s = sum(cmask(jj, :));
cnew(:, kk:kk+s-1) = c(:, cmask(jj, :));
kk = kk + s;
end
As cmask has dimensions [length(v),length(c)] if you have a huge number of levels and lots of contour points in each then memory consumption may become a problem and modification of this extraction/reordering method may be required - i.e. process each level separately which of course will be slower.

matlab plotting a family of functions

Generate a plot showing the graphs of
y=(2*a+1)*exp(-x)-(a+1)*exp(2*x)
in the range x ∈ <-2, 4> for all integer values of a between -3 and 3
I know how to make typical plot for 2 values and set a range on the axes, but how to draw the graph dependent on the parameter a?
To elaborate on Ben Voigt's comment: A more advanced technique would be to replace the for-loop with a call to bsxfun to generate a matrix of evaluations of M(i,j) = f(x(i),a(j)) and call plot with this matrix. Matlab will then use the columns of the matrix and plot each column with individual colors.
%%// Create a function handle of your function
f = #(x,a) (2*a+1)*exp(-x)-(a+1)*exp(2*x);
%%// Plot the data
x = linspace(-2, 4);
as = -3:3;
plot(x, bsxfun(f,x(:),as));
%%// Add a legend
legendTexts = arrayfun(#(a) sprintf('a == %d', a), as, 'uni', 0);
legend(legendTexts, 'Location', 'best');
You could also create the evaluation matrix using ndgrid, which explicitly returns all combinations of the values of x and as. Here you have to pay closer attention on properly vectorizing the code. (We were lucky that the bsxfun approach worked without having to change the original f.)
f = #(x,a) (2*a+1).*exp(-x)-(a+1).*exp(2*x); %// Note the added dots.
[X,As] = ndgrid(x,as);
plot(x, f(X,As))
However for starters, you should get familiar with loops.
You can do it using a simple for loop as follows. You basically loop through each value of a and plot the corresponding y function.
clear
clc
close all
x = -2:4;
%// Define a
a = -3:3;
%// Counter for legend
p = 1;
LegendText = cell(1,numel(a));
figure;
hold on %// Important to keep all the lines on the same plot.
for k = a
CurrColor = rand(1,3);
y= (2*k+1).*exp(-x)-(k+1).*exp(2.*x);
plot(x,y,'Color',CurrColor);
%// Text for legend
LegendText{p} = sprintf('a equals %d',k);
p = p+1;
end
legend(LegendText,'Location','best')
Which gives something like this:
You can customize the graph as you like. Hope that helps get you started!

Plot eigen Vector e1 & e2 in matlab?

How to be able plot eigen vector in Matlab an make it sure have the exact position as a new axes of our data??
here is my code for PCA
a= randn(100,3);
b=mean(a);
c=cov(a);
[vec,val] = eigs(c);
e1=vec(:,1);
e2=vec(:,2);
plot3(a(:,1),a(:,2),a(:,3),'ro');
hold on
%% Here is the Problem begins
plot(e1,'k--');
plot(e2,'k--');
Here is the output that I got
That two lines represent the e1&e2.
How to plot the e1 & e2 properly???
You can use the output from eig to directly plot all three eigenvectors (or a subset):
a = randn(100,3);
b = mean(a);
c = cov(a);
[vec,val] = eig(c);
plot3(a(:,1),a(:,2),a(:,3),'ro');
hold on
z = zeros(1,3);
% plot3([z(1:2);vec(1,1:2)],[z(1:2);vec(2,1:2)],[z(1:2);vec(3,1:2)],'k')
plot3([z;vec(1,:)],[z;vec(2,:)],[z;vec(3,:)],'k')
axis equal
grid on
And if you want the scaled eigenvectors:
sc_vec = vec*val;
z = zeros(1,3);
plot3([z;sc_vec(1,:)],[z;sc_vec(2,:)],[z;sc_vec(3,:)],'b')
Another option is to use quiver3 to get lines with arrowheads:
scale = 1;
z = zeros(1,3);
quiver3(z,z,z,vec(1,:),vec(2,:),vec(3,:),scale,'g')
Just don't expect the arrows to always look perfect, because Matlab isn't particularly good at this sort of thing.
Note that eig may return the eigenvalues and -vectors in a different order than eigs, but it is the function that you should be using. eigs is a specialized function that solved the eigenproblem in a different way and is much less efficient.
You can use plot3
a= randn(100,3);
b=mean(a);
c=cov(a);
[vec,val] = eigs(c);
e1=[zeros(size(vec(:,1))),vec(:,1)]'; e1 = e1/norm(e1)*4;
e2=[zeros(size(vec(:,2))),vec(:,2)]'; e2 = e2/norm(e2)*4;
e3=[zeros(size(vec(:,3))),vec(:,3)]'; e3 = e3/norm(e3)*4;
plot3(a(:,1),a(:,2),a(:,3),'ro');
hold on
%% Here is the Problem begins
plot3(e1(:,1),e1(:,2),e1(:,3),'k','LineWidth',2);
plot3(e2(:,1),e2(:,2),e2(:,3),'b','LineWidth',2);
plot3(e3(:,1),e3(:,2),e3(:,3),'g','LineWidth',2);
To represent each vector, use plot3 to plot a line from the origin to the coordinates defined by the vector, perhaps multiplied by a large number (I use 10 in the example) to make the line longer:
plot3(10*[0 e1(1)], [0 e1(2)], [0 e1(3)],'b--');
plot3(10*[0 e2(1)], [0 e2(2)], [0 e2(3)],'g--');
You may need to change the view to get a good perspective. For that you can use view function, or click the "Rotate 3D" icon (circular arrow) in the figure toolbar.

Multiple colormaps using bar(z,'stacked')

I have read the article recommended by a post on another colormap thread http://www.mathworks.com/matlabcentral/answers/101346 and I understand the concept. I am having trouble understanding the values of CDATA when using the bar(z,'stacked') function.
I have one figure with a major axis plotted using cmap, and I have created and positioned a new axis for the bar chart and I want it to use cmap2.
For example, my code includes:
maps = colormap([cmap;cmap2]);
bH = bar(z,'stacked');
Where z = 25x10 (annual data for 10 years over 25 sites)
Now when I look at the CDATA
get(bH,'CDATA') A cell array is returned of size 1x10 with each cell containing the string 'scaled'.
Now if I look at the CDATA of each of the children
childH = get(bH,'children');
get(childH{i},'CDATA')
A matrix of size 25x10 is returned with every value equal.
e.g. childH{i}'s CDATA is a matrix of size 25x10 having all values = i
So how can I scale these to map to my colormap since
from the documentation above I need to perform:
m = size(colormap,1); % Number of colors in the current colormap
Data = get(H,'CData') % Where H is a handle to a surface or patch object
cmin = min(CData(:)); % Minimum color value
cmax = max(CData(:)); % Maximum color value
idx = min(m,round((m-1)*(CData-cmin)/(cmax-cmin))+1);
idx becomes min(m,nan) which is always m?
I really need help understanding this.
Am I missing something or is this function a special case?
First make sure that cmap2 has exactly the number of colors that you want to use, then get the barseries object to map into it directly. Something like:
childH = get(bH, 'children');
for a = 1:numel(childH)
C = get(childH{a}, 'FaceVertexCData');
C(:) = a+size(cmap, 1);
set(childH{a}, 'FaceVertexCData', C, 'CDataMapping', 'direct');
end