Setting a specific number of tick marks on MATLAB plot - matlab

I am trying to figure out how to set a custom number of tick marks on the x-axis of a plot I am creating in MATLAB, but I am not sure if this is possible. I saw this question that seems to be asking the same thing, but that answer wasn't helpful since
set(gca,'XTick',tickVector);
sets the location of the ticks, not the number of ticks.
My code is as follows.
rangeBegin = 100000;
rangeEnd = 200000;
numberOfXTicks = 5;
plot(data(:, 1));
xAxisVals = linspace(rangeBegin, rangeEnd, numberOfXTicks);
%set(gca,'XTick',rangeBegin:rangeEnd); % Doesn't work as expected
set(gca,'XTickLabel',xAxisVals);
So in this example, I am just looking for a way to force MATLAB to create the plot with 5 ticks on the x-axis in order to match the 5 XTickLabels that I have set.
data is an array of doubles that is roughly <3000x1>.
EDIT: I should also add that I want my x-axis values to be from a separate array. The data array shown above corresponds to a time array (not shown...my bad), and each value in the data array has a corresponding value in the time array. Since I am selecting a range from the data array, I want to select the corresponding time values and use those as the x labels. But obviously I do not want 3000 time labels on my x-axis.
Hopefully this is more clear.

numberOfXTicks = 5;
h = plot(data(:, 1));
xData = get(h,'XData');
set(gca,'Xtick',linspace(xData(1),xData(end),numberOfXTicks))

Related

In matlab 2016b use a colormap to color the slices of a pie chart

This seems like it should be a lot easier than it is...
In matlab 2016b, I want to use a colormap to color the slices of a pie chart.
My data are three element vectors and might contain a zero. I have three colors in my colormap that need to be used in the order of the vector data.
For example:
data = [1 0 1];
my_cols = [1.0000 0.8398 0; 0.8594 0.0781 0.2344; 0.2539 0.4102 0.8789];
labels = {'','',''};
p = pie(data,labels);
p.Patch = my_cols;
I have tried all sorts of ways that have been previously suggested but it seems to not work with version 2016b.
Note that I need the first element of my data to always correspond to the first color in my colormap. I think Matlab colors slices based on size, but I don't want this.
I do not have 16b at hand. The following was done in 17a:
data = [1 0.5 1];
my_cols = [1.0000 0.8398 0; 0.8594 0.0781 0.2344; 0.2539 0.4102 0.8789];
labels = {'','',''};
p = pie(data,labels);
p(1).FaceColor = my_cols(1,:);
p(3).FaceColor = my_cols(2,:);
p(5).FaceColor = my_cols(3,:);
Explanation: pie returns 2 elements for each slice, the patch object and the corresponding string object. You must set the color for the patch objects, i.e. in your case p(1), p(3), and p(5).
Note that I changed your data input. With the zero in the vector you will get a warning and your variable dimensions are off.

Creating plots with disconnected/discrete lines

Here is my code:
for p = 1:length(id_unique)
h=figure;
hold on
j = 1;
for i = 1:1:length(id)
if id_unique(p)==id(i)
h=plot([startdate(i),enddate(i)],[j,j],'ok-');
hold on
j = j + 1;
end
end
grid on
hold off
savefig([plotname,'.fig'])
print(plotname,'-djpeg','-r300')
close
end
% id: integer vector containing 50000 values
% id_unique: sorted unique values from vector 'id'
% startdate: datetime vector containing 50000 dates
% enddate: datetime vector containing 50000 dates
Each elements/values in 'id' vector implies an event where the startdate and the enddate of the event is available in the corresponding position in 'startdate' and 'enddate' vectors.
Thus an event id(1) has the start date in startdate(i) and end date in enddate(i).
The program takes a value from the 'id_unique' vector and for each matched value found in 'id', it draws a line in the plot, denoting the beginning and ending time of the event.
For example, suppose 55 is an id-value from vector 'id_unique' and we have this value 1000 times in id. So for 55 a plot is created depicting 1000 separate lines with a marker 'o' at the beginning of the event, a marker 'o' at the end of the event and a line connecting both markers.
Please look at the attached plot that is generated from this code block. If id_unique has 70 values, 70 such plots will be created from this code. In the image, many lines are too small because of small difference between start and end date, so the markers overlap each other and look like a single point.
Now the problem comes when for an id-value in 'id_unique', we have a lot of instances of it in the 'id' vector. When the program plots individual lines unto 100 it works quite fast, but after plotting 300 lines in the same figure the program gets slow. When the program plots 1000 lines in the same figure, it takes about 5-7 seconds for each line. So it takes many hours to generate a plot with many lines.
Is there a way to improve my code to make these plot generation faster.
You don't need a loop:
you can use something like:
a = 1:0.1:4*pi;
b = sin(a); %vector that represent the start of each line
c = sin(a)+1; %vector that represent the end of each line
plot([b;c],[a;a],'-ko','markersize',2)
Result:
The function plot need 2 arguments: x and y, but, and this is why the world is beautiful, the function plot can manage several lines. If x and y are matrices, matlab interpret each column as a new line.
Having thought about this more, I now would suggest doing the following - rather than creating multiple lines in a plot, which generates a lot of objects in the background, it is better to produce one line per plot, that is broken up into multiple segments. If startdate and enddate are vectors of 1xlength(id), then the following code will be much faster as it concatenates all of the lines together, with NaN values in between. This makes the plot break the line at that point. All very quick, without the need to mess about with xlim and ylim as I previously suggested...
Here's my code:
for p = 1:length(id_unique)
h=figure;
block=[startdate(id==id_unique(p));enddate(id==id_unique(p))];
x_vals=reshape([block;nan(1,size(block,2))],1,[]);
y_vals=reshape([(1:size(block,2));(1:size(block,2));nan(1,size(block,2))],1,[]);
plot(x_vals,y_vals,'ok-');
grid on
savefig([plotname,'.fig'])
print(plotname,'-djpeg','-r300')
close
end
I hope this works better for you. (Of course, if your startdate and enddate vectors are length(id) by 1, then you should transpose them using .' in the 3rd line above).
I'm not sure what the purpose of the separate plots is, but it would be possible to plot them all on the same graph if that were useful. The code would then be:
h=figure;
hold on;
for p = 1:length(id_unique)
block=[startdate(id==id_unique(p));enddate(id==id_unique(p))];
x_vals=reshape([block;nan(1,size(block,2))],1,[]);
y_vals=reshape([(1:size(block,2));(1:size(block,2));nan(1,size(block,2))],1,[]);
plot(x_vals,y_vals,'Marker','o');
grid on
end
savefig([plotname,'.fig'])
print(plotname,'-djpeg','-r300')
close
This lets Matlab set the line type and colour using its standard series. It also allows you to use the legend function to add labels. Of course, if the position within id were important, rather than using a sequence for y_vals, you could use the position information obtained from find, changing the 4th and 6th lines to be:
[~,index]=find(id==id_unique(p));
block=[startdate(index);enddate(index)];
y_vals=reshape(index;index;nan(1,size(block,2))],1,[]);
Then you see all of id on one plot, with the different values of id distinguished by colour and linetype. You can then use the legend function to generate a legend:
legend(num2str(id_unique.'));
(This assumes that id_unique is a row vector. If it is a column vector, remove the .').
Here is way to also plot 2 different markers:
% some random data:
N = 50;
id = randi(5,N,1);
startdate = sort(randi(100,N,1));
enddate = startdate+randi(10,N,1);
% plotting:
ax = plot([startdate(:).'; enddate(:).'],[1:N; 1:N],'-k',...
startdate,1:N,'k<',enddate,1:N,'k>')
The (:).' after the vectors is not really needed, it's just to make sure they will be given in the right direction to plot - 2 rows, startdate above enddate.
which gives (randomly):
If you want to divide the data to groups by id, and color them this way, you can do the following:
N = 30;
id = randi(5,N,1);
startdate = datetime(sort(736000+randi(100,N,1)),'ConvertFrom','datenum');
enddate = startdate+randi(20,N,1);
% plotting:
ax = plot([startdate(:).'; enddate(:).'],[1:N; 1:N],'-',...
startdate,1:N,'k<',enddate,1:N,'k>');
% coloring:
cmap = colormap('jet');
col = cmap(floor(linspace(1,64,numel(unique(id)))),:);
for k = 1:N
ax(k).Color = col(id(k),:);
ax(k).LineWidth = 2;
end
% set the legend:
c = 1;
leg_ent = zeros(numel(unique(id)),1);
for k = unique(id).'
leg_ent(c) = find(id==k,1,'first');
c = c+1;
end
legend(ax(leg_ent),num2str(unique(id)),'Location','SouthEast')
and you will get:

MATLAB Finding the number of data points within confidence intervals

I have a set of data in Matlab, a matrix 6256x48, that I have found the mean, std dev, and CI intervals for. This was done using:
[muhat1,sigmahat1,muci1,sigmaci1] = normfit(data);
My question is, how can I find the number of results or data points in each column of the original data that are within the confidence intervals within the muci1 array.
The muci1 array is 2 rows of 48 points, the top row being the lower bound and the bottom row being the upper bound.
data = rand(6258,48); %//data
[A,B]=size(data); %// size of your data
[muhat1,sigmahat1,muci1,sigmaci1] = normfit(data); %//stats of your data
mask(A,B)=0; %// create output mask
for ii = 1:B
mask(:,ii) = data(:,ii)<muci1(2,ii)&data(:,ii)>muci1(1,ii); %// fill mask
end
FinalResult = sum(mask,1); %// number of points within CI per column
finalresult2 = sum(FinalResult); %// number of points within all CIs total
The for loop searches for entries in each column that are between the two bounds as given by muci1. If a number is between the bounds it gets a 1 in the mask, otherwise it becomes a 0.

Plot a cell into a time-changing curve

I have got a cell, which is like this : Data={[2,3],[5,6],[1,4],[6,7]...}
The number in every square brackets represent x and y of a point respectively. There will be a new coordinate into the cell in every loop of my algorithm.
I want to plot these points into a time-changing curve, which will tell me the trajectory of the point.
As a beginner of MATLAB, I have no idea of this stage. Thanks for your help.
Here is some sample code to get you started. It uses some basic Matlab functionalities that you will hopefully find useful as you continue using it. I added come data points to you cell array for illustrative purposes.
The syntax to access elements into the cell array might seem weird but is important. Look here for details about cell array indexing.
In order to give nice colors to the points, I generated an array based on the jet colormap built-in in Matlab. Basically issuing the command
Colors = jet(N)
create a N x 3 matrix in which every row is a 3-element color ranging from blue to red. That way you can see which points were detected before other (i.e. blue before red). Of course you can change that to anything you want (look here if you're interested).
So here is the code. If something is unclear please ask for clarifications.
clear
clc
%// Get data
Data = {[2,3],[5,6],[1,4],[6,7],[8,1],[5,2],[7,7]};
%// Set up a matrix to color the points. Here I used a jet colormap
%// available from MATLAB but that could be anything.
Colors = jet(numel(Data));
figure;
%// Use "hold all" to prevent the content of the figure to be overwritten
%// at every iterations.
hold all
for k = 1:numel(Data)
%// Note the syntax used to access the content of the cell array.
scatter(Data{k}(1),Data{k}(2),60,Colors(k,:),'filled');
%// Trace a line to link consecutive points
if k > 1
line([Data{k-1}(1) Data{k}(1)],[Data{k-1}(2) Data{k}(2)],'LineStyle','--','Color','k');
end
end
%// Set up axis limits
axis([0 10 0 11])
%// Add labels to axis and add a title.
xlabel('X coordinates','FontSize',16)
ylabel('Y coordinates','FontSize',16)
title('This is a very boring title','FontSize',18)
Which outputs the following:
This would be easier to achieve if all of your data was stored in a n by 2 (or 2 by n) matrix. In this case, each row would be a new entry. For example:
Data=[2,3;
5,6;
1,4;
6,7];
plot(Data(:, 1), Data(:, 2))
Would plot your points. Fortunately, Matlab is able to handle matrices which grow on every iteration, though it is not recommended.
If you really wanted to work with cells, there are a couple of ways you could do it. Firstly, you could assign the elements to a matrix and repeat the above method:
NumPoints = numel(Data);
DataMat = zeros(NumPoints, 2);
for I = 1:NumPoints % Data is a cell here
DataMat(I, :) = cell2mat(Data(I));
end
You could alternatively plot the elements straight from the cell, though this would limit your plot options.
NumPoints = numel(Data);
hold on
for I = 1:NumPoints
point = cell2mat(Data(I));
plot(point(1), point(2))
end
hold off
With regards to your time changing curve, if you find that Matlab starts to slow down after it stores lots of points, it is possible to limit your viewing window in time with clever indexing. For example:
index = 1;
SamplingRate = 10; % How many times per second are we taking a sample (Hertz)?
WindowTime = 10; % How far into the past do we want to store points (seconds)?
NumPoints = SamplingRate * WindowTime
Data = zeros(NumPoints, 2);
while running
% Your code goes here
Data(index, :) = NewData;
index = index + 1;
index = mod(index-1, NumPoints)+1;
plot(Data(:, 1), Data(:, 2))
drawnow
end
Will store your data in a Matrix of fixed size, meaning Matlab won't slow down.

mean squared displacement from multiple trajectories

I have a matrix of multiple particle trajectories that I would like to analyze separately The trajectory number is one of the columns of the matrix, so I am trying to sort based on that number. I am using some of the code from this answer: MSD with matlab (which was very helpful, thank you!) to calculate MSD, but I am having difficulty parsing out the individual trajectories. To explain in more detail what I am trying to do: I have trajectory outputs that are in matrix format, with one column for trajectory number, one column for x-position, one column for y-position, etc. I want to be able to take this information and calculate the mean-squared displacement for each trajectory. In order to do this, I have to create a way to distinguish data points based on trajectory number (which is listed in row 7 of mymatrix). This seems to be where I am having trouble. The important columns in this matrix are 1: x-position, 2: y-position and 7: trajectory number. So far I have
total_rows=size(mymatrix,1);
max_trajectory_number=mymatrix(total_rows,7);
nData=0;
msd=zeros(total_rows, 4)
for i=0:max_trajectory_number
trajectornumber= mymatrix(i,7);
if trajectorynumber.equals(i)
nData=nData+1; %counts the number of instances of this trajectory number, which is the number of data points in the trajectory
for dt = 1:nData
deltaCoords = mymatrix(1+dt:end,1:2) - traj0mat(1:end-dt,1:2); %calculates time-averaged MSD based on y and y positions in colums 1 and 2 respectively
squaredDisplacement = sum(deltaCoords.^2,2); %# dx^2+dy^2+dz^2
msd(dt,1) = trajectorynumber; %trajectory number
msd(dt,2) = mean(squaredDisplacement); %# average
msd(dt,3) = std(squaredDisplacement); %# std
msd(dt,4) = length(squaredDisplacement); %# n
end
end
Unfortunately when I run this on mymatrix, the resulting msd matrix remains all zeros. I think this is likely due to an error in sorting based on the trajectory number. I do not get an error just not the results I was looking for
If anyone has any suggestions on how to fix this, it would be greatly appreciated.
It looks like you want to bundle all rows identified by the same trajectory number. I assume that they show up in chronological order as you continue down a column. Then try something like
tnumbs = unique(mymatrix(:,7)); % identify unique trajectory numbers
for i=1:length(tnumbs) % loop through trajectories
icurr = find(mymatrix(:,7)==tnumbs(i)); % find indices to entries for current trajectory
% perform your averaging
deltaCoords = mymatrix(icurr(1+dt:end),1:2) - traj0mat(icurr(1:end-dt),1:2); %calculates time-averaged MSD based on y and y positions in colums 1 and 2 respectively
squaredDisplacement = sum(deltaCoords.^2,2); %# dx^2+dy^2+dz^2
msd(i,1) = tnumbs(i); %trajectory number
msd(i,2) = mean(squaredDisplacement); %# average
msd(i,3) = std(squaredDisplacement); %# std
msd(i,4) = length(squaredDisplacement); %# n
end