matlab_-_datatypes

This shows you the differences between two versions of the page.

Both sides previous revision Previous revision | |||

matlab_-_datatypes [2012/10/06 06:08] jochen re-written |
matlab_-_datatypes [2012/10/06 17:58] (current) jochen Indexing |
||
---|---|---|---|

Line 195: | Line 195: | ||

mainfig.ShowPage(2);</code> | mainfig.ShowPage(2);</code> | ||

+ | ===== Indexing ===== | ||

+ | It is both a blessing and a curse that Matlab uses the same language elements for passing arguments into a function and indexing into a non-scalar array:<code matlab>% creating a 3x3 variable with random numbers | ||

+ | randvals = randn(3, 3); | ||

+ | |||

+ | % accessing the value at the 3rd row and 2nd column | ||

+ | randvals(3, 2) | ||

+ | |||

+ | % computing the sum along the 2nd dimension | ||

+ | sum(randvals, 2)</code> | ||

+ | |||

+ | In both cases, common parentheses, **''(''** and **'')''**, are used to | ||

+ | * sub-select values (array elements) from a non-scalar variable | ||

+ | * pass arguments (in this case the variable ''randvals'' and the scalar value ''2'') into a function | ||

+ | |||

+ | One of the reasons is that even the syntax **''randvals(3, 2)''** can be seen as a function call (and, for user defined objects, actually leads to a function call!). | ||

+ | |||

+ | The blessing is that, for user defined objects, this can be used to create very elegant code. The curse, on the other hand, is that it cannot be determined if an expression is an indexing operation of a function call, in cases such as<code matlab>var_or_function(x, y);</code> | ||

+ | |||

+ | ==== Subscript indexing ==== | ||

+ | Given that, in principle, all of Matlab's variables support non-scalar (single value/element) content, it is necessary to allow to access individual elements. In the example above, this is exactly what happens with **''randvals(3, 2)''**, which selects the value in the 3rd row and 2nd column of the array. | ||

+ | |||

+ | But subscript indexing not only allows to select a single element, but also ranges of elements. For this purpose, each indexing expression can be a list of indices. When a variable is accessed to "read" from it, each of these lists must contain only valid entries (integer numbers, with a minimum of 1 and a maximum according to the size of the array in that dimension). Other than that, there are no restrictions (for reading from an array). When writing to an array (subscript assignment), the list must be unique, but values can be greater than the existing size, in which case the variable is expanded accordingly: | ||

+ | |||

+ | <code matlab>% creating a 5x4, i.e. 5 rows and 4 columns, variable with random values | ||

+ | fivebyfour = randn(5, 4); | ||

+ | |||

+ | % reading the value at row 3, column 1 | ||

+ | fivebyfour(3, 1) | ||

+ | |||

+ | % reading the entire 2nd row | ||

+ | secondrow = fivebyfour(2, :) | ||

+ | |||

+ | % reading the 4th column | ||

+ | fourthcol = fivebyfour(:, 4) | ||

+ | |||

+ | % reading the 2nd to 4th row, 1st to 3rd column | ||

+ | smaller3x3 = fivebyfour(2:4, 1:3) | ||

+ | |||

+ | % reading all uneven rows and columns | ||

+ | unevens = fivebyfour(1:2:end, 1:2:end) | ||

+ | |||

+ | % reading (in this order) 4th, 1st, and 3rd rows (complete) | ||

+ | r413 = fivebyfour([4, 1, 3], :) | ||

+ | |||

+ | % repeatedly reading the 2nd column | ||

+ | col2times3 = fivebyfour(:, [2, 2, 2])</code> | ||

+ | |||

+ | All but the last of these expressions are also valid for assignment, in which case the value or array being assigned must either be a scalar (which is then stored in all of the written-to elements) or match in size (i.e. to write into a 3x3 sub-part, only a 1x1 or 3x3 right-hand-side value/array can be used). | ||

+ | |||

+ | In addition to these expressions, write access also allows to use indices exceeding the size: | ||

+ | |||

+ | <code matlab>% increase the size to 6-by-6 | ||

+ | fivebyfour(4:6, 4:6) = 1;</code> | ||

+ | |||

+ | Importantly, this performs two steps: | ||

+ | * first, the array is expanded, with all new elements being assigned the "neutral" element: | ||

+ | * for numeric variables this is 0 | ||

+ | * for logical variables this is **''false''** | ||

+ | * for char variables this is also 0 (which is NOT the blank character)! so this syntax should not be used to extend a string! | ||

+ | * for cell arrays this is an empty double array (empty cell content) | ||

+ | * for struct arrays all fields are empty double arrays | ||

+ | * next, the portion that is specified with the indexing expression is assigned the provided value(s) | ||

+ | |||

+ | This means that in the above example, the first three values of the 5th and 6th columns will be 0! | ||

+ | |||

+ | And finally, this type of indexing also allows to **shrink** an array by a special syntax:<code matlab>% remove 2nd row | ||

+ | fivebyfour(2, :) = []; | ||

+ | |||

+ | % remove 3rd and 4th column | ||

+ | fivebyfour(:, 3:4) = [];</code> | ||

+ | |||

+ | Please note: for higher dimensional variables (3D/4D), all but one indexing expression **must** be **'':''** (the colon character), because the region to be eliminated must be "removable" without interfering with array storage rules. | ||

+ | |||

+ | Overall, the idea behind using subscripts is the most "complete" form of indexing: using as many expressions (arguments) as dimensions. If for instance a variable stores numeric values in 3 dimensions (such as a anatomical 3D image of a subject's head) in a, say, 256-by-256-by-256 array, you can then easily access a slice in any of the three dimensions: | ||

+ | |||

+ | <code matlab>% assuming that vol3d is a 3D array, getting three slices in the middle | ||

+ | xyslice = vol3d(:, :, 128); | ||

+ | xzslice = vol3d(:, 128, :); | ||

+ | yzslice = vol3d(128, :, :);</code> | ||

+ | |||

+ | ==== Single expression indexing ==== | ||

+ | Matlab's internal storage works like this: in a multi-dimensional array, values are stored in order of column indices, then row indices, then 3rd, then 4th dimension, and so forth. That means that in a 3x3 variable, the order of values (in memory) is as follows: | ||

+ | |||

+ | <code matlab>% order of values in a 3x3 variable | ||

+ | ttvar(1, 1) | ||

+ | ttvar(2, 1) | ||

+ | ttvar(3, 1) | ||

+ | ttvar(1, 2) | ||

+ | ttvar(2, 2) | ||

+ | ttvar(3, 2) | ||

+ | ttvar(1, 3) | ||

+ | ttvar(2, 3) | ||

+ | ttvar(3, 3)</code> | ||

+ | |||

+ | The total number of values is simply the product of all dimension lengths (size). There are contexts in which, for instance, an operation has to be performed to each individual element of an array, regardless of position. Matlab thus allows to access all elements with a single index expression: | ||

+ | |||

+ | <code matlab>% accessing element ttvar(2, 2) via single index | ||

+ | ttvar(5)</code> | ||

+ | |||

+ | Please note that this syntax can be extremely misleading, particularly for people unfamiliar with Matlab index expressions! There is, however, one extremely useful application for this, in which **all** values of an array are considered as a single column: | ||

+ | |||

+ | <code matlab>% computing the total average over a 3D volume | ||

+ | avgslice = mean(vol3d, 3); | ||

+ | avgcolumn = mean(avgslice, 2); | ||

+ | totalavg = mean(avgcolumn); | ||

+ | |||

+ | % alternatively, by "columnizing" the array, compute in one step | ||

+ | totalavg = mean(vol3d(:));</code> | ||

+ | |||

+ | Please note that for multi-dimensional arrays, this syntax leads to an error if the index exceeds the total number of elements, i.e. an array cannot be resized with a single index expression! | ||

+ | |||

+ | ==== Variables as indices ==== | ||

+ | Matlab also allows to use (numeric) variables (and return values of functions) to be used in index expressions:<code matlab>% create a 4x4 array with random numbers | ||

+ | four_by_four = randn(4, 4); | ||

+ | |||

+ | % select random row | ||

+ | rrowindex = ceil(4 * rand(1, 1)); | ||

+ | rrowdata = four_by_four(rrowindex, :) | ||

+ | |||

+ | % select random column without variable | ||

+ | rcoldata = four_by_four(:, ceil(4 * rand(1, 1))) | ||

+ | |||

+ | % and select a random value from an array without "knowing" its size | ||

+ | randomarrayvalue = four_by_four(ceil(numel(four_by_four) * rand(1, 1)))</code> | ||

+ | |||

+ | In this context, the **''size''** and **''numel''** functions of Matlab are important! **''size(variable)''** returns a 1-by-number-of-dimensions list of array sizes of the passed in variable (or other argument), and **''numel''** returns the total number of elements. | ||

+ | |||

+ | This can be used, for instance, when an operation has to be applied to a data, say, slice by slice:<code matlab>% inquire about the size/dimensions of a volume | ||

+ | volsize = size(vol3d); | ||

+ | |||

+ | % "loop" (iterate) over all slices (in 3rd dimension) | ||

+ | for slice = 1:volsize(3) | ||

+ | |||

+ | % compute critical value | ||

+ | critval = critval_function(vol3d(:, :, slice)); | ||

+ | | ||

+ | % break (leave loop) if threshold is hit | ||

+ | if critval >= 10 | ||

+ | break; | ||

+ | end | ||

+ | end</code> | ||

+ | |||

+ | ==== Logical indexing ==== | ||

+ | On top of using numbers (or numeric expressions, variables, etc.) in indexing expressions, Matlab also supports selecting indices using a logical expression. The most typical application is by applying a comparison operator to establish a threshold: | ||

+ | |||

+ | <code matlab>% generate an array with 10 random numbers | ||

+ | r = randn(10, 1); | ||

+ | |||

+ | % sum all numbers that are greater (or equal) 0 | ||

+ | pos_sum = sum(r(r >= 0))</code> | ||

+ | |||

+ | The indexing expression **''(r >= 0)''** performs an element-by-element comparison with 0. This comparison creates (temporarily) an array of logical (true/false) values with the same size as ''r'', which is then used to "select" all values from r for which the comparison is true. | ||

+ | |||

+ | If the comparison operator is used on and then returns a multi-dimensional logical array, the indexing operation automatically converts the result into a column vector (given that arbitrary elements are selected, not allowing the result to be regularly shaped). | ||

+ | |||

+ | Logical indexing can also be used with the subscript notation (more than one expression), in which case each logical expression ought to have as many elements as the size of the variable in that dimension:<code matlab>% create a 10-by-10 array with random numbers | ||

+ | r10x10 = randn(10, 10); | ||

+ | |||

+ | % sub-select some rows and some columns | ||

+ | randompart = r10x10(randn(1, 10) > 0, randn(1, 10) > 0)</code> |

matlab_-_datatypes.txt ยท Last modified: 2012/10/06 17:58 by jochen