From 8858c38bca6d798c02eea7fef6fb07ce1be70811 Mon Sep 17 00:00:00 2001 From: fherreazcue Date: Tue, 14 Nov 2023 14:46:38 +0000 Subject: [PATCH] Updated times and added bits that were missing. Also re-extracted code. --- code/01-intro.m | 1 + code/02-arrays.m | 4 +- code/03-loading_data.m | 2 + code/04-plotting.m | 11 ++ code/06-cond.m | 212 ++++++++++++++++++++++++++++++++ code/{06-func.m => 07-func.m} | 0 code/08-cond.m | 206 ------------------------------- code/{07-loops.m => 08-loops.m} | 0 episodes/01-intro.md | 9 ++ episodes/02-arrays.md | 8 +- episodes/03-loading_data.md | 19 ++- episodes/04-plotting.md | 37 +++++- 12 files changed, 293 insertions(+), 216 deletions(-) create mode 100644 code/06-cond.m rename code/{06-func.m => 07-func.m} (100%) delete mode 100644 code/08-cond.m rename code/{07-loops.m => 08-loops.m} (100%) diff --git a/code/01-intro.m b/code/01-intro.m index aa5dcd31..d013d0be 100644 --- a/code/01-intro.m +++ b/code/01-intro.m @@ -24,6 +24,7 @@ size3 = 'L' patient_name = "Jane Doe" alive_on_day_3 = true + class(patient_name) c3 = frac == mass/age diff --git a/code/02-arrays.m b/code/02-arrays.m index 86e872ce..9434ccbf 100644 --- a/code/02-arrays.m +++ b/code/02-arrays.m @@ -56,8 +56,8 @@ % ! Challenge: % ## Slicing character arrays element = 'oxygen'; - disp(['first three characters: ', element(1:3)]) - disp(['last three characters: ', element(4:6)]) + disp("first three characters: " + element(1:3)) + disp("last three characters: " + element(4:6)) % !! Solution: diff --git a/code/03-loading_data.m b/code/03-loading_data.m index eddd3b4b..1d3f24a5 100644 --- a/code/03-loading_data.m +++ b/code/03-loading_data.m @@ -6,6 +6,8 @@ % ## Tip: Good Enough Practices for Scientific Computing + pwd + ls patient_data = readmatrix('data/base/inflammation-01.csv'); size(patient_data) class(patient_data) diff --git a/code/04-plotting.m b/code/04-plotting.m index 0213926e..3716aa6a 100644 --- a/code/04-plotting.m +++ b/code/04-plotting.m @@ -66,6 +66,17 @@ plot(per_day_min) title('Min') +% ## Where is the `nexttile`? + tiledlayout(3,5) + nexttile(3) + + +% ## Resizing tiles + nexttile([3,1]) + nexttile(8,[2,3]) + nexttile(1,[2,2]) + + % ## Clearing a figure % ## Heatmaps diff --git a/code/06-cond.m b/code/06-cond.m new file mode 100644 index 00000000..f7fe5049 --- /dev/null +++ b/code/06-cond.m @@ -0,0 +1,212 @@ + + + + + num = 127; + disp('before conditional...') + + if num > 100 + disp('The number is greater than 100') + end + + disp('...after conditional') + num = 53; + disp('before conditional...') + + if num > 100 + disp('The number is greater than 100') + else + disp('The number is not greater than 100') + end + + disp('...after conditional') + num = 53; + + disp('before conditional...') + if num > 100 + disp('The number is greater than 100') + else + disp('The number is not greater than 100') + if num > 50 + disp('But it is greater than 50...') + end + end + + disp('...after conditional') + %CONDITIONAL_DEMO Demo script to illustrate use of conditionals + + num = 53; + + if num > 0 + disp('num is positive') + elseif num == 0 + disp('num is zero') + else + disp('num is negative') + end + % Demo script to illustrate use of conditionals + num = 53; + + if num > 0 + disp('num is positive') + elseif num == 0 + disp('num is zero') + elseif num > 50 + % This block will never be executed + disp('num is greater than 50') + else + disp('num is negative') + end + if ((1 > 0) && (-1 > 0)) + disp('both parts are true') + else + disp('At least one part is not true') + end + if (1 < 0) || (3 < 4) + disp('At least one part is true') + end + +% ! Challenge: +% ## True and False Statements + if '' + disp('empty string is true') + else + disp('empty string is false') + end + + if 'foo' + disp('non empty string is true') + else + disp('non empty string is false') + end + + if [] + disp('empty array is true') + else + disp('empty array is false') + end + + if [22.5, 1.0] + disp('non empty array is true') + else + disp('non empty array is false') + end + + if [0, 0] + disp('array of zeros is true') + else + disp('array of zeros is false') + end + + if true + disp('true is true') + else + disp('true is false') + end + + +% ! Challenge: +% ## Close Enough +% !! Solution: + %NEAR Display 1 if variable a is within 10% of variable b + % and display 0 otherwise + a = 1.1; + b = 1.2; + + if a/b >= 0.9 && a/b <= 1.1 + disp(1) + else + disp(0) + end + + +% ## Scripts with choices + % PLOT_DAILY_AVERAGE_OPTION Plots daily average, max and min inflammation across patients. If save_plots is set to + % true, the figures are saved to disk. If save_plots is set to false, the figures are displayed on the screen. + + % Load patient data + patient_data = readmatrix('data/base/inflammation-01.csv'); + + save_plots=true; + + if save_plots == true + figure(visible='off') + else + figure + end + + % Define tiled layout and labels + tlo = tiledlayout(1,3); + xlabel(tlo,'Day of trial') + ylabel(tlo,'Inflammation') + + % Plot average inflammation per day + nexttile + plot(mean(patient_data, 1)) + title('Average') + + % Plot max inflammation per day + nexttile + plot(max(patient_data, [], 1)) + title('Max') + + % Plot min inflammation per day + nexttile + plot(min(patient_data, [], 1)) + title('Min') + + if save_plots == true + % Save plot in 'results' folder as png image: + saveas(gcf,'results/daily_average_01.png') + + close() + + end + +% ! Challenge: +% ## Changing behaviour based on patient data +% !! Solution: + % Load patient data + patient_data = readmatrix('data/base/inflammation-01.csv'); + + % Compute global statistics + g_mean = mean(patient_data(:)); + g_max = max(patient_data(:)); + g_min = min(patient_data(:)); + + patient_number = 8; + + % Compute patient statistics + p_mean = mean(patient_data(patient_number,:)); + p_max = max(patient_data(patient_number,:)); + p_min = min(patient_data(patient_number,:)); + + % Compare patient vs global + disp('Patient:') + disp(patient_number) + + printed_something = false; + + if p_mean > g_mean + disp('Patient''s mean inflammation is higher than the global mean inflammation.') + printed_something = true; + end + + if p_max == g_max + disp('Patient''s maximum inflammation is the same as the global maximum.') + printed_something = true; + end + + if p_min == g_min + disp('Patient''s minimum inflammation is the same as the global minimum.') + printed_something = true; + end + + if printed_something == false + disp('Patient''s mean, maximum and minimum inflammation are not of interest.') + end + + + + + diff --git a/code/06-func.m b/code/07-func.m similarity index 100% rename from code/06-func.m rename to code/07-func.m diff --git a/code/08-cond.m b/code/08-cond.m deleted file mode 100644 index ec358ad7..00000000 --- a/code/08-cond.m +++ /dev/null @@ -1,206 +0,0 @@ - - - - - num = 37; - - if num > 100 - disp('greater') - else - disp('not greater') - end - - disp('done') - num = 53; - disp('before conditional...') - - if num > 100 - disp('53 is greater than 100') - end - - disp('...after conditional') - %CONDITIONAL_DEMO Demo script to illustrate use of conditionals - - num = 53; - - if num > 0 - disp('num is positive') - elseif num == 0 - disp('num is zero') - else - disp('num is negative') - end - % Demo script to illustrate use of conditionals - num = 53; - - if num > 0 - disp('num is positive') - elseif num == 0 - disp('num is zero') - elseif num > 50 - % This block will never be executed - disp('num is greater than 50') - else - disp('num is negative') - end - if ((1 > 0) && (-1 > 0)) - disp('both parts are true') - else - disp('one part is not true') - end - if (1 < 0) || (3 < 4) - disp('at least one part is true') - end - -% ! Challenge: -% ## True and False Statements - if '' - disp('empty string is true') - else - disp('empty string is false') - end - - if 'foo' - disp('non empty string is true') - else - disp('non empty string is false') - end - - if [] - disp('empty array is true') - else - disp('empty array is false') - end - - if [22.5, 1.0] - disp('non empty array is true') - else - disp('non empty array is false') - end - - if [0, 0] - disp('array of zeros is true') - else - disp('array of zeros is false') - end - - if true - disp('true is true') - else - disp('true is false') - end - - -% ! Challenge: -% ## Close Enough -% !! Solution: - %NEAR Display 1 if variable a is within 10% of variable b - % and display 0 otherwise - a = 1.1; - b = 1.2; - - if a/b >= 0.9 && a/b <= 1.1 - disp(1) - else - disp(0) - end - - - numbers = [-5, 3, 2, -1, 9, 6]; - total = 0; - - for n = numbers - if n >= 0 - total = total + n; - end - end - - disp(['sum of positive values: ', num2str(total)]) - pos_total = 0; - neg_total = 0; - - for n = numbers - if n >= 0 - pos_total = pos_total + n; - else - neg_total = neg_total + n; - end - end - - disp(['sum of positive values: ', num2str(pos_total)]) - disp(['sum of negative values: ', num2str(neg_total)]) - for number = 1:3 - for letter = 'ab' - disp([num2str(number), letter]) - end - end - -% ! Challenge: -% ## Nesting -% !! Solution: - for letter = 'ab' - for number = 1:3 - disp([num2str(number), letter]) - end - end - - - print(img_name,'-dpng') - close() - figure(visible='off') - figure(visible='on') - % or equivalently: figure() - %PLOT_ALL Save plots of statistics to disk. - % Use variable plot_switch to control interactive plotting - % vs saving images to disk. - % plot_switch = 0: show plots interactively - % plot_switch = 1: save plots to disk - - plot_switch = 0; - - files = dir('data/inflammation-*.csv'); - - % Process each file in turn - for i = 1:length(files) - file_name = files(i).name; - - % Generate strings for image names: - img_name = replace(file_name, '.csv', '.png'); - - % Generate path to data file and image file - file_name = fullfile('data', filename); - img_name = fullfile('results', img_name); - - patient_data = readmatrix(file_name); - - % Create figures - if plot_switch == 1 - figure(visible='off') - else - figure(visible='on') - end - - tlo = tiledlayout(1,3); - xlabel(tlo,'Day of trial') - ylabel(tlo,'Inflammation') - - nexttile - plot(mean(patient_data, 1)) - title('Average') - - nexttile - plot(max(patient_data, [], 1)) - title('Max') - - nexttile - plot(min(patient_data, [], 1)) - title('Min') - - if plot_switch == 1 - print(img_name, '-dpng') - close() - end - - end - - diff --git a/code/07-loops.m b/code/08-loops.m similarity index 100% rename from code/07-loops.m rename to code/08-loops.m diff --git a/episodes/01-intro.md b/episodes/01-intro.md index 9b57ebeb..4010ce71 100644 --- a/episodes/01-intro.md +++ b/episodes/01-intro.md @@ -208,6 +208,15 @@ Notice the single tick for character variables, in contrast with the double quot If you look at the workspace, you'll notice that the icon next to each variable is different, and if you hover over it, it will tell you the type of variable it is. +You can also check the "class" of the variable with the `class` function: +```matlab +>> class(patient_name) +``` +```output +ans = + 'string' +``` + ::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/episodes/02-arrays.md b/episodes/02-arrays.md index 3bd313d4..faaf7567 100644 --- a/episodes/02-arrays.md +++ b/episodes/02-arrays.md @@ -1,7 +1,7 @@ --- title: Arrays -teaching: 50 -exercises: 20 +teaching: 30 +exercises: 30 --- ::::::::::::::::::::::::::::::::::::::: objectives @@ -380,8 +380,8 @@ We can take slices of character arrays as well: ```matlab >> element = 'oxygen'; ->> disp(['first three characters: ', element(1:3)]) ->> disp(['last three characters: ', element(4:6)]) +>> disp("first three characters: " + element(1:3)) +>> disp("last three characters: " + element(4:6)) ``` ```output diff --git a/episodes/03-loading_data.md b/episodes/03-loading_data.md index d5b13dd6..da4035c7 100644 --- a/episodes/03-loading_data.md +++ b/episodes/03-loading_data.md @@ -1,7 +1,7 @@ --- title: Loading data -teaching: 30 -exercises: 10 +teaching: 35 +exercises: 15 --- ::::::::::::::::::::::::::::::::::::::: objectives @@ -53,10 +53,18 @@ Use the **Current Folder** window in the MATLAB GUI to browse to your project fo (the one now containing the 'data', 'results' and 'src' directories). To verify the current directory in matlab we can run `pwd` (print working directory). +```matlab +>> pwd +``` +```output +.../Desktop/matlab-novice-inflammation +``` A second check we can do is to run the `ls` (list) command in the Command Window to list the contents of the working directory --- we should get the following output: - +```matlab +>> ls +``` ```output data results src ``` @@ -76,6 +84,11 @@ The first few rows of our first file, `data/base/inflammation-01.csv`, look like 0,0.081,0.216,0.277,0.273,0.356,0.38,0.349,0.315,0.23,0.235,0.198,0.106,0.198,0.084,0.171,0.126,0.14,0.086,0.01,0.06,0.081,0.022,0.035,0.01,0.086,-0,0.102,0.032,0.07,0.017,0.136,0.022,-0,0.031,0.054,-0,-0,0.05,0.001 ``` +There is a very tempting button that says "Import Data" in the toolbar. +If you click on it, you can find the file, and it will take you through a GUI wizard to upload the data. +However, this is much more complicated than what we need, and it is not very helpful for loading multiple files (as we will in later episodes). +Instead, lets try to do it on the command window. + We can search the documentation to try to learn how to read our matrix of data. Type `read matrix` into the documentation toolbar. MATLAB suggests using `readmatrix`. diff --git a/episodes/04-plotting.md b/episodes/04-plotting.md index acea3319..0c02400f 100644 --- a/episodes/04-plotting.md +++ b/episodes/04-plotting.md @@ -1,6 +1,6 @@ --- title: Plotting data -teaching: 25 +teaching: 30 exercises: 10 --- @@ -209,6 +209,39 @@ and pass it as a first argument to `title`, `xlabel` or `ylabel`, for example: ::::::::::::::::::::::::::::::::::::::::: callout +## Where is the `nexttile`? + +You can specify which *tile* you want to plot next by specifying the number as an argument to `nexttile` like so: +```matlab +>> tiledlayout(3,5) +>> nexttile(3) +``` +Note that, as opposed to numerical arrays, the indexing goes along the row first, and then jumps to the next column. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +## Resizing tiles + +You can also choose a different size for a plot by occupying many *tiles* in one go. +You do that by specifying the number of rows and columns you want to use in an array (`[rows,columns]`), like this: +```matlab +>> nexttile([3,1]) +``` +And you can specify the starting tile at the same time, like this: +```matlab +>> nexttile(8,[2,3]) +``` +Note that using a starting tile that overlaps another plot will erase that axes. For example, try: +```matlab +>> nexttile(1,[2,2]) +``` + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + ## Clearing a figure If you now try to plot something like the mean, as we had done before, @@ -271,5 +304,7 @@ In our case, which one you use is a matter of taste. - Use `hold on` and `hold off` to plot multiple lines at the same time. - Use `legend` and add `,DisplayName="legend name here"` inside the plot function to add a legend. - Use `tiledlayout(m,n)` to create a grid of `m` x `n` plots, and use `nexttile` to change the position of the next plot. +- Choose the location and size of the tile by passing arguments to `nextile` as `nexttile(position,[m,n])`. +- Use `heatmap` or `imagesc` to plot a whole matrix with values coded as color hues. ::::::::::::::::::::::::::::::::::::::::::::::::::