%% Introduction to Matlab
% 
% Videos
% <https://www.mathworks.com/videos/live-script-features-for-online-teaching-1613631548624.html 
% Introduction to Live Scripting>

clear all
close
clc
% Some dummy code

x = 1:0.1:10
y = x .^ 2
plot (x,y)
% Basics
% Data Types
%% 
% * Integers, Real, Strings, Booleans
% * By default MATLAB creates numbers to be *double* precision
% * The type of data in a variable is reported by the *class* command

% integers - can be int8, int16, int32, and int64
x = int32(9);
% real numbers -- single (32) or double (64) precision 
% explicitly defined as single precision
y = single(5.3);
% double precision is default number type
z = 1.5e-7;
% string variable
s = "This is a string";
% boolean variable true or false
b = true;

fprintf("class of x is %s and its value is %d", class(x), x);
fprintf("class of y is %s", class(y));
fprintf("class of b is %s", class(b));

% Vectors and Matrices 
% Vectors and Matrices are created using the square brackets notation. Elements 
% are separated by commas or spaces, and a semicolon designated a new row. The 
% function _length(v)_ returns the length of a vector. The function _size(m)_  
% returns a vector with the dimensions of the matrix. The length of a matrix is 
% essentially the size of its longest dimension. 

v = 1:10
sprintf("The length of vector v is %d", length(v))

m = [1 2 4 4; 8 1 6 5]
sprintf("The size of matrix m");
disp(size(m));

sprintf("The length of matrix m is %d", length(m))
% Plotting 
%% 
% # Create a vector *x* of values from 0 to $$2\pi$$ in steps of 0.1
% # Create another vector *y* by taking sin(x) -- i.e. trignometric sine function 
% for each value in *x*
% # Plot *y* vs. *x* 

% create x
x = 0:0.1:2*pi;
% create y
y = sin(x);
% plot y vs x
plot(x, y);
grid on
title("Sine Function")
xlabel("x")
ylabel("sin(x)")

% Plotting and labeliing
% Multiple plots are shown. One of the points is also labelled. 


figure()
x = 0:0.1:2*pi;
y=sin(x);
plot(x,y)
grid on
% plotting the second graph
hold on
z = exp(-x);
plot(x,z,'r:*');
axis ([ 0 2*pi 0 1])
title('2-D Plots');
xlabel('Time');
ylabel('Sin(t)');

% This is text for creating the legend
text(pi/3,sin(pi/3),'\leftarrow (sin \pi/3)')
legend('Sine Wave','Decaying Exponential');
% String comparisons and find function 
% _strfind_ functions is used for finding the location of a pattern within a 
% string. 
%% 
% * Ask the user to enter a string. Note that the user input should be enclosed 
% in quotes for it to be treated as a string. Alternatively, one may use the option 
% "s" to force the input to be treated as a string
% * Find the location of the pattern "the" in the string. 

str = input("Enter a string to search: ", "s")
str = lower(str);
pat = "the";
locs = strfind(str, pat);
sprintf("Locations of %s ", pat);
disp(locs)
%% 
% The function _strcmp_ is used to compare strings
%% 
% * Create a string variable _*eco*_  and set to "Eco-RI"
% * Create an array _*enymes*_ of string variables = {"Bam-HI", "Eco-RI", "Hind-III"}
% * Find the _find_ function to get the index of _*eco*_ within _*enzymes*_

eco = "Eco-Ri";
enzymes = ["Bam-HI", "Eco-RI", "Hind-III", "Eco-RI"];
match = strcmpi(eco, enzymes)
indx = find(match);
sprintf("Found %s at locations ", eco)
disp(indx)
% Computing non-overlapping and overlapping pattern counts
% Consider the string "AAACCTAATAAA"
%% 
% * Provide command for finding count of non-overlappring occurrence of "AA" 
% or "AT" in the string
% * Provide command for finding count of overlapping occurrence of the above 
% pattern using the lookahead operator (?=pat) which matches _pat_ but doesn’t 
% consume it.
%% 
% Note that regular expressions [AT] matches _one_ character specified in the 
% list of characters enclosed in square brackets. A range of charactes to choose 
% from may also be specified, such as [A-Za-z] is valid specification to choose 
% an alphabetical character. 

seq = "AAACCTAATAAA";
freq = pattern_count("A[AT]", seq);
pat = "A[AT]";
locs = regexp(seq, pat);

fprintf ("Non-overlapping frequency count %-d", length(locs));

pat = "A(?=[AT])";
locs = regexp(seq, pat);
freq = pattern_count("A(?=[AT])", seq);
fprintf ("Overlapping frequency count %-d", length(locs));
% Functions
% A function may be used to count patterns. Functions enable modularization 
% and reusing the same logic.
% 
% A function defined in the Appendix checks to see if a set of 3 lengths form 
% a triangle. In order to check if a triangle is formed by three lengths, the 
% triangle inequlaity must be satisfied. That is, the length of the largest side 
% must be less than the sum of two other sides. 

is_triangle(3, 4, 5)
is_triangle(3, 9, 5)
%% 
% Function _pattern_count_ (defined at the end of live-script) computes the 
% count of occurrences of a regular expression in a string.
% 
% Alternatively, functions may be defined as separate ".m" files.

seq = "AAACCTAATAAA";
pat = "A[AT]";
freq = pattern_count(seq, pat);

fprintf ("Non-overlapping frequency count %-d", freq);

pat = "A(?=[AT])";
freq = pattern_count(seq, pat);
fprintf ("Overlapping frequency count %-d", freq);
% Containers
% Cell Arrays
% A cell array is a data type with indexed data containers called cells, where 
% each cell can contain any type of data, including other cell arrays.
%% 
% * Create an empty cell array with 3 rows and 2 coulums
% * The three rows of the cell array contains the following elements:
%% 
% # "eye", 3x3 identify matrix
% # "fibonacci", array with elements: [1, 1, 2, 3, 5]
% # "magic", a 3x3 magic square
%% 
% * Display the cell array

mycell = cell(3,2);
mycell(1,1) = {"eye"};
mycell(1,2) = {eye(3)};

mycell(2,1) = {"fibonacci"};
mycell(2,2) = {[1, 1, 2, 3, 5]};

mycell(3,1) = {"magic"};
mycell(3,2) = {magic(3)};

disp ("Display elements of the cell")
celldisp(mycell)

disp ("Graphical Schematic of cell array contents")
cellplot(mycell)
% Structures
%% 
% * Create a structure array with patient records, with each patient's age, 
% blood glucose, and heart-rate;
%% 
% John Smith, Age = 30, Blood Gucose = 109, Heart Rate = 80
% 
% Sally Snow, Age = 24, Blood Gucose = 99, Heart Rate = 68
% 
% Arun Seth, Age = 47, Blood Glucose=116, Heart Rate = 84
% 
% Sonia Bull, Age = 39, Blood Glucose=118, Heart Rate = 81
%% 
% * Create a stacked bar graph with three series: Age, Glucose, and HR

% Create an array of structures

pats = struct();
pats(1).Name = "John Smith";
pats(1).Age = 30;
pats(1).Glucose = 109; 
pats(1).HR = 80;

pats(2).Name = "Sally Snow";
pats(2).Age = 24;
pats(2).Glucose = 99; 
pats(2).HR = 68;

pats(3).Name = "Arun Seth";
pats(3).Age = 47;
pats(3).Glucose = 116; 
pats(3).HR = 84;

pats(4).Name = "Sonia Bull";
pats(4).Age = 39;
pats(4).Glucose = 118; 
pats(4).HR = 81;

% extract ages, glucose, and heart rate

age = [pats.Age];
glucose = [pats.Glucose];
hr = [pats.HR];

res = [age' glucose' hr'];
names = categorical([pats.Name]);
bar(names, res);
grid;
legend({'Age', 'Glucose', 'HR'}, ...
    'Location', 'eastoutside');
% Tables
%% 
% * Create a cell array of names: "Adam", "John", "Sally"
% * Create an array of scores: [81, 72, 90]
% * Create a table of names and scores. Table's column names should be "Student", 
% "Score"
% * Add a new column to the table named "Grade"
% * Assign the grades to students based on logic:
%% 
% $$\text{Grade} = \left\{    \begin{array}{lr}        A, & \text{if score}  
% \geq 90\\        B, & \text{if }  80 \leq score  < 90 \\                 C, 
% & \text{if }  70 \leq score  < 80 \\         D, & \text{otherwise}    \end{array}$$ 

names = {"Adam", "John", "Sally"};
scores = [81, 72, 90];
class = table();
class.Student = names';
class.Score = scores';
disp(class);

% Loop through rows
for i = 1:size(class, 1)
    x = class.Score (i);
    if x >= 90
        class.Grade(i) = 'A';
    elseif x >= 80
        class.Grade(i) = 'B';
    elseif x >= 70
        class.Grade(i) = 'C';
    else
        class.Grade(i) = 'D';
    end
end

disp(class);
% Reading Tables from a CSV or Excel file
%% 
% * Read a file _samples.csv_ into a table
% * Compute the average strength value
% * Add a new column named, _Positive,_ that is boolean True or False based 
% on whether the Strength is greater than the average
% * Save the revised table into a file _samples_2.csv_

samples = readtable ("samples.csv");
avg_strength = mean(samples.Strength);
samples.Postive = samples.Strength > avg_strength;
writetable(samples, "samples_2.csv");
% Datamatrix
% A typical datamatrix file is a CSV file with samples readings as its columns, 
% and genes along its rows. The first row is treated as _Variable Names_. The 
% first column is treated as _RowNames_ if the 'ReadRowNames' option is set true

filename = "data_matrix.csv";
tbl = readtable (filename);

fprintf('matrix size %d %d', size(tbl))

%% Accessing Columns and Rows

disp('first row in the table');
tbl (1,:)

disp('First three rows from column named Gene');
tbl (1:3, 'Gene')
disp('Accesing last three Gene Values for Sample_1 ')
tbl(end-2:end, {'Gene', 'Sample_1'})

% check which of the variables are numeric
numeric = cellfun(@isnumeric, table2cell(tbl(1,:)))

% compute the average representation of Gene 3
% steps -- 
% (1) find row index for Gene_3
% (2) use numeric columns to compute mean

avg = mean(tbl{strcmp(tbl.Gene, 'Gene_3'), numeric});
sprintf("Average for Gene 3 is %5.3f", avg)


%% Reading and Assigning names to rows

frm = readtable (filename, 'ReadRowNames', true);
disp('values of row Gene_4 in Sample_3 and Sample_4');
frm('Gene_4', {'Sample_3', 'Sample_4'})

disp('values of row Gene_3 in column Sample_2');
frm.Sample_2('Gene_3')

% computing values of Gene_3 mean is simpler

avg = mean(frm{"Gene_3", :});
sprintf("Average for Gene 3 is %5.3f", avg)
% Dictionaries
%% 
% * Create a dictionary listing the locations of the vowels in the string: "The 
% quick brown fox jumped over lazy deer"
% * Use the dictionary to list the match locations for the vowel "o"

dict = dictionary();

str = "The quick brown fox jumped over lazy dog";
vowels = ['a', 'e', 'i', 'o', 'u'];

for v = vowels
    indx = regexp(str, v, 'ignorecase');
    dict(v) = {indx};
end

disp("Locations of occurrence of 'o' ");
dict('o')
% File Operations
% Generally, you can read data from a file by specifying the type of data to 
% be expected. _textscan_ function reads in the data into a cell array 

%% Open File 
fid=fopen('data_matrix.csv');

numCols = 6;
numHeaders = 1;
% Define Formats
format_header = repmat('%s ', 1, numCols);
format_data = ['%s ', repmat('%f ', 1, numCols-1)];

%% Read Data
% Read Data using defined formats
header = textscan(fid, format_header, 1);
data = textscan(fid, format_data);
% Close file
fclose(fid);

%% Display Results

disp('Header row');
[header{:}]

disp('Elements from column 3');
data{1, 3}(:)

disp ('Elements of first and last columns');
[first,~, ~, ~, ~, ~, last] = deal(data)
% Review Questions
%% 
% *Question 1*: Plot the $cosine$ function in the range of $-\pi$to $+\pi$by 
% stepping through the $x$ values in increments of 0.05. 

hold off 
x = 0:0.05:2*pi
y = cos(x)
plot(x,y)
%% 
% *Question 2*: A string is an array of characters. Search and list the index 
% locations of character "A" in the string TTATTATTATTA.

str = "TTATTATTATTA";
pat = "A";
s_find = strfind(str,pat)
%% 
% *Question 3*: 
% 
% Condier the following array of strings:
% 
% ["AATAA", "CCTG", "AAA", "AGGCT", "AAAT"]
% 
% (a) Find the indice(s) of elements that are equal to the string "AA" 
% 
% (b) Find the indices of elements that include the pattern "AA"

%(a)

arry = ["AATAA", "CCTG", "AA", "AGGCT", "AAAT"];
%(a)
i = find (strcmpi(arry, "AA"));
disp(i);

%(b)
y = strfind(x, "AA");
z = cellfun(@(a)~isempty(a), y);
indx = find (z);
disp(indx)
%% 
% *Question 4*: Find the overlapping and non-overlapping frequency counts for 
% the pattern "CC" or "CG" in the sequence CCCGCCGGCGCCCC


%% 
% *Question* : In the patient array of structures, add two new patients in Structures
% 
% Ian Brown, Age = 51, Blood Gucose = 105, Heart Rate = 78
% 
% Sam Singh, Age = 36, Blood Gucose = 95, Heart Rate = 72
% 
% Plot the bar graphs. Also compute the mean value for blood glucose for the 
% entire group. 


%% 
% *Question 5:* With reference to the table created by reading the file _data_matrix.csv_ 
% in section Datamatrix
%% 
% * create a new column named _Ratio_1_2_ with values equal to the ratio of 
% gene expressions equal to the value for _Sample_1_ divided by the value for 
% _Sample_2_.
% * create another column named _AvgExpr_ with the value equal to the averge 
% value of gene expression across all samples. 


%% 
% *Quetion 6*: For the cell array example in section Cell Arrays
%% 
% * replace the 3x3 magic square with a 4x4 magic square.
% * add a third colum with a short description for the rows: (1) "A 3x3 identity 
% matrix", (2) "first five elements of the fibonnaci series", (3) a 4x4 magic 
% square
% * add fourth and fifth rows with contents:
%% 
% "zeros", zeros(3), "a 3x3 zero matrix"
% 
% "ones", ones(4, 5), "a 4 by 5 matrix of ones"


% Appendix
% Functions can either be defined as .m files, or appear at the end of a Live 
% Script.
% Functions 
% Computes the frequency of a pattern in a sequence. Pattern and sequence is 
% passed in as parameters. pattern is specified as a regular expression.

function [freq_count, locs] = pattern_count (sequence, pattern)
    locs = regexp(sequence, pattern);
    freq_count = length(locs);
end
%% 
% *Another function*

function str_tri_test = is_triangle(a,b,c)
% istriangle determine if a,b,c form a triangle
    v = [a b c];
    vsort = sort(v);
    
    if vsort(1) + vsort(2) > vsort(3)
    s1 = ['The sides ', num2str(v),' form a triangle.'];
    % Checking the type of triangle formed
    if (a==b) & (b==c) % all sides equal
        s2 =' The triangle is an equilateral triangle.';
    elseif (a==b) | (b==c) | (a==c)
        s2 = ' The triangle is an isosceles triangle.';
    else
        s2 = ' The triangle is a scalene triangle.';
    end    
    str_tri_test = strcat(s1,s2);
    else
    str_tri_test = ['The sides ', num2str(v), ...
				       ' do not form a triangle.'];
    end
end