fprintf print chars and num with no loops - matlab

I'm trying to use fprintf to write a data file. Say I have a matrix containing data like this:
Values = [ 1, 735123.0, 23, 24, 25;
2, 735123.5, 34, 35, 36;
...
8000, 739122.5, 21, 22, 43]
I can write that to a file using:
fprintf(FileID, '%d, %f, %d, %d, %d', Values')
But really that second column represents dates (datestr(735123.5) = 11-Sep-2012 12:00:00) and I'd like fprintf to print dates in the second column of the data file, so that the file will read
1, 11-Sep-2012 00:00:00, 23, 24, 25
2, 11-Sep-2012 12:00:00, 34, 35, 36
...
8000, 24-Aug-2023 12:00:00, 21, 22, 43
My matrix is thousands of lines long so I'd prefer not to have to loop through line by line.
Any suggestions how to procede?

Something like
n = num2cell(Values');
n(2,:) = cellfun(#datestr, n(2, :),'UniformOutput', false);
fprintf(FileID, '%d, %s, %d, %d, %d', n{:});
Although cellfun is basically a loop.

Without for loops or cellfun:
separator = repmat(', ',size(Values,1),1); %// column used as separator
lineFeeds = repmat('\n',size(Values,1),1); %// column of line feeds
string = [ num2str((Values(:,1))) ...
separator ...
datestr(Values(:,2)) ...
separator ...
num2str(Values(:,3)) ...
separator ...
num2str(Values(:,4)) ...
separator ...
num2str(Values(:,5)) ...
lineFeeds ];
string = reshape(string.',1,[]); %'// put everything in one row
FileID = fopen('tmp.txt', 'wt'); %// use 't', or '\n' may not get written to file
fprintf(FileID, string);
fclose(FileID);

Related

CSV file export in MATLAB adding new lines

I'm trying to take in a complex csv file in MATLAB and edit/rearrange it. I used tableread to pull out the numerical data that I then manipulated. Afterwards I aimed to take the first 52 rows of text metadata, add three more rows then combine with the numerical data and output as a csv file.
However, I can't seem to find a way to work with the text metadata rows that doesn't ultimately add new lines between them when output.
e.g. this is how my csv outputs:
#HEADER
,,,,,,
Instrument, Data Processed Analysis
,,,,,
Version,1.3.1,1.25
,,,,
Created,Monday, August 16, 2021 3:13:38 PM
,,,
Filename,D5-116.NGXDP
,,,,,
When it should look like:
#HEADER
NGX, Data Processed Analysis
Version,1.3.1,1.25
Created,Monday, August 16, 2021 3:13:38 PM
Filename,D5-116.NGXDP
Here is my code:
`
close
clear
fileName = 'D5-116.NGXDP';
fileOut = fileName(1:end-6);
fileOut = append(fileOut, '.csv');
eEnergy = 1.602176634e-19; %electron energy in coulombs
resisTor = 1e11; %Resistor value for EM
%% Reading and Edit Mass Data - this is too hardcoded right now
T = readtable(fileName, 'FileType', 'text');
T = T{:,:}; %convert from table to matrix
dataOrg(:,1:3) = T(1087:1236, 1:3); %cycle:time:Ar
dataOrg(:,4) = T(935:1084, 3); %39
dataOrg(:,5) = T(783:932, 3); %38
dataOrg(:,6) = T(631:780, 3); %37
dataOrg(:,7) = T(479:628, 3); %36
dataOrg(:,7) = dataOrg(:,7) * eEnergy * resisTor; %36Ar - convert CPS to V
dataOrg(:,3:7) = dataOrg(:,3:7) * 1000; %Convert all to mV
%% Reading the metadata from the file
T2 = fopen(fileName);
metaData = fread(T2, '*char')'; %read content
fclose(T2);
results = strsplit(metaData, '\n'); %split the char data by entry spaces
metaNeat = results(:,1:52)'; %Takes the metadata prior to #collectors
metaNeat(end+1, 1) = {'Blocks, 1'}; %added data
metaNeat(end+1, 1) = {'Cycles, 150'}; %added data
metaNeat(end+1, 1) = {'Cycle, Time, 40, 39, 38, 37, 36'};
for n = 1:length(metaNeat) %scan each row, if there is a comma split them
if contains(metaNeat(n,1), ',') == 1
tempMeta = split(metaNeat(n,1), ',')';
metaNeat(n,1:size(tempMeta, 2)) = tempMeta;
clear tempMeta
end
end
outPut = metaNeat; %metadata section
outPut(end+1:(end+150), 1:7) = num2cell(dataOrg); %mass value section
writecell(outPut,fileOut,'Delimiter',',', 'FileType', 'text')
I'm sure there is a way to do this in three lines of course. My guess is that the strsplit function I'm using to separate the char cell into multiple rows is preserving the \n value. The added lines (e.g. Blocks, 1) do not show gaps in the csv file. Any tips or advice would be appreciated.
Thanks for your time,

MATLAB CSV read error

At first, I would like to say that this is not a duplicate of this: Reading CSV files with MATLAB?
In my script, I am trying to read a CSV file (sensor data). It is of the format:
2015-10-08 01:00:00.000,-0.762,-0.68,-0.234
2015-10-08 01:00:00.013,-0.762,-0.676,-0.234
2015-10-08 01:00:00.025,-0.762,-0.672,-0.234
2015-10-08 01:00:00.038,-0.762,-0.672,-0.23
and suddenly I get this error:
Error using dlmread (line 147)
Mismatch between file and format character vector.
Trouble reading 'Numeric' field from file (row number 1, field number 1) ==>
,-0.02,-0.004,1.004\n
Error in csvread (line 48)
m=dlmread(filename, ',', r, c);
Error in getAvgData (line 17)
rawData = csvread([filePath, '/', fileList.name]);
Error in precomputeProcess (line 31)
getAvgData;
This code used to work well without this error and this is the first time I am seeing this. I am not sure if textScan would be of any help. here is my code snippet:
for k = 1:length(hourSampleRateList)
hourSampleRate = hourSampleRateList(k);
disp(['Start at sampling rate: ', num2str(hourSampleRate)]);
for hour = startHour:endHour
hourStr = num2str(hour,'%02i');
filePath = fullfile(pwd, username, 'MasterSynced', yearStr, monthStr,dayStr,hourStr);
fileList = dir([filePath, '/RawDataFloat*.csv']);
if (isempty(fileList))
continue;
end
rawData = csvread([filePath, '/', fileList.name]);
avgData = zeros(ceil(length(rawData)/hourSampleRate), 4);
j = 1;
for i = 1:hourSampleRate:length(rawData)-1;
avgData(j, :) = mean(rawData(i:i+hourSampleRate-1, :));
j = j + 1;
end
filePath = fullfile(pwd, username, 'MasterSynced', yearStr, monthStr,dayStr,hourStr);
myPath = [filePath, '\Avg', num2str(hourSampleRate, '%03i'), '-', fileList.name];
if exist(myPath, 'file') == 2
delete(myPath);
end
dlmwrite(myPath,avgData,'delimiter',',','precision','%.3f');
disp(['Day-Hour(', dayStr, '-', hourStr, '): completed.']);
end
end
Any help or info would be helpful.
M = csvread(filename) reads a comma-separated value (CSV) formatted
file into array M. The file must contain only numeric values.
Your first column is a date, not a numerical value.
M = csvread(filename,R1,C1) reads data from the file starting at row
offset R1 and column offset C1.
So you may skip the first column by using rawData = csvread([filePath, '/', fileList.name],0,1);
Also if your version is < 2016b, this MATLAB Answer suggests to use textscan instead, with 'HeaderLines',8 and appropriate format discriptor, 'Delimiter', and if necessary, 'EndOfLine' declarations.

Alignment of text in matlab 'text' command

I want to print the following text on a matlab figure with ':' sign vertically aligned:
Total Events: 1234
Mean Value: 1234
Standard Deviation: 1234
1st Quartile: 1234
...
...
I am using text function and trying to insert spaces manually but they never seemed to be aligned perfectly and looks wavy.
Any helps, please.
You can use a fixed-width font and use a cell array to put the text on different lines:
text( 0, 0, { ' Total Events: 1234' ...
' Mean Value: 1234' ...
'Standard Deviation: 1234' ...
' 1st Quartile: 1234' }, 'FontName', 'FixedWidth' )
Use string format
strings = {'Total Events', 'Mean Value', 'Standard Deviation', '1st Quartile'};
max_len = max( cellfun( #numel, strings ) );
fs = sprintf( '%% %ds: 1234\n', max_len );
cellfun( #(x) fprintf(1,fs,x), strings );
Results with:
Total Events: 1234
Mean Value: 1234
Standard Deviation: 1234
1st Quartile: 1234
As you can see the command that aligns to the right is
sprintf( '% 18s: 1234', strings{1} )
So, eventually in your text command, instead of explicitly writing a string, you can format one using sprintf:
text( 0, 0, sprintf( '% 18s: %d', strings{ii}, values(ii) );
Assuming you have strings - cell array of strings and same-length array values with corresponding values to print.

How to return an array with unhappy numbers removed?

I'm quite new to using MATLAB, and am still trying to understand how to make this particular function. I understand the formula for performing this on paper, but I'm having trouble translating it into the required MATLAB syntax.
How would a function be written such that it takes an array of numbers, and returns that array with unhappy numbers removed i.e. only happy numbers remaining?
EDIT - Proving and input and output
Input:
array = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Output:
array = [7, 13, 19, 23, 31, 79, 97]
A happy number is such that a number's squared digits summed eventually equal to 1, or continue the process indefinitely as seen here.
I've written a small function (which might be further improved) to test the "happines" of a number.
Current version only works with scalar and one dim. array.
Input: the scalar or array to be tested
Output:
1) an index: happy (1) unhappy(0)
2) the list of happy number within the input set
3) the list of unhappy number within the input set
Running the function with the input specified in the question, the function returns:
function [is_happy,h_array,unh_array]=happy_number(in_val)
%
% Output:
% is_happy: 1 ==> the numberis happy
% 0 ==> the numberis unhappy
% h_array: happy numbers within input
% unh_array: unhappy numbers within input
%
% Input validity check (to be improved)
s=size(in_val);
if(iscell(in_val) || isstr(in_val) || isstruct(in_val) ...
|| ~find(s,1) || length(s) >= 3 || sum(floor(in_val)-in_val) ~= 0)
error('Only scalar or 1 dim array supported')
end
% Vars initialization
h_array=[];
unh_array=[];
h_array_cnt=1;
unh_array_cnt=1;
h_unh_cnt=1;
% Loop through input number
for i=1:length(in_val)
seq=[];
n=in_val(i);
seq_cnt=1;
seq(seq_cnt)=n;
% Test if the number is happy
while(n ~= 1 && n ~= 4)
% Decompose the number in its digits
sn=num2str(n);
nv=str2num(sn(:));
seq_cnt=seq_cnt+1;
seq(seq_cnt)=sum(nv.^2);
n=seq(seq_cnt);
end
% Set and display results
if(n == 1)
disp(['Number ' num2str(seq(1)) ' is HAPPY'])
is_happy(h_unh_cnt)=1;
h_unh_cnt=h_unh_cnt+1;
h_array(h_array_cnt)=seq(1);
h_array_cnt=h_array_cnt+1;
else
disp(['Number ' num2str(seq(1)) ' is UNHAPPY'])
is_happy(h_unh_cnt)=0;
h_unh_cnt=h_unh_cnt+1;
unh_array(unh_array_cnt)=seq(1);
unh_array_cnt=unh_array_cnt+1;
end
end
Hope this helps.
If you have the index of your unhappy numbers. You can remove them by writing :
array(unhappy_index) = [];
If you do not have the unhappy index, you can find them by using the followng command:
find()

How can I load 100 files with similar names and/or string in just one step in MATLAB?

I have 100 ASCII files in my directory all named as follows:
int_001.ASC
int_002.ASC
int_003.ASC
.
.
.
int_099.ASC
int_100.ASC
I have to import them in MATLAB all with importdata, which should work as follows:
A = importdata('int_001.ASC', ' ', 9)
x = A.data(:,1)
y = A.data(:,2)
My question is: how can I avoid writing 100 times importdata? Is there a way to write the first string only and then have all data uploaded?
Thanks
fls = dir( 'int_*.ASC' );
for fi=1:numel(fls)
A{fi} = importdata( fls(fi).name, ' ', 9 );
% ...
end
UPDATE:
You may use string formatting to read the files according to their numbers:
for fi=1:100
A{fi} = importdata( sprintf('int_%03d.ASC', fi ), ' ', 9 );
% ...
end
You can use strcat function in a for loop :
for k=1:n
fileName = strcat('int_',num2str(k, '%03d'),'.ASC');
A(k) = importdata(fileName, ' ', 9);
x(k) = A(k).data(:,1);
y(k) = A(k).data(:,2);
end
If you want to take this a little overboard:
alldata = arrayfun(...
#(dirEntry)importdata(dirEntry.name, ' ', 9), ...
dir('int_*.ASC'),...
'uniformoutput',false);
This line does the following
Gets a listing of all files matching the partial filename, as an array of structures (h/t Shai)
For each element in that array, performs the importdata call from your original post.
Compiles all the outputs into a cell array.