Matlab -- Conversion to double from cell is not possible - matlab

Can someone tell me why I am receiving this error --
??? The following error occurred converting from cell to
double:
Error using ==> double
Conversion to double from cell is not possible.
Error in ==> test at 18
CX(end+1,:) = temp(1);
Here is the code:
file = fopen('C:\Program Files (x86)\Notepad++\testFile.txt'); % open text file
tline = fgetl(file); % read line by line and remove new line characters
%declare empty arrays
CX = [];
CY = [];
CZ = [];
while ischar(tline) % true if tline is a character array
temp = textscan(fid,'%*s%f%f%f','Delimiter',',<>'); % loads the values from all rows with the specified format into the variable data
CX(end+1,:) = temp(1);
CY(end+1,:) = temp(2);
CZ(end+1,:) = temp(3);
tline = fgetl(file);
end
fclose(file); % close the file
plot3(CX, CY, CZ) % plot the data and label the axises
xlabel('x')
ylabel('y')
zlabel('z')
grid on
axis square

Quick guess: does using curly braces help?
CX(end+1,:) = temp{1}

Use cell2mat to convert from a cell array (what textscan returns) to a numeric array, which you can use (like append to, in your case) with other numeric arrays.
I would also recommend using vertcat rather than the approach you've taken to concatenating:
CX = vertcat(CX, cell2mat(temp(1)));
Or, you could read all 3 values in to a row and concatentate into a N-by-3 matrix instead... lots of options.

Related

Issues printing a character string in Matlab

I'm new to MATLAB and I'm having problems printing a character array to a file. I only get the first character printed out. I read lines from a file and build an matrix of matrices. One matrix is an array of character vectors. Here's how I read the data
tline = fgetl(iin);
t_current = tline(9:34);
...
data.t = [data.t; t_current];
Then later I do this:
npts = length(data.t);
fid1 = fopen(fname, 'w');
fprintf(fid1, 'Day Rank\n');
fprintf(fid1, '------- -------\n');
for k = 1:npts
time_str = data.t(k);
fprintf(fid1, '%s %f3\n',time_str, data.rank(k));
end
fclose(fid1);
data.t is <10082,26 char> and looks something like this:
val =
2015-07-16T03:28:36.410305
2015-07-16T03:29:00.000000
...
All I get with the fprintf is a '2'. I tried to use convertCharsToStrings but that failed with an error message: Undefined function 'convertCharsToStrings' for input arguments of type
'char'.
This must be something simple I'm missing.
Thanks,
-Mike
Since "data.t is <10082,26 char>", try this:
...
for k = 1:npts
time_str = data.t(k, :);
...
If you do not use the , :, Matlab will use linear indexing for the matrix as opposed to subscripts.
It turns out I needed to use a different format for getting the time string:
time_str=data.t(k,1:end)

Reading a Complex CSV format Into Matlab

4,7,33 308:0.364759856031284 1156:0.273818346738286 1523:0.17279792082766 9306:0.243665855423149
7,4,33 1156:0.185729429759684 1681:0.104443202690279 5351:0.365670526234034 6212:0.0964006003127458
I have a textfile in the above format. The first 3 columns are labels and need to be extracted into another file keeping the order intact.
As one proceeds through the file, each row has varying number of labels. I have been reading the csvread function in Matlab but that is generic and would not work in the above case.
Next, I need to extract
308:0.364759856031284 1156:0.273818346738286 1523:0.17279792082766 9306:0.243665855423149
such that at column 308 in the Matrix for Row 1, I put in the value 0.364759856031284.
Since your row format changes you need to read the file line by line
fid = fopen(filename, 'rt'); % open file for text reading
resultMatrix = []; % start with empty matrix
while 1
line = fgetl(fid);
if ~ischar(line), break, end
% get the value separators, :
seps = strfind(line, ':');
% get labels
whitespace = iswhite(line(1:seps(1)-1)); % get white space
lastWhite = find(whitespace, 'last'); % get last white space pos
labelString = deblank(line(1:lastWhite)); % string with all labels separated by ,
labelString(end+1) = ','; % add final , to match way of extraction
ix = strfind(labelString, ','); % get pos of ,
labels = zeros(numel(ix),1); % create the labels array
start = 1;
for n1 = 1:numel(labels)
labels(n1,1) = str2num(labelString(start:ix(n1)-1));
end
% continue and do a similar construction for the COL:VALUE pairs
% If you do not know how many rows and columns your final matrix will have
% you need to continuously update the size 1 row for each loop and
% then add new columns if any of the current rows COLs are outside current matrix
cols = zeros(numel(seps,1);
values = cols;
for n1 = 1:numel(seps)
% find out current columns start pos and value end pos using knowledge of
% the separator, :, position and that whitespace separates COL:VALUE pairs
cols(n1,1) = str2num(line(colStart:seps(n1)-1));
values(n1,1) = str2num(line(seps(n1)+1:valueEnd));
end
if isempty(resultMatrix)
resultMatrix = zeros(1,max(cols)); % make the matrix large enough to hold the last col
else
[nR,nC] = size(resultMatrix); % get current size
if max(cols) > nC
% add columns to resultMatrix so we still can fit column data
resultMatrix = [resultMatrix, zeros(nR, max(cols)-nC)];
end
% add row
resultMatrix = [resultMatrix;zeros(1,max(nC,max(cols)))];
end
% loop through cols and values and populate the resultMatrix with wanted data
end
fclose(fid);
Note, the above code is untested so it will contain errors but it should be easy to fix.
I purposely left out minor parts and it should not be too difficult filling that out.

Reading dat file into matrix in matlab with different different amounts of data each row

I'm trying to write a matlab function that will load a data into a matrix. The problem is the data has one more value each row. So I can't use load unfortunately, so I'm trying to use fgetl.
The data looks like:
143234
454323 354654
543223 343223 325465
etc
What I did is create a matrix of zeros, the dimensions being the height and the longest string of data. To put the data into the matrix I used fgetl to read each row and then used textscan to split the data up at whitespace. Then I used str2num (I think this is where the error is) to convert the string to a number.
First heres my code:
%READTRI Opens the triangle dat file and turns it into a matrix
fid = fopen('triangledata.dat');
%create matrix of zeros for the data to be retrieved
trimat = zeros(15,15);
%Check to see if the file loaded properly
if fid == -1
disp('File load error')
else
%if it does, continue
%read each line of data into a
while feof(fid) == 0
%run through line by line
aline = fgetl(fid);
%split aline into parts by whitespace
splitstr = textscan(aline,'%s','delimiter',' ');
%This determines what row of the matrix the for loop writes to
rowCount = 1;
%run through cell array to get the numbers out and write them to
%the matrix
for i = 1:length(splitstr)
%convert to number
num = str2num(splitstr{i});
%write num to matrix
trimat(rowCount, i) = num;
end
%iterate rowCount
rowCount = rowCount + 1;
end
%close the file
closeresult = fclose(fid);
%check for errors
if closeresult == 0
disp('File close successful')
else
disp('File close not successful')
end
end
end
The error I'm getting is:
Error using str2num (line 33)
Requires string or character array input.
Error in readTri (line 32)
num = str2num(splitstr{i});
What bothers me is that when I try, in the interactive console the same thing that goes on in the loop i.e. import aline, split it into a cell array using textscan, then use num2str to convert it to a integer. Everything works. So either the way I'm using num2str is wrong or the for loop is doing something funky.
I was just hoping for ideas, there is a LOT of data so adding zeros to make load work is not possible.
thanks for reading!
You can use dlmread instead of load or fgetl
It automatically returns a matrix with zeros whenever the line is not as long as the longest.
Just do
matrix = dlmread('triangledata.dat');
Why not using textscan?
fid = fopen('test.txt','r');
C = textscan(fid, '%f%f%f');
fclose(fid);
res = cell2mat(C)
The result is
res =
143234 NaN NaN
454323 354654 NaN
543223 343223 325465
where missing values are NaN.

Reading parameters from a text file into the workspace

I have a file which has the following information:
% ---------------------- location details --------------------------
%
% lat : latitude [minimum = -90, maximum = 90, unit =
% degrees north]
% lon : longitude [ minimum = -360, maximum = 360, unit =
% deg east]
% z: altitude (above sea level, m)
%---------------------------------------------------------------
% location:
lat = 54.35
lon = -2.9833
This is a small section of the file.
I would like to read some of this information into MATLAB, where the information can then be used to perform some calculations. The part of the file that I would like to read into MATLAB are those in the text file that are not commented, i.e have a % at the start of the line, and the variable should then be saved in the workspace. For example, I would like to have:
lat = 54.35
lon = -2.9833
in the workspace.
How would I go about this? I have read about textscan and fopen, although these don't really seem to help me in this instance.
The quick-and-dirty approach
The simplest solution I could think of to read this file indeed employs textscan :) and since the lines are conveniently written in valid MATLAB syntax, you could use eval later to evaluate them. Start by reading each line as one string (ignoring the comments in the header)
fid = fopen(filename);
C = textscan(fid, '%s', 'Delimiter', '', 'CommentStyle', '%')
fclose(fid);
Then feed the lines one by one into eval to create the variables in the MATLAB workspace:
cellfun(#eval, C{1});
What this does is interpret the line as a MATLAB command, i.e create variables as named in the file and assign the appropriate values. If you want to suppress the output of eval, you can use evalc instead to "absorb the output":
cellfun(#evalc, C{1}, 'UniformOutput', false);
This should work for your basic example, but it would fail if you have more than one instance of any parameter. Also note that the eval family is notoriously slow.
A more robust approach
If the lines in your file structure have the parameter name = number pattern, you can read the lines more intelligently:
fid = fopen(filename);
C = textscan(fid, '%[^= ]%*[= ]%f', 'CommentStyle', '%')
fclose(fid);
The %[^= ] in the pattern matches the first characters until the first space or equality sign. The %*[ =] ignores the equality sign and any trailing spaces, and then the numerical value is matched with %f. The resulting cell array C stores the parameter names in the first cell and their corresponding values in the second cell.
Now it's up to you to manipulate the parsed data. For instance, to extract all values of lat and lon, you can do this:
lat = C{2}(strcmp(C{1}, 'lat'));
lon = C{2}(strcmp(C{1}, 'lon'));
If you have more than one "lat" line, lat will be an array holding all these values.
Here's another quick and dirty way:
fp = fopen('foo.txt');
found = 1;
while ~feof(fp)
line = fgetl(fp);
if (line(1) ~= '%') && ischar(line)
value(found) = sscanf(line,'%*s %*s %f');
found = found + 1;
end
end
The %*s skips the 'lat' or 'long' and the '='.
The example you provided is kinda well-behaved, therefore the following solution might need some tailoring. However, I would recommend it against any eval():
% Read whole file ignoring lines that start with '%' and using '=' as delimiter
fid = fopen('test.txt');
s = textscan(fid,'%s%f', 'CommentStyle','%','Delimiter','=');
fclose(fid);
% Identify lines with latitude and those with longitude
idxLat = strncmpi('lat',s{1},3);
idxLon = strncmpi('lon',s{1},3);
% Store all latitudes and longitudes
lat = s{2}(idxLat);
lon = s{2}(idxLon);
Gets you a structure with field names matching parameter names, accepts comma-separated lists. List any parameters that should stay as strings in char_params
char_params={};
fid = fopen(filename);
% Load lines into cell (1x1) containing cell array s (Nx1),
% skipping lines starting with % and cutting off anything after % in a line
s = textscan(fid,'%s', 'CommentStyle','%','Delimiter','%');
fclose(fid);
% access the lines strings s{1}, split across '=' and remove whitespace on both sides
s=strtrim(split(s{1},'='));
% Interpret parameters and save to structure
for ind=1:length(s)
% User says which parameters are strings
if any(strcmpi(s{ind,1},char_params))
file_struct.(s{ind,1})=s{ind,2};
% Otherwise, assume they are numbers or numeric row arrays
else
% remove parentheses and brackets
trim_s=regexprep(s(ind,2),'[[]()]','');
% convert comma-separated lists into row arrays
file_struct.(s{ind,1})=str2double(split(trim_s{1},',')).';
end
end

Reading a text file and plotting it in 3D

I want to read in a text file that contains some strings but mostly numbers. I want to be able to ignore the strings and only look at the numbers. I want to plot those values on a 3D plane. The data looks like this:
Tech4:<152.266724,173.189377,27.995975>
<117.880638,156.116531,27.999983>
<129.849899,59.195660,27.999983>
<249.321121,60.605404,27.999983>
<224.120361,139.072739,28.000668>
<171.188950,143.490921,56.933430>
<171.188950,143.490921,83.548088>
<171.188950,143.490921,27.999985>
I believe to read in a file is just:
File = textread('testFile.txt');
How can I only look at those values and then plot it.
Thanks!
fid = fopen([pathname,filename]);
tline = fgetl(fid);
CX = [];
CY = [];
CZ = [];
while ischar(tline)
% skip < and >
tline = substr(tline, 1, length(tline)-2)
% extract numbers
temp = textscan(tline,'%n%n%n', 'delimiter',',');
CX(end+1,:) = [temp(1)];
CY(end+1,:) = [temp(2)];
CZ(end+1,:) = [temp(3)];
tline = fgetl(fid);
end
fclose(fid);
and then plot it using
plot3(CX, CY, CZ)
function call.
Add the check for "Tech4:" at the beginning however...
I think you can also directly use textscan in a one-liner:
fid = fopen('testFile.txt');
data = textscan(fid,'%*s%f,%f,%f');
fclose(fid);
this loads the values from all rows with the specified format into the variable data.
no matlab around to test it out though.
fscanf is an option to, the same kind of parameters as textscan.
EDIT: typo, you want to detect floats (%f) of course, and not integers (%d)
EDIT2: got matlab and tested it out, this works here for your sample input ^^
fid = fopen('testFile.txt');
data = textscan(fid,'%*s%f%f%f','Delimiter',',<>')
fclose(fid);