I'm working with k-means in MATLAB. I am trying to create the plot/graph, but my data has three dimensional array. Here is my k-means code:
clc
clear all
close all
load cobat.txt; % read the file
k=input('Enter a number: '); % determine the number of cluster
isRand=0; % 0 -> sequeantial initialization
% 1 -> random initialization
[maxRow, maxCol]=size(cobat);
if maxRow<=k,
y=[m, 1:maxRow];
elseif k>7
h=msgbox('cant more than 7');
else
% initial value of centroid
if isRand,
p = randperm(size(cobat,1)); % random initialization
for i=1:k
c(i,:)=cobat(p(i),:);
end
else
for i=1:k
c(i,:)=cobat(i,:); % sequential initialization
end
end
temp=zeros(maxRow,1); % initialize as zero vector
u=0;
while 1,
d=DistMatrix3(cobat,c); % calculate the distance
[z,g]=min(d,[],2); % set the matrix g group
if g==temp, % if the iteration doesn't change anymore
break; % stop the iteration
else
temp=g; % copy the matrix to the temporary variable
end
for i=1:k
f=find(g==i);
if f % calculate the new centroid
c(i,:)=mean(cobat(find(g==i),:),1);
end
end
c
[B,index] = sortrows( c ); % sort the centroids
g = index(g); % arrange the labels based on centroids
end
y=[cobat,g]
hold off;
%This plot is actually placed in plot 3D code (last line), but I put it into here, because I think this is the plotting line
f = PlotClusters(cobat,g,y,Colors) %Here is the error
if Dimensions==2
for i=1:NumOfDataPoints %plot data points
plot(cobat(i,1),cobat(i,2),'.','Color',Colors(g(i),:))
hold on
end
for i=1:NumOfCenters %plot the centers
plot(y(i,1),y(i,2),'s','Color',Colors(i,:))
end
else
for i=1:NumOfDataPoints %plot data points
plot3(cobat(i,1),cobat(i,2),cobat(i,3),'.','Color',Colors(g(i),:))
hold on
end
for i=1:NumOfCenters %plot the centers
plot3(y(i,1),y(i,2),y(i,3),'s','Color',Colors(i,:))
end
end
end
And here is the plot 3D code:
%This function plots clustering data, for example the one provided by
%kmeans. To be able to plot, the number of dimensions has to be either 2 or
%3.
%Inputs:
% Data - an m-by-d matrix, where m is the number of data points to
% cluster and d is the number of dimensions. In my code, it is cobat
% IDX - an m-by-1 indices vector, where each element gives the
% cluster to which the corresponding data point in Data belongs. In my file, it is 'g'
% Centers y - an optional c-by-d matrix, where c is the number of
% clusters and d is the dimensions of the problem. The matrix
% gives the location of the cluster centers. If this is not
% given, the centers will be calculated. In my file, I think, it is 'y'
% Colors - an optional color scheme generated by hsv. If this is not
% given, a color scheme will be generated.
%
function f = PlotClusters(cobat,g,y,Colors)
%Checking inputs
switch nargin
case 1 %Not enough inputs
error('Clustering data is required to plot clusters. Usage: PlotClusters(Data,IDX,Centers,Colors)')
case 2 %Need to calculate cluster centers and color scheme
[NumOfDataPoints,Dimensions]=size(cobat);
if Dimensions~=2 && Dimensions~=3 %Check ability to plot
error('It is only possible to plot in 2 or 3 dimensions.')
end
if length(g)~=NumOfDataPoints %Check that each data point is assigned to a cluster
error('The number of data points in Data must be equal to the number of indices in IDX.')
end
NumOfClusters=max(g);
Centers=zeros(NumOfClusters,Dimensions);
NumOfCenters=NumOfClusters;
NumOfPointsInCluster=zeros(NumOfClusters,1);
for i=1:NumOfDataPoints
Centers(g(i),:)=y(g(i),:)+cobat(i,:);
NumOfPointsInCluster(g(i))=NumOfPointsInCluster(g(i))+1;
end
for i=1:NumOfClusters
y(i,:)=y(i,:)/NumOfPointsInCluster(i);
end
Colors=hsv(NumOfClusters);
case 3 %Need to calculate color scheme
[NumOfDataPoints,Dimensions]=size(cobat);
if Dimensions~=2 && Dimensions~=3 %Check ability to plot
error('It is only possible to plot in 2 or 3 dimensions.')
end
if length(g)~=NumOfDataPoints %Check that each data point is assigned to a cluster
error('The number of data points in Data must be equal to the number of indices in IDX.')
end
NumOfClusters=max(g);
[NumOfCenters,Dims]=size(y);
if Dims~=Dimensions
error('The number of dimensions in Data should be equal to the number of dimensions in Centers')
end
if NumOfCenters<NumOfClusters %Check that each cluster has a center
error('The number of cluster centers is smaller than the number of clusters.')
elseif NumOfCenters>NumOfClusters %Check that each cluster has a center
disp('There are more centers than clusters, all will be plotted')
end
Colors=hsv(NumOfCenters);
case 4 %All data is given just need to check consistency
[NumOfDataPoints,Dimensions]=size(cobat);
if Dimensions~=2 && Dimensions~=3 %Check ability to plot
error('It is only possible to plot in 2 or 3 dimensions.')
end
if length(g)~=NumOfDataPoints %Check that each data point is assigned to a cluster
error('The number of data points in Data must be equal to the number of indices in IDX.')
end
NumOfClusters=max(g);
[NumOfCenters,Dims]=size(y);
if Dims~=Dimensions
error('The number of dimensions in Data should be equal to the number of dimensions in Centers')
end
if NumOfCenters<NumOfClusters %Check that each cluster has a center
error('The number of cluster centers is smaller than the number of clusters.')
elseif NumOfCenters>NumOfClusters %Check that each cluster has a center
disp('There are more centers than clusters, all will be plotted')
end
[NumOfColors,RGB]=size(Colors);
if RGB~=3 || NumOfColors<NumOfCenters
error('Colors should have at least the same number of rows as number of clusters and 3 columns')
end
end
%Data is ready. Now plotting
end
Here is the error:
??? Undefined function or variable 'Colors'.
Error in ==> clustere at 69
f = PlotClusters(cobat,g,y,Colors)
Am I wrong call the function like that? What should I do? Your help will be appreciated a lot.
Your code is very messy, and unnecessarily long..
Here is smaller example that does the same thing. You'll need the Statistics toolbox to run it (for the kmeans function and Iris dataset):
%# load dataset of 150 instances and 3 dimensions
load fisheriris
X = meas(:,1:3);
[numInst,numDims] = size(X);
%# K-means clustering
%# (K: number of clusters, G: assigned groups, C: cluster centers)
K = 3;
[G,C] = kmeans(X, K, 'distance','sqEuclidean', 'start','sample');
%# show points and clusters (color-coded)
clr = lines(K);
figure, hold on
scatter3(X(:,1), X(:,2), X(:,3), 36, clr(G,:), 'Marker','.')
scatter3(C(:,1), C(:,2), C(:,3), 100, clr, 'Marker','o', 'LineWidth',3)
hold off
view(3), axis vis3d, box on, rotate3d on
xlabel('x'), ylabel('y'), zlabel('z')
You could simply go for scatter():
As you can see from the image, you differentiate colors, size of the clusters. FOr more details check out the examples in the documentation.
Here is the sample code for how we can get the 3d graph.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x =[1,2,3,4,5,6,7,8,9,10]
y =[5,6,2,3,13,4,1,2,4,8]
z =[2,3,3,3,5,7,9,11,9,10]
ax.scatter(x, y, z, c='r', marker='o')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
Related
As seen on the figure below, I have a collection of data from different time sets. However, there is a line connecting the end of each data section to the start of the next.
Is there any way of suppressing this connection without altering the data?
Intro
Currently MATLAB is drawing lines between all consecutive points in your arrays, including when there is a big jump in x value.
An equivalent example would be this plot:
% Create some x with points spaced by 0.1, except at 2 jumps of 5
x = [0:0.1:10, 15:0.1:25, 30:0.1:40];
y = sin(x);
plot(x,y)
Notice the straight line joins between our 3 sections (10-15, 25-30).
Method 1: hold on for multiple plots
We can use the find and diff to get the regions where x jumps, and then plot each region individually.
% Include indices for the first (we're going to +1, so start at 0) and last elements
% You can change this 1 to any tolerance you like, it might be of the order 10^4 for you!
idx = [0, find(diff(x) > 1), numel(x)];
% Hold on for multiple plots
hold on;
% Loop over sections and plot
for ii = 2:numel(idx)
% Plots will loop through colours if you don't specify one, specified blue ('b') here
plot(x(idx(ii-1)+1:idx(ii)), y(idx(ii-1)+1:idx(ii)), 'b')
end
hold off; % good practise so you don't accidentally plot more on this fig!
Method 2: using NaN
You could use also use NaN values to break up your data. NaN values aren't plotted by MATLAB, so if we include one in each break, there will be nothing to connect the line to and we'll see a break:
% Notice the NaNs!
x = [0:0.1:10, NaN, 15:0.1:25, NaN, 30:0.1:40];
y = sin(x);
plot(x,y)
Automation: You may want to use the diff function to find these jumps on the fly for some pre-existing x, like so
% Define some x and y as before, without NaNs, with big gaps in x
x = [0:0.1:10, 15:0.1:25, 30:0.1:40];
y = sin(x);
% Create anonymous function to insert NaN at vector index 'n'
insertNaN = #(v, n) [v(1:n), NaN, v(n+1:end)];
% Get indices where gap is bigger than some value (in this case 1)
idx = find(diff(x) > 1);
% Loop *backwards* through indices (so they don't shift up by 1 as we go)
for ii = numel(idx):-1:1
x = insertNaN(x,idx(ii));
y = insertNaN(y,idx(ii));
end
% Plot appears the same as the second plot above
plot(x,y);
Note: If you want to do further processing on x and y, it might not be best to add random NaN values into the array! You can either:
Remove them afterwards (assuming there weren't pre-existing NaNs)
x = x(~isnan(x));
y = y(~isnan(y));
Use temporary variables for plotting
xplot = x;
% then adding NaNs to xplot for plotting ...
I am using MATLAB R2015a. I have defined a grid which is basically a matrix that stores the latitudes of the grid points in the first column and the longitudes of the grid points in the second column I have some data for energy of an earthquake for a region stored in a column vector where each element corresponds to the energy at the corresponding grid point. I have done a surface plot using this code (here e_lat and e_long are the first and second columns of the grid matrix respectively):-
function [b] = cumulative_plot( beam, e_lat,e_long, t_start, t_end)
%CUMULATIVE_PLOT Plots the cumulative energy of the earthquake
%% Input Arguments
% *beam* - Energy for each time increment (columns) for each grid point (rows)
%
% *e_lat* - Vector containing Latitudes of the grid points
%
% *e_long* - Vector containing Longitudes of the grid points
%
% *t_start* - starting time
%
% *t_end* - ending time
%
% *t_start* and *t_end* define the time window within which the energy is
% to be considered
%% Code
b = [];
b = sum(beam(:,t_start:t_end)')'; % Adding the energy within the time window
b = b./max(b); % Normalising
fn = 'cumulative_energy.txt';
f = fopen(fn,'w');
for i=1:length(e_lat)
fprintf(f,'%f %f %f \n',e_long(i),e_lat(i),b(i));
end
fclose(f);
energy_surf = fit([e_long,e_lat],b, 'loess');
plot(energy_surf,'style','contour');
hold on;
plot3(73.6400 ,34.5239 ,20,'s','MarkerSize',20,'MarkerEdgeColor','k','MarkerFaceColor','k')
hold on;
plot3(94.709,23.03,20,'s','MarkerSize',20,'MarkerEdgeColor','b','MarkerFaceColor','b')
shading interp
alpha(1)
view(0,90)
box off
colorbar
title(['Cumu Energy(0.05 - 0.2 Hz) at seconds = ' num2str(t_start )],'FontWeight','bold','FontSize',15,'FontName','Times');
xlabel('Long/degree','FontWeight','bold','FontSize',13,'FontName','Times');
ylabel('Lat/degree','FontWeight','bold','FontSize',13,'FontName','Times');
end
This is an example (the actual data that I am processing):-
cumulative_plot(b_corr,e_lat,e_long,1,20);
I want to make a contour plot of this energy data on a geographic map of the region specified. Is this possible?
To give a better idea, this is what I have right now :-
And this is kind of what I want to achieve (without the purple circular markers and other things. Just the base energy) :-
If you have the bmp image of the mountain details, save the data in RGB format, and mix it with the data of the cumulative energy scale by its intensity. Intensity provide the alpha blending value.
I read in an image in MATLAB and display it using imagesc. I then set the colormap to grey.
On top of this image, I plot points with the jet colour scheme. How do I then display the jet colorbar, to correspond to the colours of the points plotted on top of the original image? I tried redefining the colorbar after all of the plots, but this changes the original grey scale image back to colours, which isn't desired.
Code:
%Create Figure with handle.
h5=figure('units','normalized','outerposition',[0 0 1 1]);
whitebg(h5,[0 0 0]);
subplot(2,5,1);
k=1;
for i=16:25
subplot(2,5,k);
imagesc(squeeze(ana(:,:,i)));
title(['Z=',num2str(i)]);
colormap gray
axis equal
k=k+1;
colorbar
end
%Adapt colour values so that they are between 0 and 1. We want to scale
%both data sets equally, so we find the smallest value across Ix and Iy. We
%also find what will be the new largest value across Ix and Iy, after we
%add the magnitude of the smallest value to make all numbers greater than
%or equal to 0.
absolutemin=min(min(Ix(:,1)),min(Iy(:,1)));
absolutemax=max(abs(absolutemin)+(max(Ix(:,1))),abs(absolutemin)+max(Iy(:,1)));
%Add the smallest value, and divide by the largest maximum value for both Ix
%and Iy.
ixcolours=uint8(((Ix(:,1)+abs(absolutemin))/absolutemax).*255)+1;
iycolours=uint8(((Iy(:,1)+abs(absolutemin))/absolutemax).*255)+1;
mycolours=jet(256);
o=1;
for k=16:25; %For all 3D slices
for i=1:471; %and for all x and y seed slices
if k==seed_locs(i,3);
subplot(2,5,o);
hold all%go to the corresponding z subplot
plot(seed_locs(i,1),seed_locs(i,2),'MarkerFaceColor',mycolours(ixcolours(i),:),'MarkerEdgeColor',mycolours(ixcolours(i),:),'MarkerSize',10,'Marker','s') %plot the x and y seedlocs
%hold on
end
end
for i=1:486;
if k==test_locs(i,3);
subplot(2,5,o);
hold all
plot(test_locs(i,1),test_locs(i,2),'MarkerFaceColor',mycolours(iycolours(i),:),'MarkerEdgeColor',mycolours(iycolours(i),:),'MarkerSize',10,'Marker','s') %plot the x and y seedlocs
% hold on
end
end
o=o+1; %go to the next z subplot
end
colormap jet
colorbar
I think the following example can help you to improve your code. You firstly need to define two colormaps:
colormap([cool(64);gray(64)]);
Then let's say we have two different sets of datapoints to plot:
[X,Y,Z] = peaks(25);
h(1) = surf(X,Y,Z);hold on
h(2) = pcolor(X,Y,Z);
So the data is defined with two different handles. Now we need to make the CData using the minimum and maximum values.
cmin = min(Z(:));
cmax = max(Z(:));
C1 = min(64,round((64-1)*(Z-cmin)/(cmax-cmin))+1); % CData for the first datapoints
C2 = 64+C1; % CData for the second datapoints
Now we update the CDatas for each object.
set(h(1),'CData',C1);
set(h(2),'CData',C2);
Now you can set the CLim property of axes:
caxis([min(C1(:)) max(C2(:))])
colorbar;
After seeing this great post in SO:
Most efficient way of drawing grouped boxplot matlab
I was wondering if it is possible to create a function like that but a bit more generic, as in my application I need to make several analysis of different algorithms in different situations and it would be very tedious to tune the plotting code for each case.
I would like something generic for this kind of plots:
I coded a Matlab function that does that for you (me).
Features:
In each boxplot different amount of data supported
Any amount of groups and boxplot per group supported
Xlabel and boxplotlabel supported
Automatic choice of colors or user specified colors
Example of result of function:
CODE:
function multiple_boxplot(data,xlab,Mlab,colors)
% data is a cell matrix of MxL where in each element there is a array of N
% length. M is how many data for the same group, L, how many groups.
%
% Optional:
% xlab is a cell array of strings of length L with the names of each
% group
%
% Mlab is a cell array of strings of length M
%
% colors is a Mx4 matrix with normalized RGBA colors for each M.
% check that data is ok.
if ~iscell(data)
error('Input data is not even a cell array!');
end
% Get sizes
M=size(data,2);
L=size(data,1);
if nargin>=4
if size(colors,2)~=M
error('Wrong amount of colors!');
end
end
if nargin>=2
if length(xlab)~=L
error('Wrong amount of X labels given');
end
end
% Calculate the positions of the boxes
positions=1:0.25:M*L*0.25+1+0.25*L;
positions(1:M+1:end)=[];
% Extract data and label it in the group correctly
x=[];
group=[];
for ii=1:L
for jj=1:M
aux=data{ii,jj};
x=vertcat(x,aux(:));
group=vertcat(group,ones(size(aux(:)))*jj+(ii-1)*M);
end
end
% Plot it
boxplot(x,group, 'positions', positions);
% Set the Xlabels
aux=reshape(positions,M,[]);
labelpos = sum(aux,1)./M;
set(gca,'xtick',labelpos)
if nargin>=2
set(gca,'xticklabel',xlab);
else
idx=1:L;
set(gca,'xticklabel',strsplit(num2str(idx),' '));
end
% Get some colors
if nargin>=4
cmap=colors;
else
cmap = hsv(M);
cmap=vertcat(cmap,ones(1,M)*0.5);
end
color=repmat(cmap, 1, L);
% Apply colors
h = findobj(gca,'Tag','Box');
for jj=1:length(h)
patch(get(h(jj),'XData'),get(h(jj),'YData'),color(1:3,jj)','FaceAlpha',color(4,jj));
end
if nargin>=3
legend(fliplr(Mlab));
end
end
Simple example:
clear;clc;
% Create example data
A=rand(100,10);
B=rand(200,10);
C=rand(150,10);
% prepare data
data=cell(10,3);
for ii=1:size(data,1)
Ac{ii}=A(:,ii);
Bc{ii}=B(:,ii);
Cc{ii}=C(:,ii);
end
data=vertcat(Ac,Bc,Cc);
xlab={'Hey','this','works','pretty','nicely.','And','it','has','colors','!!!!'};
col=[102,255,255, 200;
51,153,255, 200;
0, 0, 255, 200];
col=col/255;
multiple_boxplot(data',xlab,{'A', 'B', 'C'},col')
title('Here it is!')
Mathworks file exchange file can be found here:
http://www.mathworks.com/matlabcentral/fileexchange/47233-multiple-boxplot-m
I am considered as a very beginner to MATLAB.
I need to find a FWHM of some graphs which quite noisy and not consistence at the peak.
here below is my basic code, with the help of some codes from stackoverflow users.
DD11=dicomrt_read3ddose(1,'waterphantom50x1mm15x1cmslabs500Mill_2.5cmFS_20cmx20cmDE.3ddose');
%plot first function
a=squeeze(DD11(100,:,55));
figure;
plot(a);
hold on;
%find half of maximum value
max(a);
halfAmax=0.5*(max(a));
%plot straight line across the first function
x2=[1:1:200];
LineValue=halfAmax;
plot(x2,LineValue);
%Find the starting indices of those segments of consecutive points that exceed LineValue
idx = find(diff(a >= LineValue))
hold on;
x3 = x2(idx) + (LineValue - a(idx)) .* (x2(idx+1) - x2(idx)) ./ (a(idx+1) - a(idx))
plot(x3, LineValue, 'go', [x2(1) x2(end)], LineValue*[1 1], 'k:');
%distance of the two points
fwhmwidth=[x3(end)-x3(1)].*0.1
hold on;
%plot first function
b=squeeze(DD11(100,:,7));
plot(b);
hold on;
%find half of maximum value
max(b);
halfAmax=0.5*(max(b));
%plot straight line across the first function
x2=[1:1:200];
LineValue=halfAmax;
plot(x2,LineValue);
%Find the starting indices of those segments of consecutive points that exceed LineValue
idx = find(diff(b >= LineValue))
hold on;
x3 = x2(idx) + (LineValue - b(idx)) .* (x2(idx+1) - x2(idx)) ./ (b(idx+1) - b(idx))
plot(x3, LineValue, 'go', [x2(1) x2(end)], LineValue*[1 1], 'k:');
%distance of the two points
fwhmwidth=[x3(end)-x3(1)].*0.1
I am hoping that;
(1) I could find the average value for those peak since they are noisy
(2) I could get a better explanation on the code which I have above like below;
%Find the starting indices of those segments of consecutive points that exceed LineValue
idx = find(diff(b >= LineValue))
hold on;
x3 = x2(idx) + (LineValue - b(idx)) .* (x2(idx+1) - x2(idx)) ./ (b(idx+1) - b(idx))
plot(x3, LineValue, 'go', [x2(1) x2(end)], LineValue*[1 1], 'k:');
Thanks very much.
Answer to (2):
%Find the starting... is a commentary. In Matlab, they start by %.
idx = find(diff(b >= LineValue)) locates all nonzero elements of array diff(b >= LineValue), and returns the linear indices of those elements in vector idx. In this case, it will only return the first nonzero element. Check Find
hold on refers to the plot. You have already a plot and by using hold on you will be to add further curves to the same plot.
x3 = x2(idx) + (LineValue - a(idx)) .* (x2(idx+1) - x2(idx)) ./ is performing operations with numbers and with matrices. c = a .* b multiplies arrays a and b element-by-element and returns the result in c. Inputs a and b must have the same size unless one is a scalar. You can check that out in the Matlab Help by clicking F1.
plot(x3, LineValue, 'go', [x2(1) x2(end)], LineValue*[1 1], 'k:') plots 2 different curves. The first term contains the x-axis values, the second the y-axis values and the third gives the information about the LineStyle, Color and Marker. In that case 'go' = green circles and 'k:' = black dots. Have a look in Matlab's plot documentation for much more info.
Hope that helps