Plotting specific points from a column - matlab

I have a data file in which I take all of the numbers from 2 columns. The 2 columns of data, which I call 'a' and 'r', have an initial value stored in them which I would like to discount. It also has several runs in the the data, so the initialization is repeated about 15 times. Is there a way that I can graph the log of the points that correspond to a being greater than the initial value (in this case 4) and its corresponding r value? It would be along the lines of
fia = fopen('data.txt');
A = fscanf(fia, '%f %f, [2,inf]);
a=A(1,:);
r=A(2;:);
plot(log(a(4:end)),log(r)); % I know this won't work, as it breaks down the matrix, but something like this.

Related

How to slice and store a set of curves in multiple variables in matlab?

I have a table with 2 columns (x and y value) and 100 rows (the x values repeat in a certain interval).
Therfore I would like to perform the following task for changeable table sizes (only changes in the row size!):
I want to determine the amount of repetitions of the x values and save this information as a variable named n. Here the amount of repetition is 5 (each x value occurs 5 times in total).
I want to know the range of the x values from repetition circle and save this information as R = height(range); Here the x range is [0,20]
With the above informaton I would like the create smaller tables where only one repetition of the x values is present
How could I implement this in matlab?
Stay safe and healthy,
Greta
This approach converts the Table to an array/matrix using the table2array() function for further processing. To find the repeated pattern in the x-values the unique() function is used to retrieve the vector that is repeated multiple times. The range of the values can be calculated by using the min() and max() functions and concatenating the values in a 2 element array. The assignin() function can then be used to create a set of smaller tables that separate the y-values according to the x-value repetitions.
Table Used to Test Script:
x = repmat((1:20).',[5 1]);
y = rand(100,1);
Table = array2table([x y]);
Script:
Array = table2array(Table);
Unique_X_Values = unique(Array(:,1));
Number_Of_Repetitions = length(Array)/length(Unique_X_Values);
Range = [min(Array(:,1)) max(Array(:,1))];
Y_Reshaped = reshape(Array(:,2),[numel(Array(:,2))/Number_Of_Repetitions Number_Of_Repetitions]);
for Column_Index = 1: Number_Of_Repetitions
Variable_Name = ['Small_Tables_' num2str(Column_Index)];
assignin('base',Variable_Name,array2table(Y_Reshaped(:,Column_Index)));
eval(Variable_Name);
end
fprintf("Number of repetitions: %d\n",Number_Of_Repetitions);
fprintf("Range: [%d,%d]\n",Range(1),Range(2));

MATLAB automatically assigns unwanted dimensions to a dynamically updated cell array

I want to generate a 3D cell array called timeData so that timeData(:,:,a) for some integer a is an nx1 matrix of data, and the number of rows n varies with the value of a in a 1:1 correspondence. To do this, I am generating a 2D array of data called data that is nx1. This assignment statement takes place within a for loop as follows:
% Before iterating, I define an array of indices where I want to store the
% data sets in timeData. This choice of storage location is for
% organizational purposes.
A = [2, 5, 9, 21, 34, 100]; % Notice they are in ascending order, but have
% gaps that have no predictability.
sizeA = size(A);
numIter = A(1);
for m = 1:numIter % numIter is the number of data sets that I need to store
% in timeData
% At this point, some code that is entirely irrelevant to my question
% generates a nx1 array of data. One example of this data array is below.
data = [1.1;2.3;5.5;4.4]; % This is one example of what data could be. Its
% number of rows, n, changes each iteration, as
% do its contents.
B = size(data);
timeData(1:B(1),1,A(m)) = num2cell(data);
end
This code does put all contents of data in the appropriate locations within timeData as I want. However, it also adds {0x0 double} rows to all 2D arrays of timeData(:,:,a) for any a whose corresponding number of rows n was not the largest number of rows. Thus, there are many of these 2D arrays that have 10 to a couple hundred 0-valued rows that I don't want. For values of a that did not have a corresponding data set, the content of timeData(:,:,a) is an nx1 array of {0x0 double}.
I need to iterate over the contents of timeData in subsequent code, and I need to be able to find the size of the data set that is in timeData(:,:,a) without somehow discounting all the {0x0 double}.
How can I modify my assignment statement to fix this?
Edit: Desired output of the above example is the following with n = 5. Let this data set be represented by a = 9.
timeData(:,:,9) = {[1.1]}
{[2.3]}
{[5.5]}
{[8.6]}
{[4.4]}
Now, consider the possibility that a previous or subsequent value of the A matrix had a data set with n = 7, and n = 7 is the largest data set (largest n value). timeData(:,:,9) outputs like so in my code:
timeData(:,:,9) = {[1.1]}
{[2.3]}
{[5.5]}
{[8.6]}
{[4.4]}
{[0x0 double]}
{[0x0 double]}
#Dev-iL, as I understand it, your answer gives me the ability to delete the cells that have {[0x0 double]} in them (this is what I mean by "discounting"). This is a good plan B, but is there a way to prevent the {[0x0 double]} cells from showing up in the first place?
Edit 2: Update to the above statement "your answer gives me the ability to delete the cells that have {[0x0 double]} in them (this is what I mean by "discounting")". The cellfun(#isempty... ) function makes the {[0x0 double]}cells go to {[0x0 cell]}, it does not remove them. In other words, size(timeData(:,:,9)) is the same before and after the command is performed. This is not what I want. I want size(timeData(:,:,9)) to be 5x1 no matter what n is for any other value of a.
Edit 3: I just realized that the most desired output would be the following:
timeData(:,:,9) = {[1.1;2.3;5.5;8.6;4.4]} % An n x 1 column matrix within
% the cell.
but I can work with this outcome or the outcome as described above.
Unfortunately, I don't understand the structure of your dataset, which is why I can't suggest a better assignment method. However, I'd like to point out an operation that can you help deal with your data after it's been created:
cellfun(#isempty,timeData);
What the above does is return a logical array the size of timeData, indicating which cells contain something "empty". Typically, an array of arbitrary datatype is considered "empty" when it has at least one dimension that is equal to 0.
How can you use it to your advantage?
%% Example 1: counting non-empty cells:
nData = sum(~cellfun(#isempty,timeData(:)));
%% Example 2: assigning empty cells in place of empty double arrays:
timeData(cellfun(#isempty,timeData)) = {{}};

Using Matlab to randomly split an Excel Sheet

I have an Excel sheet containing 1838 records and I need to RANDOMLY split these records into 3 Excel Sheets. I am trying to use Matlab but I am quite new to it and I have just managed the following code:
[xlsn, xlst, raw] = xlsread('data.xls');
numrows = 1838;
randindex = ceil(3*rand(numrows, 1));
raw1 = raw(:,randindex==1);
raw2 = raw(:,randindex==2);
raw3 = raw(:,randindex==3);
Your general procedure will be to read the spreadsheet into some matlab variables, operate on those matrices such that you end up with three thirds and then write each third back out.
So you've got the read covered with xlsread, that results in the two matrices xlsnum and xlstxt. I would suggest using the syntax
[~, ~, raw] = xlsread('data.xls');
In the xlsread help file (you can access this by typing doc xlsread into the command window) it says that the three output arguments hold the numeric cells, the text cells and the whole lot. This is because a matlab matrix can only hold one type of value and a spreadsheet will usually be expected to have text or numbers. The raw value will hold all of the values but in a 'cell array' instead, a different kind of matlab data type.
So then you will have a cell array valled raw. From here you want to do three things:
work out how many rows you have (I assume each record is a row) by using the size function and specifying the appropriate dimension (again check the help file to see how to do this)
create an index of random numbers between 1 and 3 inclusive, which you can use as a mask
randindex = ceil(3*rand(numrows, 1));
apply the mask to your cell array to extract the records matching each index
raw1 = raw(:,randindex==1); % do the same for the other two index values
write each cell back to a file
xlswrite('output1.xls', raw1);
You will probably have to fettle the arguments to get it to work the way you want but be sure to check the doc functionname page to get the syntax just right. Your main concern will be to get the indexing correct - matlab indexes row-first whereas spreadsheets tend to be column-first (e.g. cell A2 is column A and row 2, but matlab matrix element M(1,2) is the first row and the second column of matrix M, i.e. cell B1).
UPDATE: to split the file evenly is surprisingly more trouble: because we're using random numbers for the index it's not guaranteed to split evenly. So instead we can generate a vector of random floats and then pick out the lowest 33% of them to make index 1, the highest 33 to make index 3 and let the rest be 2.
randvec = rand(numrows, 1); % float between 0 and 1
pct33 = prctile(randvec,100/3); % value of 33rd percentile
pct67 = prctile(randvec,200/3); % value of 67th percentile
randindex = ones(numrows,1);
randindex(randvec>pct33) = 2;
randindex(randvec>pct67) = 3;
It probably still won't be absolutely even - 1838 isn't a multiple of 3. You can see how many members each group has this way
numel(find(randindex==1))

Matlab - importing ascii data

I ve got an ascii file and im trying to import it to matlab in order to make some plots. Is there any way of importing those data, even tho they contain , (comma) rather than . (dot)?
00:00:00,000;-2,14;
00:00:00,001;-1,80;
Well the first column which I want to create is referred to the time and its corresponding to 00:00:00,001; 00:00:00,002; etc.
The second column should be the amplitude of the sample i.e. -2,14; -1,80 etc.
Yup. First use importdata so that you can read each row of your text file as a cell in a cell array. After, to allow for the processing of your times to be performed in MATLAB, you'll need to replace each , character with a .. This will allow you to use MATLAB's commands for date and time processing. Specifically, use regular expressions to help you do this. Regular expressions help you find patterns in strings. We can use these patterns to help extract out the data you need. Use regexprep to replace all , characters with a ..
For the purposes of this answer, the example data that I'm going to be using is:
00:00:00,000;-2,14;
00:00:00,001;-1,80;
00:00:00,002;-0,80;
00:00:00,003;2,40;
00:00:00,004;3,78;
Therefore, assuming that your data is stored in a text file called data.txt, do:
%// Load in each row as a cell array
A = importdata('data.txt');
%// Each row has , replaced with .
Arep = regexprep(A, ',', '\.');
Now, what we can do is split up all of the quantities by using ; as the delimiter. We can use regexp to help us split up the quantities. We can further decompose the data by:
Arep_decomp = regexp(Arep, '[^;]+', 'match');
The first parameter is the cell array that contains each of our rows in the text file (with the commas converted to periods). The second parameter is a pattern that specifies what exactly you're trying to look for in each string in the cell array. [^;]+ means that you want to find all strings that consist of a bunch of characters excluding until we hit a semi-colon. Once we hit the semi-colon, we stop. 'match' means that you want to retrieve the actual strings which will be stored as cell arrays.
The result after the above line's execution gives:
Arep_decomp{1}{1} =
00:00:00.000
Arep_decomp{1}{2} =
-2.14
Arep_decomp{2}{1} =
00:00:00.001
Arep_decomp{2}{2} =
-1.80
Arep_decomp{3}{1} =
00:00:00.002
Arep_decomp{3}{2} =
-0.80
Arep_decomp{4}{1} =
00:00:00.003
Arep_decomp{4}{2} =
2.40
Arep_decomp{5}{1} =
00:00:00.004
Arep_decomp{5}{2} =
3.78
You can see that the output cell array, Arep_decomp is a 5 element cell array, where each cell is a nested 2 element cell array, where the first element is the time, and the second element is the magnitude. Note that these are all strings.
What you can do now is create two numeric arrays that will convert these quantities into numeric representations. Specifically, the time format that you have looks like the form:
HH:MM:SS.FFF
H is for hours, M is for minutes, S is for seconds and F is for microseconds. Use datenum to allow you to convert these time representations into actual date numbers. You would do this so that you can plot these on a graph, but then you perhaps want to display these times on the plot as well. That can easily be done by manipulating some plot functions. Nevertheless, use cellfun so that we can extract out the time strings as a separate array so we can use this for plotting later, and also use this to convert the time strings into date numbers via datenum, and convert the magnitude numbers into actual numbers.
Therefore:
datestr = cellfun(#(x) x{1}, Arep_decomp, 'uni', 0);
datenums = cellfun(#(x) datenum(x, 'HH:MM:SS.FFF'), datestr);
mags = cellfun(#(x) str2double(x{2}), Arep_decomp);
The first line of code extracts out each of the time strings as a single cell array - the uni=0 flag is important to do this. Next, we convert each time string into a date number, and we convert the magnitude strings into physical numbers by str2double.
Now, all you have to do is plot the data. That can be done by:
plot(datenums, mags);
set(gca, 'XTick', datenums);
set(gca, 'XTickLabel', datestr);
The above code plots the data where the date numbers are on the horizontal axis, the magnitude numbers are on the vertical axis, but we will probably want to rename the horizontal axis to be those time strings that you wanted. Therefore, we use to calls to set to ensure that the only ticks that are visible are from the date numbers themselves, and we relabel the date numbers so that they are the string representations of the times themselves.
Once we run the above code, we get:
Because the time step in between times is so small, it may clutter the horizontal axis as the labels are long, yet the interval is short. Therefore, you may consider only displaying times at a certain interval and you can do that by doing something like:
step_size = 5;
plot(datenums, mags);
set(gca, 'XTick', datenums(1:step_size:end));
set(gca, 'XTickLabel', datestr(1:step_size:end));
step_size controls how many ticks and labels appear in succession. Obviously, you need to make sure that step_size is smaller than the total number of points in your data.
For your copying and pasting pleasure, this is what the full code I wrote looks like:
%// Load in each row as a cell array
A = importdata('data.txt');
%// Each row has , replaced with .
Arep = regexprep(A, ',', '\.');
Arep_decomp = regexp(Arep, '[^;]+', 'match');
datestr = cellfun(#(x) x{1}, Arep_decomp, 'uni', 0);
datenums = cellfun(#(x) datenum(x, 'HH:MM:SS.FFF'), datestr);
mags = cellfun(#(x) str2double(x{2}), Arep_decomp);
step_size = 1;
%step_size = 5;
plot(datenums, mags);
set(gca, 'XTick', datenums(1:step_size:end));
set(gca, 'XTickLabel', datestr(1:step_size:end));

Increasing the length of a column in MATLAB

I'm just beginning to teach myself MATLAB, and I'm making a 501x6 array. The columns will contain probabilities for flipping 101 sided die, and as such, the columns contain 101,201,301 entries, not 501. Is there a way to 'stretch the column' so that I add 0s above and below the useful data? So far I've only thought of making a column like a=[zeros(200,1);die;zeros(200,1)] so that only the data shows up in rows 201-301, and similarly, b=[zeros(150,1);die2;zeros(150,1)], if I wanted 200 or 150 zeros to precede and follow the data, respectively in order for it to fit in the array.
Thanks for any suggestions.
You can do several thing:
Start with an all-zero matrix, and only modify the elements you need to be non-zero:
A = zeros(501,6);
A(someValue:someOtherValue, 5) = value;
% OR: assign the range to a vector:
A(someValue:someOtherValue, 5) = 1:20; % if someValue:someOtherValue is the same length as 1:20