Convert Matlab Console output to new expression - matlab

In order to debug a very complex set of functions, I want to isolate a subfunction from the workspace in order to make different test. Therefore a need selected values from the function workspace to be defined already. By setting a break point at the specific position I can "look" into the current workspace by displaying the values in the console, like the variable HF33
HF33 =
1.0777 0.0865 0.0955
-0.1891 0.8110 -0.1889
0.0935 0.0846 1.0755
Is there some function / script that could convert this result to a new Matlab expression that can be pasted somewhere else (for example at the head of a new script), e.g.:
HF33 = [ 1.0777, 0.0865, 0.0955;
-0.1891, 0.8110, -0.1889;
0.0935, 0.0846, 1.0755 ];
With that I could test the subfunction and its behavior by easily changing the given values and see whats happening without having the huge debug workspace running.
Is there some easy function like res2exp(HF33)?

First: Create this function to get the variable name
function out = varname(var)
out = inputname(1);
end
you can print it direct to console:
fprintf('%s =%s\n',varname(varToSave),mat2str(varToSave));
Or use fopen and fprint to write it in a file
fop = fopen('filename','w');
fprint(fop,'%s = %s' ,varname(varToSave),mat2str(varToSave));
fclose(fop);
I think this will help you

It might be a function like mat2str() you are looking for but it will not give exactly the printout you are asking for. Here is an example of how it could be used:
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> B = mat2str(A)
B =
[16 2 3 13;5 11 10 8;9 7 6 12;4 14 15 1]
And if you want the output to be totally copy/paste-able you could use:
disp(['C = ',mat2str(A)])
C = [16 2 3 13;5 11 10 8;9 7 6 12;4 14 15 1]

I made this up just now. It is not formatted beautifully, but it achieves what you are trying to do - if I understand you correctly.
a = [ 2 3 4 5
4 5 5 6
3 4 5 6];
fprintf('\nb = [\n\n');
disp(a);
fprintf(']\n\n');
Copy and paste this and see if it does what you want. It's also very simple code, so you could modify it if the spacing and newline characters aren't where you want them.
You could also make a small function out of this if you wanted to.
If you want me to make a function of it, let me know... I can do it tomorrow. But you can probably figure it out.
Ehh, I just made the function. It didn't take long.
function reprint_matrix(matrix)
var_name = inputname(1);
fprintf('\n%s = [\n\n', var_name);
disp(matrix);
fprintf(']\n\n');
end

I'm not sure what you are looking for, but I think this will help you:
http://www.mathworks.com/matlabcentral/fileexchange/24447-generate-m-file-code-for-any-matlab-variable/content/examples/html/gencode_example.html
Did not use it because I use mat-files to transfer data.
You can combine it with the clipboard function:
clipboard('copy',gencode(ans))

Though there are several ways to write variables to text, saving variables as text is definitely bad practice if it can be avoided. Hence, the best advice I can give you is to solve your problem in a different way.
Suppose you want to use HF33 in your subfunction, then here is what I would recommend:
First of all, save your variable of interest:
save HF33 HF33
Then when you are in the function where you want to use this variable:
load HF33
This assumes that your working directory (not workspace) is the same in both cases, but otherwise you can simply add the path in your save or load command. If you want to display it you can now simply call the variable HF33 without a semicolon (this is probably the only safe way to display it exactly the way you expect in all cases).
Note that this method can easily be adapted to transfer multiple variables at once.

Related

How to import dates correctly from this .csv file into Matlab?

I have a .csv file with the first column containing dates, a snippet of which looks like the following:
date,values
03/11/2020,1
03/12/2020,2
3/14/20,3
3/15/20,4
3/16/20,5
04/01/2020,6
I would like to import this data into Matlab (I think the best way would probably be using the readtable() function, see here). My goal is to bring the dates into Matlab as a datetime array. As you can see above, the problem is that the dates in the original .csv file are not consistently formatted. Some of them are in the format mm/dd/yyyy and some of them are mm/dd/yy.
Simply calling data = readtable('myfile.csv') on the .csv file results in the following, which is not correct:
'03/11/2020' 1
'03/12/2020' 2
'03/14/0020' 3
'03/15/0020' 4
'03/16/0020' 5
'04/01/2020' 6
Does anyone know a way to automatically account for this type of data in the import?
Thank you!
My version: Matlab R2017a
EDIT ---------------------------------------
Following the suggestion of Max, I have tried specifiying some of the input options for the read command using the following:
T = readtable('example.csv',...
'Format','%{dd/MM/yyyy}D %d',...
'Delimiter', ',',...
'HeaderLines', 0,...
'ReadVariableNames', true)
which results in:
date values
__________ ______
03/11/2020 1
03/12/2020 2
NaT 3
NaT 4
NaT 5
04/01/2020 6
and you can see that this is not working either.
If you are sure all the dates involved do not go back more than 100 years, you can easily apply the pivot method which was in use in the last century (before th 2K bug warned the world of the danger of the method).
They used to code dates in 2 digits only, knowing that 87 actually meant 1987. A user (or a computer) would add the missing years automatically.
In your case, you can read the full table, parse the dates, then it is easy to detect which dates are inconsistent. Identify them, correct them, and you are good to go.
With your example:
a = readtable(tfile) ; % read the file
dates = datetime(a.date) ; % extract first column and convert to [datetime]
idx2change = dates.Year < 2000 ; % Find which dates where on short format
dates.Year(idx2change) = dates.Year(idx2change) + 2000 ; % Correct truncated years
a.date = dates % reinject corrected [datetime] array into the table
yields:
a =
date values
___________ ______
11-Mar-2020 1
12-Mar-2020 2
14-Mar-2020 3
15-Mar-2020 4
16-Mar-2020 5
01-Apr-2020 6
Instead of specifying the format explicitly (as I also suggested before), one should use the delimiterImportoptions and in the case of a csv-file, use the delimitedTextImportOptions
opts = delimitedTextImportOptions('NumVariables',2,...% how many variables per row?
'VariableNamesLine',1,... % is there a header? If yes, in which line are the variable names?
'DataLines',2,... % in which line does the actual data starts?
'VariableTypes',{'datetime','double'})% as what data types should the variables be read
readtable('myfile.csv',opts)
because the neat little feature recognizes the format of the datetime automatically, as it knows that it must be a datetime-object =)

Looping through a set of variables sharing the same prefix

I routinely work with student exam files, where each response to an exam item is recorded in points. I want to transform that variable into 1 or 0 (effectively reducing each item to Correct or Incorrect).
Every dataset has the same nomenclature, where the variable is prefixed with points_ and then followed by an identification number (e.g., points_18616). I'm using the following syntax:
RECODE points_18616 (0=Copy) (SYSMIS=SYSMIS) (ELSE=1) INTO Binary_18616.
VARIABLE LABELS Binary_18616 'Binary Conversion of Item_18616'.
EXECUTE.
So I end up creating this syntax for each variable, and since every dataset is different, it gets tedious. Is there a way to loop through a dataset and perform this transformation on all variables that are prefixed with points_?
Here is a way to do it:
First I'll create a little fake data to demonstrate on:
data list list/points_18616 points_18617 points_18618 points_18619 (4f2).
begin data
4 5 6 7
5 6 7 8
6 7 8 9
7 8 9 9
end data.
* the following code will create a list of all the relevant variables in a new file.
SPSSINC SELECT VARIABLES MACRONAME="!list" /PROPERTIES PATTERN = "points_*".
* now we'll use the created list in a macro to loop your syntax over all the vars.
define !doList ()
!do !lst !in(!eval(!list))
RECODE !lst (0=Copy) (SYSMIS=SYSMIS) (ELSE=1) INTO !concat("Binary", !substr(!lst,7)).
VARIABLE LABELS !concat("Binary", !substr(!lst,7)) !concat("'Binary Conversion of Item",!substr(!lst,7) ,"'.").
!doend
!enddefine.
!doList.
EXECUTE.

How to get a script to give a value to an input prompt?

I have a collection of smaller scripts foo1, foo2, etc. and a script master.m that runs them all, like this:
% master.m
run foo1
run foo2
Let's say foo1 calls for input somewhere by saying a = input('Gimme a number\n');.
I thought that if I put the value(s) I wanted on new lines after the run command that they would be entered as input, but they don't. I've also tried enclosing them as a string, i.e. '5'. That doesn't work either.
Is their another function I should use? I looked at the help file for input, but there's no output function. Presumably there's something like write or writetostdio somewhere.
How do I give user input to a script that is being called by another script without touching the keyboard? Can I put the values I want to input in the master.m file?
EDIT:
Because there's some confusion, I'll try to clear it up.
The scripts foo1 and foo2 will NOT be passing values back and forth. Every script will be run independently. Instead, I'm trying to test a program for a range of user behaviours (which are responses to prompts via input in foo1). These are normally typed on the keyboard, but I want my master.m file to tell foo1 what the user inputs are.
Sorry if this is confusing, but hopefully that clears it up.
Modifying existing code to accommodate both manual input and testing inputs is trivial:
function foo1(niterations)
if nargin == 0
niterations = round(input('How many iterations? '));
end
for ii = 1:numel(niterations)
% Run the thing
fprintf('Running some random program with %d iterations! Yay!\n', niterations(ii));
end
end
Using this approach we can do:
>> foo1
How many iterations? 2
Running some random program with 2 iterations! Yay!
or
>> foo1(2)
Running some random program with 2 iterations! Yay!
or
>> foo1([1, 3, 5, 7, 9])
Running some random program with 1 iterations! Yay!
Running some random program with 3 iterations! Yay!
Running some random program with 5 iterations! Yay!
Running some random program with 7 iterations! Yay!
Running some random program with 9 iterations! Yay!
This is far more logical than trying to pipe things from text files, use evalin to poof things into workspaces, or whatever automagical approach is required to accommodate using scripts in this fashion.
Ok, this is a bit ugly... but might be a work-around if for some reason foo1.m etc. have to remain as scripts.
The idea is to replace each instance of input with a newly defined function myInput which checks if a variable PROMPT_VALUE has been set in the base work-space; and returns that if so, and otherwise passes through to the built-in input. For example:
% myInput.m
function [ valueOut ] = myInput( promptString )
W = evalin('caller','whos'); %or 'base'
doesPVexist = ismember('PROMPT_VALUE',[W(:).name]);
if doesPVexist
valueOut = evalin('caller', 'PROMPT_VALUE');
else
valueOut = input(promptString);
end
end
Assuming we have the following sub-scripts:
% foo1.m
a = myInput('Number to double: ');
disp(2*a);
% foo2.m
b = myInput('Number to halve: ');
disp(b/2);
We can test the approach as follows:
% master.m
clearvars;
PROMPT_VALUE=5;
run foo1.m;
PROMPT_VALUE=3;
run foo2.m
If you run this as-is it will take the PROMPT_VALUE as inputs to each of the subscripts (returning 10, and 1.5). If those lines are commented out it will look for input from the user.

How to import large dataset and put it in a single column

I want to import the large data set (multiple column) by using the following code. I want to get all in a single column instead only one row (multi column). So i did transpose operation but it still doesn't work appropriately.
clc
clear all
close all
dataX_Real = fopen('dataX_Real_in.txt');dataX_Real=dataX_Real';
I will really appreciate your support and suggestions. Thank You
The sample files can be found using the following link.
When using fopen, all you are doing is opening up the file. You aren't reading in the data. What is returned from fopen is actually a file pointer that gives you access to the contents of the file. It doesn't actually read in the contents itself. You would need to use things like fread or fscanf to read in the content from the text data.
However, I would recommend you use dlmread instead, as this doesn't require a fopen call to open your file. This will open up the file, read the contents and store it into a variable in one function call:
dataX_Real = dlmread('dataX_Real_in.txt');
By doing the above and using your text file, I get 44825 elements. Here are the first 10 entries of your data:
>> format long;
>> dataX_Real(1:10)
ans =
Columns 1 through 4
-0.307224970000000 0.135961950000000 -1.072544100000000 0.114566020000000
Columns 5 through 8
0.499754310000000 -0.340369000000000 0.470609910000000 1.107567700000000
Columns 9 through 10
-0.295783020000000 -0.089266816000000
Seems to match up with what we see in your text file! However, you said you wanted it as a single column. This by default reads the values in on a row basis, so here you can certainly transpose:
dataX_Real = dataX_Real.';
Displaying the first 10 elements, we get:
>> dataX_Real = dataX_Real.';
>> dataX_Real(1:10)
ans =
-0.307224970000000
0.135961950000000
-1.072544100000000
0.114566020000000
0.499754310000000
-0.340369000000000
0.470609910000000
1.107567700000000
-0.295783020000000
-0.089266816000000

copying every nth line and duplicating it on it's following line

I am trying to make test files for the project, and I figured in order to make a bradycardia test file from an example file of a normal ECG.
Therefore I would need to copy every third line and insert it into the next line.
for example:
a = [
1
2
3
4
5
6
7
8
9
10]
and I want:
b = [
1
2
3
3
4
5
6
6
7
8
9
9
10]
and so on... but since the file is 6000 characters long, obviously i cannot manually copy it. And I need it to be 9000 characters long I've tried looking online on how to do this, and am having no luck.
Any suggestions?
b=zeros(floor(4/3*length(a)),1);
b(1:4:end)=a(1:3:end);
b(2:4:end)=a(2:3:end);
b(3:4:end)=a(3:3:end);
b(4:4:end)=a(3:3:end);
Another way:
b = a(sort([1:numel(a) 3:3:numel(a)]))
And here is a third faster and simpler method
b = a(round(1:0.75:numel(a)))
This only works if length(a) is a multiple of 3, but seems to be faster than the other answers, at least for large vectors:
b = reshape([reshape(a,3,[]); a(3:3:end).'],[],1);