matlab_prog
matlab_prog
matlab_prog
Programming Fundamentals
R2024b
How to Contact MathWorks
Phone: 508-647-7000
Language
Syntax Basics
1
Continue Long Statements on Multiple Lines . . . . . . . . . . . . . . . . . . . 1-2
Program Components
2
MATLAB Operators and Special Characters . . . . . . . . . . . . . . . . . . . . 2-2
Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
Special Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3
String and Character Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4
v
Compatible Array Sizes for Basic Operations . . . . . . . . . . . . . . . . . . 2-12
Inputs with Compatible Sizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-12
Inputs with Incompatible Sizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14
vi Contents
Fast Fourier Transform Example . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-72
Troubleshooting Operations with Comma-Separated Lists . . . . . . . . 2-72
Numeric Classes
4
Integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Integer Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Creating Integer Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Arithmetic Operations on Integer Classes . . . . . . . . . . . . . . . . . . . . . 4-4
Largest and Smallest Values for Integer Classes . . . . . . . . . . . . . . . . 4-4
Loss of Precision Due to Conversion . . . . . . . . . . . . . . . . . . . . . . . . . 4-5
vii
Integer Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-20
viii Contents
Why Do Strings in Cell Arrays Return an Error? . . . . . . . . . . . . . . . 6-59
Why Does length() of String Return 1? . . . . . . . . . . . . . . . . . . . . . . 6-59
Why Does isempty("") Return 0? . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-60
Why Does Appending Strings Using Square Brackets Return Multiple
Strings? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-61
ix
Plot Dates and Times . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-44
Categorical Arrays
8
Create Categorical Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
x Contents
Tables
9
Create Tables and Assign Data to Them . . . . . . . . . . . . . . . . . . . . . . . 9-2
Timetables
10
Create Timetables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-2
xi
Combine Timetables and Synchronize Their Data . . . . . . . . . . . . . 10-13
Structures
11
Structure Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
Create Scalar Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
Access Values in Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
Index into Nonscalar Structure Array . . . . . . . . . . . . . . . . . . . . . . . 11-4
Cell Arrays
12
Create Cell Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-2
xii Contents
Add or Delete Cells in Cell Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-9
Function Handles
13
Create Function Handle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-2
What Is a Function Handle? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-2
Creating Function Handles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-2
Anonymous Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-3
Arrays of Function Handles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-4
Saving and Loading Function Handles . . . . . . . . . . . . . . . . . . . . . . 13-4
Dictionaries
14
Map Data with Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-2
xiii
Combining Integer and Double Types . . . . . . . . . . . . . . . . . . . . . . . 15-7
Combining Character and Double Types . . . . . . . . . . . . . . . . . . . . . 15-7
Combining Logical and Double Types . . . . . . . . . . . . . . . . . . . . . . . 15-7
Using Objects
16
Copying Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-2
Two Copy Behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-2
Handle Object Copy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-2
Value Object Copy Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-2
Handle Object Copy Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-3
Testing for Handle or Value Class . . . . . . . . . . . . . . . . . . . . . . . . . . 16-5
Scripts
18
Create Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-2
xiv Contents
Access Help for Local Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 18-14
xv
Custom Live Editor Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-53
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-102
Function Basics
20
Create Functions in Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-2
Syntax for Function Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-2
Contents of Functions and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-3
End Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-4
xvi Contents
Share Data Between Workspaces . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-10
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-10
Best Practice: Passing Arguments . . . . . . . . . . . . . . . . . . . . . . . . . 20-10
Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-10
Persistent Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-11
Global Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-12
Evaluating in Another Workspace . . . . . . . . . . . . . . . . . . . . . . . . . 20-12
xvii
Error handling when import not found . . . . . . . . . . . . . . . . . . . . . 20-43
Nested functions inherit import statements from parent functions
................................................ 20-44
Change in precedence of compound name resolution . . . . . . . . . . 20-44
Anonymous functions can include resolved and unresolved identifiers
................................................ 20-45
Function Arguments
21
Find Number of Function Arguments . . . . . . . . . . . . . . . . . . . . . . . . 21-2
xviii Contents
Error Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-12
Breakpoints in Anonymous Functions . . . . . . . . . . . . . . . . . . . . . . 22-13
Invalid Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-14
Disable Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-14
Clear Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-15
xix
Check Code for Errors and Warnings Using the Code Analyzer . . . 24-5
Enable Continuous Code Checking . . . . . . . . . . . . . . . . . . . . . . . . . 24-5
View Code Analyzer Status for File . . . . . . . . . . . . . . . . . . . . . . . . . 24-6
View Code Analyzer Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-7
Fix Problems in Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-8
Analyze Files Using the Code Analyzer App . . . . . . . . . . . . . . . . . 24-10
Identify and Store Issues in Files With codeIssues Object . . . . . . . 24-11
Analyze Files Using the Code Issues Panel in MATLAB Online . . . . 24-12
Adjust Code Analyzer Message Indicators and Messages . . . . . . . 24-13
Enable custom checks and configure existing checks . . . . . . . . . . 24-15
Understand Code Containing Suppressed Messages . . . . . . . . . . . 24-15
Understand the Limitations of Code Analysis . . . . . . . . . . . . . . . . 24-16
Enable MATLAB Compiler Deployment Messages . . . . . . . . . . . . . 24-18
Programming Utilities
25
Identify Program Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2
Simple Display of Program File Dependencies . . . . . . . . . . . . . . . . 25-2
xx Contents
Detailed Display of Program File Dependencies . . . . . . . . . . . . . . . 25-2
Dependencies Within a Folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2
xxi
Validate Repeating Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-13
Avoid Using varargin for Repeating Arguments . . . . . . . . . . . . . . . 26-14
Software Development
Error Handling
27
Exception Handling in a MATLAB Application . . . . . . . . . . . . . . . . . 27-2
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27-2
Getting an Exception at the Command Line . . . . . . . . . . . . . . . . . . 27-2
Getting an Exception in Your Program Code . . . . . . . . . . . . . . . . . . 27-3
Generating a New Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27-3
xxii Contents
Retrieving Information About the Cleanup Routine . . . . . . . . . . . . 27-11
Using onCleanup Versus try/catch . . . . . . . . . . . . . . . . . . . . . . . . 27-12
onCleanup in Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27-12
Program Scheduling
28
Schedule Command Execution Using Timer . . . . . . . . . . . . . . . . . . . 28-2
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28-2
Example: Displaying a Message . . . . . . . . . . . . . . . . . . . . . . . . . . . 28-2
Performance
29
Measure the Performance of Your Code . . . . . . . . . . . . . . . . . . . . . . 29-2
Overview of Performance Timing Functions . . . . . . . . . . . . . . . . . . 29-2
Time Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-2
Time Portions of Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-2
The cputime Function vs. tic/toc and timeit . . . . . . . . . . . . . . . . . . . 29-2
Tips for Measuring Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-3
xxiii
Profile Your Code to Improve Performance . . . . . . . . . . . . . . . . . . . . 29-4
What Is Profiling? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-4
Profile Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-4
Profile Multiple Statements in Command Window . . . . . . . . . . . . . 29-10
Profile an App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-11
Preallocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-14
Preallocating a Nondouble Matrix . . . . . . . . . . . . . . . . . . . . . . . . 29-14
Vectorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-16
Using Vectorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-16
Array Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-17
Logical Array Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-18
Matrix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29-19
Ordering, Setting, and Counting Operations . . . . . . . . . . . . . . . . . 29-20
Functions Commonly Used in Vectorization . . . . . . . . . . . . . . . . . 29-21
Background Processing
30
Asynchronous Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30-2
Asynchronous Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30-2
Background Workers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30-4
xxiv Contents
Memory Usage
31
Strategies for Efficient Use of Memory . . . . . . . . . . . . . . . . . . . . . . . 31-2
Use Appropriate Data Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31-2
Avoid Temporary Copies of Data . . . . . . . . . . . . . . . . . . . . . . . . . . . 31-3
Reclaim Used Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31-4
xxv
Projects
33
Create Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-2
What Are Projects? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-2
Create Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-2
Open Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-2
Set Up Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-3
Add Files to Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-5
Other Ways to Create Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33-6
xxvi Contents
Extract Folder to Create a Referenced Project . . . . . . . . . . . . . . . 33-33
Manage Changes in Referenced Project Using Checkpoints . . . . . 33-33
Packages
34
Organize and Distribute Code Using MATLAB Package Manager
..................................................... 34-2
What Is a Package? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-2
Package Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-2
Share Packages in Repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-3
xxvii
Create and Manage Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-8
Create Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-8
Modify Installed Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-8
Edit Package Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-8
Manage Package Code and Subfolders . . . . . . . . . . . . . . . . . . . . . . 34-9
Manage Package Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . 34-9
xxviii Contents
Switch Branch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35-22
Compare Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35-22
Merge Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35-23
Revert to Head . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35-23
Delete Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35-23
xxix
Unit Testing
36
Write Test Using Live Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-3
xxx Contents
Write Setup and Teardown Code Using Classes . . . . . . . . . . . . . . . 36-56
Test Fixtures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-56
Test Case with Method-Level Setup Code . . . . . . . . . . . . . . . . . . . 36-56
Test Case with Class-Level Setup Code . . . . . . . . . . . . . . . . . . . . . 36-57
xxxi
Run Tests in Parallel with Custom Plugin . . . . . . . . . . . . . . . . . . . 36-123
Create Plugin Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-123
Extend Running of Test Session . . . . . . . . . . . . . . . . . . . . . . . . . 36-123
Extend Creation of Shared Test Fixtures and Test Cases . . . . . . . 36-124
Extend Running of Test Suite Portion . . . . . . . . . . . . . . . . . . . . . 36-124
Extend Reporting of Finalized Test Suite Portion . . . . . . . . . . . . 36-125
Define Helper Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-126
Plugin Class Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-126
Create Test Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-128
Add Plugin to Test Runner and Run Tests . . . . . . . . . . . . . . . . . . 36-128
Write Tests That Use App Testing and Mocking Frameworks . . . 36-173
Create App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-173
Test App with Manual Intervention . . . . . . . . . . . . . . . . . . . . . . . 36-174
Create Fully Automated Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . 36-175
xxxii Contents
Measure Fast Executing Test Code . . . . . . . . . . . . . . . . . . . . . . . . 36-191
xxxiii
Build Automation
37
Overview of MATLAB Build Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37-2
Create Plan with Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37-2
Run Tasks in Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37-3
xxxiv Contents
Define Basic System Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-11
Create System Object Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-11
Define Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-11
xxxv
Summary of Call Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-46
Setup Call Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-46
Running the Object or Step Call Sequence . . . . . . . . . . . . . . . . . . . . . . 38-46
Reset Method Call Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-47
Release Method Call Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38-47
Create New System Objects for File Input and Output . . . . . . . . . . . . . 38-71
xxxvi Contents
Language
37
1
Syntax Basics
The start and end quotation marks for a character vector must appear on the same line. For example,
this code returns an error, because each line contains only one quotation mark:
x = [1.23...
4.56];
is the same as
x = [1.23 4.56];
1-2
Name=Value in Function Calls
Use the name=value syntax to help identify name-value arguments for functions and to clearly
distinguish names from values in lists of name-value arguments.
Most functions and methods support both syntaxes, but there are some limitations on where and how
the name=value syntax can be used:
Mixing name,value and name=value syntaxes: The recommended practice is to use only one
syntax in any given function call. However, if you do mix name=value and name,value syntaxes
in a single call, all name=value arguments must appear after the name,value arguments. For
example, plot(x,y,"Color","red",LineWidth=2) is a valid combination, but
plot(x,y,Color="red","LineWidth",2) errors.
• Using positional arguments after name-value arguments: Some functions have positional
arguments that appear after name-value arguments. For example, this call to the verifyEqual
method uses the RelTol name-value argument, followed by a string input:
verifyEqual(testCase,1.5,2,"RelTol",0.1,...
"Difference exceeds relative tolerance.")
Using the name=value syntax (RelTol=0.1) causes the statement to error. In cases where a
positional argument follows name-value arguments, use the name,value syntax.
• Names that are invalid variable names: Name-value arguments with names that are invalid
MATLAB variable names cannot be used with the name=value syntax. See “Variable Names” on
page 1-5 for more info. For example, a name-value argument like "allow-empty",true errors
if passed as allow-empty=true. Use the name,value syntax in these cases.
Function authors do not need to code differently to support both the name,value and name=value
syntaxes. For information on using argument validation with name-value arguments, see “Validate
Name-Value Arguments” on page 26-16.
1-3
1 Syntax Basics
This example shows how to ignore specific outputs from a function using the tilde (~) operator.
helpFile = which('help');
[helpPath,name,ext] = fileparts(helpFile);
The current workspace now contains three variables from fileparts: helpPath, name, and ext. In
this case, the variables are small. However, some functions return results that use much more
memory. If you do not need those variables, they waste space on your system.
If you do not use the tilde operator, you can request only the first N outputs of a function (where N is
less than or equal to the number of possible outputs) and ignore any remaining outputs. For example,
request only the first output, ignoring the second and third.
helpPath = fileparts(helpFile);
If you request more than one output, enclose the variable names in square brackets, []. The
following code ignores the output argument ext.
[helpPath,name] = fileparts(helpFile);
To ignore function outputs in any position in the argument list, use the tilde operator. For example,
ignore the first output using a tilde.
[~,name,ext] = fileparts(helpFile);
You can ignore any number of function outputs using the tilde operator. Separate consecutive tildes
with a comma. For example, this code ignores the first two output arguments.
[~,~,ext] = fileparts(helpFile);
See Also
More About
• “Ignore Inputs in Function Definitions” on page 21-10
1-4
Variable Names
Variable Names
In this section...
“Valid Names” on page 1-5
“Conflicts with Function Names” on page 1-5
Valid Names
A valid variable name starts with a letter, followed by letters, digits, or underscores. MATLAB is case
sensitive, so A and a are not the same variable. The maximum length of a variable name is the value
that the namelengthmax command returns.
You cannot define variables with the same names as MATLAB keywords, such as if or end. For a
complete list, run the iskeyword command.
Avoid creating variables with the same name as a function (such as i, j, mode, char, size, and
path). In general, variable names take precedence over function names. If you create a variable that
uses the name of a function, you sometimes get unexpected results.
Check whether a proposed name is already in use with the exist or which function. exist returns
0 if there are no existing variables, functions, or other artifacts with the proposed name. For example:
exist checkname
ans =
0
If you inadvertently create a variable with a name conflict, remove the variable from memory with the
clear function.
Another potential source of name conflicts occurs when you define a function that calls load or eval
(or similar functions) to add variables to the workspace. In some cases, load or eval add variables
that have the same names as functions. Unless these variables are in the function workspace before
the call to load or eval, the MATLAB parser interprets the variable names as function names. For
more information, see:
1-5
1 Syntax Basics
See Also
clear | exist | iskeyword | namelengthmax | which | isvarname
1-6
Case and Space Sensitivity
In MATLAB code, use an exact match with regard to case for variables, files, and functions. For
example, if you have a variable, a, you cannot refer to that variable as A. It is a best practice to use
lowercase only when naming functions. This is especially useful when you use both Microsoft®
Windows® and UNIX®1 platforms because their file systems behave differently with regard to case.
When you use the help function, the help displays some function names in all uppercase, for
example, PLOT, solely to distinguish the function name from the rest of the text. Some functions for
interfacing to Oracle® Java® software do use mixed case and the command-line help and the
documentation accurately reflect that.
Spaces
Blank spaces around operators such as -, :, and ( ), are optional, but they can improve readability.
For example, MATLAB interprets the following statements the same way.
y = sin (3 * pi) / 2
y=sin(3*pi)/2
However, blank spaces act as delimiters in horizontal concatenation. When defining row vectors, you
can use spaces and commas interchangeably to separate elements:
A = [1, 0 2, 3 3]
A =
1 0 2 3 3
Because of this flexibility, check to ensure that MATLAB stores the correct values. For example, the
statement [1 sin (pi) 3] produces a much different result than [1 sin(pi) 3] does.
[1 sin (pi) 3]
[1 sin(pi) 3]
ans =
1 UNIX is a registered trademark of The Open Group in the United States and other countries.
1-7
1 Syntax Basics
MATLAB has two ways of calling functions, called function syntax and command syntax. This page
discusses the differences between these syntax formats and how to avoid common mistakes
associated with command syntax.
For introductory information on calling functions, see “Calling Functions”. For information related to
defining functions, see “Create Functions in Files” on page 20-2.
In function syntax, inputs can be data, variables, and even MATLAB expressions. If an input is data,
such as the numeric value 2 or the string array ["a" "b" "c"], MATLAB passes it to the function
as-is. If an input is a variable MATLAB will pass the value assigned to it. If an input is an expression,
like 2+2 or sin(2*pi), MATLAB evaluates it first, and passes the result to the function. If the
functions has outputs, you can assign them to variables as shown in the example syntax above.
Command syntax is simpler but more limited. To use it, separate inputs with spaces rather than
commas, and do not enclose them in parentheses.
With command syntax, MATLAB passes all inputs as character vectors (that is, as if they were
enclosed in single quotation marks) and does not assign outputs to user defined variables. If the
function returns an output, it is assigned to the ans variable. To pass a data type other than a
character vector, use the function syntax. To pass a value that contains a space, you have two options.
One is to use function syntax. The other is to put single quotes around the value. Otherwise, MATLAB
treats the space as splitting your value into multiple inputs.
If a value is assigned to a variable, you must use function syntax to pass the value to the function.
Command syntax always passes inputs as character vectors and cannot pass variable values. For
example, create a variable and call the disp function with function syntax to pass the value of the
variable:
A = 123;
disp(A)
123
You cannot use command syntax to pass the value of A, because this call
1-8
Choose Command Syntax or Function Syntax
disp A
is equivalent to
disp('A')
and returns
filename = 'accounts.txt';
A = int8(1:8);
B = A;
or
Some functions expect character vectors for variable names, such as save, load, clear, and whos.
For example,
requests information about variable X in the example file durer.mat. This command is equivalent to
whos('-file','durer.mat','X')
1-9
1 Syntax Basics
ls ./d
This could be a call to the ls function with './d' as its argument. It also could represent element-
wise division on the array ls, using the variable d as the divisor.
If you issue this statement at the command line, MATLAB uses syntactic rules, the current workspace,
and path to determine whether ls and d are functions or variables. However, some components, such
as the Code Analyzer and the Editor/Debugger, operate without reference to the path or workspace.
When you are using those components, MATLAB uses syntactic rules to determine whether an
expression is a function call using command syntax.
In general, when MATLAB recognizes an identifier (which might name a function or a variable), it
analyzes the characters that follow the identifier to determine the type of expression, as follows:
ls =d
• An open parenthesis after an identifier implies a function call. For example:
ls('./d')
• Space after an identifier, but not after a potential operator, implies a function call using command
syntax. For example:
ls ./d
• Spaces on both sides of a potential operator, or no spaces on either side of the operator, imply an
operation on variables. For example, these statements are equivalent:
ls ./ d
ls./d
Therefore, MATLAB treats the potentially ambiguous statement ls ./d as a call to the ls function
using command syntax.
The best practices is to avoid defining variable names that conflict with common functions to prevent
ambiguity and have consistent whitespace around operators or to call functions with explicit
parentheses..
See Also
“Calling Functions” | “Create Functions in Files” on page 20-2
1-10
Resolve Error: Undefined Function or Variable
Issue
You may encounter the following error message, or something similar, while working with functions
or variables in MATLAB:
These errors usually indicate that MATLAB cannot find a particular variable or MATLAB program file
in the current directory or on the search path.
Possible Solutions
Verify Spelling of Function or Variable Name
One of the most common causes is misspelling the function or variable name. Especially with longer
names or names containing similar characters (such as the letter l and numeral one), it is easy to
make mistakes and hard to detect them.
Often, when you misspell a MATLAB function, a suggested function name appears in the Command
Window. For example, this command fails because it includes an uppercase letter in the function
name:
accumArray
When this happens, press Enter to execute the suggested command or Esc to dismiss it.
Object methods are typically called using function syntax: for instance method(object,inputs).
Alternatively, they can be called using dot notation: for instance object.method(inputs). One
common error is to mix these syntaxes. For instance, you might call the method using function syntax,
but to provide inputs following dot notation syntax and leave out the object as an input: for instance,
method(inputs). To avoid this, when calling an object method, make sure you specify the object
first, either through the first input of function syntax or through the first identifier of dot notation.
When you write a function, you establish its name when you write its function definition line. This
name should always match the name of the file you save it to. For example, if you create a function
named curveplot,
then you should name the file containing that function curveplot.m. If you create a pcode file for
the function, then name that file curveplot.p. In the case of conflicting function and file names, the
file name overrides the name given to the function. In this example, if you save the curveplot
1-11
1 Syntax Basics
function to a file named curveplotfunction.m, then attempts to invoke the function using the
function name will fail:
curveplot
Undefined function or variable 'curveplot'.
If you encounter this problem, change either the function name or file name so that they are the
same.
To Locate the file that defines this function, use the MATLAB Find Files utility as follows:
1
On the Home tab, in the File section, click Find Files.
2 Under Find files named, enter *.m
3 Under Find files containing text, enter the function name.
4 Click the Find button
If you are unable to use a built-in function from MATLAB or its toolboxes, make sure that the function
is installed and is the correct version.
If you do not know which toolbox contains the function you need, search for the function
documentation at https://www.mathworks.com/help. The toolbox name appears at the top of the
function reference page. Alternatively, for steps to identify toolboxes that a function depends on, see
“Identify Program Dependencies” on page 25-2.
Once you know which toolbox the function belongs to, use the license function to see which
toolboxes are installed on the system from which you run MATLAB. The license function displays a
list of all currently installed MathWorks® products. If you can locate the toolbox you need in the
output displayed by license, then the toolbox is installed. If you cannot, you need to install it in
order to use it. For help with installing MathWorks products, see “Install License Manager on License
Server”.
1-12
Resolve Error: Undefined Function or Variable
Tip If you have a custom file path, this step will delete it.
The MATLAB search path is a subset of all the folders in the file system. MATLAB uses the search
path to locate files used with MathWorks products efficiently. For more information, see “What Is the
MATLAB Search Path?”.
If the function you are attempting to use is part of a toolbox, then verify that the toolbox is available
using ver.
Because MATLAB stores the toolbox information in a cache file, you need to first update this cache
and then reset the path.
1
On the Home tab, in the Environment section, click Preferences.
A small dialog box opens warning that you will lose your current path settings if you proceed.
Select Yes if you decide to proceed.
Run license to see if the toolbox is installed. If not, you may need to reinstall this toolbox to use this
function. For more information about installing a toolbox, see How do I install additional toolboxes
into an existing installation of MATLAB.
Once license shows your toolbox, run the following command to see if you can find the function:
replacing <functionname> with the name of the function. If MATLAB finds your function file, it
presents you with the path to it. You can add that file to the path using the addpath function. If it
does not, make sure the necessary toolbox is installed, and that it is the correct version.
If you are unable to use a built-in function from a MATLAB toolbox and have confirmed that the
toolbox is installed, make sure that you have an active license for that toolbox. Use license to
display currently active licenses. For additional support for managing licenses, see “Manage Your
Licenses”.
1-13
2
Program Components
Arithmetic Operators
Symbol Role
+ Addition
+A Unary plus
- Subtraction
-A Unary minus
.* Element-wise multiplication
* Matrix multiplication
./ Element-wise right division
/ Matrix right division
.\ Element-wise left division
\ Matrix left division
Relational Operators
Symbol Role
== Equal to
Logical Operators
Symbol Role
& Find logical AND
2-2
MATLAB Operators and Special Characters
Symbol Role
| Find logical OR
&& Find logical AND (with short-circuiting)
|| Find logical OR (with short-circuiting)
~ Find logical NOT
Special Characters
Symbol Role
@ Create anonymous functions and function
handles, call superclass methods
. Decimal point, element-wise operations, indexing
... Line continuation
, Separate row elements in an array, array
subscripts, function input and output arguments,
commands entered on the same line
: Vector creation, for-loop iteration, indexing
; Separate rows in an array creation command,
suppress output of a line of code
( ) Operator precedence, function argument
enclosure, indexing
[ ] Array construction and concatenation, empty
matrix creation, element deletion, multiple output
argument assignment
{ } Create cell array, indexing
% Code comments, conversion specifier
{% %} Block of comments that extend beyond one line
! Issue operating system command
? Retrieve metaclass information for class name
'' Create character array
"" Create string
~ Represent logical NOT, suppress specific input or
output arguments.
= Variable creation and indexing assignment.
2-3
2 Program Components
Use the special characters in this table to specify a folder path using a character vector or string.
Description: In addition to their use as mathematical operators, the slash and backslash
characters separate the elements of a path or folder. On Microsoft Windows based
systems, both slash and backslash have the same effect. On The Open Group UNIX based
systems, you must use slash only.
Examples
dir([matlabroot '\toolbox\matlab\elmat\shiftdim.m'])
dir([matlabroot '/toolbox/matlab/elmat/shiftdim.m'])
dir([matlabroot '/toolbox/matlab/elmat/shiftdim.m'])
.. Name: Dot dot
Description: Two dots in succession refers to the parent of the current folder. Use this
character to specify folder paths relative to the current folder.
Examples
To go up two levels in the folder tree and down into the test folder, use:
cd ..\..\test
More Information
• cd
2-4
MATLAB Operators and Special Characters
* Name: Asterisk
Description: In addition to being the symbol for matrix multiplication, the asterisk * is
used as a wildcard character.
Wildcards are generally used in file operations that act on multiple files or folders.
MATLAB matches all characters in the name exactly except for the wildcard character *,
which can match any one or more characters.
Examples
Locate all files with names that start with january_ and have a .mat file extension:
dir('january_*.mat')
@ Name: At symbol
Examples
\@myClass\get.m
More Information
Examples
+myfolder
+myfolder/pkfcn.m % a namespace function
+myfolder/@myClass % class folder in a namespace
More Information
• “Create Namespaces”
There are certain special characters that you cannot enter as ordinary text. Instead, you must use
unique character sequences to represent them. Use the symbols in this table to format strings and
character vectors on their own or in conjunction with formatting functions like compose, sprintf,
and error. For more information, see “Formatting Text” on page 6-24.
2-5
2 Program Components
See Also
More About
• “Array vs. Matrix Operations” on page 2-7
• “Array Comparison with Relational Operators” on page 2-16
• “Compatible Array Sizes for Basic Operations” on page 2-12
• “Operator Precedence” on page 2-19
• “Find Array Elements That Meet Conditions” on page 5-2
• “Greek Letters and Special Characters in Chart Text”
2-6
Array vs. Matrix Operations
Introduction
MATLAB has two different types of arithmetic operations: array operations and matrix operations.
You can use these arithmetic operations to perform numeric computations, for example, adding two
numbers, raising the elements of an array to a given power, or multiplying two matrices.
Matrix operations follow the rules of linear algebra. By contrast, array operations execute element by
element operations and support multidimensional arrays. The period character (.) distinguishes the
array operations from the matrix operations. However, since the matrix and array operations are the
same for addition and subtraction, the character pairs .+ and .- are unnecessary.
Array Operations
Array operations execute element by element operations on corresponding elements of vectors,
matrices, and multidimensional arrays. If the operands have the same size, then each element in the
first operand gets matched up with the element in the same location in the second operand. If the
operands have compatible sizes, then each input is implicitly expanded as needed to match the size of
the other.
As a simple example, you can add two vectors with the same size.
A = [1 1 1]
A =
1 1 1
B = [1 2 3]
B =
1 2 3
A+B
ans =
2 3 4
If one operand is a scalar and the other is not, then MATLAB implicitly expands the scalar to be the
same size as the other operand. For example, you can compute the element-wise product of a scalar
and a matrix.
A = [1 2 3; 1 2 3]
A =
2-7
2 Program Components
1 2 3
1 2 3
3.*A
ans =
3 6 9
3 6 9
Implicit expansion also works if you subtract a 1-by-3 vector from a 3-by-3 matrix because the two
sizes are compatible. When you perform the subtraction, the vector is implicitly expanded to become
a 3-by-3 matrix.
A = [1 1 1; 2 2 2; 3 3 3]
A =
1 1 1
2 2 2
3 3 3
m = [2 4 6]
m =
2 4 6
A - m
ans =
-1 -3 -5
0 -2 -4
1 -1 -3
A row vector and a column vector have compatible sizes. If you add a 1-by-3 vector to a 2-by-1 vector,
then each vector implicitly expands into a 2-by-3 matrix before MATLAB executes the element-wise
addition.
x = [1 2 3]
x =
1 2 3
y = [10; 15]
y =
10
15
x + y
ans =
11 12 13
16 17 18
2-8
Array vs. Matrix Operations
If the sizes of the two operands are incompatible, then you get an error.
A = [8 1 6; 3 5 7; 4 9 2]
A =
8 1 6
3 5 7
4 9 2
m = [2 4]
m =
2 4
A - m
For more information, see “Compatible Array Sizes for Basic Operations” on page 2-12.
The following table provides a summary of arithmetic array operators in MATLAB. For function-
specific information, click the link to the function reference page in the last column.
Matrix Operations
Matrix operations follow the rules of linear algebra and are not compatible with multidimensional
arrays. The required size and shape of the inputs in relation to one another depends on the operation.
For nonscalar inputs, the matrix operators generally calculate different answers than their array
operator counterparts.
For example, if you use the matrix right division operator, /, to divide two matrices, the matrices
must have the same number of columns. But if you use the matrix multiplication operator, *, to
2-9
2 Program Components
multiply two matrices, then the matrices must have a common inner dimension. That is, the number
of columns in the first input must be equal to the number of rows in the second input. The matrix
multiplication operator calculates the product of two matrices with the formula,
n
C(i, j) = ∑ A(i, k)B(k, j) .
k=1
A = [1 3;2 4]
A =
1 3
2 4
B = [3 0;1 5]
B =
3 0
1 5
A*B
ans =
6 15
10 20
The previous matrix product is not equal to the following element-wise product.
A.*B
ans =
3 0
2 20
The following table provides a summary of matrix arithmetic operators in MATLAB. For function-
specific information, click the link to the function reference page in the last column.
2-10
Array vs. Matrix Operations
See Also
More About
• “Compatible Array Sizes for Basic Operations” on page 2-12
• “MATLAB Operators and Special Characters” on page 2-2
• “Operator Precedence” on page 2-19
2-11
2 Program Components
Most binary (two-input) operators and functions in MATLAB support numeric arrays that have
compatible sizes. Two inputs have compatible sizes if, for every dimension, the dimension sizes of the
inputs are either the same or one of them is 1. In the simplest cases, two array sizes are compatible if
they are exactly the same or if one is a scalar. MATLAB implicitly expands arrays with compatible
sizes to be the same size during the execution of the element-wise operation or function.
These are some combinations of scalars, vectors, and matrices that have compatible sizes:
• One input is a matrix, and the other is a column vector with the same number of rows.
2-12
Compatible Array Sizes for Basic Operations
Multidimensional Arrays
Every array in MATLAB has trailing dimensions of size 1. For multidimensional arrays, this means
that a 3-by-4 matrix is the same as a matrix of size 3-by-4-by-1-by-1-by-1. Examples of
multidimensional arrays with compatible sizes are:
• One input is a matrix, and the other is a 3-D array with the same number of rows and columns.
• One input is a matrix, and the other is a 3-D array. The dimensions are all either the same or one
of them is 1.
Empty Arrays
The rules are the same for empty arrays or arrays that have a dimension size of zero. The size of the
dimension that is not equal to 1 determines the size of the output. This means that dimensions with a
2-13
2 Program Components
size of zero must be paired with a dimension of size 1 or 0 in the other array, and that the output has
a dimension size of 0.
A: 1-by-0
B: 3-by-1
Result: 3-by-0
A: 3-by-2
B: 4-by-2
• Two nonscalar row vectors with lengths that are not the same.
A: 1-by-3
B: 1-by-4
Examples
Subtract Vector from Matrix
To simplify vector-matrix operations, use implicit expansion with dimensional functions such as sum,
mean, min, and others.
For example, calculate the mean value of each column in a matrix, then subtract the mean value from
each element.
A = magic(3)
A =
8 1 6
3 5 7
4 9 2
C = mean(A)
C =
5 5 5
A - C
ans =
3 -4 1
-2 0 2
-1 4 -3
Row and column vectors have compatible sizes, and when you perform an operation on them the
result is a matrix.
2-14
Compatible Array Sizes for Basic Operations
For example, add a row and column vector. The result is the same as bsxfun(@plus,a,b).
a = [1 2 3 4]
ans =
1 2 3 4
b = [5; 6; 7]
ans =
5
6
7
a + b
ans =
6 7 8 9
7 8 9 10
8 9 10 11
See Also
bsxfun
More About
• “Array vs. Matrix Operations” on page 2-7
• “MATLAB Operators and Special Characters” on page 2-2
2-15
2 Program Components
Relational operators compare operands quantitatively, using operators like “less than”, “greater
than”, and “not equal to.” The result of a relational comparison is a logical array indicating the
locations where the relation is true.
Array Comparison
Numeric Arrays
The relational operators perform element-wise comparisons between two arrays. The arrays must
have compatible sizes to facilitate the operation. Arrays with compatible sizes are implicitly expanded
to be the same size during execution of the calculation. In the simplest cases, the two operands are
arrays of the same size, or one is a scalar. For more information, see “Compatible Array Sizes for
Basic Operations” on page 2-12.
For example, if you compare two matrices of the same size, then the result is a logical matrix of the
same size with elements indicating where the relation is true.
A = [2 4 6; 8 10 12]
A =
2 4 6
8 10 12
B = [5 5 5; 9 9 9]
B =
5 5 5
9 9 9
A < B
ans =
2-16
Array Comparison with Relational Operators
1 1 0
1 0 0
A > 7
ans =
0 0 0
1 1 1
If you compare a 1-by-N row vector to an M-by-1 column vector, then MATLAB expands each vector
into an M-by-N matrix before performing the comparison. The resulting matrix contains the
comparison result for each combination of elements in the vectors.
A = 1:3
A =
1 2 3
B = [2; 3]
B =
2
3
A >= B
ans =
0 1 1
0 0 1
Empty Arrays
The relational operators work with arrays for which any dimension has size zero, as long as both
arrays have compatible sizes. This means that if one array has a dimension size of zero, then the size
of the corresponding dimension in the other array must be 1 or zero, and the size of that dimension in
the output is zero.
A = ones(3,0);
B = ones(3,1);
A == B
ans =
A == []
return an error if A is not 0-by-0 or 1-by-1. This behavior is consistent with that of all other binary
operators, such as +, -, >, <, &, |, and so on.
2-17
2 Program Components
Complex Numbers
• The operators >, <, >=, and <= use only the real part of the operands in performing comparisons.
• The operators == and ~= test both real and imaginary parts of the operands.
Logic Statements
Use relational operators in conjunction with the logical operators A & B (AND), A | B (OR),
xor(A,B) (XOR), and ~A (NOT), to string together more complex logical statements.
For example, you can locate where negative elements occur in two arrays.
A = [2 -1; -3 10]
A =
2 -1
-3 10
B = [0 -2; -3 -1]
B =
0 -2
-3 -1
ans =
0 1
1 0
For more examples, see “Find Array Elements That Meet Conditions” on page 5-2.
See Also
gt | lt | ge | le | eq | ne
More About
• “Array vs. Matrix Operations” on page 2-7
• “Compatible Array Sizes for Basic Operations” on page 2-12
• “MATLAB Operators and Special Characters” on page 2-2
2-18
Operator Precedence
Operator Precedence
You can build expressions that use any combination of arithmetic, relational, and logical operators.
Precedence levels determine the order in which MATLAB evaluates an expression. Within each
precedence level, operators have equal precedence and are evaluated from left to right. The
precedence rules for MATLAB operators are shown in this list, ordered from highest precedence level
to lowest precedence level:
1 Parentheses ()
2 Transpose (.'), power (.^), complex conjugate transpose ('), matrix power (^)
3 Power with unary minus (.^-), unary plus (.^+), or logical negation (.^~) as well as matrix
power with unary minus (^-), unary plus (^+), or logical negation (^~).
Note Although most operators work from left to right, the operators (^-), (.^-), (^+), (.^+),
(^~), and (.^~) work from second from the right to left. It is recommended that you use
parentheses to explicitly specify the intended precedence of statements containing these
operator combinations.
4 Unary plus (+), unary minus (-), logical negation (~)
5 Multiplication (.*), right division (./), left division (.\), matrix multiplication (*), matrix
right division (/), matrix left division (\)
6 Addition (+), subtraction (-)
7 Colon operator (:)
8 Less than (<), less than or equal to (<=), greater than (>), greater than or equal to (>=),
equal to (==), not equal to (~=)
9 Element-wise AND (&)
10 Element-wise OR (|)
11 Short-circuit AND (&&)
12 Short-circuit OR (||)
The same precedence rule holds true for the && and || operators.
2-19
2 Program Components
C = (A./B).^2
C =
2.2500 81.0000 1.0000
See Also
More About
• “Array vs. Matrix Operations” on page 2-7
• “Compatible Array Sizes for Basic Operations” on page 2-12
• “Array Comparison with Relational Operators” on page 2-16
• “MATLAB Operators and Special Characters” on page 2-2
2-20
Average Similar Data Points Using a Tolerance
This example shows how to use uniquetol to find the average z-coordinate of 3-D points that have
similar (within tolerance) x and y coordinates.
Use random points picked from the peaks function in the domain [ − 3, 3] × [ − 3, 3] as the data set.
Add a small amount of noise to the data.
xy = rand(10000,2)*6-3;
z = peaks(xy(:,1),xy(:,2)) + 0.5-rand(10000,1);
A = [xy z];
plot3(A(:,1), A(:,2), A(:,3), '.')
view(-28,32)
Find points that have similar x and y coordinates using uniquetol with these options:
• Specify ByRows as true, since the rows of A contain the point coordinates.
• Specify OutputAllIndices as true to return the indices for all points that are within tolerance
of each other.
• Specify DataScale as [1 1 Inf] to use an absolute tolerance for the x and y coordinates, while
ignoring the z-coordinate.
DS = [1 1 Inf];
[C,ia] = uniquetol(A, 0.3, 'ByRows', true, ...
'OutputAllIndices', true, 'DataScale', DS);
2-21
2 Program Components
Average each group of points that are within tolerance (including the z-coordinates), producing a
reduced data set that still holds the general shape of the original data.
for k = 1:length(ia)
aveA(k,:) = mean(A(ia{k},:),1);
end
hold on
plot3(aveA(:,1), aveA(:,2), aveA(:,3), '.r', 'MarkerSize', 15)
See Also
uniquetol
More About
• “Group Scattered Data Using a Tolerance” on page 2-23
2-22
Group Scattered Data Using a Tolerance
This example shows how to group scattered data points based on their proximity to points of interest.
Create a set of random 2-D points. Then create and plot a grid of equally spaced points on top of the
random data.
x = rand(10000,2);
[a,b] = meshgrid(0:0.1:1);
gridPoints = [a(:), b(:)];
plot(x(:,1), x(:,2), '.')
hold on
plot(gridPoints(:,1), gridPoints(:,2), 'xr', 'Markersize', 6)
Use ismembertol to locate the data points in x that are within tolerance of the grid points in
gridPoints. Use these options with ismembertol:
• Specify ByRows as true, since the point coordinates are in the rows of x.
• Specify OutputAllIndices as true to return all of the indices for rows in x that are within
tolerance of the corresponding row in gridPoints.
For each grid point, plot the points in x that are within tolerance of that grid point.
2-23
2 Program Components
figure
hold on
for k = 1:length(LocB)
plot(x(LocB{k},1), x(LocB{k},2), '.')
end
plot(gridPoints(:,1), gridPoints(:,2), 'xr', 'Markersize', 6)
See Also
ismembertol
More About
• “Average Similar Data Points Using a Tolerance” on page 2-21
2-24
Bit-Wise Operations
Bit-Wise Operations
This topic shows how to use bit-wise operations in MATLAB® to manipulate the bits of numbers.
Operating on bits is directly supported by most modern CPUs. In many cases, manipulating the bits of
a number in this way is quicker than performing arithmetic operations like division or multiplication.
Number Representations
Any number can be represented with bits (also known as binary digits). The binary, or base 2, form of
a number contains 1s and 0s to indicate which powers of 2 are present in the number. For example,
the 8-bit binary form of 7 is
00000111
A collection of 8 bits is also called 1 byte. In binary representations, the bits are counted from the
right to the left, so the first bit in this representation is a 1. This number represents 7 because
2 1 0
2 + 2 + 2 = 7.
When you type numbers into MATLAB, it assumes the numbers are double precision (a 64-bit binary
representation). However, you can also specify single-precision numbers (32-bit binary
representation) and integers (signed or unsigned, from 8 to 64 bits). For example, the most memory
efficient way to store the number 7 is with an 8-bit unsigned integer:
a = uint8(7)
a = uint8
You can even specify the binary form directly using the prefix 0b followed by the binary digits (for
more information, see “Hexadecimal and Binary Values” on page 6-54). MATLAB stores the number
in an integer format with the fewest number of bits. Instead of specifying all the bits, you need to
specify only the left-most 1 and all the digits to the right of it. The bits to the left of that bit are
trivially zero. So the number 7 is:
b = 0b111
b = uint8
MATLAB stores negative integers using two's complement. For example, consider the 8-bit signed
integer -8. To find the two's complement bit pattern for this number:
1 Start with the bit pattern of the positive version of the number, 8: 00001000.
2 Next, flip all of the bits: 11110111.
3 Finally, add 1 to the result: 11111000.
n = 0b11111000s8
2-25
2 Program Components
n = int8
-8
MATLAB does not natively display the binary format of numbers. For that, you can use the dec2bin
function, which returns a character vector of binary digits for positive integers. Again, this function
returns only the digits that are not trivially zero.
dec2bin(b)
ans =
'111'
You can use bin2dec to switch between the two formats. For example, you can convert the binary
digits 10110101 to decimal format with the commands
data = [1 0 1 1 0 1 0 1];
dec = bin2dec(num2str(data))
dec =
181
The cast and typecast functions are also useful to switch among different data types. These
functions are similar, but they differ in how they treat the underlying storage of the number:
Because MATLAB does not display the digits of a binary number directly, you must pay attention to
data types when you work with bit-wise operations. Some functions return binary digits as a
character vector (dec2bin), some return the decimal number (bitand), and others return a vector of
the bits themselves (bitget).
MATLAB has several functions that enable you to perform logical operations on the bits of two equal-
length binary representations of numbers, known as bit masking:
• bitand — If both digits are 1, then the resulting digit is also a 1. Otherwise, the resulting digit is
0.
• bitor — If either digit is 1, then the resulting digit is also a 1. Otherwise, the resulting digit is 0.
• bitxor — If the digits are different, then the resulting digit is a 1. Otherwise, the resulting digit
is 0.
In addition to these functions, the bit-wise complement is available with bitcmp, but this is a unary
operation that flips the bits in only one number at a time.
One use of bit masking is to query the status of a particular bit. For example, if you use a bit-wise
AND operation with the binary number 00001000, you can query the status of the fourth bit. You can
then shift that bit to the first position so that MATLAB returns a 0 or 1 (the next section describes bit
shifting in more detail).
n = 0b10111001;
n4 = bitand(n,0b1000);
n4 = bitshift(n4,-3)
2-26
Bit-Wise Operations
n4 = uint8
Bit-wise operations can have surprising applications. For example, consider the 8-bit binary
representation of the number n = 8:
00001000
8 is a power of 2, so its binary representation contains a single 1. Now consider the number
n − 1 = 7:
00000111
By subtracting 1, all of the bits starting at the right-most 1 are flipped. As a result, when n is a power
of 2, corresponding digits of n and n − 1 are always different, and the bit-wise AND returns zero.
n = 0b1000;
bitand(n,n-1)
ans = uint8
0
However, when n is not a power of 2, then the right-most 1 is for the 2 bit, so n and n − 1 have all
0
the same bits except for the 2 bit. For this case, the bit-wise AND returns a nonzero number.
n = 0b101;
bitand(n,n-1)
ans = uint8
This operation suggests a simple function that operates on the bits of a given input number to check
whether the number is a power of 2:
function tf = isPowerOfTwo(n)
tf = n && ~bitand(n,n-1);
end
The use of the short-circuit AND operator && checks to make sure that n is not zero. If it is, then the
function does not need to calculate bitand(n,n-1) to know that the correct answer is false.
Shifting Bits
Because bit-wise logical operations compare corresponding bits in two numbers, it is useful to be able
to move the bits around to change which bits are compared. You can use bitshift to perform this
operation:
• bitshift(A,N) shifts the bits of A to the left by N digits. This is equivalent to multiplying A by
N
2 .
• bitshift(A,-N) shifts the bits of A to the right by N digits. This is equivalent to dividing A by
N
2 .
These operations are sometimes written A<<N (left shift) and A>>N (right shift), but MATLAB does not
use << and >> operators for this purpose.
2-27
2 Program Components
When the bits of a number are shifted, some bits fall off the end of the number, and 0s or 1s are
introduced to fill in the newly created space. When you shift bits to the left, the bits are filled in on
the right; when you shift bits to the right, the bits are filled in on the left.
For example, if you shift the bits of the number 8 (binary: 1000) to the right by one digit, you get 4
(binary: 100).
n = 0b1000;
bitshift(n,-1)
ans = uint8
Similarly, if you shift the number 15 (binary: 1111) to the left by two digits, you get 60 (binary:
111100).
n = 0b1111;
bitshift(15,2)
ans =
60
When you shift the bits of a negative number, bitshift preserves the signed bit. For example, if you
shift the signed integer -3 (binary: 11111101) to the right by 2 digits, you get -1 (binary: 11111111).
In these cases, bitshift fills in on the left with 1s rather than 0s.
n = 0b11111101s8;
bitshift(n,-2)
ans = int8
-1
Writing Bits
You can use the bitset function to change the bits in a number. For example, change the first bit of
the number 8 to a 1 (which adds 1 to the number):
bitset(8,1)
ans =
9
By default, bitset flips bits to on or 1. You can optionally use the third input argument to specify the
bit value.
bitset does not change multiple bits at once, so you need to use a for loop to change multiple bits.
Therefore, the bits you change can be either consecutive or nonconsecutive. For example, change the
first two bits of the binary number 1000:
bits = [1 2];
c = 0b1000;
for k = 1:numel(bits)
c = bitset(c,bits(k));
end
dec2bin(c)
2-28
Bit-Wise Operations
ans =
'1011'
Another common use of bitset is to convert a vector of binary digits into decimal format. For
example, use a loop to set the individual bits of the integer 11001101.
data = [1 1 0 0 1 1 0 1];
n = length(data);
dec = 0b0u8;
for k = 1:n
dec = bitset(dec,n+1-k,data(k));
end
dec
dec = uint8
205
dec2bin(dec)
ans =
'11001101'
Another use of bit shifting is to isolate consecutive sections of bits. For example, read the last four
bits in the 16-bit number 0110000010100000. Recall that the last four bits are on the left of the
binary representation.
n = 0b0110000010100000;
dec2bin(bitshift(n,-12))
ans =
'110'
To isolate consecutive bits in the middle of the number, you can combine the use of bit shifting with
logical masking. For example, to extract the 13th and 14th bits, you can shift the bits to the right by
12 and then mask the resulting four bits with 0011. Because the inputs to bitand must be the same
integer data type, you can specify 0011 as an unsigned 16-bit integer with 0b11u16. Without the -
u16 suffix, MATLAB stores the number as an unsigned 8-bit integer.
m = 0b11u16;
dec2bin(bitand(bitshift(n,-12),m))
ans =
'10'
Another way to read consecutive bits is with bitget, which reads specified bits from a number. You
can use colon notation to specify several consecutive bits to read. For example, read the last 8 bits of
n.
bitget(n,16:-1:8)
0 1 1 0 0 0 0 0 1
2-29
2 Program Components
You can also use bitget to read bits from a number when the bits are not next to each other. For
example, read the 5th, 8th, and 14th bits from n.
1 1 0
See Also
bitand | bitor | bitxor | bitget | bitset | bitshift | bitcmp
More About
• “Integers” on page 4-2
• “Perform Cyclic Redundancy Check” on page 2-31
• “Hexadecimal and Binary Values” on page 6-54
2-30
Perform Cyclic Redundancy Check
This example shows how to perform a cyclic redundancy check (CRC) on the bits of a number. CRCs
are used to detect errors in the transmission of data in digital systems. When a piece of data is sent, a
short check value is attached to it. The check value is obtained by polynomial division with the bits in
the data. When the data is received, the polynomial division is repeated, and the result is compared
with the check value. If the results differ, then the data was corrupted during transmission.
1101100111011010
To obtain the check value, divide this number by the polynomial x3 + x2 + x + 1. You can represent
this polynomial with its coefficients: 1111.
The division is performed in steps, and after each step the polynomial divisor is aligned with the left-
most 1 in the number. Because the result of dividing by the four term polynomial has three bits (in
general dividing by a polynomial of length n + 1 produces a check value of length n), append the
number with 000 to calculate the remainder. At each step, the result uses the bit-wise XOR of the four
bits being operated on, and all other bits are unchanged.
1101100111011010 000
1111
----------------
0010100111011010 000
Each successive division operates on the result of the previous step, so the second division is
0010100111011010 000
1111
----------------
0001010111011010 000
The division is completed once the dividend is all zeros. The complete division, including the above
two steps, is
1101100111011010 000
1111
0010100111011010 000
1111
0001010111011010 000
1111
0000101111011010 000
1111
0000010011011010 000
1111
0000001101011010 000
1111
0000000010011010 000
1111
0000000001101010 000
2-31
2 Program Components
1111
0000000000010010 000
1111
0000000000001100 000
1111
0000000000000011 000
11 11
0000000000000000 110
The remainder bits, 110, are the check value for this message.
In MATLAB®, you can perform this same operation to obtain the check value using bit-wise
operations. First, define variables for the message and polynomial divisor. Use unsigned 32-bit
integers so that extra bits are available for the remainder.
message = 0b1101100111011010u32;
messageLength = 16;
divisor = 0b1111u32;
divisorDegree = 3;
Next, initialize the polynomial divisor. Use dec2bin to display the bits of the result.
divisor = bitshift(divisor,messageLength-divisorDegree-1);
dec2bin(divisor)
ans =
'1111000000000000'
Now, shift the divisor and message so that they have the correct number of bits (16 bits for the
message and 3 bits for the remainder).
divisor = bitshift(divisor,divisorDegree);
remainder = bitshift(message,divisorDegree);
dec2bin(divisor)
ans =
'1111000000000000000'
dec2bin(remainder)
ans =
'1101100111011010000'
Perform the division steps of the CRC using a for loop. The for loop always advances a single bit
each step, so include a check to see if the current digit is a 1. If the current digit is a 1, then the
division step is performed; otherwise, the loop advances a bit and continues.
for k = 1:messageLength
if bitget(remainder,messageLength+divisorDegree)
remainder = bitxor(remainder,divisor);
end
remainder = bitshift(remainder,1);
end
Shift the bits of the remainder to the right to get the check value for the operation.
2-32
Perform Cyclic Redundancy Check
CRC_check_value = bitshift(remainder,-messageLength);
dec2bin(CRC_check_value)
ans =
'110'
You can use the check value to verify the integrity of a message by repeating the same division
operation. However, instead of using a remainder of 000 to start, use the check value 110. If the
message is error free, then the result of the division will be zero.
Reset the remainder variable, and add the CRC check value to the remainder bits using a bit-wise OR.
Introduce an error into the message by flipping one of the bit values with bitset.
remainder = bitshift(message,divisorDegree);
remainder = bitor(remainder,CRC_check_value);
remainder = bitset(remainder,6);
dec2bin(remainder)
ans =
'1101100111011110110'
Perform the CRC division operation and then check if the result is zero.
for k = 1:messageLength
if bitget(remainder,messageLength+divisorDegree)
remainder = bitxor(remainder,divisor);
end
remainder = bitshift(remainder,1);
end
if remainder == 0
disp('Message is error free.')
else
disp('Message contains errors.')
end
References
[1] Sklar, Bernard. Digital Communications: Fundamentals and Applications. Englewood Cliffs, NJ:
Prentice Hall, 1988.
[2] Wicker, Stephen B. Error Control Systems for Digital Communication and Storage. Upper Saddle
River, NJ: Prentice Hall, 1995.
See Also
bitshift | bitxor
More About
• “Bit-Wise Operations” on page 2-25
• “Hexadecimal and Binary Values” on page 6-54
2-33
2 Program Components
Conditional Statements
Conditional statements enable you to select at run time which block of code to execute. The simplest
conditional statement is an if statement. For example:
% If it is even, divide by 2
if rem(a, 2) == 0
disp('a is even')
b = a/2;
end
if statements can include alternate choices, using the optional keywords elseif or else. For
example:
a = randi(100, 1);
if a < 30
disp('small')
elseif a < 80
disp('medium')
else
disp('large')
end
Alternatively, when you want to test for equality against a set of known values, use a switch
statement. For example:
switch dayString
case 'Monday'
disp('Start of the work week')
case 'Tuesday'
disp('Day 2')
case 'Wednesday'
disp('Day 3')
case 'Thursday'
disp('Day 4')
case 'Friday'
disp('Last day of the work week')
otherwise
disp('Weekend!')
end
For both if and switch, MATLAB executes the code corresponding to the first true condition, and
then exits the code block. Each conditional statement requires the end keyword.
In general, when you have many possible discrete, known values, switch statements are easier to
read than if statements. However, you cannot test for inequality between switch and case values.
For example, you cannot implement this type of condition with a switch:
2-34
Conditional Statements
if yourNumber < 0
disp('Negative')
elseif yourNumber > 0
disp('Positive')
else
disp('Zero')
end
See Also
if | switch | end | return
External Websites
• Fundamentals of Programming (MathWorks Teaching Resources)
2-35
2 Program Components
With loop control statements, you can repeatedly execute a block of code. There are two types of
loops:
• for statements loop a specific number of times, and keep track of each iteration with an
incrementing index variable.
x = ones(1,10);
for n = 2:6
x(n) = 2 * x(n - 1);
end
• while statements loop as long as a condition remains true.
For example, find the first integer n for which factorial(n) is a 100-digit number:
n = 1;
nFactorial = 1;
while nFactorial < 1e100
n = n + 1;
nFactorial = nFactorial * n;
end
It is a good idea to indent the loops for readability, especially when they are nested (that is, when one
loop contains another loop):
A = zeros(5,100);
for m = 1:5
for n = 1:100
A(m, n) = 1/(m + n - 1);
end
end
You can programmatically exit a loop using a break statement, or skip to the next iteration of a loop
using a continue statement. For example, count the number of lines in the help for the magic
function (that is, all comment lines until a blank line):
fid = fopen('magic.m','r');
count = 0;
while ~feof(fid)
line = fgetl(fid);
if isempty(line)
break
elseif ~strncmp(line,'%',1)
continue
end
count = count + 1;
end
fprintf('%d lines in MAGIC help\n',count);
fclose(fid);
2-36
Loop Control Statements
Tip If you inadvertently create an infinite loop (a loop that never ends on its own), stop execution of
the loop by pressing Ctrl+C.
See Also
for | while | break | continue | end
External Websites
• Fundamentals of Programming (MathWorks Teaching Resources)
2-37
2 Program Components
Regular Expressions
In this section...
“What Is a Regular Expression?” on page 2-38
“Steps for Building Expressions” on page 2-39
“Operators and Characters” on page 2-42
This topic describes what regular expressions are and how to use them to search text. Regular
expressions are flexible and powerful, though they use complex syntax. An alternative to regular
expressions is a pattern (since R2020b), which is simpler to define and results in code that is easier
to read. For more information, see “Build Pattern Expressions” on page 6-40.
The character vector 'Joh?n\w*' is an example of a regular expression. It defines a pattern that
starts with the letters Jo, is optionally followed by the letter h (indicated by 'h?'), is then followed
by the letter n, and ends with any number of word characters, that is, characters that are alphabetic,
numeric, or underscore (indicated by '\w*'). This pattern matches any of the following:
Regular expressions provide a unique way to search a volume of text for a particular subset of
characters within that text. Instead of looking for an exact character match as you would do with a
function like strfind, regular expressions give you the ability to look for a particular pattern of
characters.
km/h
km/hr
km/hour
kilometers/hour
kilometers per hour
You could locate any of the above terms in your text by issuing five separate search commands:
strfind(text, 'km/h');
strfind(text, 'km/hour');
% etc.
To be more efficient, however, you can build a single phrase that applies to all of these search terms:
2-38
Regular Expressions
Translate this phrase into a regular expression (to be explained later in this section) and you have:
pattern = 'k(ilo)?m(eters)?(/|\sper\s)h(r|our)?';
Now locate one or more of the terms using just a single command:
ans =
There are four MATLAB functions that support searching and replacing characters using regular
expressions. The first three are similar in the input values they accept and the output values they
return. For details, click the links to the function reference pages.
Function Description
regexp Match regular expression.
regexpi Match regular expression, ignoring case.
regexprep Replace part of text using regular expression.
regexptranslate Translate text into regular expression.
When calling any of the first three functions, pass the text to be parsed and the regular expression in
the first two input arguments. When calling regexprep, pass an additional input that is an
expression that specifies a pattern for the replacement.
This entails breaking up the text you want to search for into groups of like character types. These
character types could be a series of lowercase letters, a dollar sign followed by three numbers
and then a decimal point, etc.
2 Express each pattern as a regular expression on page 2-41
2-39
2 Program Components
Use the metacharacters and operators described in this documentation to express each segment
of your search pattern as a regular expression. Then combine these expression segments into the
single expression to use in the search.
3 Call the appropriate search function on page 2-41
Pass the text you want to parse to one of the search functions, such as regexp or regexpi, or to
the text replacement function, regexprep.
The example shown in this section searches a record containing contact information belonging to a
group of five friends. This information includes each person's name, telephone number, place of
residence, and email address. The goal is to extract specific information from the text..
contacts = { ...
'Harry 287-625-7315 Columbus, OH hparker@hmail.com'; ...
'Janice 529-882-1759 Fresno, CA jan_stephens@horizon.net'; ...
'Mike 793-136-0975 Richmond, VA sue_and_mike@hmail.net'; ...
'Nadine 648-427-9947 Tampa, FL nadine_berry@horizon.net'; ...
'Jason 697-336-7728 Montrose, CO jason_blake@mymail.com'};
The first part of the example builds a regular expression that represents the format of a standard
email address. Using that expression, the example then searches the information for the email
address of one of the group of friends. Contact information for Janice is in row 2 of the contacts cell
array:
contacts{2}
ans =
A typical email address is made up of standard components: the user's account name, followed by an
@ sign, the name of the user's internet service provider (ISP), a dot (period), and the domain to which
the ISP belongs. The table below lists these components in the left column, and generalizes the
format of each component in the right column.
2-40
Regular Expressions
In this step, you translate the general formats derived in Step 1 into segments of a regular
expression. You then add these segments together to form the entire expression.
The table below shows the generalized format descriptions of each character pattern in the left-most
column. (This was carried forward from the right column of the table in Step 1.) The second column
shows the operators or metacharacters that represent the character pattern.
Assembling these patterns into one character vector gives you the complete expression:
email = '[a-z_]+@[a-z]+\.(com|net)';
In this step, you use the regular expression derived in Step 2 to match an email address for one of the
friends in the group. Use the regexp function to perform the search.
Here is the list of contact information shown earlier in this section. Each person's record occupies a
row of the contacts cell array:
contacts = { ...
'Harry 287-625-7315 Columbus, OH hparker@hmail.com'; ...
'Janice 529-882-1759 Fresno, CA jan_stephens@horizon.net'; ...
'Mike 793-136-0975 Richmond, VA sue_and_mike@hmail.net'; ...
'Nadine 648-427-9947 Tampa, FL nadine_berry@horizon.net'; ...
'Jason 697-336-7728 Montrose, CO jason_blake@mymail.com'};
This is the regular expression that represents an email address, as derived in Step 2:
email = '[a-z_]+@[a-z]+\.(com|net)';
Call the regexp function, passing row 2 of the contacts cell array and the email regular
expression. This returns the email address for Janice.
regexp(contacts{2}, email, 'match')
ans =
{'jan_stephens@horizon.net'}
MATLAB parses a character vector from left to right, “consuming” the vector as it goes. If matching
characters are found, regexp records the location and resumes parsing the character vector, starting
just after the end of the most recent match.
Make the same call, but this time for the fifth person in the list:
2-41
2 Program Components
ans =
{'jason_blake@mymail.com'}
You can also search for the email address of everyone in the list by using the entire cell array for the
input argument:
Metacharacters
Metacharacters represent letters, letter ranges, digits, and space characters. Use them to construct a
generalized pattern of characters.
2-42
Regular Expressions
Character Representation
Operator Description
\a Alarm (beep)
\b Backspace
\f Form feed
\n New line
\r Carriage return
\t Horizontal tab
\v Vertical tab
\char Any character with special meaning in regular expressions that you want to match literally
(for example, use \\ to match a single backslash)
Quantifiers
Quantifiers specify the number of times a pattern must occur in the matching text.
2-43
2 Program Components
{0,1} is equivalent to ?.
expr{m,} At least m times consecutively. '<a href="\w{1,}\.html">' matches an
<a> HTML tag when the file name contains one
{0,} and {1,} are equivalent to * and +, or more characters.
respectively.
expr{n} Exactly n times consecutively. '\d{4}' matches four consecutive digits.
Equivalent to {n,n}.
Quantifiers can appear in three modes, described in the following table. q represents any of the
quantifiers in the previous table.
'<tr><td><p>text</p></td>'
exprq? Lazy expression: match as few characters as Given the text'<tr><td><p>text</p></
necessary. td>', the expression '</?t.*?>' ends each
match at the first occurrence of the closing
angle bracket (>):
Grouping Operators
Grouping operators allow you to capture tokens, apply one operator to multiple elements, or disable
backtracking in a specific group.
2-44
Regular Expressions
Anchors
Anchors in the expression match the beginning or end of a character vector or word.
Lookaround Assertions
Lookaround assertions look for patterns that immediately precede or follow the intended match, but
are not part of the match.
The pointer remains at the current location, and characters that correspond to the test expression
are not captured or discarded. Therefore, lookahead assertions can match overlapping character
groups.
2-45
2 Program Components
If you specify a lookahead assertion before an expression, the operation is equivalent to a logical AND.
For more information, see “Lookahead Assertions in Regular Expressions” on page 2-50.
Logical and conditional operators allow you to test the state of a given condition, and then use the
outcome to determine which pattern, if any, to match next. These operators support logical OR and if
or if/else conditions. (For AND conditions, see “Lookaround Assertions” on page 2-45.)
Conditions can be tokens on page 2-47, lookaround assertions on page 2-45, or dynamic expressions
on page 2-47 of the form (?@cmd). Dynamic expressions must return a logical or numeric value.
2-46
Regular Expressions
Token Operators
Tokens are portions of the matched text that you define by enclosing part of the regular expression in
parentheses. You can refer to a token by its sequence in the text (an ordinal token), or assign names
to tokens for easier code maintenance and readable output.
Note If an expression has nested parentheses, MATLAB captures tokens that correspond to the
outermost set of parentheses. For example, given the search pattern '(and(y|rew))', MATLAB
creates a token for 'andrew' but not for 'y' or 'rew'.
Dynamic Expressions
Dynamic expressions allow you to execute a MATLAB command or a regular expression to determine
the text to match.
The parentheses that enclose dynamic expressions do not create a capturing group.
2-47
2 Program Components
Within dynamic expressions, use the following operators to define replacement terms.
Comments
The comment operator enables you to insert comments into your code to make it more maintainable.
The text of the comment is ignored by MATLAB when matching against the input text.
Search Flags
Flag Description
(?-i) Match letter case (default for regexp and regexprep).
(?i) Do not match letter case (default for regexpi).
2-48
Regular Expressions
Flag Description
(?s) Match dot (.) in the pattern with any character (default).
(?-s) Match dot in the pattern with any character that is not a newline character.
(?-m) Match the ^ and $ metacharacters at the beginning and end of text (default).
(?m) Match the ^ and $ metacharacters at the beginning and end of a line.
(?-x) Include space characters and comments when matching (default).
(?x) Ignore space characters and comments when matching. Use '\ ' and '\#' to
match space and # characters.
The expression that the flag modifies can appear either after the parentheses, such as
(?i)\w*
or inside the parentheses and separated from the flag with a colon (:), such as
(?i:\w*)
The latter syntax allows you to change the behavior for part of a larger expression.
See Also
regexp | regexpi | regexprep | regexptranslate | pattern
More About
• “Lookahead Assertions in Regular Expressions” on page 2-50
• “Tokens in Regular Expressions” on page 2-53
• “Dynamic Regular Expressions” on page 2-59
• “Search and Replace Text” on page 6-37
2-49
2 Program Components
Lookahead Assertions
There are two types of lookaround assertions for regular expressions: lookahead and lookbehind. In
both cases, the assertion is a condition that must be satisfied to return a match to the expression.
A lookahead assertion has the form (?=test) and can appear anywhere in a regular expression.
MATLAB looks ahead of the current location in the text for the test condition. If MATLAB matches the
test condition, it continues processing the rest of the expression to find a match.
For example, look ahead in a character vector specifying a path to find the name of the folder that
contains a program file (in this case, fileread.m).
chr = which('fileread')
chr =
'matlabroot\toolbox\matlab\iofun\fileread.m'
regexp(chr,'\w+(?=\\\w+\.[mp])','match')
ans =
{'iofun'}
The match expression, \w+, searches for one or more alphanumeric or underscore characters. Each
time regexp finds a term that matches this condition, it looks ahead for a backslash (specified with
two backslashes, \\), followed by a file name (\w+) with an .m or .p extension (\.[mp]). The
regexp function returns the match that satisfies the lookahead condition, which is the folder name
iofun.
Overlapping Matches
Lookahead assertions do not consume any characters in the text. As a result, you can use them to find
overlapping character sequences.
For example, use lookahead to find every sequence of six nonwhitespace characters in a character
vector by matching initial characters that precede five additional characters:
startIndex =
1 8 9 16 17 24 25
2-50
Lookahead Assertions in Regular Expressions
Without the lookahead operator, MATLAB parses a character vector from left to right, consuming the
vector as it goes. If matching characters are found, regexp records the location and resumes parsing
the character vector from the location of the most recent match. There is no overlapping of
characters in this process.
chr = 'Locate several 6-char. phrases';
startIndex = regexpi(chr,'\S{6}')
startIndex =
1 8 16 24
chr =
Merely searching for non-vowels ([^aeiou]) does not return the expected answer, as the output
includes capital letters, space characters, and punctuation:
c = regexp(chr,'[^aeiou]','match')
c =
Columns 1 through 14
{' '} {'N'} {'O'} {'R'} {'M'} {'E'} {'S'} {'T'} {' '} {'E'} {'s
Columns 15 through 28
{' '} {'t'} {'h'} {' '} {'m'} {'t'} {'r'} {'x'} {' '} {'2'} {'-
Columns 29 through 42
{'.'} {'↵'} {' '} {' '} {' '} {' '} {'N'} {'O'} {'R'} {'M'} {'E
Column 43
{'S'}
2-51
2 Program Components
Try this again, using a lookahead operator to create the following AND condition:
c = regexp(chr,'(?=[a-z])[^aeiou]','match')
c =
{'s'} {'t'} {'m'} {'t'} {'t'} {'h'} {'m'} {'t'} {'r'} {'x'} {'n
Note that when using a lookahead operator to perform an AND, you need to place the match
expression expr after the test expression test:
(?=test)expr or (?!test)expr
See Also
regexp | regexpi | regexprep
More About
• “Regular Expressions” on page 2-38
2-52
Tokens in Regular Expressions
In this section...
“Introduction” on page 2-53
“Multiple Tokens” on page 2-55
“Unmatched Tokens” on page 2-56
“Tokens in Replacement Text” on page 2-56
“Named Capture” on page 2-57
Introduction
Parentheses used in a regular expression not only group elements of that expression together, but
also designate any matches found for that group as tokens. You can use tokens to match other parts
of the same text. One advantage of using tokens is that they remember what they matched, so you
can recall and reuse matched text in the process of searching or replacing.
Each token in the expression is assigned a number, starting from 1, going from left to right. To make
a reference to a token later in the expression, refer to it using a backslash followed by the token
number. For example, when referencing a token generated by the third set of parentheses in the
expression, use \3.
As a simple example, if you wanted to search for identical sequential letters in a character array, you
could capture the first letter as a token and then search for a matching character immediately
afterwards. In the expression shown below, the (\S) phrase creates a token whenever regexp
matches any nonwhitespace character in the character array. The second part of the expression,
'\1', looks for a second instance of the same character immediately following the first.
poe = ['While I nodded, nearly napping, ' ...
'suddenly there came a tapping,'];
mat =
The cell array tok contains cell arrays that each contain a token.
tok{:}
ans =
{'d'}
ans =
2-53
2 Program Components
{'p'}
ans =
{'d'}
ans =
{'p'}
The cell array ext contains numeric arrays that each contain starting and ending indices for a token.
ext{:}
ans =
11 11
ans =
26 26
ans =
35 35
ans =
57 57
For another example, capture pairs of matching HTML tags (e.g., <a> and </a>) and the text
between them. The expression used for this example is
expr = '<(\w+).*?>.*?</\1>';
The first part of the expression, '<(\w+)', matches an opening angle bracket (<) followed by one or
more alphabetic, numeric, or underscore characters. The enclosing parentheses capture token
characters following the opening angle bracket.
The second part of the expression, '.*?>.*?', matches the remainder of this HTML tag (characters
up to the >), and any characters that may precede the next opening angle bracket.
The last part, '</\1>', matches all characters in the ending HTML tag. This tag is composed of the
sequence </tag>, where tag is whatever characters were captured as a token.
hstr = '<!comment><a name="752507"></a><b>Default</b><br>';
expr = '<(\w+).*?>.*?</\1>';
2-54
Tokens in Regular Expressions
ans =
'<a name="752507"></a>'
ans =
'<b>Default</b>'
tok{:}
ans =
{'a'}
ans =
{'b'}
Multiple Tokens
Here is an example of how tokens are assigned values. Suppose that you are going to search the
following text:
You choose to search the above text with the following search pattern:
and(y|rew)|(t)e(d)
This pattern has three parenthetical expressions that generate tokens. When you finally perform the
search, the following tokens are generated for each match.
Only the highest level parentheses are used. For example, if the search pattern and(y|rew) finds the
text andrew, token 1 is assigned the value rew. However, if the search pattern (and(y|rew)) is
used, token 1 is assigned the value andrew.
2-55
2 Program Components
Unmatched Tokens
For those tokens specified in the regular expression that have no match in the text being evaluated,
regexp and regexpi return an empty character vector ('') as the token output, and an extent that
marks the position in the string where the token was expected.
The example shown here executes regexp on a character vector specifying the path returned from
the MATLAB tempdir function. The regular expression expr includes six token specifiers, one for
each piece of the path. The third specifier [a-z]+ has no match in the character vector because this
part of the path, Profiles, begins with an uppercase letter:
chr = tempdir
chr =
'C:\WINNT\Profiles\bpascal\LOCALS~1\Temp\'
When a token is not found in the text, regexp returns an empty character vector ('') as the token
and a numeric array with the token extent. The first number of the extent is the string index that
marks where the token was expected, and the second number of the extent is equal to one less than
the first.
In the case of this example, the empty token is the third specified in the expression, so the third token
returned is empty:
tok{:}
ans =
The third token extent returned in the variable ext has the starting index set to 10, which is where
the nonmatching term, Profiles, begins in the path. The ending extent index is set to one less than
the starting index, or 9:
ext{:}
ans =
1 2
4 8
10 9
19 25
27 34
36 39
2-56
Tokens in Regular Expressions
When using tokens in replacement text, reference them using $1, $2, etc. instead of \1, \2, etc. This
example captures two tokens and reverses their order. The first, $1, is 'Norma Jean' and the
second, $2, is 'Baker'. Note that regexprep returns the modified text, not a vector of starting
indices.
ans =
Named Capture
If you use a lot of tokens in your expressions, it may be helpful to assign them names rather than
having to keep track of which token number is assigned to which token.
When referencing a named token within the expression, use the syntax \k<name> instead of the
numeric \1, \2, etc.:
ans =
Named tokens can also be useful in labeling the output from the MATLAB regular expression
functions. This is especially true when you are processing many pieces of text.
For example, parse different parts of street addresses from several character vectors. A short name is
assigned to each token in the expression:
p1 = '(?<adrs>\d+\s\S+\s(Road|Street|Avenue|Drive))';
p2 = '(?<city>[A-Z][a-z]+)';
p3 = '(?<state>[A-Z]{2})';
p4 = '(?<zip>\d{5})';
As the following results demonstrate, you can make your output easier to work with by using named
tokens:
loc1 =
2-57
2 Program Components
loc2 =
loc3 =
See Also
regexp | regexpi | regexprep
More About
• “Regular Expressions” on page 2-38
2-58
Dynamic Regular Expressions
In this section...
“Introduction” on page 2-59
“Dynamic Match Expressions — (??expr)” on page 2-60
“Commands That Modify the Match Expression — (??@cmd)” on page 2-60
“Commands That Serve a Functional Purpose — (?@cmd)” on page 2-61
“Commands in Replacement Expressions — ${cmd}” on page 2-63
Introduction
In a dynamic expression, you can make the pattern that you want regexp to match dependent on the
content of the input text. In this way, you can more closely match varying input patterns in the text
being parsed. You can also use dynamic expressions in replacement terms for use with the
regexprep function. This gives you the ability to adapt the replacement text to the parsed input.
You can include any number of dynamic expressions in the match_expr or replace_expr
arguments of these commands:
regexp(text, match_expr)
regexpi(text, match_expr)
regexprep(text, match_expr, replace_expr)
As an example of a dynamic expression, the following regexprep command correctly replaces the
term internationalization with its abbreviated form, i18n. However, to use it on a different
term such as globalization, you have to use a different replacement expression:
match_expr = '(^\w)(\w*)(\w$)';
replace_expr1 = '$118$3';
regexprep('internationalization', match_expr, replace_expr1)
ans =
'i18n'
replace_expr2 = '$111$3';
regexprep('globalization', match_expr, replace_expr2)
ans =
'g11n'
match_expr = '(^\w)(\w*)(\w$)';
replace_expr = '$1${num2str(length($2))}$3';
2-59
2 Program Components
ans =
'i18n'
ans =
'g11n'
When parsed, a dynamic expression must correspond to a complete, valid regular expression. In
addition, dynamic match expressions that use the backslash escape character (\) require two
backslashes: one for the initial parsing of the expression, and one for the complete match. The
parentheses that enclose dynamic expressions do not create a capturing group.
There are three forms of dynamic expressions that you can use in match expressions, and one form
for replacement expressions, as described in the following sections
Here is an example of the type of expression that you can use with this operator:
chr = {'5XXXXX', '8XXXXXXXX', '1X'};
regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once');
The purpose of this particular command is to locate a series of X characters in each of the character
vectors stored in the input cell array. Note however that the number of Xs varies in each character
vector. If the count did not vary, you could use the expression X{n} to indicate that you want to match
n of these characters. But, a constant value of n does not work in this case.
The solution used here is to capture the leading count number (e.g., the 5 in the first character vector
of the cell array) in a token, and then to use that count in a dynamic expression. The dynamic
expression in this example is (??X{$1}), where $1 is the value captured by the token \d+. The
operator {$1} makes a quantifier of that token value. Because the expression is dynamic, the same
pattern works on all three of the input vectors in the cell array. With the first input character vector,
regexp looks for five X characters; with the second, it looks for eight, and with the third, it looks for
just one:
regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once')
ans =
For example, use the dynamic expression (??@flilplr($1)) to locate a palindrome, “Never Odd or
Even”, that has been embedded into a larger character vector.
2-60
Dynamic Regular Expressions
First, create the input string. Make sure that all letters are lowercase, and remove all nonword
characters.
chr = lower(...
'Find the palindrome Never Odd or Even in this string');
chr =
'findthepalindromeneveroddoreveninthisstring'
Locate the palindrome within the character vector using the dynamic expression:
palindrome =
{'neveroddoreven'}
The dynamic expression reverses the order of the letters that make up the character vector, and then
attempts to match as much of the reversed-order vector as possible. This requires a dynamic
expression because the value for $1 relies on the value of the token (.{3,}).
Dynamic expressions in MATLAB have access to the currently active workspace. This means that you
can change any of the functions or variables used in a dynamic expression just by changing variables
in the workspace. Repeat the last command of the example above, but this time define the function to
be called within the expression using a function handle stored in the base workspace:
fun = @fliplr;
palindrome =
{'neveroddoreven'}
The following example parses a word for zero or more characters followed by two identical
characters followed again by zero or more characters:
ans =
2-61
2 Program Components
{'mississippi'}
To track the exact steps that MATLAB takes in determining the match, the example inserts a short
script (?@disp($1)) in the expression to display the characters that finally constitute the match.
Because the example uses greedy quantifiers, MATLAB attempts to match as much of the character
vector as possible. So, even though MATLAB finds a match toward the beginning of the string, it
continues to look for more matches until it arrives at the very end of the string. From there, it backs
up through the letters i then p and the next p, stopping at that point because the match is finally
satisfied:
regexp('mississippi', '\w*(\w)(?@disp($1))\1\w*', 'match')
i
p
p
ans =
{'mississippi'}
Now try the same example again, this time making the first quantifier lazy (*?). Again, MATLAB
makes the same match:
regexp('mississippi', '\w*?(\w)\1\w*', 'match')
ans =
{'mississippi'}
But by inserting a dynamic script, you can see that this time, MATLAB has matched the text quite
differently. In this case, MATLAB uses the very first match it can find, and does not even consider the
rest of the text:
regexp('mississippi', '\w*?(\w)(?@disp($1))\1\w*', 'match')
m
i
s
ans =
{'mississippi'}
To demonstrate how versatile this type of dynamic expression can be, consider the next example that
progressively assembles a cell array as MATLAB iteratively parses the input text. The (?!) operator
found at the end of the expression is actually an empty lookahead operator, and forces a failure at
each iteration. This forced failure is necessary if you want to trace the steps that MATLAB is taking to
resolve the expression.
MATLAB makes a number of passes through the input text, each time trying another combination of
letters to see if a fit better than last match can be found. On any passes in which no matches are
2-62
Dynamic Regular Expressions
found, the test results in an empty character vector. The dynamic script (?@if(~isempty($&)))
serves to omit the empty character vectors from the matches cell array:
matches = {};
expr = ['(Euler\s)?(Cauchy\s)?(Boole)?(?@if(~isempty($&)),' ...
'matches{end+1}=$&;end)(?!)'];
matches
matches =
{'Euler Cauchy Bo…'} {'Euler Cauchy '} {'Euler '} {'Cauchy Boole'} {'Cauchy '}
The operators $& (or the equivalent $0), $`, and $' refer to that part of the input text that is
currently a match, all characters that precede the current match, and all characters to follow the
current match, respectively. These operators are sometimes useful when working with dynamic
expressions, particularly those that employ the (?@cmd) operator.
This example parses the input text looking for the letter g. At each iteration through the text, regexp
compares the current character with g, and not finding it, advances to the next character. The
example tracks the progress of scan through the text by marking the current location being parsed
with a ^ character.
(The $` and $´ operators capture that part of the text that precedes and follows the current parsing
location. You need two single-quotation marks ($'') to express the sequence $´ when it appears
within text.)
chr = 'abcdefghij';
expr = '(?@disp(sprintf(''starting match: [%s^%s]'',$`,$'')))g';
Commands in replacement expressions only check the local workspace for variables. Caller and
global workspaces are not available to commands in replacement expressions
In the regexprep call shown here, the replacement pattern is '${convertMe($1,$2)}'. In this
case, the entire replacement pattern is a dynamic expression:
2-63
2 Program Components
The dynamic expression tells MATLAB to execute a function named convertMe using the two tokens
(\d+\.?\d*) and (\w+), derived from the text being matched, as input arguments in the call to
convertMe. The replacement pattern requires a dynamic expression because the values of $1 and $2
are generated at runtime.
The following example defines the file named convertMe that converts measurements from imperial
units to metric.
At the command line, call the convertMe function from regexprep, passing in values for the
quantity to be converted and name of the imperial unit:
ans =
ans =
ans =
2-64
Dynamic Regular Expressions
As with the (??@ ) operator discussed in an earlier section, the ${ } operator has access to
variables in the currently active workspace. The following regexprep command uses the array A
defined in the base workspace:
A = magic(3)
A =
8 1 6
3 5 7
4 9 2
ans =
See Also
regexp | regexpi | regexprep
More About
• “Regular Expressions” on page 2-38
2-65
2 Program Components
Comma-Separated Lists
In this section...
“What Is a Comma-Separated List?” on page 2-66
“Generating a Comma-Separated List” on page 2-66
“Assigning Output from a Comma-Separated List” on page 2-68
“Assigning to a Comma-Separated List” on page 2-68
“How to Use Comma-Separated Lists” on page 2-69
“Fast Fourier Transform Example” on page 2-72
“Troubleshooting Operations with Comma-Separated Lists” on page 2-72
1,2,3
ans =
ans =
ans =
When used with large and more complex data structures like MATLAB structures and cell arrays,
comma-separated lists can help simplify your code.
When you extract multiple elements from a cell array, the result is a comma-separated list. Define a 4-
by-6 cell array.
C = cell(4,6);
for k = 1:24
C{k} = k*2;
end
C
2-66
Comma-Separated Lists
C =
C{:,5}
ans =
34
ans =
36
ans =
38
ans =
40
C{1,5},C{2,5},C{3,5},C{4,5}
When you extract a field of a structure array across one of its dimensions, the result is a comma-
separated list.
Start by converting the cell array used above into a 4-by-1 MATLAB structure with six fields: f1
through f6. Read field f5 for all rows, and MATLAB returns a comma-separated list.
S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2);
S.f5
ans =
34
ans =
36
ans =
2-67
2 Program Components
38
ans =
40
S(1).f5,S(2).f5,S(3).f5,S(4).f5
C = cell(4,6);
for k = 1:24
C{k} = k*2;
end
[c1,c2,c3,c4,c5,c6] = C{1,1:6};
c5
c5 =
34
When you specify fewer output variables than the number of outputs returned by the expression,
MATLAB assigns the first N outputs to those N variables and ignores any remaining outputs. In this
example, MATLAB assigns C{1,1:3} to the variables c1, c2, and c3 and ignores C{1,4:6}.
[c1,c2,c3] = C{1,1:6};
S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2);
[sf1,sf2,sf3] = S.f5;
sf3
sf3 =
38
You also can use the deal function for this purpose.
This example uses deal to overwrite each element in a comma-separated list. First initialize a two-
element list. This step is necessary because you cannot use comma-separated list assignment with an
undefined variable when using : as an index. See “Comma-Separated List Assignment to an
Undefined Variable” on page 2-75 for more information.
2-68
Comma-Separated Lists
c{1} = [];
c{2} = [];
c{:}
ans =
[]
ans =
[]
ans =
10 20
ans =
14 12
This example works in the same way, but with a comma-separated list of vectors in a structure field.
s(1).field1 = [[]];
s(2).field1 = [[]];
s.field1
ans =
[]
ans =
[]
ans =
10 20
ans =
14 12
2-69
2 Program Components
These sections provide examples of using comma-separated lists with cell arrays. Each of these
examples applies to structures as well.
Constructing Arrays
You can use a comma-separated list to enter a series of elements when constructing a matrix or array.
When you specify a list of elements with C{:,5}, MATLAB inserts the four individual elements.
C = cell(4,6);
for k = 1:24
C{k} = k*2;
end
A = {'Hello',C{:,5},magic(4)}
A =
When you specify the C cell itself, MATLAB inserts the entire cell array.
A = {'Hello',C,magic(4)}
A =
Displaying Arrays
ans =
'Hello'
ans =
2-70
Comma-Separated Lists
ans =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
Concatenation
Putting a comma-separated list inside square brackets extracts the specified elements from the list
and concatenates them.
A = [C{:,5:6}]
A =
34 36 38 40 42 44 46 48
When writing the code for a function call, you enter the input arguments as a list with each argument
separated by a comma. If you have these arguments stored in a structure or cell array, then you can
generate all or part of the argument list from the structure or cell array instead. This can be
especially useful when passing in variable numbers of arguments.
X = -pi:pi/10:pi;
Y = tan(sin(X)) - sin(tan(X));
C = cell(2,3);
C{1,1} = 'LineWidth';
C{2,1} = 2;
C{1,2} = 'MarkerEdgeColor';
C{2,2} = 'k';
C{1,3} = 'MarkerFaceColor';
C{2,3} = 'g';
figure
plot(X,Y,'--rs',C{:})
MATLAB functions can also return more than one value to the caller. These values are returned in a
list with each value separated by a comma. Instead of listing each return value, you can use a comma-
separated list with a structure or cell array. This becomes more useful for functions that have variable
numbers of return values.
C = cell(1,3);
[C{:}] = fileparts('work/mytests/strArrays.mat')
C =
2-71
2 Program Components
fftshift uses vectors of indices to perform the swap. For the vector shown above, the index [1 2
3 4 5 6] is rearranged to form a new index [4 5 6 1 2 3]. The function then uses this index
vector to reposition the elements. For a multidimensional array, fftshift constructs an index vector
for each dimension. A comma-separated list makes this task much simpler.
function y = fftshift(x)
numDims = ndims(x);
idx = cell(1,numDims);
for k = 1:numDims
m = size(x,k);
p = ceil(m/2);
idx{k} = [p+1:m 1:p];
end
y = x(idx{:});
end
The function stores the index vectors in cell array idx. Building this cell array is relatively simple.
For each of the N dimensions, determine the size of that dimension and find the integer index nearest
the midpoint. Then, construct a vector that swaps the two halves of that dimension.
By using a cell array to store the index vectors and a comma-separated list for the indexing operation,
fftshift shifts arrays of any dimension using just a single operation: y = x(idx{:}). If you use
explicit indexing, you need to write one if statement for each dimension you want the function to
handle.
if ndims(x) == 1
y = x(index1);
else if ndims(x) == 2
y = x(index1,index2);
end
end
Another way to handle this without a comma-separated list is to loop over each dimension, converting
one dimension at a time and moving data each time. With a comma-separated list, you move the data
just once. A comma-separated list makes it easy to generalize the swapping operation to any number
of dimensions.
2-72
Comma-Separated Lists
Compound indexing expressions with braces or dots can produce comma-separated lists. You must
index into the individual elements of the list to access them.
For example, create a 1-by-2 cell array that contains two 3-by-3 matrices of doubles.
A = {magic(3),rand(3)}
A =
A{1,:}
ans =
8 1 6
3 5 7
4 9 2
ans =
Indexing into A this way produces a comma-separated list that includes both matrices contained by
the cell array. You cannot use parentheses indexing to retrieve the entries at (1,2) in both matrices
in the list.
A{1,:}(1,2)
To retrieve the entries at (1,2) in both of the matrices in the cell array, index into the cells
individually.
A{1,1}(1,2)
A{1,2}(1,2)
ans =
ans =
0.0357
2-73
2 Program Components
Arguments for conditional statements, logical operators, loops, and switch statements cannot be
comma-separated lists. For example, you cannot directly loop through the contents of a comma-
separated list using a for loop.
A = cell(1,3);
A{1} = 2;
A{2} = 3;
A{3} = 5;
A{:}
ans =
ans =
ans =
Using for to loop through the comma-separated list generated by A{:} errors.
for c = A{:}
disp(c)
end
To loop over the contents of A, enclose A{:} in square brackets to concatenate the values into a
vector.
for c = [A{:}]
disp(c)
end
Unlike with arrays, using simple assignment to assign values to multiple elements of a comma-
separated list errors. For example, define a 2-by-3 cell array.
B = cell(2,3);
2-74
Comma-Separated Lists
Assigning a value of 5 to all cells of the array using : as an index for B errors.
B{:} = 5
One way to accomplish this assignment is to enclose B{:} in square brackets and use the deal
function.
[B{:}] = deal(5)
B =
You cannot assign a comma-separated list to an undefined variable using : as an index. In the
example in “Assigning to a Comma-Separated List” on page 2-68, the variable x is defined as a
comma-separated list with explicit indices before assigning new values to it using : as an index.
x{1} = [];
x{2} = [];
[x{:}] = deal([10 20],[14 12]);
x{:}
ans =
10 20
ans =
14 12
Performing the same assignment with a variable that has not been initialized errors.
To solve this problem, initialize y in the same way as x, or create y using enough explicit indices to
accommodate the number of values produced by the deal function.
y =
2-75
2 Program Components
See Also
cell | deal | struct
2-76
Alternatives to the eval Function
• MATLAB compiles code the first time you run it to enhance performance for future runs. However,
because code in an eval statement can change at run time, it is not compiled.
• Code within an eval statement can unexpectedly create or assign to a variable already in the
current workspace, overwriting existing data.
• Concatenated character vectors within an eval statement are often difficult to read. Other
language constructs can simplify the syntax in your code.
For many common uses of eval, there are preferred alternate approaches, as shown in the following
examples.
For example, create a cell array that contains 10 elements, where each element is a numeric array:
numArrays = 10;
A = cell(numArrays,1);
for n = 1:numArrays
A{n} = magic(n);
end
Access the data in the cell array by indexing with curly braces. For example, display the fifth element
of A:
A{5}
ans =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
2-77
2 Program Components
10 12 19 21 3
11 18 25 2 9
The assignment statement A{n} = magic(n) is more elegant and efficient than this call to eval:
eval(['A', int2str(n),' = magic(n)']) % Not recommended
The best practice is to use function syntax, which allows you to pass variables as inputs. For example:
currentFile = 'myfile1.mat';
save(currentFile)
You can construct file names within a loop using the sprintf function (which is usually more
efficient than int2str), and then call the save function without eval. This code creates 10 files in
the current folder:
numFiles = 10;
for n = 1:numFiles
randomData = rand(n);
currentFile = sprintf('myfile%d.mat',n);
save(currentFile,'randomData')
end
• Create function handles with the @ symbol or with the str2func function. For example, run a
function from a list stored in a cell array:
examples = {@odedemo,@sunspots,@fitdemo};
n = input('Select an example (1, 2, or 3): ');
examples{n}()
• Use the feval function. For example, call a plot function (such as plot, bar, or pie) with data
that you specify at run time:
2-78
Alternatives to the eval Function
If you enter weight at the input prompt, then you can find the minimum weight value with the
following command.
min(dataToUse)
ans =
90
For an additional example, see “Generate Field Names from Variables” on page 11-10.
Error Handling
The preferred method for error handling in MATLAB is to use a try, catch statement. For example:
try
B = A;
catch exception
disp('A is undefined')
end
If your workspace does not contain variable A, then this code returns:
A is undefined
Previous versions of the documentation for the eval function include the syntax
eval(expression,catch_expr). If evaluating the expression input returns an error, then eval
evaluates catch_expr. However, an explicit try/catch is significantly clearer than an implicit
catch in an eval statement. Using the implicit catch is not recommended.
2-79
Classes (Data Types)
81
3
There are many different data types, or classes, that you can work with in MATLAB. You can build
matrices and arrays of floating-point and integer data, characters and strings, logical true and
false values, and so on. Function handles connect your code with any MATLAB function regardless
of the current scope. Tables, timetables, structures, and cell arrays provide a way to store dissimilar
types of data in the same container.
There are 17 fundamental classes in MATLAB. Each of these classes is in the form of a matrix or
array. With the exceptions of function handles and tables, this matrix or array is a minimum of 0-by-0
in size and can grow to an n-dimensional array of any size. A function handle is always scalar (1-by-1).
A table always has m rows and n variables, where m >= 0 and n >= 0.
Numeric classes in the MATLAB software include signed and unsigned integers, and single- and
double-precision floating-point numbers. By default, MATLAB stores all numeric values as double-
precision floating point. (You cannot change the default type and precision.) You can choose to store
any number, or array of numbers, as integers or as single-precision. Integer and single-precision
arrays offer more memory-efficient storage than double-precision.
All numeric types support basic array operations, such as subscripting, reshaping, and mathematical
operations.
You can create two-dimensional double and logical matrices using one of two storage formats:
full or sparse. For matrices with mostly zero-valued elements, a sparse matrix requires a fraction
of the storage space required for an equivalent full matrix. Sparse matrices invoke methods
especially tailored to solve sparse problems.
These classes require different amounts of storage, the smallest being a logical value or 8-bit
integer which requires only 1 byte. It is important to keep this minimum size in mind if you work on
data in files that were written using a precision smaller than 8 bits.
Tables and timetables also support mathematical operations as long as all their variables have
numeric data types. For more information, see “Direct Calculations on Tables and Timetables” on
page 9-54.
3-2
Fundamental MATLAB Classes
3-3
3 Overview of MATLAB Classes
See Also
More About
• “Valid Combinations of Unlike Classes” on page 15-2
External Websites
• Programming: Organizing Data (MathWorks Teaching Resources)
3-4
Use is* Functions to Detect State
• An array has a specified data type (such as numeric, double, categorical, datetime, or
string)
• A numeric matrix has certain properties (such as being symmetric)
• The elements of a numeric array are finite, real, or complex
• The elements of a categorical or datetime array meet certain conditions
• An array has any elements that are outliers, missing values, or local maxima or minima
• An object is a graphics handle, or a Java or COM object
This table contains an alphabetical list of the most notable is* functions with descriptions of the
states that they detect.
Function Description
isa Determine if input has specified data type
isappdata Determine if application data exists
isapprox Determine approximate equality
isbanded Determine if matrix is within specific bandwidth
isbetween Determine which elements are within specified range
iscalendarduration Determine if input is calendarDuration array
iscategorical Determine if input is categorical array
iscategory Determine if inputs are names of categories
iscell Determine if input is cell array
iscellstr Determine if input is cell array of character vectors
ischange Find abrupt changes in input
ischar Determine if input is character array
iscolumn Determine if input is column vector
iscom Determine if input is Component Object Model (COM) object
isConfigured Determine if dictionary is configured
isdatetime Determine if input is datetime array
isdiag Determine if matrix is diagonal
isdst Find elements of datetime array that occur during daylight saving
time
isduration Determine if input is duration array
isempty Determine if input is empty array
isenum Determine if input is enumeration
3-5
3 Overview of MATLAB Classes
Function Description
isequal Determine if arrays are numerically equal
isequaln Determine if arrays are numerically equal, treating NaNs as equal
isevent Determine if input is Component Object Model (COM) object event
isfield Determine if input is MATLAB structure array field
isfile Determine if input is a file
isfinite Find array elements that are finite
isfloat Determine if input is floating-point array
isfolder Determine if input is folder
isgraphics Determine if input is valid graphics object handle
ishandle Determine if input is valid graphics or Java object handle
ishermitian Determine if matrix is Hermitian or skew-Hermitian
ishold Determine if graphics hold state is on
isinf Find array elements that are infinite
isinteger Determine if input is integer array
isinterface Determine if input is Component Object Model (COM) interface
isjava Determine if input is Java object
isKey Determine if dictionary contains key
iskeyword Determine if input is MATLAB keyword
isletter Find characters that are letters
islocalmax Find local maxima in input
islocalmax2 Find local maxima in 2-D data
islocalmin Find local minima in input
islocalmin2 Find local minima in 2-D data
islogical Determine if input is logical array
ismac Determine if version is for macOS platform
ismatrix Determine if input is matrix
ismember Find array elements that are members of set array
ismembertol Find array elements, within tolerance, that are members of set array
ismethod Determine if object has specified method
ismissing Find missing values in input
isnan Find numeric array elements that are NaN (Not-a-Number)
isnat Find datetime array elements that are NaT (Not-a-Time)
isnumeric Determine if input is numeric array
isobject Determine if input is MATLAB object
isordinal Determine if input is ordinal categorical array
isoutlier Find outliers in input
3-6
Use is* Functions to Detect State
Function Description
ispc Determine if version is for Windows (PC) platform
isprime Find array elements that are prime
isprop Determine if input is object property
isprotected Determine if categories of categorical array are protected
isreal Determine if all numeric array elements are real numbers
isregular Determine if input times are regular with respect to time or
calendar unit
isrow Determine if input is row vector
isscalar Determine if input is scalar
issorted Determine if array is sorted
issortedrows Determine if matrix or table rows are sorted
isspace Find characters that are space characters
issparse Determine if input is sparse
isstring Determine if input is string array
isStringScalar Determine if input is string array with one element
isstrprop Find characters in input strings that are of specified category
isstruct Determine if input is structure array
isstudent Determine if version is Student Version
issymmetric Determine if matrix is symmetric or skew-symmetric
istable Determine if input is table
istabular Determine if input is table or timetable
istall Determine if input is tall array
istimetable Determine if input is timetable
istril Determine if matrix is lower triangular
istriu Determine if matrix is upper triangular
isundefined Find undefined elements in categorical array
isUnderlyingType Determine if input has specified underlying data type
isuniform Determine if vector is uniformly spaced
isunix Determine if version is for Linux® or macOS platforms
isvalid Determine if input is valid handle
isvarname Determine if input is valid variable name
isvector Determine if input is vector
isweekend Find elements of datetime array that occur during weekends
See Also
exist | openvar | what | which | who | whos | Workspace Browser
3-7
3 Overview of MATLAB Classes
Related Examples
• “Fundamental MATLAB Classes” on page 3-2
3-8
4
Numeric Classes
Integers
In this section...
“Integer Classes” on page 4-2
“Creating Integer Data” on page 4-2
“Arithmetic Operations on Integer Classes” on page 4-4
“Largest and Smallest Values for Integer Classes” on page 4-4
“Loss of Precision Due to Conversion” on page 4-5
Integer Classes
MATLAB has four signed and four unsigned integer classes. Signed types enable you to work with
negative integers as well as positive, but cannot represent as wide a range of numbers as the
unsigned types because one bit is used to designate a positive or negative sign for the number.
Unsigned types give you a wider range of numbers, but these numbers can only be zero or positive.
MATLAB supports 1-, 2-, 4-, and 8-byte storage for integer data. You can save memory and execution
time for your programs if you use the smallest integer type that accommodates your data. For
example, you do not need a 32-bit integer to store the value 100.
Here are the eight integer classes, the range of values you can store with each type, and the MATLAB
conversion function required to create that type.
For example, to store 325 as a 16-bit signed integer assigned to variable x, type
x = int16(325);
4-2
Integers
If the number being converted to an integer has a fractional part, MATLAB rounds to the nearest
integer. If the fractional part is exactly 0.5, then MATLAB chooses the nearest integer whose
absolute value is larger in magnitude:
x = 325.499;
int16(x)
ans =
int16
325
x = x + .001;
int16(x)
ans =
int16
326
If you need to round a number using a rounding scheme other than the default, MATLAB provides
four rounding functions: round, fix, floor, and ceil. The fix function enables you to override the
default and round towards zero when there is a nonzero fractional part:
x = 325.9;
int16(fix(x))
ans =
int16
325
Arithmetic operations that involve both integers and floating-point numbers always result in an
integer data type. MATLAB rounds the result, when necessary, according to the default rounding
algorithm. The example below yields an exact answer of 1426.75 which MATLAB then rounds to the
next highest integer:
int16(325)*4.39
ans =
int16
1427
The integer conversion functions are also useful when converting other classes, such as character
vectors, to integers:
chr = 'Hello World';
int8(chr)
ans =
4-3
4 Numeric Classes
If you convert a NaN value to an integer class, the result is a value of 0 in that integer class. For
example:
int32(NaN)
ans =
int32
• Integers or integer arrays of the same integer data type. Arithmetic operations yield a result that
has the same data type as the operands:
ans =
'uint32'
• Integers or integer arrays and scalar double-precision floating-point numbers. Arithmetic
operations yield a result that has the same data type as the integer operands:
ans =
'uint32'
For all binary operations in which one operand is an array of integer data type (except 64-bit
integers) and the other is a scalar double, MATLAB computes the operation using element-wise
double-precision arithmetic, and then converts the result back to the original integer data type. For
binary operations involving a 64-bit integer array and a scalar double, MATLAB computes the
operation as if 80-bit extended-precision arithmetic were used, to prevent loss of precision.
Operations involving complex numbers with integer types are not supported.
For each integer data type, there is a largest and smallest number that you can represent with that
type. The table shown under “Integer Classes” on page 4-2 lists the largest and smallest values for
each integer data type in the “Range of Values” column.
You can also obtain these values with the intmax and intmin functions:
intmax("int8")
ans =
int8
4-4
Integers
127
intmin("int8")
ans =
int8
-128
If you convert a number that is larger than the maximum value of an integer data type to that type,
MATLAB sets it to the maximum value. Similarly, if you convert a number that is smaller than the
minimum value of the integer data type, MATLAB sets it to the minimum value. For example:
x = int8(300)
x =
int8
127
x = int8(-300)
x =
int8
-128
Also, when the result of an arithmetic operation involving integers exceeds the maximum (or
minimum) value of the data type, MATLAB sets it to the maximum (or minimum) value:
x = int8(100)*3
x =
int8
127
x = int8(-100)*3
x =
int8
-128
4-5
4 Numeric Classes
For example, convert a numeric array of large integers to a 64-bit signed integer array by using
int64. The output array loses precision.
-72057594035891656 81997179153022976
Instead, call int64 with each scalar element to return an accurate array.
-72057594035891654 81997179153022975
You can also create the integer array without loss of precision by using the hexadecimal or binary
values on page 6-54 of the integers.
-72057594035891654 81997179153022975
4-6
Floating-Point Numbers
Floating-Point Numbers
“Floating point” refers to a set of data types that encode real numbers, including fractions and
decimals. Floating-point data types allow for a varying number of digits after the decimal point, while
fixed-point data types have a specific number of digits reserved before and after the decimal point.
So, floating-point data types can represent a wider range of numbers than fixed-point data types.
Due to limited memory for number representation and storage, computers can represent a finite set
of floating-point numbers that have finite precision. This finite precision can limit accuracy for
floating-point computations that require exact values or high precision, as some numbers are not
represented exactly. Despite their limitations, floating-point numbers are widely used due to their fast
calculations and sufficient precision and range for solving real-world problems.
You can store numbers between approximately –3.4 × 1038 and 3.4 × 1038 using either double or
single precision. If you have numbers outside of that range, store them using double precision.
Because the default numeric type for MATLAB is type double, you can create a double-precision
floating-point number with a simple assignment statement.
x = 10;
c = class(x)
c =
'double'
You can convert numeric data, characters or strings, and logical data to double precision by using the
double function. For example, convert a signed integer to a double-precision floating-point number.
x = int8(-113);
y = double(x)
y =
-113
You can also convert numeric data, characters or strings, and logical data to single precision by using
the single function. For example, convert a signed integer to a single-precision floating-point
number.
x = int8(-113);
y = single(x)
4-7
4 Numeric Classes
y =
single
-113
MATLAB constructs its double and single floating-point data types according to IEEE format and
follows the round to nearest, ties to even rounding mode by default.
where:
s, f, and e are each determined by a finite number of bits in memory, with f and e depending on the
precision of the data type.
Find the largest and smallest positive values that can be represented with the double data type by
using the realmax and realmin functions, respectively.
m = realmax
4-8
Floating-Point Numbers
m =
1.7977e+308
n = realmin
n =
2.2251e-308
realmax and realmin return normalized IEEE values. You can find the largest and smallest negative
values by multiplying realmax and realmin by -1. Numbers greater than realmax or less than –
realmax are assigned the values of positive or negative infinity, respectively.
Find the largest and smallest positive values that can be represented with the single data type by
calling the realmax and realmin functions with the argument "single".
m = realmax("single")
m =
single
3.4028e+38
n = realmin("single")
n =
single
1.1755e-38
You can find the largest and smallest negative values by multiplying realmax("single") and
realmin("single") by –1. Numbers greater than realmax("single") or less than –
realmax("single") are assigned the values of positive or negative infinity, respectively.
Not all integers are representable using floating-point data types. The largest consecutive integer, x,
is the greatest integer for which all integers less than or equal to x can be exactly represented, but x
+ 1 cannot be represented in floating-point format. The flintmax function returns the largest
consecutive integer. For example, find the largest consecutive integer in double-precision floating-
point format, which is 253, by using the flintmax function.
x = flintmax
x =
9.0072e+15
Find the largest consecutive integer in single-precision floating-point format, which is 224.
y = flintmax("single")
y =
single
16777216
When you convert an integer data type to a floating-point data type, integers that are not exactly
representable in floating-point format lose accuracy. flintmax, which is a floating-point number, is
less than the greatest integer representable by integer data types using the same number of bits. For
example, flintmax for double precision is 253, while the maximum value for type int64 is 264 – 1.
Therefore, converting an integer greater than 253 to double precision results in a loss of accuracy.
4-9
4 Numeric Classes
• Limitations of your computer hardware — For example, hardware with insufficient memory
truncates the results of floating-point calculations.
• Gaps between each floating-point number and the next larger floating-point number — These gaps
are present on any computer and limit precision.
You can determine the size of a gap between consecutive floating-point numbers by using the eps
function. For example, find the distance between 5 and the next larger double-precision number.
e = eps(5)
e =
8.8818e-16
You cannot represent numbers between 5 and 5 + eps(5) in double-precision format. If a double-
precision computation returns the answer 5, the result is accurate within eps(5). This radius of
accuracy is often called machine epsilon.
The gaps between floating-point numbers are not equal. For example, the gap between 1e10 and the
next larger double-precision number is larger than the gap between 5 and the next larger double-
precision number.
e = eps(1e10)
e =
1.9073e-06
Similarly, find the distance between 5 and the next larger single-precision number.
x = single(5);
e = eps(x)
e =
single
4.7684e-07
Gaps between single-precision numbers are larger than the gaps between double-precision numbers
because there are fewer single-precision numbers. So, results of single-precision calculations are less
precise than results of double-precision calculations.
When you convert a double-precision number to a single-precision number, you can determine the
upper bound for the amount the number is rounded by using the eps function. For example, when
you convert the double-precision number 3.14 to single precision, the number is rounded by at most
eps(single(3.14)).
The flintmax function returns the largest consecutive integer in floating-point format. Above this
value, consecutive floating-point integers have a gap greater than 1.
Find the gap between flintmax and the next floating-point number by using eps:
4-10
Floating-Point Numbers
format long
x = flintmax
x =
9.007199254740992e+15
e = eps(x)
e =
2
Because eps(x) is 2, the next larger floating-point number that can be represented exactly is x + 2.
y = x + e
y =
9.007199254740994e+15
z = x + 1
z =
9.007199254740992e+15
Double-Precision Operands
You can perform basic arithmetic operations with double and any of the following data types. If one
or more operands are an integer scalar or array, the double operand must be a scalar. The result is
of type double, except where noted otherwise.
Single-Precision Operands
You can perform basic arithmetic operations with single and any of the following data types. The
result is of type single.
• single
• double
• char
• logical
4-11
4 Numeric Classes
Round-Off Error
Round-off error can occur due to the finite-precision representation of floating-point numbers. For
example, the number 4/3 cannot be represented exactly as a binary fraction. As such, this calculation
returns the quantity eps(1), rather than 0.
e = 1 - 3*(4/3 - 1)
e =
2.2204e-16
x =
1.2246e-16
Round-off error is most noticeable when many operations are performed on floating-point numbers,
allowing errors to accumulate and compound. A best practice is to minimize the number of operations
whenever possible.
Cancellation
Cancellation can occur when you subtract a number from another number of roughly the same
magnitude, as measured by eps. For example, eps(2^53) is 2, so the numbers 2^53 + 1 and 2^53
have the same floating-point representation.
x = (2^53 + 1) - 2^53
x =
0
When possible, try rewriting computations in an equivalent form that avoids cancellations.
Swamping
Swamping can occur when you perform operations on floating-point numbers that differ by many
orders of magnitude. For example, this calculation shows a loss of precision that makes the addition
insignificant.
x = 1 + 1e-16
x =
1
Intermediate Conversions
When you perform arithmetic with different data types, intermediate calculations and conversions
can yield unexpected results. For example, although x and y are both 0.2, subtracting them yields a
4-12
Floating-Point Numbers
nonzero result. The reason is that y is first converted to double before the subtraction is performed.
This subtraction result is then converted to single, z.
format long
x = 0.2
x =
0.200000000000000
y = single(0.2)
y =
single
0.2000000
z = x - y
z =
single
-2.9802323e-09
Linear Algebra
Common issues in floating-point arithmetic, such as the ones described above, can compound when
applied to linear algebra problems because the related calculations typically consist of multiple steps.
For example, when solving the system of linear equations Ax = b, MATLAB warns that the results
may be inaccurate because operand matrix A is ill conditioned.
A = diag([2 eps]);
b = [2; eps];
x = A\b;
References
[1] Moler, Cleve. Numerical Computing with MATLAB. Natick, MA: The MathWorks, Inc., 2004.
See Also
Functions
double | single | flintmax | realmax | realmin | eps | isfloat
4-13
4 Numeric Classes
The following statement shows one way of creating a complex value in MATLAB. The variable x is
assigned a complex number with a real part of 2 and an imaginary part of 3:
x = 2 + 3i;
Another way to create a complex number is using the complex function. This function combines two
numeric inputs into a complex output, making the first input real and the second imaginary:
x = rand(3) * 5;
y = rand(3) * -8;
z = complex(x, y)
z =
4.7842 -1.0921i 0.8648 -1.5931i 1.2616 -2.2753i
2.6130 -0.0941i 4.8987 -2.3898i 4.3787 -3.7538i
4.4007 -7.1512i 1.3572 -5.2915i 3.6865 -0.5182i
You can separate a complex number into its real and imaginary parts using the real and imag
functions:
zr = real(z)
zr =
4.7842 0.8648 1.2616
2.6130 4.8987 4.3787
4.4007 1.3572 3.6865
zi = imag(z)
zi =
-1.0921 -1.5931 -2.2753
-0.0941 -2.3898 -3.7538
-7.1512 -5.2915 -0.5182
4-14
Infinity and NaN
Infinity
MATLAB represents infinity by the special value Inf. Infinity results from operations like division by
zero and overflow, which lead to results too large to represent as conventional floating-point values.
MATLAB also provides a function called Inf that returns the IEEE arithmetic representation for
positive infinity as a double scalar value.
Several examples of statements that return positive or negative infinity in MATLAB are shown here.
x = 1/0 x = 1.e1000
x = x =
Inf Inf
x = exp(1000) x = log(0)
x = x =
Inf -Inf
x = log(0);
isinf(x)
ans =
1
NaN
MATLAB represents values that are not real or complex numbers with a special value called NaN,
which stands for “Not a Number”. Expressions like 0/0 and inf/inf result in NaN, as do any
arithmetic operations involving a NaN:
x = 0/0
x =
NaN
x = NaN;
whos x
Name Size Bytes Class
x 1x1 8 double
The NaN function returns one of the IEEE arithmetic representations for NaN as a double scalar
value. The exact bit-wise hexadecimal representation of this NaN value is,
4-15
4 Numeric Classes
format hex
x = NaN
x =
fff8000000000000
Always use the isnan function to verify that the elements in an array are NaN:
isnan(x)
ans =
MATLAB preserves the “Not a Number” status of alternate NaN representations and treats all of the
different representations of NaN equivalently. However, in some special cases (perhaps due to
hardware limitations), MATLAB does not preserve the exact bit pattern of alternate NaN
representations throughout an entire calculation, and instead uses the canonical NaN bit pattern
defined above.
Because two NaNs are not equal to each other, logical operations involving NaN always return false,
except for a test for inequality, (NaN ~= NaN):
NaN ~= NaN
ans =
1
4-16
Identifying Numeric Classes
Command Operation
whos x Display the data type of x.
xType = class(x); Assign the data type of x to a variable.
isnumeric(x) Determine if x is a numeric type.
isa(x, 'integer') Determine if x is the specified numeric type. (Examples for any
isa(x, 'uint64') integer, unsigned 64-bit integer, any floating point, double precision,
isa(x, 'float') and single precision are shown here).
isa(x, 'double')
isa(x, 'single')
isreal(x) Determine if x is real or complex.
isnan(x) Determine if x is Not a Number (NaN).
isinf(x) Determine if x is infinite.
isfinite(x) Determine if x is finite.
4-17
4 Numeric Classes
x = 4/3
x =
1.3333
You can change the display in the Command Window or Editor using the format function.
format long
x
x =
1.333333333333333
Using the format function only sets the format for the current MATLAB session. To set the format for
subsequent sessions, click Preferences on the Home tab in the Environment section. Select
MATLAB > Command Window, and then choose a Numeric format option.
4-18
Display Format for Numeric Values
The display format only affects how numbers are displayed, not how they are stored in MATLAB.
See Also
format
Related Examples
• “Format Output”
4-19
4 Numeric Classes
Integer Arithmetic
This example shows how to perform arithmetic on integer data representing signals and images.
Load measurement datasets comprising signals from four instruments using 8 and 16-bit A-to-D's
resulting in data saved as int8, int16 and uint16. Time is stored as uint16.
load integersignal
% Look at variables
whos Signal1 Signal2 Signal3 Signal4 Time1
Plot Data
First we will plot two of the signals to see the signal ranges.
4-20
Integer Arithmetic
It is likely that these values would need to be scaled to calculate the actual physical value that the
signal represents, for example, Volts.
Process Data
We can perform standard arithmetic on integers such as +, -, *, and /. Let's say we wished to find the
sum of Signal1 and Signal2.
Now let's plot the sum signal and see where it saturates.
cla;
plot(Time1, SumSig);
hold on
Saturated = (SumSig == intmin('int8')) | (SumSig == intmax('int8')); % Find where it has saturate
plot(Time1(Saturated),SumSig(Saturated),'rd')
grid
hold off
4-21
4 Numeric Classes
Here we see the images are 24-bit color, stored as three planes of uint8 data.
Display Images
cla;
image(street1); % Display image
axis equal
axis off
4-22
Integer Arithmetic
4-23
4 Numeric Classes
Scale an Image
We can scale the image by a double precision constant but keep the image stored as integers. For
example,
duller = 0.5 * street2; % Scale image with a double constant but create an integer
whos duller
subplot(1,2,1);
image(street2);
axis off equal tight
title('Original'); % Display image
subplot(1,2,2);
image(duller);
axis off equal tight
title('Duller'); % Display image
4-24
Integer Arithmetic
We can add the two street images together and plot the ghostly result.
4-25
4 Numeric Classes
4-26
Single Precision Math
This example shows how to perform arithmetic and linear algebra with single precision data. It also
shows how the results are computed appropriately in single-precision or double-precision, depending
on the input.
Ad = [1 2 0; 2 5 -1; 4 10 -1]
Ad = 3×3
1 2 0
2 5 -1
4 10 -1
A = single(Ad); % or A = cast(Ad,'single');
We can also create single precision zeros and ones with their respective functions.
n = 1000;
Z = zeros(n,1,'single');
O = ones(n,1,'single');
whos A Ad O Z n
A 3x3 36 single
Ad 3x3 72 double
O 1000x1 4000 single
Z 1000x1 4000 single
n 1x1 8 double
We can see that some of the variables are of type single and that the variable A (the single precision
version of Ad) takes half the number of bytes of memory to store because singles require just four
bytes (32-bits), whereas doubles require 8 bytes (64-bits).
4-27
4 Numeric Classes
1 2 4
2 5 10
0 -1 -1
whos B
B 3x3 36 single
C = A * B % Matrix multiplication
5 12 24
12 30 59
24 59 117
C = A .* B % Elementwise arithmetic
1 4 0
4 25 -10
0 -10 1
5 2 -2
-2 -1 1
0 -2 1
1 0 0
0 1 0
0 0 1
1 0 0
0 1 0
0 0 1
E = eig(A) % Eigenvalues
4-28
Single Precision Math
3.7321
0.2679
1.0000
F = fft(A(:,1)) % FFT
7.0000 + 0.0000i
-2.0000 + 1.7321i
-2.0000 - 1.7321i
12.3171
0.5149
0.1577
1 -5 5 -1
3.7321
1.0000
0.2679
R = conv(P,Q)
4-29
4 Numeric Classes
Now let's look at a function to compute enough terms in the Fibonacci sequence so the ratio is less
than the correct machine epsilon (eps) for datatype single or double.
ans =
19
ans =
41
4-30
Single Precision Math
fcurrent = ones(dtype);
fnext = fcurrent;
goldenMean = (ones(dtype)+sqrt(5))/2;
tol = eps(goldenMean);
nterms = 2;
while abs(fnext/fcurrent - goldenMean) >= tol
nterms = nterms + 1;
temp = fnext;
fnext = fnext + fcurrent;
fcurrent = temp;
end
Notice that we initialize several of our variables, fcurrent, fnext, and goldenMean, with values
that are dependent on the input datatype, and the tolerance tol depends on that type as well. Single
precision requires that we calculate fewer terms than the equivalent double precision calculation.
4-31
5
This example shows how to filter the elements of an array by applying conditions to the array. For
instance, you can examine the even elements in a matrix, find the location of all 0s in a
multidimensional array, or replace NaN values in data. You can perform these tasks using a
combination of the relational and logical operators. The relational operators (>, <, >=, <=, ==, ~=)
impose conditions on the array, and you can apply multiple conditions by connecting them with the
logical operators and, or, and not, respectively denoted by the symbols &, |, and ~.
To apply a single condition, start by creating a 5-by-5 matrix that contains random integers between 1
and 15. Reset the random number generator to the default state for reproducibility.
rng("default")
A = randi(15,5)
A = 5×5
13 2 3 3 10
14 5 15 7 1
2 9 15 14 13
14 15 8 12 15
10 15 13 15 11
Use the relational less than operator, <, to determine which elements of A are less than 9. Store the
result in B.
B = A < 9
0 1 1 1 0
0 1 0 1 1
1 0 0 0 0
0 0 1 0 0
0 0 0 0 0
The result is a logical matrix. Each value in B is a logical 1 (true) or logical 0 (false) that indicates
whether the corresponding element of A fulfills the condition A < 9. For example, A(1,1) is 13, so
B(1,1) is logical 0 (false). However, A(1,2) is 2, so B(1,2) is logical 1 (true).
Although B contains information about which elements in A are less than 9, B does not tell you what
their values are. Rather than comparing the two matrices element by element, you can use B to index
into A.
A(B)
ans = 8×1
2
2
5
3
5-2
Find Array Elements That Meet Conditions
8
3
7
1
The result is a column vector of the elements in A that are less than 9. Since B is a logical matrix, this
operation is called logical indexing. In this case, the logical array being used as an index is the same
size as the array it is indexing, but this is not a requirement. For more information, see “Array
Indexing”.
Some problems require information about the locations of the array elements that meet a condition
rather than their actual values. In this example, you can use the find function to locate all of the
elements in A less than 9.
I = find(A < 9)
I = 8×1
3
6
7
11
14
16
17
22
The result is a column vector of linear indices. Each index describes the location of an element in A
that is less than 9, so in practice A(I) returns the same result as A(B). The difference is that A(B)
uses logical indexing, whereas A(I) uses linear indexing.
You can use the logical and, or, and not operators to apply any number of conditions to an array; the
number of conditions is not limited to one or two.
First, use the logical and operator, denoted &, to specify two conditions: the elements must be less
than 9 and greater than 2. Specify the conditions as a logical index to view the elements that
satisfy both conditions.
A(A<9 & A>2)
ans = 5×1
5
3
8
3
7
The result is a list of the elements in A that satisfy both conditions. Be sure to specify each condition
with a separate statement connected by a logical operator. For example, you cannot specify the
conditions above using A(2<A<9) because it evaluates to A(2<A | A<9).
Next, find the elements in A that are less than 9 and even.
5-3
5 The Logical Class
ans = 3×1
2
2
8
The result is a list of all even elements in A that are less than 9. The use of the logical not operator,
~, converts the matrix mod(A,2) into a logical matrix, with a value of logical 1 (true) located where
an element is divisible by 2 or even.
Finally, find the elements in A that are less than 9 and even and not equal to 2.
A(A<9 & ~mod(A,2) & A~=2)
ans =
8
The result, 8, is less than 9, even, and not equal to 2. It is the only element in A that satisfies all three
conditions.
Use the find function to get the index of the element equal to 8 that satisfies the conditions.
find(A<9 & ~mod(A,2) & A~=2)
ans =
14
Sometimes it is useful to simultaneously change the values of several existing array elements. Use
logical indexing with a simple assignment statement to replace the values in an array that meet a
condition.
For example, replace all values in A that are greater than 10 with the number 10.
A(A>10) = 10
A = 5×5
10 2 3 3 10
10 5 10 7 1
2 9 10 10 10
10 10 8 10 10
10 10 10 10 10
Next, replace all values in A that are not equal to 10 with a NaN value.
A(A~=10) = NaN
A = 5×5
5-4
Find Array Elements That Meet Conditions
NaN NaN 10 10 10
10 10 NaN 10 10
10 10 10 10 10
Lastly, replace all of the NaN values in A with zeros and apply the logical not operator on A, ~A.
A(isnan(A)) = 0;
C = ~A
0 1 1 1 0
0 1 0 1 1
1 1 0 0 0
0 0 1 0 0
0 0 0 0 0
The resulting matrix has values of logical 1 (true) in place of the NaN values, and logical 0 (false)
in place of the 10s. The logical not operation, ~A, converts the numeric array A into a logical array C
such that A&C returns a matrix of logical 0 (false) values and A|C returns a matrix of logical 1
(true) values.
See Also
nan | Short-Circuit AND | Short-Circuit OR | isnan | find | and | or | xor | not
5-5
5 The Logical Class
This example shows how to use the any and all functions to reduce an entire array to a single
logical value.
The any and all functions are natural extensions of the logical | (OR) and & (AND) operators,
respectively. However, rather than comparing just two elements, the any and all functions compare
all of the elements in a particular dimension of an array. It is as if all of those elements are connected
by & or | operators and the any or all functions evaluate the resulting long logical expressions.
Therefore, unlike the core logical operators, the any and all functions reduce the size of the array
dimension that they operate on so that it has size 1. This enables the reduction of many logical values
into a single logical condition.
First, create a matrix A that contains random integers between 1 and 25. Reset the random number
generator to the default state for reproducibility.
rng default
A = randi(25,5)
A = 5×5
21 3 4 4 17
23 7 25 11 1
4 14 24 23 22
23 24 13 20 24
16 25 21 24 17
Next, use the mod function along with the logical NOT operator, ~, to determine which elements in A
are even.
A = ~mod(A,2)
0 0 1 1 0
0 0 0 0 0
1 1 1 0 1
0 1 0 1 1
1 0 0 1 0
The resulting matrices have values of logical 1 (true) where an element is even, and logical 0
(false) where an element is odd.
Since the any and all functions reduce the dimension that they operate on to size 1, it normally
takes two applications of one of the functions to reduce a 2–D matrix into a single logical condition,
such as any(any(A)). However, if you use the notation A(:) to regard all of the elements of A as a
single column vector, you can use any(A(:)) to get the same logical information without nesting the
function calls.
any(A(:))
5-6
Reduce Logical Arrays to Single Value
ans = logical
1
You can perform logical and relational comparisons within the function call to any or all. This makes
it easy to quickly test an array for a variety of properties.
all(~A(:))
ans = logical
0
Determine whether any main or super diagonal elements in A are even. Since the vectors returned by
diag(A) and diag(A,1) are not the same size, you first need to reduce each diagonal to a single
scalar logical condition before comparing them. You can use the short-circuit OR operator || to
perform the comparison, since if any elements in the first diagonal are even then the entire
expression evaluates to true regardless of what appears on the right-hand side of the operator.
any(diag(A)) || any(diag(A,1))
ans = logical
1
See Also
any | all | and | or | xor | Short-Circuit AND | Short-Circuit OR
5-7
6
There are two ways to represent text in MATLAB®. You can store text in string arrays and in
character vectors. MATLAB displays strings with double quotes and character vectors with single
quotes.
You can store any 1-by-n sequence of characters as a string, using the string data type. Enclose text
in double quotes to create a string.
str =
"Hello, world"
Though the text "Hello, world" is 12 characters long, str itself is a 1-by-1 string, or string scalar.
You can use a string scalar to specify a file name, plot label, or any other piece of textual information.
n = strlength(str)
n =
12
If the text includes double quotes, use two double quotes within the definition.
str =
"They said, "Welcome!" and waved."
To add text to the end of a string, use the plus operator, +. If a variable can be converted to a string,
then plus converts it and appends it.
fahrenheit = 71;
celsius = (fahrenheit-32)/1.8;
tempText = "temperature is " + celsius + "C"
tempText =
"temperature is 21.6667C"
tempText2 =
"Today's temperature is 21.6667C"
The string function can convert different types of inputs, such as numeric, datetime, duration, and
categorical values. For example, convert the output of pi to a string.
ps = string(pi)
ps =
"3.1416"
6-2
Text in String and Character Arrays
You can store multiple pieces of text in a string array. Each element of the array can contain a string
having a different number of characters, without padding.
str = ["Mercury","Gemini","Apollo";...
"Skylab","Skylab B","ISS"]
str is a 2-by-3 string array. You can find the lengths of the strings with the strlength function.
N = strlength(str)
N = 2×3
7 6 6
6 8 3
String arrays are supported throughout MATLAB and MathWorks® products. Functions that accept
character arrays (and cell arrays of character vectors) as inputs also accept string arrays.
To store a 1-by-n sequence of characters as a character vector, using the char data type, enclose it in
single quotes.
chr =
'Hello, world'
The text 'Hello, world' is 12 characters long, and chr stores it as a 1-by-12 character vector.
whos chr
If the text includes single quotes, use two single quotes within the definition.
chr =
'They said, 'Welcome!' and waved.'
• To specify single pieces of text, such as file names and plot labels.
• To represent data that is encoded using characters. In such cases, you might need easy access to
individual characters.
seq = 'GCTAGAATCC';
6-3
6 Characters and Strings
You can access individual characters or subsets of characters by indexing, just as you would index
into a numeric array.
seq(4:6)
ans =
'AGA'
Concatenate character vector with square brackets, just as you concatenate other types of arrays.
seq2 =
'GCTAGAATCCATTAGAAACC'
You can also concatenate text using append. The append function is recommended because it treats
string arrays, character vectors, and cell arrays of character vectors consistently.
seq2 = append(seq,'ATTAGAAACC')
seq2 =
'GCTAGAATCCATTAGAAACC'
MATLAB functions that accept string arrays as inputs also accept character vectors and cell arrays of
character vectors.
See Also
string | char | cellstr | strlength | plus | horzcat | append
Related Examples
• “Create String Arrays” on page 6-5
• “Analyze Text Data with String Arrays” on page 6-15
• “Frequently Asked Questions About String Arrays” on page 6-58
• “Update Your Code to Accept Strings” on page 6-63
• “Cell Arrays of Character Vectors” on page 6-12
6-4
Create String Arrays
String arrays store pieces of text and provide a set of functions for working with text as data. You can
index into, reshape, and concatenate strings arrays just as you can with arrays of any other type. You
also can access the characters in a string and append text to strings using the plus operator. To
rearrange strings within a string array, use functions such as split, join, and sort.
MATLAB® provides string arrays to store pieces of text. Each element of a string array contains a 1-
by-n sequence of characters.
str =
"Hello, world"
As an alternative, you can convert a character vector to a string using the string function. chr is a
1-by-17 character vector. str is a 1-by-1 string that has the same text as the character vector.
chr = 'Greetings, friend'
chr =
'Greetings, friend'
str = string(chr)
str =
"Greetings, friend"
Create a string array containing multiple strings using the [] operator. str is a 2-by-3 string array
that contains six strings.
str = ["Mercury","Gemini","Apollo";
"Skylab","Skylab B","ISS"]
Find the length of each string in str with the strlength function. Use strlength, not length, to
determine the number of characters in strings.
L = strlength(str)
L = 2×3
7 6 6
6 8 3
As an alternative, you can convert a cell array of character vectors to a string array using the string
function. MATLAB displays strings in string arrays with double quotes, and displays characters
vectors in cell arrays with single quotes.
6-5
6 Characters and Strings
C = {'Mercury','Venus','Earth'}
C = 1x3 cell
{'Mercury'} {'Venus'} {'Earth'}
str = string(C)
In addition to character vectors, you can convert numeric, datetime, duration, and categorical values
to strings using the string function.
ans =
"23-Jan-2025 01:02:34"
Also, you can read text from files into string arrays using the readtable, textscan, and fscanf
functions.
String arrays can contain both empty and missing values. An empty string contains zero characters.
When you display an empty string, the result is a pair of double quotes with nothing between them
(""). The missing string is the string equivalent to NaN for numeric arrays. It indicates where a string
array has missing values. When you display a missing string, the result is <missing>, with no
quotation marks.
Create an empty string array using the strings function. When you call strings with no
arguments, it returns an empty string. Note that the size of str is 1-by-1, not 0-by-0. However, str
contains zero characters.
str = strings
str =
""
Create an empty character vector using single quotes. Note that the size of chr is 0-by-0.
chr = ''
chr =
6-6
Create String Arrays
Create a string array where every element is an empty string. You can preallocate a string array with
the strings function.
str = strings(2,3)
To create a missing string, convert a missing value using the string function. The missing string
displays as <missing>.
str = string(missing)
str =
<missing>
You can create a string array with both empty and missing strings. Use the ismissing function to
determine which elements are strings with missing values. Note that the empty string is not a
missing string.
str(1) = "";
str(2) = "Gemini";
str(3) = string(missing)
ismissing(str)
0 0 1
Compare a missing string to another string. The result is always 0 (false), even when you compare a
missing string to another missing string.
str = string(missing);
str == "Gemini"
ans = logical
0
str == string(missing)
ans = logical
0
String arrays support array operations such as indexing and reshaping. Use array indexing to access
the first row of str and all the columns.
6-7
6 Characters and Strings
str = ["Mercury","Gemini","Apollo";
"Skylab","Skylab B","ISS"];
str(1,:)
str(2,2)
ans =
"Skylab B"
Assign a new string outside the bounds of str. MATLAB expands the array and fills unallocated
elements with missing values.
str(3,4) = "Mir"
You can index into a string array using curly braces, {}, to access characters directly. Use curly
braces when you need to access and modify characters within a string element. Indexing with curly
braces provides compatibility for code that could work with either string arrays or cell arrays of
character vectors. But whenever possible, use string functions to work with the characters in strings.
Access the second element in the second row with curly braces. chr is a character vector, not a
string.
str = ["Mercury","Gemini","Apollo";
"Skylab","Skylab B","ISS"];
chr = str{2,2}
chr =
'Skylab B'
Access the character vector and return the first three characters.
str{2,2}(1:3)
ans =
'Sky'
Find the space characters in a string and replace them with dashes. Use the isspace function to
inspect individual characters within the string. isspace returns a logical vector that contains a true
value wherever there is a space character. Finally, display the modified string element, str(2,2).
TF = isspace(str{2,2})
6-8
Create String Arrays
0 0 0 0 0 0 1 0
str{2,2}(TF) = "-";
str(2,2)
ans =
"Skylab-B"
Note that in this case, you can also replace spaces using the replace function, without resorting to
curly brace indexing.
replace(str(2,2)," ","-")
ans =
"Skylab-B"
Concatenate strings into a string array just as you would concatenate arrays of any other kind.
Transpose str1 and str2. Concatenate them and then vertically concatenate column headings onto
the string array. When you concatenate character vectors into a string array, the character vectors
are automatically converted to strings.
str1 = str1';
str2 = str2';
str = [str1 str2];
str = [["Mission:","Station:"] ; str]
To append text to strings, use the plus operator, +. The plus operator appends text to strings but
does not change the size of a string array.
Append a last name to an array of names. If you append a character vector to strings, then the
character vector is automatically converted to a string.
names = ["Mary";"John";"Elizabeth";"Paul";"Ann"];
names = names + ' Smith'
6-9
6 Characters and Strings
"John Smith"
"Elizabeth Smith"
"Paul Smith"
"Ann Smith"
Append different last names. You can append text to a string array from a string array or from a cell
array of character vectors. When you add nonscalar arrays, they must be the same size.
names = ["Mary";"John";"Elizabeth";"Paul";"Ann"];
lastnames = ["Jones";"Adams";"Young";"Burns";"Spencer"];
names = names + " " + lastnames
Append a missing string. When you append a missing string with the plus operator, the output is a
missing string.
str1 = "Jones";
str2 = string(missing);
str1 + str2
ans =
<missing>
MATLAB provides a rich set of functions to work with string arrays. For example, you can use the
split, join, and sort functions to rearrange the string array names so that the names are in
alphabetical order by last name.
Split names on the space characters. Splitting changes names from a 5-by-1 string array to a 5-by-2
array.
names = ["Mary Jones";"John Adams";"Elizabeth Young";"Paul Burns";"Ann Spencer"];
names = split(names)
Switch the columns of names so that the last names are in the first column. Add a comma after each
last name.
names = [names(:,2) names(:,1)];
names(:,1) = names(:,1) + ','
6-10
Create String Arrays
"Adams," "John"
"Young," "Elizabeth"
"Burns," "Paul"
"Spencer," "Ann"
Join the last and first names. The join function places a space character between the strings it joins.
After the join, names is a 5-by-1 string array.
names = join(names)
names = sort(names)
See Also
string | strings | strlength | ismissing | isspace | plus | split | join | sort
Related Examples
• “Analyze Text Data with String Arrays” on page 6-15
• “Search and Replace Text” on page 6-37
• “Compare Text” on page 6-32
• “Test for Empty Strings and Missing Values” on page 6-20
• “Frequently Asked Questions About String Arrays” on page 6-58
• “Update Your Code to Accept Strings” on page 6-63
6-11
6 Characters and Strings
To store text as a character vector, enclose it single quotes. Typically, a character vector has text that
you consider to be a single piece of information, such as a file name or a label for a plot. If you have
many pieces of text, such as a list of file names, then you can store them in a cell array. A cell array
whose elements are all character vectors is a cell array of character vectors.
Note
• The recommended way to store text is to use string arrays. If you create variables that have the
string data type, store them in string arrays, not cell arrays. For more information, see “Text in
String and Character Arrays” on page 6-2 and “Update Your Code to Accept Strings” on page 6-
63.
• While the phrase cell array of strings frequently has been used to describe such cell arrays, the
phrase is no longer accurate because such a cell array holds character vectors, not strings.
To create a cell array of character vectors, use curly braces, {}, just as you would to create any cell
array. For example, use a cell array of character vectors to store a list of names.
C = {'Li','Sanchez','Jones','Yang','Larson'}
C = 1x5 cell
{'Li'} {'Sanchez'} {'Jones'} {'Yang'} {'Larson'}
The character vectors in C can have different lengths because a cell array does not require that its
contents have the same size. To determine the lengths of the character vectors in C, use the
strlength function.
L = strlength(C)
L = 1×5
2 7 5 4 6
To access character vectors in a cell array, index into it using curly braces, {}. Extract the contents of
the first cell and store it as a character vector.
C = {'Li','Sanchez','Jones','Yang','Larson'};
chr = C{1}
chr =
'Li'
6-12
Cell Arrays of Character Vectors
C{1} = 'Yang'
C = 1x5 cell
{'Yang'} {'Sanchez'} {'Jones'} {'Yang'} {'Larson'}
To refer to a subset of cells, instead of their contents, index using smooth parentheses.
C(1:3)
While you can access the contents of cells by indexing, most functions that accept cell arrays as
inputs operate on the entire cell array. For example, you can use the strcmp function to compare the
contents of C to a character vector. strcmp returns 1 where there is a match and 0 otherwise.
TF = strcmp(C,'Yang')
1 0 0 1 0
num = sum(TF)
num =
2
Use TF as logical indices to return the matches in C. If you index using smooth parentheses, then the
output is a cell array containing only the matches.
M = C(TF)
M = 1x2 cell
{'Yang'} {'Yang'}
String arrays are supported throughout MATLAB® and MathWorks® products. Therefore it is
recommended that you use string arrays instead of cell arrays of character vectors. (However,
MATLAB functions that accept string arrays as inputs do accept character vectors and cell arrays of
character vectors as well.)
You can convert cell arrays of character vectors to string arrays. To convert a cell array of character
vectors, use the string function.
C = {'Li','Sanchez','Jones','Yang','Larson'}
6-13
6 Characters and Strings
C = 1x5 cell
{'Li'} {'Sanchez'} {'Jones'} {'Yang'} {'Larson'}
str = string(C)
In fact, the string function converts any cell array, so long as all of the contents can be converted to
strings.
str2 = string(C2)
See Also
cellstr | char | iscellstr | strcmp | string
More About
• “Text in String and Character Arrays” on page 6-2
• “Access Data in Cell Array” on page 12-4
• “Create String Arrays” on page 6-5
• “Update Your Code to Accept Strings” on page 6-63
• “Frequently Asked Questions About String Arrays” on page 6-58
6-14
Analyze Text Data with String Arrays
This example shows how to store text from a file as a string array, sort the words by their frequency,
plot the result, and collect basic statistics for the words found in the file.
Read text from Shakespeare's Sonnets with the fileread function. fileread returns the text as a
1-by-100266 character vector.
sonnets = fileread('sonnets.txt');
sonnets(1:35)
ans =
'THE SONNETS
by William Shakespeare'
Convert the text to a string using the string function. Then, split it on newline characters using the
splitlines function. sonnets becomes a 2625-by-1 string array, where each string contains one
line from the poems. Display the first five lines of sonnets.
sonnets = string(sonnets);
sonnets = splitlines(sonnets);
sonnets(1:5)
To calculate the frequency of the words in sonnets, first clean it by removing empty strings and
punctuation marks. Then reshape it into a string array that contains individual words as elements.
Remove the strings with zero characters ("") from the string array. Compare each element of
sonnets to "", the empty string. You can create strings, including an empty string, using double
quotes. TF is a logical vector that contains a true value wherever sonnets contains a string with zero
characters. Index into sonnets with TF and delete all strings with zero characters.
TF = (sonnets == "");
sonnets(TF) = [];
sonnets(1:10)
6-15
6 Characters and Strings
Replace some punctuation marks with space characters. For example, replace periods, commas, and
semi-colons. Keep apostrophes because they can be part of some words in the Sonnets, such as
light's.
p = [".","?","!",",",";",":"];
sonnets = replace(sonnets,p," ");
sonnets(1:10)
Strip leading and trailing space characters from each element of sonnets.
sonnets = strip(sonnets);
sonnets(1:10)
Split sonnets into a string array whose elements are individual words. You can use the split
function to split elements of a string array on whitespace characters, or on delimiters that you
specify. However, split requires that every element of a string array must be divisible into an equal
number of new strings. The elements of sonnets have different numbers of spaces, and therefore are
not divisible into equal numbers of strings. To use the split function on sonnets, write a for-loop
that calls split on one element at a time.
Create the empty string array sonnetWords using the strings function. Write a for-loop that splits
each element of sonnets using the split function. Concatenate the output from split onto
sonnetWords. Each element of sonnetWords is an individual word from sonnets.
sonnetWords = strings(0);
for i = 1:length(sonnets)
6-16
Analyze Text Data with String Arrays
Find the unique words in sonnetWords. Count them and sort them based on their frequency.
To count words that differ only by case as the same word, convert sonnetWords to lowercase. For
example, The and the count as the same word. Find the unique words using the unique function.
Then, count the number of times each unique word occurs using the histcounts function.
sonnetWords = lower(sonnetWords);
[words,~,idx] = unique(sonnetWords);
numOccurrences = histcounts(idx,numel(words));
Sort the words in sonnetWords by number of occurrences, from most to least common.
[rankOfOccurrences,rankIndex] = sort(numOccurrences,'descend');
wordsByFrequency = words(rankIndex);
Plot the occurrences of words in the Sonnets from the most to least common words. Zipf's Law states
that the distribution of occurrences of words in a large body text follows a power-law distribution.
loglog(rankOfOccurrences);
xlabel('Rank of word (most to least common)');
ylabel('Number of Occurrences');
6-17
6 Characters and Strings
Calculate the total number of occurrences of each word in sonnetWords. Calculate the number of
occurrences as a percentage of the total number of words, and calculate the cumulative percentage
from most to least common. Write the words and the basic statistics for them to a table.
numOccurrences = numOccurrences(rankIndex);
numOccurrences = numOccurrences';
numWords = length(sonnetWords);
T = table;
T.Words = wordsByFrequency;
6-18
Analyze Text Data with String Arrays
T.NumOccurrences = numOccurrences;
T.PercentOfText = numOccurrences / numWords * 100.0;
T.CumulativePercentOfText = cumsum(numOccurrences) / numWords * 100.0;
T(1:10,:)
ans=10×4 table
Words NumOccurrences PercentOfText CumulativePercentOfText
______ ______________ _____________ _______________________
The most common word in the Sonnets, and, occurs 490 times. Together, the ten most common words
account for 20.163% of the text.
See Also
string | split | join | unique | replace | lower | splitlines | histcounts | strip | sort |
table
Related Examples
• “Create String Arrays” on page 6-5
• “Search and Replace Text” on page 6-37
• “Compare Text” on page 6-32
• “Test for Empty Strings and Missing Values” on page 6-20
6-19
6 Characters and Strings
String arrays can contain both empty strings and missing values. Empty strings contain zero
characters and display as double quotes with nothing between them (""). You can determine if a
string is an empty string using the == operator. The empty string is a substring of every other string.
Therefore, functions such as contains always find the empty string within other strings. String
arrays also can contain missing values. Missing values in string arrays display as <missing>. To find
missing values in a string array, use the ismissing function instead of the == operator.
You can test a string array for empty strings using the == operator.
You can create an empty string using double quotes with nothing between them (""). Note that the
size of str is 1-by-1, not 0-by-0. However, str contains zero characters.
str = ""
str =
""
Create an empty character vector using single quotes. Note that the size of chr is 0-by-0. The
character array chr actually is an empty array, and not just an array with zero characters.
chr = ''
chr =
Create an array of empty strings using the strings function. Each element of the array is a string
with no characters.
str2 = strings(1,3)
if (str == "")
disp 'str has zero characters'
end
Do not use the isempty function to test for empty strings. A string with zero characters still has a
size of 1-by-1. However, you can test if a string array has at least one dimension with a size of zero
using the isempty function.
Create an empty string array using the strings function. To be an empty array, at least one
dimension must have a size of zero.
str = strings(0,3)
6-20
Test for Empty Strings and Missing Values
str =
isempty(str)
ans = logical
1
Test a string array for empty strings. The == operator returns a logical array that is the same size as
the string array.
str = ["Mercury","","Apollo"]
str == ''
0 1 0
Strings always contain the empty string as a substring. In fact, the empty string is always at both the
start and the end of every string. Also, the empty string is always found between any two consecutive
characters in a string.
TF = logical
1
TF = startsWith(str,"")
TF = logical
1
Count the number of characters in str. Then count the number of empty strings in str. The count
function counts empty strings at the beginning and end of str, and between each pair of characters.
Therefore if str has N characters, it also has N+1 empty strings.
str
str =
"Hello, world"
6-21
6 Characters and Strings
strlength(str)
ans =
12
count(str,"")
ans =
13
Replace a substring with the empty string. When you call replace with an empty string, it removes
the substring and replaces it with a string that has zero characters.
replace(str,"world","")
ans =
"Hello, "
Insert a substring after empty strings using the insertAfter function. Because there are empty
strings between each pair of characters, insertAfter inserts substrings between each pair.
insertAfter(str,"","-")
ans =
"-H-e-l-l-o-,- -w-o-r-l-d-"
In general, string functions that replace, erase, extract, or insert substrings allow you to specify
empty strings as the starts and ends of the substrings to modify. When you do so, these functions
operate on the start and end of the string, and between every pair of characters.
You can test a string array for missing values using the ismissing function. The missing string is the
string equivalent to NaN for numeric arrays. It indicates where a string array has missing values. The
missing string displays as <missing>.
To create a missing string, convert a missing value using the string function.
str = string(missing)
str =
<missing>
You can create a string array with both empty and missing strings. Use the ismissing function to
determine which elements are strings with missing values. Note that the empty string is not a
missing string.
str(1) = "";
str(2) = "Gemini";
str(3) = string(missing)
ismissing(str)
6-22
Test for Empty Strings and Missing Values
0 0 1
Compare str to a missing string. The comparison is always 0 (false), even when you compare a
missing string to another missing string.
str == string(missing)
0 0 0
To find missing strings, use the ismissing function. Do not use the == operator.
See Also
string | strings | strlength | ismissing | contains | startsWith | endsWith | erase |
extractBetween | extractBefore | extractAfter | insertAfter | insertBefore | replace |
replaceBetween | eraseBetween | eq | all | any
Related Examples
• “Create String Arrays” on page 6-5
• “Analyze Text Data with String Arrays” on page 6-15
• “Search and Replace Text” on page 6-37
• “Compare Text” on page 6-32
6-23
6 Characters and Strings
Formatting Text
To convert data to text and control its format, you can use formatting operators with common
conversion functions, such as num2str and sprintf. These operators control notation, alignment,
significant digits, and so on. They are similar to those used by the printf function in the C
programming language. Typical uses for formatted text include text for display and output files.
For example, %f converts floating-point values to text using fixed-point notation. Adjust the format by
adding information to the operator, such as %.2f to represent two digits after the decimal mark, or
%12f to represent 12 characters in the output, padding with spaces as needed.
A = pi*ones(1,3);
txt = sprintf('%f | %.2f | %12f', A)
txt =
'3.141593 | 3.14 | 3.141593'
You can combine operators with ordinary text and special characters in a format specifier. For
instance, \n inserts a newline character.
txt =
'Displaying pi:
3.141593
3.14
3.141593'
Functions that support formatting operators are compose, num2str, sprintf, fprintf, and the
error handling functions assert, error, warning, and MException.
Conversion Character
The conversion character specifies the notation of the output. It consists of a single character and
appears last in the format specifier.
Specifier Description
c Single character.
6-24
Formatting Text
Specifier Description
d Decimal notation (signed).
e Exponential notation (using a lowercase e, as in 3.1415e+00).
E Exponential notation (using an uppercase E, as in 3.1415E+00).
f Fixed-point notation.
g The more compact of %e or %f. (Insignificant zeroes do not print.)
G Same as %g, but using an uppercase E.
o Octal notation (unsigned).
s Character vector or string array.
u Decimal notation (unsigned).
x Hexadecimal notation (unsigned, using lowercase letters a–f).
X Hexadecimal notation (unsigned, using uppercase letters A–F).
For example, format the number 46 using different conversion characters to display the number in
decimal, fixed-point, exponential, and hexadecimal formats.
A = 46*ones(1,4);
txt = sprintf('%d %f %e %X', A)
txt =
'46 46.000000 4.600000e+01 2E'
Subtype
The subtype field is a single alphabetic character that immediately precedes the conversion
character. Without the subtype field, the conversion characters %o, %x, %X, and %u treat input data as
integers. To treat input data as floating-point values instead and convert them to octal, decimal, or
hexadecimal representations, use one of following subtype specifiers.
b The input data are double-precision floating-point values rather than unsigned integers. For
example, to print a double-precision value in hexadecimal, use a format like %bx.
t The input data are single-precision floating-point values rather than unsigned integers.
Precision
The precision field in a formatting operator is a nonnegative integer that immediately follows a
period. For example, in the operator %7.3f, the precision is 3. For the %g operator, the precision
indicates the number of significant digits to display. For the %f, %e, and %E operators, the precision
indicates how many digits to display to the right of the decimal point.
txt =
While you can specify the precision in a formatting operator for input text (for example, in the %s
operator), there is usually no reason to do so. If you specify the precision as p, and p is less than the
number of characters in the input text, then the output contains only the first p characters.
6-25
6 Characters and Strings
Field Width
The field width in a formatting operator is a nonnegative integer that specifies the number of digits or
characters in the output when formatting input values. For example, in the operator %7.3f, the field
width is 7.
Specify different field widths. To show the width for each output, use the | character. By default, the
output text is padded with space characters when the field width is greater than the number of
characters.
txt =
When used on text input, the field width can determine whether to pad the output text with spaces. If
the field width is less than or equal to the number of characters in the input text, then it has no effect.
txt =
Flags
Optional flags control additional formatting of the output text. The table describes the characters you
can use as flags.
Right- and left-justify the output. The default behavior is to right-justify the output text.
6-26
Formatting Text
txt =
'right-justify: 12.30
left-justify: 12.30 '
Display a + sign for positive numbers. The default behavior is to omit the leading + sign for positive
numbers.
txt =
Pad to the left with spaces and zeroes. The default behavior is to pad with spaces.
txt =
Note You can specify more than one flag in a formatting operator.
Value Identifiers
By default, functions such as sprintf insert values from input arguments into the output text in
sequential order. To process the input arguments in a nonsequential order, specify the order using
numeric identifiers in the format specifier. Specify nonsequential arguments with an integer
immediately following the % sign, followed by a $ sign.
ans = ans =
Special Characters
Special characters can be part of the output text. But because they cannot be entered as ordinary
text, they require specific character sequences to represent them. To insert special characters into
output text, use any of the character sequences in the table.
6-27
6 Characters and Strings
The figure illustrates how the field width and precision settings affect the output of the formatting
functions. In this figure, the zero following the % sign in the formatting operator means to add leading
zeroes to the output text rather than space characters.
6-28
Formatting Text
• If the field width is not specified, then it defaults to p+1+n, where n is the number of digits in the
whole part of the input value.
• If the field width w is greater than p+1+n, then the whole part of the output value is padded to the
left with w-(p+1+n) additional characters. The additional characters are space characters unless
the formatting operator includes the 0 flag. In that case, the additional characters are zeroes.
You can specify the field width and precision using values from a sequential argument list. Use an
asterisk (*) in place of the field width or precision fields of the formatting operator.
For example, format and display three numbers. In each case, use an asterisk to specify that the field
width or precision come from input arguments that follow the format specifier.
txt =
The table describes the effects of each formatting operator in the example.
You can mix the two styles. For example, get the field width from the following input argument and
the precision from the format specifier.
txt =
'123.46'
You also can specify field width and precision as values from a nonsequential argument list, using an
alternate syntax shown in the figure. Within the formatting operator, specify the field width and
precision with asterisks that follow numbered identifiers and $ signs. Specify the values of the field
width and precision with input arguments that follow the format specifier.
6-29
6 Characters and Strings
For example, format and display three numbers. In each case, use a numbered identifier to specify
that the field width or precision come from input arguments that follow the format specifier.
txt =
The table describes the effect of each formatting operator in the example.
ans = ans =
If your function call provides more input arguments than there are formatting operators in the format
specifier, then the operators are reused. However, only function calls that use sequential ordering
reuse formatting operators. You cannot reuse formatting operators when you use numbered
identifiers.
6-30
Formatting Text
ans = ans =
'1234' '1'
If you use numbered identifiers when the input data is a vector or array, then the output does not
contain formatted data.
ans = ans =
See Also
compose | sprintf | fprintf | num2str
Related Examples
• “Convert Text to Numeric Values” on page 6-48
• “Convert Numeric Values to Text” on page 6-45
External Websites
• Programming: Organizing Data (MathWorks Teaching Resources)
6-31
6 Characters and Strings
Compare Text
Compare text in character arrays and string arrays in different ways. You can compare string arrays
and character vectors with relational operators and with the strcmp function. You can sort string
arrays using the sort function, just as you would sort arrays of any other type. MATLAB® also
provides functions to inspect characters in pieces of text. For example, you can determine which
characters in a character vector or string array are letters or space characters.
You can compare string arrays for equality with the relational operators == and ~=. When you
compare string arrays, the output is a logical array that has 1 where the relation is true, and 0 where
it is not true.
Create two string scalars. You can create strings using double quotes.
str1 = "Hello";
str2 = "World";
str1,str2
str1 =
"Hello"
str2 =
"World"
str1 == str2
ans = logical
0
str1 = ["Mercury","Gemini","Apollo";...
"Skylab","Skylab B","International Space Station"];
str2 = "Apollo";
str1 == str2
0 0 1
0 0 0
Compare a string array to a character vector. As long as one of the variables is a string array, you can
make the comparison.
chr = 'Gemini';
TF = (str1 == chr)
0 1 0
6-32
Compare Text
0 0 0
Index into str1 with TF to extract the string elements that matched Gemini. You can use logical
arrays to index into an array.
str1(TF)
ans =
"Gemini"
Compare for inequality using the ~= operator. Index into str1 to extract the elements that do not
match 'Gemini'.
TF = (str1 ~= chr)
1 0 1
1 1 1
str1(TF)
Compare two nonscalar string arrays. When you compare two nonscalar arrays, they must be the
same size.
str2 = ["Mercury","Mars","Apollo";...
"Jupiter","Saturn","Neptune"];
TF = (str1 == str2)
1 0 1
0 0 0
str1(TF)
You can also compare strings with the relational operators >, >=, <, and <=. Strings that start with
uppercase letters come before strings that start with lowercase letters. For example, the string
"ABC" is less than "abc". Digits and some punctuation marks also come before letters.
6-33
6 Characters and Strings
ans = logical
1
Compare a string array that contains names to another name with the > operator. The names
Sanchez, de Ponte, and Nash come after Matthews, because S, d, and N all are greater than M.
1 0 1 0 1
str(TF)
You can sort string arrays. MATLAB® stores characters as Unicode® using the UTF-16 character
encoding scheme. Character and string arrays are sorted according to the UTF-16 code point order.
For the characters that are also the ASCII characters, this order means that uppercase letters come
before lowercase letters. Digits and some punctuation also come before letters.
sort(str)
Sort a 2-by-3 string array. The sort function sorts the elements in each column separately.
sort(str2)
To sort the elements in each row, sort str2 along the second dimension.
sort(str2,2)
6-34
Compare Text
You can compare character vectors and cell arrays of character vectors to each other. Use the
strcmp function to compare two character vectors, or strncmp to compare the first N characters.
You also can use strcmpi and strncmpi for case-insensitive comparisons.
Compare two character vectors with the strcmp function. chr1 and chr2 are not equal.
chr1 = 'hello';
chr2 = 'help';
TF = strcmp(chr1,chr2)
TF = logical
0
Note that the MATLAB strcmp differs from the C version of strcmp. The C version of strcmp
returns 0 when two character arrays are the same, not when they are different.
Compare the first two characters with the strncmp function. TF is 1 because both character vectors
start with the characters he.
TF = strncmp(chr1,chr2,2)
TF = logical
1
Compare two cell arrays of character vectors. strcmp returns a logical array that is the same size as
the cell arrays.
1
0
0
You can inspect the characters in string arrays or character arrays with the isstrprop, isletter,
and isspace functions.
Determine which characters in a character vector are space characters. isspace returns a logical
vector that is the same size as chr.
6-35
6 Characters and Strings
0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0
The isstrprop function can query characters for many different traits. isstrprop can determine
whether characters in a string or character vector are letters, alphanumeric characters, decimal or
hexadecimal digits, or punctuation characters.
Determine which characters in a string are punctuation marks. isstrprop returns a logical vector
whose length is equal to the number of characters in str.
str =
"A horse! A horse! My kingdom for a horse!"
isstrprop(str,"punct")
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
isstrprop(chr,"alpha")
1 1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1
See Also
strcmp | sort | isstrprop | isletter | isspace | eq | ne | gt | ge | le | lt
Related Examples
• “Text in String and Character Arrays” on page 6-2
• “Create String Arrays” on page 6-5
• “Analyze Text Data with String Arrays” on page 6-15
• “Search and Replace Text” on page 6-37
• “Test for Empty Strings and Missing Values” on page 6-20
6-36
Search and Replace Text
Processing text data often involves finding and replacing substrings. There are several functions that
find text and return different information: some functions confirm that the text exists, while others
count occurrences, find starting indices, or extract substrings. These functions work on character
vectors and string scalars, such as "yes", as well as character and string arrays, such as
["yes","no";"abc","xyz"]. In addition, you can use patterns to define rules for searching, such as
one or more letter or digit characters.
To determine if text is present, use a function that returns logical values, like contains,
startsWith, or endsWith. Logical values of 1 correspond to true, and 0 corresponds to false.
TF = logical
1
Calculate how many times the text occurs using the count function.
n = count(txt,"sea")
n =
2
To locate where the text occurs, use the strfind function, which returns starting indices.
idx = strfind(txt,"sea")
idx = 1×2
11 28
Find and extract text using extraction functions, such as extract, extractBetween,
extractBefore, or extractAfter.
mid = extractBetween(txt,"sea","shore")
mid =
"shells by the sea"
mid = extractBetween(txt,"sea","shore","Boundaries","inclusive")
mid =
"seashells by the seashore"
The search and replacement functions can also find text in multi-element arrays. For example, look
for color names in several song titles.
6-37
6 Characters and Strings
colors =["Red","Yellow","Blue","Black","White"];
TF = contains(songs,colors)
1
0
1
To list the songs that contain color names, use the logical TF array as indices into the original songs
array. This technique is called logical indexing.
colorful = songs(TF)
Use the function replace to replace text in songs that matches elements of colors with the string
"Orange".
replace(songs,colors,"Orange")
Match Patterns
Since R2020b
In addition to searching for literal text, like “sea” or “yellow”, you can search for text that matches a
pattern. There are many predefined patterns, such as digitsPattern to find numeric digits.
address = "123a Sesame Street, New York, NY 10128";
nums = extract(address,digitsPattern)
For additional precision in searches, you can combine patterns. For example, locate words that start
with the character “S”. Use a string to specify the “S” character, and lettersPattern to find
additional letters after that character.
pat = "S" + lettersPattern;
StartWithS = extract(address,pat)
6-38
Search and Replace Text
"Street"
See Also
contains | extract | count | pattern | replace | strfind
Related Examples
• “Text in String and Character Arrays” on page 6-2
• “Build Pattern Expressions” on page 6-40
• “Test for Empty Strings and Missing Values” on page 6-20
• “Regular Expressions” on page 2-38
6-39
6 Characters and Strings
Since R2020b
Patterns are a tool to aid in searching for and modifying text. Similar to regular expressions, a
pattern defines rules for matching text. Patterns can be used with text-searching functions like
contains, matches, and extract to specify which portions of text these functions act on. You can
build a pattern expression in a way similar to how you would build a mathematical expression, using
pattern functions, operators, and literal text. Because building pattern expressions is open ended,
patterns can become quite complicated. Building patterns in steps and using functions like
maskedPattern and namedPattern can help organize complicated patterns.
The simplest pattern is built from a single pattern function. For example, lettersPattern matches
any letter characters. There are many pattern functions for matching different types of characters
and other features of text. A list of these functions can be found on the pattern reference page.
txt = "abc123def";
pat = lettersPattern;
extract(txt,pat)
Patterns combine with other patterns and literal text by using the plus(+) operator. This operator
appends patterns and text together in the order they are defined in the pattern expression. The
combined patterns only match text in the same order. In this example, "YYYY/MM/DD" is not a match
because a four-letter string must be at the end of the text.
txt = "Dates can be expressed as MM/DD/YYYY, DD/MM/YYYY, or YYYY/MM/DD";
pat = lettersPattern(2) + "/" + lettersPattern(2) + "/" + lettersPattern(4);
extract(txt,pat)
Patterns used with the or(|) operator specify that only one of the two specified patterns needs to
match a section of text. If neither pattern is able to match then the pattern expression fails to match.
txt = "123abc";
pat = lettersPattern|digitsPattern;
extract(txt,pat)
Some pattern functions take patterns as their input and modify them in some way. For example,
optionalPattern makes a specified pattern match if possible, but the pattern is not required for a
successful match.
6-40
Build Pattern Expressions
Boundary Patterns
Boundary patterns are a special type of pattern that do not match characters but rather match the
boundaries between a designated character type and other characters or the start or end of that
piece of text. For example, digitBoundary matches the boundaries between digit characters and
nondigit characters and between digit characters and the start or end of the text. It does not match
digit characters themselves. Boundary patterns are useful as delimiters for functions like split.
txt = "123abc";
pat = digitBoundary;
split(txt,pat)
Boundary patterns are special amongst patterns because they can be negated using the not(~)
operator. When negated in this way, boundary patterns match before or after characters that did not
satisfy the requirements above. For example, ~digitBoundary matches the boundary between:
Use replace to mark the locations matched by ~digitBoundary with a "|" character.
txt = "123abc";
pat = ~digitBoundary;
replace(txt,pat,"|")
ans =
"1|2|3a|b|c|"
Sometimes a simple pattern is not sufficient to solve a problem and a more complicated pattern is
needed. As a pattern expression grows it can become difficult to understand what it is matching. One
way to simplify building a complicated pattern is building each part of the pattern separately and
then combining the parts together into a single pattern expression.
For instance, email addresses use the form local_part@domain.TLD. Each of the three identifiers —
local_part, domain, and TLD — must be a combination of digits, letters and underscore characters. To
build the full pattern, start by defining a pattern for the identifiers. Build a pattern that matches one
letter or digit character or one underscore character.
6-41
6 Characters and Strings
identifier = asManyOfPattern(identCharacters,1);
Test the pattern by seeing how well it matches the following example emails.
exampleEmails = ["janedoe@mathworks.com"
"abe.lincoln@whitehouse.gov"
"alberteinstein@physics.university.edu"];
matches(exampleEmails,emailPattern)
1
0
0
The pattern fails to match several of the example emails even though all the emails are valid. Both the
local_part and domain can be made of a series of identifiers that are separated by periods. Use the
identifier pattern to build a pattern that is capable of matching a series of identifiers.
asManyOfPattern matches as many concurrent appearances of the specified pattern as possible,
but if there are none the rest of the pattern is still able to match successfully.
Use this pattern to build a new emailPattern that can match all of the example emails.
1
1
1
Complex patterns can sometimes be difficult to read and interpret, especially by those you share
them with who are unfamiliar with the pattern's structure. For example, when displayed,
emailPattern is long and difficult to read.
emailPattern
emailPattern = pattern
Matching:
Part of the issue with the display is that there are many repetitions of the identifier pattern. If the
exact details of this pattern are not important to users of the pattern, then the display of the
6-42
Build Pattern Expressions
identifier pattern can be concealed using maskedPattern. This function creates a new pattern
where the display of identifier is masked and the variable name, "identifier", is displayed
instead. Alternatively, you can specify a different name to be displayed. The details of patterns that
are masked in this way can be accessed by clicking "Show all details" in the displayed pattern.
identifier = maskedPattern(identifier);
identifierSeries = asManyOfPattern(identifier + ".") + identifier
identifierSeries = pattern
Matching:
Patterns can be further organized using the namedPattern function. namedPattern designates a
pattern as a named pattern that changes how the pattern is displayed when combined with other
patterns. Email addresses have several important portions, local_part@domain.TLD, which each have
their own matching rules. Create a named pattern for each section.
localPart = namedPattern(identifierSeries,"local_part");
Named patterns can be nested, to further delineate parts of a pattern. To nest a named pattern, build
a pattern using named patterns and then designate that pattern as a named pattern. For example,
Domain.TLD can be divided into the domain, subdomains, and the top level domain (TLD). Create
named patterns for each part of domain.TLD.
subdomain = namedPattern(identifierSeries,"subdomain");
domainName = namedPattern(identifier,"domainName");
tld = namedPattern(identifier,"TLD");
Nest the named patterns for the components of domain underneath a single named pattern domain.
domain = optionalPattern(subdomain + ".") + ...
domainName + "." + ...
tld;
domain = namedPattern(domain);
Combine the patterns together into a single named pattern, emailPattern. In the display of
emailPattern you can see each named pattern and what they match as well as the information on
any nested named patterns.
emailPattern = localPart + "@" + domain
emailPattern = pattern
Matching:
6-43
6 Characters and Strings
You can access named patterns and nested named patterns by dot-indexing into a pattern. For
example, you can access the nested named pattern subdomain by dot-indexing from emailPattern
into domain and then dot-indexing again into subdomain.
emailPattern.domain.subdomain
ans = pattern
Matching:
Dot-assignment can be used to change named patterns without needing to rewrite the rest of the
pattern expression.
emailPattern.domain = "mathworks.com"
emailPattern = pattern
Matching:
See Also
pattern | string, " " | regexp | contains | replace | extract
More About
• “Search and Replace Text” on page 6-37
• “Regular Expressions” on page 2-38
6-44
Convert Numeric Values to Text
This example shows how to convert numeric values to text and append them to larger pieces of text.
For example, you might want to add a label or title to a plot, where the label includes a number that
describes a characteristic of the plot.
Convert to Strings
To convert a number to a string that represents it, use the string function.
str = string(pi)
str =
"3.1416"
The string function converts a numeric array to a string array having the same size.
A = [256 pi 8.9e-3];
str = string(A)
You can specify the format of the output text using the compose function, which accepts format
specifiers for precision, field width, and exponential notation.
str = compose("%9.7f",pi)
str =
"3.1415927"
If the input is a numeric array, then compose returns a string array. Return a string array that
represents numbers using exponential notation.
A = [256 pi 8.9e-3];
str = compose("%5.2e",A)
The simplest way to combine text and numbers is to use the plus operator (+). This operator
automatically converts numeric values to strings when the other operands are strings.
For example, plot a sine wave. Calculate the frequency of the wave and add a string representing that
value in the title of the plot.
X = linspace(0,2*pi);
Y = sin(X);
plot(X,Y)
freq = 1/(2*pi);
str = "Sine Wave, Frequency = " + freq + " Hz"
6-45
6 Characters and Strings
str =
"Sine Wave, Frequency = 0.15915 Hz"
title(str)
Sometimes existing text is stored in character vectors or cell arrays of character vectors. However,
the plus operator also automatically converts those types of data to strings when another operand is
a string. To combine numeric values with those types of data, first convert the numeric values to
strings, and then use plus to combine the text.
str = 'Sine Wave, Frequency = ' + string(freq) + {' Hz'}
str =
"Sine Wave, Frequency = 0.15915 Hz"
Character Codes
If your data contains integers that represent Unicode® values, use the char function to convert the
values to the corresponding characters. The output is a character vector or array.
u = [77 65 84 76 65 66];
c = char(u)
c =
'MATLAB'
Converting Unicode values also allows you to include special characters in text. For instance, the
Unicode value for the degree symbol is 176. To add char(176) to a string, use plus.
6-46
Convert Numeric Values to Text
deg = char(176);
temp = 21;
str = "Temperature: " + temp + deg + "C"
str =
"Temperature: 21°C"
You can represent hexadecimal and binary values in your code either using text or using literals. The
recommended way to represent them is to write them as literals. You can write hexadecimal and
binary literals using the 0x and 0b prefixes respectively. However, it can sometimes be useful to
represent such values as text, using the dec2hex or dec2bin functions.
For example, set a bit in a binary value. If you specify the binary value using a literal, then it is stored
as an integer. After setting one of the bits, display the new binary value as text using the dec2bin
function.
register = 0b10010110
register = uint8
150
register = bitset(register,5,0)
register = uint8
134
binStr = dec2bin(register)
binStr =
'10000110'
See Also
dec2bin | dec2hex | char | string | compose | plus
More About
• “Convert Text to Numeric Values” on page 6-48
• “Hexadecimal and Binary Values” on page 6-54
• “Convert Between Text and datetime or duration Values” on page 7-56
• “Formatting Text” on page 6-24
• “Unicode and ASCII Values” on page 6-52
6-47
6 Characters and Strings
This example shows how to convert text to the numeric values that it represents. Typically, you need
to perform such conversions when you have text that represents numbers to be plotted or used in
calculations. For example, the text might come from a text file or spreadsheet. If you did not already
convert it to numeric values when importing it into MATLAB®, you can use the functions shown in
this example.
You can convert string arrays, character vectors, and cell arrays of character vectors to numeric
values. Text can represent hexadecimal or binary values, though when you convert them to numbers
they are stored as decimal values. You can also convert text representing dates and time to
datetime or duration values, which can be treated like numeric values.
Double-Precision Values
The recommended way to convert text to double-precision values is to use the str2double function.
It can convert character vectors, string arrays, and cell arrays of character vectors.
For example, create a character vector using single quotes and convert it to the number it represents.
X = str2double('3.1416')
X =
3.1416
If the input argument is a string array or cell array of character vectors, then str2double converts
it to a numeric array having the same size. You can create strings using double quotes. (Strings have
the string data type, while character vectors have the char data type.)
str = ["2.718","3.1416";
"137","0.015"]
X = str2double(str)
X = 2×2
2.7180 3.1416
137.0000 0.0150
The str2double function can convert text that includes commas (as thousands separators) and
decimal points. For example, you can use str2double to convert the Balance variable in the table
below. Balance represents numbers as strings, using a comma as the thousands separator.
load balances
balances
balances=3×2 table
Customer Balance
_________ ___________
6-48
Convert Text to Numeric Values
"Diaz" "13,790.00"
"Johnson" "2,456.10"
"Wu" "923.71"
T.Balance = str2double(T.Balance)
T=3×2 table
Customer Balance
_________ _______
"Diaz" 13790
"Johnson" 2456.1
"Wu" 923.71
While the str2num function can also convert text to numbers, it is not recommended. str2num uses
the eval function, which can cause unintended side effects when the text input includes a function
name. To avoid these issues, use str2double.
As an alternative, you can convert strings to double-precision values using the double function. If the
input is a string array, then double returns a numeric array that has the same size, just as
str2double does. However, if the input is a character vector, then double converts the individual
characters to numbers representing their Unicode® values.
X = double("3.1416")
X =
3.1416
X = double('3.1416')
X = 1×6
51 46 49 52 49 54
This list summarizes the best practices for converting text to numeric values.
• To convert text to numeric values, use the str2double function. It treats string arrays, character
vectors, and cell arrays of character vectors consistently.
• You can also use the double function for string arrays. However, it treats character vectors
differently.
• Avoid str2num. It calls the eval function which can have unintended consequences.
You can represent hexadecimal and binary numbers as text or as literals. When you write them as
literals, you must use the 0x and 0b prefixes. When you represent them as text and then convert
them, you can use the prefixes, but they are not required.
D = 0x3FF
6-49
6 Characters and Strings
D = uint16
1023
Then convert text representing the same value by using the hex2dec function. It recognizes the
prefix but does not require it.
D = hex2dec('3FF')
D =
1023
D = hex2dec('0x3FF')
D =
1023
D = bin2dec('101010')
D =
42
D = bin2dec('0b101010')
D =
42
MATLAB provides the datetime and duration data types to store dates and times, and to treat
them as numeric values. To convert text representing dates and times, use the datetime and
duration functions.
Convert text representing a date to a datetime value. The datetime function recognizes many
common formats for dates and times.
C = '2019-09-20'
C =
'2019-09-20'
D = datetime(C)
D = datetime
20-Sep-2019
str = ["2019-01-31","2019-02-28","2019-03-31"]
D = datetime(str)
6-50
Convert Text to Numeric Values
D = 1x3 datetime
31-Jan-2019 28-Feb-2019 31-Mar-2019
If you convert text to duration values, then use the hh:mm:ss or dd:hh:mm:ss formats.
D = duration('12:34:56')
D = duration
12:34:56
See Also
bin2dec | hex2dec | str2double | datetime | duration | double | table
More About
• “Convert Numeric Values to Text” on page 6-45
• “Convert Between Text and datetime or duration Values” on page 7-56
• “Hexadecimal and Binary Values” on page 6-54
• “Formatting Text” on page 6-24
• “Unicode and ASCII Values” on page 6-52
6-51
6 Characters and Strings
MATLAB® stores all characters as Unicode® characters using the UTF-16 encoding, where every
character is represented by a numeric code value. (Unicode incorporates the ASCII character set as
the first 128 symbols, so ASCII characters have the same numeric codes in Unicode and ASCII.) Both
character arrays and string arrays use this encoding. You can convert characters to their numeric
code values by using various numeric conversion functions. You can convert numbers to characters
using the char function.
You can convert characters to integers that represent their Unicode code values. To convert a single
character or a character array, use any of these functions:
• double
• uint16, uint32, or uint64
The best practice is to use the double function. However, if you need to store the numeric values as
integers, use unsigned integers having at least 16 bits because MATLAB uses the UTF-16 encoding.
Convert a character vector to Unicode code values using the double function.
C = 'MATLAB'
C =
'MATLAB'
unicodeValues = double(C)
unicodeValues = 1×6
77 65 84 76 65 66
You cannot convert characters in a string array directly to Unicode code values. In particular, the
double function converts strings to the numbers they represent, just as the str2double function
does. If double cannot convert a string to a number, then it returns a NaN value.
str = "MATLAB";
double(str)
ans =
NaN
To convert characters in a string, first convert the string to a character vector, or use curly braces to
extract the characters. Then convert the characters using a function such as double.
C = char(str);
unicodeValues = double(C)
unicodeValues = 1×6
77 65 84 76 65 66
6-52
Unicode and ASCII Values
You can convert Unicode values to characters using the char function.
D = [77 65 84 76 65 66]
D = 1×6
77 65 84 76 65 66
C = char(D)
C =
'MATLAB'
A typical use for char is to create characters you cannot type and append them to strings. For
example, create the character for the degree symbol and append it to a string. The Unicode code
value for the degree symbol is 176.
deg = char(176)
deg =
'°'
myLabel =
"Current temperature is 21°C"
For more information on Unicode, including mappings between characters and code values, see
Unicode.
See Also
char | double | single | string | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 |
uint64
More About
• “Convert Text to Numeric Values” on page 6-48
• “Convert Numeric Values to Text” on page 6-45
External Websites
• Unicode
6-53
6 Characters and Strings
You can represent numbers as hexadecimal or binary values. In some contexts, these representations
of numbers are more convenient. For example, you can represent the bits of a hardware register
using binary values. In MATLAB®, there are two ways to represent hexadecimal and binary values:
• As literals. Starting in R2019b, you can write hexadecimal and binary values as literals using an
appropriate prefix as notation. For example, 0x2A is a literal that specifies 42—and MATLAB
stores it as a number, not as text.
• As strings or character vectors. For example, the character vector '2A' represents the number 42
as a hexadecimal value. When you represent a hexadecimal or binary value using text, enclose it
in quotation marks. MATLAB stores this representation as text, not a number.
MATLAB provides several functions for converting numbers to and from their hexadecimal and binary
representations.
Hexadecimal literals start with a 0x or 0X prefix, while binary literals start with a 0b or 0B prefix.
MATLAB stores the number written with this notation as an integer. For example, these two literals
both represent the integer 42.
A = 0x2A
A = uint8
42
B = 0b101010
B = uint8
42
Do not use quotation marks when you write a number using this notation. Use 0-9, A-F, and a-f to
represent hexadecimal digits. Use 0 and 1 to represent binary digits.
By default, MATLAB stores the number as the smallest unsigned integer type that can accommodate
it. However, you can use an optional suffix to specify the type of integer that stores the value.
• To specify unsigned 8-, 16-, 32-, and 64-bit integer types, use the suffixes u8, u16, u32, and u64.
• To specify signed 8-, 16-, 32-, and 64-bit integer types, use the suffixes s8, s16, s32, and s64.
A = 0x2As32
A = int32
42
When you specify signed integer types, you can write literals that represent negative numbers.
Represent negative numbers in two's complement form. For example, specify a negative number with
a literal using the s8 suffix.
6-54
Hexadecimal and Binary Values
A = 0xFFs8
A = int8
-1
Because MATLAB stores these literals as numbers, you can use them in any context or function where
you use numeric arrays. For example, you can create a 64-bit signed integer array without a loss of
precision for large integers.
C = [0xFF000000001F123As64 0x1234FFFFFFFFFFFs64]
-72057594035891654 81997179153022975
For comparison, when you convert an array of large integers (larger than flintmax) using int64,
precision can be lost because MATLAB initially represents a numeric array input as double precision
by default.
C_inaccurate = int64([-72057594035891654 81997179153022975])
-72057594035891656 81997179153022976
You can also convert integers to character vectors that represent them as hexadecimal or binary
values using the dec2hex and dec2bin functions. Convert an integer to hexadecimal.
hexStr = dec2hex(255)
hexStr =
'FF'
binStr =
'10000'
Since these functions produce text, use them when you need text that represents numeric values. For
example, you can append these values to a title or a plot label, or write them to a file that stores
numbers as their hexadecimal or binary representations.
The recommended way to convert an array of numbers to text is to use the compose function. This
function returns a string array having the same size as the input numeric array. To produce
hexadecimal format, use %X as the format specifier.
A = [255 16 12 1024 137]
A = 1×5
6-55
6 Characters and Strings
hexStr = compose("%X",A)
The dec2hex and dec2bin functions also convert arrays of numbers to text representing them as
hexadecimal or binary values. However, these functions return character arrays, where each row
represents a number from the input numeric array, padded with zeros as necessary.
To convert a binary value to hexadecimal, start with a binary literal, and convert it to text
representing its hexadecimal value. Since a literal is interpreted as a number, you can specify it
directly as the input argument to dec2hex.
D = 0b1111;
hexStr = dec2hex(D)
hexStr =
'F'
If you start with a hexadecimal literal, then you can convert it to text representing its binary value
using dec2bin.
D = 0x8F;
binStr = dec2bin(D)
binStr =
'10001111'
One typical use of binary numbers is to represent bits. For example, many devices have registers that
provide access to a collection of bits representing data in memory or the status of the device. When
working with such hardware you can use numbers in MATLAB to represent the value in a register.
Use binary values and bitwise operations to represent and access particular bits.
Create a number that represents an 8-bit register. It is convenient to start with binary representation,
but the number is stored as an integer.
register = 0b10010110
register = uint8
150
To get or set the values of particular bits, use bitwise operations. For example, use the bitand and
bitshift functions to get the value of the fifth bit. (Shift that bit to the first position so that
MATLAB returns a 0 or 1. In this example, the fifth bit is a 1.)
b5 = bitand(register,0b10000);
b5 = bitshift(b5,-4)
6-56
Hexadecimal and Binary Values
b5 = uint8
register = bitset(register,5,0)
register = uint8
134
Since register is an integer, use the dec2bin function to display all the bits in binary format.
binStr is a character vector, and represents the binary value without a leading 0b prefix.
binStr = dec2bin(register)
binStr =
'10000110'
See Also
bin2dec | bitand | bitshift | bitset | dec2bin | dec2hex | hex2dec | sprintf | sscanf
More About
• “Convert Text to Numeric Values” on page 6-48
• “Convert Numeric Values to Text” on page 6-45
• “Formatting Text” on page 6-24
• “Bit-Wise Operations” on page 2-25
• “Perform Cyclic Redundancy Check” on page 2-31
External Websites
• Two's Complement
6-57
6 Characters and Strings
In most respects, strings arrays behave like character vectors and cell arrays of character vectors.
However, there are a few key differences between string arrays and character arrays that can lead to
results you might not expect. For each of these differences, there is a recommended way to use
strings that leads to the expected result.
With command syntax, you separate inputs with spaces rather than commas, and you do not enclose
input arguments in parentheses. For example, you can use the cd function with command syntax to
change folders.
cd C:\Temp
The text C:\Temp is a character vector. In command form, all arguments are always character
vectors. If you have an argument, such as a folder name, that contains spaces, then specify it as one
input argument by enclosing it in single quotes.
cd 'C:\Program Files'
But if you specify the argument using double quotes, then cd throws an error.
cd "C:\Program Files"
Error using cd
Too many input arguments.
The error message can vary depending on the function that you use and the arguments that you
specify. For example, if you use the load function with command syntax and specify the argument
using double quotes, then load throws a different error.
load "myVariables.mat"
In command form, double quotes are treated as part of the literal text rather than as the string
construction operator. If you wrote the equivalent of cd "C:\Program Files" in functional form,
then it would look like a call to cd with two arguments.
cd('"C:\Program','Files"')
When specifying arguments as strings, use function syntax. All functions that support command
syntax also support function syntax. For example, you can use cd with function syntax and input
arguments that are double quoted strings.
6-58
Frequently Asked Questions About String Arrays
cd("C:\Program Files")
Avoid using cell arrays of strings. When you use cell arrays, you give up the performance advantages
that come from using string arrays. And in fact, most functions do not accept cell arrays of strings as
input arguments, options, or values of name-value pairs. For example, if you specify a cell array of
strings as an input argument, then the contains function throws an error.
C = {"Venus","Earth","Mars"}
TF = contains(C,"Earth")
Cell arrays can contain variables having any data types, including strings. It is still possible to create
a cell array whose elements all contain strings. And if you already have specified cell arrays of
character vectors in your code, then replacing single quotes with double quotes might seem like a
simple update. However, it is not recommended that you create or use cell arrays of strings.
Create a character vector using single quotes. To determine its length, use the length function.
Because C is a vector, its length is equal to the number of characters. C is a 1-by-11 vector.
C = 'Hello world';
L = length(C)
L = 11
Create a string with the same characters, using double quotes. Though it stores 11 characters, str is
a 1-by-1 string array, or string scalar. If you call length on a string scalar, then the output argument is
1, no matter how many characters it stores.
str = "Hello World";
L = length(str)
6-59
6 Characters and Strings
L = 1
To determine the number of characters in a string, use the strlength function. For compatibility,
strlength operates on character vectors as well. In both cases strlength returns the number of
characters.
L = strlength(C)
L = 11
L = strlength(str)
L = 11
You also can use strlength on string arrays containing multiple strings and on cell arrays of
character vectors.
The length function returns the size of the longest dimension of an array. For a string array, length
returns the number of strings along the longest dimension of the array. It does not return the number
of characters within strings.
L = 0
However, an empty string is not an empty array. An empty string is a string scalar that happens to
have no characters.
sz = size("")
sz = 1×2
1 1
If you call isempty on an empty string, then it returns 0 (false) because the string is not an empty
array.
tf = isempty("")
tf = logical
0
However, if you call isempty on an empty character array, then it returns 1 (true). A character
array specified as an empty pair of single quotes, '', is a 0-by-0 character array.
tf = isempty('')
tf = logical
1
To test whether a piece of text has no characters, the best practice is to use the strlength function.
You can use the same call whether the input is a string scalar or a character vector.
str = "";
if strlength(str) == 0
6-60
Frequently Asked Questions About String Arrays
chr = '';
if strlength(chr) == 0
disp('Character vector has no text')
end
For example, if you concatenate two strings, then the result is a 1-by-2 string array.
However, if you concatenate two character vectors, then the result is a longer character vector.
chr = 'HelloWorld'
To append text to a string (or to the elements of a string array), use the plus operator instead of
square brackets.
str = "HelloWorld"
As an alternative, you can use the strcat function. strcat appends text whether the input
arguments are strings or character vectors.
str = strcat("Hello","World")
str = "HelloWorld"
Whether you use square brackets, plus, or strcat, you can specify an arbitrary number of
arguments. Append a space character between Hello and World.
See Also
string | strlength | contains | plus | strcat | sprintf | dir | cd | copyfile | load | length
| size | isempty
6-61
6 Characters and Strings
Related Examples
• “Create String Arrays” on page 6-5
• “Test for Empty Strings and Missing Values” on page 6-20
• “Compare Text” on page 6-32
• “Update Your Code to Accept Strings” on page 6-63
6-62
Update Your Code to Accept Strings
If your code has few dependencies, or if you are developing new code, then consider using string
arrays as your primary text data type for better performance. In that case, best practice is to write or
update your API to accept input arguments that are character vectors, cell arrays of character
vectors, or string arrays.
For the definitions of string array and other terms, see “Terminology for Character and String Arrays”
on page 6-69.
Functions
• If an input argument can be either a character vector or a cell array of character vectors, then
update your code so that the argument also can be a string array. For example, consider a
function that has an input argument you can specify as a character vector (using single
quotes). Best practice is to update the function so that the argument can be specified as either
a character vector or a string scalar (using double quotes).
• Accept strings as both names and values in name-value pair arguments.
• A cell array of string arrays has a string array in each cell. For example, {"hello","world"}
is a cell array of string arrays. While you can create such a cell array, it is not recommended
for storing text. The elements of a string array have the same data type and are stored
efficiently. If you store strings in a cell array, then you lose the advantages of using a string
array.
However, if your code accepts heterogeneous cell arrays as inputs, then consider accepting cell
arrays that contain strings. You can convert any strings in such a cell array to character
vectors.
6-63
6 Characters and Strings
• If your function returns a character vector or cell array of character vectors, then do not
change the output type, even if the function accepts string arrays as inputs. For example, the
fileread function accepts an input file name specified as either a character vector or a
string, but the function returns the file contents as a character vector. By keeping the output
type the same, you can maintain backward compatibility.
• Return the same data type when the function modifies input text.
• If your function modifies input text and returns the modified text as the output argument, then
the input and output arguments should have the same data type. For example, the lower
function accepts text as the input argument, converts it to all lowercase letters, and returns it.
If the input argument is a character vector, then lower returns a character vector. If the input
is a string array, then lower returns a string array.
• Consider adding a 'TextType' argument to import functions.
• If your function imports data from files, and at least some of that data can be text, then
consider adding an input argument that specifies whether to return text as a character array or
a string array. For example, the readtable function provides the 'TextType' name-value
pair argument. This argument specifies whether readtable returns a table with text in cell
arrays of character vectors or string arrays.
Classes
• For string adoption, treat methods as though they are functions. Accept string arrays as input
arguments, and in general, do not change the data type of the output arguments, as described
in the previous section.
• Do not change the data types of properties.
• If a property is a character vector or a cell array of character vectors, then do not change its
type. When you access such a property, the value that is returned is still a character vector or a
cell array of character vectors.
As an alternative, you can add a new property that is a string, and make it dependent on the
old property to maintain compatibility.
• Set properties using string arrays.
• If you can set a property using a character vector or cell array of character vectors, then
update your class to set that property using a string array too. However, do not change the
data type of the property. Instead, convert the input string array to the data type of the
property, and then set the property.
• Add a string method.
• If your class already has a char and/or a cellstr method, then add a string method. If you
can represent an object of your class as a character vector or cell array of character vectors,
then represent it as a string array too.
6-64
Update Your Code to Accept Strings
The convertStringsToChars function provides a way to process all input arguments, converting
only those arguments that are string arrays. To enable your existing code to accept string arrays as
inputs, add a call to convertStringsToChars at the beginnings of your functions and methods.
For example, if you have defined a function myFunc that accepts three input arguments, process all
three inputs using convertStringsToChars. Leave the rest of your code unaltered.
function y = myFunc(a,b,c)
[a,b,c] = convertStringsToChars(a,b,c);
<line 1 of original code>
<line 2 of original code>
...
In this example, the arguments [a,b,c] overwrite the input arguments in place. If any input
argument is not a string array, then it is unaltered.
If myFunc accepts a variable number of input arguments, then process all the arguments specified by
varargin.
function y = myFunc(varargin)
[varargin{:}] = convertStringsToChars(varargin{:});
...
Performance Considerations
The convertStringsToChars function is more efficient when converting one input argument. If
your function is performance sensitive, then you can convert input arguments one at a time, while
still leaving the rest of your code unaltered.
function y = myFunc(a,b,c)
a = convertStringsToChars(a);
b = convertStringsToChars(b);
c = convertStringsToChars(c);
...
Functions
• If an input argument can be a string array, then also allow it to be a character vector or cell
array of character vectors.
6-65
6 Characters and Strings
• Accept character arrays as both names and values in name-value pair arguments.
• A cell array of string arrays has a string array in each cell. While you can create such a cell
array, it is not recommended for storing text. If your code uses strings as the primary text data
type, store multiple pieces of text in a string array, not a cell array of string arrays.
However, if your code accepts heterogeneous cell arrays as inputs, then consider accepting cell
arrays that contain strings.
• In general, return strings.
• If your function returns output arguments that are text, then return them as string arrays.
• Return the same data type when the function modifies input text.
• If your function modifies input text and returns the modified text as the output argument, then
the input and output arguments should have the same data type.
Classes
• Accept character vectors and cell arrays of character vectors as input arguments, as described
in the previous section. In general, return strings as outputs.
• Specify properties as string arrays.
• If a property contains text, then set the property using a string array. When you access the
property, return the value as a string array.
The convertCharsToStrings function provides a way to process all input arguments, converting
only those arguments that are character vectors or cell arrays of character vectors. To enable your
new code to accept these text data types as inputs, add a call to convertCharsToStrings at the
beginnings of your functions and methods.
For example, if you have defined a function myFunc that accepts three input arguments, process all
three inputs using convertCharsToStrings.
function y = myFunc(a,b,c)
[a,b,c] = convertCharsToStrings(a,b,c);
<line 1 of original code>
<line 2 of original code>
...
6-66
Update Your Code to Accept Strings
In this example, the arguments [a,b,c] overwrite the input arguments in place. If any input
argument is not a character vector or cell array of character vectors, then it is unaltered.
If myFunc accepts a variable number of input arguments, then process all the arguments specified by
varargin.
function y = myFunc(varargin)
[varargin{:}] = convertCharsToStrings(varargin{:});
...
Performance Considerations
The convertCharsToStrings function is more efficient when converting one input argument. If
your function is performance sensitive, then you can convert input arguments one at a time, while
still leaving the rest of your code unaltered.
function y = myFunc(a,b,c)
a = convertCharsToStrings(a);
b = convertCharsToStrings(b);
c = convertCharsToStrings(c);
...
If you must convert input arguments, then use the functions in this table.
Conversion Function
String scalar to character vector char
String array to cell array of character vectors cellstr
Character vector to string scalar string
Cell array of character vectors to string array string
6-67
6 Characters and Strings
An empty string is a string with no characters. MATLAB displays an empty string as a pair of double
quotes with nothing between them (""). However, an empty string is still a 1-by-1 string array. It is
not an empty array.
The recommended way to check whether a string is empty is to use the strlength function.
str = "";
tf = (strlength(str) ~= 0)
Note Do not use the isempty function to check for an empty string. An empty string has no
characters but is still a 1-by-1 string array.
The strlength function returns the length of each string in a string array. If the string must be a
string scalar, and also not empty, then check for both conditions.
tf = (isStringScalar(str) && strlength(str) ~= 0)
If str could be either a character vector or string scalar, then you still can use strlength to
determine its length. strlength returns 0 if the input argument is an empty character vector ('').
tf = ((ischar(str) || isStringScalar(str)) && strlength(str) ~= 0)
An empty string array is, in fact, an empty array—that is, an array that has at least one dimension
whose length is 0.
The recommended way to create an empty string array is to use the strings function, specifying 0
as at least one of the input arguments. The isempty function returns 1 when the input is an empty
string array.
str = strings(0);
tf = isempty(str)
6-68
Update Your Code to Accept Strings
The strlength function returns a numeric array that is the same size as the input string array. If the
input is an empty string array, then strlength returns an empty array.
str = strings(0);
L = strlength(str)
String arrays also can contain missing strings. The missing string is the string equivalent to NaN for
numeric arrays. It indicates where a string array has missing values. The missing string displays as
<missing>, with no quotation marks.
You can create missing strings using the missing function. The recommended way to check for
missing strings is to use the ismissing function.
str = string(missing);
tf = ismissing(str)
Note Do not check for missing strings by comparing a string to the missing string.
The missing string is not equal to itself, just as NaN is not equal to itself.
str = string(missing);
f = (str == missing)
See Also
char | cellstr | string | strings | convertStringsToChars | convertCharsToStrings |
isstring | isStringScalar | ischar | iscellstr | strlength | validateattributes |
convertContainedStringsToChars
6-69
6 Characters and Strings
More About
• “Create String Arrays” on page 6-5
• “Test for Empty Strings and Missing Values” on page 6-20
• “Compare Text” on page 6-32
• “Search and Replace Text” on page 6-37
• “Frequently Asked Questions About String Arrays” on page 6-58
6-70
7
For example, create a MATLAB datetime array that represents two dates: June 28, 2014 at 6 a.m. and
June 28, 2014 at 7 a.m. Specify numeric values for the year, month, day, hour, minute, and second
components for the datetime.
t = datetime(2014,6,28,6:7,0,0)
t =
28-Jun-2014 06:00:00 28-Jun-2014 07:00:00
Change the value of a date or time component by assigning new values to the properties of the
datetime array. For example, change the day number of each datetime by assigning new values to the
Day property.
t.Day = 27:28
t =
Change the display format of the array by changing its Format property. The following format does
not display any time components. However, the values in the datetime array do not change.
t =
Jun 27, 2014 Jun 28, 2014
If you subtract one datetime array from another, the result is a duration array in units of fixed
length.
t2 = datetime(2014,6,29,6,30,45)
t2 =
29-Jun-2014 06:30:45
d = t2 - t
d =
48:30:45 23:30:45
By default, a duration array displays in the format, hours:minutes:seconds. Change the display
format of the duration by changing its Format property. You can display the duration value with a
single unit, such as hours.
d.Format = 'h'
d =
7-2
Represent Dates and Times in MATLAB
You can create a duration in a single unit using the seconds, minutes, hours, days, or years
functions. For example, create a duration of 2 days, where each day is exactly 24 hours.
d = days(2)
d =
2 days
You can create a calendar duration in a single unit of variable length. For example, one month can be
28, 29, 30, or 31 days long. Specify a calendar duration of 2 months.
L = calmonths(2)
L =
2mo
Use the caldays, calweeks, calquarters, and calyears functions to specify calendar durations
in other units.
Add a number of calendar months and calendar days. The number of days remains separate from the
number of months because the number of days in a month is not fixed, and cannot be determined
until you add the calendar duration to a specific datetime.
L = calmonths(2) + caldays(35)
L =
2mo 35d
t2 = t + calmonths(2) + caldays(35)
t2 =
whos t2
In summary, there are several ways to represent dates and times, and MATLAB has a data type for
each approach:
7-3
7 Dates and Time
The calendarDuration data type also accounts for daylight saving time changes and leap years,
so that 1 day might be more or less than 24 hours, and 1 year can have 365 or 366 days.
See Also
datetime | duration | calendarDuration
7-4
Specify Time Zones
In MATLAB®, you can specify time zones for datetime arrays. This example shows how to create
and work with datetime arrays that include time zones.
A time zone is a geographic area that observes a uniform standard time. Time zones include time
offsets from Coordinated Universal Time (UTC), time offsets from daylight saving time (DST), and a
set of historical changes to those offsets. To set a time zone and calculate time zone offsets, the
datetime data type uses code and data provided by the Internet Assigned Numbers Authority (IANA)
in the IANA Time Zone Database.
To see a complete table of time zones that are known to MATLAB, use the timezones function. Every
row of the table shows the name of a time zone, its geographic area, its offset from UTC, and its offset
due to DST. For time zones that observe DST, the DST offset is applied according to the current and
historical rules for those time zones.
AllTimeZones = timezones
AllTimeZones=446×4 table
Name Area UTCOffset DSTOffset
______________________ ______ _________ _________
{'Africa/Abidjan' } Africa 0 0
{'Africa/Accra' } Africa 0 0
{'Africa/Addis_Ababa'} Africa 3 0
{'Africa/Algiers' } Africa 1 0
{'Africa/Asmera' } Africa 3 0
{'Africa/Bamako' } Africa 0 0
{'Africa/Bangui' } Africa 1 0
{'Africa/Banjul' } Africa 0 0
{'Africa/Bissau' } Africa 0 0
{'Africa/Blantyre' } Africa 2 0
{'Africa/Brazzaville'} Africa 1 0
{'Africa/Bujumbura' } Africa 2 0
{'Africa/Cairo' } Africa 2 1
{'Africa/Casablanca' } Africa 0 1
{'Africa/Ceuta' } Africa 1 1
{'Africa/Conakry' } Africa 0 0
⋮
To see the version of the IANA Time Zone Database that MATLAB uses, return the second output from
timezones.
[~,DBversion] = timezones
DBversion =
'2024a'
To find the name of a time zone, you can search the Name variable of the table of time zones. To find
the whole name when you know part of the name, you can use the contains function. For example,
find the name of the time zone that corresponds to New York. Replace space characters with
underscores in your search string.
7-5
7 Dates and Time
TFindex = contains(AllTimeZones.Name,"New_York");
NewYorkZone = AllTimeZones.Name(TFindex)
Display the corresponding row of the time zones table. To match the exact name of the time zone, use
the matches function.
TFindex = matches(AllTimeZones.Name,NewYorkZone);
AllTimeZones(TFindex,:)
ans=1×4 table
Name Area UTCOffset DSTOffset
____________________ _______ _________ _________
{'America/New_York'} America -5 1
Every datetime array has a time zone property. By default, this property is not set, which means the
resulting datetime array is unzoned. You can use unzoned datetime arrays for local time
calculations in which you do not need to consider DST or local times in other time zones.
For example, create a datetime value for the current time, and display its TimeZone property. The
current date and time values come from your system clock. Without a time zone, the datetime value
cannot calculate the time zone offset relative to UTC.
D = datetime("now")
D = datetime
23-Jan-2025 15:28:24
D.TimeZone
ans =
There are two ways to set the time zone of a datetime array. The first way is to specify the
TimeZone name-value argument of the datetime function when creating the datetime array.
Specifying this argument sets the value of the TimeZone property.
D = datetime("now",TimeZone="America/New_York")
D = datetime
23-Jan-2025 15:28:25
D.TimeZone
ans =
'America/New_York'
The second way is to assign a value to the TimeZone property after you have created the datetime
array.
7-6
Specify Time Zones
D = datetime("now")
D = datetime
23-Jan-2025 15:28:25
D.TimeZone = "America/New_York"
D = datetime
23-Jan-2025 15:28:25
You can also specify the TimeZone property as a duration that is just a fixed time zone offset from
UTC. Such an offset does not incorporate any current or historical offset rules, such as daylight
saving time.
For example, specify a time zone offset that is five hours behind UTC. This offset is the same as the
UTC offset for America/New_York, but it does not include any offset for daylight saving time.
D = datetime("now",TimeZone="-05:00")
D = datetime
23-Jan-2025 15:28:25
D.TimeZone
ans =
'-05:00'
The default format for datetime arrays does not include the time zone. However, you can include the
time zone offset in the format by using the z or Z identifiers.
For example, change the format to include the date, time, and time zone offset using z. The z
identifier specifies the short localized version of the offset. Its behavior depends on your locale.
D = datetime("now", ...
TimeZone="America/New_York", ...
Format="dd-MMM-uuuu HH:mm:ss z")
D = datetime
23-Jan-2025 15:28:25 EST
7-7
7 Dates and Time
The Z identifier specifies a basic format that displays the offset as hours, minutes, and optionally
seconds.
D.Format = "dd-MMM-uuuu HH:mm:ss Z"
D = datetime
23-Jan-2025 15:28:25 -0500
You can also specify the long UTC format. For a complete list of time zone offset identifiers, see
datetime.
D.Format = "dd-MMM-uuuu HH:mm:ss ZZZZ"
D = datetime
23-Jan-2025 15:28:25 UTC-05:00
If you change the time zone of a datetime value, it still encodes the same point in time. If the offset
from UTC changes, then the date and time values change in a way that compensates for the change
in the offset.
For example, create a datetime value in the New York time zone, and format it to display the time
zone offset.
D = datetime("today", ...
TimeZone="America/New_York", ...
Format="dd-MMM-uuuu HH:mm:ss z")
D = datetime
23-Jan-2025 00:00:00 EST
Then change its time zone to the zone for Los Angeles. The date and time values change to encode
the same point in time in a different time zone.
D.TimeZone = "America/Los_Angeles"
D = datetime
22-Jan-2025 21:00:00 PST
If you compare datetime values that have different time zones, then the comparison takes the time
zone offsets into account. However, you cannot compare zoned and unzoned datetime arrays
because an unzoned array has no known time zone offset. Both arrays must be zoned or unzoned.
For example, create a datetime value. Then copy it and change its time zone.
NYTime = datetime("today", ...
TimeZone="America/New_York", ...
Format="dd-MMM-uuuu HH:mm:ss z")
NYTime = datetime
23-Jan-2025 00:00:00 EST
7-8
Specify Time Zones
LATime = NYTime;
LATime.TimeZone = "America/Los_Angeles"
LATime = datetime
22-Jan-2025 21:00:00 PST
Compare the two values using the == operator. The values are equal because they encode the same
point in time.
AreTimesEqual = logical
1
TimeDiff = duration
00:00:00
LATime = datetime
22-Jan-2025 23:00:00 PST
Compare the two times. Despite their date and time values, the time in Los Angeles occurs later than
the time in New York.
IsLATimeLater = logical
1
TimeDiff = duration
02:00:00
The TimeZone property applies to every element in a datetime array. However, you can concatenate
datetime arrays that have different time zones. The concatenated array has the same time zone as
the first array. You cannot concatenate zoned and unzoned datetime arrays because the unzoned
array has no known time zone offset. Both arrays must be zoned or unzoned.
For example, concatenate NYTime and LATime. The result has the time zone for New York.
7-9
7 Dates and Time
Then concatenate in the reverse order. The result has the time zone for Los Angeles.
A leap second is a one-second adjustment that is applied to UTC. Leap seconds were introduced in
1972 to account for the difference between precise time based on atomic clocks and observed solar
time, which varies due to small changes in earth's rotation rate. Those changes do not come in a
predictable pattern, so leap seconds have been declared as needed. The leap second data
incorporated into MATLAB is provided by the International Earth Rotation and Reference Systems
Service (IERS). For more information, see the IERS Bulletins.
The datetime data type has a special time zone that accounts for leap seconds. For any calculations
or comparisons that involve leap seconds, specify the time zone as "UTCLeapSeconds". When you
use this time zone, the default format includes the date, time, and the letter Z to indicate UTC,
according to the ISO 8601 standard.
todayLS = datetime("today",TimeZone="UTCLeapSeconds")
todayLS = datetime
2025-01-23T00:00:00.000Z
You cannot combine or compare datetime arrays when one array has leap seconds and the other
array does not.
One way to see the effect of leap seconds is to calculate the length of time between today's date and
January 1, 1972, in the UTC and UTCLeapSeconds time zones. First calculate the duration in the UTC
zone. The duration is shown in hh:mm:ss format.
durationWithoutLS = duration
465144:00:00
Then calculate the duration in the UTCLeapSeconds zone. The difference between the two durations
is due to the cumulative effect of the leap seconds declared since 1972.
durationWithLS = duration
465144:00:27
To see all the leap seconds known to MATLAB and the dates they were declared, use the
leapseconds function.
LS = leapseconds
7-10
Specify Time Zones
LS=27×2 timetable
Date Type CumulativeAdjustment
___________ ____ ____________________
30-Jun-1972 + 1 sec
31-Dec-1972 + 2 sec
31-Dec-1973 + 3 sec
31-Dec-1974 + 4 sec
31-Dec-1975 + 5 sec
31-Dec-1976 + 6 sec
31-Dec-1977 + 7 sec
31-Dec-1978 + 8 sec
31-Dec-1979 + 9 sec
30-Jun-1981 + 10 sec
30-Jun-1982 + 11 sec
30-Jun-1983 + 12 sec
30-Jun-1985 + 13 sec
31-Dec-1987 + 14 sec
31-Dec-1989 + 15 sec
31-Dec-1990 + 16 sec
⋮
The second output returns the IERS Bulletin C version number of the leap second data used in
MATLAB.
[~,LSvers] = leapseconds
LSvers =
67
See Also
datetime | timezones | leapseconds
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Set Date and Time Display Format” on page 7-15
• “Convert Between Text and datetime or duration Values” on page 7-56
• “Share Code and Data Across Locales” on page 7-24
• “Convert Date and Time to Julian Date or POSIX Time” on page 7-12
7-11
7 Dates and Time
You can convert datetime arrays to represent points in time in specialized numeric formats. In
general, these formats represent a point in time as the number of seconds or days that have elapsed
since a specified starting point. For example, the Julian date is the number of days and fractional days
that have elapsed since the beginning of the Julian period. The POSIX® time is the number of
seconds that have elapsed since 00:00:00 1-Jan-1970 UTC (Coordinated Universal Time). MATLAB®
provides the juliandate and posixtime functions to convert datetime arrays to Julian dates and
POSIX times.
While datetime arrays are not required to have a time zone, converting "unzoned" datetime values
to Julian dates or POSIX times can lead to unexpected results. To ensure the expected result, specify
the time zone before conversion.
You can specify a time zone for a datetime array, but you are not required to do so. In fact, by
default the datetime function creates an "unzoned" datetime array.
d = datetime("now")
d = datetime
23-Jan-2025 16:57:24
d is constructed from the local time on your machine and has no time zone associated with it. In many
contexts, you might assume that you can treat the times in an unzoned datetime array as local
times. However, the juliandate and posixtime functions treat the times in unzoned datetime
arrays as UTC times, not local times. To avoid any ambiguity, it is recommended that you avoid using
juliandate and posixtime on unzoned datetime arrays. For example, avoid using
posixtime(datetime("now")) in your code.
If your datetime array has values that do not represent UTC times, specify the time zone using the
TimeZone name-value pair argument so that juliandate and posixtime interpret the datetime
values correctly.
d = datetime("now","TimeZone","America/New_York")
d = datetime
23-Jan-2025 16:57:24
As an alternative, you can specify the TimeZone property after you create the array.
d.TimeZone = "America/Los_Angeles"
d = datetime
23-Jan-2025 13:57:24
7-12
Convert Date and Time to Julian Date or POSIX Time
A Julian date is the number of days (including fractional days) since noon on November 24, 4714
BCE, in the proleptic Gregorian calendar, or January 1, 4713 BCE, in the proleptic Julian calendar. To
convert datetime arrays to Julian dates, use the juliandate function.
DZ = 1x3 datetime
29-Aug-2016 10:05:24 29-Sep-2016 10:05:24 29-Oct-2016 10:05:24
format longG
JDZ = juliandate(DZ)
JDZ = 1×3
Create an unzoned copy of DZ. Convert D to the equivalent Julian dates. As D has no time zone,
juliandate treats the times as UTC times.
D = DZ;
D.TimeZone = "";
JD = juliandate(D)
JD = 1×3
Compare JDZ and JD. The differences are equal to the time zone offset between UTC and the
America/New_York time zone in fractional days.
JDZ - JD
ans = 1×3
The POSIX time is the number of seconds (including fractional seconds) elapsed since 00:00:00 1-
Jan-1970 UTC (Coordinated Universal Time), ignoring leap seconds. To convert datetime arrays to
POSIX times, use the posixtime function.
7-13
7 Dates and Time
DZ = 1x3 datetime
29-Aug-2016 10:05:24 29-Sep-2016 10:05:24 29-Oct-2016 10:05:24
PTZ = posixtime(DZ)
PTZ = 1×3
Create an unzoned copy of DZ. Convert D to the equivalent POSIX times. As D has no time zone,
posixtime treats the times as UTC times.
D = DZ;
D.TimeZone = "";
PT = posixtime(D)
PT = 1×3
Compare PTZ and PT. The differences are equal to the time zone offset between UTC and the
America/New_York time zone in seconds.
PTZ - PT
ans = 1×3
See Also
datetime | timezones | posixtime | juliandate
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Specify Time Zones” on page 7-5
7-14
Set Date and Time Display Format
In this section...
“Formats for Individual Date and Duration Arrays” on page 7-15
“datetime Display Format” on page 7-15
“duration Display Format” on page 7-16
“calendarDuration Display Format” on page 7-17
“Default datetime Format” on page 7-17
t.Format = 'default'
Changing the Format property does not change the values in the array, only their display. For
example, the following can be representations of the same datetime value (the latter two do not
display any time components):
The Format property of the datetime, duration, and calendarDuration data types accepts
different formats as inputs.
To change the default formats, see “Default datetime Format” on page 7-17.
Alternatively, you can specify a custom date format that includes Unicode characters as literal text.
This table shows several common display formats and examples of the formatted output for the date,
Saturday, April 19, 2014 at 9:41:06 PM in New York City. In such formats you can use nonletter ASCII
characters such as hyphens, spaces, or colons, or any non-ASCII characters, to separate date and
time fields. To include the ASCII letters A-Z and a-z as literal characters in the format, enclose them
in quotation marks.
7-15
7 Dates and Time
For a complete list of valid symbolic identifiers, see the Format property for datetime arrays.
Note The letter identifiers that datetime accepts are different from those used by the datestr,
datenum, and datevec functions.
To specify the number of fractional digits displayed, use the format function.
To display a duration in the form of a digital timer, specify one of the following character vectors.
• 'dd:hh:mm:ss'
• 'hh:mm:ss'
• 'mm:ss'
• 'hh:mm'
You also can display up to nine fractional second digits by appending up to nine S characters. For
example, 'hh:mm:ss.SSS' displays the milliseconds of a duration value to 3 digits.
Changing the Format property does not change the values in the array, only their display.
7-16
Set Date and Time Display Format
This table describes the date and time components that the characters represent.
To specify the number of digits displayed for fractional seconds, use the format function.
Changing the Format property does not change the values in the array, only their display.
datetime.setDefaultFormats('default',fmt)
where fmt is a character vector composed of the letters A-Z and a-z described for the Format
property of datetime arrays, above. For example,
datetime.setDefaultFormats('default','yyyy-MM-dd hh:mm:ss')
sets the default datetime format to include a 4-digit year, 2-digit month number, 2-digit day number,
and hour, minute, and second values.
In addition, you can specify a default format for datetimes created without time components. For
example,
datetime.setDefaultFormats('defaultdate','yyyy-MM-dd')
sets the default date format to include a 4-digit year, 2-digit month number, and 2-digit day number.
7-17
7 Dates and Time
To reset the both the default format and the default date-only formats to the factory defaults, type
datetime.setDefaultFormats('reset')
You also can set the default formats in the Preferences dialog box. For more information, see “Set
Command Window Preferences”.
See Also
datetime | duration | calendarDuration | format
7-18
Generate Sequence of Dates and Time
This example shows how to use the colon (:) operator to generate sequences of datetime or
duration values in the same way that you create regularly spaced numeric vectors.
Create a sequence of datetime values starting from November 1, 2013, and ending on November 5,
2013. The default step size is one calendar day.
t1 = datetime(2013,11,1,8,0,0);
t2 = datetime(2013,11,5,8,0,0);
t = t1:t2
t = 1x5 datetime
01-Nov-2013 08:00:00 02-Nov-2013 08:00:00 03-Nov-2013 08:00:00 04-Nov-2013 08:00:00 05
t = t1:caldays(2):t2
t = 1x3 datetime
01-Nov-2013 08:00:00 03-Nov-2013 08:00:00 05-Nov-2013 08:00:00
Specify a step size in units other than days. Create a sequence of datetime values spaced 18 hours
apart.
t = t1:hours(18):t2
t = 1x6 datetime
01-Nov-2013 08:00:00 02-Nov-2013 02:00:00 02-Nov-2013 20:00:00 03-Nov-2013 14:00:00 04
Use the years, days, minutes, and seconds functions to create datetime and duration sequences
using other fixed-length date and time units. Create a sequence of duration values between 0 and 3
minutes, incremented by 30 seconds.
d = 0:seconds(30):minutes(3)
7-19
7 Dates and Time
d = 1x7 duration
0 sec 30 sec 60 sec 90 sec 120 sec 150 sec 180 sec
Assign a time zone to t1 and t2. In the America/New_York time zone, t1 now occurs just before a
daylight saving time change.
t1.TimeZone = 'America/New_York';
t2.TimeZone = 'America/New_York';
If you create the sequence using a step size of one calendar day, then the difference between
successive datetime values is not always 24 hours.
t = t1:t2;
dt = diff(t)
dt = 1x4 duration
24:00:00 25:00:00 24:00:00 24:00:00
t = 1x5 datetime
01-Nov-2013 08:00:00 02-Nov-2013 08:00:00 03-Nov-2013 07:00:00 04-Nov-2013 07:00:00 05
dt = 1x4 duration
24:00:00 24:00:00 24:00:00 24:00:00
If you specify a step size in terms of an integer, it is interpreted as a number of 24-hour days.
t = t1:1:t2
t = 1x5 datetime
01-Nov-2013 08:00:00 02-Nov-2013 08:00:00 03-Nov-2013 07:00:00 04-Nov-2013 07:00:00 05
This example shows how to add a duration or calendar duration to a datetime to create a sequence of
datetime values.
7-20
Generate Sequence of Dates and Time
t = t1 + hours(0:2)
t = 1x3 datetime
01-Nov-2013 08:00:00 01-Nov-2013 09:00:00 01-Nov-2013 10:00:00
t = t1 + calmonths(1:5)
t = 1x5 datetime
01-Dec-2013 08:00:00 01-Jan-2014 08:00:00 01-Feb-2014 08:00:00 01-Mar-2014 08:00:00 01
dt = caldiff(t)
dt = 1x4 calendarDuration
1mo 1mo 1mo 1mo
dt = caldiff(t,'days')
dt = 1x4 calendarDuration
31d 31d 28d 31d
Add a number of calendar months to the date, January 31, 2014, to create a sequence of dates that
fall on the last day of each month.
t = datetime(2014,1,31) + calmonths(0:11)
t = 1x12 datetime
31-Jan-2014 28-Feb-2014 31-Mar-2014 30-Apr-2014 31-May-2014 30-Jun-2014 31-Jul-201
This example shows how to use the linspace function to create equally spaced datetime or duration
values between two specified endpoints.
Create a sequence of five equally spaced dates between April 14, 2014, and August 4, 2014. First,
define the endpoints.
A = datetime(2014,04,14);
B = datetime(2014,08,04);
The third input to linspace specifies the number of linearly spaced points to generate between the
endpoints.
C = linspace(A,B,5)
7-21
7 Dates and Time
C = 1x5 datetime
14-Apr-2014 12-May-2014 09-Jun-2014 07-Jul-2014 04-Aug-2014
Create a sequence of six equally spaced durations between 1 and 5.5 hours.
A = duration(1,0,0);
B = duration(5,30,0);
C = linspace(A,B,6)
C = 1x6 duration
01:00:00 01:54:00 02:48:00 03:42:00 04:36:00 05:30:00
This example shows how to use the dateshift function to generate sequences of dates and time
where each instance obeys a rule relating to a calendar unit or a unit of time. For instance, each
datetime must occur at the beginning a month, on a particular day of the week, or at the end of a
minute. The resulting datetime values in the sequence are not necessarily equally spaced.
Generate a sequence of dates consisting of the next three occurrences of Monday. First, define
today's date.
t1 = datetime('today','Format','dd-MMM-yyyy eee')
t1 = datetime
23-Jan-2025 Thu
The first input to dateshift is always the datetime array from which you want to generate a
sequence. Specify 'dayofweek' as the second input to indicate that the datetime values in the
output sequence must fall on a specific day of the week. You can specify the day of the week either by
number or by name. For example, you can specify Monday either as 2 or 'Monday'.
t = dateshift(t1,'dayofweek',2,1:3)
t = 1x3 datetime
27-Jan-2025 Mon 03-Feb-2025 Mon 10-Feb-2025 Mon
Generate a sequence of start-of-month dates beginning with April 1, 2014. Specify 'start' as the
second input to dateshift to indicate that all datetime values in the output sequence should fall at
the start of a particular unit of time. The third input argument defines the unit of time, in this case,
month. The last input to dateshift can be an array of integer values that specifies how t1 should be
shifted. In this case, 0 corresponds to the start of the current month, and 4 corresponds to the start
of the fourth month from t1.
t1 = datetime(2014,04,01);
t = dateshift(t1,'start','month',0:4)
7-22
Generate Sequence of Dates and Time
t = 1x5 datetime
01-Apr-2014 01-May-2014 01-Jun-2014 01-Jul-2014 01-Aug-2014
t1 = datetime(2014,04,01);
t = dateshift(t1,'end','month',0:2)
t = 1x3 datetime
30-Apr-2014 31-May-2014 30-Jun-2014
dt = caldiff(t,'days')
dt = 1x2 calendarDuration
31d 30d
You can specify other units of time such as week, day, and hour.
t1 = datetime('now')
t1 = datetime
23-Jan-2025 02:03:14
t = dateshift(t1,'start','hour',0:4)
t = 1x5 datetime
23-Jan-2025 02:00:00 23-Jan-2025 03:00:00 23-Jan-2025 04:00:00 23-Jan-2025 05:00:00 23
Generate a sequence of datetime values beginning with the previous hour. Negative integers in the
last input to dateshift correspond to datetime values earlier than t1.
t = dateshift(t1,'start','hour',-1:1)
t = 1x3 datetime
23-Jan-2025 01:00:00 23-Jan-2025 02:00:00 23-Jan-2025 03:00:00
See Also
dateshift | linspace
7-23
7 Dates and Time
In this section...
“Write Locale-Independent Date and Time Code” on page 7-24
“Write Dates in Other Languages” on page 7-25
“Read Dates in Other Languages” on page 7-25
Follow these best practices when sharing code that handles dates and time with MATLAB® users in
other locales. These practices ensure that the same code produces the same output display and that
output files containing dates and time are read correctly on systems in different countries or with
different language settings.
Create language-independent datetime values. That is, create datetime values that use month
numbers rather than month names, such as 01 instead of January. Avoid using day of week names.
t = datetime('today','Format','yyyy-MM-dd')
t = datetime
2025-01-23
instead of this:
t = datetime('today','Format','eeee, dd-MMM-yyyy')
t = datetime
Thursday, 23-Jan-2025
Display the hour using 24-hour clock notation rather than 12-hour clock notation. Use the 'HH'
identifiers when specifying the display format for datetime values.
t = datetime('now','Format','HH:mm')
t = datetime
16:27
instead of this:
t = datetime('now','Format','hh:mm a')
t = datetime
04:27 PM
7-24
Share Code and Data Across Locales
When specifying the display format for time zone information, use the Z or X identifiers instead of the
lowercase z to avoid the creation of time zone names that might not be recognized in other languages
or regions.
t.TimeZone = 'America/New_York';
t = datetime
23-01-2025 -0500
If you share files but not code, you do not need to write locale-independent code while you work in
MATLAB. However, when you write to a file, ensure that any text representing dates and times is
language-independent. Then, other MATLAB users can read the files easily without having to specify
a locale in which to interpret date and time data.
Specify an appropriate format for text representing dates and times when you use the char or
cellstr functions. For example, convert two datetime values to a cell array of character vectors
using cellstr. Specify the format and the locale to represent the day, month, and year of each
datetime value as text.
t = [datetime('today');datetime('tomorrow')]
t = 2x1 datetime
23-Jan-2025
24-Jan-2025
S = 2x1 cell
{'23. Januar 2025'}
{'24. Januar 2025'}
S is a cell array of character vectors representing dates in German. You can export S to a text file to
use with systems in the de_DE locale.
7-25
7 Dates and Time
• When reading text files using the textscan function, specify the file encoding when opening the
file with fopen. The encoding is the fourth input argument to fopen.
• When reading text files using the readtable function, use the FileEncoding name-value pair
argument to specify the character encoding associated with the file.
See Also
datetime | char | cellstr | readtable | textscan
7-26
Extract or Assign Date and Time Components of Datetime Array
This example shows two ways to extract date and time components from existing datetime arrays:
accessing the array properties or calling a function. Then, the example shows how to modify the date
and time components by modifying the array properties.
t = 1x3 datetime
24-Jan-2025 02:39:18 24-Feb-2026 22:39:18 25-Mar-2027 18:39:18
Get the year values of each datetime in the array. Use dot notation to access the Year property of t.
t_years = t.Year
t_years = 1×3
Get the month values of each datetime in t by accessing the Month property.
t_months = t.Month
t_months = 1×3
1 2 3
You can retrieve the day, hour, minute, and second components of each datetime in t by accessing the
Hour, Minute, and Second properties, respectively.
Use the month function to get the month number for each datetime in t. Using functions is an
alternate way to retrieve specific date or time components of t.
m = month(t)
m = 1×3
1 2 3
Use the month function rather than the Month property to get the full month names of each datetime
in t.
m = month(t,'name')
7-27
7 Dates and Time
m = 1x3 cell
{'January'} {'February'} {'March'}
You can retrieve the year, quarter, week, day, hour, minute, and second components of each datetime
in t using the year, quarter, week, hour, minute, and second functions, respectively.
w = week(t)
w = 1×3
4 9 13
Use the ymd function to get the year, month, and day values of t as three separate numeric arrays.
[y,m,d] = ymd(t)
y = 1×3
m = 1×3
1 2 3
d = 1×3
24 24 25
Use the hms function to get the hour, minute, and second values of t as three separate numeric
arrays.
[h,m,s] = hms(t)
h = 1×3
2 22 18
m = 1×3
39 39 39
s = 1×3
7-28
Extract or Assign Date and Time Components of Datetime Array
Assign new values to components in an existing datetime array by modifying the properties of the
array. Use dot notation to access a specific property.
Change the year number of all datetime values in t to 2014. Use dot notation to modify the Year
property.
t.Year = 2014
t = 1x3 datetime
24-Jan-2014 02:39:18 24-Feb-2014 22:39:18 25-Mar-2014 18:39:18
Change the months of the three datetime values in t to January, February, and March, respectively.
You must specify the new value as a numeric array.
t.Month = [1,2,3]
t = 1x3 datetime
24-Jan-2014 02:39:18 24-Feb-2014 22:39:18 25-Mar-2014 18:39:18
t.TimeZone = 'Europe/Berlin';
Change the display format of t to display only the date, and not the time information.
t.Format = 'dd-MMM-yyyy'
t = 1x3 datetime
24-Jan-2014 24-Feb-2014 25-Mar-2014
If you assign values to a datetime component that are outside the conventional range, MATLAB®
normalizes the components. The conventional range for day of month numbers is from 1 to 31. Assign
day values that exceed this range.
t = 1x3 datetime
30-Dec-2013 01-Feb-2014 01-Apr-2014
The month and year numbers adjust so that all values remain within the conventional range for each
date component. In this case, January -1, 2014 converts to December 30, 2013.
See Also
datetime | ymd | hms | week
7-29
7 Dates and Time
Create a space-delimited text file named schedule.txt that contains the following (to create the
file, use any text editor, and copy and paste):
Date Name Time
10.03.2015 Joe 14:31
10.03.2015 Bob 15:33
11.03.2015 Bob 11:29
12.03.2015 Kim 12:09
12.03.2015 Joe 13:05
Read the file using the readtable function. Use the %D conversion specifier to read the first and
third columns of data as datetime values.
T = readtable('schedule.txt','Format','%{dd.MM.uuuu}D %s %{HH:mm}D','Delimiter',' ')
T =
Date Name Time
__________ _____ _____
10.03.2015 'Joe' 14:31
10.03.2015 'Bob' 15:33
11.03.2015 'Bob' 11:29
12.03.2015 'Kim' 12:09
12.03.2015 'Joe' 13:05
Change the display format for the T.Date and T.Time variables to view both date and time
information. Since the data in the first column of the file ("Date") have no time information, the time
of the resulting datetime values in T.Date default to midnight. Since the data in the third column of
the file ("Time") have no associated date, the date of the datetime values in T.Time defaults to the
current date.
T.Date.Format = 'dd.MM.uuuu HH:mm';
T.Time.Format = 'dd.MM.uuuu HH:mm';
T
T =
Date Name Time
________________ _____ ________________
10.03.2015 00:00 'Joe' 12.12.2014 14:31
10.03.2015 00:00 'Bob' 12.12.2014 15:33
11.03.2015 00:00 'Bob' 12.12.2014 11:29
12.03.2015 00:00 'Kim' 12.12.2014 12:09
12.03.2015 00:00 'Joe' 12.12.2014 13:05
Combine the date and time information from two different table variables by adding T.Date and the
time values in T.Time. Extract the time information from T.Time using the timeofday function.
myDatetime = T.Date + timeofday(T.Time)
myDatetime =
10.03.2015 14:31
10.03.2015 15:33
7-30
Combine Date and Time from Separate Variables
11.03.2015 11:29
12.03.2015 12:09
12.03.2015 13:05
See Also
readtable | timeofday
7-31
7 Dates and Time
This example shows how to add and subtract date and time values to calculate future and past dates
and elapsed durations in exact units or calendar units. You can add, subtract, multiply, and divide
date and time arrays in the same way that you use these operators with other MATLAB® data types.
However, there is some behavior that is specific to dates and time.
Create a datetime scalar. By default, datetime arrays are not associated with a time zone.
t1 = datetime('now')
t1 = datetime
23-Jan-2025 03:07:23
t2 = t1 + hours(1:3)
t2 = 1x3 datetime
23-Jan-2025 04:07:23 23-Jan-2025 05:07:23 23-Jan-2025 06:07:23
Verify that the difference between each pair of datetime values in t2 is 1 hour.
dt = diff(t2)
dt = 1x2 duration
01:00:00 01:00:00
diff returns durations in terms of exact numbers of hours, minutes, and seconds.
t2 = t1 - minutes(20:10:40)
t2 = 1x3 datetime
23-Jan-2025 02:47:23 23-Jan-2025 02:37:23 23-Jan-2025 02:27:23
Add a numeric array to a datetime array. MATLAB treats each value in the numeric array as a
number of exact, 24-hour days.
t2 = t1 + [1:3]
t2 = 1x3 datetime
24-Jan-2025 03:07:23 25-Jan-2025 03:07:23 26-Jan-2025 03:07:23
If you work with datetime values in different time zones, or if you want to account for daylight saving
time changes, work with datetime arrays that are associated with time zones. Create a datetime
scalar representing March 8, 2014, in New York.
7-32
Date and Time Arithmetic
t1 = datetime(2014,3,8,0,0,0,'TimeZone','America/New_York')
t1 = datetime
08-Mar-2014
t2 = 1x3 datetime
08-Mar-2014 00:00:00 09-Mar-2014 00:00:00 10-Mar-2014 01:00:00
Because a daylight saving time shift occurred on March 9, 2014, the third datetime in t2 does not
occur at midnight.
Verify that the difference between each pair of datetime values in t2 is 24 hours.
dt = diff(t2)
dt = 1x2 duration
24:00:00 24:00:00
You can add fixed-length durations in other units such as years, hours, minutes, and seconds by
adding the outputs of the years, hours, minutes, and seconds functions, respectively.
To account for daylight saving time changes, you should work with calendar durations instead of
durations. Calendar durations account for daylight saving time shifts when they are added to or
subtracted from datetime values.
t3 = 1x3 datetime
08-Mar-2014 09-Mar-2014 10-Mar-2014
View that the difference between each pair of datetime values in t3 is not always 24 hours due to the
daylight saving time shift that occurred on March 9.
dt = diff(t3)
dt = 1x2 duration
24:00:00 23:00:00
t1 = datetime
31-Jan-2014
t2 = t1 + calmonths(1:4)
7-33
7 Dates and Time
t2 = 1x4 datetime
28-Feb-2014 31-Mar-2014 30-Apr-2014 31-May-2014
Calculate the difference between each pair of datetime values in t2 in terms of a number of calendar
days using the caldiff function.
dt = caldiff(t2,'days')
dt = 1x3 calendarDuration
31d 30d 31d
The number of days between successive pairs of datetime values in dt is not always the same
because different months consist of a different number of days.
t2 = t1 + calyears(0:4)
t2 = 1x5 datetime
31-Jan-2014 31-Jan-2015 31-Jan-2016 31-Jan-2017 31-Jan-2018
Calculate the difference between each pair of datetime values in t2 in terms of a number of calendar
days using the caldiff function.
dt = caldiff(t2,'days')
dt = 1x4 calendarDuration
365d 365d 366d 365d
The number of days between successive pairs of datetime values in dt is not always the same
because 2016 is a leap year and has 366 days.
You can use the calquarters, calweeks, and caldays functions to create arrays of calendar
quarters, calendar weeks, or calendar days that you add to or subtract from datetime arrays.
Adding calendar durations is not commutative. When you add more than one calendarDuration
array to a datetime, MATLAB adds them in the order in which they appear in the command.
t2 = datetime
30-May-2014
First add 30 calendar days to the same date, and then add 3 calendar months. The result is not the
same because when you add a calendar duration to a datetime, the number of days added depends on
the original date.
7-34
Date and Time Arithmetic
t2 = datetime
02-Jun-2014
d1 = calendarDuration
1y 2mo 20d
d2 = calmonths(11) + caldays(23)
d2 = calendarDuration
11mo 23d
d = d1 + d2
d = calendarDuration
2y 1mo 43d
When you sum two or more calendar durations, a number of months greater than 12 roll over to a
number of years. However, a large number of days does not roll over to a number of months, because
different months consist of different numbers of days.
Increase d by multiplying it by a factor of 2. Calendar duration values must be integers, so you can
multiply them only by integer values.
2*d
ans = calendarDuration
4y 2mo 86d
Subtract one datetime array from another to calculate elapsed time in terms of an exact number of
hours, minutes, and seconds.
Find the exact length of time between a sequence of datetime values and the start of the previous
day.
t2 = datetime('now') + caldays(1:3)
t2 = 1x3 datetime
24-Jan-2025 03:07:24 25-Jan-2025 03:07:24 26-Jan-2025 03:07:24
t1 = datetime('yesterday')
t1 = datetime
22-Jan-2025
dt = t2 - t1
7-35
7 Dates and Time
dt = 1x3 duration
51:07:24 75:07:24 99:07:24
whos dt
dt 1x3 40 duration
View the elapsed durations in units of days by changing the Format property of dt.
dt.Format = 'd'
dt = 1x3 duration
2.1301 days 3.1301 days 4.1301 days
Scale the duration values by multiplying dt by a factor of 1.2. Because durations have an exact
length, you can multiply and divide them by fractional values.
dt2 = 1.2*dt
Use the between function to find the number of calendar years, months, and days elapsed between
two dates.
t1 = datetime('today')
t1 = datetime
23-Jan-2025
t2 = t1 + calmonths(0:2) + caldays(4)
t2 = 1x3 datetime
27-Jan-2025 27-Feb-2025 27-Mar-2025
dt = between(t1,t2)
dt = 1x3 calendarDuration
4d 1mo 4d 2mo 4d
See Also
between | diff | caldiff
7-36
Compare Dates and Time
This example shows how to compare dates, times, and durations by using relational operators and
comparison functions. Because the datetime and duration data types represent dates and times
quantitatively, you can use the same relational operators that you use to compare numeric arrays.
However, the comparisons have slightly different meanings, depending on the data type.
• A datetime value can occur before, at the same time as, or after another datetime value.
• A duration value can be shorter than, the same length of time as, or longer than another
duration value.
The calendarDuration data type does not support comparisons using relational operators.
Calendar units do not necessarily represent fixed lengths of time.
You can compare two datetime arrays, and you can compare two duration arrays. The arrays must
have compatible sizes because relational operators perform element-wise comparisons. In the
simplest cases, the two arrays have the same size or one is a scalar. For more information, see
“Compatible Array Sizes for Basic Operations” on page 2-12.
Dates and times can also be represented by text, while durations can also be represented by text and
by numbers. Therefore, you can compare datetime arrays to text and duration arrays to text and
numbers. Relational operators convert text and numbers to the correct data types before performing
operations.
You cannot compare a datetime array and a duration array. However, you can compare
components of datetime arrays to numbers or to duration arrays.
Create a datetime array. To convert text representing a date and time, use the datetime function.
d1 = datetime("2022-06-05 11:37:05")
d1 = datetime
05-Jun-2022 11:37:05
Create another datetime array by converting input numeric arrays that represent datetime
components—years, months, days, hours, minutes, and seconds.
d2 = datetime(2022,2:4:10,15,12,0,0)
d2 = 1x3 datetime
15-Feb-2022 12:00:00 15-Jun-2022 12:00:00 15-Oct-2022 12:00:00
Compare the two datetime arrays. The result shows which elements of d2 occur after d1.
tf = d2 > d1
0 1 1
To create a datetime array containing only the matching elements, index into d2 using tf.
7-37
7 Dates and Time
afterd1 = d2(tf)
If you have text that represents dates and times in a format that the datetime function recognizes,
then you can compare the text to a datetime array. The comparison implicitly converts the text.
For example, compare d2 to a string that represents June 1, 2022. (If the string only specifies a date,
then the implicit conversion to datetime sets the time to midnight.) The first element of d2 occurs
before June 1.
tf = d2 >= "2022-06-01"
0 1 1
afterJune1 = d2(tf)
The datetime data type provides access to the components of datetime values. Access components
by using the year, quarter, month, day, hour, minute, and second functions. You can compare
components to numbers or duration values because these functions return numbers.
For example, display the datetime array d2. Then display its month component.
d2
d2 = 1x3 datetime
15-Feb-2022 12:00:00 15-Jun-2022 12:00:00 15-Oct-2022 12:00:00
m = month(d2)
m = 1×3
2 6 10
Another way to access the month component is by using the Month property of d2. You can access
datetime components by their Year, Month, Day, Hour, Minute, and Second properties.
m = d2.Month
m = 1×3
2 6 10
7-38
Compare Dates and Time
To find the elements of d2 that occur before the month of June, compare d2 to the numeric value
corresponding to June. Then index into d2.
tf = month(d2) < 6
1 0 0
beforeJune = d2(tf)
beforeJune = datetime
15-Feb-2022 12:00:00
Create a duration array. To convert text in hh:mm:ss format, use the duration function.
t1 = duration("03:37:12")
t1 = duration
03:37:12
Create another duration array by converting input numeric arrays that represent hours, minutes,
and seconds.
t2 = duration(0:2:6,30,0)
t2 = 1x4 duration
00:30:00 02:30:00 04:30:00 06:30:00
Compare the two duration arrays. The result show which elements of t2 are longer than t1.
tf = t2 > t1
0 0 1 1
To create a new duration array containing only the matching elements, index into t2 using tf.
longerThanT1 = t2(tf)
If you have text that represents a length of time in a format that the duration function recognizes,
then you can compare the text to a duration array. The comparison implicitly converts the text.
For example, compare t2 to a string that represents two hours and five minutes. The first element of
t2 is shorter.
7-39
7 Dates and Time
tf = t2 >= "02:05:00"
0 1 1 1
longerThan205 = t2(tf)
You can compare numeric arrays to duration arrays. The comparison treats a numeric value as a
number of fixed-length (24-hour) days.
1 1 1 1
t2(tf)
Compare the elements of t2 to one hour. Only the first element of t2 is shorter.
tf = t2 < 1/24
1 0 0 0
t2(tf)
ans = duration
00:30:00
Create datetime values for October 1, 2022, at 4:00 p.m. in Los Angeles and October 1, 2022 at
5:00 p.m. in New York. The two cities are in different time zones.
You can create datetime arrays with time zones by specifying the TimeZone name-value argument.
To show the time zone when displaying these values, specify the Format name-value argument. Note
that you can specify a datetime display format that differs from the format of the input text.
LAtime = datetime("2022-10-01 16:00:00", ...
"TimeZone","America/Los_Angeles",...
"Format","dd-MMM-yyyy hh:mm:ss a z")
7-40
Compare Dates and Time
LAtime = datetime
01-Oct-2022 04:00:00 PM PDT
NYtime = datetime
01-Oct-2022 05:00:00 PM EDT
Compare the times in the two cities. On the same day, 4:00 p.m. in Los Angeles occurs after 5:00 p.m.
in New York. When you specify time zones, comparisons of datetime arrays account for the time
zone information of each array.
tf = logical
1
Compare two datetime values with the same clock time using the == operator. The two values are
not equal because their time zones are different.
NYtime4 = datetime
01-Oct-2022 04:00:00 PM EDT
tf = NYtime4 == LAtime
tf = logical
0
You cannot compare a datetime array with a time zone to a datetime array without a time zone. If
only one datetime array has a time zone, then there is not enough information for a comparison.
7-41
7 Dates and Time
For example, determine if any elements of a datetime array occur during the first quarter of 2022.
(The end of the first quarter is the same as the first moment of the second quarter.)
start1Q = datetime("2022-01-01");
end1Q = datetime("2022-04-01");
d = datetime(2022,2:4:10,15,12,0,0)
d = 1x3 datetime
15-Feb-2022 12:00:00 15-Jun-2022 12:00:00 15-Oct-2022 12:00:00
To determine which elements of d are between the start and the end of the first quarter, use
isbetween. Specify the time interval between start1Q and end1Q as an open-right interval.
tf = isbetween(d,start1Q,end1Q,"openright")
1 0 0
When you use isbetween and specify an open-right interval, it is equivalent to this expression. The
interval includes the moment at the start of January 1, 2022 and every moment up to, but not
including, the start of April 1, 2022. When you specify the end of a time period by using the start of
the next time period, consider that time period to be an open-right time interval.
1 0 0
d(tf)
ans = datetime
15-Feb-2022 12:00:00
Specify the time zone of d by setting its TimeZone property. Then determine if any elements occur
during daylight saving time.
d.TimeZone = "America/New_York";
isdst(d)
0 1 1
7-42
Compare Dates and Time
isweekend(d)
0 0 1
To show the day of the week of the matching elements, use the day function.
weekendDays = d(isweekend(d))
weekendDays = datetime
15-Oct-2022 12:00:00
day(weekendDays,"name")
See Also
datetime | duration | isbetween | isdst | isweekend | ismissing | day | month
More About
• “Set Date and Time Display Format” on page 7-15
• “Specify Time Zones” on page 7-5
• “Generate Sequence of Dates and Time” on page 7-19
• “Extract or Assign Date and Time Components of Datetime Array” on page 7-27
• “Date and Time Arithmetic” on page 7-32
• “Convert Between Text and datetime or duration Values” on page 7-56
• “Array Comparison with Relational Operators” on page 2-16
7-43
7 Dates and Time
This example shows how to create line plots with dates and times that are stored as datetime and
duration arrays. The datetime data type represents points in time, such as August 24, 2020,
10:50:30 a.m., while the duration data type represents lengths of time, such as 12 hours and 30
minutes. Most plotting functions accept datetime and duration arrays as x-, y-, and z-coordinates
and show tick values with appropriate date and time units. You can specify your own axis limits and
tick values using datetime and duration values. You can also change the format of tick values to
show date and time units of your choice. Data tips show datetime and duration values for cursor
positions on a plot, and you can export those values to workspace variables. When you read data from
a spreadsheet or comma-separated value (CSV) file, you can include the date and time data in your
plots.
You can plot datetime and duration arrays without converting them to numeric arrays. Most
plotting functions accept datetime and duration arrays as input arguments.
For example, plot a data set that has datetime values on the x-axis and numeric values on the y-axis.
The x-coordinates are the datetime values for every day in June and July 2021. The plot
automatically displays tick values with an appropriate format on the x-axis. In this case, the
appropriate format shows month names and day numbers with the year.
7-44
Plot Dates and Times
Similarly, plot a data set that has duration values on the x-axis. To create a duration array in units
of seconds, use the seconds function.
XTimes = seconds(0:120);
YNumsForXTimes = cos(0:0.05:6);
plot(XTimes,YNumsForXTimes)
7-45
7 Dates and Time
When you change the limits on a plot, the tick values that are shown for datetime and duration
values are updated automatically. You can update limits interactively or by calling the xlim, ylim, or
zlim functions for the corresponding axis. Specify the new limits as a datetime or duration array.
If you change limits to zoom in or zoom out far enough, then the tick values can show other date and
time components, not just new tick values.
For example, plot the XDates and YNumsForXDates arrays. Then change the x-axis limits to June 20
and July 7, 2021, using xlim. The plot displays new tick values.
plot(XDates,YNumsForXDates)
xlim([datetime("2021-06-20") datetime("2021-07-07")])
7-46
Plot Dates and Times
Change the x-axis limits to June 20 and June 22, 2021. The tick values show hour and minute
components in hh:mm format because the plot is zoomed in enough to show smaller time units on the
x-axis.
xlim([datetime("2021-06-20") datetime("2021-06-22")])
7-47
7 Dates and Time
You do not have to change axes limits to change tick values. Instead, you can specify your own tick
values along the x-, y-, or z-axes by using the xticks, yticks, or zticks functions. Specify the tick
values as a datetime or duration array.
For example, plot the XTimes and YNumsForXTimes arrays. Then specify tick values at 0, 60, and
120 seconds by using xticks.
plot(XTimes,YNumsForXTimes)
xticks(seconds([0 60 120]))
7-48
Plot Dates and Times
Plotting functions use default formats to display datetime and duration values as tick values. To
override the format for the tick values on an axis, use the xtickformat, ytickformat, or
ztickformat functions.
For example, plot XDates and YNumsForXDates. Specify a tick value format showing year, month,
and day numbers by using xtickformat.
plot(XDates,YNumsForXDates)
xtickformat("yyyy-MM-dd")
7-49
7 Dates and Time
As an alternative, you can also call plot with the DatetimeTickFormat or DurationTickFormat
name-value arguments. For example, this call to the plot function creates the same plot.
plot(XDates,YNumsForXDates,"DatetimeTickFormat","yyyy-MM-dd")
However, these name-value arguments can be used with the plot function only. You can use
functions such as xtickformat after calling any plotting function, such as scatter, stem, and
stairs.
Axis limits, the locations of tick labels, and the x-, y-, and z-values for datetime and duration
arrays in line plots are also stored as properties of an Axes object. These properties represent those
aspects of line plots.
For example, the XLim and XTick properties associated with the plot of XDates and
YNumsForXDates store datetime values. Get the Axes object for the plot and display these
properties.
ax = gca;
ax.XLim
7-50
Plot Dates and Times
ax.XTick
When you click on a plot, you create a data tip at that cursor position that displays its x- and y-
coordinates. Data tips display numeric values as well as datetime and duration values. However,
when you export the cursor data to the workspace, the coordinates are reported as a pair of numeric
values. To convert exported cursor data to the datetime or duration value, use the num2ruler
function.
For example, plot XDates and YNumsForXDates. Then create a data tip by clicking on the plot.
To export the cursor data to the workspace, right-click the data tip and select Export Cursor Data
to Workspace. This action exports the cursor data to a structure in the workspace.
cursor_info =
7-51
7 Dates and Time
The cursor_info.Position field represents the cursor data as a pair of numeric values. The Axes
object associated with the plot has the information needed to convert the numeric value of the x-
coordinate to a datetime value. Get the Axes object for the plot. Then pass the numeric x-
coordinate and the x-axis from the Axes object to num2ruler.
ax = gca;
datetimePosition = num2ruler(cursor_info.Position(1),ax.XAxis)
datetimePosition =
datetime
26-Jun-2021
You do not need to convert the numeric y-coordinate, cursor_info.Position(2) because the y-
values in this plot are numeric.
Data files such as spreadsheets and CSV files often store dates and times as formatted text. When you
read in data from such files, you can convert text representing dates and times to datetime or
duration arrays. Then you can create plots of that data.
For example, create a plot of data from the example data file outages.csv. This CSV file contains six
columns of data. Two columns contain text that represent dates and times.
Region,OutageTime,Loss,Customers,RestorationTime,Cause
SouthWest,2002-02-01 12:18,458.9772218,1820159.482,2002-02-07 16:50,winter storm
SouthEast,2003-01-23 00:49,530.1399497,212035.3001,,winter storm
SouthEast,2003-02-07 21:15,289.4035493,142938.6282,2003-02-17 08:14,winter storm
...
The recommended way to read data from a CSV file is to use the readtable function. This function
reads data from a file and returns it in a table.
Read in outages.csv. The readtable function automatically converts the text in the OutageTime
and RestorationTime columns to datetime arrays. The columns that represent numbers (Loss
and Customers) are read in as numeric arrays. The remaining columns are read in as strings. The
table stores the columns of data from outages.csv in table variables that have the same names.
Finally, sort the rows of T by the dates and times in OutageTime by using the sortrows function. If
a table is not sorted by time, then it is a best practice to sort the table by time before plotting or
analyzing the data.
T = readtable("outages.csv","TextType","string");
T = sortrows(T,"OutageTime")
T=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
7-52
Plot Dates and Times
You can access table variables by using dot notation, referring to a table variable by name. With dot
notation, you can treat table variables like arrays.
Plot the power loss against outage time. To access these variables from the table, use dot notation.
plot(T.OutageTime,T.Loss)
Calculate the durations of the power outages and plot them against OutageTime. To calculate the
durations, subtract OutageTime from RestorationTime. The result, OutageDuration, is a
duration array, because arithmetic with datetime values produces lengths of time as output. Some
of these outage durations are long, so change the format of the y-axis tick values from hours to years
7-53
7 Dates and Time
by using ytickformat. The fact that some outages apparently last for years indicates there might be
a few questionable data values in the file. Depending on how you plan to analyze the data, you can
either reprocess it in some way or remove the rows containing bad values.
See Also
plot | datetime | duration | seconds | readtable | sortrows | xlim | xtickformat | xticks
Related Examples
• “2-D and 3-D Plots”
• “Types of MATLAB Plots”
• “Generate Sequence of Dates and Time” on page 7-19
• “Compare Dates and Time” on page 7-37
• “Date and Time Arithmetic” on page 7-32
• “Convert Between Text and datetime or duration Values” on page 7-56
7-54
Core Functions Supporting Date and Time Arrays
This table lists notable MATLAB functions that operate on datetime, duration, and
calendarDuration arrays in addition to other arrays.
7-55
7 Dates and Time
This example shows how to convert between text and data types that represent dates and times. The
datetime data type represents points in time, such as August 24, 2020, 10:50:30 a.m., and the
duration data type represents lengths of time, such as 3 hours, 47 minutes, and 16 seconds. A
common reason for converting dates and times to text is to append them to strings that are used as
plot labels or file names. Similarly, if a file has columns of data that store dates and times as text, you
can read the data from those columns into datetime or duration arrays, making the data more
useful for analysis.
To convert:
• datetime or duration values to text, use the string function. (You can also use the char
function to convert these values to character vectors.)
• text to datetime values, use the datetime function.
• text to duration values, use the duration function.
Also, some functions, such as the readcell, readvars, and readtable functions, read text from
files and automatically convert text representing dates and times to datetime or duration arrays.
Create a datetime value that represents the current date and time.
d = datetime("now")
d = datetime
23-Jan-2025 16:57:36
str = string(d)
str =
"23-Jan-2025 16:57:36"
Similarly, you can convert duration values. For example, first create a duration value that
represents 3 hours and 30 minutes. One way to create this value is to use the hours and minutes
functions. These functions create duration values that you can then combine.
d = hours(3) + minutes(30)
d = duration
3.5 hr
Convert d to text.
str = string(d)
str =
"3.5 hr"
7-56
Convert Between Text and datetime or duration Values
One common use of such strings is to add them to plot labels or file names. For example, create a
simple plot with a title that includes today's date. First convert the date and add it to the string
myTitle.
d = datetime("today")
d = datetime
23-Jan-2025
myTitle =
"Plot generated on: 23-Jan-2025"
plot(rand(10,1))
title(myTitle)
You can also convert arrays of datetime or duration values. When you convert them by using the
string function, the resulting string array has the same size.
D = datetime(2021,1:3,15,12,0,0)'
7-57
7 Dates and Time
D = 3x1 datetime
15-Jan-2021 12:00:00
15-Feb-2021 12:00:00
15-Mar-2021 12:00:00
str = string(D)
Similarly, you can create a duration array and convert it. One way to create a duration array is to
use the duration function. Call it with numeric inputs that specify hours, minutes, and seconds.
D = duration(1:3,30,0)'
D = 3x1 duration
01:30:00
02:30:00
03:30:00
str = string(D)
The datetime and duration data types have properties that specify the format for display. Live
scripts and the Command Window use that format to display values. When you convert datetime or
duration arrays by using the string function, you can specify a different format.
d = datetime("now")
d = datetime
23-Jan-2025 16:57:37
Specify a format using letter identifiers for the full name of the month, the day, year, and time.
Convert d to a string that represents the date and time using that format.
str =
"23 January 2025, 04:57:37 PM"
7-58
Convert Between Text and datetime or duration Values
Similarly, you can specify a format when you convert a duration array. First create a duration
value.
d = hours(1) + minutes(30) + seconds(45)
d = duration
1.5125 hr
Convert d to a string using the identifiers hh:mm:ss for the hour, minute, and second.
fmt = "hh:mm:ss";
string(d,fmt)
ans =
"01:30:45"
Note: The string function does not provide a second input argument for a format when converting
other data types.
You can also convert datetime and duration arrays using different locales. The locale provides
appropriate names for the day and month. To use a locale that is not the default locale, provide it as
another input argument.
For example, specify fr_FR as the locale to represent the current date and time using the French
name for the month.
d = datetime("now")
d = datetime
23-Jan-2025 16:57:37
str =
"23 janvier 2025, 04:57:37 PM"
Similarly, you can specify a locale when you convert duration arrays. The locale for France uses a
different abbreviation for hours.
d = hours(5)
d = duration
5 hr
fmt = "h";
locale = "fr_FR";
str = string(d,fmt,locale)
str =
"5 h"
Note: The string function does not provide a third input argument for a locale when converting
other data types.
7-59
7 Dates and Time
You can convert text to datetime values if the text specifies dates and times in a format that the
datetime function recognizes.
str =
"2021-09-15 09:12:34"
d = datetime(str)
d = datetime
15-Sep-2021 09:12:34
The datetime function recognizes many commonly used text formats. However, if your text is in a
format that datetime does not recognize, you can specify the format as an input argument.
For example, create a string that specifies a date and time using the ISO 8601 standard.
str = "2021-09-15T091234"
str =
"2021-09-15T091234"
The datetime function does not recognize this format. To convert this string to a datetime value,
specify the format of the input text. Then call the datetime function. (When the format includes
literal text, enclose it in quotation marks. In this example specify the literal text T as 'T'.)
infmt = "yyyy-MM-dd'T'HHmmss";
d = datetime(str,"InputFormat",infmt)
d = datetime
15-Sep-2021 09:12:34
You can convert text to duration values if the text specifies times in a format that the duration
function recognizes.
str = "00:34:01"
str =
"00:34:01"
d = duration(str)
7-60
Convert Between Text and datetime or duration Values
d = duration
00:34:01
The duration function recognizes formats that specify days, hours, minutes, and seconds separated
by colons. These formats are:
• "dd:hh:mm:ss"
• "hh:mm:ss"
• "mm:ss"
• "hh:mm"
• Any of the first three formats, with up to nine S characters to indicate fractional second digits,
such as "hh:mm:ss.SSSS"
If the input text is ambiguous, which means that it could be interpreted as matching the "mm:ss" or
"hh:mm" formats, specify the format as an input argument.
str =
"34:01"
To convert this string to a duration of 34 minutes and 1 second, specify the format. Then call the
duration function.
infmt = "mm:ss";
d = duration(str,"InputFormat",infmt)
d = duration
00:34:01
Many files, such as spreadsheets and text files, store dates and times as text. If the dates and times
are in recognized formats, then functions such as readcell, readvars, and readtable can read
them and automatically convert them to datetime or duration arrays.
For example, the CSV file outages.csv is a sample file that is distributed with MATLAB®. The file
contains data for a set of electrical power outages. The first line of outages.csv has column names.
The rest of the file has comma-separated data values for each outage. The file has 1468 lines of data.
The first few lines are shown here.
Region,OutageTime,Loss,Customers,RestorationTime,Cause
SouthWest,2002-02-01 12:18,458.9772218,1820159.482,2002-02-07 16:50,winter storm
SouthEast,2003-01-23 00:49,530.1399497,212035.3001,,winter storm
SouthEast,2003-02-07 21:15,289.4035493,142938.6282,2003-02-17 08:14,winter storm
West,2004-04-06 05:44,434.8053524,340371.0338,2004-04-06 06:10,equipment fault
MidWest,2002-03-16 06:18,186.4367788,212754.055,2002-03-18 23:23,severe storm
...
To read the first three columns from outages.csv and store them directly in arrays, use the
readvars function. To read text into variables that store string arrays, specify the TextType name-
7-61
7 Dates and Time
value argument. However, the function recognizes the values in the second column of the CSV file as
dates and times and creates the OutageTime variable as a datetime array. Display the first five
rows of each output array.
[Region,OutageTime,Loss] = readvars("outages.csv","TextType","string");
whos Region OutageTime Loss
Loss(1:5)
ans = 5×1
458.9772
530.1399
289.4035
434.8054
186.4368
OutageTime(1:5)
Region(1:5)
To read the whole spreadsheet and store the data in a table, use the readtable function. To read
text into table variables that store string arrays, specify the TextType name-value argument.
However, readtable still converts OutageTime and RestorationTime to table variables that store
datetime arrays.
T = readtable("outages.csv","TextType","string")
T=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
7-62
Convert Between Text and datetime or duration Values
As these table variables are datetime arrays, you can perform convenient calculations with them.
For example, you can calculate the durations of the power outages and attach them to the table as a
duration array.
T=1468×7 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
See Also
char | string | duration | datetime | hours | minutes | seconds | readcell | readvars |
readtable | readtimetable | table | timetable
More About
• “Represent Dates and Times in MATLAB” on page 7-2
• “Generate Sequence of Dates and Time” on page 7-19
• “Extract or Assign Date and Time Components of Datetime Array” on page 7-27
• “Compare Dates and Time” on page 7-37
7-63
7 Dates and Time
External Websites
• Proleptic Gregorian Calendar
7-64
Replace Discouraged Instances of Serial Date Numbers and Date Strings
In particular, the datetime data type provides many advantages over serial date numbers. These
advantages include:
• Flexible formats for both output display and input text parsing
• Storage for fractional seconds out to nanosecond precision
• Properties to account for time zones, daylight saving time, and leap seconds
MATLAB functions offer equivalent support for datetime arrays. That is, functions that accept serial
date numbers or date strings as inputs also accept datetime arrays as inputs. For example, the plot
function accepts both serial date numbers and datetime arrays. If you specify datetime arrays,
then plot automatically formats axis and tick labels using properties of the datetime inputs. This
plotting capability is another example of the advantages provided by datetime arrays.
This topic shows you how to remove serial date numbers and date strings from your MATLAB code.
You can convert them to the recommended data types, replace functions and syntaxes that use serial
date numbers or date strings, and update your own functions while maintaining backward
compatibility.
7-65
7 Dates and Time
times as serial date numbers. The datestr function returns dates and times as date strings.
Functions such as date, now, and today return serial date numbers or date strings. These functions
are not recommended.
This table describes common date and time operations, the discouraged functions that perform these
operations, and their recommended replacements. There are no plans to remove the discouraged
functions described in the table.
d = datetime("2022-01-01");
d = d + hours(0:4:12)
d = datetime("2022-01-01");
d = d + calmonths(0:2)
Return current time (as a date clock Use datetime or
vector). datetime("now"), and
datevec to convert to a date
vector.
d = datetime
% or
d = datetime("now")
d = datevec(datetime)
Return current date (as text). date Use datetime("today").
d = datetime("today")
d = datetime("today");
d = string(d)
7-66
Replace Discouraged Instances of Serial Date Numbers and Date Strings
d = 738522;
d = datetime(d,"ConvertFrom","datenum")
Specify dates and times (as datestr Use the string or char
text). function.
d = datetime(2022,6,28,12,34,56)
d = string(d)
Convert date vector to text. datestr Use the string or char
function.
dv = [2022 6 28 12 34 56];
d = datetime(dv)
d = string(d)
Return last dates of months. eomdate Use the dateshift function
with datetime values as inputs.
d = datetime("today")
endMonth = dateshift(d,"end","month")
y = 2022;
m = 6;
endMonth = dateshift(datetime(y,m,1),"e
7-67
7 Dates and Time
startOfToday = datetime("today")
currentTime = datetime("now")
elapsedTime = currentTime - startOfToda
d1 = datetime("2022-01-01")
d2 = datetime("now")
elapsedTime = between(d1,d2)
Return date of last occurrence lweekdate Use the dateshift and
of weekday in month. datetime functions.
october = datetime(2021,10,1);
endOfOctober = dateshift(october,"end",
lastTuesday = dateshift(endOfOctober,"d
Convert dates and times to m2xdate Use the exceltime function.
Excel® serial date numbers.
Example: Return current date
as Excel serial date number.
d = datetime("today")
excelNum = exceltime(d)
Return number of whole months months Use the between function with
between dates. datetime values as inputs.
d1 = datetime("2021-01-01")
d2 = datetime("today")
numMonths = between(d1,d2,"months")
7-68
Replace Discouraged Instances of Serial Date Numbers and Date Strings
d = datetime
% or
d = datetime("now")
Return date of specific nweekdate Use the dateshift and
occurrence of weekday in datetime functions.
month.
Example: Return first Tuesday
of October 2021 as datetime
value.
october = datetime(2021,10,1);
firstTuesday = dateshift(october,"dayof
Return current date. today Use datetime("today").
d = datetime("today")
Return weeks in year (as weeknum Use the week function with
numbers). datetime values as inputs.
d = datetime("today")
weekNumber = week(d,"weekofyear")
Convert Excel serial date x2mdate Use the datetime with
numbers to MATLAB dates and dateType as "excel".
times.
Example: Convert Excel serial
date number to datetime
value.
excelNum = 44481
dt = datetime(excelNum,"ConvertFrom","e
7-69
7 Dates and Time
The functions that return date and time components are year, quarter, month, and so on. The
datevec, ymd, hms, and timeofday functions also return components as numeric vectors or
matrices. All of these functions support datetime arrays as inputs.
Many of these functions also support serial date numbers and date strings as inputs. However, the
syntaxes that support these inputs are not recommended. Instead, use datetime arrays as inputs.
The table shows discouraged syntaxes and recommended syntaxes for these functions.
There are no plans to remove support for serial date numbers and date strings from these functions.
• In existing code, accept datetime arrays as input arguments. If an input argument can be an
array of serial date numbers or date strings, then update your code so that the argument can also
be a datetime array.
If your code is already based on serial date numbers or date strings, then a simple and quick
method to accept datetime inputs is to convert them as the first step in the code. To convert
7-70
Replace Discouraged Instances of Serial Date Numbers and Date Strings
datetime arrays to serial date numbers, use the convertTo function. To convert datetime
arrays to date strings, use the string or char function.
For example, if your function myFunc accepts serial date numbers, update it to accept a
datetime array too. Leave the rest of your code unaltered.
function y = myFunc(d)
if (isdatetime(d))
d = convertTo(d,"datenum")
<line 1 of original code>
<line 2 of original code>
...
• In general, do not change the output type. Even if your existing code returns serial date numbers
or date strings, it is a best practice to maintain the expected output type when other users depend
on your code.
• In the long term, consider rewriting your existing code to perform time-based calculations in
terms of datetime arrays. If you simply convert datetime inputs to serial date numbers or date
strings, then you lose information in their properties, such as time zones.
• If you rewrite your code and it is code that accepted date strings as inputs, then you might need to
consider backward compatibility. To preserve backward compatibility, you can interpret date
strings in the same way that the datenum function interprets them.
d = "01/02/22";
d = matlab.datetime.compatibility.convertDatenum(d)
• In new code, use datetime arrays as the primary data type for representing points in time. Use
duration arrays as the primary type for representing elapsed times.
If you must also accept serial date numbers and date strings as input arguments, then use the
datetime function to convert them.
See Also
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Convert Between Text and datetime or duration Values” on page 7-56
• “Compare Dates and Time” on page 7-37
• “Extract or Assign Date and Time Components of Datetime Array” on page 7-27
• “Date and Time Arithmetic” on page 7-32
• “Generate Sequence of Dates and Time” on page 7-19
• “Plot Dates and Times” on page 7-44
7-71
7 Dates and Time
Note The datenum and datestr functions are not recommended. Instead, use datetime values to
represent points in time rather than serial date numbers or date vectors. Unlike these numeric
representations, datetime values display in a human-readable format, and have properties to
account for time zones and leap seconds. For more information on updating your code to use
datetime values, see “Replace Discouraged Instances of Serial Date Numbers and Date Strings” on
page 7-65.
If an element falls outside the conventional range, MATLAB adjusts both that date vector element and
the previous element. For example, if the minutes element is 70, MATLAB adjusts the hours element
by 1 and sets the minutes element to 10. If the minutes element is -15, then MATLAB decreases the
hours element by 1 and sets the minutes element to 45.
In this example, the month element has a value of 22. MATLAB increments the year value to 2022 and
sets the month to October. Both the datetime and datestr functions adjust for the month element
that is outside the conventional range. However, datestr is not recommended.
d1 = datetime([2021 22 03 00 00 00])
d1 =
datetime
03-Oct-2022
d2 = datestr([2021 22 03 00 00 00])
d2 =
'03-Oct-2022'
The functions account for negative values the same way in any component that is not a month
component. For example, these calls both take inputs with month specified as 7 (July) and the number
of days specified as -5. They both subtract five from the last day of June, which is June 30, to yield a
return date of June 25, 2022.
d1 =
datetime
25-Jun-2022
d2 =
'25-Jun-2022'
The exception to this rule occurs when the month component is a number less than 1. In that case,
datetime and datestr behave differently. The datetime function subtracts the month component
from the beginning of the year component, so that the output date occurs during the previous year.
7-72
Carryover in Date Vectors and Strings
For example, this call with inputs for the year 2022 returns a date of July 3, 2021 because the month
component is -5.
d1 = datetime([2022 -5 3 0 0 0])
d1 =
datetime
03-Jul-2021
However, datestr instead sets the month component of the output to January 2022. When the input
has a month component that is less than 1, datestr treats it as 1.
d2 = datestr([2022 -5 3 0 0 0])
d2 =
'03-Jan-2022'
The carrying forward of values also applies when you use the datenum function to convert text
representing dates and times. For example, datenum interprets October 3, 2022 and September 33,
2022 as the same date, and returns the same serial date number. But again, datenum is not
recommended.
d = datenum("2022-10-03")
d =
738797
d = datenum("2022-09-33")
d =
738797
However, the datetime function does not interpret the text representing September 33, 2022. It
does not attempt to carry over values in text that specifies dates and times outside convention
ranges. Instead the result is an error.
d = datetime("2022-10-03")
d =
datetime
03-Oct-2022
d = datetime("2022-09-33")
7-73
7 Dates and Time
Note The datenum and datestr functions are not recommended. Instead, use datetime values to
represent points in time rather than serial date numbers or date vectors. Unlike these numeric
representations, datetime values display in a human-readable format, often avoiding the need for
conversion to text.
If you need to convert a date vector to text, the best practice is to first convert it to a datetime
value, and then to convert the datetime value to text by using the string or char functions. For
more information on updating your code to use datetime values, see “Replace Discouraged
Instances of Serial Date Numbers and Date Strings” on page 7-65.
While you can convert date vectors to text directly by using the datestr function, you might get
unexpected results, as described in this section.
Because a date vector is a 1-by-6 row vector of numbers, the datestr function might interpret input
date vectors as vectors of serial date numbers and return unexpected output. Or it might interpret
vectors of serial date numbers as date vectors. This ambiguity exists because datestr has a
heuristic rule for interpreting a 1-by-6 row vector as either a date vector or a vector of six serial date
numbers. The same ambiguity applies to inputs that are m-by-6 numeric matrices, where each row
can be interpreted either as a date vector or as six serial date numbers.
For example, consider a date vector that includes the year 3000. This year is outside the range of
years that datestr interprets as elements of date vectors. Therefore, the input is interpreted as a 1-
by-6 vector of serial date numbers.
d = datestr([3000 11 05 10 32 56])
d =
'18-Mar-0008'
'11-Jan-0000'
'05-Jan-0000'
'10-Jan-0000'
'01-Feb-0000'
'25-Feb-0000'
Here datestr interprets 3000 as a serial date number, and converts it to the text '18-Mar-0008'
(the date that is 3000 days after 0-Jan-0000). Also, datestr converts the next five elements as
though they also were serial date numbers.
There are two methods for converting such a date vector to text.
• The recommended method is to convert the date vector to a datetime value. Then convert it
using the char, cellstr, or string function. The datetime function always treats 1-by-6
numeric vectors as date vectors.
dt = datetime([3000 11 05 10 32 56]);
ds = string(dt)
7-74
Converting Date Vector Returns Unexpected Output
dt =
"05-Nov-3000 10:32:56"
• As an alternative, convert it to a serial date number using the datenum function. Then, convert
the date number to a character vector using datestr.
dn = datenum([3000 11 05 10 32 56]);
ds = datestr(dn)
ds =
'05-Nov-3000 10:32:56'
When converting dates to text, datestr interprets input as either date vectors or serial date
numbers using a heuristic rule. Consider an m-by-6 matrix. The datestr function interprets the
matrix as m date vectors when:
If either condition is false, for any row, then datestr interprets the m-by-6 matrix as an m-by-6 matrix
of serial date numbers.
Usually, dates with years in the range 1700–2300 are interpreted as date vectors. However, datestr
might interpret rows with month, day, hour, minute, or second values outside their normal ranges as
serial date numbers. For example, datestr correctly interprets the following date vector for the year
2020:
d = datestr([2020 06 21 10 51 00])
d =
'21-Jun-2020 10:51:00'
But given a day value outside the typical range (1–31), datestr returns a date for each element of
the vector.
d =
'12-Jul-0005'
'06-Jan-0000'
'10-Oct-0005'
'10-Jan-0000'
'20-Feb-0000'
'00-Jan-0000'
Again, the datetime function always treats numeric inputs as date vectors. In this case, it calculates
an appropriate date, interpreting 2110 as the 2110th day since the beginning of June 2020.
d =
7-75
7 Dates and Time
datetime
11-Mar-2026 10:51:00
• When you have a matrix of date vectors that datestr might interpret incorrectly as serial date
numbers, convert the matrix by using either the datetime or datenum functions. Then convert
those values to text.
• When you have a matrix of serial date numbers that datestr might interpret as date vectors, first
convert the matrix to a column vector. Then, use datestr to convert the column vector.
See Also
datetime | datevec | char | string
More About
• “Represent Dates and Times in MATLAB” on page 7-2
• “Convert Between Text and datetime or duration Values” on page 7-56
7-76
8
Categorical Arrays
This example shows how to create categorical arrays from various types of input data and modify
their elements. The categorical data type stores values from a finite set of discrete categories. You
can create a categorical array from a numeric array, logical array, string array, or cell array of
character vectors. The unique values from the input array become the categories of the categorical
array. A categorical array provides efficient storage and convenient manipulation of data while also
maintaining meaningful names for the values.
By default, the categories of a categorical array do not have a mathematical ordering. For example,
the discrete set of pet categories ["dog" "cat" "bird"] has no meaningful mathematical
ordering, so MATLAB® uses the alphabetical ordering ["bird" "cat" "dog"]. But you can also
create ordinal categorical arrays, in which the categories do have meaningful mathematical
orderings. For example, the discrete set of size categories ["small" "medium" "large"] can
have the mathematical ordering of small < medium < large. Ordinal categorical arrays enable
you to make comparisons between their elements.
To create a categorical array from an input array, use the categorical function.
For example, create a string array whose elements are all states from New England. Notice that some
of the strings have leading and trailing spaces.
statesNE = ["MA" "ME" " CT" "VT" " ME " "NH" "VT" "MA" "NH" "CT" "RI "]
Convert the string array to a categorical array. When you create categorical arrays from string arrays
(or cell arrays of character vectors), leading and trailing spaces are removed.
statesNE = categorical(statesNE)
List the categories of statesNE by using the categories function. Every element of statesNE
belongs to one of these categories. Because statesNE has six unique states, there are six categories.
The categories are listed in alphabetical order because the state abbreviations have no mathematical
ordering.
categories(statesNE)
8-2
Create Categorical Arrays
To add one element to a categorical array, you can assign text that represents a category name. For
example, add a state to statesNE.
statesNE(12) = "ME"
You can assign missing values as undefined elements of a categorical array. An undefined categorical
value does not belong to any category, similar to NaN (Not-a-Number) in numeric arrays.
To assign missing values, use the missing function. For example, modify the first element of the
categorical array to be a missing value.
statesNE(1) = missing
If you convert a string array to a categorical array, then missing strings and empty strings become
undefined elements in the categorical array. If you convert a numeric array, then NaNs become
undefined elements. Therefore, assigning missing strings, "", '', or NaNs to elements of a
categorical array converts them to undefined categorical values.
statesNE(2) = ""
In an ordinal categorical array, the order of the categories defines a mathematical order that enables
comparisons. Because of this mathematical order, you can compare elements of an ordinal categorical
array using relational operators. You cannot compare elements of categorical arrays that are not
ordinal.
8-3
8 Categorical Arrays
For example, create a string array that contains the sizes of eight objects.
AllSizes = ["medium" "large" "small" "small" "medium" ...
"large" "medium" "small"];
The string array has three unique values: "large", "medium", and "small". A string array has no
convenient way to indicate that small < medium < large.
Convert the string array to an ordinal categorical array. Define the categories as small, medium, and
large, in that order. For an ordinal categorical array, the first category specified is the smallest and
the last category is the largest.
valueset = ["small" "medium" "large"];
sizeOrd = categorical(AllSizes,valueset,"Ordinal",true)
The order of the values in the categorical array, sizeOrd, remains unchanged.
List the discrete categories in sizeOrd. The order of the categories matches their mathematical
ordering small < medium < large.
categories(sizeOrd)
If you have an array with continuous numeric data, specifying numeric ranges as categories can be
useful. In such cases, bin the data using the discretize function. Assign category names to the
bins.
For example, create a vector of 100 random numbers between 0 and 50.
x = rand(100,1)*50
x = 100×1
40.7362
45.2896
6.3493
45.6688
31.6180
4.8770
13.9249
27.3441
47.8753
48.2444
⋮
Use discretize to create a categorical array by binning the values of x. Put all the values between
0 and 15 in the first bin, all the values between 15 and 35 in the second bin, and all the values
8-4
Create Categorical Arrays
between 35 and 50 in the third bin. Each bin includes the left endpoint but does not include the right
endpoint, except the last bin.
catnames = ["small" "medium" "large"];
binnedData = discretize(x,[0 15 35 50],"categorical",catnames)
binnedData is an ordinal categorical array with three categories, such that small < medium <
large.
To display the number of elements in each category, use the summary function.
summary(binnedData)
small 30
medium 35
large 35
<undefined> 0
Additional statistics:
Min small
Median medium
Max large
8-5
8 Categorical Arrays
You can make various kinds of charts of the binned data. For example, make a pie chart of
binnedData.
pie(binnedData)
You can preallocate a categorical array of any size by creating an array of NaNs and converting it to a
categorical array. After you preallocate the array, you can initialize its categories by adding the
category names to the array.
A = NaN(2,4)
A = 2×4
Then convert the array of NaNs to a categorical array of undefined categorical values.
A = categorical(A)
A = 2x4 categorical
<undefined> <undefined> <undefined> <undefined>
8-6
Create Categorical Arrays
categories(A)
ans =
Add small, medium, and large categories to A is by using the addcats function.
A = 2x4 categorical
<undefined> <undefined> <undefined> <undefined>
<undefined> <undefined> <undefined> <undefined>
While the elements of A are still undefined values, the categories of A are defined.
categories(A)
Now that A has categories, you can assign defined categorical values as elements of A.
A(1) = "medium";
A(8) = "small";
A(3:5) = "large"
A = 2x4 categorical
medium large large <undefined>
<undefined> large <undefined> small
See Also
categorical | categories | discretize | summary | addcats | missing
Related Examples
• “Advantages of Using Categorical Arrays” on page 8-46
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Access Data Using Categorical Arrays” on page 8-33
• “Ordinal Categorical Arrays” on page 8-48
• “Compare Categorical Array Elements” on page 8-19
8-7
8 Categorical Arrays
This example shows how to convert variables in a table from text to categorical arrays. The same
workflow applies for table variables that are string arrays and variables that are cell arrays of
character vectors.
load patients
Store the patient data from Age, Height, Weight, SelfAssessedHealthStatus, and Location in
a table. Use the unique identifiers in the variable LastName as row names. To convert variables that
are cell arrays of character vectors to string arrays, use the convertvars function.
T = table(Age,Height,Weight,Smoker,...
SelfAssessedHealthStatus,Location,...
'RowNames',LastName);
T = convertvars(T,@iscellstr,"string")
T=100×6 table
Age Height Weight Smoker SelfAssessedHealthStatus Locatio
___ ______ ______ ______ ________________________ ________________
The variables, Location and SelfAssessedHealthStatus, contain discrete sets of unique values.
When a variable contains a set of values that can be thought of as categories, such as locations or
statuses, consider converting it to a categorical variable.
T.Location = categorical(T.Location);
The variable, SelfAssessedHealthStatus, contains four unique values: Excellent, Fair, Good,
and Poor.
8-8
Convert Text in Table Variables to Categorical
T.SelfAssessedHealthStatus = categorical(T.SelfAssessedHealthStatus,...
{'Poor','Fair','Good','Excellent'},'Ordinal',true);
Print a Summary
View the data type, description, units, and other descriptive statistics for each variable by using
summary to summarize the table.
format compact
summary(T)
T: 100x6 table
Variables:
Age: double
Height: double
Weight: double
Smoker: logical (34 true)
SelfAssessedHealthStatus: ordinal categorical (4 categories)
Location: categorical (3 categories)
Statistics for applicable variables:
NumMissing Min Median Max Mea
Age 0 25 39 50 38.2
Height 0 60 67 72 67.0
Weight 0 111 142.5000 202
SelfAssessedHealthStatus 0 Poor Good Excellent
Location 0
The table variables SelfAssessedHealthStatus and Location are categorical arrays. The
summary contains the counts of the number of elements in each category. For example, the summary
indicates that 11 of the 100 patients assess their own health as poor and 34 assess their health as
excellent.
Create a subtable, T1, containing the age, height, and weight of all patients who were observed at
County General Hospital and assesses their own health as excellent. You can easily create a logical
vector based on the values in the categorical arrays Location and
SelfAssessedHealthStatus.
rows is a 100-by-1 logical vector with logical true (1) for the table rows where the location is County
General Hospital and the patients assessed their health as excellent.
vars = ["Age","Height","Weight"];
T1 = T(rows,vars)
T1=13×3 table
Age Height Weight
8-9
8 Categorical Arrays
Since ordinal categorical arrays have a mathematical ordering for their categories, you can
perform elementwise comparisons of them with relational operations, such as greater than and less
than.
Create a subtable, T2, of the age, height, and weight of all patients who assessed their health status
as poor or fair.
rows = T.SelfAssessedHealthStatus<='Fair';
vars = ["Age","Height","Weight"];
T2 = T(rows,vars)
T2=26×3 table
Age Height Weight
___ ______ ______
Johnson 43 69 163
Jones 40 67 133
Thomas 42 66 137
Jackson 25 71 174
Garcia 27 69 131
Rodriguez 39 64 117
Lewis 41 62 137
Lee 44 66 146
Hall 25 70 189
Hernandez 36 68 166
Lopez 40 66 137
Gonzalez 35 66 118
Mitchell 39 71 164
Campbell 37 65 135
Parker 30 68 182
Stewart 49 68 170
8-10
Convert Text in Table Variables to Categorical
See Also
Related Examples
• “Create Tables and Assign Data to Them” on page 9-2
• “Create Categorical Arrays” on page 8-2
• “Access Data in Tables” on page 9-37
• “Access Data Using Categorical Arrays” on page 8-33
More About
• “Advantages of Using Categorical Arrays” on page 8-46
• “Ordinal Categorical Arrays” on page 8-48
8-11
8 Categorical Arrays
Load sample data gathered from 100 patients. Display the data types and sizes of the arrays from the
patients MAT-file.
load patients
whos
The workspace variable, Location, lists three unique medical facilities where patients were
observed.
To access and compare data more easily, convert Location to a categorical array.
Location = categorical(Location);
Summarize the categorical array. The summary displays the number of times each category appears
in Location.
summary(Location)
39 patients were observed at County General Hospital, 24 at St. Mary's Medical Center, and 37 at the
VA Hospital.
Convert SelfAssessedHealthStatus to an ordinal categorical array, such that the categories have
the mathematical ordering Poor < Fair < Good < Excellent.
8-12
Plot Categorical Data
summary(SelfAssessedHealthStatus)
Poor 11
Fair 15
Good 40
Excellent 34
<undefined> 0
Additional statistics:
Min Poor
Median Good
Max Excellent
Plot Histogram
Create a histogram bar plot directly from SelfAssessedHealthStatus. This categorical array is an
ordinal categorical array. The categories have the ordering Poor < Fair < Good < Excellent,
which determines the order of the categories along the x-axis of the plot. The histogram function
plots the category counts for each of the four categories.
figure
histogram(SelfAssessedHealthStatus)
title("Self Assessed Health Status From 100 Patients")
8-13
8 Categorical Arrays
Create a histogram of the hospital location for only the patients who assessed their health as Fair or
Poor.
figure
histogram(Location(SelfAssessedHealthStatus <= "Fair"))
title("Location of Patients in Fair or Poor Health")
8-14
Plot Categorical Data
figure
pie(SelfAssessedHealthStatus);
title("Self Assessed Health Status From 100 Patients")
8-15
8 Categorical Arrays
The function pie accepts the categorical array, SelfAssessedHealthStatus, and plots a pie chart
of the four categories.
Create a Pareto chart from the category counts for each of the four categories of
SelfAssessedHealthStatus.
figure
A = countcats(SelfAssessedHealthStatus);
C = categories(SelfAssessedHealthStatus);
pareto(A,C);
title("Self Assessed Health Status From 100 Patients")
8-16
Plot Categorical Data
The first input argument to pareto must be a vector. If a categorical array is a matrix or
multidimensional array, reshape it into a vector before calling countcats and pareto.
Determine if self-assessed health is related to blood pressure readings. Create a scatter plot of
Diastolic and Systolic readings for two groups of patients.
First, create x- and y-arrays of blood pressure readings for two groups of patients. The first group of
patients consists of those who assess their self-health as either Poor or Fair. The second group
consists of those who assess their self-health as Good or Excellent.
You can use the categorical array, SelfAssessedHealthStatus, to create logical indices. Use the
logical indices to extract values from Diastolic and Systolic into different arrays.
X1 and Y1 are 26-by-1 numeric arrays containing data for the patients with Poor or Fair health.
X2 and Y2 are 74-by-1 numeric arrays containing data for the patients with Good or Excellent
health.
8-17
8 Categorical Arrays
Create a scatter plot of blood pressure readings for the two groups of patients. The plot shows no
suggestive differences between the two groups, possibly indicating that blood pressure does not
affect how these patients assessed their own health.
figure
h1 = scatter(X1,Y1,"o");
hold on
h2 = scatter(X2,Y2,"x");
See Also
categorical | summary | countcats | histogram | pie | bar | rose | scatter
Related Examples
• “Access Data Using Categorical Arrays” on page 8-33
8-18
Compare Categorical Array Elements
This example shows how to use relational operations with a categorical array.
colors = categorical(C)
categories(colors)
Use the relational operator, eq (==), to compare the first and second rows of colors.
colors(1,:) == colors(2,:)
1 0 1 1
Only the values in the second column differ between the rows.
Compare the entire categorical array, colors, to the string "blue" to find the location of all blue
values.
colors == "blue"
1 0 0 1
1 0 0 1
There are four blue entries in colors, one in each corner of the array.
8-19
8 Categorical Arrays
Add a mathematical ordering to the categories in colors. Specify the category order that represents
the ordering of color spectrum, red < green < blue. The elements in the categorical array remain
the same.
categories(colors)
Determine if elements in the first column of colors are greater than the elements in the second
column.
1
1
Both values in the first column, blue, are greater than the corresponding values in the second
column, red and green.
Find all the elements in colors that are less than blue.
0 1 1 0
0 1 1 0
The function lt (<) indicates the location of all green and red values with 1.
See Also
categorical | categories
Related Examples
• “Access Data Using Categorical Arrays” on page 8-33
8-20
Compare Categorical Array Elements
More About
• “Relational Operations”
• “Advantages of Using Categorical Arrays” on page 8-46
• “Ordinal Categorical Arrays” on page 8-48
8-21
8 Categorical Arrays
Create a categorical array that contains the preferred lunchtime beverage of 25 students in
classroom A.
rng("default")
A = randi(3,[25,1]);
A = categorical(A,1:3,["milk" "water" "juice"])
A = 25x1 categorical
juice
juice
milk
juice
water
milk
milk
water
juice
juice
milk
juice
juice
water
juice
milk
water
juice
juice
juice
water
milk
juice
juice
juice
summary(A)
A: 25x1 categorical
milk 6
water 5
juice 14
<undefined> 0
Create another categorical array that contains the preferences of 28 students in classroom B.
B = randi(3,[28,1]);
B = categorical(B,1:3,["milk" "water" "juice"])
8-22
Combine Categorical Arrays
B = 28x1 categorical
juice
juice
water
water
milk
juice
milk
milk
milk
milk
juice
juice
milk
juice
milk
water
water
juice
juice
milk
water
water
water
juice
juice
milk
juice
water
B: 28x1 categorical
milk 9
water 8
juice 11
<undefined> 0
Concatenate the data from classrooms A and B into a single categorical array, Group1.
Group1 = [A;B]
8-23
8 Categorical Arrays
milk
juice
juice
water
juice
milk
water
juice
juice
juice
water
milk
juice
juice
juice
juice
juice
water
water
milk
⋮
milk 15
water 13
juice 25
<undefined> 0
Create a categorical array, Group2, that contains data from 50 students who were given the
additional beverage option of soda.
Group2 = randi(4,[50,1]);
Group2 = categorical(Group2,1:4,["juice" "milk" "soda" "water"])
8-24
Combine Categorical Arrays
milk
water
milk
water
juice
water
milk
juice
milk
soda
milk
milk
water
soda
⋮
juice 12
milk 14
soda 10
water 14
<undefined> 0
8-25
8 Categorical Arrays
juice
juice
juice
juice
water
water
milk
⋮
Summarize the resulting categorical array. Concatenation appends the categories exclusive to the
second input, soda, to the end of the list of categories from the first input, milk, water, juice,
soda.
summary(students)
milk 29
water 27
juice 37
soda 10
<undefined> 0
To change the order of the categories in the categorical array, use the reordercats function.
students = reordercats(students,["juice" "milk" "water" "soda"]);
categories(students)
To find the unique responses from Group1 and Group2, use the union function.
C = union(Group1,Group2)
C = 4x1 categorical
milk
water
juice
soda
union returns the combined values from Group1 and Group2 with no repetitions. In this case, C is
equivalent to the categories of the concatenation, students.
All of the categorical arrays in this example were nonordinal. To combine ordinal categorical arrays,
they must have the same sets of categories including their order.
See Also
categorical | categories | summary | union | cat | horzcat | vertcat
8-26
Combine Categorical Arrays
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Produce All Combinations of Categories from Two Categorical Arrays” on page 8-28
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Access Data Using Categorical Arrays” on page 8-33
More About
• “Ordinal Categorical Arrays” on page 8-48
8-27
8 Categorical Arrays
This example shows how multiplication produces all combinations of the categories from two
categorical arrays. When you multiply two categorical arrays, the output is a categorical array with
entirely new categories. This set of new categories is the set of all the ordered pairs created from the
categories of the input arrays. This set of all possible combinations of categories is also known as the
Cartesian product of the two original sets of categories.
Multiplication also produces the elements of the output array from the corresponding elements of the
input arrays. If either input array has undefined elements, then the corresponding elements of the
output array are also undefined. If the input arrays are both ordinal categorical arrays, then so is the
output array.
Create two categorical arrays. To multiply them, either the two arrays must have the same number of
elements, or one array must have only one element.
A = 1x3 categorical
blue red green
B = 1x3 categorical
+ - +
However, the two arrays can have different numbers of categories, as shown by categories. The
categories function returns the set of categories that a categorical array has.
categories(A)
categories(B)
Multiply the two categorical arrays. The elements of the product come from combinations of the
corresponding elements from the input arrays.
C = A.*B
8-28
Produce All Combinations of Categories from Two Categorical Arrays
C = 1x3 categorical
blue + red - green +
However, the categories of the product are all the ordered pairs that can be created from the
categories of the two inputs. So, it is possible that some categories are not represented by any
elements of the output array.
categories(C)
The order of the categories of the product follows from the orders of the categories of the input
arrays. Therefore, B.*A does not equal A.*B.
D = B.*A
D = 1x3 categorical
+ blue - red + green
The categories of B.*A are also different from the categories of A.*B.
categories(D)
Multiply two categorical arrays. If either A or B have an undefined element, the corresponding
element of C is also undefined. You can create undefined elements by using the missing function.
A = 1x4 categorical
blue red green <undefined>
B = 1x4 categorical
+ <undefined> + -
C = A.*B
8-29
8 Categorical Arrays
C = 1x4 categorical
blue + <undefined> green + <undefined>
However, the presence of undefined elements in the inputs does not change the categories of the
output array. Undefined elements do not belong to a category.
categories(C)
Create two ordinal categorical arrays. Display the categories of each array.
A = 1x6 categorical
blue red green red green red
categories(A)
B = 1x6 categorical
+ - + - + -
categories(B)
C = A.*B
C = 1x6 categorical
blue + red - green + red - green + red -
8-30
Produce All Combinations of Categories from Two Categorical Arrays
categories(C)
The output array C is an ordinal categorical array because A and B are both ordinal.
isordinal(C)
ans = logical
1
Since R2023a
You can also produce all combinations of categories by using the combinations function. When you
use combinations, the two input arrays can have different lengths. However, the output is a table,
not a categorical array. The table variables are separate categorical arrays. The table does not
contain a categorical array whose categories are the combinations shown in the table.
A1 = 1x4 categorical
blue red green black
A2 = categorical(["+" "-"])
A2 = 1x2 categorical
+ -
T = combinations(A1,A2)
T=8×2 table
A1 A2
_____ __
blue +
blue -
red +
red -
green +
green -
black +
black -
See Also
times | categorical | categories | isordinal | missing | combinations
8-31
8 Categorical Arrays
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Access Data Using Categorical Arrays” on page 8-33
• “Compare Categorical Array Elements” on page 8-19
• “Combine Categorical Arrays” on page 8-22
• “Ordinal Categorical Arrays” on page 8-48
8-32
Access Data Using Categorical Arrays
• Select elements from particular categories. For categorical arrays, use the logical operators
== or ~= to select data that is in, or not in, a particular category. To select data in a particular
group of categories, use the ismember function.
For ordinal categorical arrays, use inequalities >, >=, <, or <= to find data in categories above or
below a particular category.
• Delete data that is in a particular category. Use logical operators to include or exclude data
from particular categories.
• Find elements that are not in a defined category. Categorical arrays indicate which elements
do not belong to a defined category by <undefined>. Use the isundefined function to find
observations without a defined value.
This example shows how to index and search using categorical arrays. You can access data using
categorical arrays stored within a table in a similar manner.
Load data about 100 patients from the sample patients.mat MAT-file.
load patients.mat
whos
8-33
8 Categorical Arrays
The arrays Location and SelfAssessedHealthStatus contain data that belong in categories.
Each array contains text taken from a small set of unique values (indicating three locations and four
health statuses respectively). To convert Location and SelfAssessedHealthStatus to
categorical arrays, use the categorical function. On the other hand, the array LastName has a list
of last names that are not categories. So, convert LastName to a string array using the string
function.
Location = categorical(Location);
SelfAssessedHealthStatus = categorical(SelfAssessedHealthStatus);
LastName = string(LastName);
For categorical arrays, you can use the logical operators == and ~= to find the data that is in, or not
in, a particular category.
Determine if there are any patients observed at the location, Rampart General Hospital.
any(Location == "Rampart General Hospital")
ans = logical
0
You can use ismember to find data in a particular group of categories. For example, call ismember
using Location as input data. Create a logical vector that identifies patients observed at either
County General Hospital or VA Hospital.
Location
8-34
Access Data Using Categorical Arrays
VA Hospital
VA Hospital
County General Hospital
County General Hospital
VA Hospital
VA Hospital
County General Hospital
County General Hospital
County General Hospital
⋮
VA_CountyGenIndex = ...
ismember(Location,["County General Hospital","VA Hospital"])
1
1
0
1
1
0
1
1
0
1
⋮
VA_CountyGenIndex is a 100-by-1 logical array containing logical true (1) for each element in
Location that is a member of the categories County General Hospital or VA Hospital. The
output, VA_CountyGenIndex contains 76 nonzero elements.
Use the logical vector, VA_CountyGenIndex to select the LastName of the patients observed at
either County General Hospital or VA Hospital.
VA_CountyGenPatients = LastName(VA_CountyGenIndex)
8-35
8 Categorical Arrays
"Walker"
"Hall"
"Allen"
"Young"
"Hernandez"
"King"
"Wright"
"Lopez"
"Green"
"Adams"
"Baker"
"Mitchell"
⋮
Use the summary function to print a summary containing the category names and the number of
elements in each category.
summary(Location)
Location is a 100-by-1 categorical array with three categories. County General Hospital
occurs in 39 elements, St. Mary's Medical Center in 24 elements, and VA Hospital in 37
elements.
summary(SelfAssessedHealthStatus)
Excellent 34
Fair 15
Good 40
Poor 11
<undefined> 0
Use logical operator == to access the ages of patients who assess their own health status as Good.
Then plot a histogram of this data.
figure()
histogram(Age(SelfAssessedHealthStatus == "Good"))
title("Ages of Patients with Good Health Status")
8-36
Access Data Using Categorical Arrays
You can use logical operators to include or exclude data from particular categories. Delete all patients
observed at VA Hospital from the workspace variables, Age and Location.
Age = Age(Location ~= "VA Hospital");
Location = Location(Location ~= "VA Hospital")
8-37
8 Categorical Arrays
Now, Age is a 63-by-1 numeric array, and Location is a 63-by-1 categorical array.
List the categories of Location, as well as the number of elements in each category.
summary(Location)
The patients observed at VA Hospital are deleted from Location, but VA Hospital is still a
category.
Use the removecats function to remove VA Hospital from the categories of Location.
Location = removecats(Location,"VA Hospital");
Delete Element
You can delete elements by indexing. For example, you can remove the first element of Location by
selecting the rest of the elements with Location(2:end). However, an easier way to delete
elements is to use [].
Location(1) = [];
summary(Location)
8-38
Access Data Using Categorical Arrays
Location is a 62-by-1 categorical array that has two categories. Deleting the first element has no
effect on other elements from the same category and does not delete the category itself.
After removing the category, County General Hospital, elements that previously belonged to
that category no longer belong to any category defined for Location. The categorical elements that
do not belong to any category are undefined, and display <undefined> as their values.
Use the function isundefined to find elements of a categorical array that do not belong to any
category.
undefinedIndex = isundefined(Location);
undefinedIndex is a 62-by-1 categorical array containing logical true (1) for all undefined
elements in Location.
Use the summary function to print the number of undefined elements in Location. Then display the
first five elements of Location.
summary(Location)
Location(1:5)
8-39
8 Categorical Arrays
<undefined>
The first element of Location belongs to the category, St. Mary's Medical Center. Set the first
element to be an undefined value so that it no longer belongs to any category. The recommended way
is to use the missing function to create undefined values. Another way is to assign '' or "" to
elements of the array. When you assign such values to elements of a categorical array, it converts
them to undefined values.
Location(1) = missing;
Location(3) = '';
Location(1:5)
The summary function shows that these assignments increased the number of undefined elements.
summary(Location)
You can make selected elements undefined without removing a category or changing the categories
of other elements. Set undefined elements to indicate elements with values that are unknown.
You can use undefined elements to preallocate the size of a categorical array for better performance.
Create a categorical array that has elements with known locations only.
definedIndex = ~isundefined(Location);
newLocation = Location(definedIndex);
summary(newLocation)
Expand the size of newLocation so that it is a 200-by-1 categorical array. Set the last new element
to be an undefined element. All of the other new elements are also assigned undefined values. The 22
original elements keep the values that they had.
newLocation(200) = missing;
summary(newLocation)
8-40
Access Data Using Categorical Arrays
newLocation has room for values you plan to store in the array later.
See Also
categorical | categories | summary | any | histogram | removecats | isundefined
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Plot Categorical Data” on page 8-12
• “Compare Categorical Array Elements” on page 8-19
• “Work with Protected Categorical Arrays” on page 8-42
More About
• “Advantages of Using Categorical Arrays” on page 8-46
• “Ordinal Categorical Arrays” on page 8-48
8-41
8 Categorical Arrays
This example shows how to work with a categorical array with protected categories.
When you create a categorical array with the categorical function, you have the option of
specifying whether or not the categories are protected. Ordinal categorical arrays always have
protected categories, but you also can create a nonordinal categorical array that is protected using
the Protected name-value argument.
When you assign values that are not members of a category, the array updates automatically so that
its list of categories includes the new values. Similarly, you can combine (nonordinal) categorical
arrays that have different categories. The categories in the result include the categories from both
arrays.
When you assign new values to a protected categorical array, the values must belong to one of the
existing categories. Similarly, you can only combine protected arrays that have the same categories.
• If you want to combine two nonordinal categorical arrays that have protected categories, they
must have the same categories, but the order does not matter. The resulting categorical array
uses the category order from the first array.
• If you want to combine two ordinal categorical array (that always have protected categories), they
must have the same categories, including their order.
To add new categories to the array, you must use the addcats function.
Create a categorical array containing the sizes of 10 objects. Use the category names small,
medium, and large for the values "S", "M", and "L".
A = categorical(["M";"L";"S";"S";"M";"L";"M";"L";"M";"S"], ...
["S" "M" "L"], ...
["small" "medium" "large"], ...
"Ordinal",true)
A = 10x1 categorical
medium
large
small
small
medium
large
medium
large
medium
small
categories(A)
8-42
Work with Protected Categorical Arrays
{'large' }
When you create an ordinal categorical array, the categories are always protected.
Use the isprotected function to verify that the categories of A are protected.
tf = isprotected(A)
tf = logical
1
If you try to assign a new value that does not belong to one of the existing categories, then MATLAB®
returns an error. For example, you cannot assign the value "xlarge" to the categorical array, as in
the expression A(2) = "xlarge", because xlarge is not a category of A. Instead, MATLAB returns
the error:
To add a new category for xlarge, use the addcats function. Because A is ordinal you must specify
the order for the new category.
A = addcats(A,"xlarge",After="large");
A(2) = "xlarge"
A = 10x1 categorical
medium
xlarge
small
small
medium
large
medium
large
medium
small
A is now a 10-by-1 categorical array with four categories, such that small < medium < large <
xlarge.
Create another ordinal categorical array, B, containing the sizes of five items.
B = categorical([2;1;1;2;2],1:2,["xsmall" "small"],Ordinal=true)
8-43
8 Categorical Arrays
B = 5x1 categorical
small
xsmall
xsmall
small
small
B is a 5-by-1 categorical array with two categories such that xsmall < small.
To combine two ordinal categorical arrays (which always have protected categories), they must have
the same categories and the categories must be in the same order.
categories(A)
Add the categories medium, large, and xlarge to B after the category small.
B = addcats(B,["medium" "large" "xlarge"],After="small");
categories(B)
The categories of A and B are now the same including their order.
C = 15x1 categorical
medium
xlarge
small
small
medium
large
medium
large
medium
small
small
8-44
Work with Protected Categorical Arrays
xsmall
xsmall
small
small
categories(C)
C is a 16-by-1 ordinal categorical array with five categories, such that xsmall < small < medium
< large < xlarge.
See Also
categorical | categories | summary | isprotected | isordinal | addcats
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Access Data Using Categorical Arrays” on page 8-33
• “Combine Categorical Arrays” on page 8-22
• “Produce All Combinations of Categories from Two Categorical Arrays” on page 8-28
More About
• “Ordinal Categorical Arrays” on page 8-48
8-45
8 Categorical Arrays
The only ordering that string arrays provide is alphanumeric order. If you use a categorical array,
then you can specify any ordering that makes sense for your set of categories. You can use relational
operations to test for equality and perform elementwise comparisons that have a meaningful
mathematical ordering.
This example shows how to compare the memory required to store data as a string array to the
memory required for a categorical array. String arrays must store each element even when they have
many repeated values. Categorical arrays store only one copy of each category name, often reducing
the amount of memory required to store an array when it has many repeated values.
whos state
8-46
Advantages of Using Categorical Arrays
stateCats = categorical(state);
categories(stateCats)
Display information about the two variables. There is a significant reduction in the memory required
to store the categorical array.
See Also
categorical | categories
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Compare Categorical Array Elements” on page 8-19
• “Access Data Using Categorical Arrays” on page 8-33
More About
• “Ordinal Categorical Arrays” on page 8-48
8-47
8 Categorical Arrays
In this section...
“Order of Categories” on page 8-48
“How to Create Ordinal Categorical Arrays” on page 8-48
“Working with Ordinal Categorical Arrays” on page 8-50
Order of Categories
categorical is a data type to store data with values from a finite set of discrete categories, which
can have a natural order. You can specify and rearrange the order of categories in all categorical
arrays. However, you only can treat ordinal categorical arrays as having a mathematical ordering to
their categories. Use an ordinal categorical array if you want to use the functions min, max, or
relational operations, such as greater than and less than.
The discrete set of pet categories ["dog" "cat" "bird"] has no meaningful mathematical
ordering. You are free to use any category order and the meaning of the associated data does not
change. For example, pets = categorical(["bird" "cat" "dog" "dog" "cat"]) creates a
categorical array and the categories are listed in alphabetical order, ["bird" "cat" "dog"]. You
can choose to specify or change the order of the categories to ["dog" "cat" "bird"] and the
meaning of the data does not change.
Ordinal categorical arrays contain categories that have a meaningful mathematical ordering. For
example, the discrete set of size categories ["small" "medium" "large"] has the mathematical
ordering small < medium < large. The first category listed is the smallest and the last category
is the largest. The order of the categories in an ordinal categorical array affects the result from
relational comparisons of ordinal categorical arrays.
This example shows how to create an ordinal categorical array by using the categorical function
with the Ordinal name-value argument.
Create an ordinal categorical array. To make the array ordinal, set the Ordinal name-value
argument to true.
sizes = categorical(A,valueset,Ordinal=true)
8-48
Ordinal Categorical Arrays
Create an equivalent categorical array from an array of integers. Use the values 1, 2, and 3 to define
the categories small, medium, and large, respectively.
A2 = [2 3; 1 2; 3 1];
valueset = 1:3;
catnames = ["small" "medium" "large"];
sizes2 = categorical(A2,valueset,catnames,Ordinal=true)
isequal(sizes,sizes2)
ans = logical
1
sizes and sizes2 are equivalent categorical arrays with the same ordering of categories.
To convert an ordinal categorical array to a nonordinal array, use the categorical function without
the Ordinal name-value argument.
sizes3 = categorical(sizes)
isordinal(sizes3)
ans = logical
0
sizes3 = categorical(sizes3,Ordinal=true);
isordinal(sizes3)
ans = logical
1
8-49
8 Categorical Arrays
sizes3 is now a 3-by-2 ordinal categorical array equivalent to sizes and sizes2.
See Also
categorical | categories | isordinal | isequal
Related Examples
• “Create Categorical Arrays” on page 8-2
• “Convert Text in Table Variables to Categorical” on page 8-8
• “Compare Categorical Array Elements” on page 8-19
• “Access Data Using Categorical Arrays” on page 8-33
More About
• “Advantages of Using Categorical Arrays” on page 8-46
8-50
Core Functions Supporting Categorical Arrays
The following table lists notable MATLAB functions that operate on categorical arrays in addition to
other arrays.
8-51
9
Tables
Tables are suitable for column-oriented data such as tabular data from text files or spreadsheets.
Tables store columns of data in variables. The variables in a table can have different data types,
though all of the variables must have the same number of rows. However, table variables are not
restricted to storing only column vectors. For example, a table variable can contain a matrix with
multiple columns as long as it has the same number of rows as the other table variables.
In MATLAB®, you can create tables and assign data to them in several ways.
The way you choose depends on the nature of your data and how you plan to use tables in your code.
You can create a table from arrays by using the table function. For example, create a small table
with data for five patients.
First, create six column-oriented arrays of data. These arrays have five rows because there are five
patients. (Most of these arrays are 5-by-1 column vectors, while BloodPressure is a 5-by-2 matrix.)
LastName = ["Sanchez";"Johnson";"Zhang";"Diaz";"Brown"];
Age = [38;43;38;40;49];
Smoker = [true;false;true;false;true];
Height = [71;69;64;67;64];
Weight = [176;163;131;133;119];
BloodPressure = [124 93; 109 77; 125 83; 117 75; 122 80];
Now create a table, patients, as a container for the data. In this call to the table function, the
input arguments use the workspace variable names for the names of the variables in patients.
patients = table(LastName,Age,Smoker,Height,Weight,BloodPressure)
patients=5×6 table
LastName Age Smoker Height Weight BloodPressure
_________ ___ ______ ______ ______ _____________
9-2
Create Tables and Assign Data to Them
The table is a 5-by-6 table because it has six variables. As the BloodPressure variable shows, a
table variable itself can have multiple columns. This example shows why tables have rows and
variables, not rows and columns.
Once you have created a table, you can add a new variable at any time by using dot notation. Dot
notation refers to table variables by name, T.varname, where T is the table and varname is the
variable name. This notation is similar to the notation you use to access and assign data to the fields
of a structure.
For example, add a BMI variable to patients. Calculate body mass index, or BMI, using the values in
patients.Weight and patients.Height. Assign the BMI values to a new table variable.
patients.BMI = (patients.Weight*0.453592)./(patients.Height*0.0254).^2
patients=5×7 table
LastName Age Smoker Height Weight BloodPressure BMI
_________ ___ ______ ______ ______ _____________ ______
Another way to create a table is to start with an empty table and assign variables to it. For example,
re-create the table of patient data, but this time assign variables using dot notation.
patients2 = table
patients2 =
Next, create a copy of the patient data by assigning variables. Table variable names do not have to
match array names, as shown by the Name and BP table variables.
patients2.Name = LastName;
patients2.Age = Age;
patients2.Smoker = Smoker;
patients2.Height = Height;
patients2.Weight = Weight;
patients2.BP = BloodPressure
patients2=5×6 table
Name Age Smoker Height Weight BP
_________ ___ ______ ______ ______ __________
9-3
9 Tables
Sometimes you know the sizes and data types of the data that you want to store in a table, but you
plan to assign the data later. Perhaps you plan to add only a few rows at a time. In that case,
preallocating space in the table and then assigning values to empty rows can be more efficient.
For example, to preallocate space for a table to contain time and temperature readings at different
stations, use the table function. Instead of supplying input arrays, specify the sizes and data types of
the table variables. To give them names, specify the 'VariableNames' argument. Preallocation fills
table variables with default values that are appropriate for their data types.
sz = [4 3];
varTypes = ["double","datetime","string"];
varNames = ["Temperature","Time","Station"];
temps = table('Size',sz,'VariableTypes',varTypes,'VariableNames',varNames)
temps=4×3 table
Temperature Time Station
___________ ____ _________
0 NaT <missing>
0 NaT <missing>
0 NaT <missing>
0 NaT <missing>
One way to assign or add a row to a table is to assign a cell array to a row. If the cell array is a row
vector and its elements match the data types of their respective variables, then the assignment
converts the cell array to a table row. However, you can assign only one row at a time using cell
arrays. Assign values to the first two rows.
temps(1,:) = {75,datetime('now'),"S1"};
temps(2,:) = {68,datetime('now')+1,"S2"}
temps=4×3 table
Temperature Time Station
___________ ____________________ _________
As an alternative, you can assign rows from a smaller table into a larger table. With this method, you
can assign one or more rows at a time.
temps(3:4,:) = table([63;72],[datetime('now')+2;datetime('now')+3],["S3";"S4"])
temps=4×3 table
Temperature Time Station
___________ ____________________ _______
9-4
Create Tables and Assign Data to Them
You can use either syntax to increase the size of a table by assigning rows beyond the end of the
table. If necessary, missing rows are filled in with default values.
temps(6,:) = {62,datetime('now')+6,"S6"}
temps=6×3 table
Temperature Time Station
___________ ____________________ _________
You can convert variables that have other data types to tables. Cell arrays and structures are other
types of containers that can store arrays that have different data types. So you can convert cell arrays
and structures to tables. You can also convert an array to a table where the table variables contain
columns of values from the array. To convert these kinds of variables, use the array2table,
cell2table, or struct2table functions.
For example, convert an array to a table by using array2table. Arrays do not have column names,
so the table has default variable names.
A = randi(3,3)
A = 3×3
3 3 1
3 2 2
1 1 3
a2t = array2table(A)
a2t=3×3 table
A1 A2 A3
__ __ __
3 3 1
3 2 2
1 1 3
You can provide your own table variable names by using the "VariableNames" name-value
argument.
a2t = array2table(A,"VariableNames",["First","Second","Third"])
a2t=3×3 table
First Second Third
9-5
9 Tables
3 3 1
3 2 2
1 1 3
It is common to have a large quantity of tabular data in a file such as a CSV (comma-separated value)
file or an Excel® spreadsheet. To read such data into a table, use the readtable function.
For example, the CSV file outages.csv is a sample file that is distributed with MATLAB. The file
contains data for a set of electrical power outages. The first line of outages.csv has column names.
The rest of the file has comma-separated data values for each outage. The first few lines are shown
here.
Region,OutageTime,Loss,Customers,RestorationTime,Cause
SouthWest,2002-02-01 12:18,458.9772218,1820159.482,2002-02-07 16:50,winter storm
SouthEast,2003-01-23 00:49,530.1399497,212035.3001,,winter storm
SouthEast,2003-02-07 21:15,289.4035493,142938.6282,2003-02-17 08:14,winter storm
West,2004-04-06 05:44,434.8053524,340371.0338,2004-04-06 06:10,equipment fault
MidWest,2002-03-16 06:18,186.4367788,212754.055,2002-03-18 23:23,severe storm
...
To read outages.csv and store the data in a table, you can use readtable. It reads numeric
values, dates and times, and strings into table variables that have appropriate data types. Here, Loss
and Customers are numeric arrays. The OutageTime and RestorationTime variables are
datetime arrays because readtable recognizes the date and time formats of the text in those
columns of the input file. To read the rest of the text data into string arrays, specify the "TextType"
name-value argument.
outages = readtable("outages.csv","TextType","string")
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
9-6
Create Tables and Assign Data to Them
Finally, you can interactively preview and import data from spreadsheets or delimited text files by
using the Import Tool. There are two ways to open the Import Tool.
• MATLAB Toolstrip: On the Home tab, in the Variable section, click Import Data.
• MATLAB command prompt: Enter uiimport(filename), where filename is the name of a text
or spreadsheet file.
For example, open the outages.csv sample file by using uiimport and which to get the path to
the file.
uiimport(which("outages.csv"))
The Import Tool shows you a preview of the six columns from outages.csv. To import the data as a
table, follow these steps.
See Also
Functions
readtable | table | array2table | cell2table | struct2table
Apps
Import Tool
9-7
9 Tables
Related Examples
• “Access Data in Tables” on page 9-37
• “Add and Delete Table Rows” on page 9-9
• “Add, Delete, and Rearrange Table Variables” on page 9-12
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Rename and Describe Table Variables” on page 9-26
• “Tables of Mixed Data” on page 9-86
9-8
Add and Delete Table Rows
This example shows how to add and delete rows in a table. You can also edit tables using the
Variables Editor.
load patients
T = table(LastName,Gender,Age,Height,Weight,Smoker,Systolic,Diastolic);
size(T)
ans = 1×2
100 8
Read data on more patients from a comma-delimited file, morePatients.csv, into a table, T2. Then,
append the rows from T2 to the end of the table, T.
T2 = readtable('morePatients.csv');
Tnew = [T;T2];
size(Tnew)
ans = 1×2
104 8
The table Tnew has 104 rows. In order to vertically concatenate two tables, both tables must have the
same number of variables, with the same variable names. If the variable names are different, you can
directly assign new rows in a table to rows from another table. For example, T(end+1:end+4,:) =
T2.
To append new rows stored in a cell array, vertically concatenate the cell array onto the end of the
table. You can concatenate directly from a cell array when it has the right number of columns and the
contents of its cells can be concatenated onto the corresponding table variables.
cellPatients = {'Trujillo','Male',42,70,158,0,116,83;
'Falk','Female',28,62,125,1,120,71};
Tnew = [Tnew;cellPatients];
size(Tnew)
ans = 1×2
106 8
You also can convert a cell array to a table using the cell2table function.
9-9
9 Tables
You also can append new rows stored in a structure. Convert the structure to a table, and then
concatenate the tables.
structPatients(1,1).LastName = 'George';
structPatients(1,1).Gender = 'Nonbinary';
structPatients(1,1).Age = 45;
structPatients(1,1).Height = 76;
structPatients(1,1).Weight = 182;
structPatients(1,1).Smoker = 1;
structPatients(1,1).Systolic = 132;
structPatients(1,1).Diastolic = 85;
structPatients(2,1).LastName = 'Russo';
structPatients(2,1).Gender = 'Female';
structPatients(2,1).Age = 29;
structPatients(2,1).Height = 58;
structPatients(2,1).Weight = 120;
structPatients(2,1).Smoker = 0;
structPatients(2,1).Systolic = 112;
structPatients(2,1).Diastolic = 70;
Tnew = [Tnew;struct2table(structPatients)];
size(Tnew)
ans = 1×2
108 8
To omit any rows in a table that are duplicated, use the unique function.
Tnew = unique(Tnew);
size(Tnew)
ans = 1×2
107 8
Tnew([18,20,21],:) = [];
size(Tnew)
ans = 1×2
104 8
9-10
Add and Delete Table Rows
First, specify the variable of identifiers, LastName, as row names. Then, delete the variable,
LastName, from Tnew. Finally, use the row name to index and delete rows.
Tnew.Properties.RowNames = Tnew.LastName;
Tnew.LastName = [];
Tnew('Smith',:) = [];
size(Tnew)
ans = 1×2
103 7
The table now has one less row and one less variable.
You also can search for observations in the table. For example, delete rows for any patients under the
age of 30.
ans = 1×2
86 7
See Also
table | readtable | array2table | cell2table | struct2table
Related Examples
• “Add, Delete, and Rearrange Table Variables” on page 9-12
• “Clean Messy and Missing Data in Tables” on page 9-18
9-11
9 Tables
This example shows how to add, delete, and rearrange column-oriented variables in a table. You can
add, move, and delete table variables using the addvars, movevars, and removevars functions. As
alternatives, you also can modify table variables using dot syntax or by indexing into the table. Use
the splitvars and mergevars functions to split multicolumn variables and combine multiple
variables into one. Finally, you can reorient a table so that the rows of the table become variables of
an output table, using the rows2vars function.
You also can modify table variables using the Variables Editor.
Load arrays of sample data from the patients MAT-file. Display the names and sizes of the variables
loaded into the workspace.
load patients
whos -file patients
Create two tables. Create one table, T, with information collected from a patient questionnaire and
create another table, T2, with data measured from patients. Each table has 100 rows.
T = table(Age,SelfAssessedHealthStatus,Smoker);
T.SelfAssessedHealthStatus = string(T.SelfAssessedHealthStatus);
T2 = table(Height,Weight,Systolic,Diastolic);
head(T,5)
38 "Excellent" true
43 "Fair" false
38 "Good" false
40 "Fair" false
49 "Good" false
head(T2,5)
9-12
Add, Delete, and Rearrange Table Variables
71 176 124 93
69 163 109 77
64 131 125 83
67 133 117 75
64 119 122 80
T = [T T2];
head(T,5)
If the tables that you are horizontally concatenating have row names, horzcat concatenates the
tables by matching the row names. Therefore, the tables must use the same row names, but the row
order does not matter.
Add the names of patients from the workspace variable LastName before the first table variable in T.
You can specify any location in the table using the name of a variable near the new location. Use
quotation marks to refer to the names of table variables. However, do not use quotation marks for
input arguments that are workspace variables.
T = addvars(T,LastName,'Before',"Age");
T.LastName = string(T.LastName);
head(T,5)
You also can specify locations in a table using numbers. For example, the equivalent syntax using a
number to specify location is T = addvars(T,LastName,'Before',1).
9-13
9 Tables
An alternative way to add new table variables is to use dot syntax. When you use dot syntax, you
always add the new variable as the last table variable. You can add a variable that has any data type,
as long as it has the same number of rows as the table.
Create a new variable for blood pressure as a horizontal concatenation of the two variables
Systolic and Diastolic. Add it to T.
T now has 9 variables and 100 rows. A table variable can have multiple columns. So although
BloodPressure has two columns, it is one table variable.
Add a new variable, BMI, in the table T, that contains the body mass index for each patient. BMI is a
function of height and weight. When you calculate BMI, you can refer to the Weight and Height
variables that are in T.
T.BMI = (T.Weight*0.453592)./(T.Height*0.0254).^2;
The operators ./ and .^ in the calculation of BMI indicate element-wise division and exponentiation,
respectively.
head(T,5)
Move the table variable BMI using the movevars function, so that it is after the variable Weight.
When you specify table variables by name, use quotation marks.
T = movevars(T,"BMI",'After',"Weight");
head(T,5)
9-14
Add, Delete, and Rearrange Table Variables
You also can specify locations in a table using numbers. For example, the equivalent syntax using a
number to specify location is T = movevars(T,"BMI",'After',6). It is often more convenient to
refer to variables by name.
As an alternative, you can move table variables by indexing. You can index into a table using the same
syntax you use for indexing into a matrix.
T = T(:,[1:7 10 8 9]);
head(T,5)
In a table with many variables, it is often more convenient to use the movevars function.
Delete Variables
To delete table variables, use the removevars function. Delete the Systolic and Diastolic table
variables.
T = removevars(T,["Systolic","Diastolic"]);
head(T,5)
As an alternative, you can delete variables using dot syntax and the empty matrix, []. Remove the
Age variable from the table.
T.Age = [];
head(T,5)
9-15
9 Tables
You also can delete variables using indexing and the empty matrix, []. Remove the
SelfAssessedHealthStatus variable from the table.
T(:,"SelfAssessedHealthStatus") = [];
head(T,5)
To split multicolumn table variables into variables that each have one column, use the splitvars
functions. Split the variable BloodPressure into two variables.
T = splitvars(T,"BloodPressure",'NewVariableNames',["Systolic","Diastolic"]);
head(T,5)
Similarly, you can group related table variables together in one variable, using the mergevars
function. Combine Systolic and Diastolic back into one variable, and name it BP.
T = mergevars(T,["Systolic","Diastolic"],'NewVariableName',"BP");
head(T,5)
9-16
Add, Delete, and Rearrange Table Variables
You can reorient the rows of a table or timetable, so that they become the variables in the output
table, using the rows2vars function. However, if the table has multicolumn variables, then you must
split them before you can call rows2vars.
Reorient the rows of T. Specify that the names of the patients in T are the names of table variables in
the output table. The first variable of T3 contains the names of the variables of T. Each remaining
variable of T3 contains the data from the corresponding row of T.
T = splitvars(T,"BP",'NewVariableNames',["Systolic","Diastolic"]);
T3 = rows2vars(T,'VariableNamesSource',"LastName");
T3(:,1:5)
ans=6×5 table
OriginalVariableNames Smith Johnson Williams Jones
_____________________ ______ _______ ________ ______
{'Smoker' } 1 0 0 0
{'Height' } 71 69 64 67
{'Weight' } 176 163 131 133
{'BMI' } 24.547 24.071 22.486 20.831
{'Systolic' } 124 109 125 117
{'Diastolic'} 93 77 83 75
You can use dot syntax with T3 to access patient data as an array. However, if the row values of an
input table cannot be concatenated, then the variables of the output table are cell arrays.
T3.Smith
ans = 6×1
1.0000
71.0000
176.0000
24.5467
124.0000
93.0000
See Also
table | addvars | movevars | removevars | splitvars | mergevars | inner2outer |
rows2vars
Related Examples
• “Add and Delete Table Rows” on page 9-9
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Rename and Describe Table Variables” on page 9-26
9-17
9 Tables
This example shows how to clean and reorganize a table that has messy and missing data values.
First, you can identify missing data by using the Import Tool or by using functions such as the
summary and ismissing functions. You can standardize, fill, or remove missing values by using the
standardizeMissing, fillmissing, or rmmissing functions. Then you can clean your table
further by reorganizing it. You can rearrange table rows and variables by using functions such as the
sortrows and movevars functions.
Examine the data in the sample comma-separated value (CSV) file, messy.csv, by using the Import
Tool. The tool previews the data and enables you to specify how to import the data. To examine
messy.csv in the Import Tool, after opening this example in MATLAB®, go to the Home tab, click
Import Data in the Variable section, and open messy.csv using the file selection dialog box.
The Import Tool shows that messy.csv has five columns with text and numeric values.
9-18
Clean Messy and Missing Data in Tables
• Empty text
• Period (.)
• NA
• NaN
• -99
The Import Tool automatically recognizes (but does not visually highlight) some missing data
indicators, such as NaN in numeric columns and empty text in text columns.
The tool highlights other indicators, such as the empty text, period, and NA, that occur in column B.
These values are not standard missing values. However, nonnumeric values in a numeric column are
likely to represent missing values. When you import the data, you can specify that these values
should also be treated as missing values.
When numeric data otherwise consists of positive values, a single negative value, such as -99, can be
a flag for missing data. If a number such as -99 represents missing data in your table, then you must
specify that it is a missing value when you clean your table.
You can import data into the MATLAB workspace from the Import Tool. You can also use the
readtable function to read the data from a file and import it as a table.
Import the data in messy.csv using the readtable function. To read text data into table variables
that are string arrays, use the TextType name-value argument. To treat specified nonnumeric values
in numeric columns as missing values, use the TreatAsMissing name-value argument. For columns
A and C with text data, readtable imports any empty text as missing strings, which display as
<missing>. For columns B, D, and E with numeric data, readtable imports empty text as NaN
values, and also imports . and NA as NaN values when you specify them using TreatAsMissing.
However, the values that are -99 remain unchanged because they are numeric.
messyTable = readtable("messy.csv","TextType","string","TreatAsMissing",[".","NA"])
messyTable=21×5 table
A B C D E
______ ____ _________ ____ ____
9-19
9 Tables
To view a summary of the table, use the summary function. The summary shows the data type and
other descriptive statistics for each table variable. For example, summary shows the number of
missing values in each numeric variable of messyTable.
summary(messyTable)
Variables:
A: string
B: double
C: string
D: double
E: double
A 0
B 3 -99 22.5000 563 90.1056 174.0532
C 1
D 2 -99 14 563 83.8000 171.0755
E 1 -99 21.5000 563 81.5950 166.7100
To find the rows of messyTable that have at least one missing value, use the ismissing function. If
you have nonstandard missing values in your data, such as -99, you can specify it along with the
standard missing values.
The output of ismissing is a logical array that identifies the elements of messyTable that have
missing values.
missingElements = ismissing(messyTable,{string(missing),NaN,-99})
0 1 0 0 0
0 1 0 0 0
0 1 0 1 1
0 0 1 1 0
0 1 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
⋮
To create a logical vector that identifies rows that have missing values, use the any function.
rowsWithMissingValues = any(missingElements,2)
9-20
Clean Messy and Missing Data in Tables
1
1
1
1
1
0
0
0
0
0
⋮
To index into the table and return only the rows that have missing values, use the logical vector
rowsWithMissingValues.
missingValuesTable = messyTable(rowsWithMissingValues,:)
missingValuesTable=6×5 table
A B C D E
______ ____ _________ ___ ____
One strategy for cleaning the missing values in a table is to replace them with more meaningful
values. You can replace nonstandard missing values by inserting standard missing values. Then you
can fill missing values with adjusted values. For example, you can fill missing values with their
nearest neighbors or with the mean value of a table variable.
In this example, -99 is a nonstandard value for indicating a missing value. To replace the instances of
-99 with standard missing values, use the standardizeMissing function. NaN is the standard
missing value for single- and double-precision floating-point numeric arrays.
messyTable = standardizeMissing(messyTable,-99)
messyTable=21×5 table
A B C D E
______ ____ _________ ____ ____
9-21
9 Tables
"oii4" 5 "yes" 5 5
"wnk3" 245 "yes" 245 245
"abk6" 563 "no" 563 563
"pnj5" 463 "no" 463 463
"wnn3" 6 "no" 6 6
"oks9" 23 "yes" 23 23
"wba3" 14 "yes" 14 14
⋮
To fill missing values, use the fillmissing function. The function provides many methods that fill
missing values. For example, fill missing values with their nearest neighbors that are not missing
values.
filledTable = fillmissing(messyTable,"nearest")
filledTable=21×5 table
A B C D E
______ ____ _____ ____ ____
Another strategy for cleaning the missing values in a table is to remove the rows that have them.
To remove rows that have missing values, use the rmmissing function.
remainingTable = rmmissing(messyTable)
remainingTable=15×5 table
A B C D E
______ ____ _____ ____ ____
9-22
Clean Messy and Missing Data in Tables
Once you have cleaned the missing values in a table, you can organize it in other ways. For example,
you can sort the rows of a table by the values in one or more variables.
sortedTable=15×5 table
A B C D E
______ ____ _____ ____ ____
Sort the rows in descending order by C, and then sort in ascending order by A.
sortedBy2Vars = sortrows(remainingTable,["C","A"],["descend","ascend"])
sortedBy2Vars=15×5 table
A B C D E
______ ____ _____ ____ ____
9-23
9 Tables
"pkn4" 2 "no" 2 2
"ple2" 2 "no" 2 2
"pnj5" 463 "no" 463 463
"wnn3" 6 "no" 6 6
Sorting by C, the rows are grouped first by "yes", followed by "no". Then sorting by A, the rows are
listed alphabetically.
To reorder the table so that A and C are next to each other, use the movevars function.
sortedRowsAndMovedVars = movevars(sortedBy2Vars,"C","After","A")
sortedRowsAndMovedVars=15×5 table
A C B D E
______ _____ ____ ____ ____
You can also reorder table variables by indexing. Use smooth parentheses and a variable index that
specifies the order of the variables in the output table.
sortedRowsAndMovedVars = sortedBy2Vars(:,["A","C","B","D","E"])
sortedRowsAndMovedVars=15×5 table
A C B D E
______ _____ ____ ____ ____
9-24
Clean Messy and Missing Data in Tables
"wnn3" "no" 6 6 6
See Also
table | ismissing | standardizeMissing | fillmissing | rmmissing | sortrows | movevars |
Import Tool | readtable | summary
Related Examples
• “Missing Data in MATLAB”
• “Clean Messy Data and Locate Extrema Using Live Editor Tasks”
• “Access Data in Tables” on page 9-37
• “Add and Delete Table Rows” on page 9-9
• “Add, Delete, and Rearrange Table Variables” on page 9-12
• “Rename and Describe Table Variables” on page 9-26
• “Summarize or Pivot Data in Tables Using Groups”
9-25
9 Tables
Tables, which hold data in column-oriented variables, provide properties that can store more
descriptive information about the data. For instance, the variable names are stored in a property, so if
you want to rename variables to be more descriptive, you can change a table property to do so. This
example shows how to access and change table properties, including the names, descriptions, and
units of table variables. The example also shows how to produce a table summary to view these
properties with statistics about the data in the table variables.
Create a table using a subset of the sample patient data from the file patients.mat.
load patients.mat
BloodPressure = [Systolic Diastolic];
LastName = string(LastName);
T = table(LastName,Age,Height,Weight,Smoker,BloodPressure)
T=100×6 table
LastName Age Height Weight Smoker BloodPressure
__________ ___ ______ ______ ______ _____________
A table has properties that you can use to describe the table as a whole as well as its individual
variables.
A table stores its properties in a Properties object. To access the properties of a table, use dot
notation.
T.Properties
ans =
TableProperties with properties:
Description: ''
UserData: []
9-26
Rename and Describe Table Variables
You can also use dot notation to access a specific property. For example, access the property that
stores the array of variable names.
T.Properties.VariableNames
Variable names are most useful when they are descriptive. So, you might want to rename variables in
your table.
The recommended way to rename variables is to use the renamevars function. For example, rename
the LastName variable of T to PatientName.
T = renamevars(T,"LastName","PatientName")
T=100×6 table
PatientName Age Height Weight Smoker BloodPressure
___________ ___ ______ ______ ______ _____________
T.Properties.VariableNames("BloodPressure") = "BP"
9-27
9 Tables
T=100×6 table
PatientName Age Height Weight Smoker BP
___________ ___ ______ ______ ______ __________
To change any other table property, you must use dot notation. In general, you can use the other
properties to annotate the table with information that describes it or the variables.
For example, add a description for the table as a whole. Assign a string to the Description
property. Also, add units that are associated with the table variables. Assign a string array of the units
to the VariableUnits property. While the property stores a cell array of character vectors, you can
assign values to it using a string array. An individual empty string within the string array indicates
that the corresponding variable does not have units.
ans =
TableProperties with properties:
You can also assign values by indexing into properties. For example, add descriptions for the
PatientName and BP variables only. You can index by name or by the position a variable has in the
table.
9-28
Rename and Describe Table Variables
ans =
TableProperties with properties:
You cannot delete table properties. However, you can delete the values stored in table properties.
Remove the description for the LastName variable. The descriptions are text, so remove it by
assigning an empty string as the new description.
T.Properties.VariableDescriptions(1) = "";
T.Properties
ans =
TableProperties with properties:
Remove all the descriptions in VariableDescriptions. To remove all the values stored in a table
property, assign an empty array.
T.Properties.VariableDescriptions = {};
T.Properties
ans =
TableProperties with properties:
9-29
9 Tables
ans =
TableProperties with properties:
You can produce a table summary to view its properties with statistics about each variable. To
produce this summary, use the summary function. The summary displays the description of the table
and the descriptions and units for each variable. The summary also displays statistics for table
variables whose data types support the required calculations.
summary(T)
T: 100x6 table
Variables:
9-30
Rename and Describe Table Variables
PatientName 0
Age 0 25 39 50 38.2800 7.2154
Height 0 60 67 72 67.0700 2.8365
Weight 0 111 142.5000 202 154 26.5714
BP(:,1) 0 109 122 138 122.7800 6.7128
BP(:,2) 0 68 81.5000 99 82.9600 6.9325
You can also store the summary in a structure instead of displaying it.
S = summary(T)
S.BP
See Also
table | renamevars | summary
Related Examples
• “Access Data in Tables” on page 9-37
• “Add, Delete, and Rearrange Table Variables” on page 9-12
• “Add Custom Properties to Tables and Timetables” on page 9-32
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Calculations When Tables Have Both Numeric and Nonnumeric Data” on page 9-66
9-31
9 Tables
This example shows how to add custom properties to tables and timetables, set and access their
values, and remove them.
All tables and timetables have properties that contain metadata about them or their variables. You
can access these properties through the T.Properties object, where T is the name of the table or
timetable. For example, T.Properties.VariableNames returns a cell array containing the names
of the variables of T.
The properties you access through T.Properties are part of the definitions of the table and
timetable data types. You cannot add or remove these predefined properties. But starting in
R2018b, you can add and remove your own custom properties, by modifying the
T.Properties.CustomProperties object of a table or timetable.
Add Properties
Read power outage data into a table. Sort it using the first variable that contains dates and times,
OutageTime. Then display the first three rows.
T = readtable('outages.csv');
T = sortrows(T,'OutageTime');
head(T,3)
Display its properties. These are the properties that all tables have in common. Note that there is also
a CustomProperties object, but that by default it has no properties.
T.Properties
ans =
TableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Row' 'Variables'}
VariableNames: {'Region' 'OutageTime' 'Loss' 'Customers' 'RestorationTime' 'Cause
VariableTypes: ["cell" "datetime" "double" "double" "datetime" "cell"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowNames: {}
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
To add custom properties, use the addprop function. Specify the names of the properties. For each
property, also specify whether it has metadata for the whole table (similar to the Description
property) or for its variables (similar to the VariableNames property). If the property has variable
metadata, then its value must be a vector whose length is equal to the number of variables.
9-32
Add Custom Properties to Tables and Timetables
Add custom properties that contain an output file name, file type, and indicators of which variables to
plot. Best practice is to assign the input table as the output argument of addprop, so that the custom
properties are part of the same table. Specify that the output file name and file type are table
metadata using the 'table' option. Specify that the plot indicators are variable metadata using the
'variable' option.
T = addprop(T,{'OutputFileName','OutputFileType','ToPlot'}, ...
{'table','table','variable'});
T.Properties
ans =
TableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Row' 'Variables'}
VariableNames: {'Region' 'OutageTime' 'Loss' 'Customers' 'RestorationTime' 'Cause
VariableTypes: ["cell" "datetime" "double" "double" "datetime" "cell"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowNames: {}
When you add custom properties using addprop, their values are empty arrays by default. You can
set and access the values of the custom properties using dot syntax.
Set the output file name and type. These properties contain metadata for the table. Then assign a
logical array to the ToPlot property. This property contains metadata for the variables. In this
example, the elements of the value of the ToPlot property are true for each variable to be included
in a plot, and false for each variable to be excluded.
T.Properties.CustomProperties.OutputFileName = 'outageResults';
T.Properties.CustomProperties.OutputFileType = '.mat';
T.Properties.CustomProperties.ToPlot = [false false true true true false];
T.Properties
ans =
TableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Row' 'Variables'}
VariableNames: {'Region' 'OutageTime' 'Loss' 'Customers' 'RestorationTime' 'Cause
VariableTypes: ["cell" "datetime" "double" "double" "datetime" "cell"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowNames: {}
9-33
9 Tables
OutputFileName: 'outageResults'
OutputFileType: '.mat'
ToPlot: [0 0 1 1 1 0]
Plot variables from T in a stacked plot using the stackedplot function. To plot only the Loss,
Customers, and RestorationTime values, use the ToPlot custom property as the second input
argument.
stackedplot(T,T.Properties.CustomProperties.ToPlot);
When you move or delete table variables, both the predefined and custom properties are reordered so
that their values correspond to the same variables. In this example, the values of the ToPlot custom
property stay aligned with the variables marked for plotting, just as the values of the
VariableNames predefined property stay aligned.
T.Customers = [];
T.Properties
ans =
TableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Row' 'Variables'}
9-34
Add Custom Properties to Tables and Timetables
Convert the table to a timetable, using the outage times as row times. Move Region to the end of the
table, and RestorationTime before the first variable, using the movevars function. Note that the
properties are reordered appropriately. The RestorationTime and Loss variables still have
indicators for inclusion in a plot.
T = table2timetable(T);
T = movevars(T,'Region','After','Cause');
T = movevars(T,'RestorationTime','Before',1);
T.Properties
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'OutageTime' 'Variables'}
VariableNames: {'RestorationTime' 'Loss' 'Cause' 'Region'}
VariableTypes: ["datetime" "double" "cell" "cell"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [1468x1 datetime]
StartTime: 2002-02-01 12:18
SampleRate: NaN
TimeStep: NaN
Events: []
Remove Properties
You can remove any or all of the custom properties of a table using the rmprop function. However,
you cannot use it to remove predefined properties from T.Properties, because those properties are
part of the definition of the table data type.
Remove the OutputFileName and OutputFileType custom properties. Display the remaining table
properties.
T = rmprop(T,{'OutputFileName','OutputFileType'});
T.Properties
9-35
9 Tables
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'OutageTime' 'Variables'}
VariableNames: {'RestorationTime' 'Loss' 'Cause' 'Region'}
VariableTypes: ["datetime" "double" "cell" "cell"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [1468x1 datetime]
StartTime: 2002-02-01 12:18
SampleRate: NaN
TimeStep: NaN
Events: []
See Also
readtable | table | head | addprop | table2timetable | movevars | rmprop | sortrows |
stackedplot
Related Examples
• “Rename and Describe Table Variables” on page 9-26
• “Access Data in Tables” on page 9-37
• “Add, Delete, and Rearrange Table Variables” on page 9-12
9-36
Access Data in Tables
A table is a container that stores column-oriented data in variables. To access the data in a table, you
can index into the table by specifying rows and variables, just as you can index into a matrix by
specifying rows and columns. Table variables have names, just as the fields of a structure have
names. The rows of a table also can have names, but row names are not required. To index into a
table, specify rows and variables using either positions, names, or data types. The result can be either
an array or a table.
This topic describes the different table indexing syntaxes and when to use each type. Additional
examples show the different ways to apply these table indexing types. The table at the end of the
topic summarizes the indexing syntaxes, how to specify rows and variables, and the resulting outputs.
• Dot notation, as in T.varname or T.(expression), extracts an array from one table variable.
• Curly braces, as in T{rows,vars}, extract an array from the specified rows and variables. The
variables must have compatible data types so that they can be concatenated into one array.
• Parentheses, as in T(rows,vars), return a table that has only the specified rows and variables.
9-37
9 Tables
T = table([1;2;3;4;5],[5;10;15;20;25],[150;300;450;600;750])
• To access one table variable, use dot notation. Specify a variable name or an expression that
matches the name or position of a variable.
Using literal names of variables is faster than using expressions. For example, T.Var1 and T.(1)
both access the first variable of T, but using the expression is slower.
X = T.Var1
Y = T.Var1(1:3)
Z = T.(1)
T.Var1 = T.Var1 .* 10
You can also specify one variable using curly braces. However, accessing a variable using dot
notation is faster than accessing a variable using curly braces.
• To access multiple table variables, use curly braces.
X = T{:,["Var1","Var2"]}
Y = T{1:3,["Var1","Var2"]}
T{:,["Var1","Var2"]} = T{:,["Var1","Var2"]} .* 10
9-38
Access Data in Tables
• To return a table that has only specified rows and variables, use parentheses.
T2 = T(:,["Var1","Var2"])
T2 = T(1:3,["Var1","Var2"])
A = rand(5,1)
B = rand(5,1)
T(:,["Var1","Var2"]) = table(A,B)
You can index into tables by specifying numeric indices, row and variable names, or variable data
types.
Create a table. Load arrays of data from the sample patients.mat file. Then create a table from
these arrays using the table function. The names of the input arrays become the names of the table
variables. Row names are optional. To specify row names, use the RowNames name-value argument.
T=100×4 table
Age Height Weight Smoker
___ ______ ______ ______
Index by Position
You can index into tables by specifying positions as numeric indices. You can also use colons and the
end keyword.
For example, index into the first three rows of T. This syntax is a compact way to return a table with
the specified number of rows.
firstRows = T(1:3,:)
firstRows=3×4 table
Age Height Weight Smoker
9-39
9 Tables
Return a table with the first two variables and the last three rows of T.
lastRows = T(end-2:end,1:2)
lastRows=3×2 table
Age Height
___ ______
Griffin 49 70
Diaz 45 68
Hayes 48 66
If the variables have compatible data types, then you can use curly braces to return the extracted
data as an array.
lastRowsAsArray = T{end-2:end,1:2}
lastRowsAsArray = 3×2
49 70
45 68
48 66
You can index into tables by specifying variable names using a string array. Table variable names do
not have to be valid MATLAB® identifiers. They can include spaces and non-ASCII characters, and
can start with any character.
For example, return a table that has only the first three rows of T and the Height and Weight
variables.
variablesByName = T(1:3,["Height","Weight"])
variablesByName=3×2 table
Height Weight
______ ______
Smith 71 176
Johnson 69 163
Williams 64 131
arraysFromVariables = 3×2
71 176
9-40
Access Data in Tables
69 163
64 131
You can also use dot notation to index into one variable. In fact, dot notation is more efficient when
you access just one variable.
heightAsArray = T.Height
heightAsArray = 100×1
71
69
64
67
64
68
64
68
68
66
⋮
Use dot notation to return the first three rows of the Height variable as an array.
firstHeights = T.Height(1:3)
firstHeights = 3×1
71
69
64
If a table has row names, you can index into it by row name, not just by row number. For example,
return rows of T for three specific patients.
rowsByName = T(["Griffin","Diaz","Hayes"],:)
rowsByName=3×4 table
Age Height Weight Smoker
___ ______ ______ ______
You can also use curly braces to return the data as an array.
arraysFromRows = T{["Griffin","Diaz","Hayes"],:}
arraysFromRows = 3×4
49 70 186 0
45 68 172 1
9-41
9 Tables
48 66 177 0
To index into one element of a table, specify one row and one variable. Use curly braces to return the
element as an array, a scalar value in this case.
oneElement = T{"Diaz","Height"}
oneElement =
68
To return that element as a table with one row and one variable, use parentheses.
oneElementTable = T("Diaz","Height")
oneElementTable=table
Height
______
Diaz 68
To index into a table by specifying variables that have the same data type, create a data type
subscript using the vartype function.
For example, create a data type subscript to match numeric table variables.
numSubscript = vartype("numeric")
numSubscript =
table vartype subscript:
Return a table that has only the numeric variables of T. The Smoker variable is not included because
it is a logical variable.
onlyNumVariables = T(:,numSubscript)
onlyNumVariables=100×3 table
Age Height Weight
___ ______ ______
Smith 38 71 176
Johnson 43 69 163
Williams 38 64 131
Jones 40 67 133
Brown 49 64 119
Davis 46 68 142
Miller 33 64 142
Wilson 40 68 180
Moore 28 68 183
Taylor 31 66 132
Anderson 45 68 128
9-42
Access Data in Tables
Thomas 42 66 137
Jackson 25 71 174
White 39 72 202
Harris 36 65 129
Martin 48 71 181
⋮
You can use any indexing syntax to assign values to a table. You can assign values to variables, rows,
or individual elements.
Import power outage data from a spreadsheet into a table using the readtable function.
outages = readtable("outages.csv",TextType="string")
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
To assign values to one variable, use dot notation. For example, scale the Loss variable by a factor of
100.
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
9-43
9 Tables
You can also assign data to multiple variables by using curly braces. The variables must have
compatible data types. For example, scale Loss and Customers by a factor of 1/10,000.
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ _______ _________ ________________ ______________
To assign one row to a table, you can use either a one-row table or a cell array. In this case, using a
cell array can be more convenient than creating and assigning a one-row table.
For example, assign data to a new row at the end of outages. Display the end of the table.
outages(end+1,:) = {"East",datetime("now"),17.3,325,datetime("tomorrow"),"unknown"};
outages(end-2:end,:)
ans=3×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ________ _________ ________________ _____________
9-44
Access Data in Tables
To assign data to multiple rows, assign values from another table that has variables with the same
names and data types. For example, create a new two-row table.
newOutages = table(["West";"North"], ...
datetime(2024,1,1:2)', ...
[3;4], ...
[300;400], ...
datetime(2024,1,3:4)',["unknown";"unknown"], ...
VariableNames=outages.Properties.VariableNames)
newOutages=2×6 table
Region OutageTime Loss Customers RestorationTime Cause
_______ ___________ ____ _________ _______________ _________
Assign the two-row table to the first two rows of outages. Then display the first four rows of
outages.
outages(1:2,:) = newOutages;
outages(1:4,:)
ans=4×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ _________ ________________ _______________
To assign values to elements of a table, use curly braces. For example, assign causes for the first two
outages.
outages{1,"Cause"} = "severe storm";
outages{2,"Cause"} = "attack";
outages(1:4,:)
ans=4×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ _________ ________________ _______________
9-45
9 Tables
To find the rows of a table where values meet conditions, use logical indexing. Specify the table
variables that have values of interest and create an array of row indices where values in those
variables meet conditions that you specify. Index into the table using the row indices.
outages = readtable("outages.csv",TextType="string")
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
___________ ________________ ______ __________ ________________ ______________
Next, create row indices that match the rows where a variable meets a condition. For example, create
indices for rows where the region is West.
rows = matches(outages.Region,"West")
0
0
0
1
0
1
1
1
0
0
⋮
You can index into a table with logical indices. Display the rows of the table for the outages that occur
in the West region.
outages(rows,:)
ans=354×6 table
Region OutageTime Loss Customers RestorationTime Cause
9-46
Access Data in Tables
You can match multiple conditions with one logical expression. For example, find the rows where
outages affected more than one million customers in the West or MidWest regions.
ans=10×6 table
Region OutageTime Loss Customers RestorationTime Cause
_________ ________________ ______ __________ ________________ ________________
• Linear indexing is not supported. When you index with curly braces or parentheses, you must
specify both rows and variables.
• Variable names and row names can include any characters, including spaces and non-ASCII
characters. Also, they can start with any character, not just letters. Variable and row names do not
have to be valid MATLAB identifiers (as determined by the isvarname function).
9-47
9 Tables
• When you specify rows or variables by name, you can use a pattern object to specify names. For
example, "Var" + digitsPattern matches all names that start with Var and end with any
number of digits.
Array extracted
from the first
table variable
9-48
Access Data in Tables
First five
elements of
array extracted
from table
variable named
Date
• T.
("2019-06-30
")(1:5)
First five
elements of
array extracted
from table
variable named
2019-06-30
• T.(1)(1:5)
First five
elements of
array extracted
from the first
table variable
• T.Var1(1:5,1
:3)
9-49
9 Tables
Array
concatenated
from all rows
and the
variables
named A and B
• T{:,"A" +
wildcardPatt
ern}
Array
concatenated
from all rows
and the
variables whose
names start
with A
9-50
Access Data in Tables
9-51
9 Tables
9-52
Access Data in Tables
See Also
table | readtable | vartype | matches
Related Examples
• “Tables of Mixed Data” on page 9-86
• “Create Tables and Assign Data to Them” on page 9-2
• “Rename and Describe Table Variables” on page 9-26
• “Calculations When Tables Have Both Numeric and Nonnumeric Data” on page 9-66
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Find Array Elements That Meet Conditions” on page 5-2
9-53
9 Tables
Since R2023a
You can perform calculations directly on tables and timetables without extracting their data by
indexing. To perform direct calculations with the same syntaxes used for arrays, your tables and
timetables must meet several conditions:
• All variables of your tables and timetables must have data types that support calculations.
• If you perform an operation where only one operand is a table or timetable, then the other
operand must be a numeric or logical array.
• If you perform an operation where both operands are tables or timetables, then they must have
compatible sizes.
This example shows how perform operations without indexing into your tables and timetables. You
can also call common mathematical and statistical functions, such as sum, mean, and cumsum. This
example also shows how to perform operations on tables and timetables when their rows and
variables are in different orders but have matching names (or, in the case of timetables, matching row
times). For a complete list of supported functions and operations, as well as related rules for their
use, see “Rules for Table and Timetable Mathematics” on page 9-61.
Before R2023a, or for tables and timetables that have a mix of numeric and nonnumeric variables,
see “Calculations When Tables Have Both Numeric and Nonnumeric Data” on page 9-66.
A simple arithmetic operation is to scale a table by a constant. If all your table variables support
multiplication, then you can scale your table without extracting data from it.
For example, read data from a CSV (comma-separated values) file, testScoresNumeric.csv, into a
table by using the readtable function. The sample file contains 10 test scores for each of three
tests.
testScores = readtable("testScoresNumeric.csv")
testScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
90 87 93
87 85 83
86 85 88
75 80 72
89 86 87
96 92 98
78 75 77
91 94 92
86 83 85
79 76 82
The test scores are based on a 100-point scale. To convert them to scores on a 25-point scale, multiply
the table by 0.25. To multiply tables and timetables, use the times operator, .*.
9-54
Direct Calculations on Tables and Timetables
scaledScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
If different tests have different scales, then you can multiply the table by a vector. When you perform
operations where one operand is a table or timetable, then the other operand must be a scalar, vector,
matrix, table, or timetable that has a compatible size.
For example, use a row vector to weight each test by a different factor.
weightedScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
18 26.1 46.5
17.4 25.5 41.5
17.2 25.5 44
15 24 36
17.8 25.8 43.5
19.2 27.6 49
15.6 22.5 38.5
18.2 28.2 46
17.2 24.9 42.5
15.8 22.8 41
Tables also support common mathematical and statistical functions. For example, calculate the sum of
the weighted test scores across each row of the table. To sum across rows, specify the second
dimension of the table when you call sum.
sumScores = sum(weightedScores,2)
sumScores=10×1 table
sum
____
90.6
84.4
86.7
75
9-55
9 Tables
87.1
95.8
76.6
92.4
84.6
79.6
To calculate the mean score of each test, use the mean function. By default, mean calculates along the
variables, the first dimension of the table.
meanScores = mean(weightedScores)
meanScores=1×3 table
Test1 Test2 Test3
_____ _____ _____
Timetables support the same operations and mathematical and statistical functions that tables
support.
For example, load a timetable that records the main shock amplitude of an earthquake over a period
of 50 seconds, sampled at 200 Hz. The three timetable variables correspond to three directional
components of the shockwave as measured by an accelerometer.
load quakeData
quakeData
quakeData=10001×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
0.005 sec 5 3 0
0.01 sec 5 3 0
0.015 sec 5 2 0
0.02 sec 5 2 0
0.025 sec 5 2 0
0.03 sec 5 2 0
0.035 sec 5 1 0
0.04 sec 5 1 0
0.045 sec 5 1 0
0.05 sec 5 0 0
0.055 sec 5 0 0
0.06 sec 5 0 0
0.065 sec 5 0 0
0.07 sec 5 0 0
0.075 sec 5 0 0
0.08 sec 5 0 0
⋮
Calculate the propagation speed of the shockwave. First, multiply the timetable by the gravitational
acceleration.
quakeData = 0.098 .* quakeData
9-56
Direct Calculations on Tables and Timetables
quakeData=10001×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
Then calculate the propagation speed by integrating the acceleration data. You can approximate the
integration by calculating the cumulative sum of each variable. Scale the cumulative sums by the
time step of the timetable. The cumsum function returns a timetable that has the same size and the
same row times as the input.
speedQuake=10001×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
Calculate the means of the scaled cumulative sums. The mean function returns the output as a one-
row table.
meanQuake = mean(speedQuake)
9-57
9 Tables
meanQuake=1×3 table
EastWest NorthSouth Vertical
________ __________ ________
Center the scaled cumulative sums by subtracting the means. The output is a timetable with the
propagation speeds for each component.
speedQuake=10001×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
Tables and timetables have variables, and the variables have names. Table rows can also have row
names. And timetable rows always have row times. When operating on two tables or timetables, their
variables and rows must meet these conditions:
• Both operands must have the same size, or one of them must be a one-row table.
• Both operands must have variables with the same names. However, the variables in each operand
can be in a different order.
• If both operands are tables and have row names, then their row names must be the same.
However, the row names in each operand can be in a different order.
• If both operands are timetables, then their row times must be the same. However, the row times in
each operand can be in a different order.
For example, create two tables and add them. These tables have variable names but no row names.
The variables are in the same order.
A = table([1;2],[3;4],VariableNames=["V1","V2"])
A=2×2 table
V1 V2
9-58
Direct Calculations on Tables and Timetables
__ __
1 3
2 4
B = table([1;3],[2;4],VariableNames=["V1","V2"])
B=2×2 table
V1 V2
__ __
1 2
3 4
C = A + B
C=2×2 table
V1 V2
__ __
2 5
5 8
Now create two tables that have row names and variables in different orders.
A = table([1;2],[3;4],VariableNames=["V1","V2"],RowNames=["R1","R2"])
A=2×2 table
V1 V2
__ __
R1 1 3
R2 2 4
B = table([4;2],[3;1],VariableNames=["V2","V1"],RowNames=["R2","R1"])
B=2×2 table
V2 V1
__ __
R2 4 3
R1 2 1
Add the tables. The result is a table that has variables and rows in the same orders as the variables
and rows of the first table in the expression.
C = A + B
C=2×2 table
V1 V2
__ __
R1 2 5
R2 5 8
9-59
9 Tables
Similarly, add two timetables. The result is a timetable with variables and row times in the same
orders as in the first timetable.
A = timetable(seconds([15;30]),[1;2],[3;4],VariableNames=["V1","V2"])
A=2×2 timetable
Time V1 V2
______ __ __
15 sec 1 3
30 sec 2 4
B = timetable(seconds([30;15]),[4;2],[3;1],VariableNames=["V2","V1"])
B=2×2 timetable
Time V2 V1
______ __ __
30 sec 4 3
15 sec 2 1
C = A + B
C=2×2 timetable
Time V1 V2
______ __ __
15 sec 2 5
30 sec 5 8
See Also
table | timetable | readtable
Related Examples
• “Access Data in Tables” on page 9-37
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
9-60
Rules for Table and Timetable Mathematics
You can perform calculations directly on tables and timetables without indexing to extract their data.
Most of the common functions and operators for mathematics and statistics support tables and
timetables. Operations on tables and timetables have rules about data types and sizes as well as
variable names, row names, row times, and variable units. Operations on tables and timetables whose
variables have units also have rules for propagating those units into the output table or timetable.
An event table is a kind of timetable. So, you can also perform calculations directly on event tables.
They follow the same rules that timetables follow. However, they have additional properties that
specify event labels and event durations. These properties impose additional constraints when you
perform operations on event tables.
These functions and operators also support direct calculations on event tables.
• Arithmetic functions and operators — +, -, .*, ./, .\, .^, abs, ceil, cumprod, cumsum,
diff, fix, floor, mod, prod, rem, round, sum
• Relational operators — ==, >=, >, <=, <, ~=
• Logical operators — &, ~, |, xor
• Trigonometric functions — acos, acosd, acosh, acot, acotd, acoth, acsc, acscd, acsch,
asec, asecd, asech, asin, asind, asinh, atan, atan2, atan2d, atand, atanh, cos, cosd,
cosh, cospi, cot, cotd, coth, csc, cscd, csch, sec, secd, sech, sin, sind, sinh, sinpi,
tan, tand, tanh
• Exponential and logarithmic functions — exp, expm1, log, log10, log1p, log2, nextpow2,
nthroot, pow2, reallog, realpow, realsqrt, sqrt
• Statistics functions — bounds, cummax, cummin, max, mean, median, min, mode, var
For example, these statements use arithmetic, relational, and logical operators as well as
mathematics and statistics functions with operands that are tables, timetables, or event tables.
T = T .* 0.5;
T = T1 + T2;
T2 = T > 10;
T2 = ~(T < 0);
T2 = abs(T);
T2 = mean(T);
9-61
9 Tables
• Both operands must have the same size, or one of them must be a one-row table.
• Both operands must have variables with the same names. However, the variables in each operand
can be in a different order.
• If both operands are tables and both have row names, then their row names must be the same.
However, the row names in each operand can be in a different order.
• If both operands are timetables, then their row times must be the same. However, the row times in
each operand can be in a different order.
• If one operand is a timetable and the other operand is a table, then the table cannot have row
names. The output is a timetable.
In general, these rules apply to operations on tables and timetables with variables that have units:
• If the VariableUnits property of a table or timetable is {}, the default value, then the units are
undefined.
• If you specify empty strings, "", as units, then those units are undefined.
• If you perform an operation on two operands, both operands have units, and the units are
incompatible, then the operation returns an error.
• If you perform an operation on two operands and only one operand has units, then the result has
the same units, but the operation also issues a warning.
• If an operation or function would result in modified or compound units, such as a multiplication
that results in units of kg*m, then the result of the operation or function has no units.
Operations and functions do not support unit conversions. For example, if a variable in one table has
units of meters (m), and the corresponding variable in the other table has units of centimeters (cm),
then the operation treats those units as incompatible units. The operation does not attempt to convert
centimeters to meters.
This table shows rules for arithmetic operations when table or timetable variables have units that are
the same (both A), different (A and B), or undefined (one unit is undefined, and the other is either A or
B).
9-62
Rules for Table and Timetable Mathematics
In general, logical operators and exponential, logarithmic, and trigonometric functions do not
propagate units. However, some functions do propagate units when it is known that the output has
the same units as the input. The functions that propagate units are:
• abs
• bounds
• ceil
• cummax
• cummin
• cumsum
• fix
• floor
• max
• mean
• median
• min
• mode (units propagated to first and third outputs only)
• round
• std
• sum
9-63
9 Tables
• The operands must follow the same rules that apply to operations on timetables.
• The EventLabelsVariable property of both event tables must be set to the same variable name,
or it must be unset in both event tables.
• The EventLengthsVariable property of both event tables must be set to the same variable
name, or it must be unset in both event tables.
• The EventEndsVariable property of both event tables must be set to the same variable name,
or it must be unset in both event tables.
When one operand is an event table, and the other is a timetable or a table:
• The operands must follow the same rules that apply to operations on timetables, or to operations
where one operand is a timetable and the other is a table.
• The output is an event table.
• The output event table has the same values for the EventLabelsVariable,
EventLengthsVariable, and EventEndsVariable properties as the input event table.
• The output event table has the same values for the EventLabelsVariable,
EventLengthsVariable, and EventEndsVariable properties as the input event table.
• If the function reduces the event table along the first dimension, then the output is a table. For
example, if you call the mean function on an event table to calculate the mean value of each
variable, then the output is a one-row table.
• If the function reduces the event table along the second dimension, then the output is an event
table. However, the EventLabelsVariable, EventLengthsVariable, and
EventEndsVariable properties of the output event table are unset because its variables have
different names.
For example, if you call the mean function on an event table to calculate the mean value of each
row, then the output is an event table with one variable, named mean. Its
EventLabelsVariable, EventLengthsVariable, and EventEndsVariable properties are
unset.
See Also
table | timetable | eventtable
9-64
Rules for Table and Timetable Mathematics
Related Examples
• “Access Data in Tables” on page 9-37
• “Direct Calculations on Tables and Timetables” on page 9-54
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
9-65
9 Tables
This example shows how to perform calculations on data in tables when they have both numeric and
nonnumeric data. After you identify the table variables that contain numeric data, you can access the
data in those variables by using either curly braces or dot notation. Then you can perform arithmetic
operations or call functions on the numeric data and assign the result back into the table, all in one
line of code. You also can use the rowfun function for calculations across the rows of a table and the
varfun function for calculations along the variables. If your table has groups of data within it, you
can use the groupsummary, rowfun, and varfun functions to perform calculations for each group in
the table.
Read data from a CSV (comma-separated values) file, testScores.csv, into a table by using the
readtable function. The sample file contains test scores for 10 students who attend two different
schools. The output table contains variables that have numeric data and other variables that have text
data. One of these variables, School, has a fixed set of values or categories. These categories denote
two groups of students within this table. Convert School to a categorical variable.
scores = readtable("testScores.csv","TextType","string");
scores.School = categorical(scores.School)
scores=10×5 table
LastName School Test1 Test2 Test3
__________ __________ _____ _____ _____
One straightforward way to work with the numeric data is to create a subtable that has only the
numeric variables. You can create a subtable by indexing into a table using parentheses and
specifying rows and variables. The subtable is a new, smaller table that contains only the specified
rows and variables from the old table.
For example, create a subtable from scores that has only the test scores. Because the first two
variables have nonnumeric data, you can index into this table specifying the other variables.
numericScores = scores(:,3:end)
numericScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
9-66
Calculations When Tables Have Both Numeric and Nonnumeric Data
90 87 93
87 85 83
86 85 88
75 80 72
89 86 87
96 92 98
78 75 77
91 94 92
86 83 85
79 76 82
Another way to specify variables is to use the vartype function to specify them by data type. This
function is useful when you have a large table with many variables that have different data types. It
returns a subscript that you can use to specify table variables.
numericVars = vartype("numeric")
numericVars =
table vartype subscript:
numericScores = scores(:,numericVars)
numericScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
90 87 93
87 85 83
86 85 88
75 80 72
89 86 87
96 92 98
78 75 77
91 94 92
86 83 85
79 76 82
(Since R2023a) You can perform operations on a table directly, as long as all its variables have data
types that support the operations. For more information, see “Direct Calculations on Tables and
Timetables” on page 9-54.
For example, scale the numeric data so the test scores are on a 25-point scale.
numericScores = numericScores .* 0.25
numericScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
9-67
9 Tables
21.5 21.25 22
18.75 20 18
22.25 21.5 21.75
24 23 24.5
19.5 18.75 19.25
22.75 23.5 23
21.5 20.75 21.25
19.75 19 20.5
Before R2023a, you cannot use this syntax. Instead, index into the table using curly braces, or use the
Variables affordance to specify all table rows and variables. These syntaxes return the same result
as the previous operation and work in all releases.
When you use these syntaxes, they extract the table contents and concatenate them into an array,
perform the calculation, and assign the results back into the table. The only requirement is that the
variables must all have data types that allow them to be concatenated.
• With curly braces, you can also specify a subset of rows and variables, as in
numericScores{1:5,["Test1","Test3"]}.
• With Variables, you always get all rows and all variables concatenated into an array.
(Since R2023a) You can also call many mathematical and statistical functions on a table directly. For
example, subtract the minimum value within each table variable from that variable.
numericScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
3.75 3 5.25
3 2.5 2.75
2.75 2.5 4
0 1.25 0
3.5 2.75 3.75
5.25 4.25 6.5
0.75 0 1.25
4 4.75 5
2.75 2 3.25
1 0.25 2.5
Again, before R2023a you cannot use this syntax. Instead, use either of the following syntaxes. They
return the same result and work in all releases.
In all releases, you can also perform calculations on one variable at a time by using dot notation and
variable names. For example, add a correction worth five points to the last set of scores in Test3.
9-68
Calculations When Tables Have Both Numeric and Nonnumeric Data
Because the other table variables are unaffected by operations on an individual variable, you can
perform this kind of calculation in any table. It does not matter whether the other variables have
numeric or nonnumeric data.
numericScores.Test3 = numericScores.Test3 + 5
numericScores=10×3 table
Test1 Test2 Test3
_____ _____ _____
3.75 3 10.25
3 2.5 7.75
2.75 2.5 9
0 1.25 5
3.5 2.75 8.75
5.25 4.25 11.5
0.75 0 6.25
4 4.75 10
2.75 2 8.25
1 0.25 7.5
The full table, scores, has numeric and nonnumeric variables. In all releases, use curly-brace
indexing or dot notation to perform calculations on specified rows and variables within tables.
For example, find the mean, minimum, and maximum values of the test scores for each student.
Calculate these values across each row. Assign them to scores as new table variables.
One simple, useful way is to extract the data into a matrix, call a function on it, and then assign the
output to a new table variable. For example, calculate the mean test scores across each row. Then
add them to scores in a new table variable, TestMean. Use curly braces to extract the numeric data
from Test1, Test2, and Test3 into a matrix. To calculate the mean across rows, specify the
dimension as 2 when you call mean.
vars = ["Test1","Test2","Test3"];
scores.TestMean = mean(scores{:,vars},2)
scores=10×6 table
LastName School Test1 Test2 Test3 TestMean
__________ __________ _____ _____ _____ ________
Another way to perform calculations across rows is to use the rowfun function. You do not need to
extract data from the table when using rowfun. Instead, pass the table and a function to apply to the
9-69
9 Tables
data as input arguments to rowfun. While the syntax is a little more complex, rowfun can be useful
when the function that you apply takes multiple input arguments or returns multiple output
arguments.
For example, use the bounds function to find the minimum and maximum test scores. The bounds
function returns two output arguments, so apply it to scores by using rowfun. The output of
rowfun is a new table that has TestMin and TestMax variables. In this case, also specify
"SeparateInputs" as false so that values across each row are combined into a vector before
being passed to bounds.
minmaxTest=10×2 table
TestMin TestMax
_______ _______
87 93
83 87
85 88
72 80
86 89
92 98
75 78
91 94
83 86
76 82
Concatenate scores and minmaxTest so that these values are in one table.
scores=10×8 table
LastName School Test1 Test2 Test3 TestMean TestMin TestMax
__________ __________ _____ _____ _____ ________ _______ _______
Find the mean score for each test. Calculate these values along the table variables.
9-70
Calculations When Tables Have Both Numeric and Nonnumeric Data
The simplest way is to use mean. First use curly braces to extract the numeric data from Test1,
Test2, and Test3 into a matrix. Then call mean to calculate the mean of each column of the matrix.
The output is a numeric vector where each element is the mean of a table variable.
vars = ["Test1","Test2","Test3"];
meanOfEachTest = mean(scores{:,vars})
meanOfEachTest = 1×3
Another way to perform calculations along table variables is to use the varfun function. You do not
need to extract data from the table when using varfun. Instead, pass the table and a function to
apply to the data as input arguments to varfun.
Calculate the mean scores using varfun. The output is a new table with meaningful names for the
table variables.
meanOfEachTest=1×3 table
mean_Test1 mean_Test2 mean_Test3
__________ __________ __________
If your table has one or more grouping variables, then you can perform calculations on groups of data
within the table. You can use the values in a grouping variable to specify the groups that the rows
belong to.
For example, the School variable in scores has two values, ABC School and XYZ School. You can
think of these two values as categories that denote groups of data in scores. In this case, you can
perform calculations by school.
To apply a function and use grouping variables, you can use the varfun function. You can specify a
function, such as mean, and then use varfun to apply it to each table variable that you specify. When
you also specify grouping variables, varfun applies the function to each group within each table
variable.
vars = ["Test1","Test2","Test3"];
meanScoresBySchool = varfun(@mean, ...
scores, ...
"InputVariables",vars, ...
"GroupingVariables","School")
meanScoresBySchool=2×5 table
School GroupCount mean_Test1 mean_Test2 mean_Test3
__________ __________ __________ __________ __________
9-71
9 Tables
Starting in R2018a, you also can use the groupsummary function to perform calculations on groups
of data in each table variable.
meanScoresBySchool = groupsummary(scores,"School","mean",vars)
meanScoresBySchool=2×5 table
School GroupCount mean_Test1 mean_Test2 mean_Test3
__________ __________ __________ __________ __________
The syntax for groupsummary is a bit simpler. Also, you can use groupsummary to specify multiple
methods at once. For example, find both the minimum and maximum scores of each test by school.
minmaxBySchool = groupsummary(scores,"School",["min","max"],vars)
minmaxBySchool=2×8 table
School GroupCount min_Test1 max_Test1 min_Test2 max_Test2 min_Test3
__________ __________ _________ _________ _________ _________ _________
ABC School 5 75 96 80 94 72
XYZ School 5 78 90 75 87 77
To use all the predefined methods of groupsummary, specify "all" as the method. Calculate all
statistics on the mean test score by school.
allStatsBySchool = groupsummary(scores,"School","all","TestMean")
allStatsBySchool=2×14 table
School GroupCount mean_TestMean sum_TestMean min_TestMean max_TestMean
__________ __________ _____________ ____________ ____________ ____________
Sometimes you might want to find a particular value in one table variable and then find the
corresponding value in another table variable. In such cases use rowfun.
For example, find the student in each school who had the highest mean test score. The attached
supporting function, findNameAtMax, returns both the highest score and the name of the student
who had that score. Use rowfun to apply findNameAtMax to each group of students. The rowfun
function is suitable because findNameAtMax has multiple input arguments (last names and test
scores) and also returns multiple output arguments.
9-72
Calculations When Tables Have Both Numeric and Nonnumeric Data
maxScoresBySchool=2×4 table
School GroupCount max_TestMean LastName
__________ __________ ____________ _________
Supporting Function
See Also
table | rowfun | varfun | groupsummary | readtable | vartype
Related Examples
• “Access Data in Tables” on page 9-37
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Summarize or Pivot Data in Tables Using Groups”
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
9-73
9 Tables
You can perform calculations on groups of data within table variables. In such calculations, you split
one or more table variables into groups of data, perform a calculation on each group, and combine
the results into one or more output variables. MATLAB® provides several functions that split data
into groups and combine the results for you. You need only specify which table variables contain data,
which variables define groups, and the function to apply to the groups of data.
For example, this diagram shows a simple grouped calculation that splits a numeric table variable
into two groups of data, calculates the mean of each group, and then combines the mean values into
an output variable.
You can perform grouped calculations on table variables by using any of these functions:
In most cases, groupsummary is the recommended function for grouped calculations. It is simple to
use and returns a table with labels that describe results. The other listed functions, however, also
offer capabilities that can be useful in some situations.
This topic has examples that use each of these functions. It ends with a summary of their behaviors
and recommended usages.
The sample spreadsheet outages.csv contains data values that represent electric utility power
outages in the United States. To create a table from the file, use the readtable function. To read
text data from the file into table variables that are string arrays, specify the TextType name-value
argument as "string".
outages = readtable("outages.csv","TextType","string")
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
9-74
Perform Calculations by Group in Table
Table variables can have any data type. But conceptually, you can also think of tables as having two
general kinds of variables: data variables and grouping variables.
• Data variables enable you to describe individual events or observations. For example, in outages
you can think of the OutageTime, Loss, Customers, and RestorationTime variables as data
variables.
• Grouping variables enable you to group together events or observations that have something in
common. For example, in outages you can think of the Region and Cause variables as grouping
variables. You can group together and analyze the power outages that occur in the same region or
share the same cause.
Often, grouping variables contain a discrete set of fixed values that specify categories. The categories
specify groups that data values can belong to. The categorical data type can be a convenient type
for working with categories.
To convert Region and Cause to categorical variables, use the convertvars function.
outages = convertvars(outages,["Region","Cause"],"categorical")
outages=1468×6 table
Region OutageTime Loss Customers RestorationTime Cause
_________ ________________ ______ __________ ________________ _______________
9-75
9 Tables
You can calculate statistics by group in a table using functions such as groupsummary, varfun, and
splitapply. These functions enable you to specify groups of data within a table and methods that
perform calculations on each group. You can store the results in another table or in output arrays.
For example, determine the mean power loss and customers affected due to the outages in each
region in the outages table. The recommended way to perform this calculation is to use the
groupsummary function. Specify Region as the grouping variable, mean as the method to apply to
each group, and Loss and Customers as the data variables. The output lists the regions (in the
Region variable), the number of power outages per region (in the GroupCount variable), and the
mean power loss and customers affected in each region (in the mean_Loss and mean_Customers
variables, respectively).
meanLossByRegion = groupsummary(outages,"Region","mean",["Loss","Customers"])
meanLossByRegion=5×4 table
Region GroupCount mean_Loss mean_Customers
_________ __________ _________ ______________
• You can specify many common methods (such as max, min, and mean) by name, without using
function handles.
• You can specify multiple methods in one call.
• NaNs, NaTs, and other missing values in the data variables are automatically omitted when
calculating results.
The third point explains why the mean_Loss and mean_Customers variables do not have NaNs in the
meanLossByRegion output table.
To specify multiple methods in one call to groupsummary, list them in an array. For example,
calculate the maximum, mean, and minimum power loss by region.
lossStatsByRegion = groupsummary(outages,"Region",["max","mean","min"],"Loss")
lossStatsByRegion=5×5 table
Region GroupCount max_Loss mean_Loss min_Loss
_________ __________ ________ _________ ________
9-76
Perform Calculations by Group in Table
The minimum loss in every region is zero. To analyze only those outages that resulted in losses
greater than zero, exclude the rows in outages where the loss is zero. First create a vector of logical
indices whose values are logical 1 (true) for rows where outages.Loss is greater than zero. Then
index into outages to return a table that includes only those rows. Again, calculate the maximum,
mean, and minimum power loss by region.
nonZeroLossIndices = outages.Loss > 0;
nonZeroLossOutages = outages(nonZeroLossIndices,:);
nonZeroLossStats = groupsummary(nonZeroLossOutages,"Region",["max","mean","min"],"Loss")
nonZeroLossStats=5×5 table
Region GroupCount max_Loss mean_Loss min_Loss
_________ __________ ________ _________ ________
There are alternative functions that perform grouped calculations in tables. While groupsummary is
recommended, the alternative functions are also useful in some situations.
For example, calculate the maximum power loss by region using varfun. The output table has a
similar format to the output of groupsummary.
maxLossByVarfun = varfun(@max, ...
outages, ...
"InputVariables","Loss", ...
"GroupingVariables","Region")
maxLossByVarfun=5×3 table
Region GroupCount max_Loss
_________ __________ ________
9-77
9 Tables
SouthWest 26 2796
West 354 16659
The last point is a significant difference in behavior between groupsummary and varfun. For
example, the Loss variable has NaNs. If you use varfun to calculate the mean losses, then by default
the results are NaNs, unlike the default groupsummary results.
meanLossByVarfun = varfun(@mean, ...
outages, ...
"InputVariables","Loss", ...
"GroupingVariables","Region")
meanLossByVarfun=5×3 table
Region GroupCount mean_Loss
_________ __________ _________
To omit missing values when using varfun, wrap the method in an anonymous function so that you
can specify the "omitnan" option.
omitnanMean = @(x)(mean(x,"omitnan"));
meanLossOmitNaNs=5×3 table
Region GroupCount Fun_Loss
_________ __________ ________
Another point refers to a different but related use case, which is to perform ungrouped calculations
on table variables. To apply a method to all table variables without grouping, use varfun. For
example, calculate the maximum power loss and the maximum number of customers affected in the
entire table.
9-78
Perform Calculations by Group in Table
maxValuesInOutages=1×2 table
max_Loss max_Customers
________ _____________
23418 5.9689e+06
The rowfun function applies a method along the rows of a table. Where varfun applies a method to
each specified variable, one by one, rowfun takes all specified table variables as input arguments to
the method and applies the method once.
For example, calculate the median loss per customer in each region. To perform this calculation, first
specify a function that takes two input arguments (loss and customers), divides the loss by the
number of customers, and then returns the median.
Then call rowfun. You can specify a meaningful output variable name by using the
OutputVariablesNames name-value argument.
meanLossPerCustomer=5×3 table
Region GroupCount MedianLossPerCustomer
_________ __________ _____________________
You can also use rowfun when the method returns multiple outputs. For example, use bounds to
calculate the minimum and maximum loss per region in one call to rowfun. The bounds function
returns two output arguments.
boundsLossPerRegion=5×4 table
Region GroupCount MinLoss MaxLoss
_________ __________ _______ _______
9-79
9 Tables
You can use the findgroups function to define groups and then use splitapply to apply a method
to each group. The findgroups function returns a vector of group numbers that identifies which
group a row of data is part of. The splitapply function returns a numeric array of the outputs of
the method applied to the groups.
For example, calculate the maximum power loss by region using findgroups and splitapply.
G = findgroups(outages.Region)
G = 1468×1
4
3
3
5
1
5
5
5
2
1
⋮
maxLossArray = splitapply(@max,outages.Loss,G)
maxLossArray = 5×1
104 ×
2.3141
2.3418
0.8767
0.2796
1.6659
Like rowfun, splitapply enables you to specify methods that return multiple outputs. Calculate
both minima and maxima by using bounds.
[minLossArray,maxLossArray] = splitapply(@bounds,outages.Loss,G)
minLossArray = 5×1
0
0
0
0
0
maxLossArray = 5×1
104 ×
9-80
Perform Calculations by Group in Table
2.3141
2.3418
0.8767
0.2796
1.6659
You can also specify methods that take multiple inputs. For example, use the medianLossCustFcn
function again to calculate the median loss per customer. But this time, return the median loss per
customer in each region as an array.
medianLossArray = splitapply(medianLossCustFcn,outages.Loss,outages.Customers,G)
medianLossArray = 5×1
0.0042
0.0029
0.0032
0.0026
0.0025
The numeric outputs of findgroups and splitapply are not annotated like the output of
groupsummary. However, returning numeric outputs can have other benefits:
• You can use the output of findgroups in multiple calls to splitapply. You might want to use
findgroups and splitapply for efficiency when you make many grouped calculations on a
large table.
• You can create a results table with a different format by building it from the outputs of
findgroups and splitapply.
• You can call methods that return multiple outputs.
• You can append the outputs of splitapply to an existing table.
If you already have a table of results, you can append the results of another calculation to that table.
For example, calculate the mean duration of power outages in each region in hours. Append the mean
durations as a new variable to the lossStatsByRegion table.
First subtract the outage times from the restoration times to return the durations of the power
outages. Convert these durations to hours by using the hours function.
D = outages.RestorationTime - outages.OutageTime;
H = hours(D)
H = 1468×1
105 ×
0.0015
NaN
0.0023
0.0000
0.0007
9-81
9 Tables
0.0001
0.0000
0.0001
0.0001
0.0001
⋮
Next use mean to calculate the mean durations. The outage durations have some NaN values because
the outage and restoration times have some missing values. As before, wrap the method in an
anonymous function to specify the "omitnan" option.
omitnanMean = @(x)(mean(x,"omitnan"));
Calculate the mean duration of power outages by region. Append it to lossStatsByRegion as a new
table variable.
G = findgroups(outages.Region);
lossStatsByRegion.mean_Outage = splitapply(omitnanMean,H,G)
lossStatsByRegion=5×6 table
Region GroupCount max_Loss mean_Loss min_Loss mean_Outage
_________ __________ ________ _________ ________ ___________
There is another way to specify groups. Instead of specifying categories as unique values in a
grouping variable, you can bin values in a variable where values are distributed continuously. Then
you can use those bins to specify groups.
For example, bin the power outages by year. To count the number of power outages per year, use the
groupcounts function.
outagesByYear = groupcounts(outages,"OutageTime","year")
outagesByYear=13×3 table
year_OutageTime GroupCount Percent
_______________ __________ _______
2002 36 2.4523
2003 62 4.2234
2004 79 5.3815
2005 74 5.0409
2006 108 7.3569
2007 91 6.1989
2008 115 7.8338
2009 142 9.673
2010 177 12.057
2011 190 12.943
2012 207 14.101
2013 186 12.67
9-82
Perform Calculations by Group in Table
2014 1 0.06812
Visualize the number of outages per year. The number per year increases over time in this data set.
bar(outagesByYear.year_OutageTime,outagesByYear.GroupCount)
You can use groupsummary with bins as groups. For example, calculate the median values for
customers affected and power losses by year.
medianLossesByYear = groupsummary(outages,"OutageTime","year","median",["Customers","Loss"])
medianLossesByYear=13×4 table
year_OutageTime GroupCount median_Customers median_Loss
_______________ __________ ________________ ___________
9-83
9 Tables
Visualize the median number of customers affected by outages per year. Although the number of
outages increased over time, the median number of affected customers decreased.
plot(medianLossesByYear,"year_OutageTime","median_Customers")
Return the rows of outages for years with more than 75 outages. To index into outages by those
years, use the groupfilter function. To find the bins with more than 75 rows, specify an anonymous
function that returns a logical 1 if the number of rows in a bin is greater than 75.
outages75 = groupfilter(outages,"OutageTime","year",@(x) numel(x) > 75)
outages75=1295×7 table
Region OutageTime Loss Customers RestorationTime Cause
_________ ________________ ______ __________ ________________ _______________
9-84
Perform Calculations by Group in Table
Use these tips and recommendations to decide which functions to use to perform group calculations.
• Specify groups using either grouping variables or bins created from numeric, datetime, or
duration variables.
• To perform calculations by group on data in tables or timetables, use the recommended function
groupsummary. The related functions groupcounts, groupfilter, and grouptransform also
are useful.
• Consider using varfun to automatically include missing values (such as NaNs and NaTs) when
applying methods to groups of data. Also, varfun can perform both grouped and ungrouped
calculations.
• Consider using findgroups and splitapply for efficiency when you make many consecutive
grouped calculations on a large table.
• Consider using findgroups and splitapply to append new arrays to an existing table of
results.
• To perform calculations using a method that returns multiple outputs, such as bounds, use either
rowfun or splitapply.
• To perform calculations along rows using a method that requires multiple input arguments, use
either rowfun or splitapply.
See Also
groupsummary | groupcounts | groupfilter | grouptransform | varfun | rowfun |
findgroups | splitapply | table | categorical | datetime | duration | readtable |
convertvars | bounds
Related Examples
• “Access Data in Tables” on page 9-37
• “Calculations When Tables Have Both Numeric and Nonnumeric Data” on page 9-66
• “Access Data Using Categorical Arrays” on page 8-33
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Summarize or Pivot Data in Tables Using Groups”
9-85
9 Tables
You can use the table data type to collect mixed-type data and metadata properties, such as variable
names, row names, descriptions, and variable units, in a single container. Tables are suitable for
column-oriented or tabular data that is often stored as columns in a text file or in a spreadsheet. For
example, you can use a table to store experimental data, with rows representing different
observations and columns representing different measured variables.
Tables consist of rows and column-oriented variables. Variables in a table can have different data
types and different sizes, but the variables must have the same number of rows. Also, the data within
a variable is homogeneous, which enables you to treat a table variable like an array of data.
For example, load sample data about patients from the patients.mat MAT-file. Combine blood
pressure data into a single variable. Convert a four-category variable called
SelfAssessedHealthStatus—which has values of Poor, Fair, Good, or Excellent—to a
categorical array. View information about several of the variables.
load patients
BloodPressure = [Systolic Diastolic];
SelfAssessedHealthStatus = categorical(SelfAssessedHealthStatus);
whos("Age","Smoker","BloodPressure","SelfAssessedHealthStatus")
Now, create a table from these variables and display it. The variables can be stored together in a
table because they all have the same number of rows, 100.
T = table(Age,Smoker,BloodPressure,SelfAssessedHealthStatus)
T=100×4 table
Age Smoker BloodPressure SelfAssessedHealthStatus
___ ______ _____________ ________________________
9-86
Tables of Mixed Data
Each variable in a table has one data type. If you add a new row to the table, MATLAB® forces
consistency of the data type between the new data and the corresponding table variables. For
example, if you try to add information for a new patient where the first column contains the patient's
health status instead of age, as in the expression T(end+1,:) = {"Poor",true,[130 84],37},
then you receive the error:
The error occurs because MATLAB® cannot assign numeric data, 37, to the categorical array,
SelfAssessedHealthStatus.
You can index into a table using parentheses, curly braces, or dot notation. Parentheses allow you to
select a subset of the data in a table and preserve the table container. Curly braces and dot notation
allow you to extract data from a table. Within each table indexing method, you can specify the rows
or variables to access by name or by numeric index.
Consider the sample table from above. Each row in the table, T, represents a different patient. The
workspace variable, LastName, contains unique identifiers for the 100 rows. Add row names to the
table by setting the RowNames property to LastName and display the first five rows of the updated
table.
T.Properties.RowNames = LastName;
T(1:5,:)
ans=5×4 table
Age Smoker BloodPressure SelfAssessedHealthStatus
___ ______ _____________ ________________________
In addition to labeling the data, you can use row and variable names to access data in the table. For
example, use named indexing to display the age and blood pressure of the patients Williams and
Brown.
T(["Williams","Brown"],["Age","BloodPressure"])
ans=2×2 table
Age BloodPressure
___ _____________
Williams 38 125 83
Brown 49 122 80
9-87
9 Tables
Now, use numeric indexing to return an equivalent subtable. Return the third and fifth rows from the
first and third variables.
T([3 5],[1 3])
ans=2×2 table
Age BloodPressure
___ _____________
Williams 38 125 83
Brown 49 122 80
For more information on table indexing, see “Access Data in Tables” on page 9-37.
In addition to storing data, tables have properties to store metadata, such as variable names, row
names, descriptions, and variable units. You can access a property using T.Properties.PropName,
where T is the name of the table and PropName is the name of a table property.
For example, add a table description, variable descriptions, and variable units for Age.
T.Properties.Description = "Simulated Patient Data";
T.Properties.VariableDescriptions = ...
["" ...
"true or false" ...
"Systolic/Diastolic" ...
"Status Reported by Patient"];
T.Properties.VariableUnits("Age") = "Yrs";
Individual empty strings within VariableDescriptions indicate that the corresponding variable
does not have a description. For more information, see the Properties section of table.
T: 100x4 table
Variables:
Age 0 25 39 50 38.2800
BloodPressure(:,1) 0 109 122 138 122.7800
BloodPressure(:,2) 0 68 81.5000 99 82.9600
SelfAssessedHealthStatus 0
9-88
Tables of Mixed Data
Like a table, a cell array can provide storage for mixed-type data in a single container. But unlike a
table, a cell array does not provide metadata that describes its contents. It does not force data in its
columns to remain homogenous. You cannot access the contents of a cell array using row names or
column names.
For example, convert T to a cell array using the table2cell function. The output cell array contains
the same data but has no information about that data. If it is important to keep such information
attached to your data, then storing it in a table is a better choice than storing it in a cell array.
C = table2cell(T)
To access subsets of data in a cell array, you can only use indexing with parentheses or curly braces.
C(1:5,1:3)
Comparison to Structures
Structures also can provide storage for mixed-type data. A structure has fields that you can access by
name, just as you can access table variables by name. However, it does not force data in its fields to
remain homogenous. Structures do not provide any metadata to describe their contents.
For example, convert T to a scalar structure where every field is an array, in a way that resembles
table variables. Use the table2struct function with the ToScalar name-value argument.
S = table2struct(T,ToScalar=true)
9-89
9 Tables
In this structure, you can access arrays of data by using field names.
S.Age
ans = 100×1
38
43
38
40
49
46
33
40
28
31
⋮
But to access subsets of data in the fields, you can only use numeric indices, and you can only access
one field at a time. Table row and variable indexing provides more flexible access to data in a table.
S.Age(1:5)
ans = 5×1
38
43
38
40
49
See Also
table | summary | table2cell | table2struct | readtable
Related Examples
• “Create Tables and Assign Data to Them” on page 9-2
• “Access Data in Tables” on page 9-37
• “Add, Delete, and Rearrange Table Variables” on page 9-12
• “Add and Delete Table Rows” on page 9-9
• “Rename and Describe Table Variables” on page 9-26
• “Direct Calculations on Tables and Timetables” on page 9-54
9-90
Changes to DimensionNames Property in R2016b
The table data type is suitable for collecting column-oriented, heterogeneous data in a single
container. Tables also contain metadata properties such as variable names, row names, dimension
names, descriptions, and variable units. Starting in R2016b, you can use the dimension names to
access table data and metadata using dot subscripting. To support that, the dimension names must
satisfy the same requirements as the variable names. For backwards compatibility, tables enforce
those restrictions by automatically modifying dimension names when needed.
T =
Number Party
______ __________
Display its properties, including the dimension names. The default values of the dimension names are
'Row' and 'Variables'.
T.Properties
ans =
Description: ''
UserData: []
DimensionNames: {'Row' 'Variables'}
VariableNames: {'Number' 'Party'}
VariableDescriptions: {}
VariableUnits: {}
RowNames: {5×1 cell}
Starting in R2016b, you can assign new names to the dimension names, and use them to access table
data. Dimension names must be valid MATLAB identifiers, and must not be one of the reserved
names, 'Properties', 'RowNames', or 'VariableNames'.
Assign a new name to the first dimension name, and use it to access the row names of the table.
T.Properties.DimensionNames{1} = 'Name';
T.Name
ans =
9-91
9 Tables
'Van Buren'
'Arthur'
'Fillmore'
'Garfield'
'Polk'
Create a new table variable called Name. When you create the variable, the table modifies its first
dimension name to prevent a conflict. The updated dimension name becomes Name_1.
T =
T.Properties.DimensionNames
ans =
'Name_1' 'Data'
Similarly, if you assign a dimension name that is not a valid MATLAB identifier, the name is modified.
ans =
'LastName' 'Data'
In R2016b, tables raise warnings when dimension names are not valid identifiers, or conflict with
variable names or reserved names, so that you can continue to work with code and tables created
with previous releases. If you encounter these warnings, it is recommended that you update your
code to avoid them.
9-92
Data Cleaning and Calculations in Tables
This example shows how to clean data stored in a MATLAB® table. It also shows how to perform
calculations by using the numeric and categorical data that the table contains.
Because tables and timetables are containers, working with them is somewhat different than working
with ordinary numeric arrays. The example shows how to use different tabular subscripting modes,
how these modes differ, and the advantages and disadvantages of each mode for different situations.
It also shows how to access and assign data, apply transformation and summary functions, convert
table variables to different data types, and plot results.
The Ames Housing Data used in this example comes from residential real estate data for the town of
Ames, Iowa, in the United States. You can download the original data from an XLS (Excel®
Workbook) spreadsheet. The data description is available as a text file. (Used with permission of the
copyright holder. Please contact the copyright holder if you wish to publish or redistribute this data.)
The best way to import a spreadsheet into MATLAB is to use the readtable function, or for data that
include timestamps, the readtimetable function. While the Ames Housing Data includes the sale
month and year for each house, the month and year are stored in separate columns. In this case, it is
simpler to use readtable.
Read the housing data. With readtable you can read data directly from a URL. Store all text data
from the spreadsheet as string arrays in the output table. Also, when readtable reads column
headers from a file, it uses them as table variable names and transforms them into valid MATLAB
identifiers. To preserve the original names, use the 'VariableNamingRule' name-value argument.
housing = readtable("http://jse.amstat.org/v19n3/decock/AmesHousing.xls","TextType","string");
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Display housing. The table has one variable for each of the 82 columns in the spreadsheet.
housing
housing=2930×82 table
Order PID MSSubClass MSZoning LotFrontage LotArea Street Alley
_____ ____________ __________ ________ ___________ _______ ______ _____
9-93
9 Tables
The spreadsheet has some column headers with spaces and other column headers that start with
numbers. Column headers become variable names in the output table. By default, readtable
standardizes names with spaces by using camel case, and standardizes names beginning with
numbers by prepending them with 'x'. Although a table can have variable names with spaces and
other non-alphanumeric characters in them, the standardization makes working with table variable
names more natural. Before standardizing names, readtable saves the original column headers in
housing.Properties.VariableDescriptions.
housing.Properties.VariableDescriptions
In this example, the original variable names are not needed. To delete them, assign an empty cell
array to the VariableDescriptions property.
housing.Properties.VariableDescriptions = {};
You can remove the Order variable because it is a row index and not needed. To remove one variable
from the table, assign an empty array, [], to the variable, just as you delete rows or columns from a
matrix.
housing.Order = [];
There are 81 variables left in the table. For a complete analysis of the housing prices, most of the
variables are probably important. But for this example, only a much smaller subset is needed. To
delete the unwanted variables one-by-one is tedious. The removevars function can delete them all at
once, but in this case there is an easier way. First list the variables that you want to keep. Then use
subscripting to select them and delete the others. Selecting variables by name is often much easier
than figuring out their numeric indices.
housing=2930×25 table
PID MSSubClass LotFrontage LotArea Neighborhood BldgType OverallCo
____________ __________ ___________ _______ ____________ ________ _________
9-94
Data Cleaning and Calculations in Tables
Two of the variable names are not very clear. Rename those variables with better names by using the
VariableNames property.
There are two other variable names, starting with 'x', that look odd. Another way to rename them is
to use the renamevars function. If you use renamevars, assign the output to the original table.
Otherwise the update is lost.
Six of the variables are string arrays. Conceptually they all contain categorical data: discrete,
nonnumeric values drawn from a small fixed set of possible values or categories. It is almost always a
good idea to convert that kind of data to categorical arrays. You can use the
detectImportOptions function to control the data types of the data you read with readtable. But
instead of starting over, you can convert these table variables to have the categorical data type.
For example, convert the Neighborhood variable to a categorical array.
housing.Neighborhood = categorical(housing.Neighborhood);
This assignment overwrites, or replaces, the existing text variable Neighborhood in the table with a
new categorical variable. Replacement is what enables the assignment to change the data type. In
contrast, this assignment, using indexing:
housing.Neighborhood(:) = categorical(housing.Neighborhood)
assigns values into the existing text variable, element by element, rather than replacing the variable.
In that case housing.Neighborhood remains a string array. This behavior is consistent with the
behavior of ordinary workspace variables. Assignment by indexing into an array does not change the
type of the array. For example, if you index into an array of integers and assign a floating-point value
to an element, the value is truncated and stored as an integer.
x = uint32([1 2 3]);
x(2) = 2.2 % converted to 2, as a uint32
1 2 3
Assignment with dot notation is one way to convert the type of a variable in a table. The
convertvars function is another way and has two benefits. First, it avoids any confusion about
overwriting as opposed to assignment into a variable. The convertvars function always overwrites
9-95
9 Tables
existing variables and converts their type. Second, convertvars can operate on more than one
variable at a time. There are several more text variables in housing to be converted to the
categorical data type. Changing them one at a time would get tedious, but convertvars can
convert more than one variable in one command.
housing = convertvars(housing,["BldgType" "Foundation"],"categorical");
It is not necessary to explicitly list the variables by name or position in the table. You can find all the
table variables that are string arrays and convert them to categorical variables. To specify table
variables that are string arrays, use the function handle @isstring when calling convertvars.
housing = convertvars(housing,@isstring,"categorical");
In both cases, assign the output of convertvars back to the original table. Otherwise, the update is
lost.
Sometimes, converting all text variables to categorical is too much. For example, if the current
homeowners' names were present in the data, then it would not make sense to store them in a
categorical variable. Homeowners' names do not define housing categories. You might keep their
names in a string array instead.
As another example, the CentralAir variable is one of the variables that was converted to
categorical. But because its categories are just Y and N, it might make more sense to consider it a
logical variable.
summary(housing.CentralAir)
N 196
Y 2734
The logical data type (like all the integer types) does not allow missing values (analogous to NaN),
while categorical does. The CentralAir variable happens to have no missing data values. You
can use either logical or categorical as the data type for CentralAir.
any(ismissing(housing.CentralAir))
ans = logical
0
Convert the data type to logical, with true corresponding to Y, using dot notation to overwrite the
existing categorical variable with the new logical one.
housing.CentralAir = (housing.CentralAir == "Y");
housing=2930×25 table
PID MSSubClass LotFrontage LotArea Neighborhood BldgType OverallCond
__________ __________ ___________ _______ ____________ ________ ___________
9-96
Data Cleaning and Calculations in Tables
All the text data has been converted to categorical variables. But there are still a few things to
clean up.
The OverallCond variable was read in as a numeric array, but its values are all drawn from the
integers 1-10. You can leave these values as numeric data, but you can think of it as ordinal
categorical data. When a categorical array is ordinal, its categories have a specified order. For
example, the categories 10 and 5 can be compared (10 > 5, because a house whose condition is
rated as a 10 is theoretically nicer than one rated 5), but for these comparisons, there is no numeric
meaning to 10 - 5. To avoid unintentionally treating OverallCond as numeric data, convert it to an
ordinal categorical array, which still enables relational comparisons but prevents arithmetic
operations. The category names 1, 2, and so on are easy to interpret and are acceptable.
housing.OverallCond = categorical(housing.OverallCond,1:10,"Ordinal",true);
Similarly, the MSSubClass variable consisted of numeric codes in the original spreadsheet. You can
think of those values as being categorical data. Because there is no mathematical order to these
particular codes, the categories are nonordinal (or nominal). In this case, readtable read those
values in as text to preserve leading zeroes in the codes. MSSubClass was then converted to
categorical data.
While MSSubClass has the data type that you want, you might find it difficult to interpret the codes
as categories of houses. The file that describes the Ames Housing Data contains the definitions of the
numeric codes. Giving these categories readable names can help you understand the data. To make it
clear which names go with which numbers, specify both the categories (code) and their names
(subclass) in another call to the categorical function.
code = ["020" "030" "040" "045" "050" "060" "070" "075" "080" "085" "090" "120" "150" "160" "180"
subclass = ["1-STORY 1946 & NEWER ALL STYLES" ...
"1-STORY 1945 & OLDER" ...
"1-STORY W/FINISHED ATTIC ALL AGES" ...
"1-1/2 STORY - UNFINISHED ALL AGES" ...
"1-1/2 STORY FINISHED ALL AGES" ...
"2-STORY 1946 & NEWER" ...
"2-STORY 1945 & OLDER" ...
"2-1/2 STORY ALL AGES" ...
"SPLIT OR MULTI-LEVEL" ...
"SPLIT FOYER" ...
"DUPLEX - ALL STYLES AND AGES" ...
"1-STORY PUD (Planned Unit Development) - 1946 & NEWER" ...
"1-1/2 STORY PUD - ALL AGES" ...
"2-STORY PUD - 1946 & NEWER" ...
"PUD - MULTILEVEL - INCL SPLIT LEV/FOYER" ...
9-97
9 Tables
The category names for the BldgType variable are not obvious. As with MSSubClass, more
descriptive names can help you understand the building categories. To display the number of houses
in each building category, use the summary function.
summary(housing.BldgType)
1Fam 2425
2fmCon 62
Duplex 109
Twnhs 101
TwnhsE 233
With only five categories, you can safely list the new category names in the right order without
specifying the old names. To rename categories, use the renamecats function.
types = ["Single-family Detached" "Two-family Conversion" "Duplex" "Townhouse End Unit" "Townhous
housing.BldgType = renamecats(housing.BldgType,types);
The GarageType variable includes the category NA, standing for Not Applicable. In GarageType, NA
means that the house does not have a garage. But it is too easy to confuse NA with a missing value. A
true missing value means it cannot be determined if a house has a garage. But in this housing data, it
is always known if a house has a garage. Change that one category name to make its meaning clearer.
housing.GarageType = renamecats(housing.GarageType,"NA","None");
Finally, the PID variable was read in as a string array. While its values were numeric, some of them
had leading zeroes. The readtable function preserved this information by storing the values as
strings. Then the call to convertvars converted the PID variable to a categorical array. PID
stores identification numbers that are unique. Identification numbers are assigned as needed and do
not come from a fixed set of values. There is no particular advantage in storing them in a
categorical variable. If every identification number is a category, then adding a new identification
number means adding a new category to PID. It might be more convenient to convert PID back to a
string array. To convert values to strings, use the string function.
housing.PID = string(housing.PID);
housing=2930×25 table
PID MSSubClass LotFrontage LotAr
____________ _____________________________________________________ ___________ _____
9-98
Data Cleaning and Calculations in Tables
The table has separate variables for the month and year of sale. It is more convenient if those
variables are combined in one datetime variable. Assignment by using dot notation is a good way to
add a new variable at the right edge of a table. Add the date of sale as a new variable.
Now delete the two original variables. It is easier to list the variables by name and use removevars.
housing=2930×24 table
PID MSSubClass LotFrontage LotAr
____________ _____________________________________________________ ___________ _____
Explore the data by making some simple plots. Many basic plotting commands do not accept tables as
input arguments. But you can use dot notation to pass one or more table variables into a plotting
function. You are taking arrays out of the table and passing them as input arguments to a plotting
function.
For example, make a scatter plot of the sale prices of houses in the table as a function of the years in
which they were built.
scatter(housing.YearBuilt,housing.SalePrice,20,"filled");
9-99
9 Tables
A log transformation of the prices might show a simpler relationship between year and price. Also,
you can show more information in the scatter plot by using the living area of the houses to color the
markers. The living areas have a long right tail, so it is also useful to show a log transformation of the
areas. To transform the two table variables, wrap them in calls to the log function. Then make
another scatter plot.
logSalePrice = log(housing.SalePrice);
logLivingArea = log(housing.TotalAboveGroundLivingArea);
scatter(housing.YearBuilt,logSalePrice,20,logLivingArea,"filled");
9-100
Data Cleaning and Calculations in Tables
Any large, complex data set collected over a long period of time might contain some errors. Check for
errors in the housing data. Dates in the data are a good place to start. First compare YearBuilt to
YearRemod_Add.
checkRows = housing.YearBuilt > housing.YearRemod_Add;
housing(checkRows,:)
ans=1×24 table
PID MSSubClass LotFrontage LotArea Neighborhood
____________ _______________________________ ___________ _______ ____________
It is not possible for remodeling to have been done in 2001 if the house itself was built in 2002. If you
assume that the YearBuilt value is known to be the error (an assumption that needs to be
confirmed), you can use dot notation to assign 2001 as the year in which this house was built.
housing.YearBuilt(checkRows) = 2001;
ans=2×24 table
PID MSSubClass LotFrontage LotArea Neighborhood
9-101
9 Tables
There is another issue. These two houses were sold in late 2007, as shown in the LastSoldDate
variable. But the corresponding value in YearBuilt is 2008. It might be that for these houses, the
years in YearBuilt were recorded in early 2008 (another assumption needing confirmation). Update
the YearBuilt variable, this time by using dot notation to assign to two rows.
housing.YearBuilt(checkRows) = 2007;
The next step in cleaning the data is to check for missing data in the numeric and categorical
variables. The one logical variable in housing does not support missing values. The ismissing
function indicates which elements of the table have missing values.
missingElements = ismissing(housing)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
⋮
The ismissing function returns a logical matrix that is the same size as the table. Summing the
columns of that matrix gives the number of missing values in each of the variables of the table.
numMissing = sum(missingElements,1)
numMissing = 1×24
0 0 490 0 0 0 0 0 0 0 0 0 0 0 0 0
Only three of the variables have missing data, but without the variable names it is not easy to tell
which variables they are. One way to tell is to index into the VariableNames property of the table to
find the names that correspond to the variables with missing values.
housing.Properties.VariableNames(numMissing > 0)
Deciding what to do about missing data is a challenge. If the data is missing at random, and there are
only a few missing values, one strategy is to remove those rows from the table. The four missing
9-102
Data Cleaning and Calculations in Tables
basement bath values (NaNs, in this case) occur in only two rows. You can remove those two rows by
using the rmmissing function.
ans=2×24 table
PID MSSubClass LotFrontage LotArea Neighborhood
____________ _______________________________ ___________ _______ ____________
This call to rmmissing removes only the rows that have missing values in BsmtFullBath and
BsmtHalfBath. The 490 rows with missing LotFrontage values are still in the table. You can
remove these 490 rows but doing so deletes more than 16% of the data. You also can fill these
missing values with the mean frontage value by using the fillmissing function, but that is not
practical for this data. For variables that form a time series, fillmissing also supports filling
variables with interpolated values or moving-window smoothed values. LotFrontage is not a time
series. The data in this variable is a cross-sectional data set.
One commonly used strategy for filling in missing values in cross-sectional data is to create a
regression model to predict the missing values in a row from the non-missing data in that row. A
simple scatter plot indicates that there is a log-log relationship between the area of a lot and its
frontage. That relationship suggests a model.
loglog(housing.LotArea,housing.LotFrontage,'o')
9-103
9 Tables
You can use that log-log relationship to fill in the missing LotFrontage values by regressing the
values on LotArea.
missingValues = ismissing(housing.LotFrontage);
beta = polyfit(log(housing.LotArea(~missingValues)),log(housing.LotFrontage(~missingValues)),1);
housing.LotFrontage(missingValues) = exp(polyval(beta,log(housing.LotArea(missingValues))));
You can use dot notation to work on data in a table when you use functions such as polyfit and
polyval that accept numeric vectors but not tables. You can think of a table as a container that is
designed to hold data having different types. Functions such as polyfit that are specifically for
numeric inputs do not work on a table because a table often contains nonnumeric data. Even when a
table contains only numeric data, it is still a container. The functions must be applied to the contents
of the table. Use dot notation to access table variables.
Add the imputed missing values that you calculated with polyfit and polyval to the scatter plot. A
simple imputation scheme might not be sufficient in a real analysis of this data, but it illustrates how
to visualize and make computations on numeric data in a table.
hold on
loglog(housing.LotArea(missingValues),housing.LotFrontage(missingValues),'rx')
hold off
9-104
Data Cleaning and Calculations in Tables
Dot notation has been convenient for operations such as converting an existing table variable, adding
a new variable, assigning values, plotting, and applying functions like polyval to a table variable.
Dot notation is also convenient for arithmetic operations on table variables. For example, convert the
LotFrontage variable from feet to meters.
housing=2928×24 table
PID MSSubClass LotFrontage LotAr
____________ _____________________________________________________ ___________ _____
9-105
9 Tables
Using dot notation means that the multiplication is applied not to the housing table, which cannot
be done because tables are containers, but rather to its LotFrontage variable, which is a numeric
vector. With dot notation, you extracted LotFrontage from the table and put the modified version
back in.
Another way to access the contents of a table is to subscript into it by using curly braces, just as you
use curly braces to extract the contents of a cell array. You can use curly brace subscripting to refer
to and operate on data in a table by extracting and reinserting contents. For example, convert
LotFrontage back to feet by using curly brace subscripting.
Dot notation and brace subscripting are different syntaxes for the same kinds of operations. They
both work on the contents of a table. Also, they both enable you to specify a table variable and a
subset of its rows.
housing.LotArea(1:2)
ans = 2×1
31770
11622
housing{1:2,"LotArea"}
ans = 2×1
31770
11622
While both syntaxes work on the contents of table, there are two subtle differences to consider.
First, a limitation of curly brace subscripting is that it assigns into the contents of a table rather than
replacing a variable. For example, this assignment does not change the data type of the
LotFrontage variable in the way that an assignment using dot notation does. The call to the single
function on the right side of the assignment creates an array having the single data type. But by
subscripting into housing with curly braces, you assign values from that array into the existing table
variable. And the data type of LotFrontage is double. The values from the right side are converted
back to double by this assignment.
housing{:,"LotFrontage"} = single(housing{:,"LotFrontage"});
Second, a benefit of curly brace subscripting is that, unlike dot notation, it uses the familiar two-
dimensional subscripting syntax. This syntax enables you to refer to more than one variable at a time
and also to a subset of rows. For example, there are five variables whose units are square feet.
Converting these variables to square meters one at a time is tedious. To apply the multiplication to all
five variables at once, use curly brace subscripting.
9-106
Data Cleaning and Calculations in Tables
A common mistake is to use parenthesis subscripting instead of braces to operate on the contents of a
table. While some functions, such as ismissing or varfun, do accept a table as their input, many
numeric operations, including arithmetic, do not. For example, this assignment using parentheses
results in an error. The try-catch block catches the error and displays it.
try
housing(:,areaVars) = 0.3048^2 * housing(:,areaVars);
catch ME
disp(ME.message)
end
A third way to do calculations on numeric variables in a table is to use the varfun function. Like
curly brace subscripting, varfun can operate on all or only some of the variables in a table. Unlike
curly braces, varfun operates on each table variable separately. By default, varfun returns another
table containing a variable for each separate result.
Sometimes the operation that you want to apply is an existing function. To pass the function as an
argument to varfun, use a function handle. For example, use the round function to round data in the
variables specified by areaVars.
roundedAreaTable = varfun(@round,housing,"InputVariables",areaVars)
roundedAreaTable=2928×5 table
round_LotArea round_FirstFlrArea round_SecondFlrArea round_LowQualFinishedArea ro
_____________ __________________ ___________________ _________________________ __
2952 154 0 0
1080 83 0 0
1325 123 0 0
1037 196 0 0
1285 86 65 0
927 86 63 0
457 124 0 0
465 119 0 0
501 150 0 0
697 96 72 0
929 71 83 0
741 110 0 0
781 73 63 0
945 125 0 0
634 140 0 0
4971 157 148 0
⋮
9-107
9 Tables
If there is no function that does exactly what you want, you can also write an anonymous function to
do it.
sqMeters2sqFeet = @(x) x / 0.3048^2;
areaTable = varfun(sqMeters2sqFeet,housing,"InputVariables",areaVars)
areaTable=2928×5 table
Fun_LotArea Fun_FirstFlrArea Fun_SecondFlrArea Fun_LowQualFinishedArea Fun_TotalA
___________ ________________ _________________ _______________________ __________
31770 1656 0 0
11622 896 0 0
14267 1329 0 0
11160 2110 0 0
13830 928 701 0
9978 926 678 0
4920 1338 0 0
5005 1280 0 0
5389 1616 0 0
7500 1028 776 0
10000 763 892 0
7980 1187 0 0
8402 789 676 0
10176 1341 0 0
6820 1502 0 0
53504 1690 1589 0
⋮
Because that result is a table, it can be assigned back into the original table with parenthesis
subscripting.
housing(:,areaVars) = areaTable;
housing.Properties.VariableUnits(areaVars) = "ft^2";
housing(:,areaVars) = areaTable;
The two assignments have the same effect. The assignment with parentheses assigns one table to
another. The assignment with curly braces explicitly assigns values to the content of the table. The
left and right sides of that assignment are numeric matrices. Because curly brace subscripting
extracts and reinserts data, it is a convenient way to modify data in place. Contents-to-contents
assignment can operate on only one data type at a time, while table-to-table assignment can move
data of different types. For example, this assignment results in an error because it involves mixed
numeric and categorical data in brace subscripting.
try
housing{:,["LotFrontage" "OverallCond"]} = normalize(housing{:,["LotFrontage" "OverallCond"]}
catch ME
disp(ME.message)
end
9-108
Data Cleaning and Calculations in Tables
Because varfun returns a table, assignment using parenthesis subscripting cannot change the type
of any table variables. For example, this assignment does not convert any variables from the double
to single data type.
housing(:,areaVars) = varfun(@single,housing,"InputVariables",areaVars);
To convert the data types of table variables, use convertvars, as previously shown.
Because curly brace subscripting extracts the variables from a table as one matrix having one data
type, you can use it to perform row operations across numeric variables in a table. For example, a
check on the data is to compare the individual square footage variables against
TotalAboveGroundLivingArea. Extract the former by using curly braces. Then compare their row
sums to TotalAboveGroundLivingArea, extracted by using dot notation.
area = housing{:,["FirstFlrArea" "SecondFlrArea" "LowQualFinishedArea"]}
area = 2928×3
1656 0 0
896 0 0
1329 0 0
2110 0 0
928 701 0
926 678 0
1338 0 0
1280 0 0
1616 0 0
1028 776 0
⋮
isequal(sum(area,2), housing.TotalAboveGroundLivingArea)
ans = logical
1
The square footage data is consistent. Another example is to compute the total number of bathrooms
in each house by extracting the four different bathroom counts and adding them up across each row.
bathCountVars = ["BsmtHalfBath" "HalfBath" "BsmtFullBath" "FullBath"];
bathCounts = housing{:,bathCountVars}
bathCounts = 2928×4
0 0 1 1
0 0 0 1
0 1 0 1
0 1 1 2
0 1 0 2
0 1 0 2
0 0 1 2
0 0 0 2
0 0 1 2
0 1 0 2
⋮
9-109
9 Tables
sum(housing{:,bathCountVars},2);
but that sum is not correct. Half-baths count only half as much as full bathrooms. A trend in real
estate listings is to account for multiple half-baths by counting them after the decimal point. Matrix
multiplication makes that operation one line.
Replace those four variables with TotalBaths, rather than adding a new variable at the end of the
table. Begin this replacement by using addvars to add TotalBaths next to the existing variables.
There is a mistake in one row of the data. A townhouse built in 2007 probably does not have four half
baths and no full baths.
groupcounts(housing,"TotalBaths")
ans=17×3 table
TotalBaths GroupCount Percent
__________ __________ ________
0.4 1 0.034153
1 442 15.096
1.1 293 10.007
1.2 20 0.68306
1.3 2 0.068306
2 890 30.396
2.1 558 19.057
2.2 29 0.99044
3 349 11.919
3.1 288 9.8361
3.2 6 0.20492
3.3 1 0.034153
4 25 0.85383
4.1 16 0.54645
4.2 3 0.10246
6 2 0.068306
⋮
ans=1×25 table
PID MSSubClass LotFrontage LotAr
____________ _____________________________________________________ ___________ _____
"0528228275" 1-STORY PUD (Planned Unit Development) - 1946 & NEWER 53 3922
The BsmtHalfBath count should be two full bathrooms. The bathroom counts are all numeric. The
assignment with braces updates all three values across that row.
9-110
Data Cleaning and Calculations in Tables
housing = removevars(housing,bathCountVars)
housing=2928×21 table
PID MSSubClass LotFrontage LotAr
____________ _____________________________________________________ ___________ _____
Unlike curly braces, varfun operates on each variable in a table separately. For that reason, varfun
cannot do row operations. The related function rowfun can do row operations. It is often simpler and
faster to use curly brace subscripting for row operations.
In previous sections, the operations on numeric data in the table were transformations that replace
the original values. Many other important operations are reductions whose results are scalars. For
example, calculate the median price of the values in SalePrice.
median(housing.SalePrice)
ans = 160000
The median function works column-wise on matrices. You can use curly brace subscripting to extract
those four variables as a numeric matrix. Then you can calculate the medians of the columns of the
matrix.
median(housing{:,["LotFrontage", "LotArea" "TotalAboveGroundLivingArea" "SalePrice"]})
ans = 1×4
105 ×
This operation does not attach variable names or any other table metadata to the result. As an
alternative, you can use varfun to apply median to each variable in the table. With varfun, the
result is another table that contains separate numeric results and preserves the names.
varfun(@median,housing,"InputVariables",["LotFrontage", "LotArea" "TotalAboveGroundLivingArea" "S
ans=1×4 table
median_LotFrontage median_LotArea median_TotalAboveGroundLivingArea median_SalePrice
9-111
9 Tables
These two ways to get the medians are equivalent. There is a trade-off between having the variable
names preserved in another table and having the results in one numeric row vector. The way you pick
depends on what you plan to do with the result.
Using curly braces when calculating the medians has another drawback. Curly braces require
compatible data type for all the variables. That is, the data you extract from the variables must have
data types that allow them to be concatenated into one matrix. Ordinal categorical data can also
have median values. Because categorical and numeric arrays cannot be concatenated, this
operation results in an error.
But because varfun operates on each variable in the table separately, there is no requirement that
the variables have the same data type or compatible types allowing concatenation. The only
requirement is that all the variables must support the function that is applied. To calculate the
medians of ordinal categorical variables and numeric variables in one function call use varfun.
ans=1×5 table
median_LotFrontage median_LotArea median_OverallCond median_TotalAboveGroundLivingAr
__________________ ______________ __________________ _______________________________
See Also
categorical | table | readtable | varfun | renamevars | convertvars | summary |
ismissing | rmmissing | datetime | removevars | addvars | groupcounts
Related Examples
• “Access Data in Tables” on page 9-37
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Create Timetables” on page 10-2
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Perform Calculations by Group in Table” on page 9-74
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Summarize or Pivot Data in Tables Using Groups”
9-112
Grouped Calculations in Tables and Timetables
Grouped calculations can help you interpret large datasets such as time-series data. In such
calculations, you use a grouping variable to split a dataset into groups and apply a function to each
group. A grouping variable contains values, such as time periods or station locations, that you can use
to group other data values, such as temperature readings or atmospheric concentrations of a gas. In
MATLAB®, you can store such data in tables or timetables. With grouped calculations in a table you
can often calculate results in-place, in one table, instead of breaking data out into separate tables and
merging results later.
This example shows how to import nitrogen dioxide (NO2) data from the US Environmental
Protection Agency (EPA) into a table and do grouped calculations on this data. NO2 is one of the
Criteria Air Pollutants regulated under the US Clean Air Act. It is toxic by itself and is also a key
component of photochemical smog that results in ground-level ozone production. NO2 is produced
through high-temperature processes that can split nitrogen and oxygen gases and enable them to
recombine. Natural processes contribute NO2 to the atmosphere, but so do human activities such as
combustion in automobile engines and power plants, lightning, and biomass burning. The
concentration of NO2 in the atmosphere is also influenced by the photochemical cycling between NO
and NO2, atmospheric transport, and ultimately oxidation to nitric acid, causing acid rain. Different
processes contribute NO2 to the atmosphere on different timescales, leading to daily (diurnal),
weekly, and annual cycles in its atmospheric concentration. Time-series analysis of such data relies
heavily on grouped calculations to examine different periodic behavior or to average the data over
time to smooth out high-frequency variability and reveal long-term trends.
The example first shows how to do preliminary data cleaning, including conversion of the table to a
timetable. Then it shows simple ways to group the data by one grouping variable and calculate annual
mean NO2 concentrations. It also shows how to group the NO2 data by two grouping variables
together, time and location, enabling calculations that find locations exceeding EPA standards at
various times. You can also group the NO2 data by time period to look for daily or yearly cycles.
Finally it shows how to apply a function that requires inputs from multiple table variables to find the
times at which the maximum NO2 concentrations occurred at each site.
First, import NO2 data from the Air Quality System (AQS) database maintained by the EPA. This data
consists of hourly measurements of NO2 concentrations from outdoor monitors across the United
States, Puerto Rico, and the U.S. Virgin Islands. It is stored as a set of zipped spreadsheets, one for
each year starting with 1980.
Download hourly NO2 measurements for the years 1985–1989. You can download and unzip the
compressed spreadsheets by using the unzip function. The result is set of files in your current folder
with names such as hourly_42602_1985.csv. Here, 42602 is an EPA code for NO2. (Data from the
US Environmental Protection Agency. Air Quality System Data Mart available via Air Data: Air Quality
Data Collected at Outdoor Monitors Across the US. Accessed July 15, 2021.)
yrs = string(1985:1989);
urls = "https://aqs.epa.gov/aqsweb/airdata/hourly_42602_" + yrs + ".zip";
fnames = strings(numel(yrs),1);
for ii = 1:numel(yrs)
fnames(ii) = unzip(urls(ii));
end
fnames
9-113
9 Tables
Import data from the spreadsheets into a table. Start by creating an empty table. Then import data
from the spreadsheets, one by one, by using the readtable function and adding it to the table.
Create import options that help specify how readtable imports tabular data. To create import
options based on the contents of the spreadsheets, use the detectImportOptions function. Read
all the text data into table variables that store strings. You can also specify that only specified table
variables have certain data types. To specify that only the TimeGMT and TimeLocal table variables
store times as duration arrays, use the setvaropts function.
NO2data = table;
opts = detectImportOptions(fnames(1),"TextType","string");
opts = setvaropts(opts,["TimeGMT","TimeLocal"],"Type","duration","InputFormat","hh:mm");
Import data from the spreadsheets by using the readtable function. You can vertically concatenate
the tables you read in so that all the data is in one large table.
The spreadsheets have column names, such as "Time GMT", that you cannot use as MATLAB
identifiers. As the warning messages indicate, readtable converts these names into table variable
names that are valid MATLAB identifiers, such as TimeGMT. When a table variable name is also a
valid MATLAB identifier, it is easier to access the variable by using dot notation, as in
NO2data.TimeGMT.
for ii = 1:numel(yrs)
NO2data = [NO2data; readtable(fnames(ii),opts)];
end
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names
Display NO2data. It has 24 variables storing NO2 sample measurements, site locations, state names,
times, and many other pieces of information.
NO2data
NO2data=11294497×24 table
StateCode CountyCode SiteNum ParameterCode POC Latitude Longitude Datum
_________ __________ _______ _____________ ___ ________ _________ ______
9-114
Grouped Calculations in Tables and Timetables
Next, prepare NO2data for analysis by cleaning the data. Data cleaning is the process of detecting
and correcting (or removing) parts of the data set that are either corrupt, inaccurate, or irrelevant.
You can also convert table variables so that they have data types that can be more convenient for
analysis, such as categorical or datetime arrays.
For example, the table variable SampleMeasurement has measurements of NO2 concentration.
Concentrations below the method detection limit (MDL) are unreliable. To exclude them from
analysis, find the rows where SampleMeasurement is below the MDL. Set those elements to NaN.
NO2data.SampleMeasurement(NO2data.SampleMeasurement < NO2data.MDL) = NaN;
Create a table that contains only the subset of variables that are relevant to this example. You can use
table subscripting to create a table that has all rows (specified by a colon) and only those variables
that you name.
NO2data = NO2data(:,["DateLocal","TimeLocal","SampleMeasurement","StateName","CountyName","SiteNu
NO2data=11294497×8 table
DateLocal TimeLocal SampleMeasurement StateName CountyName SiteNum Latitu
___________ _________ _________________ _________ __________ _______ ______
9-115
9 Tables
Combine the local date and time into a single timestamp. The new Timestamp table variable is a
datetime array. Delete the DateLocal and TimeLocal variables because they are now redundant.
NO2data.Timestamp = NO2data.DateLocal + NO2data.TimeLocal;
NO2data.Timestamp.Format = "default";
NO2data.DateLocal = [];
NO2data.TimeLocal = [];
To categorize the data later, convert the StateName and CountyName variables to categorical
arrays, first erasing space characters from the names. There are fixed sets of state and county names
in the data, which makes it convenient to create categories based on them.
NO2data.StateName = categorical(erase(NO2data.StateName," "));
NO2data.CountyName = categorical(erase(NO2data.CountyName," "));
Rename the SampleMeasurement variable to MeasuredNO2. One way to rename table variables is
by using the VariableNames property of the table.
NO2data.Properties.VariableNames("SampleMeasurement") = "MeasuredNO2";
Convert NO2data to a timetable. The datetime values in Timestamp are now row times that label
the rows of the timetable. The dates and times of the original table were in separate variables. To put
data like this data into a timetable, it is more convenient to import the data as a table, and then
combine the separate date and time variables into one datetime variable. Then convert the modified
table by using the table2timetable function.
NO2data = table2timetable(NO2data)
NO2data=11294497×6 timetable
Timestamp MeasuredNO2 StateName CountyName SiteNum Latitude Long
____________________ ___________ _________ __________ _______ ________ ____
Given the size of the timetable, it is obvious that there are many thousands of hourly measurements
in every state. One way to calculate the number of measurements for each state is to sum the number
9-116
Grouped Calculations in Tables and Timetables
of rows that have a particular state as a category. For example, calculate the number of
measurements for Alaska, and then for Arizona.
numAlaska = sum(NO2data.StateName=="Alaska")
numAlaska = 7071
numArizona = sum(NO2data.StateName=="Arizona")
numArizona = 142793
It is tedious to perform this calculation multiple times or to store intermediate results in many
variables or subtables. Instead, MATLAB provides functions that group data in tables and apply
functions to each group in-place. For example, use the groupcounts function to group the data in
NO2data by the states in StateName and count the rows in each group. Instead of calling sum many
times, call groupcounts once.
NO2counts = groupcounts(NO2data,"StateName")
NO2counts=42×3 table
StateName GroupCount Percent
__________________ __________ ________
To sort the results in a table or timetable, use the sortrows function. Sort gc on its GroupCount
variable from highest to lowest value.
sortedNO2counts = sortrows(NO2counts,"GroupCount","descend")
sortedNO2counts=42×3 table
StateName GroupCount Percent
_____________ __________ _______
9-117
9 Tables
To calculate other statistics, use the groupsummary function. For example, find the maximum NO2
concentration measured in each state.
NO2max = groupsummary(NO2data,"StateName","max","MeasuredNO2");
sortedNO2max = sortrows(NO2max,"max_MeasuredNO2","descend")
sortedNO2max=42×3 table
StateName GroupCount max_MeasuredNO2
____________ __________ _______________
As an alternative, you can use the varfun function with the "GroupingVariables" name-value
argument for grouped calculations. But the groupsummary function is simpler and performs most of
the same grouped calculations as varfun.
Functions such as groupcounts, groupsummary, and varfun work equally well on tables and
timetables. But timetables also provide the retime and synchronize functions, which can perform
time-based calculations by using their row times. You can group timetable data by time and perform
calculations on data within the time periods. The retime function is the best option for such cases.
For example, group the data in NO2data into yearly time periods. Find the maximum NO2
concentration for each year.
yearlyMaxNO2 = retime(NO2data(:,"MeasuredNO2"),"yearly","max")
yearlyMaxNO2=5×1 timetable
Timestamp MeasuredNO2
9-118
Grouped Calculations in Tables and Timetables
___________ ___________
01-Jan-1985 407.3
01-Jan-1986 500
01-Jan-1987 497
01-Jan-1988 743.5
01-Jan-1989 462
This calculation is useful if you have one time series. In this case, the data in the MeasuredNO2
variable come from multiple sites. A more useful analysis is to group by both year and site.
The US EPA has two National Ambient Air Quality Standards (NAAQS) for NO2. A location is not in
compliance with the NAAQS if either:
Analyze data in NO2data to find locations that are not in compliance with the first standard, where
the annual mean exceeded 53 ppb. There are three different ways to approach this analysis. What the
three approaches have in common is that you can group the data by both time and site to calculate
annual means by site.
To find sites that do not comply with the NAAQS, calculate the mean value for each site for each year.
While NO2data does not include unique identifiers for the sites, you can use state names, county
names, and site numbers together to uniquely identify air quality sites.
The row times of NO2data are datetime values. Extract their year components and add a new
variable to NO2data named Year. Calculate the annual means for each site by using groupsummary
with StateName, CountyName, SiteNum, and Year as grouping variables.
NO2data.Year = year(NO2data.Timestamp);
meanNO2bySite = groupsummary(NO2data,["StateName","CountyName","SiteNum","Year"],"mean","Measured
meanNO2bySite=1585×6 table
StateName CountyName SiteNum Year GroupCount mean_MeasuredNO2
_________ ______________ _______ ____ __________ ________________
9-119
9 Tables
To find the sites that have the highest mean NO2, sort the timetable.
sortedMeanNO2bySite = sortrows(meanNO2bySite,"mean_MeasuredNO2","descend")
sortedMeanNO2bySite=1585×6 table
StateName CountyName SiteNum Year GroupCount mean_MeasuredNO2
__________ __________ _______ ____ __________ ________________
You can create a table that includes only those sites exceeding 53 ppb by using logical indexing.
Create a logical vector that indicates the rows where mean_MeasuredNO2 is greater than 53. Use
that vector as a subscript to get matching rows from meanNO2bySite.
sitesExceed53ppb=19×6 table
StateName CountyName SiteNum Year GroupCount mean_MeasuredNO2
__________ __________ _______ ____ __________ ________________
9-120
Grouped Calculations in Tables and Timetables
Sometimes pivoting, or rearranging statistics calculated from tabular data, makes it easier to see and
analyze results, particularly when you look at the relationship between two grouping variables. For
example, you can create a pivot table for the annual mean NO2 by site. By pivoting, you can create a
table where every site lists annual mean NO2 in its own table variable, showing the relationship
between year and site. In MATLAB, you can create pivot tables by using the stack and unstack
functions, which stack and unstack table variables into taller or wider formats.
A complication in this case is that NO2data has three grouping variables that together uniquely
identify sites: state name, county name, and site number. To create a pivot table, first combine these
three table variables into one variable. Convert StateName, CountyName, and SiteNum into strings
and add them together. Replace spaces and dashes with underscores, and erase periods and
parentheses. The names in SiteID are unique site identifiers.
siteID = string(NO2data.StateName) + "_" + string(NO2data.CountyName) + "_" + string(NO2data.Site
siteID = replace(siteID,[" ","-"],"_");
siteID = erase(siteID,[".","(",")"]);
Add SiteID to NO2data as a new table variable. Calculate annual means by using groupsummary,
but this time use SiteID as a grouping variable.
NO2data.SiteID = categorical(siteID);
meanNO2bySiteID = groupsummary(NO2data,["SiteID","Year"],"mean","MeasuredNO2")
meanNO2bySiteID=1585×4 table
SiteID Year GroupCount mean_MeasuredNO2
__________________________ ____ __________ ________________
To create a pivot table, use the unstack function. Each unique site in the SiteID variable of
meanNO2bySiteID becomes the name of a separate table variable in the output,
pivotedMeanNO2bySiteID, and has the annual means associated with that site. This unstacking
operation is how you can create a pivot table in MATLAB.
pivotedMeanNO2bySiteID = unstack(meanNO2bySiteID,"mean_MeasuredNO2","SiteID","GroupingVariable","
9-121
9 Tables
pivotedMeanNO2bySiteID=5×443 table
Year Alaska_KenaiPeninsula_1004 Arizona_Apache_10 Arizona_Apache_11 Arizona_Apach
____ __________________________ _________________ _________________ _____________
This representation of the annual means by site has an advantage and a disadvantage.
• It is easier to look at the short five-year time series for each site. After unstacking, each site has
its own variable in pivotedMeanNO2bySiteID. You can easily compare sites to each other.
• It is harder to sort and pick out the largest values across the whole pivoted table. After
unstacking, pivotedMeanNO2bySiteID has 443 variables. The stacked version,
meanNO2bySite, has only seven variables.
To group data in NO2data by year and another grouping variable, it was necessary to add Year as an
additional variable. Also, the output from groupsummary is a table even when the input is a
timetable. But suppose you want to keep the results in a timetable instead. The retime function can
also produce annual summaries. But it can group data only by time. To group data by site and by year,
rearrange NO2data so that you can call retime on a timetable where the NO2 concentrations are
already grouped by site.
Group the raw data in NO2data by site by using the unstack function. The output timetable has a
separate variable for each site. This timetable looks similar to a pivot table. But instead of having
means or some other statistic, NO2bySite has all the raw data. It is just reorganized. For further
convenience, sort the rows of the timetable by their row times so that the earliest timestamps come
first.
NO2bySite = unstack(NO2data,"MeasuredNO2","SiteID","GroupingVariable","Timestamp");
NO2bySite = sortrows(NO2bySite)
NO2bySite=43824×442 timetable
Timestamp Alaska_KenaiPeninsula_1004 Arizona_Apache_10 Arizona_Apache_11
____________________ __________________________ _________________ _________________
In this format you can easily plot the raw data by using the stackedplot function. This plot shows
NO2 concentrations for each site as a function of time.
stackedplot(NO2bySite)
9-122
Grouped Calculations in Tables and Timetables
To create a timetable that is also a pivot table, use retime to calculate annual means.
meanNO2bySiteTT = retime(NO2bySite,"yearly","mean")
meanNO2bySiteTT=5×442 timetable
Timestamp Alaska_KenaiPeninsula_1004 Arizona_Apache_10 Arizona_Apache_11 Arizon
___________ __________________________ _________________ _________________ ______
stackedplot(meanNO2bySiteTT)
9-123
9 Tables
You might want to preserve information from the original timetable NO2data in this timetable of
results. For example, you might want to add the latitudes and longitudes of the sites to NO2bySite.
They were stored for each timestamp in NO2data. But to store them more compactly in this
timetable, add them as per-variable custom properties to NO2bySite.
LatLon = groupsummary(NO2data,"SiteID","mode",["Latitude","Longitude"]);
NO2bySite = addprop(NO2bySite,["Latitude","Longitude"],["variable","variable"]);
NO2bySite.Properties.CustomProperties.Latitude(string(LatLon.SiteID)) = LatLon.mode_Latitude';
NO2bySite.Properties.CustomProperties.Longitude(string(LatLon.SiteID)) = LatLon.mode_Longitude';
To calculate compliance with the second NAAQS standard for NO2 requires a sequence of grouped
calculations. By the second standard, a location is out of compliance if the 98th percentile of the 1-
hour daily maximum concentrations of NO2, averaged over 3 years, exceeds 100 ppb.
Start with the hourly concentrations of NO2 by site. To find the daily maximum for each site, use the
retime function, specifying "max" as the method to find the maximum concentration for each day's
worth of data. Then find the 98th percentiles of the daily maximums in each year's worth of data,
calling retime a second time. To calculate percentiles, use the findPrctile supporting function
referred to in this example.
dailyMax = retime(NO2bySite,"daily","max");
yearlyP98 = retime(dailyMax,"yearly",@(x)findPrctile(x,98))
yearlyP98=5×442 timetable
Timestamp Alaska_KenaiPeninsula_1004 Arizona_Apache_10 Arizona_Apache_11 Arizon
9-124
Grouped Calculations in Tables and Timetables
01-Jan-1985 NaN 27 29
01-Jan-1986 NaN 13 14
Next calculate a moving mean for each site, specifying a three-year window for the moving mean. The
smoothdata enables you to apply the movmean function to each variable in yearlyP98.
moving3yearAvg = smoothdata(yearlyP98,"movmean",[years(3) 0])
moving3yearAvg=5×442 timetable
Timestamp Alaska_KenaiPeninsula_1004 Arizona_Apache_10 Arizona_Apache_11 Arizon
___________ __________________________ _________________ _________________ ______
01-Jan-1985 NaN 27 29
01-Jan-1986 NaN 20 21.5
Display sites that are out of compliance. First specify a time range starting in 1987, the first year for
which the moving three-year window has three full years of data.
full3years = timerange("1987-01-01","1989-01-01","closed")
full3years =
timetable timerange subscript:
Next find sites that exceeded the standard during any year in the 1987–1989 time period. The vector
exceed is a vector of logical values whose values are 1 (true) where the corresponding variables of
moving3yearAvg have values that exceed the standard. You can use logical arrays to index into
tables. In this case, index into moving3yearAvg by using exceed to display only the variables for
the sites that exceed the standard.
exceed = any(moving3yearAvg{full3years,:}>100,1);
moving3yearAvg(full3years,exceed)
ans=3×85 timetable
Timestamp California_Alameda_1001 California_ContraCosta_3001 California_Fresno_5
___________ _______________________ ___________________________ ___________________
The NO2bySite timetable has latitudes and longitudes for the sites, saved as custom properties. The
latitudes and longitudes are associated with the variables of the timetable. You can mark the sites
that exceeded the standard on a map by using the geoscatter function. The sites that exceeded the
standard in 1987 are marked in yellow. (Here, moving3yearAvg{1,:} accesses the first row of the
timetable, corresponding to the year 1987.) The sites out of compliance in 1987 were typically large
cities such as Los Angeles. Due to the Clean Air Act, a similar analysis using the latest data for the
years 2015–2019 would show no sites out of compliance with the NO2 standard.
9-125
9 Tables
geoscatter(moving3yearAvg.Properties.CustomProperties.Latitude,...
moving3yearAvg.Properties.CustomProperties.Longitude,...
moving3yearAvg{1,:},moving3yearAvg{1,:}>100,'filled')
Another way to group by time is by using periodic time units to look for things like seasonality or
daily cycles. For example, consider the average daily pattern of NO2 concentrations at each site. It is
likely that fossil fuel combustion emissions from human activity and atmospheric photochemistry
driven by the sun contribute to a daily cycle in NO2 concentrations. You cannot calculate the mean
daily cycle using retime. One approach is to use the varfun function by adding a grouping variable
based on the time of day of each timestamp. The timeofday function returns the time of day, or
length of time since midnight, as a duration. This code sample shows the approach by using varfun.
NO2bySite.Hour = timeofday(NO2bySite.Timestamp);
NO2bySite.Hour.Format = "hh:mm";
meanDailyCycleNO2 = varfun(@mean,NO2bySite,"GroupingVariable","Hour")
For common calendar periods such as hour of day or month of year, there is a simpler method. These
common calendar periods are options of the groupsummary function. Call groupsummary with the
"hourofday" option.
meanDailyCycleNO2 = groupsummary(NO2bySite,"Timestamp","hourofday","mean")
meanDailyCycleNO2=24×444 table
hourofday_Timestamp GroupCount mean_Alaska_KenaiPeninsula_1004 mean_Arizona_Apache_1
___________________ __________ _______________________________ _____________________
9-126
Grouped Calculations in Tables and Timetables
0 1826 11.067 5
⋮
To visualize the daily cycle for the first few sites, use stackedplot. Compare the pattern of a single
peak in remote sites in Alaska and Arizona to the morning and evening peaks during rush hour at
urban sites in Arizona and California.
meanDailyCycleNO2.GroupCount = [];
meanDailyCycleNO2.hourofday_Timestamp = hours(double(meanDailyCycleNO2.hourofday_Timestamp));
stackedplot(meanDailyCycleNO2,'XVariable','hourofday_Timestamp')
The retime, groupsummary, and varfun functions all apply functions separately to each table
variable. But sometimes you have functions that use more than one table variable as inputs. For
example, you might want to find the time or index at which some condition occurred within each
group of data values. In such cases, use the rowfun function. It enables you to apply functions that
require multiple inputs.
For example, determine when the maximum NO2 concentration occurred at each site. This
determination requires a function such as the findMax supporting function referred to in this
example. The findMax function requires both timestamps and data values as input arguments. It
returns the maximum value with the time at which the maximum value occurred.
9-127
9 Tables
To group the data in NO2data by SiteID and find the times when the maximum NO2 concentration
occurred at each site, use rowfun. Specify that the inputs to findMax are Timestamp and
MeasuredNO2 from NO2data. Convert NO2data to a table so that rowfun returns a table.
NO2data = timetable2table(NO2data);
rowfun(@findMax,NO2data,"GroupingVariable","SiteID","InputVariables",["Timestamp","MeasuredNO2"],
"OutputVariableNames",["MaxMeasuredNO2","MaxOccurrenceTime"])
ans=442×4 table
SiteID GroupCount MaxMeasuredNO2 MaxOccurrenceTime
___________________________ __________ ______________ ____________________
With these results you could extend your analysis to find out why the NO2 concentrations were
particularly high on those dates.
Supporting Functions
See Also
categorical | table | timetable | readtable | detectImportOptions | varfun | datetime |
groupcounts | groupsummary | rowfun | retime | stackedplot
9-128
Grouped Calculations in Tables and Timetables
Related Examples
• “Access Data in Tables” on page 9-37
• “Clean Messy and Missing Data in Tables” on page 9-18
• “Summarize or Pivot Data in Tables Using Groups”
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Perform Calculations by Group in Table” on page 9-74
• “Data Cleaning and Calculations in Tables” on page 9-93
9-129
10
Timetables
Create Timetables
A timetable is a type of table that associates a time with each row. Like tables, timetables store
column-oriented data variables that have the same number of rows. Timetables store their row times
as vectors of datetime or duration values. In addition, timetables support time-specific functions
to align, combine, and perform calculations with timestamped data in one or more timetables.
In MATLAB®, you can create timetables and assign data to them in several ways.
• Create a timetable from a vector of row times and data arrays by using the timetable function.
• Add variables to an existing timetable by using dot notation.
• Assign variables to an empty timetable.
• Preallocate a timetable and fill in its data later.
• Convert variables to timetables by using the array2timetable, table2timetable, and
timeseries2timetable functions.
• Read a timetable from a file by using the readtimetable function.
• Use the Import Tool to import your data as a table. Then convert it by using table2timetable.
• For Simulink® users: Extract timetables from Simulink.SimulationData.Dataset objects by
using the extractTimetable (Simulink) function.
The way you choose depends on the nature of your data and how you plan to use timetables in your
code.
You can create a timetable from a vector of row times and data arrays by using the timetable
function. For example, create a timetable that contains weather conditions at various times.
First, create a vector of row times. This vector can be a datetime or duration vector. Then create
data arrays with temperature, pressure, precipitation, and storm duration readings.
Now create a timetable as a container for the data. The timetable function uses the input argument
variable names as the timetable variable names. Also, the first input argument provides the name of
the vector of row times. The vector of row times is not a timetable variable. Rather, the row times are
metadata that label the rows, just as the variable names are metadata that label the variables. So, the
resulting timetable is a 3-by-4 timetable.
weather = timetable(MeasurementTime,Temperature,Pressure,Precipitation,StormDuration)
weather=3×4 timetable
MeasurementTime Temperature Pressure Precipitation StormDuration
____________________ ___________ ________ _____________ _____________
10-2
Create Timetables
You can also specify the vector of row times by using the RowTimes name-value argument. When you
use this name-value argument, timetable uses Time as the name of the vector of row times.
weather = timetable(Temperature,Pressure,Precipitation,StormDuration,RowTimes=MeasurementTime)
weather=3×4 timetable
Time Temperature Pressure Precipitation StormDuration
____________________ ___________ ________ _____________ _____________
Once you have created a timetable, you can add a new variable at any time by using dot notation. Dot
notation refers to timetable variables by name, such as T.varname, where T is the timetable and
varname is the variable name.
weather=3×5 timetable
Time Temperature Pressure Precipitation StormDuration WindSpee
____________________ ___________ ________ _____________ _____________ ________
Another way to create a timetable is to start with an empty timetable of just row times and then add
variables to it. For example, create another version of the timetable of weather conditions. But this
time, add variables using dot notation.
First, create an empty timetable by calling timetable with only a vector of row times. The result is
an empty timetable because it has no variables.
weather2 = timetable(MeasurementTime)
weather2 =
MeasurementTime
____________________
18-Dec-2023 08:03:05
18-Dec-2023 10:03:17
18-Dec-2023 12:03:13
10-3
10 Timetables
(While you can call timetable with no arguments at all, the result is an empty timetable that also
has no row times. The resulting 0-by-0 timetable is of little use because adding row times to it is less
efficient than simply creating an empty timetable with a vector of row times.)
Add variables to the empty timetable by using dot notation. Timetable variable names do not have to
match array names from the workspace, as shown by the assignment to the WindSpeed variable.
weather2.Temperature = Temperature;
weather2.Pressure = Pressure;
weather2.Precipitation = Precipitation;
weather2.StormDuration = StormDuration;
weather2.WindSpeed = w
weather2=3×5 timetable
MeasurementTime Temperature Pressure Precipitation StormDuration WindSpee
____________________ ___________ ________ _____________ _____________ ________
Preallocate Timetable
If you know the sizes and data types of the data that you want to store in a timetable, but you plan to
assign the data later, preallocating space in the timetable and then assigning values to empty rows
can be more efficient.
For example, to preallocate space for a 4-by-3 timetable that contains time, temperature, and wind
speed readings at different stations, use the timetable function. You must supply row times so that
you can subscript into the timetable by row times. But instead of supplying input data arrays, specify
the sizes and data types of the timetable variables. To give them names, specify the VariableNames
name-value argument. Preallocation fills timetable variables with default values that are appropriate
for their data types.
d = datetime(2023,6,1:4)';
sz = [4 3];
varTypes = ["double","double","string"];
varNames = ["Temperature","WindSpeed","Station"];
TT = timetable(Size=sz, ...
VariableTypes=varTypes, ...
RowTimes=d, ...
VariableNames=varNames)
TT=4×3 timetable
Time Temperature WindSpeed Station
___________ ___________ _________ _________
01-Jun-2023 0 0 <missing>
02-Jun-2023 0 0 <missing>
03-Jun-2023 0 0 <missing>
04-Jun-2023 0 0 <missing>
You can assign data to one row at a time. Specify the row of data values as a cell array.
TT(datetime("2023-06-01"),:) = {48.2,13.33,"S1"}
10-4
Create Timetables
TT=4×3 timetable
Time Temperature WindSpeed Station
___________ ___________ _________ _________
Instead of supplying row times from a vector when you preallocate a timetable, you can specify a
sample rate or time step for creating the necessary row times. By default, the row times of such a
timetable start with 0 seconds. For example, preallocate a 3-by-2 timetable whose row times have a
time step of 0.1 second by using the TimeStep name-value argument.
TT=3×2 timetable
Time Var1 Var2
_______ ____ ____
0 sec 0 0
0.1 sec 0 0
0.2 sec 0 0
To preallocate a timetable whose first row has a row time that is not 0 seconds, specify the
StartTime name-value argument. The value of StartTime can be a datetime or duration scalar.
When you specify StartTime, you must also specify either SampleRate or TimeStep to set the
sample rate or time step. For example, preallocate a timetable using a sample rate of 1000 Hz that
starts at 15 seconds.
TT=3×3 timetable
Time Var1 Var2 Var3
__________ ____ ____ ____
15 sec 0 0 0
15.001 sec 0 0 0
15.002 sec 0 0 0
For example, convert an array to a timetable by using the array2timetable function. Specify a
start time and sample rate to add row times.
X = rand(5,3);
TT = array2timetable(X,StartTime=seconds(10),SampleRate=500)
10-5
10 Timetables
TT=5×3 timetable
Time X1 X2 X3
__________ _______ _______ _______
When you use array2timetable, you can specify a sample rate or a time step with or without a
start time. Or you can specify a vector of row times.
Similarly, you can convert a table to a timetable by using the table2timetable function. For
example, create a table and then add row times to it.
T=5×2 table
Reading1 Reading2
________ ________
98 120
97.5 111
97.9 119
98.1 117
97.9 116
Time = seconds(1:1:5);
TT = table2timetable(T,RowTimes=Time)
TT=5×2 timetable
Time Reading1 Reading2
_____ ________ ________
1 sec 98 120
2 sec 97.5 111
3 sec 97.9 119
4 sec 98.1 117
5 sec 97.9 116
With table2timetable, you can specify a vector of row times, or you can specify a sample rate or a
time step with or without a start time.
However, if a table already has dates and times, then you can call table2timetable without other
arguments. The function converts the first datetime or duration variable in the table to a vector of
row times in the output timetable.
For example, create a table with a datetime variable. Then convert it to a timetable. While T is a 3-
by-4 table, TT is a 3-by-3 timetable because MeasurementTime becomes the vector of row times in
TT.
T = table(Temperature,Pressure,MeasurementTime,StormDuration)
10-6
Create Timetables
T=3×4 table
Temperature Pressure MeasurementTime StormDuration
___________ ________ ____________________ _____________
TT = table2timetable(T)
TT=3×3 timetable
MeasurementTime Temperature Pressure StormDuration
____________________ ___________ ________ _____________
The timeseries data type is another data type for working with time series data in MATLAB. The
timetable data type is the recommended data type for working with time series data. To convert a
timeseries array to a timetable, use the timeseries2timetable function.
• If the input is a timeseries object, then the output is a timetable with one variable.
• If the input is an array of timeseries objects, then the output is a timetable with more than one
variable.
Events
Name
UserData
Data
DataInfo
Time
TimeInfo
Quality
QualityInfo
IsTimeFirst
TreatNaNasMissing
Length
TT = timeseries2timetable(ts)
TT=5×3 timetable
Time Series_1 Series_2 Series_3
______ ________ ________ ________
10-7
10 Timetables
To read tabular data such as a CSV (comma-separated values) file or an Excel® spreadsheet into a
timetable, use the readtimetable function.
For example, the sample file outages.csv contains data for a set of electrical power outages. The
first line of outages.csv has column names. The rest of the file has comma-separated data values
for each outage. The first few lines are shown here.
Region,OutageTime,Loss,Customers,RestorationTime,Cause
SouthWest,2002-02-01 12:18,458.9772218,1820159.482,2002-02-07 16:50,winter storm
SouthEast,2003-01-23 00:49,530.1399497,212035.3001,,winter storm
SouthEast,2003-02-07 21:15,289.4035493,142938.6282,2003-02-17 08:14,winter storm
West,2004-04-06 05:44,434.8053524,340371.0338,2004-04-06 06:10,equipment fault
MidWest,2002-03-16 06:18,186.4367788,212754.055,2002-03-18 23:23,severe storm
...
To import the data from outages.csv into a timetable, use readtimetable. It reads numeric
values, dates and times, and strings into variables that have appropriate data types. Here, Loss and
Customers are numeric arrays. The OutageTime and RestorationTime columns of the input file
are imported as datetime arrays because readtimetable recognizes the date and time formats of
the text in those columns. Note that OutageTime is the first column in the input file whose values
contain dates and times, so readtimetable converts it to the vector of row times in the output
timetable. The outages.csv file has six columns, but readtimetable converts it to a timetable
that has a vector of row times and five variables.
outages = readtimetable("outages.csv",TextType="string")
outages=1468×5 timetable
OutageTime Region Loss Customers RestorationTime Cause
________________ ___________ ______ __________ ________________ ______________
10-8
Create Timetables
Finally, you can interactively preview and import data from spreadsheets, delimited text files, and
fixed-width text files by using the Import Tool. However, while the Import Tool can import data as a
table, it cannot import data directly as a timetable.
If you do use the Import Tool, follow these steps to create a timetable:
See Also
Functions
timetable | readtimetable | array2timetable | table2timetable |
timeseries2timetable
Apps
Import Tool
Related Examples
• “Access Data in Tables” on page 9-37
• “Select Times in Timetable” on page 10-24
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Combine Timetables and Synchronize Their Data” on page 10-13
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
10-9
10 Timetables
This example shows how to resample and aggregate data in a timetable. A timetable is a type of table
that associates a time with each row. A timetable can store column-oriented data variables that have
different data types and sizes, provided that each variable has the same number of rows. With the
retime function, you can resample timetable data, or aggregate timetable data into time bins you
specify.
Import Timetable
Load a timetable containing weather measurements taken from November 15, 2015, to November 19,
2015. The timetable contains humidity, temperature, and pressure readings taken over this time
period.
load outdoors
outdoors(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
___________________ ________ ____________ __________
Determine if the timetable is regular. A regular timetable is one in which the differences between all
consecutive row times are the same. outdoors is not a regular timetable.
TF = isregular(outdoors)
TF = logical
0
Find the differences in the time steps. They vary between half a minute and an hour and a half.
dt = unique(diff(outdoors.Time))
dt = 3x1 duration
00:00:24
01:29:36
01:30:00
Adjust the data in the timetable with the retime function. Specify an hourly time vector. Interpolate
the timetable data to the new row times.
TT = retime(outdoors,"hourly","spline");
TT(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
10-10
Resample and Aggregate Data in Timetable
Specify an hourly time vector for TT. For each row in TT, copy values from the corresponding row in
outdoors whose row time is nearest.
TT = retime(outdoors,"hourly","nearest");
TT(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
___________________ ________ ____________ __________
The retime function provides aggregation methods, such as mean. Calculate the daily means for the
data in outdoors.
TT = retime(outdoors,"daily","mean");
TT
TT=4×3 timetable
Time Humidity TemperatureF PressureHg
___________________ ________ ____________ __________
Calculate the means over six-hour time intervals. Specify a regular time step using the "regular"
input argument and the TimeStep name-value argument.
TT = retime(outdoors,"regular","mean",TimeStep=hours(6));
TT(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
___________________ ________ ____________ __________
10-11
10 Timetables
As an alternative, you can specify a time vector that has the same six-hour time intervals. Specify a
format for the time vector to display both date and time when you display the timetable.
tv = datetime(2015,11,15):hours(6):datetime(2015,11,18);
tv.Format = "dd-MMM-yyyy HH:mm:ss";
TT = retime(outdoors,tv,"mean");
TT(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
____________________ ________ ____________ __________
See Also
timetable | table2timetable | synchronize | retime
Related Examples
• “Combine Timetables and Synchronize Their Data” on page 10-13
• “Retime and Synchronize Timetable Variables Using Different Methods” on page 10-19
• “Select Times in Timetable” on page 10-24
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Add Event Table from External Data to Timetable” on page 10-77
• “Find Events in Timetable Using Event Table” on page 10-94
10-12
Combine Timetables and Synchronize Their Data
You can combine timetables and synchronize their data in a variety of ways. You can concatenate
timetables vertically or horizontally, but only when they contain the same row times or timetable
variables. Use the synchronize function to combine timetables with different row times and
timetable variables. synchronize creates a timetable that contains all variables from all input
timetables. It then synchronizes the data from the input timetables to the row times of the output
timetable. synchronize can fill in missing elements of the output timetable with missing data
indicators, with values copied from their nearest neighbors, or with interpolated values.
synchronize also can aggregate timetable data over time bins you specify.
Load timetables from openPricesSmall and concatenate them vertically. The timetables are
opWeek1 and opWeek2. They contain opening prices for some stocks during the first and second
weeks of January 2016.
load openPricesSmall
opWeek1=5×2 timetable
Time AAPL FB
____________________ ______ ______
opWeek2
opWeek2=5×2 timetable
Time AAPL FB
____________________ ______ ______
Concatenate the timetables. You can concatenate timetables vertically when they have the same
variables. The row times label the rows and are not contained in a timetable variable. Note that the
row times of a timetable can be out of order and do not need to be regularly spaced. For example, op
does not include days that fall on weekends. A timetable also can contain duplicate times. op contains
two rows for 08-Jan-2016 09:00:00.
op = [opWeek2;opWeek1]
op=10×2 timetable
Time AAPL FB
10-13
10 Timetables
You also can concatenate timetables horizontally. The timetables must have the same row times and
different variables.
Display the timetable opOtherStocks. The timetable has the same row times as opWeek1, but
variables for different stocks.
opOtherStocks
opOtherStocks=5×2 timetable
Time MSFT TWTR
____________________ _____ _____
Concatenate opWeek1 and opOtherStock. The output timetable has one set of row times and the
variables from both timetables.
op = [opWeek1 opOtherStocks]
op=5×4 timetable
Time AAPL FB MSFT TWTR
____________________ ______ ______ _____ _____
Load air quality data and weather measurements from two different timetables and synchronize
them. The dates of the measurements range from November 15, 2015, to November 19, 2015. The air
quality data come from a sensor inside a building, while the weather measurements come from
sensors outside.
10-14
Combine Timetables and Synchronize Their Data
load indoors
load outdoors
Display the first five lines of each timetable. They contain measurements of different quantities taken
at different times.
indoors(1:5,:)
ans=5×2 timetable
Time Humidity AirQuality
___________________ ________ __________
2015-11-15 00:00:24 36 80
2015-11-15 01:13:35 36 80
2015-11-15 02:26:47 37 79
2015-11-15 03:39:59 37 82
2015-11-15 04:53:11 36 80
outdoors(1:5,:)
ans=5×3 timetable
Time Humidity TemperatureF PressureHg
___________________ ________ ____________ __________
Synchronize the timetables. The output timetable tt contains all the times from both timetables.
synchronize puts a missing data indicator where there are no data values to place in tt. When both
input timetables have a variable with the same name, such as Humidity, synchronize renames
both variables and adds both to the output timetable.
tt = synchronize(indoors,outdoors);
tt(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
Synchronize the timetables, and fill in missing timetable elements with linear interpolation. To
synchronize on a time vector that includes all times from both timetables, specify "union" for the
output times.
ttLinear = synchronize(indoors,outdoors,"union","linear");
ttLinear(1:5,:)
10-15
10 Timetables
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
Synchronize the timetables to an hourly time vector. The input timetables had irregular row times.
The output timetable has regular row times with one hour as the time step.
ttHourly = synchronize(indoors,outdoors,"hourly","linear");
ttHourly(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
Synchronize the timetables to a 30-minute time step. Specify a regular time step using the
"regular" input argument and the TimeStep name-value argument.
ttHalfHour = synchronize(indoors,outdoors,"regular","linear",TimeStep=minutes(30));
ttHalfHour(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
As an alternative, you can synchronize the timetables to a time vector that specifies half-hour
intervals.
tv = [datetime(2015,11,15):minutes(30):datetime(2015,11,18)];
tv.Format = indoors.Time.Format;
ttHalfHour = synchronize(indoors,outdoors,tv,"linear");
ttHalfHour(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
10-16
Combine Timetables and Synchronize Their Data
Synchronize the timetables and calculate the daily means for all variables in the output timetable.
ttDaily = synchronize(indoors,outdoors,"daily","mean");
ttDaily
ttDaily=4×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
Synchronize the timetables to six-hour time intervals and calculate a mean for each interval.
tt6Hours = synchronize(indoors,outdoors,"regular","mean",TimeStep=hours(6));
tt6Hours(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
As an alternative, specify a time vector that has the same six-hour time intervals.
tv = [datetime(2015,11,15):hours(6):datetime(2015,11,18)];
tv.Format = indoors.Time.Format;
tt6Hours = synchronize(indoors,outdoors,tv,"mean");
tt6Hours(1:5,:)
ans=5×5 timetable
Time Humidity_indoors AirQuality Humidity_outdoors TemperatureF
___________________ ________________ __________ _________________ ____________
10-17
10 Timetables
See Also
timetable | table2timetable | synchronize | retime
Related Examples
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Retime and Synchronize Timetable Variables Using Different Methods” on page 10-19
• “Select Times in Timetable” on page 10-24
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Add Event Table from External Data to Timetable” on page 10-77
• “Find Events in Timetable Using Event Table” on page 10-94
10-18
Retime and Synchronize Timetable Variables Using Different Methods
This example shows how to fill in gaps in timetable variables, using different methods for different
variables. You can specify whether each timetable variable contains continuous or discrete data using
the VariableContinuity property of the timetable. When you resample the timetable using the
retime function, retime either interpolates, fills in with previous values, or fills in with missing data
indicators, depending on the values in the VariableContinuity property. Similarly, the
synchronize function interpolates or fills in values based on the VariableContinuity property of
the input timetables.
Create Timetable
Create a timetable that has simulated weather measurements for several days in May 2017. The
timetable variables Tmax and Tmin contain maximum and minimum temperature readings for each
day, and PrecipTotal contains total precipitation for the day. WXEvent is a categorical array,
recording whether certain kinds of weather events, such as thunder or hail, happened on any given
day. The timetable has simulated data from May 4 to May 10, 2017, but is missing data for two days,
May 6th and May 7th.
Station1=5×4 timetable
Date Tmax Tmin PrecipTotal WXEvent
___________ ____ ____ ___________ _______
One way to fill in data for the two missing days is to use the retime function. If you call retime
without specifying a method, then retime fills in gaps with missing data indicators. For instance,
retime fills gaps in numeric variables with NaN values, and gaps in the categorical variable with
undefined elements.
Station1Daily = retime(Station1,'daily')
Station1Daily=7×4 timetable
Date Tmax Tmin PrecipTotal WXEvent
___________ ____ ____ ___________ ___________
10-19
10 Timetables
If you specify a method when you call retime, it uses the same method to fill gaps in every variable.
To apply different methods to different variables, you can call retime multiple times, each time
indexing into the timetable to access a different subset of variables.
However, you also can apply different methods by specifying the VariableContinuity property of
the timetable. You can specify whether each variable contains continuous or discrete data. Then the
retime function applies a different method to each timetable variable, depending on the
corresponding VariableContinuity value.
If you specify VariableContinuity, then the retime function fills in the output timetable variables
using the following methods:
• 'unset' — Fill in values using the missing data indicator for that type (such as NaN for numeric
variables).
• 'continuous' — Fill in values using linear interpolation.
• 'step' — Fill in values using previous value.
• 'event' — Fill in values using the missing data indicator for that type.
Specify that the temperature data in Station1 is continuous, that PrecipTotal is step data, and
that WXEvent is event data.
Station1.Properties.VariableContinuity = {'continuous','continuous','step','event'};
Station1.Properties
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Date' 'Variables'}
VariableNames: {'Tmax' 'Tmin' 'PrecipTotal' 'WXEvent'}
VariableTypes: ["double" "double" "double" "categorical"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: [continuous continuous step event]
RowTimes: [5x1 datetime]
StartTime: 04-May-2017
SampleRate: NaN
TimeStep: NaN
Events: []
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
Resample the data in Station1. Given the values assigned to VariableContinuity, the retime
function interpolates the temperature data, fills in the previous day's values in PrecipTotal, and
fills in WXEvent with undefined elements.
Station1Daily = retime(Station1,'daily')
10-20
Retime and Synchronize Timetable Variables Using Different Methods
Station1Daily=7×4 timetable
Date Tmax Tmin PrecipTotal WXEvent
___________ ____ ______ ___________ ___________
If you specify a method, then retime applies that method to all variables, overriding the values in
VariableContinuity.
Station1Missing = retime(Station1,'daily','fillwithmissing')
Station1Missing=7×4 timetable
Date Tmax Tmin PrecipTotal WXEvent
___________ ____ ____ ___________ ___________
The synchronize function also fills in output timetable variables using different methods, depending
on the values specified in the VariableContinuity property of each input timetable.
Create a second timetable that contains pressure readings in millibars from a second weather station.
The timetable has simulated readings from May 4 to May 8, 2017.
Date = datetime(2017,5,4:8)';
Pressure = [995 1003 1013 1018 1006]';
Station2 = timetable(Date,Pressure)
Station2=5×1 timetable
Date Pressure
___________ ________
04-May-2017 995
05-May-2017 1003
06-May-2017 1013
07-May-2017 1018
08-May-2017 1006
Synchronize the data from the two stations using the synchronize function. synchronize fills in
values for variables from Station1 according to the values in the VariableContinuity property
of Station1. However, since the VariableContinuity property of Station2 is empty,
synchronize fills in Pressure with NaN values.
10-21
10 Timetables
BothStations = synchronize(Station1,Station2)
BothStations=7×5 timetable
Date Tmax Tmin PrecipTotal WXEvent Pressure
___________ ____ ______ ___________ ___________ ________
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Date' 'Variables'}
VariableNames: {'Pressure'}
VariableTypes: "double"
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: continuous
RowTimes: [5x1 datetime]
StartTime: 04-May-2017
SampleRate: NaN
TimeStep: 1d
Events: []
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
Synchronize the data from the two stations. synchronize fills in values in
BothStations.Pressure because Station2.Pressure has continuous data.
BothStations = synchronize(Station1,Station2)
BothStations=7×5 timetable
Date Tmax Tmin PrecipTotal WXEvent Pressure
___________ ____ ______ ___________ ___________ ________
10-22
Retime and Synchronize Timetable Variables Using Different Methods
If you specify a method as an input argument to synchronize, then synchronize applies that
method to all variables, just as the retime function does.
See Also
timetable | synchronize | retime
Related Examples
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Combine Timetables and Synchronize Their Data” on page 10-13
• “Select Times in Timetable” on page 10-24
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Add Event Table from External Data to Timetable” on page 10-77
• “Find Events in Timetable Using Event Table” on page 10-94
10-23
10 Timetables
A timetable is a type of table that associates a time with each row. You can select time-based subsets
of its data in several ways:
• Find times within a certain range using the timerange or withtol functions.
• Match recurring units of time, such as days or months, using the components of datetime arrays.
• Resample or group data with the retime function.
For example, read a sample file outages.csv, containing data representing electric utility outages
in the United States from 2002–2014. The vector of row times, OutageTime, indicates when the
outages occurred. The readtimetable function imports it as a datetime array. Display the first five
rows.
TT = readtimetable('outages.csv');
head(TT,5)
Before R2019a, read tabular data with readtable and convert it to a timetable using
table2timetable.
To find data in a specific range, you can use the timerange function, which defines time-based
subscripts for indexing. For instance, define a range for the summer of 2008, which started on June
20 and ended on September 21. By default, timerange defines a half-open interval that is closed on
the left and open on the right, so specify the end date as September 22.
TR = timerange("2008-06-20","2008-09-22")
TR =
timetable timerange subscript:
Find the outages that occurred in that range, and then plot the number of customers affected over
time.
summer08 = TT(TR,:);
stem(summer08.OutageTime,summer08.Customers)
ylabel("Customers")
10-24
Select Times in Timetable
Several outages during that time range had high customer impact. Expand the range to a time period
that spans the entire year of 2008 and look for similarly high numbers.
TR = timerange("2008","years");
all08 = TT(TR,:);
high08 = all08(all08.Customers > 500000,:);
stem(high08.OutageTime,high08.Customers)
ylabel('Customers')
10-25
10 Timetables
The timerange function is also helpful for selecting specific dates. Selecting times by comparing
datetime values can give misleading results because all datetime values include both date and
time components. However, when you specify only the date component of a datetime value, the time
component is set to midnight. Therefore, although there is data from June 26, a comparison like this
one returns no results.
any(summer08.OutageTime == datetime("2008-06-26"))
ans = logical
0
TR = timerange("2008-06-26","days");
june26 = summer08(TR,:)
june26=1×5 timetable
OutageTime Region Loss Customers RestorationTime Cause
________________ _____________ ______ _________ ________________ _____________
Another way to define a range is to specify a tolerance around a time using withtol. For example,
find rows from the summer of 2008 where OutageTime is within three days of Labor Day, September
1.
10-26
Select Times in Timetable
WT = withtol("2008-09-01",days(3));
nearSep1 = summer08(WT,:)
nearSep1=4×5 timetable
OutageTime Region Loss Customers RestorationTime Cause
________________ _____________ ______ _________ ________________ _____________
You also can use units of datetime values, such as hours or days, to identify rows for logical
indexing. This method can be useful for specifying periodic intervals.
For example, find the values of OutageTime whose month components have values of 3 or less,
corresponding to January, February, and March of each year. Use the resulting logical array to index
into TT.
head(winterTT,5)
Create a pie chart of the wintertime causes. The pie function accepts only numeric or categorical
inputs, so first convert Cause to categorical.
winterTT.Cause = categorical(winterTT.Cause);
pie(winterTT.Cause)
title("Causes of Outages, January to March");
10-27
10 Timetables
The retime function adjusts row times to create specified intervals, either by resampling or grouping
values. Its pre-defined intervals range from seconds to years, and you can specify how to handle
missing or multiple values for the intervals. For instance, you can select the first observation from
each week, or count observations in a quarter.
For the outage data, you can use retime to find totals for each year. First, create a timetable with
only numeric variables. Then, call retime and specify a yearly interval, combining multiple values
using a sum. The output has one row for each year, containing the total losses and total customers
affected during that year.
numTT = TT(:,vartype("numeric"));
numTT = retime(numTT,"yearly","sum");
head(numTT,5)
10-28
Select Times in Timetable
bar(numTT.OutageTime,numTT.Customers)
xlabel("Year")
ylabel("Customers")
You can use the row times of a timetable with other datetime or duration values to perform
calculations. For example, calculate the durations of the power outages listed in the outage data.
Then calculate the monthly medians of the outage durations and plot them.
First add the outage durations to TT by subtracting the row times (which are the starts of power
outages) from RestorationTime (which are the ends of the power outages). Change the format of
OutageDuration to display the durations of the outages in days. Display the first five rows of TT.
10-29
10 Timetables
Create a timetable that has only the outage durations. Some rows of TT have missing values, NaT, for
the restoration times, leading to NaN values in OutageDuration. To remove the NaN values from
medianTT, use the rmmissing function. Then use retime to calculate the monthly median outage
duration. Display the first five rows of medianTT.
medianTT = TT(:,"OutageDuration");
medianTT = rmmissing(medianTT);
medianTT = retime(medianTT,'monthly',@median);
head(medianTT,5)
OutageTime OutageDuration
________________ ______________
stairs(medianTT.OutageTime,medianTT.OutageDuration)
xlabel("Year")
ylabel("Median Duration (days)")
10-30
Select Times in Timetable
See Also
categorical | timetable | retime | timerange | readtimetable | month | withtol |
rmmissing | vartype | datetime | duration | NaT
Related Examples
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Access Data in Tables” on page 9-37
• “Calculations When Tables Have Both Numeric and Nonnumeric Data” on page 9-66
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Compare Dates and Time” on page 7-37
• “Date and Time Arithmetic” on page 7-32
10-31
10 Timetables
This example shows how to create a regular timetable from one that has missing, duplicate, or
nonuniform times. A timetable is a type of table that associates a time-stamp, or row time, with each
row of data. In a regular timetable, the row times are sorted and unique, and differ by the same
regular time step.
Also, some toolboxes have functions that work on regularly spaced time series data in the form of
numeric arrays. So the example also shows how to export the data from a timetable for use with other
functions.
There are a number of issues with row times that can make timetables irregular. The row times can
be missing. They can be out of order. They can be duplicates, creating multiple rows with the same
time that might have the same or different data. And even when they are present, sorted, and unique,
they can differ by time steps of different sizes.
Timetables provide a number of different ways to resolve missing, duplicate, or nonuniform times,
and to resample or aggregate data to create regular row times.
10-32
Clean Timetable with Missing, Duplicate, or Nonuniform Times
Load Timetable
Load a sample timetable from the MAT-file badTimes that contains weather measurements taken
over several hours on June 9, 2016. The timetable TT includes temperature, rainfall, and wind speed
measurements taken at irregular times during that day.
load badTimes
TT
TT=12×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
10-33
10 Timetables
One way to begin is by finding and removing rows that have a NaT, or missing value, as the row time.
To find missing values in the vector of row times, use ismissing. The ismissing function returns a
logical vector that contains 1 wherever TT.Time has a missing value.
natRowTimes = ismissing(TT.Time)
0
0
0
0
1
0
0
0
0
0
⋮
To keep only those rows that do not have missing values as row times, index into TT using
~natRowTimes as row indices. Assign those rows to a new timetable, goodRowTimesTT.
goodRowTimesTT = TT(~natRowTimes,:)
goodRowTimesTT=11×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
This method removes only the rows that have missing row times. The timetable variables still might
have missing data values. For example, the last row of goodRowTimesTT has NaN values for the Rain
and Windspeed variables.
As an alternative, you can remove both missing row times and missing data values at the same time
by using the rmmissing function. rmmissing removes any timetable rows that have missing row
times, missing data values, or both.
Display the missing row time and missing data values of TT.
TT
10-34
Clean Timetable with Missing, Duplicate, or Nonuniform Times
TT=12×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
Remove all rows that have missing row times or data values. Assign the remaining rows to the
timetable goodValuesTT.
goodValuesTT = rmmissing(TT)
goodValuesTT=10×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
After dealing with missing values, you can go on to sort your timetable and then determine if the
sorted timetable is regular.
tf = logical
0
Since it is not, sort the timetable on its row times by using the sortrows function.
sortedTT = sortrows(goodValuesTT)
sortedTT=10×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
10-35
10 Timetables
Determine whether sortedTT is regular. A regular timetable has the same time interval between
consecutive row times. Even a sorted timetable can have time steps that are not uniform.
tf = isregular(sortedTT)
tf = logical
0
diff(sortedTT.Time)
Since the row times are sorted, this result shows that some row times are unique and some are
duplicates.
Timetables can have duplicate rows. Timetable rows are duplicates if they have the same row times
and the same data values. In this example, the last two rows of sortedTT are duplicate rows. (There
are other rows in sortedTT that have duplicate row times but differing data values.)
To remove the duplicate rows from sortedTT, use unique. The unique function returns the unique
rows and sorts them by their row times.
uniqueRowsTT = unique(sortedTT)
uniqueRowsTT=9×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
10-36
Clean Timetable with Missing, Duplicate, or Nonuniform Times
Timetables can have rows with duplicate row times but different data values. In this example,
uniqueRowsTT has several rows with the same row times but different values.
Find the rows that have duplicate row times. First, sort the row times and find consecutive times that
have no difference between them. Times with no difference between them are the duplicates. Index
back into the vector of row times and return a unique set of times that identify the duplicate row
times in uniqueRowsTT.
dupTimes = sort(uniqueRowsTT.Time);
tf = (diff(dupTimes) == 0);
dupTimes = dupTimes(tf);
dupTimes = unique(dupTimes)
To display the rows with duplicate row times, index into uniqueRowsTT using dupTimes. When you
index on times, the output timetable contains all rows with matching row times.
uniqueRowsTT(dupTimes,:)
ans=6×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
When a timetable has rows with duplicate times, you might want to select particular rows and discard
the other rows having duplicate times. For example, you can select either the first or the last of the
rows with duplicate row times by using the unique and retime functions.
uniqueTimes = unique(uniqueRowsTT.Time)
10-37
10 Timetables
09-Jun-2016 06:01:04
09-Jun-2016 07:59:23
09-Jun-2016 08:49:10
09-Jun-2016 09:53:57
Select the first row from each set of rows that have duplicate times. To copy data from the first rows,
specify the 'firstvalue' method.
firstUniqueRowsTT = retime(uniqueRowsTT,uniqueTimes,'firstvalue')
firstUniqueRowsTT=5×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
Select the last rows from each set of rows that have duplicate times. To copy data from the last rows,
specify the 'lastvalue' method.
lastUniqueRowsTT = retime(uniqueRowsTT,uniqueTimes,'lastvalue')
lastUniqueRowsTT=5×3 timetable
Time Temp Rain WindSpeed
____________________ ____ ____ _________
As a result, the last two rows of firstUniqueRowsTT and lastUniqueRowsTT have different values
in the Temp variable.
Another way to deal with data in the rows having duplicate times is to aggregate or combine the data
values in some way. For example, you can calculate the means of several measurements of the same
quantity taken at the same time.
Calculate the mean temperature, rainfall, and wind speed for rows with duplicate row times using the
retime function.
meanTT = retime(uniqueRowsTT,uniqueTimes,'mean')
meanTT=5×3 timetable
Time Temp Rain WindSpeed
____________________ _____ ____ _________
10-38
Clean Timetable with Missing, Duplicate, or Nonuniform Times
As a result, the last two rows of meanTT have mean temperatures in the Temp variable for the rows
with duplicate row times.
Finally, you can resample data from an irregular timetable to make it regular by using the retime
function. For example, you can interpolate the data from meanTT onto a regular hourly time vector.
To use linear interpolation, specify 'linear'. Each row time in hourlyTT begins on the hour, and
there is a one-hour interval between consecutive row times.
hourlyTT = retime(meanTT,'hourly','linear')
hourlyTT=6×3 timetable
Time Temp Rain WindSpeed
____________________ ______ ________ _________
Instead of using a predefined time step such as 'hourly', you can specify a time step of your own.
To specify a time step of 30 minutes, use the 'regular' input argument and the 'TimeStep' name-
value argument. You can specify a time step of any size as a duration or calendarDuration value.
regularTT = retime(meanTT,'regular','linear','TimeStep',minutes(30))
regularTT=11×3 timetable
Time Temp Rain WindSpeed
____________________ ______ ________ _________
You can export the timetable data for use with functions to analyze data that is regularly spaced in
time. For example, the Econometrics Toolbox™ and the Signal Processing Toolbox™ have functions
you can use for further analysis on regularly spaced data.
10-39
10 Timetables
Extract the timetable data as an array. You can use the Variables property to return the data as an
array, as long as the table variables have data types that allow them to be concatenated.
A = regularTT.Variables
A = 11×3
A2 = regularTT{:,:}
A2 = 11×3
See Also
timetable | table2timetable | retime | issorted | sortrows | unique | diff | isregular |
rmmissing | fillmissing
Related Examples
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Combine Timetables and Synchronize Their Data” on page 10-13
• “Retime and Synchronize Timetable Variables Using Different Methods” on page 10-19
• “Select Times in Timetable” on page 10-24
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Add Event Table from External Data to Timetable” on page 10-77
• “Find Events in Timetable Using Event Table” on page 10-94
10-40
Using Row Labels in Table and Timetable Operations
Tables and timetables provide ways to label the rows in your data. In tables, you can label the rows
with names. In timetables, you must label the rows with dates, times, or both. Row names are
optional for tables, but row times are required for timetables. These row labels are part of the
metadata in a table or timetable. In some functions you also can use row labels as key variables,
grouping variables, and so on, just as you can use the data variables in a table or timetable. These
functions are sortrows, join, innerjoin, outerjoin, varfun, rowfun, stack, and unstack.
There are some limitations on using these table functions and on using row labels as key variables.
For example, you can sort a timetable on its row times, on one or more of its data variables, or on row
times and data variables together.
Create a timetable using the timetable function. A timetable has row times along its first
dimension, labeling the rows. The row times are a property of the timetable, not a timetable variable.
Date = datetime(2016,7,[10;10;11;11;10;10;11;11]);
X = [1;1;1;1;2;2;2;2];
Y = {'a';'b';'a';'b';'a';'b';'a';'b'};
Z = [1;2;3;4;5;6;7;8];
TT = timetable(X,Y,Z,'RowTimes',Date)
TT=8×3 timetable
Time X Y Z
___________ _ _____ _
10-Jul-2016 1 {'a'} 1
10-Jul-2016 1 {'b'} 2
11-Jul-2016 1 {'a'} 3
11-Jul-2016 1 {'b'} 4
10-Jul-2016 2 {'a'} 5
10-Jul-2016 2 {'b'} 6
11-Jul-2016 2 {'a'} 7
11-Jul-2016 2 {'b'} 8
Rename the first dimension. By default, the name of the first dimension of a timetable is Time. You
can access the Properties.DimensionNames property to rename a dimension.
TT.Properties.DimensionNames{1} = 'Date';
TT.Properties.DimensionNames
As an alternative, you can specify the row times as the first input argument to timetable, without
specifying 'RowTimes'. The timetable function names the row times, or the first dimension, after
the first input argument, just as it names the timetable variables after the other input arguments.
TT = timetable(Date,X,Y,Z)
TT=8×3 timetable
Date X Y Z
10-41
10 Timetables
___________ _ _____ _
10-Jul-2016 1 {'a'} 1
10-Jul-2016 1 {'b'} 2
11-Jul-2016 1 {'a'} 3
11-Jul-2016 1 {'b'} 4
10-Jul-2016 2 {'a'} 5
10-Jul-2016 2 {'b'} 6
11-Jul-2016 2 {'a'} 7
11-Jul-2016 2 {'b'} 8
Sort the timetable by row times. To sort on row times, refer to the first dimension of the timetable by
name.
sortrows(TT,'Date')
ans=8×3 timetable
Date X Y Z
___________ _ _____ _
10-Jul-2016 1 {'a'} 1
10-Jul-2016 1 {'b'} 2
10-Jul-2016 2 {'a'} 5
10-Jul-2016 2 {'b'} 6
11-Jul-2016 1 {'a'} 3
11-Jul-2016 1 {'b'} 4
11-Jul-2016 2 {'a'} 7
11-Jul-2016 2 {'b'} 8
ans=8×3 timetable
Date X Y Z
___________ _ _____ _
10-Jul-2016 1 {'a'} 1
11-Jul-2016 1 {'a'} 3
10-Jul-2016 1 {'b'} 2
11-Jul-2016 1 {'b'} 4
10-Jul-2016 2 {'a'} 5
11-Jul-2016 2 {'a'} 7
10-Jul-2016 2 {'b'} 6
11-Jul-2016 2 {'b'} 8
ans=8×3 timetable
Date X Y Z
___________ _ _____ _
10-Jul-2016 1 {'a'} 1
10-Jul-2016 1 {'b'} 2
10-42
Using Row Labels in Table and Timetable Operations
10-Jul-2016 2 {'a'} 5
10-Jul-2016 2 {'b'} 6
11-Jul-2016 1 {'a'} 3
11-Jul-2016 1 {'b'} 4
11-Jul-2016 2 {'a'} 7
11-Jul-2016 2 {'b'} 8
When you group rows together using the rowfun, varfun, stack, and unstack functions, you can
specify row labels as grouping variables. When you join tables or timetable together using the join,
innerjoin, and outerjoin functions, you can specify row labels as key variables.
For example, you can perform an inner join two tables together, using row names and a table variable
together as key variables. An inner join keeps only those table rows that match with respect to the
key variables.
Create two tables of patient data. A table can have row names along its first dimension, labeling the
rows, but is not required to have them. Specify the last names of patients as the row names of the
tables. Add the first names of the patients as table variables.
A = table({'Michael';'Louis';'Alice';'Rosemary';'Julie'},[38;43;45;40;49],...
'VariableNames',{'FirstName' 'Age'},...
'RowNames',{'Garcia' 'Johnson' 'Wu' 'Jones' 'Picard'})
A=5×2 table
FirstName Age
____________ ___
Garcia {'Michael' } 38
Johnson {'Louis' } 43
Wu {'Alice' } 45
Jones {'Rosemary'} 40
Picard {'Julie' } 49
B = table({'Michael';'Beverly';'Alice'},...
[64;69;67],...
[119;163;133],...
[122 80; 109 77; 117 75],...
'VariableNames',{'FirstName' 'Height' 'Weight' 'BloodPressure'},...
'RowNames',{'Garcia' 'Johnson' 'Wu'})
B=3×4 table
FirstName Height Weight BloodPressure
___________ ______ ______ _____________
If a table has row names, then you can index into it by row name. Indexing by row names is a
convenient way to select rows of a table. Index into B by a patient's last name to retrieve information
about the patient.
B('Garcia',:)
10-43
10 Timetables
ans=1×4 table
FirstName Height Weight BloodPressure
___________ ______ ______ _____________
Perform an inner join on the two tables. Both tables use the last names of patients as row names, and
contain the first names as a table variable. Some patients in the two tables have matching last names
but different first names. To ensure that both last and first names match, use the row names and
FirstName as key variables. To specify the row names as a key or grouping variable, use the name of
the first dimension of the table. By default, the name of the first dimension is 'Row'.
C = innerjoin(A,B,'Keys',{'Row','FirstName'})
C=2×5 table
FirstName Age Height Weight BloodPressure
___________ ___ ______ ______ _____________
If you rename the first dimension of a table, then you can refer to the row names by that name
instead of using 'Row'. Perform the same inner join as above but use a different name to refer to the
row names.
A.Properties.DimensionNames
Change the name of the first dimension of the table by using its Properties.DimensionNames
property. Then use the new name as a key variable.
A.Properties.DimensionNames{1} = 'LastName';
A.Properties.DimensionNames
Perform an inner join on A and B using LastName and FirstName as key variables.
B.Properties.DimensionNames{1} = 'LastName';
D = innerjoin(A,B,'Keys',{'LastName','FirstName'})
D=2×5 table
FirstName Age Height Weight BloodPressure
___________ ___ ______ ______ _____________
10-44
Using Row Labels in Table and Timetable Operations
• You cannot stack or unstack row labels using the stack and unstack functions. However, you can
use row labels as grouping variables.
• You cannot perform a join using the join, innerjoin, or outerjoin functions when the first
argument is a table and the second argument is a timetable. However, you can perform a join
when both arguments are tables, both are timetables, or the first argument is a timetable and the
second is a table.
• The output of a join operation can have row labels if you specify row labels as key variables. For
more details on row labels from a join operation, see the documentation on the 'Keys',
'LeftKeys', and 'RightKeys' arguments of the join, innerjoin, and outerjoin functions.
See Also
sortrows | join | innerjoin | outerjoin | varfun | rowfun | stack | unstack
10-45
10 Timetables
This example shows how to store timestamped earthquake data in a timetable and how to use
timetable functions to analyze and visualize the data.
The example file quake.mat contains 200 Hz data from the October 17, 1989, Loma Prieta
earthquake in the Santa Cruz Mountains. The data are courtesy of Joel Yellin at the Charles F. Richter
Seismological Laboratory, University of California, Santa Cruz.
load quake
whos e n v
In the workspace there are three variables, containing time traces from an accelerometer located in
the Natural Sciences building at UC Santa Cruz. The accelerometer recorded the main shock
amplitude of the earthquake wave. The variables n, e, v refer to the three directional components
measured by the instrument, which was aligned parallel to the fault, with its N direction pointing in
the direction of Sacramento. The data are uncorrected for the response of the instrument.
Create a variable, Time, containing the timestamps sampled at 200Hz with the same length as the
other vectors. Represent the correct units with the seconds function and multiplication to achieve
the Hz (s−1) sampling rate. This results in a duration variable which is useful for representing
elapsed time.
Time = (1/200)*seconds(1:length(e))';
whos Time
Separate variables can be organized in a table or timetable for more convenience. A timetable
provides flexibility and functionality for working with time-stamped data. Create a timetable with
the time and three acceleration variables and supply more meaningful variable names. Display the
first eight rows using the head function.
varNames = ["EastWest","NorthSouth","Vertical"];
quakeData = timetable(Time,e,n,v,VariableNames=varNames)
quakeData=10001×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
0.005 sec 5 3 0
10-46
Loma Prieta Earthquake Analysis
0.01 sec 5 3 0
0.015 sec 5 2 0
0.02 sec 5 2 0
0.025 sec 5 2 0
0.03 sec 5 2 0
0.035 sec 5 1 0
0.04 sec 5 1 0
0.045 sec 5 1 0
0.05 sec 5 0 0
0.055 sec 5 0 0
0.06 sec 5 0 0
0.065 sec 5 0 0
0.07 sec 5 0 0
0.075 sec 5 0 0
0.08 sec 5 0 0
⋮
Explore the data by accessing the variables in the timetable with dot notation. (For more
information on dot notation, see “Access Data in Tables” on page 9-37.) Choose the East-West
amplitude and plot it as function of the duration.
plot(quakeData.Time,quakeData.EastWest)
title("East-West Acceleration")
10-47
10 Timetables
Scale Data
Scale the data by the gravitational acceleration, or multiply each variable in the table by the constant.
Since the variables are all of the same type (double), you can access all variables using the
dimension name, Variables. Note that quakeData.Variables provides a direct way to modify the
numerical values within the timetable.
quakeData.Variables = 0.098*quakeData.Variables;
Examine the time region where the amplitude of the shockwave starts to increase from near zero to
maximum levels. Visual inspection of the above plot shows that the time interval from 8 to 15 seconds
is of interest. For better visualization draw black lines at the selected time spots to draw attention to
that interval. All subsequent calculations involve this interval.
t1 = seconds(8);
t2 = seconds(15);
xline(t1,LineWidth=2)
xline(t2,LineWidth=2)
Create another timetable with data in this interval. Use timerange to select the rows of interest.
tr = timerange(t1,t2);
quakeData8to15 = quakeData(tr,:)
10-48
Loma Prieta Earthquake Analysis
quakeData8to15=1400×3 timetable
Time EastWest NorthSouth Vertical
_________ ________ __________ ________
Visualize the three acceleration variables on three separate axes. To create a tiled layout with the
three plots in a 3-by-1 tile arrangement, use the tiledlayout function.
tiledlayout(3,1)
% Tile 1
nexttile
plot(quakeData8to15.Time,quakeData8to15.EastWest)
ylabel("East-West")
title("Acceleration")
% tile 2
nexttile
plot(quakeData8to15.Time,quakeData8to15.NorthSouth)
ylabel("North-South")
% Tile 3
nexttile
plot(quakeData8to15.Time,quakeData8to15.Vertical)
ylabel("Vertical")
10-49
10 Timetables
To display statistical information about the data use the summary function.
summary(quakeData8to15)
Row Times:
Time: duration
Variables:
EastWest: double
NorthSouth: double
Vertical: double
10-50
Loma Prieta Earthquake Analysis
Additional statistical information about the data can be calculated using varfun. This is useful for
applying functions to each variable in a table or timetable. The function to apply is passed to varfun
as a function handle. Apply the mean function to all three variables and output the result in format of
a table, because the time is not meaningful after computing the temporal means.
mn = varfun(@mean,quakeData8to15,OutputFormat="table")
mn=1×3 table
mean_EastWest mean_NorthSouth mean_Vertical
_____________ _______________ _____________
To identify the speed of propagation of the shockwave, integrate the accelerations once. Use
cumulative sums along the time variable to calculate the velocity of the wave front.
edot = (1/200)*cumsum(quakeData8to15.EastWest);
edot = edot - mean(edot);
Next perform the integration on all three variables to calculate the velocity. It is convenient to create
a function and apply it to the variables in the timetable with varfun. In this example, the function
is included at the end of this example and is named velFun.
vel = varfun(@velFun,quakeData8to15)
vel=1400×3 timetable
Time velFun_EastWest velFun_NorthSouth velFun_Vertical
_________ _______________ _________________ _______________
Apply the same function velFun to the velocities to determine the position.
pos = varfun(@velFun,vel)
pos=1400×3 timetable
Time velFun_velFun_EastWest velFun_velFun_NorthSouth velFun_velFun_Vertical
_________ ______________________ ________________________ ______________________
10-51
10 Timetables
Notice how the variable names in the timetable created by varfun include the name of the function
used. It is useful to track the operations that have been performed on the original data. Adjust the
variable names back to their original values using dot notation.
pos.Properties.VariableNames = varNames;
vel.Properties.VariableNames = varNames;
Plot the three components of the velocity and position for the time interval of interest. Plot velocity
and position in a 2-by-1 tile arrangement.
tiledlayout(2,1)
% Tile 1
nexttile
plot(vel.Time,vel.Variables)
legend(vel.Properties.VariableNames,Location="bestoutside")
title("Velocity")
% Tile 2
nexttile
plot(pos.Time,pos.Variables)
title("Position")
10-52
Loma Prieta Earthquake Analysis
Visualize Trajectories
The trajectories can be plotted in 2D or 3D by using the component value. This plot shows different
ways of visualizing this data.
Begin with 2-dimensional projections. Here is the first with a few values of time annotated.
figure
plot(pos.NorthSouth,pos.Vertical)
xlabel("North-South")
ylabel("Vertical")
% Select locations and label
nt = ceil((max(pos.Time) - min(pos.Time))/6);
idx = find(fix(pos.Time/nt) == (pos.Time/nt))';
text(pos.NorthSouth(idx),pos.Vertical(idx),char(pos.Time(idx)))
10-53
10 Timetables
Use plotmatrix to visualize a grid of scatter plots of all variables against one another and
histograms of each variable on the diagonal. The output variable Ax, represents each axes in the grid
and can be used to identify which axes to label using xlabel and ylabel.
figure
[S,Ax] = plotmatrix(pos.Variables);
for ii = 1:length(varNames)
xlabel(Ax(end,ii),varNames{ii})
ylabel(Ax(ii,1),varNames{ii})
end
10-54
Loma Prieta Earthquake Analysis
Plot a 3-D view of the trajectory and plot a vertical line at every tenth position point. The spacing
between vertical lines indicates the velocity.
step = 10;
figure
plot3(pos.NorthSouth,pos.EastWest,pos.Vertical,"r")
hold on
plot3(pos.NorthSouth(1:step:end),pos.EastWest(1:step:end),pos.Vertical(1:step:end),"|")
hold off
box
axis tight
xlabel("North-South")
ylabel("East-West")
zlabel("Vertical")
title("Position")
10-55
10 Timetables
Supporting Functions
function y = velFun(x)
y = (1/200)*cumsum(x);
y = y - mean(y);
end
See Also
timetable | head | summary | varfun | duration | seconds | timerange
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Create Timetables” on page 10-2
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Select Times in Timetable” on page 10-24
• “Access Data in Tables” on page 9-37
10-56
Preprocess and Explore Time-Stamped Data Using timetable
This example shows how to analyze bicycle traffic patterns from sensor data using the timetable
data container to organize and preprocess time-stamped data. The data come from sensors on
Broadway Street in Cambridge, MA. The City of Cambridge provides public access to the full data set
at the Cambridge Open Data site.
This example shows how to perform a variety of data cleaning, munging, and preprocessing tasks
such as removing missing values and synchronizing time-stamped data with different timesteps. In
addition, data exploration is highlighted including visualizations and grouped calculations using the
timetable data container to:
Import a sample of the bicycle traffic data from a comma-separated text file. The readtable function
returns the data in a table. Display the first eight rows using the head function.
bikeTbl = readtable('BicycleCounts.csv');
head(bikeTbl)
The data have timestamps, so it is convenient to use a timetable to store and analyze the data. A
timetable is similar to a table, but includes timestamps that are associated with the rows of data. The
timestamps, or row times, are represented by datetime or duration values. datetime and
duration are the recommended data types for representing points in time or elapsed times,
respectively.
Convert bikeTbl into a timetable using the table2timetable function. You must use a conversion
function because readtable returns a table. table2timetable converts the first datetime or
duration variable in the table into the row times of a timetable. The row times are metadata that
label the rows. However, when you display a timetable, the row times and timetable variables are
displayed in a similar fashion. Note that the table has five variables whereas the timetable has four.
bikeData = table2timetable(bikeTbl);
head(bikeData)
10-57
10 Timetables
Convert the Day variable to categorical. The categorical data type is designed for data that consists
of a finite set of discrete values, such as the names of the days of the week. List the categories so
they display in day order. Use dot subscripting to access variables by name.
bikeData.Day = categorical(bikeData.Day,{'Sunday','Monday','Tuesday',...
'Wednesday','Thursday','Friday','Saturday'});
In a timetable, the times are treated separately from the data variables. Access the Properties of
the timetable to show that the row times are the first dimension of the timetable, and the variables
are the second dimension. The DimensionNames property shows the names of the two dimensions,
while the VariableNames property shows the names of the variables along the second dimension.
bikeData.Properties
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Timestamp' 'Variables'}
VariableNames: {'Day' 'Total' 'Westbound' 'Eastbound'}
VariableTypes: ["categorical" "double" "double" "double"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [9387x1 datetime]
StartTime: 2015-06-24 00:00:00
SampleRate: NaN
TimeStep: NaN
Events: []
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
By default, table2timetable assigned Timestamp as the first dimension name when it converted
the table to a timetable, since this was the variable name from the original table. You can change the
names of the dimensions, and other timetable metadata, through the Properties.
10-58
Preprocess and Explore Time-Stamped Data Using timetable
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Time' 'Data'}
VariableNames: {'Day' 'Total' 'Westbound' 'Eastbound'}
VariableTypes: ["categorical" "double" "double" "double"]
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [9387x1 datetime]
StartTime: 2015-06-24 00:00:00
SampleRate: NaN
TimeStep: NaN
Events: []
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
Determine the number of days that elapsed between the latest and earliest row times. The variables
can be accessed by dot notation when referencing variables one at a time.
elapsedTime = max(bikeData.Time) - min(bikeData.Time)
elapsedTime = duration
9383:30:00
elapsedTime.Format = 'd'
elapsedTime = duration
390.98 days
To examine the typical bicycle counts on a given day, calculate the means for the total number of
bikes, and the numbers travelling westbound and eastbound.
Return the numeric data as a matrix by indexing into the contents of bikeData using curly braces.
Display the first eight rows. Use standard table subscripting to access multiple variables.
10-59
10 Timetables
counts = bikeData{:,2:end};
counts(1:8,:)
ans = 8×3
13 9 4
3 3 0
1 1 0
1 1 0
1 1 0
7 3 4
36 6 30
141 13 128
Since the mean is appropriate for only the numeric data, you can use the vartype function to select
the numeric variables. vartype can be more convenient than manually indexing into a table or
timetable to select variables. Calculate the means and omit NaN values.
counts = bikeData{:,vartype('numeric')};
mean(counts,'omitnan')
ans = 1×3
To determine how many people bicycle during a holiday, examine the data on the 4th of July holiday.
Index into the timetable by row times for July 4, 2015. When you index on row times, you must match
times exactly. You can specify the time indices as datetime or duration values, or as character
vectors that can be converted to dates and times. You can specify multiple times as an array.
Index into bikeData with specific dates and times to extract data for July 4, 2015. If you specify the
date only, then the time is assumed to be midnight, or 00:00:00.
bikeData('2015-07-04',:)
ans=1×4 timetable
Time Day Total Westbound Eastbound
___________________ ________ _____ _________ _________
ans=2×4 timetable
Time Day Total Westbound Eastbound
___________________ ________ _____ _________ _________
10-60
Preprocess and Explore Time-Stamped Data Using timetable
It would be tedious to use this strategy to extract the entire day. You can also specify ranges of time
without indexing on specific times. To create a time range subscript as a helper, use the timerange
function.
Subscript into the timetable using a time range for the entire day of July 4, 2015. Specify the start
time as midnight on July 4, and the end time as midnight on July 5. By default, timerange covers all
times starting with the start time and up to, but not including, the end time. Plot the bicycle counts
over the course of the day.
tr = timerange('2015-07-04','2015-07-05');
jul4 = bikeData(tr,'Total');
head(jul4)
Time Total
___________________ _____
2015-07-04 00:00:00 8
2015-07-04 01:00:00 13
2015-07-04 02:00:00 4
2015-07-04 03:00:00 1
2015-07-04 04:00:00 0
2015-07-04 05:00:00 1
2015-07-04 06:00:00 8
2015-07-04 07:00:00 16
bar(jul4.Time,jul4.Total)
ylabel('Bicycle Counts')
title('Bicycle Counts on July 4, 2015')
10-61
10 Timetables
From the plot, there is more volume throughout the day, leveling off in the afternoon. Because many
businesses are closed, the plot does not show typical traffic during commute hours. Spikes later in
the evening can be attributed to celebrations with fireworks, which occur after dark. To examine
these trends more closely, the data should be compared to data for typical days.
Compare the data for July 4 to data for the rest of the month of July.
jul = bikeData(timerange('2015-07-01','2015-08-01'),:);
plot(jul.Time,jul.Total)
hold on
plot(jul4.Time,jul4.Total)
ylabel('Total Count')
title('Bicycle Counts in July')
hold off
legend('Bicycle Count','July 4 Bicycle Count')
The plot shows variations that can be attributed to traffic differences between weekdays and
weekends. The traffic patterns for July 4 and 5 are consistent with the pattern for weekend traffic.
July 5 is a Monday but is often observed as a holiday. These trends can be examined more closely with
further preprocessing and analysis.
Time-stamped data sets are often messy and may contain anomalies or errors. Timetables are well
suited for resolving anomalies and errors.
10-62
Preprocess and Explore Time-Stamped Data Using timetable
A timetable does not have to have its row times in any particular order. It can contain rows that are
not sorted by their row times. A timetable can also contain multiple rows with the same row time,
though the rows can have different data values. Even when row times are sorted and unique, they can
differ by time steps of different sizes. A timetable can even contain NaT or NaN values to indicate
missing row times.
The timetable data type provides a number of different ways to resolve missing, duplicate, or
nonuniform times. You can also resample or aggregate data to create a regular timetable. When a
timetable is regular, it has row times that are sorted and unique, and have a uniform or evenly spaced
time step between them.
Determine if the timetable is sorted. A timetable is sorted if its row times are listed in ascending
order.
issorted(bikeData)
10-63
10 Timetables
ans = logical
0
Sort the timetable. The sortrows function sorts the rows by their row times, from earliest to latest
time. If there are rows with duplicate row times, then sortrows copies all the duplicates to the
output.
bikeData = sortrows(bikeData);
issorted(bikeData)
ans = logical
1
A timetable can have missing data indicators in its variables or its row times. For example, you can
indicate missing numeric values as NaNs, and missing datetime values as NaTs. You can assign, find,
remove, and fill missing values with the standardizeMissing, ismissing, rmmissing, and
fillmissing functions, respectively.
Find and count the missing values in the timetable variables. In this example, missing values indicate
circumstances when no data were collected.
missData = ismissing(bikeData);
sum(missData)
ans = 1×4
1 3 3 3
The output from ismissing is a logical matrix, the same size as the table, identifying missing data
values as true. Display any rows which have missing data indicators.
idx = any(missData,2);
bikeData(idx,:)
ans=3×4 timetable
Time Day Total Westbound Eastbound
___________________ ___________ _____ _________ _________
ismissing(bikeData) finds missing data in the timetable variables only, not the times. To find
missing row times, call ismissing on the row times.
missTimes = ismissing(bikeData.Time);
bikeData(missTimes,:)
ans=2×4 timetable
Time Day Total Westbound Eastbound
____ ___________ _____ _________ _________
10-64
Preprocess and Explore Time-Stamped Data Using timetable
In this example, missing times or data values indicate measurement errors and can be excluded.
Remove rows of the table containing missing data values and missing row times using rmmissing.
bikeData = rmmissing(bikeData);
sum(ismissing(bikeData))
ans = 1×4
0 0 0 0
sum(ismissing(bikeData.Time))
ans =
0
Determine if there are duplicate times and/or duplicate rows of data. You might want to exclude exact
duplicates, as these can also be considered measurement errors. Identify duplicate times by finding
where the difference between the sorted times is exactly zero.
idx = diff(bikeData.Time) == 0;
dup = bikeData.Time(idx)
Three times are repeated and November 19, 2015, is repeated twice. Examine the data associated
with the repeated times.
bikeData(dup(1),:)
ans=2×4 timetable
Time Day Total Westbound Eastbound
___________________ ______ _____ _________ _________
bikeData(dup(2),:)
ans=3×4 timetable
Time Day Total Westbound Eastbound
___________________ ________ _____ _________ _________
10-65
10 Timetables
The first has duplicated times but non-duplicate data, whereas the others are entirely duplicated.
Timetable rows are considered duplicates when they contain identical row times and identical data
values across the rows. You can use unique to remove duplicate rows in the timetable. The unique
function also sorts the rows by their row times.
bikeData = unique(bikeData);
The rows with duplicate times but non-duplicate data require some interpretation. Examine the data
around those times.
d = dup(1) + hours(-2:2);
bikeData(d,:)
ans=5×4 timetable
Time Day Total Westbound Eastbound
___________________ ________ _____ _________ _________
In this case, the duplicate time may have been mistaken since the data and surrounding times are
consistent. Though it appears to represent 01:00:00, it is uncertain what time this should have been.
The data can be accumulated to account for the data at both time points.
sum(bikeData{dup(1),2:end})
ans = 1×3
25 16 9
This is only one case which can be done manually. However, for many rows, the retime function can
perform this calculation. Accumulate the data for the unique times using the sum function to
aggregate. The sum is appropriate for numeric data but not the categorical data in the timetable. Use
vartype to identify the numeric variables.
vt = vartype('numeric');
t = unique(bikeData.Time);
numData = retime(bikeData(:,vt),t,'sum');
head(numData)
2015-06-24 00:00:00 13 9 4
2015-06-24 01:00:00 3 3 0
2015-06-24 02:00:00 1 1 0
2015-06-24 03:00:00 1 1 0
2015-06-24 04:00:00 1 1 0
2015-06-24 05:00:00 7 3 4
2015-06-24 06:00:00 36 6 30
2015-06-24 07:00:00 141 13 128
10-66
Preprocess and Explore Time-Stamped Data Using timetable
You cannot sum the categorical data, but since one label represents the whole day, take the first value
on each day. You can perform the retime operation again with the same time vector and concatenate
the timetables together.
vc = vartype('categorical');
catData = retime(bikeData(:,vc),t,'firstvalue');
bikeData = [catData,numData];
bikeData(d,:)
ans=4×4 timetable
Time Day Total Westbound Eastbound
___________________ ________ _____ _________ _________
The data appear to have a uniform time step of one hour. To determine if this is true for all the row
times in the timetable, use the isregular function. isregular returns true for sorted, evenly-
spaced times (monotonically increasing), with no duplicate or missing times (NaT or NaN).
isregular(bikeData)
ans = logical
0
The output of 0, or false, indicates that the times in the timetable are not evenly spaced. Explore
the time interval in more detail.
dt = diff(bikeData.Time);
[min(dt); max(dt)]
To put the timetable on a regular time interval, use retime or synchronize and specify the time
interval of interest.
Determine the counts per day using the retime function. Accumulate the count data for each day
using the sum method. This is appropriate for numeric data but not the categorical data in the
timetable. Use vartype to identify the variables by data type.
dayCountNum = retime(bikeData(:,vt),'daily','sum');
head(dayCountNum)
10-67
10 Timetables
As above, you can perform the retime operation again to represent the categorical data using an
appropriate method and concatenate the timetables together.
dayCountCat = retime(bikeData(:,vc),'daily','firstvalue');
dayCount = [dayCountCat,dayCountNum];
head(dayCount)
Examine the effect of weather on cycling behavior by comparing the bicycle count with weather data.
Load the weather timetable which includes historical weather data from Boston, MA, including storm
events.
load BostonWeatherData
head(weatherData)
01-Jul-2015 72 78 Thunderstorm
02-Jul-2015 72 60 None
03-Jul-2015 70 56 None
04-Jul-2015 67 75 None
05-Jul-2015 72 67 None
06-Jul-2015 74 69 None
07-Jul-2015 75 77 Rain
08-Jul-2015 79 68 Rain
To summarize the times and variables in the timetable, use the summary function.
summary(weatherData)
Row Times:
Time: datetime
Variables:
10-68
Preprocess and Explore Time-Stamped Data Using timetable
TemperatureF: double
Humidity: double
Events: categorical (7 categories)
Combine the bicycle data with the weather data to a common time vector using synchronize. You
can resample or aggregate timetable data using any of the methods documented on the reference
page for the synchronize function.
Synchronize the data from both timetables to a common time vector, constructed from the
intersection of their individual daily time vectors.
data = synchronize(dayCount,weatherData,'intersection');
head(data)
Compare bicycle traffic counts and outdoor temperature on separate y axes to examine the trends.
Remove the weekends from the data for visualization.
idx = ~isweekend(data.Time);
weekdayData = data(idx,{'TemperatureF','Total'});
figure
yyaxis left
plot(weekdayData.Time, weekdayData.Total)
ylabel('Bicycle Count')
yyaxis right
plot(weekdayData.Time,weekdayData.TemperatureF)
ylabel('Temperature (\circ F)')
title('Bicycle Counts and Temperature Over Time')
xlim([min(data.Time) max(data.Time)])
10-69
10 Timetables
The plot shows that the traffic and weather data might follow similar trends. Zoom in on the plot.
xlim([datetime('2015-11-01'),datetime('2016-05-01')])
10-70
Preprocess and Explore Time-Stamped Data Using timetable
The trends are similar, indicating that fewer people cycle on colder days.
Examine the data based on different intervals such as day of the week and time of day. Determine the
total counts per day using varfun to perform grouped calculations on variables. Specify the sum
function with a function handle and the grouping variable and preferred output type using name-
value pairs.
byDay = varfun(@sum,bikeData,'GroupingVariables','Day',...
'OutputFormat','table')
byDay=7×5 table
Day GroupCount sum_Total sum_Westbound sum_Eastbound
_________ __________ _________ _____________ _____________
figure
bar(byDay{:,{'sum_Westbound','sum_Eastbound'}})
legend({'Westbound','Eastbound'},'Location','eastoutside')
10-71
10 Timetables
xticklabels({'Sun','Mon','Tue','Wed','Thu','Fri','Sat'})
title('Bicycle Count by Day of Week')
The bar plot indicates that traffic is heavier on weekdays. Also, there is a difference in the Eastbound
and Westbound directions. This might indicate that people tend to take different routes when
entering and leaving the city. Another possibility is that some people enter on one day and return on
another day.
Determine the hour of day and use varfun for calculations by group.
bikeData.HrOfDay = hour(bikeData.Time);
byHr = varfun(@mean,bikeData(:,{'Westbound','Eastbound','HrOfDay'}),...
'GroupingVariables','HrOfDay','OutputFormat','table');
head(byHr)
10-72
Preprocess and Explore Time-Stamped Data Using timetable
bar(byHr{:,{'mean_Westbound','mean_Eastbound'}})
legend('Westbound','Eastbound','Location','eastoutside')
xlabel('Hour of Day')
ylabel('Bicycle Count')
title('Mean Bicycle Count by Hour of Day')
There are traffic spikes at the typical commute hours, around 9:00 a.m. and 5:00 p.m. Also, the trends
between the Eastbound and Westbound directions are different. In general, the Westbound direction
is toward residential areas surrounding the Cambridge area and toward the universities. The
Eastbound direction is toward Boston.
The traffic is heavier later in the day in the Westbound direction compared to the Eastbound
direction. This might indicate university schedules and traffic due to restaurants in the area. Examine
the trend by day of week as well as hour of day.
byHrDay = varfun(@sum,bikeData,'GroupingVariables',{'HrOfDay','Day'},...
'OutputFormat','table');
head(byHrDay)
10-73
10 Timetables
To arrange the timetable so that the days of the week are the variables, use the unstack function.
hrAndDayWeek = unstack(byHrDay(:,{'HrOfDay','Day','sum_Total'}),'sum_Total','Day');
head(hrAndDayWeek)
ribbon(hrAndDayWeek.HrOfDay,hrAndDayWeek{:,2:end})
ylim([0 24])
xlim([0 8])
xticks(1:7)
xticklabels({'Sun','Mon','Tue','Wed','Thu','Fri','Sat'})
ylabel('Hour')
title('Bicycle Count by Hour and Day of Week')
10-74
Preprocess and Explore Time-Stamped Data Using timetable
There are similar trends for the regular work days of Monday through Friday, with peaks at rush hour
and traffic tapering off in the evening. Friday has less volume, though the overall trend is similar to
the other work days. The trends for Saturday and Sunday are similar to each other, without rush hour
peaks and with more volume later in the day. The late evening trends are also similar for Monday
through Friday, with less volume on Friday.
To examine the overall time of day trends, split up the data by rush hour times. It is possible to use
different times of day or units of time using the discretize function. For example, separate the data
into groups for AM, AMRush, Day, PMRush, PM. Then use varfun to calculate the mean by group.
bikeData.HrLabel = discretize(bikeData.HrOfDay,[0,6,10,15,19,24],'categorical',...
{'AM','RushAM','Day','RushPM','PM'});
byHrBin = varfun(@mean,bikeData(:,{'Total','HrLabel'}),'GroupingVariables','HrLabel',...
'OutputFormat','table')
byHrBin=5×3 table
HrLabel GroupCount mean_Total
_______ __________ __________
AM 2342 3.5508
RushAM 1564 94.893
Day 1955 45.612
RushPM 1564 98.066
PM 1955 35.198
bar(byHrBin.mean_Total)
cats = categories(byHrBin.HrLabel);
xticklabels(cats)
title('Mean Bicycle Count During Rush Hours')
10-75
10 Timetables
In general, there is about twice as much traffic in this area during the evening and morning rush
hours compared to other times of the day. There is very little traffic in this area in the early morning,
but there is still significant traffic in the evening and late evening, comparable to the day outside of
the morning and evening rush hours.
See Also
timetable | table2timetable | head | summary | varfun | timerange | sortrows | rmmissing
| retime | datetime | unstack
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Select Times in Timetable” on page 10-24
• “Add Event Table from External Data to Timetable” on page 10-77
• “Find Events in Timetable Using Event Table” on page 10-94
10-76
Add Event Table from External Data to Timetable
To find and label events in a timetable, attach an eventtable to it. An event table is a timetable of
events. An event consists of an event time (when something happened), often an event length or
event end time (how long it happened), often an event label (what happened), and sometimes
additional information about the event. When you attach an event table to a timetable, it enables you
to find and label rows in the timetable that occur during events. By associating timetable rows with
events, you can more easily analyze and plot the data that they contain.
This example shows how you can add events to your timetable using data that comes from an external
data source. In the example, import a timetable of measurements of the Earth's rotation rate from
1962 to the present. The rotation rate varies as a function of time, causing changes in the excess
length-of-day to accumulate. Whenever the cumulative excess becomes too large, a leap second is
inserted. This example analyzes the excess length-of-day over time and treats leap seconds added
since 1972 as a set of external events. To analyze these data with event tables, use the eventtable,
eventfilter, and syncevents functions. (A related workflow is to find and label events within
your timetable. For more information about that workflow, see “Find Events in Timetable Using Event
Table” on page 10-94.)
By definition, a day is 86,400 seconds long, where the second has a precise definition in the
International System of Units (SI). However, the length of a day actually varies due to several
physical causes. It varies with the seasons by as much as 30 seconds over and 21 seconds under the
SI definition because of the eccentricity of Earth's orbit and the tilt of its axis. Averaging these
seasonal effects enables the definition of the mean solar day, which does not vary in length over a
year.
Also, there is a very long-term slowing in the rotational speed of the Earth due to tidal interaction
with the moon; a smaller, opposite, shorter-term component believed to be due to melting of
continental ice sheets; very short-term cycles on the order of decades; and unpredictable fluctuations
due to geological events and other causes. Because of those effects, the length of a mean solar day
might increase or decrease. In recent decades, it has fluctuated up and down, but has mostly been 1–
3 milliseconds longer than 86,400 seconds. That difference is known as the excess Length of Day, or
excess LOD.
For this example, create a timetable that contains the excess LOD for every day from January 1, 1962,
to the present. The International Earth Rotation and Reference Systems Service (IERS) collects and
publishes this data. However, this data needs preprocessing before storing in a MATLAB timetable
because the dates are modified Julian dates. To read the IERS data into a table, use the readtable
function. Rename the two variables of interest to MJD and ExcessLOD.
file = "https://datacenter.iers.org/data/latestVersion/223_EOP_C04_14.62-NOW.IAU1980223.txt";
IERSdata = readtable(file,NumHeaderLines=14);
IERSdata.Properties.VariableNames([4 8]) = ["MJD","ExcessLOD"];
To store the excess LOD values in a timetable, convert the modified Julian dates to datetime values.
Use the datetime function with the ConvertFrom="mjd" name-value argument. Convert the excess
LOD values to duration values by using the seconds function. Then convert IERSdata from a table
to a timetable using the table2timetable function.
10-77
10 Timetables
IERSdata.Date = datetime(IERSdata.MJD,ConvertFrom="mjd");
IERSdata.ExcessLOD = seconds(IERSdata.ExcessLOD);
IERSdata = table2timetable(IERSdata(:,["Date","ExcessLOD"]))
IERSdata=22458×1 timetable
Date ExcessLOD
___________ ____________
01-Jan-1962 0.001723 sec
02-Jan-1962 0.001669 sec
03-Jan-1962 0.001582 sec
04-Jan-1962 0.001496 sec
05-Jan-1962 0.001416 sec
06-Jan-1962 0.001382 sec
07-Jan-1962 0.001413 sec
08-Jan-1962 0.001505 sec
09-Jan-1962 0.001628 sec
10-Jan-1962 0.001738 sec
11-Jan-1962 0.001794 sec
12-Jan-1962 0.001774 sec
13-Jan-1962 0.001667 sec
14-Jan-1962 0.00151 sec
15-Jan-1962 0.001312 sec
16-Jan-1962 0.001112 sec
⋮
Plot the excess LOD as a function of time. The excess LOD is currently decreasing on average but has
remained positive except during very brief periods.
plot(IERSdata.Date,IERSdata.ExcessLOD,"b-");
xlabel("Date");
ylabel("Excess LOD");
10-78
Add Event Table from External Data to Timetable
A clock that defines a day as 86,400 SI seconds is effectively running fast with respect to the Earth's
rotation, gaining time with respect to the sun each day. A few extra milliseconds per day might seem
unimportant, but the excess LOD since 1962 accumulates.
Add the cumulative excess LOD to IERSdata as another table variable. To calculate the cumulative
sum of the excess LOD, use the cumsum function. Then use the stackedplot function to plot excess
LOD and cumulative excess LOD together. This plot shows that the shift due to the accumulated
excess LOD since the 1960s has been less than one minute.
10-79
10 Timetables
At midnight on January 1, 1972, the current version of the system of time known as Coordinated
Universal Time (UTC) was enacted, which uses 86,400 SI seconds per day. On that date, UTC was
defined to be roughly in sync with solar time at the Greenwich Meridian, or more precisely, with the
time known as UT1. However, timekeeping based on exactly 86,400 SI seconds per day would drift
away from our physical experience of solar time because of accumulated excess LOD. So, when
needed, an extra leap second adjustment is inserted to keep UTC approximately in sync with solar
time. Without these leap second adjustments after 1972, accumulated excess LOD would have caused
UTC to drift away from UT1 over the years. Within decades, the difference would have grown to tens
of seconds.
Show the difference since 1972. First, select the post-1971 excess LOD data by subscripting into
IERSdata with a time range starting on January 1, 1972. To create that time range, use the
timerange function.
IERSdata1972 = IERSdata(timerange("1972-01-01",Inf),"ExcessLOD")
IERSdata1972=18806×1 timetable
Date ExcessLOD
___________ ____________
01-Jan-1972 0.002539 sec
02-Jan-1972 0.002708 sec
03-Jan-1972 0.002897 sec
04-Jan-1972 0.003065 sec
05-Jan-1972 0.003177 sec
06-Jan-1972 0.00322 sec
10-80
Add Event Table from External Data to Timetable
Add another variable with the unadjusted difference since 1972. Start with the cumulative excess
LOD on January 1, 1972, which was 0.0454859 second. For every date that follows, calculate the
unadjusted difference. By the beginning of 2017, the unadjusted difference would have grown to
about 26 seconds. Display IERSdata1972 using a time range that includes the start of 2017.
DiffUT1_1972 = seconds(0.0454859);
IERSdata1972.UnadjustedDiff = DiffUT1_1972 + [0; cumsum(IERSdata1972.ExcessLOD(1:end-1))];
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×2 timetable
Date ExcessLOD UnadjustedDiff
___________ _____________ ______________
29-Dec-2016 0.0008055 sec 26.402 sec
30-Dec-2016 0.0008525 sec 26.402 sec
31-Dec-2016 0.0009173 sec 26.403 sec
01-Jan-2017 0.001016 sec 26.404 sec
02-Jan-2017 0.0011845 sec 26.405 sec
03-Jan-2017 0.0013554 sec 26.406 sec
This drift is what leap seconds are designed to mitigate. You can think of each leap second that is
inserted into the UTC timeline as an event. These events are not part of the LOD data. However, in
MATLAB the leapseconds function lists each leap second that has occurred since 1972. (The leap
seconds listed by leapseconds come from another data set provided by the IERS.) The timetable
returned by leapseconds contains a timestamp, a description of each event (+ for leap second
insertions, - for removals), and the cumulative number of leap seconds up to and including the event.
To date, there have been 27 leap second events, and they have all been insertions.
lsEvents = leapseconds()
lsEvents=27×2 timetable
Date Type CumulativeAdjustment
___________ ____ ____________________
30-Jun-1972 + 1 sec
31-Dec-1972 + 2 sec
31-Dec-1973 + 3 sec
31-Dec-1974 + 4 sec
31-Dec-1975 + 5 sec
31-Dec-1976 + 6 sec
31-Dec-1977 + 7 sec
31-Dec-1978 + 8 sec
31-Dec-1979 + 9 sec
30-Jun-1981 + 10 sec
30-Jun-1982 + 11 sec
30-Jun-1983 + 12 sec
10-81
10 Timetables
30-Jun-1985 + 13 sec
31-Dec-1987 + 14 sec
31-Dec-1989 + 15 sec
31-Dec-1990 + 16 sec
⋮
To treat the leap seconds as events, convert lsEvents to an event table by using the eventtable
function.
lsEvents = eventtable(lsEvents)
At this point, the main LOD data is in the IERSdata1972 timetable. The leap second events are in
the lsEvents event table. To find and label rows that occur during leap seconds in the LOD data,
attach lsEvents to IERSdata1972. Assign lsEvents to its Events property.
IERSdata1972.Properties.Events = lsEvents;
IERSdata1972.Properties
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Date' 'Variables'}
VariableNames: {'ExcessLOD' 'UnadjustedDiff'}
10-82
Add Event Table from External Data to Timetable
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [18806×1 datetime]
StartTime: 01-Jan-1972
SampleRate: NaN
TimeStep: 1d
Events: [27×2 eventtable]
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
Add the unadjusted difference, or cumulative excess LOD, at each date in lsEvents. To find the
unadjusted differences on these dates, index into the UnadjustedDiff variable of IERSdata1972
and select the unadjusted difference at the timestamps from lsEvents. Then append those
differences to each event in lsEvents as additional information about the event.
First, create an event filter using the eventfilter function. It uses the event table attached to a
timetable to create a row subscript. You can use subscript into timetables rows using matching values
from the event table. Subscript into IERSdata1972 and return an array of unadjusted differences on
the dates when leap seconds were added.
EF = eventfilter(IERSdata1972)
EF =
eventfilter with no constraints and no selected variables
<unconstrained>
UnadjustedDiff = IERSdata1972{EF.Date,"UnadjustedDiff"}
10-83
10 Timetables
22.659 sec
23.589 sec
24.583 sec
25.671 sec
26.403 sec
Add the array as a new variable to the event table. In this way, you can add more information about
events after you have attached an event table to a timetable.
IERSdata1972.Properties.Events.UnadjustedDiff = UnadjustedDiff
IERSdata1972=18806×2 timetable
Date ExcessLOD UnadjustedDiff
___________ ____________ ______________
01-Jan-1972 0.002539 sec 0.045486 sec
02-Jan-1972 0.002708 sec 0.048025 sec
03-Jan-1972 0.002897 sec 0.050733 sec
04-Jan-1972 0.003065 sec 0.05363 sec
05-Jan-1972 0.003177 sec 0.056695 sec
06-Jan-1972 0.00322 sec 0.059872 sec
07-Jan-1972 0.003201 sec 0.063092 sec
08-Jan-1972 0.003137 sec 0.066293 sec
09-Jan-1972 0.003033 sec 0.06943 sec
10-Jan-1972 0.002898 sec 0.072463 sec
11-Jan-1972 0.002772 sec 0.075361 sec
12-Jan-1972 0.002672 sec 0.078133 sec
13-Jan-1972 0.002621 sec 0.080805 sec
14-Jan-1972 0.002642 sec 0.083426 sec
15-Jan-1972 0.00274 sec 0.086068 sec
16-Jan-1972 0.002937 sec 0.088808 sec
⋮
The event table shows that at each event, the IERS inserted a leap second whenever the excess LOD
accumulated by roughly one additional second. To confirm this observation visually, plot the LOD data
overlaid with the instantaneous leap second events. Use the stackedplot function. If the input is a
timetable with an attached event table, then stackedplot automatically plots events from the event
table on top of the data from the timetable. It plots instantaneous events as vertical lines.
stackedplot(IERSdata1972)
10-84
Add Event Table from External Data to Timetable
The stackedplot function plots all events using the same default style. To plot events using
different styles, use the plot function and specify colors, markers, line styles, and so on. For
example, plot the leap second events on the unadjusted differences using red crosses instead of
vertical lines.
plot(IERSdata1972,"UnadjustedDiff");
hold on
plot(lsEvents.Date,IERSdata1972.UnadjustedDiff(lsEvents.Date),"r+");
hold off
10-85
10 Timetables
The leap seconds are instantaneous events recorded in an event table. Another way to represent
them is by using a state variable appended to the original LOD data. A state variable describes the
"state" of the process being measured at each time point rather than tagging a specific instant. One
possible state variable for this leap second data is an indicator variable that records an adjustment on
each event date, with missing values on all the other dates. This approach works because all
timestamps from the event table are also timestamps in IERSdata1972.
To copy the cumulative adjustments from the attached event table to the timetable, use the
syncevents function. The function automatically fills the other elements of the new
CumulativeAdjustment variable with missing values. Display the timetable rows around the 27th
leap second.
IERSdata1972 = syncevents(IERSdata1972,EventDataVariables="CumulativeAdjustment");
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×3 timetable
Date ExcessLOD UnadjustedDiff CumulativeAdjustment
___________ _____________ ______________ ____________________
29-Dec-2016 0.0008055 sec 26.402 sec NaN sec
30-Dec-2016 0.0008525 sec 26.402 sec NaN sec
<1 event> 31-Dec-2016 0.0009173 sec 26.403 sec 27 sec
01-Jan-2017 0.001016 sec 26.404 sec NaN sec
02-Jan-2017 0.0011845 sec 26.405 sec NaN sec
03-Jan-2017 0.0013554 sec 26.406 sec NaN sec
10-86
Add Event Table from External Data to Timetable
Another possibility, more useful in this example, is to add a state variable that indicates the
cumulative sum of leap seconds at any given date in the LOD data. Begin by removing the
CumulativeAdjustment variable from the timetable.
Then assign the attached event table to local variable in the workspace.
lsEvents = IERSdata1972.Properties.Events;
The data in IERSdata1972 begin on January 1, 1972, before the first leap second was added. So, add
one more event to lsEvents, to cover the time before the first leap second.
lsEvents(IERSdata1972.Date(1),:) = {"+",seconds(0),seconds(0)};
lsEvents = sortrows(lsEvents)
Add event end times to transform the events into interval events. The end of each interval is the day
before the next leap second was added. The last event end time is the last date in IERSdata1972.
Add the event end times to lsEvents as a new variable. Then assign the new variable to the
EventEndsVariable property of lsEvents. Event tables have properties that specify which of their
variables contain event labels, event lengths, or event end times.
10-87
10 Timetables
lsEvents.EventEnds = endEvents;
lsEvents.Properties.EventEndsVariable = "EventEnds"
Copy the cumulative adjustments by calling syncevents. The attached event table has interval
events, so syncevents fills in every row of IERSdata1972 with event data that occurs during the
intervals. Every row of IERSdata1972 records the cumulative adjustment that occurred up to that
time.
IERSdata1972 = syncevents(IERSdata1972,EventDataVariables="CumulativeAdjustment");
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×3 timetable
Date ExcessLOD UnadjustedDiff CumulativeAdjustment
___________ _____________ ______________ ____________________
<1 event> 29-Dec-2016 0.0008055 sec 26.402 sec 26 sec
30-Dec-2016 0.0008525 sec 26.402 sec NaN sec
<1 event> 31-Dec-2016 0.0009173 sec 26.403 sec 27 sec
<1 event> 01-Jan-2017 0.001016 sec 26.404 sec 27 sec
<1 event> 02-Jan-2017 0.0011845 sec 26.405 sec 27 sec
<1 event> 03-Jan-2017 0.0013554 sec 26.406 sec 27 sec
10-88
Add Event Table from External Data to Timetable
The new state variable is just like all the other variables in IERSdata1972, with a value that is
defined at each time. You can use it to compute the actual differences between UTC and UT1, given
all the leap second adjustments, by subtracting it from the unadjusted difference. The convention is
to compute the actual difference with the opposite sign as UT1 – UTC and denote it as DUT1.
ans=6×4 timetable
Date ExcessLOD UnadjustedDiff CumulativeAdjustment DU
___________ _____________ ______________ ____________________ ______
<1 event> 29-Dec-2016 0.0008055 sec 26.402 sec 26 sec 0.401
30-Dec-2016 0.0008525 sec 26.402 sec NaN sec N
<1 event> 31-Dec-2016 0.0009173 sec 26.403 sec 27 sec -0.596
<1 event> 01-Jan-2017 0.001016 sec 26.404 sec 27 sec -0.595
<1 event> 02-Jan-2017 0.0011845 sec 26.405 sec 27 sec -0.594
<1 event> 03-Jan-2017 0.0013554 sec 26.406 sec 27 sec -0.593
The IERS makes leap second adjustments to keep UTC roughly in sync with UT1. To show how this
adjustment works, plot the CumulativeAdjustment state variable as a piecewise-constant step
function over time. The step function approximates the accumulated excess LOD, so subtracting it
keeps DUT1 small. For visual confirmation, plot DUT1 along the same time axis by using the
stackedplot function. Plot UnadjustedDiff and CumulativeAdjustment together along one y-
axis, with a legend, and plot DUT1 along a second y-axis. Because the events in the attached event
table were converted to interval events that cover the entire time range, it is redundant to plot
events. So, specify the EventsVisible name-value argument as "off".
stackedplot(IERSdata1972,{["UnadjustedDiff","CumulativeAdjustment"],"DUT1"},EventsVisible="off")
10-89
10 Timetables
The two representations, a separate list of events and a state variable defined at all times, are
conceptually different. In some cases, there might not be a useful definition of a "state" that
corresponds to the periods between instantaneous events. But when there is, the two representations
are equivalent and useful in similar ways. For example, to select all the data after the 22nd leap
second but before the 23rd, you can use an event filter and timerange.
EF = eventfilter(IERSdata1972)
EF =
eventfilter with no constraints and no selected variables
<unconstrained>
data22to23=2557×4 timetable
Date ExcessLOD UnadjustedDiff CumulativeAdjustment DU
___________ _____________ ______________ ____________________ ______
<1 event> 31-Dec-1998 0.0010954 sec 21.282 sec 22 sec -0.718
<1 event> 01-Jan-1999 0.0009738 sec 21.283 sec 22 sec -0.717
<1 event> 02-Jan-1999 0.000888 sec 21.284 sec 22 sec -0.716
<1 event> 03-Jan-1999 0.0008605 sec 21.285 sec 22 sec -0.715
10-90
Add Event Table from External Data to Timetable
As an alternative, you can create a logical subscript from the state variable that selects the same
data.
data22to23=2556×4 timetable
Date ExcessLOD UnadjustedDiff CumulativeAdjustment DU
___________ _____________ ______________ ____________________ ______
<1 event> 31-Dec-1998 0.0010954 sec 21.282 sec 22 sec -0.718
<1 event> 01-Jan-1999 0.0009738 sec 21.283 sec 22 sec -0.717
<1 event> 02-Jan-1999 0.000888 sec 21.284 sec 22 sec -0.716
<1 event> 03-Jan-1999 0.0008605 sec 21.285 sec 22 sec -0.715
<1 event> 04-Jan-1999 0.0008798 sec 21.286 sec 22 sec -0.714
<1 event> 05-Jan-1999 0.0008935 sec 21.287 sec 22 sec -0.713
<1 event> 06-Jan-1999 0.0009693 sec 21.287 sec 22 sec -0.712
<1 event> 07-Jan-1999 0.0010658 sec 21.288 sec 22 sec -0.711
<1 event> 08-Jan-1999 0.0010857 sec 21.29 sec 22 sec -0.710
<1 event> 09-Jan-1999 0.0010715 sec 21.291 sec 22 sec -0.70
<1 event> 10-Jan-1999 0.0010519 sec 21.292 sec 22 sec -0.708
<1 event> 11-Jan-1999 0.0010021 sec 21.293 sec 22 sec -0.707
<1 event> 12-Jan-1999 0.0008986 sec 21.294 sec 22 sec -0.706
<1 event> 13-Jan-1999 0.0007891 sec 21.295 sec 22 sec -0.705
<1 event> 14-Jan-1999 0.0007236 sec 21.295 sec 22 sec -0.704
<1 event> 15-Jan-1999 0.0006842 sec 21.296 sec 22 sec -0.703
⋮
Both representations have their uses. For example, while each event can be plotted as a point, the
state variable is the more convenient form for highlighting regions between events in a plot. To
highlight the region between the 22nd and 23rd leap second, use the from22to23 logical subscript
created from CumulativeAdjustment.
plot(IERSdata1972,"UnadjustedDiff");
hold on
plot(IERSdata1972(from22to23,:),"UnadjustedDiff",Color="r",LineWidth=4);
hold off
10-91
10 Timetables
You can switch between the two representations. In this case, to get the leap second event dates from
CumulativeAdjustment, find the locations where the adjustment changes, and subtract one day.
The eventTimes output represents the dates on which leap seconds were added, which are
instantaneous events.
10-92
Add Event Table from External Data to Timetable
30-Jun-1981
29-Jun-1982
30-Jun-1982
29-Jun-1983
30-Jun-1983
29-Jun-1985
30-Jun-1985
30-Dec-1987
31-Dec-1987
30-Dec-1989
31-Dec-1989
⋮
To represent events, you can use event tables, with either instantaneous events or interval events, or
state variables in timetables. The representation you use depends on which one is more convenient
and useful for the data analysis that you plan to conduct. You might even switch between
representations as you go. All these representations are useful ways to add information about events
to your timestamped data in a timetable.
See Also
eventtable | timetable | datetime | seconds | leapseconds | timerange | stackedplot |
readtable | table2timetable | cumsum
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Select Times in Timetable” on page 10-24
• “Find Events in Timetable Using Event Table” on page 10-94
10-93
10 Timetables
To find and label events in a timetable, attach an eventtable to it. An event table is a timetable of
events. An event consists of an event time (when something happened), often an event length or
event end time (how long it happened), often an event label (what happened), and sometimes
additional information about the event. When you attach an event table to a timetable, it enables you
to find and label rows in the timetable that occur during events. By associating timetable rows with
events, you can more easily analyze and plot the data that they contain.
This example shows how you can define events in data using information that is already within your
timetable. In the example, import a timetable of measurements of the Earth's rotation rate from 1962
to the present. The rotation rate varies as a function of time, causing changes in the excess length-of-
day to accumulate. When you plot the excess length-of-day as a function of time, the peaks and
troughs in the plot represent events in this data set. To analyze these data with event tables, use the
extractevents, eventfilter, and syncevents functions. (A related workflow is to add events
from an external data source to your timetable. For more information about that workflow, see “Add
Event Table from External Data to Timetable” on page 10-77.)
By definition, a day is 86,400 seconds long, where the second has a precise definition in the
International System of Units (SI). However, the length of a day actually varies due to several
physical causes. It varies with the seasons by as much as 30 seconds over and 21 seconds under the
SI definition because of the eccentricity of Earth's orbit and the tilt of its axis. Averaging these
seasonal effects enables the definition of the mean solar day, which does not vary in length over a
year.
Also, there is a very long-term slowing in the rotational speed of the Earth due to tidal interaction
with the moon; a smaller, opposite, shorter-term component believed to be due to melting of
continental ice sheets; very short-term cycles on the order of decades; and unpredictable fluctuations
due to geological events and other causes. Because of those effects, the length of a mean solar day
might increase or decrease. In recent decades, it has fluctuated up and down, but has mostly been 1–
3 milliseconds longer than 86,400 seconds. That difference is known as the excess Length of Day, or
excess LOD.
For this example, create a timetable that contains the excess LOD for every day from January 1, 1962,
to the present. The International Earth Rotation and Reference Systems Service (IERS) collects and
publishes this data. However, this data needs preprocessing before storing in a MATLAB timetable
because the dates are modified Julian dates. To read the IERS data into a table, use the readtable
function. Rename the two variables of interest to MJD and ExcessLOD.
file = "https://datacenter.iers.org/data/latestVersion/223_EOP_C04_14.62-NOW.IAU1980223.txt";
IERSdata = readtable(file,"NumHeaderLines",14);
IERSdata.Properties.VariableNames([4 8]) = ["MJD","ExcessLOD"];
To store the excess LOD values in a timetable, convert the modified Julian dates to datetime values.
Use the datetime function with the "ConvertFrom","mjd" name-value argument. Then convert
IERSdata from a table to a timetable using the table2timetable function.
IERSdata.Date = datetime(IERSdata.MJD,"ConvertFrom","mjd");
IERSdata.ExcessLOD = seconds(IERSdata.ExcessLOD);
IERSdata = table2timetable(IERSdata(:,["Date","ExcessLOD"]))
10-94
Find Events in Timetable Using Event Table
IERSdata=22458×1 timetable
Date ExcessLOD
___________ ____________
Plot the excess LOD as a function of time. When the input is a timetable, the plot function
automatically plots the timetable variables that you specify against the row times.
plot(IERSdata,"ExcessLOD")
10-95
10 Timetables
Since the 1960s there have been several periods when the excess LOD decreased over the short
term. If you smooth the excess LOD data, you can see this local behavior more easily.
To smooth the excess LOD, use the smoothdata function. Then plot the smoothed data and the
excess LOD using the stackedplot function. It creates a plot of every variable in a timetable and
stacks the plots.
IERSdata.SmoothedELOD = smoothdata(seconds(IERSdata.ExcessLOD),"loess","SmoothingFactor",.4);
stackedplot(IERSdata)
The peaks and troughs of the smoothed data show where the short-term trend changed direction.
After reaching a peak, the excess LOD decreases. After reaching a trough, the excess LOD increases.
The peaks and troughs are notable events in this data set.
To identify the peaks and troughs in the smoothed data, use the islocalmax and islocalmin
functions. Then get the date and the value of the excess LOD for each peak and trough. Create a
categorical array with two types, peak and trough, which describe these two types of events.
peaks = find(islocalmax(IERSdata.SmoothedELOD));
troughs = find(islocalmin(IERSdata.SmoothedELOD));
typeLabels = categorical([zeros(size(peaks)); ones(size(troughs))],[0 1],["peak","trough"]);
Store the peaks and troughs in an event table. To extract the times of the peaks and troughs from
IERSdata, use the extractevents function. These times are the event times of the event table. The
10-96
Find Events in Timetable Using Event Table
values in typeLabels are the event labels for these events. You can consider the peaks and troughs
to be instantaneous events because they occur on specific dates in the timetable.
extremaEvents = extractevents(IERSdata,[peaks;troughs],EventLabels=typeLabels)
Date EventLabels
___________ ___________
08-Jul-1972 peak
26-Jun-1977 peak
14-Oct-1993 peak
18-Feb-2008 peak
16-Dec-2015 peak
10-Aug-1975 trough
07-Jan-1987 trough
02-Nov-2003 trough
09-Jul-2010 trough
12-Sep-2022 trough
Attach the new event table to the Events property of IERSdata. To find and label events using an
event table, you must first attach it to a timetable. While this timetable has over 22,000 rows, the
attached event table identifies nine events that occur within the time spanned by the timetable.
IERSdata.Properties.Events = extremaEvents;
IERSdata.Properties
ans =
TimetableProperties with properties:
Description: ''
UserData: []
DimensionNames: {'Date' 'Variables'}
VariableNames: {'ExcessLOD' 'SmoothedELOD'}
VariableDescriptions: {}
VariableUnits: {}
VariableContinuity: []
RowTimes: [22458×1 datetime]
StartTime: 01-Jan-1962
SampleRate: NaN
TimeStep: 1d
Events: [10×1 eventtable]
CustomProperties: No custom properties are set.
Use addprop and rmprop to modify CustomProperties.
One way to plot the events is to use the stackedplot function. If the input timetable has an
attached event table, then stackedplot plots the events on the stacked plot. It plots instantaneous
events as vertical lines and interval events as shaded regions.
10-97
10 Timetables
stackedplot(IERSdata)
The stackedplot function plots all events using the same style. To plot events using different styles
for different kinds of events, use the plot function and specify markers for different events.
For example, make a plot where you mark the peaks using triangles pointed upward and troughs
using triangles pointed downward. Start by using the plot function to plot the excess LOD. Then
overplot the smoothed excess LOD as a green curve.
plot(IERSdata.Date,IERSdata.ExcessLOD,"b-");
hold on
plot(IERSdata.Date,IERSdata.SmoothedELOD,"g-","LineWidth",2);
hold off
ylabel("Excess LOD");
10-98
Find Events in Timetable Using Event Table
Next, find the row times that correspond to the peaks and troughs. A convenient way to select the
times of these events is to use an eventfilter.
Create an event filter from the event table attached to IERSdata, by using the eventfilter
function. You can use the event filter as a row subscript to select rows that occur at events.
EF = eventfilter(IERSdata)
EF =
eventfilter with no constraints and no selected variables
<unconstrained>
Subscript into IERSdata to show the rows that occur at peaks of the smoothed excess LOD.
IERSdataPeaks = IERSdata(EF.EventLabels == "peak",:)
IERSdataPeaks=5×2 timetable
Date ExcessLOD SmoothedELOD
___________ _____________ ____________
10-99
10 Timetables
Show the rows that occur at troughs of the smoothed excess LOD.
IERSdataTroughs = IERSdata(EF.EventLabels == "trough",:)
IERSdataTroughs=5×2 timetable
Date ExcessLOD SmoothedELOD
___________ ______________ ____________
Plot the peaks using triangles pointed upward and the troughs using triangles pointed downward.
hold on
hpeaks = plot(IERSdataPeaks,"SmoothedELOD",LineStyle="none",Marker="^",MarkerFaceColor="y");
htroughs = plot(IERSdataTroughs,"SmoothedELOD",LineStyle="none",Marker="v",MarkerFaceColor="y");
hold off
From peak to trough, the excess LOD decreases, meaning that the Earth's rotation speeds up during
that interval. From trough to peak, the excess LOD increases, meaning that the rotation slows down.
10-100
Find Events in Timetable Using Event Table
You can consider these periods of decreasing and increasing excess LOD to be interval events. These
events persist over significant lengths of time within the excess LOD data set.
Change the event table into an event table that stores interval events. First, assign the attached event
table to a more convenient local variable. Then sort it by the event times.
intervalEvents = IERSdata.Properties.Events;
intervalEvents = sortrows(intervalEvents)
Date EventLabels
___________ ___________
08-Jul-1972 peak
10-Aug-1975 trough
26-Jun-1977 peak
07-Jan-1987 trough
14-Oct-1993 peak
02-Nov-2003 trough
18-Feb-2008 peak
09-Jul-2010 trough
16-Dec-2015 peak
12-Sep-2022 trough
To turn the events into interval events, assign event end times to them. In this data set, the end of
every interval is the day before the start of the next interval. (However, let the "end" of the last
interval be the last date in IERSdata.) Assign the event end times as a new variable in
intervalEvents. Then assign the new variable to the EventEndsVariable property of the event
table. This assignment turns the events into interval events.
10-101
10 Timetables
The labels "peaks" and "troughs" were appropriate labels for instantaneous events because they
identified inflection points on the smoothed excess LOD curve. But they are not appropriate labels for
interval events. Change the labels to "decreasingLOD" and "increasingLOD".
intervalEvents.EventLabels = renamecats(intervalEvents.EventLabels,["decreasingLOD","increasingLO
The first interval starts with the first peak. However, IERSdata has earlier rows leading up to that
peak. To add that period as an interval of increasing excess LOD, add another row to the event table.
Its event time is the first date in IERSdata. Its event end time is the day before the first peak.
You can add more data that describes these events in additional event table variables. For example,
compute the average change in excess LOD during each interval (in units of seconds of daily excess
LOD per year). Add that information to the interval events as a new variable.
10-102
Find Events in Timetable Using Event Table
These results show that the mean solar day, averaged over an entire year, has been decreasing over
the last few years by about 0.3 milliseconds per year. The mean solar day is currently near or even
slightly less than 86,400 seconds. However, many experts believe that this trend will not continue.
Create a simple stacked plot of the intervals when the excess LOD was increasing. First, create a
subtable of intervalEvents with increasing excess LOD.
Attach increasingEvents to the Events property of IERSdata. Then make a stacked plot that
shows only the intervals with increasing excess LOD as shaded regions.
IERSdata.Properties.Events = increasingEvents;
stackedplot(IERSdata)
10-103
10 Timetables
To work with intervals of decreasing and increasing excess LOD, attach intervalEvents to the
Events property of IERSdata. You can convert the interval events to a state variable, and make
more complex plots of the events associated with these data.
IERSdata.Properties.Events = intervalEvents;
The event table records interval events during which the smoothed excess LOD reached a peak and
began a decrease or reached a trough and began an increase. Another way to represent those
changes is as a state variable within the timetable itself. To copy event data from an attached event
table to variables of the main timetable, use the syncevents function. As a result of this call,
IERSdata has new variables, EventLabels and AnnualAvgChange, copied from the attached event
table.
IERSdata = syncevents(IERSdata)
IERSdata=22458×4 timetable
Date ExcessLOD SmoothedELOD EventLabels AnnualAvgCha
___________ ____________ ____________ _____________ ____________
10-104
Find Events in Timetable Using Event Table
Next, highlight the segments in the plot where excess LOD is increasing in green and decreasing in
red. In this case, it is more convenient to use the EventLabels state variable in IERSdata because
you need to change the color at every data point in each segment.
plot(IERSdata.Date,IERSdata.ExcessLOD,"b-");
hold on
plot(IERSdata.Date,IERSdata.SmoothedELOD,"g-","LineWidth",2);
ylabel("Excess LOD");
decreasing = (IERSdata.EventLabels == "decreasingLOD");
plot(IERSdata.Date(decreasing),IERSdata.SmoothedELOD(decreasing),'r.');
hold off
10-105
10 Timetables
Alternatively, highlight the background in regions of decreasing excess LOD. In this case, it is more
convenient to use the interval events from the attached event table, because you only need the start
and end times of the intervals when excess LOD decreases.
hold on
decreasingEvents = IERSdata.Properties.Events;
decreasingEvents = decreasingEvents(decreasingEvents.EventLabels == "decreasingLOD",:);
startEndTimes = [decreasingEvents.Date decreasingEvents.EventEnds];
h = fill(startEndTimes(:,[1 2 2 1]),[-.002 -.002 .005 .005],"red","FaceAlpha",.2,"LineStyle","non
hold off
The excess LOD has both increased and decreased since the 1960s. Indeed, in many years there were
short periods when the raw excess LOD was significantly negative. These are only very short-term
fluctuations, but during those periods the Earth was rotating one millisecond or more faster than
86,400 SI seconds.
plot(IERSdata.Date,IERSdata.ExcessLOD,"b-");
ylabel("Excess LOD");
hold on
line(IERSdata.Date([1 end]),[0 0],"Color","k","LineStyle",":")
hold off
ylabel("Excess LOD");
10-106
Find Events in Timetable Using Event Table
Identify the dates on which the excess LOD was negative. Extract those dates and the excess LODs
into an event table. As there are over 1400 rows, display the first few rows of the event table.
Date ExcessLOD
___________ _____________
Identify the years in which those days of excess LOD occurred. Then use the retime function to find
the minimum excess LOD in each of those years and return a new event table. (Because an event
table is a kind of timetable, you can call timetable functions on event tables.) These are interval
events in one sense but are stored as instantaneous events marked only by their year.
negYears = unique(dateshift(negLOD.Date,"start","year"));
negYears.Format = "uuuu";
10-107
10 Timetables
negLODEvents = retime(negLOD,negYears,"min");
negLODEvents.Properties.VariableNames = "MinExcessLOD"
Date MinExcessLOD
____ ______________
In the plot of excess LOD, mark the time axis red for each year that had periods when the excess LOD
was negative. In this data set, such years happen more frequently after the year 2000.
hold on
plot([negLODEvents.Date negLODEvents.Date+calyears(1)],[-.0016 -.0016],"r-","lineWidth",6);
ylim(seconds([-.0016 .0045]));
hold off
10-108
Find Events in Timetable Using Event Table
To represent events, you can use event tables, with either instantaneous events or interval events, or
state variables in timetables. The representation you use depends on which one is more convenient
and useful for the data analysis that you plan to conduct. You might even switch between
representations as you go. All these representations are useful ways to add information about events
to your timestamped data in a timetable.
See Also
eventtable | timetable | datetime | retime | smoothdata | islocalmax | islocalmin |
seconds | timerange | stackedplot | readtable | table2timetable
Related Examples
• “Represent Dates and Times in MATLAB” on page 7-2
• “Resample and Aggregate Data in Timetable” on page 10-10
• “Clean Timetable with Missing, Duplicate, or Nonuniform Times” on page 10-32
• “Data Cleaning and Calculations in Tables” on page 9-93
• “Grouped Calculations in Tables and Timetables” on page 9-113
• “Select Times in Timetable” on page 10-24
• “Add Event Table from External Data to Timetable” on page 10-77
10-109
11
Structures
Structure Arrays
When you have data that you want to organize by name, you can use structures to store it. Structures
store data in containers called fields, which you can then access by the names you specify. Use dot
notation to create, assign, and access data in structure fields. If the value stored in a field is an array,
then you can use array indexing to access elements of the array. When you store multiple structures
as a structure array, you can use array indexing and dot notation to access individual structures and
their fields.
Use dot notation to add the fields name, billing, and test, assigning data to each field. In this
example, the syntax patient.name creates both the structure and its first field. The commands that
follow add more fields.
patient.name = 'John Doe';
patient.billing = 127;
patient.test = [79 75 73; 180 178 177.5; 220 210 205]
11-2
Structure Arrays
billing: 512
test: [3x3 double]
With dot notation, you also can access the value of any field. For example, make a bar chart of the
values in patient.test. Add a title with the text in patient.name. If a field stores an array, then
this syntax returns the whole array.
bar(patient.test)
title("Test Results for " + patient.name)
To access part of an array stored in a field, add indices that are appropriate for the size and type of
the array. For example, create a bar chart of the data in one column of patient.test.
bar(patient.test(:,1))
11-3
11 Structures
For example, add a second structure to patients having data about a second patient. Also, assign
the original value of 127 to the billing field of the first structure. Since the array now has two
structures, you must access the first structure by indexing, as in patient(1).billing = 127.
As a result, patient is a 1-by-2 structure array with contents shown in the diagram.
11-4
Structure Arrays
Each patient record in the array is a structure of class struct. An array of structures is sometimes
referred to as a struct array. However, the terms struct array and structure array mean the same
thing. Like other MATLAB® arrays, a structure array can have any dimensions.
If you add a new structure to the array without specifying all of its fields, then the unspecified fields
contain empty arrays.
patient(3).name = 'New Name';
patient(3)
To index into a structure array, use array indexing. For example, patient(2) returns the second
structure.
patient(2)
To access a field, use array indexing and dot notation. For example, return the value of the billing
field for the second patient.
11-5
11 Structures
patient(2).billing
ans =
28.5000
You also can index into an array stored by a field. Create a bar chart displaying only the first two
columns of patient(2).test.
bar(patient(2).test(:,[1 2]))
Note You can index into part of a field only when you refer to a single element of a structure array.
MATLAB does not support statements such as patient(1:2).test(1:2,2:3), which attempt to
index into a field for multiple elements of the structure array. Instead, use the arrayfun function.
See Also
struct | fieldnames | isfield
Related Examples
• “Access Elements of a Nonscalar Structure Array” on page 11-13
• “Generate Field Names from Variables” on page 11-10
• “Create Cell Array” on page 12-2
• “Create Tables and Assign Data to Them” on page 9-2
11-6
Structure Arrays
11-7
11 Structures
Concatenate Structures
This example shows how to concatenate structure arrays using the [] operator. To concatenate
structures, they must have the same set of fields, but the fields do not need to contain the same sizes
or types of data.
Create scalar (1-by-1) structure arrays struct1 and struct2, each with fields a and b:
struct1.a = 'first';
struct1.b = [1,2,3];
struct2.a = 'second';
struct2.b = rand(5);
struct1,struct2
Just as concatenating two scalar values such as [1,2] creates a 1-by-2 numeric array, concatenating
struct1 and struct2 creates a 1-by-2 structure array.
combined = [struct1,struct2]
When you want to access the contents of a particular field, specify the index of the structure in the
array. For example, access field a of the first structure.
combined(1).a
ans =
'first'
Concatenation also applies to nonscalar structure arrays. For example, create a 2-by-2 structure
array named new. Because the 1-by-2 structure combined and the 2-by-2 structure new both have
two columns, you can concatenate them vertically with a semicolon separator.
new(1,1).a = 1;
new(1,1).b = 10;
new(1,2).a = 2;
new(1,2).b = 20;
new(2,1).a = 3;
new(2,1).b = 30;
new(2,2).a = 4;
new(2,2).b = 40;
11-8
Concatenate Structures
Access field a of the structure larger(2,1). It contains the same value as new(1,1).a.
larger(2,1).a
ans =
1
See Also
Related Examples
• “Creating, Concatenating, and Expanding Matrices”
• “Structure Arrays” on page 11-2
• “Access Elements of a Nonscalar Structure Array” on page 11-13
11-9
11 Structures
This example shows how to derive a structure field name at run time from a variable or expression.
The general syntax is
structName.(dynamicExpression)
where dynamicExpression is a variable or expression that, when evaluated, returns a string scalar.
Field names that you reference with expressions are called dynamic fieldnames, or sometimes
dynamic field names.
currentDate = datestr(now,'mmmdd');
myStruct.(currentDate) = [1,2,3]
If the current date reported by your system is February 29, then this code assigns data to a field
named Feb29:
myStruct =
Feb29: [1 2 3]
The dynamic field name can return either a character vector or a string scalar. For example, you can
specify the field Feb29 using either single or double quotes.
myStruct.('Feb29')
ans =
1 2 3
myStruct.("Feb29")
ans =
1 2 3
Field names, like variable names, must begin with a letter, can contain letters, digits, or underscore
characters, and are case sensitive. Field names cannot contain periods. To avoid potential conflicts,
do not use the names of existing variables or functions as field names.
See Also
struct | fieldnames | getfield | setfield
Related Examples
• “Variable Names” on page 1-5
• “Structure Arrays” on page 11-2
11-10
Access Data in Nested Structures
structName(index).nestedStructName(index).fieldName(indices)
When a structure is scalar (1-by-1), you do not need to include the indices to refer to the single
element. For example, create a scalar structure s, where field n is a nested scalar structure with
fields a, b, and c:
s.n.a = ones(3);
s.n.b = eye(4);
s.n.c = magic(5);
third_row_b = s.n.b(3,:)
third_row_b =
0 0 1 0
s(1).n(2).a = 2*ones(3);
s(1).n(2).b = 2*eye(4);
s(1).n(2).c = 2*magic(5);
s(2).n(1).a = '1a';
s(2).n(2).a = '2a';
s(2).n(1).b = '1b';
s(2).n(2).b = '2b';
s(2).n(1).c = '1c';
s(2).n(2).c = '2c';
11-11
11 Structures
Access part of the array in field b of the second element in n within the first element of s:
part_two_eye = s(1).n(2).b(1:2,1:2)
part_two_eye =
2 0
0 2
See Also
struct | setfield | getfield
Related Examples
• “Structure Arrays” on page 11-2
• “Ways to Organize Data in Structure Arrays” on page 11-15
11-12
Access Elements of a Nonscalar Structure Array
Although each structure in the array must have the same number of fields and the same field names,
the contents of the fields can be different types and sizes. When you refer to field f for multiple
elements of the structure array, such as
s(1:3).f
or
s.f
MATLAB returns the data from the elements in a comma-separated list, which displays as follows:
ans =
1
ans =
two
ans =
3 3 3
3 3 3
3 3 3
You cannot assign the list to a single variable with the syntax v = s.f because the fields can contain
different types of data. However, you can assign the list items to the same number of variables, such
as
[v1, v2, v3] = s.f;
If all of the fields contain the same type of data and can form a hyperrectangle, you can concatenate
the list items. For example, create a structure nums with scalar numeric values in field f, and
concatenate the data from the fields:
nums(1).f = 1;
nums(2).f = 2;
nums(3).f = 3;
allNums = [nums.f]
11-13
11 Structures
If you want to process each element of an array with the same operation, use the arrayfun function.
For example, count the number of elements in field f of each structure in array s:
The syntax @(x) creates an anonymous function. This code calls the numel function for each element
of array s, such as numel(s(1).f), and returns
numElements =
1 3 9
11-14
Ways to Organize Data in Structure Arrays
Plane organization allows easier access to all values within a field. Element-by-element organization
allows easier access to all information related to a single element or record. The following sections
include an example of each type of organization:
When you create a structure array, MATLAB stores information about each element and field in the
array header. As a result, structures with more elements and fields require more memory than
simpler structures that contain the same data.
Plane Organization
Consider an RGB image with three arrays corresponding to color intensity values.
If you have arrays RED, GREEN, and BLUE in your workspace, then these commands create a scalar
structure named img that uses plane organization:
img.red = RED;
img.green = GREEN;
img.blue = BLUE;
Plane organization allows you to easily extract entire image planes for display, filtering, or other
processing. For example, multiply the red intensity values by 0.9:
11-15
11 Structures
adjustedRed = .9 * img.red;
If you have multiple images, you can add them to the img structure, so that each element
img(1),...,img(n) contains an entire image. For an example that adds elements to a structure,
see the following section.
Element-by-Element Organization
Consider a database with patient information. Each record contains data for the patient’s name, test
results, and billing amount.
Additional patients correspond to new elements in the structure. For example, add an element for a
second patient:
patient(2).name = 'Ann Lane';
patient(2).billing = 28.50;
patient(2).test = [68, 70, 68; 118, 118, 119; 172, 170, 169];
Element-by-element organization supports simple indexing to access data for a particular patient. For
example, find the average of the first patient’s test results, calculating by rows (dimension 2) rather
than by columns:
aveResultsDoe = mean(patient(1).test,2)
See Also
struct
11-16
Ways to Organize Data in Structure Arrays
More About
• “Structure Arrays” on page 11-2
• “Access Elements of a Nonscalar Structure Array” on page 11-13
• “Memory Requirements for Structure Array” on page 11-18
11-17
11 Structures
Preallocate memory for the contents by assigning initial values with the struct function, such as
newStruct(1:25,1:50) = struct('a',ones(20),'b',zeros(30),'c',rand(40));
This code creates and populates a 25-by-50 structure array S with fields a, b, and c.
If you prefer not to assign initial values, you can initialize a structure array by assigning empty arrays
to each field of the last element in the structure array, such as
newStruct(25,50).a = [];
newStruct(25,50).b = [];
newStruct(25,50).c = [];
or, equivalently,
newStruct(25,50) = struct('a',[],'b',[],'c',[]);
However, in this case, MATLAB only allocates memory for the header, and not for the contents of the
array.
11-18
12
Cell Arrays
A cell array can store different types and sizes of data. In the past, cell arrays were recommended for
text and for tabular data of different types, such as data from a spreadsheet. Now, store text data
using a string, " " array, and store tabular data using a table. Use cell arrays for heterogeneous
data that is best referenced by its location within an array.
You can create a cell array in two ways: use the {} operator or use the cell function.
When you have data to put into a cell array, use the cell array construction operator {}.
C = {1,2,3;
'text',rand(5,10,2),{11; 22; 33}}
Like all MATLAB® arrays, cell arrays are rectangular, with the same number of cells in each row. C is
a 2-by-3 cell array.
You also can use the {} operator to create an empty 0-by-0 cell array.
C2 = {}
C2 =
When you want to add values to a cell array over time or in a loop, first create an empty array using
the cell function. This approach preallocates memory for the cell array header. Each cell contains an
empty array [].
C3 = cell(3,4)
To read from or write to specific cells, enclose indices in curly braces. For instance, populate C3 with
arrays of random data. Vary the array size based on its location in the cell array.
for row = 1:3
for col = 1:4
C3{row,col} = rand(row*10,col*10);
end
end
C3
12-2
Create Cell Array
See Also
cell
Related Examples
• “Access Data in Cell Array” on page 12-4
• “Preallocate Memory for Cell Array” on page 12-11
12-3
12 Cell Arrays
Basic Indexing
A cell array is a data type with indexed data containers called cells. Each cell can contain any type of
data. Cell arrays are often used to hold data from a file that has inconsistent formatting, such as
columns that contain both numeric and text data.
C = {'one','two','three';
100,200,rand(3,3)}
Each element is within a cell. If you index into this array using standard parentheses, the result is a
subset of the cell array that includes the cells.
C2 = C(1:2,1:2)
To read or write the contents within a specific cell, enclose the indices in curly braces.
R = C{2,3}
R = 3×3
To replace the contents of multiple cells at the same time, use parentheses to refer to the cells and
curly braces to define an equivalently sized cell array.
C(1,1:2) = {'first','second'}
12-4
Access Data in Cell Array
Most of the data processing functions in MATLAB® operate on a rectangular array with a uniform
data type. Because cell arrays can contain a mix of types and sizes, you sometimes must extract and
combine data from cells before processing that data. This section describes a few common scenarios.
When the entire cell array or a known subset of cells contains text, you can index and pass the cells
directly to any of the text processing functions in MATLAB. For instance, find where the letter t
appears in each element of the first row of C.
ts = strfind(C(1,:),'t')
The two main ways to process numeric data in a cell array are:
• Combine the contents of those cells into a single numeric array, and then process that array.
• Process the individual cells separately.
To combine numeric cells, use the cell2mat function. The arrays in each cell must have compatible
sizes for concatenation. For instance, the first two elements of the second row of C are scalar values.
Combine them into a 1-by-2 numeric vector.
v = cell2mat(C(2,1:2))
v = 1×2
100 200
To process individual cells, you can use the cellfun function. When calling cellfun, specify the
function to apply to each cell. Use the @ symbol to indicate that it is a function and to create a
function handle. For instance, find the length of each of the cells in the second row of C.
len = cellfun(@length,C(2,:))
len = 1×3
1 1 3
When some of the cells contain data that you want to process, but you do not know the exact indices,
you can use one of these options:
• Find all the elements that meet a certain condition using logical indexing, and then process those
elements.
• Check and process cells one at a time with a for- or while-loop.
12-5
12 Cell Arrays
For instance, suppose you want to process only the cells that contain character vectors. To take
advantage of logical indexing, first use the cellfun function with ischar to find those cells.
idx = cellfun(@ischar,C)
1 1 1
0 0 0
Then, use the logical array to index into the cell array, C(idx). The result of the indexing operation is
a column vector, which you can pass to a text processing function, such as strlength.
len = strlength(C(idx))
len = 3×1
5
6
31
The other approach is to use a loop to check and process the contents of each cell. For instance, find
cells that contain the letter t and combine them into a string array by looping through the cells. Track
how many elements the loop adds to the string array in variable n.
n = 0;
for k = 1:numel(C)
if ischar(C{k}) && contains(C{k},"t")
n = n + 1;
txt(n) = string(C{k});
end
end
txt
If you refer to multiple cells using curly brace indexing, MATLAB returns the contents of the cells as a
comma-separated list. For example,
C{1:2,1:2}
is the same as
Because each cell can contain a different type of data, you cannot assign this list to a single variable.
However, you can assign the list to the same number of variables as cells.
[v1,v2,v3,v4] = C{1:2,1:2}
v1 =
'first'
12-6
Access Data in Cell Array
v2 =
100
v3 =
'second'
v4 =
200
If each cell contains the same type of data with compatible sizes, you can create a single variable by
applying the array concatenation operator [] to the comma-separated list.
v = [C{2,1:2}]
v = 1×2
100 200
If the cell contents cannot be concatenated, store results in a new cell array, table, or other
heterogeneous container. For instance, convert the numeric data in the second row of C to a table.
Use the text data in the first row of C for variable names.
t = cell2table(C(2,:),VariableNames=C(1,:))
t=1×3 table
first second longer text in a third location
_____ ______ _______________________________
If a cell contains an array, you can access specific elements within that array using two levels of
indices. First, use curly braces to access the contents of the cell. Then, use the standard indexing
syntax for the type of array in that cell.
For example, C{2,3} returns a 3-by-3 matrix of random numbers. Index with parentheses to extract
the second row of that matrix.
C{2,3}(2,:)
ans = 1×3
If the cell contains a cell array, use curly braces for indexing, and if it contains a structure array, use
dot notation to refer to specific fields. For instance, consider a cell array that contains a 2-by-1 cell
array and a scalar structure with fields f1 and f2.
c = {'A'; ones(3,4)};
s = struct("f1",'B',"f2",ones(5,6));
C = {c,s}
12-7
12 Cell Arrays
Extract the arrays of ones from the nested cell array and structure.
A1 = C{1}{2}
A1 = 3×4
1 1 1 1
1 1 1 1
1 1 1 1
A2 = C{2}.f2
A2 = 5×6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
You can nest any number of cell and structure arrays. Apply the same indexing rules to lower levels in
the hierarchy. For instance, these syntaxes are valid when the referenced cells contain the expected
cell or structure array.
C{1}{2}{3}
C{4}.f1.f2(1)
C{5}.f3.f4{1}
At any indexing level, if you refer to multiple cells, MATLAB returns a comma-separated list. For
details, see Index into Multiple Cells on page 12-6.
See Also
cell | cell2mat | cellfun
Related Examples
• “Add or Delete Cells in Cell Array” on page 12-9
• “Array Indexing”
• “Comma-Separated Lists” on page 2-66
12-8
Add or Delete Cells in Cell Array
Cell arrays follow the same basic rules for expansion, concatenation, and deletion as other types of
MATLAB® arrays. However, you can index into a cell array in two ways: with curly braces {} to
access cell contents or with parentheses () to refer to the cells themselves. Keep this distinction in
mind when you add, delete, or combine cells in a cell array.
Add Cells
A common way to expand a cell array is to concatenate cell arrays vertically or horizontally. Use the
standard square bracket concatenation operator []. Separate elements with semicolons for vertical
concatenation or commas for horizontal concatenation.
C1 = {'one',2};
C2 = {ones(3,3),'four'};
C = [C1; C2]
C_horz = [C1,C2]
Concatenating a cell array and a non-cell array encloses the non-cell array in a single cell. Therefore,
the cell array must be a vector.
A = [1 2 3; 4 5 6];
C3 = [C1,A]
To create separate cells from the non-cell array, you can use num2cell.
C4 = [C,num2cell(A)]
Cell arrays also support scalar expansion. That is, if you assign values to the contents of cells outside
the existing array, the array expands to include them. The expanded array is rectangular, and any
intervening cells contain empty numeric arrays. When assigning the contents of a cell, use curly
braces.
C{3,3} = 9
12-9
12 Cell Arrays
C{end,end+1} = []
To replace the contents of cells, define a cell array using curly braces, and then assign it to an
equivalently sized set of cells using parentheses.
Delete Cells
The syntax for removing rows or columns of a cell array is consistent with other MATLAB arrays. Set
the cells equal to a pair of empty square brackets. For instance, remove the second row of C.
C(2,:) = []
Enclosing indices in curly braces replaces the contents of a cell with an empty array.
C{1,1} = []
Combine Cells
Cells can contain data of any type or size, so combining cells or extracting data from multiple cells at
the same time requires that the data is compatible. For details and examples, see “Access Data in Cell
Array” on page 12-4.
See Also
Related Examples
• “Access Data in Cell Array” on page 12-4
• “Reshaping and Rearranging Arrays”
12-10
Preallocate Memory for Cell Array
Initialize a cell array by calling the cell function, or by assigning to the last element. For example, if
C does not already exist, these statements are equivalent:
C = cell(25,50);
C{25,50} = [];
MATLAB creates the header for a 25-by-50 cell array. However, MATLAB does not allocate any
memory for the contents of each cell.
See Also
cell
Related Examples
• “Reshaping and Rearranging Arrays”
• “How MATLAB Allocates Memory” on page 31-12
12-11
13
Function Handles
In this section...
“What Is a Function Handle?” on page 13-2
“Creating Function Handles” on page 13-2
“Anonymous Functions” on page 13-3
“Arrays of Function Handles” on page 13-4
“Saving and Loading Function Handles” on page 13-4
• Passing a function to another function (often called function functions). For example, passing a
function to integration and optimization functions, such as integral and fzero.
• Specifying callback functions (for example, a callback that responds to a UI event or interacts with
data acquisition hardware).
• Constructing handles to functions defined inline instead of stored in a program file (anonymous
functions).
• Calling local functions from outside the main function.
f = @myfunction;
You call a function using a handle the same way you call the function directly. For example, suppose
that you have a function named computeSquare, defined as:
function y = computeSquare(x)
y = x.^2;
end
Create a handle and call the function to compute the square of four.
f = @computeSquare;
a = 4;
b = f(a)
b =
16
13-2
Create Function Handle
If the function does not require any inputs, then you can call the function with empty parentheses,
such as
h = @ones;
a = h()
a =
a =
@ones
Function handles are variables that you can pass to other functions. For example, calculate the
integral of x2 on the range [0,1].
q = integral(f,0,1);
Function handles store their absolute path, so when you have a valid handle, you can invoke the
function from any location. You do not have to specify the path to the function when creating the
handle, only the function name.
• Name length — Each part of the function name (including package and class names) must be less
than the number specified by namelengthmax. Otherwise, MATLAB truncates the latter part of
the name.
• Scope — The function must be in scope at the time you create the handle. Therefore, the function
must be on the MATLAB path or in the current folder. Or, for handles to local or nested functions,
the function must be in the current file.
• Precedence — When there are multiple functions with the same name, MATLAB uses the same
precedence rules to define function handles as it does to call functions. For more information, see
“Function Precedence Order” on page 20-37.
• Overloading — When a function handle is invoked with one or more arguments, MATLAB
determines the dominant argument. If the dominant argument is an object, MATLAB determines if
the object’s class has a method which overloads the same name as the function handle’s
associated function. If it does, then the object’s method is invoked instead of the associated
function.
Anonymous Functions
You can create handles to anonymous functions. An anonymous function is a one-line expression-
based MATLAB function that does not require a program file. Construct a handle to an anonymous
function by defining the body of the function, anonymous_function, and a comma-separated list of
input arguments to the anonymous function, arglist. The syntax is:
h = @(arglist)anonymous_function
For example, create a handle, sqr, to an anonymous function that computes the square of a number,
and call the anonymous function using its handle.
13-3
13 Function Handles
x =
ans =
-1
ans =
See Also
str2func | func2str | functions | isa | function_handle
Related Examples
• “Pass Function to Another Function” on page 13-5
More About
• “Anonymous Functions” on page 20-20
13-4
Pass Function to Another Function
You can use function handles as input arguments to other functions, which are called function
functions. These functions evaluate mathematical expressions over a range of values. Typical function
functions include integral, quad2d, fzero, and fminbnd.
For example, to find the integral of the natural log from 0 through 5, pass a handle to the log
function to integral.
a = 0;
b = 5;
q1 = integral(@log,a,b)
q1 =
3.0472
Similarly, to find the integral of the sin function and the exp function, pass handles to those
functions to integral.
q2 = integral(@sin,a,b)
q2 =
0.7163
q3 = integral(@exp,a,b)
q3 =
147.4132
Also, you can pass a handle to an anonymous function to function functions. An anonymous function is
a one-line expression-based MATLAB® function that does not require a program file. For example,
evaluate the integral of x/(ex − 1) on the range [0,Inf]:
fun = @(x)x./(exp(x)-1);
q4 = integral(fun,0,Inf)
q4 =
1.6449
Functions that take a function as an input (called function functions) expect that the function
associated with the function handle has a certain number of input variables. For example, if you call
integral or fzero, the function associated with the function handle must have exactly one input
variable. If you call integral3, the function associated with the function handle must have three
input variables. For information on calling function functions with more variables, see
“Parameterizing Functions”.
You can write functions that accept function handles the same way as writing functions to accept
other types of inputs. Write a function that doubles the output of the input function handle for a given
input.
function x = doubleFunction(funHandle,funInput)
x = 2*funHandle(funInput);
end
13-5
13 Function Handles
x = doubleFunction(fun,4)
x =
0.1493
See Also
Related Examples
• “Create Function Handle” on page 13-2
• “Parameterizing Functions”
More About
• “Anonymous Functions” on page 20-20
13-6
Call Local Functions Using Function Handles
This example shows how to create handles to local functions. If a function returns handles to local
functions, you can call the local functions outside of the main function. This approach allows you to
have multiple, callable functions in a single file.
Create the following function in a file, ellipseVals.m, in your working folder. The function returns
a struct with handles to the local functions.
function fh = ellipseVals
fh.focus = @computeFocus;
fh.eccentricity = @computeEccentricity;
fh.area = @computeArea;
end
function f = computeFocus(a,b)
f = sqrt(a^2-b^2);
end
function e = computeEccentricity(a,b)
f = computeFocus(a,b);
e = f/a;
end
function ae = computeArea(a,b)
ae = pi*a*b;
end
h = ellipseVals
h =
focus: @computeFocus
eccentricity: @computeEccentricity
area: @computeArea
Call a local function using its handle to compute the area of an ellipse.
h.area(3,1)
ans =
9.4248
13-7
13 Function Handles
Alternatively, you can use the localfunctions function to create a cell array of function handles
from all local functions automatically. This approach is convenient if you expect to add, remove, or
modify names of the local functions.
See Also
localfunctions
Related Examples
• “Create Function Handle” on page 13-2
More About
• “Local Functions” on page 20-25
13-8
Compare Function Handles
MATLAB® considers function handles that you construct from the same named function to be equal.
The isequal function returns a value of true when comparing these types of handles.
fun1 = @sin;
fun2 = @sin;
isequal(fun1,fun2)
ans =
logical
If you save these handles to a MAT-file, and then load them back into the workspace, they are still
equal.
Unlike handles to named functions, function handles that represent the same anonymous function are
not equal. They are considered unequal because MATLAB cannot guarantee that the frozen values of
nonargument variables are the same. For example, in this case, A is a nonargument variable.
A = 5;
h1 = @(x)A * x.^2;
h2 = @(x)A * x.^2;
isequal(h1,h2)
ans =
logical
If you make a copy of an anonymous function handle, the copy and the original are equal.
h1 = @(x)A * x.^2;
h2 = h1;
isequal(h1,h2)
ans =
logical
13-9
13 Function Handles
MATLAB considers function handles to the same nested function to be equal only if your code
constructs these handles on the same call to the function containing the nested function. This
function constructs two handles to the same nested function.
function z = findZ
z = a.^3 + b.^2 + c';
end
end
Function handles constructed from the same nested function and on the same call to the parent
function are considered equal.
[h1,h2] = test_eq(4,19,-7);
isequal(h1,h2)
ans =
logical
Function handles constructed from different calls are not considered equal.
[q1,q2] = test_eq(4,19,-7);
isequal(h1,q1)
ans =
logical
See Also
isequal
Related Examples
• “Create Function Handle” on page 13-2
13-10
14
Dictionaries
A dictionary is a data structure that creates associations between data of different types. Dictionaries
store data as values, that are accessed using corresponding unique keys. Keys and values can be
different data types, and each key and value pair is an entry.
The basic function of a dictionary is to link two associated sets of data so that an element of one set
can be used to find the corresponding element of the other. This action is called a lookup. Dictionaries
offer consistent performance regardless of how many entries the dictionary has.
This example shows how to create a dictionary and modify its entries. It then shows how dictionaries
handle data types and how to store different data types.
Create Dictionary
For example, create a dictionary using products as keys and prices as values. The dictionary output
indicates the data type of the keys and values.
d =
"Tomato" --> 1
"Carrot" --> 0.5000
"Mango" --> 2.5000
"Mushroom" --> 1.9900
Now, perform a lookup to find the price of carrots. Any price in the dictionary can be found using the
associated key.
d("Carrot")
ans =
0.5000
Modify Dictionary
To insert new entries into a dictionary, you can map a value to a new key using an equal sign (=). This
command adds the key "Potato" with a price of 0.75 as the value.
d("Potato") = 0.75
d =
"Tomato" --> 1
"Carrot" --> 0.5000
"Mango" --> 2.5000
"Mushroom" --> 1.9900
"Potato" --> 0.7500
14-2
Map Data with Dictionaries
You can change an entry by mapping a new value to an existing key. This command changes the price
of "Tomato" to 1.25.
d("Tomato") = 1.25
d =
Remove entries by mapping the key to an empty array ([]). This command removes the entry for
"Mango".
d("Mango") = []
d =
Any of the prior actions can be vectorized, rather than operating on one entry at a time. For example,
this command adds two new entries for "Celery" and "Grapes" with associated prices.
d =
Dictionary keys and values can be of almost any data type and a dictionary is typed based on its
entries. Once data types are assigned, the dictionary is configured.
Keys and values do not need to be of the same data type. However, all keys and all values in a
dictionary must share respective data types or be able to be converted to the configured data type.
If a new entry is inserted that does not match the configured data types for the dictionary, then
MATLAB® attempts to convert the data types to match the configuration.
For example, create a dictionary that accepts keys and values that are strings. Then add an entry that
contains a numeric value. MATLAB converts the value to a string.
14-3
14 Dictionaries
d = dictionary("hello","world")
d =
d("newKey") = 1
d =
isstring(d("newKey"))
ans = logical
1
Dictionaries require that all entries share the same respective data types for keys and values.
However, you can store multiple data types in a dictionary by putting the data in a cell array. Each
element of a cell array can contain data of any type or size. This approach satisfies the dictionary type
requirement because all of the values are cell arrays.
Create a cell array containing values of various data types, and then create a string array of keys.
myCell = {datetime,@myfun,struct,[1 2 3 4]}
names = ["my birthday" "my favorite function" "a structure" "numeric array"]
d =
In R2023a, lookup the contents of cells stored as values directly using curly braces ({}).
d{"numeric array"}
14-4
Map Data with Dictionaries
ans = 1×4
1 2 3 4
Similarly, new entries of any datatype can be inserted into an existing dictionary with cell values
using curly braces ({}).
d{"a new entry"} = table
d =
Dictionaries allow entries of almost any data type, but there are some limitations. Certain data types
like struct are accepted as part of an entry, but vectorized operations are not supported for
structures with different fields. Vectorized lookup is not supported for types that are not able to be
concatenated.
• Tables
• Tall arrays
• Distributed arrays
• graph and digraph objects
Unconfigured Dictionaries
When you create a dictionary without any entries, it is an unconfigured dictionary, and it has no data
type assigned to the keys and values.
d = dictionary
d =
isConfigured(d)
ans = logical
0
d =
14-5
14 Dictionaries
Before R2023b A dictionary can be configured without adding any entries by creating empty inputs
of the intended data types. For example, dictionary(string.empty,struct.empty).
See Also
dictionary | keyHash | keyMatch
Related Examples
• “Dictionaries and Custom Classes” on page 14-7
14-6
Dictionaries and Custom Classes
Hash Equivalence
Dictionaries are hash maps, meaning that they convert keys into uint64 scalar hash codes. Each
hash code represents a unique key and is used during lookup to quickly find the requested value. In
MATLAB, these scalars are generated using the keyHash function, which uses input property
information to generate a uint64 scalar. The keyMatch function can be used to determine whether
hashed keys are equivalent. For a dictionary to function properly, when keyMatch(A,B) is true, then
keyHash(A) and keyHash(B) must be equal. For most data types, this relationship holds true
without any extra steps. However, some custom classes can have properties that you do not want to
include as part of the comparison.
For example, create a class that is used to collect data and record the time that the data was
collected. This class has two properties dataValue and timestamp.
classdef myDataClass
properties
dataValue double = 0
timestamp datetime = datetime
end
end
For the purposes of comparing data, only dataValue is important. However, keyHash uses both
properties when generating a hash code.
See Also
dictionary | keyHash | keyMatch
14-7
14 Dictionaries
Related Examples
• “Map Data with Dictionaries” on page 14-2
14-8
15
Data type conversion is done with respect to a preset precedence of classes. The following table
shows the five classes you can concatenate with an unlike type without generating an error. The one
exception in the table is that you cannot convert logical values to the char data type.
For example, concatenating a double and single matrix always yields a matrix of type single.
MATLAB converts the double element to single to accomplish this.
See Also
More About
• “Combining Unlike Integer Types” on page 15-3
• “Combining Integer and Noninteger Data” on page 15-5
• “Add or Delete Cells in Cell Array” on page 12-9
• “Concatenation Examples” on page 15-7
• “Concatenating Objects of Different Classes”
15-2
Combining Unlike Integer Types
Overview
If you combine different integer types in a matrix (e.g., signed with unsigned, or 8-bit integers with
16-bit integers), MATLAB returns a matrix in which all elements are of one common type. MATLAB
sets all elements of the resulting matrix to the data type of the leftmost element in the input matrix.
For example, the result of the following concatenation is a vector of three 16-bit signed integers:
A =
A = [int16(5000) int8(50)]
A =
5000 50
B = [int8(50) int16(5000)]
B =
50 127
The first operation returns a vector of 16-bit integers. The second returns a vector of 8-bit integers.
The element int16(5000) is set to 127, the maximum value for an 8-bit signed integer.
C = [int8(50); int16(5000)]
C =
15-3
15 Combining Unlike Classes
50
127
Note You can find the maximum or minimum values for any MATLAB integer type using the intmax
and intmin functions. For floating-point types, use realmax and realmin.
A = [int8(-100) uint8(100)]
A =
-100 100
B = [uint8(100) int8(-100)]
B =
100 0
MATLAB evaluates each element prior to concatenating them into a combined array. In other words,
the following statement evaluates to an 8-bit signed integer (equal to 50) and an 8-bit unsigned
integer (unsigned -50 is set to zero) before the two elements are combined. Following the
concatenation, the second element retains its zero value but takes on the unsigned int8 type:
A = [int8(50), uint8(-50)]
A =
50 0
See Also
More About
• “Integers” on page 4-2
• “Integer Arithmetic” on page 4-20
15-4
Combining Integer and Noninteger Data
15-5
15 Combining Unlike Classes
Empty Matrices
If you construct a matrix using empty matrix elements, the empty matrices are ignored in the
resulting matrix:
15-6
Concatenation Examples
Concatenation Examples
In this section...
“Combining Single and Double Types” on page 15-7
“Combining Integer and Double Types” on page 15-7
“Combining Character and Double Types” on page 15-7
“Combining Logical and Double Types” on page 15-7
class(x)
ans =
char
15-7
15 Combining Unlike Classes
class(x)
ans =
double
15-8
16
Using Objects
16 Using Objects
Copying Objects
In this section...
“Two Copy Behaviors” on page 16-2
“Handle Object Copy” on page 16-2
“Value Object Copy Behavior” on page 16-2
“Handle Object Copy Behavior” on page 16-3
“Testing for Handle or Value Class” on page 16-5
Value objects behave like MATLAB fundamental types with respect to copy operations. Copies are
independent values. Operations that you perform on one object do not affect copies of that object.
Handle objects are referenced by their handle variable. Copies of the handle variable refer to the
same object. Operations that you perform on a handle object are visible from all handle variables that
reference that object.
a = 8;
b = a;
a = 6;
b
b =
8
clear a
b
b =
8
16-2
Copying Objects
The copy behavior of values stored as properties in value objects is the same as numeric variables.
For example, suppose vobj1 is a value object with property a:
vobj1.a = 8;
If you copy vobj1 to vobj2, and then change the value of vobj1 property a, the value of the copied
object's property, vobj2.a, is unaffected:
vobj2 =vobj1;
vobj1.a = 5;
vobj2.a
ans =
8
hobj1 = HdClass(8)
Because this statement is not terminated with a semicolon, MATLAB displays information about the
object:
hobj1 =
Data: 8
The variable hobj1 is a handle that references the object created. Copying hobj1 to hobj2 results in
another handle referring to the same object:
hobj2 = hobj1
hobj2 =
Data: 8
16-3
16 Using Objects
Because handles reference the object, copying a handle copies the handle to a new variable name,
but the handle still refers to the same object. For example, given that hobj1 is a handle object with
property Data:
hobj1.Data
ans =
Change the value of hobj1's Data property and the value of the copied object's Data property also
changes:
hobj1.Data = 5;
hobj2.Data
ans =
Because hobj2 and hobj1 are handles to the same object, changing the copy, hobj2, also changes
the data you access through handle hobj1:
hobj2.Data = 17;
hobj1.Data
ans =
17
Reassigning a handle variable produces the same result as reassigning any MATLAB variable. When
you create an object and assign it to hobj1:
hobj1 = HdClass(3.14);
hobj1 references the new object, not the same object referenced previously (and still referenced by
hobj2).
When you clear a handle from the workspace, MATLAB removes the variable, but does not remove
the object referenced by the other handle. However, if there are no references to an object, MATLAB
destroys the object.
Given hobj1 and hobj2, which both reference the same object, you can clear either handle without
affecting the object:
hobj1.Data = 2^8;
clear hobj1
hobj2
hobj2 =
Data: 256
16-4
Copying Objects
If you clear both hobj1 and hobj2, then there are no references to the object. MATLAB destroys the
object and frees the memory used by that object.
To remove an object referenced by any number of handles, use delete. Given hobj1 and hobj2,
which both refer to the same object, delete either handle. MATLAB deletes the object:
hobj1 = HdClass(8);
hobj2 = hobj1;
delete(hobj1)
hobj2
hobj2 =
Modifying Objects
When you pass an object to a function, MATLAB passes a copy of the object into the function
workspace. If the function modifies the object, MATLAB modifies only the copy of the object that is in
the function workspace. The differences in copy behavior between handle and value classes are
important in such cases:
• Value object — The function must return the modified copy of the object. To modify the object in
the caller’s workspace, assign the function output to a variable of the same name
• Handle object — The copy in the function workspace refers to the same object. Therefore, the
function does not have to return the modified copy.
ans =
ans =
16-5
16 Using Objects
ans =
containers.Map
See Also
Related Examples
• “Implement Copy for Handle Classes”
16-6
17
All MATLAB data types are implemented as object-oriented classes. You can add data types of your
own to your MATLAB environment by creating additional classes. These user-defined classes define
the structure of your new data type, and the functions, or methods, that you write for each class
define the behavior for that data type.
These methods can also define the way various MATLAB operators, including arithmetic operations,
subscript referencing, and concatenation, apply to the new data types. For example, a class called
polynomial might redefine the addition operator (+) so that it correctly performs the operation of
addition on polynomials.
3
18
Scripts
Create Scripts
Scripts are the simplest kind of code file because they have no input or output arguments. They are
useful for automating series of MATLAB commands, such as computations that you have to perform
repeatedly from the command line or series of commands you have to reference.
• Highlight commands from the Command History, right-click, and select Create Script.
• On the Home tab, click the New Script button.
• Use the edit function. For example, edit new_file_name creates (if the file does not exist) and
opens the file new_file_name. If new_file_name is unspecified, MATLAB opens a new file
called Untitled.
After you create a script, you can add code to the script and save it. For example, you can save this
code that generates random numbers from 0 through 100 as a script called numGenerator.m.
columns = 10000;
rows = 1;
bins = columns/100;
rng(now);
list = 100*rand(rows,columns);
histogram(list,bins)
Save your script and run the code using either of these methods:
• Type the script name on the command line and press Enter. For example, to run the
numGenerator.m script, type numGenerator.
• On the Editor tab, click the Run button.
You also can run the code from a second code file. To do this, add a line of code with the script name
to the second code file. For example, to run the numGenerator.m script from a second code file, add
the line numGenerator; to the file. MATLAB runs the code in numGenerator.m when you run the
second file.
When execution of the script completes, the variables remain in the MATLAB workspace. In the
numGenerator.m example, the variables columns, rows, bins, and list remain in the workspace.
To see a list of variables, type whos at the command prompt. Scripts share the base workspace with
your interactive MATLAB session and with other scripts.
See Also
More About
• “Create and Run Sections in Code” on page 18-6
• “Scripts vs. Functions” on page 18-11
• “Base and Function Workspaces” on page 20-9
• “Create Live Scripts in the Live Editor” on page 19-6
18-2
Add Comments to Code
When you write code, it is a good practice to add comments that describe the code. Comments allow
others to understand your code and can refresh your memory when you return to it later. During code
development and testing, you also can use comments to comment out any code that does not need to
run.
In the Live Editor, you can insert lines of text before and after code to describe a process or code.
Text lines provide additional flexibility such as standard formatting options, and the insertion of
images, hyperlinks, and equations. For more information, see “Create Live Scripts in the Live Editor”
on page 19-6.
Note When you have a MATLAB code file (.m) containing text that has characters in a different
encoding than that of your platform, when you save or publish your file, MATLAB displays those
characters as garbled text. Live scripts and functions (.mlx) support storing and displaying
characters across all locales.
Add Comments
To add comments to MATLAB code, use the percent (%) symbol. Comment lines can appear anywhere
in a code file, and you can append comments to the end of a line of code.
For example:
% Add up all the vector elements.
y = sum(x) % Use the sum function.
For example:
a = magic(3);
%{
sum(a)
diag(a)
sum(diag(a))
%}
sum(diag(fliplr(a)))
To comment out a selection, select the lines of code, go to the Editor or Live Editor tab, and in the
Code section, click the comment button . You also can type Ctrl+R. To uncomment the selected
lines code, click the uncomment button or type Ctrl+Shift+R. On macOS systems, use
Command+/ to comment and Command+Option+/ to uncomment. On Linux systems, use Ctrl+/ to
comment and Ctrl+Shift+/ to uncomment.
To comment out part of a statement that spans multiple lines, use an ellipsis (...) instead of a
percent sign. For example:
18-3
18 Scripts
Wrap Comments
By default, as you type comments in the Editor and Live Editor, the text wraps when it reaches a
column width of 75. The Editor and Live Editor do not wrap comments with:
To change where comment text wraps or to disable automatic comment wrapping, go to the Home
tab and in the Environment section, click Preferences. Select MATLAB > Editor/Debugger >
Language, and adjust the Comment formatting preferences. In MATLAB Online™, these
preferences are located under Editor/Debugger > MATLAB Language.
If you have existing comments that extend past the current column width, to automatically wrap the
comment, go to the Editor or Live Editor tab, and in the Code section, click the wrap comments
button . For example, suppose that you have this lengthy text into a commented line.
% This is a code file that has a comment that is a little more than 75 columns wide.
disp('Hello, world')
With the cursor on the line, go to Editor or Live Editor tab, and in the Code section, click the wrap
comments button . The comment wraps to the next line:
% This is a code file that has a comment that is a little more than 75
% columns wide.
disp('Hello, world')
Spell checking is supported in US English for MATLAB code files (.m) and live code files (.mlx). To
remove words from your local dictionary, go to your MATLAB preferences folder (the folder returned
when you run prefdir) and edit the file dict/en_US_userDictionary.tdi.
See Also
Related Examples
• “Add Help for Your Program” on page 20-5
• “Create Scripts” on page 18-2
• “Create Live Scripts in the Live Editor” on page 19-6
18-4
Add Comments to Code
• “Editor/Debugger Preferences”
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
18-5
18 Scripts
In the Editor, a section begins with two percent signs (%%). The text on the same line as %% is called
the section title. Including section titles is optional, however, it improves the readability of the file
and appears as a heading if you publish your code.
In the Live Editor, a section can consist of code, text, and output. When you create a section or modify
an existing section, the bar on the left side of the section is displayed with vertical striping. The
striping indicates that the section is stale. A stale section is a section that has not yet been run, or
that has been modified since it was last run.
18-6
Create and Run Sections in Code
Delete Sections
To delete a section break in the Editor, delete the two percent signs (%%) at the beginning of the
section. To delete a section break in the Live Editor, place your cursor at the beginning of the line
directly after the section break and press Backspace. Alternatively, you can place your cursor at the
end of the line directly before the section break and press the Delete key.
Note You cannot remove sections breaks added by MATLAB. For more information about when
MATLAB might add a section break, see “Behavior of Sections in Functions” on page 18-9 and
“Behavior of Sections in Loops and Conditional Statements” on page 18-9.
To maximize the space available for editing code in the Editor, you can hide the Run Section, Run to
Here, and Code Folding margins. This minimizes the gray area to the left of your code. To hide one or
more of the margins, right-click the gray area to the left of your code and clear the Show Run
Section Margin, Show Run to Here Margin, and/or Show Code Folding Margin options.
Run Sections
You can run your code file by either running each section individually or by running all of the code in
the file at once. To run a section individually, it must contain all the values it requires, or the values
must exist in the MATLAB workspace. When running individual sections, MATLAB does not save your
file and the file does not have to be on your search path.
Operation Instructions
Run all the code in the file. On the Editor or Live Editor tab, in the Run section, click
Run.
Run the code in the selected On the Editor or Live Editor tab, in the Section section, click
section. Run Section.
In the Live Editor, you also can click the blue bar to the left of the
section.
Run the code in the selected On the Editor or Live Editor tab, in the Section section, select
section, and then move to the Run and Advance.
next section.
Run the code in the selected On the Editor or Live Editor tab, in the Section section, select
section, and then run all the Run to End.
code after the selected
section.
18-7
18 Scripts
Operation Instructions
Run to a specific line of code Click the Run to Here button to the left of the line. If the selected
and pause. line cannot be reached, MATLAB continues running until the end of
the file is reached or a breakpoint is encountered.
In the Editor, the Run to Here button is available only for code
that has been saved. In the Live Editor, the Run to Here button is
available for all code, whether it is saved or not. In functions and
classes, the Run to Here button is available only when evaluation
is paused.
For more information, see “Debug MATLAB Code Files” on page 22-
2.
In the Editor, you can increment, decrement, multiply, or divide numeric values within a section,
rerunning that section after every change. This workflow can help you fine-tune and experiment with
your code.
To adjust a numeric value, select the value or place your cursor next to the value. Next, right-click
and select Increment Value and Run Section. In the dialog box that appears, specify a step value
for addition and subtraction or a scale value for multiplication and division. Then, click one of the
operator buttons to add to, subtract from, multiply, or divide the selected value in your section.
MATLAB runs the section after every click.
In the Live Editor, you can use controls to increment and decrement a numeric value within a section.
For example, this code calculates the factorial of the variable x.
x = 5;
y = factorial(x)
y =
120
To interactively change the value of x, in a live script, replace the value 5 with a slider. By default,
MATLAB reruns the current section when the value of the slider changes.
For more information, see “Add Interactive Controls to a Live Script” on page 19-37.
18-8
Create and Run Sections in Code
Operation Instructions
Move to specific section. On the Editor or Live Editor tab, in the Navigate section, click
Go To . Then, in the Sections section, select from the available
options.
Move to previous section. On the Editor or Live Editor tab, in the Navigate section, click
Go To , and then click Previous Section. Alternatively, you can use
the Ctrl+Up keyboard shortcut.
Move to next section On the Editor or Live Editor tab, in the Navigate section, click
Go To , and then click Next Section. Alternatively, you can use the
Ctrl+Down keyboard shortcut.
For example, this code preallocates a 10-element vector, and then calculates nine values. If a
calculated value is even, MATLAB adds one to it.
x = ones(1,10);
for n = 2:10
x(n) = x(n) + 1;
end
end
If you add a section break at line 3, inside the for loop, MATLAB adds a section break at line 9, the
end statement for the for loop. If you add a section break at line 6, inside the if statement, MATLAB
adds a section break at line 8, the end statement for the if statement, leading to three levels of
nested sections.
18-9
18 Scripts
• At the outermost level of nesting, one section spans the entire file.
• At the second level of nesting, a section exists within the for loop.
• At the third level of nesting, one section exists within the if statement.
See Also
More About
• “Create Scripts” on page 18-2
• “Create Live Scripts in the Live Editor” on page 19-6
• “Scripts vs. Functions” on page 18-11
18-10
Scripts vs. Functions
Both scripts and functions allow you to reuse sequences of commands by storing them in code files.
Scripts are the simplest type of code file, since they store commands exactly as you would type them
at the command line. However, functions are more flexible and more easily extensible.
Create a script in a file named triarea.m that computes the area of a triangle:
b = 5;
h = 3;
a = 0.5*(b.*h)
After you save the file, you can call the script from the command line:
triarea
a =
7.5000
To calculate the area of another triangle using the same script, you could update the values of b and
h in the script and rerun it. Each time you run it, the script stores the result in a variable named a
that is in the base workspace.
However, instead of manually updating the script each time, you can make your code more flexible by
converting it to a function. Replace the statements that assign values to b and h with a function
declaration statement. The declaration includes the function keyword, the names of input and
output arguments, and the name of the function.
function a = triarea(b,h)
a = 0.5*(b.*h);
end
After you save the file, you can call the function with different base and height values from the
command line without modifying the script:
a1 = triarea(1,5)
a2 = triarea(2,10)
a3 = triarea(3,6)
a1 =
2.5000
a2 =
10
a3 =
9
Functions have their own workspace, separate from the base workspace. Therefore, none of the calls
to the function triarea overwrite the value of a in the base workspace. Instead, the function assigns
the results to variables a1, a2, and a3.
18-11
18 Scripts
See Also
More About
• “Create Scripts” on page 18-2
• “Create Functions in Files” on page 20-2
• “Add Functions to Scripts” on page 18-13
• “Base and Function Workspaces” on page 20-9
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
18-12
Add Functions to Scripts
MATLAB scripts, including live scripts, can contain code to define functions. These functions are
called local functions. Local functions are useful if you want to reuse code within a script. By adding
local functions, you can avoid creating and managing separate function files. They are also useful for
experimenting with functions, which can be added, modified, and deleted easily as needed.
Local functions in scripts must be defined at the end of the file, after the last line of script code.
In the file, include two local functions, mymean and mymedian. The script mystats declares an array,
determines the length of the array, and then uses the local functions mymean and mymedian to
calculate the average and median of the array.
x = 1:10;
n = length(x);
function a = mymean(v,n)
% MYMEAN Local function that calculates mean of array.
a = sum(v)/n;
end
function m = mymedian(v,n)
% MYMEDIAN Local function that calculates median of array.
w = sort(v);
if rem(n,2) == 1
m = w((n + 1)/2);
else
m = (w(n/2) + w(n/2 + 1))/2;
end
end
avg = mymean(x,n);
med = mymedian(x,n);
To run an individual section inside a script or live script, place the cursor inside the section and use
the Run Section
18-13
18 Scripts
button (requires R2017b or later for .m files). In live scripts or functions (.mlx files), you only can
run sections that are before the local function definitions.
Local functions in the current file have precedence over functions in other files. That is, when you call
a function within a script, MATLAB checks whether the function is a local function before looking for
the function in other locations. This allows you to create an alternate version of a particular function
while retaining the original in another file.
Scripts create and access variables in the base workspace. Local functions, like all other functions,
have their own workspaces that are separate from the base workspace. Local functions cannot access
variables in the workspace of other functions or in the base workspace, unless you pass them as
arguments.
Scripts that contain local functions must contain executable code outside of a function.
For example:
help mystats>mymean
See Also
More About
• “Create Functions in Files” on page 20-2
• “Function Precedence Order” on page 20-37
• “Base and Function Workspaces” on page 20-9
18-14
19
• Add titles, headings, and formatted text to describe a process and include equations, images, and
hyperlinks as supporting material.
• Save your narratives as richly formatted, executable documents and share them with colleagues
or the MATLAB community, or convert them to HTML files, PDF files, Microsoft Word documents,
LaTeX files, Markdown files, and Jupyter® notebooks for publication.
19-2
What Is a Live Script or Function?
• Combine code and results with formatted text and mathematical equations.
• Create step-by-step lectures and evaluate them incrementally to illustrate a topic.
• Modify code on the fly to answer questions or explore related topics.
• Share lectures with students as interactive documents or in hard copy format, and distribute
partially completed files as assignments.
19-3
19 Live Scripts and Functions
Requirements
• MATLAB R2016a — MATLAB supports live scripts in versions R2016a and above, and live
functions in versions R2018a and above.
• Operating System — Starting in R2019b, MATLAB supports the Live Editor in all operating
systems supported by MATLAB. For more information, see System Requirements.
For MATLAB versions R2016a through R2019a, the Live Editor is not supported in several
operating systems supported by MATLAB.
In addition, some operating systems require additional configuration to run the Live Editor in
MATLAB versions R2016a through R2019a. If you are unable to run the Live Editor on your
system, Contact Technical Support for information on how to configure your system.
19-4
What Is a Live Script or Function?
Unsupported Features
Some MATLAB features are unsupported in the Live Editor:
• Classes — Classes are not supported in the Live Editor. Create classes as plain code files (.m)
instead. You then can use the classes in your live scripts or functions.
• MATLAB preferences — The Live Editor ignores some MATLAB preferences, including custom
keyboard shortcuts and Emacs-style keyboard shortcuts.
See Also
Related Examples
• “Create Live Scripts in the Live Editor” on page 19-6
• “Live Code File Format (.mlx)” on page 19-65
• MATLAB Live Script Gallery
19-5
19 Live Scripts and Functions
Live scripts are program files that contain your code, output, and formatted text together in a single
interactive environment called the Live Editor. In live scripts, you can write your code and view the
generated output and graphics along with the code that produced it. Add formatted text, images,
hyperlinks, and equations to create an interactive narrative that you can share with others.
To create a live script in the Live Editor, go to the Home tab and click New Live Script . You also
can use the edit function in the Command Window. For example, type edit penny.mlx to open or
create the file penny.mlx. To ensure that a live script is created, specify a .mlx extension. If an
extension is not specified, MATLAB defaults to a file with a .m extension, which supports only plain
code.
If you have an existing script (.m), you can open it as a new live script in the Live Editor. Opening a
script as a live script creates a copy of the file and leaves the original file untouched. MATLAB
converts publishing markup from the original script to formatted content in the new live script.
To open an existing script (.m) as a live script (.mlx) from the Editor, right-click the document tab,
and select Open scriptName as Live Script from the context menu. Alternatively, go to the Editor
tab, click Save , and select Save As. Then, set the Save as type to MATLAB Live Code Files
(*.mlx) and click Save. You must use one of the described conversion methods to convert your
script to a live script. Simply renaming the script with a .mlx extension does not work and can
corrupt the file.
Add Code
After you create a live script, you can add code and run it. For example, add this code that plots a
vector of random data and draws a horizontal line on the plot at the mean.
n = 50;
r = rand(n,1);
plot(r)
m = mean(r);
hold on
plot([0,n],[m,m])
hold off
title('Mean of Random Uniform Data')
19-6
Create Live Scripts in the Live Editor
Run Code
To run the code, click the vertical striped bar to the left of the code. Alternatively, go to the Live
Editor tab and click Run . While your program is running, a status indicator
appears at the top
left of the Editor window. A gray blinking bar to the left of a line of code indicates the line that
MATLAB is evaluating. To navigate to the line MATLAB is evaluating, click the status indicator.
If an error occurs while MATLAB is running your program or if MATLAB detects a significant issue in
your code, the status indicator becomes an error icon . To navigate to the error, click the icon. An
error icon to the right of the line of code indicates the error. The corresponding error message is
displayed as an output.
You do not need to save your live script to run it. When you do save your live script, MATLAB
automatically saves it with a .mlx extension. For example, go to the Live Editor tab, click Save ,
and enter the name plotRand. MATLAB saves the live script as plotRand.mlx.
Display Output
By default, the Live Editor displays output to the right of the code. Each output is displayed with the
line that creates it. To change the size of the output display panel, drag the resizer bar between the
code and output to the left or to the right.
As you scroll through the code, the Live Editor aligns the output to the code that generates it. To
disable the alignment of output to code when output is on the right, right-click the output section and
select Disable Synchronous Scrolling.
19-7
19 Live Scripts and Functions
To clear an output, right-click the output or the code line that created it, and select Clear Output. To
clear all output, right-click anywhere in the script and select Clear All Output. Alternatively, go to
the View tab and in the Output section, click the Clear all Output button.
To open an individual output such as a variable or figure in a separate window, click the Open in
figure window button in the upper-right corner of the output. Variables open in the Variables
editor, and figures open in a new figure window. Changes made to variables or figures outside of a
live script do not apply to the output displayed in the live script.
To modify figures in the output, use the tools in the upper-right corner of the figure axes or in the
Figure toolstrip. You can use the tools to explore the data in a figure and add formatting and
annotations. For more information, see “Modify Figures in Live Scripts” on page 19-14.
You can use the keyboard to interact with output in a live script by moving the focus from the code to
the output and then activating the output.
To move focus from the code to the output when output is on the right, press Ctrl+Shift+O. On
macOS systems, press Option+Command+O. When output is inline, use the down arrow and up
arrow keys. When focus is on an output, activate it by pressing Enter. Once an output is activated,
you can scroll text using the arrow keys, navigate through hyperlinks and buttons using the Tab key,
and open the context menu by pressing Shift+F10. To deactivate an output, press Esc.
To disable using the keyboard to move focus to the output when output is inline, on the Home tab, in
the Environment section, click Preferences. Select MATLAB > Editor/Debugger > Display,
and clear the Focus outputs using keyboard when output is inline option.
Change View
You can optimize the layout of your live script for your current workflow by changing where to display
output and whether to display code in the live script. To change the layout of the live script, go to the
19-8
Create Live Scripts in the Live Editor
View tab, and in the View section, select from the available options. You also can select one of the
layout buttons at the top right of the live script.
To change the default location of the output when creating a new live script, on the Home tab, in the
Environment section, click Preferences. Select MATLAB > Editor/Debugger > Display, and
then select a different option for the Live Editor default view.
In Output on Right view, the Live Editor displays output to the right of the code. Each output displays
with the line that creates it. This layout is ideal when writing code.
In Output Inline view, the Live Editor displays each output underneath the line that creates it. This
layout is ideal for sharing.
19-9
19 Live Scripts and Functions
In Hide Code view, the Live Editor hides the code and displays only output, labeled controls, tasks,
and formatted text. If a task in the live script is configured to show only code and no controls, then
the task does not display when you hide the code. This layout is ideal for sharing when you want
others to change only the value of the controls in your live script or when you do not want others to
see your code.
19-10
Create Live Scripts in the Live Editor
Format Text
You can add formatted text, images, hyperlinks, and equations to your live scripts to create a
presentable document to share with others. For example, add a title and some introductory text to
plotRand.mlx:
1
Place your cursor at the top of the live script, and in the Live Editor tab, click Text . A new
text line appears above the code.
2
Click the Select Style button and select Title.
3 Add the text Plot Random Data.
4
With your cursor still in the line, click the Align Center button to center the text.
5 Press Enter to move to the next line.
6 Type the text This script plots a vector of random data and draws a
horizontal line on the plot at the mean.
For more information, including a list of all available formatting options, see “Format Text in the Live
Editor” on page 19-20.
19-11
19 Live Scripts and Functions
Zoom
To adjust the displayed font size in the Live Editor by zooming in and out, use the Ctrl+Plus (+) and
Ctrl+Minus (-) keyboard shortcuts or the Ctrl+Mouse Scroll keyboard shortcut. On macOS
systems, use the Command key instead of the Ctrl key.
The change in the displayed font size is not honored when exporting the live script to PDF, Microsoft
Word, HTML, LaTeX, Markdown, or Jupyter notebooks.
See Also
More About
• “Format Text in the Live Editor” on page 19-20
• “Create and Run Sections in Code” on page 18-6
• “Modify Figures in Live Scripts” on page 19-14
19-12
Create Live Scripts in the Live Editor
19-13
19 Live Scripts and Functions
Explore Data
You can interactively explore figures in the output using the toolbar that appears in the upper-right
corner of the axes when you hover over a figure. The tools available depend on the contents of the
axes, but typically include zooming, panning, rotating, exporting, and restoring the original view.
Zooming, panning, and rotating the axes let you explore different views of your data. By default, you
can scroll or pinch to zoom into and out from the view of the axes. You also can drag to pan (2-D view)
or drag to rotate (3-D view). Gesture-based interactions are not supported in R2018a and previous
releases.
You can enable more interactions by clicking the zoom-in , zoom-out , pan , and rotate
buttons in the axes toolbar. For example, click the zoom-in button if you want to drag a rectangle to
zoom into a region of interest.
Note When you open a saved live script, a blue information icon appears next to each output
figure, indicating that the interactive tools are not available yet. To make these tools available, run
the live script.
Suppose that you want to explore the health information of 100 patients. Create a live script called
patients_smoking.mlx and add code that loads the data and adds a scatter plot that shows the
systolic blood pressure of patients that smoke versus patients that do not smoke, by age. Run the
code by going to the Live Editor tab and clicking Run
.
load patients
figure
scatter(Age(Smoker==1),Systolic(Smoker==1));
hold on
scatter(Age(Smoker==0),Systolic(Smoker==0));
hold off
19-14
Modify Figures in Live Scripts
Explore the points where the patient is between 35 and 40 years old. Select the zoom-in button and
drag a rectangle around the points between the 35 and 40 x-axis markers. The view zooms into the
selected region.
19-15
19 Live Scripts and Functions
Option Description
Add a title to the axes.
Title
To modify an existing title, click the existing title
and enter the modified text.
Add a label to the axes.
X-Label
To modify an existing label, click the existing
label and enter the modified text.
Y-Label
Add a legend to the figure.
Legend
To modify the existing legend descriptions, click
the existing descriptions and enter the modified
text. To remove the legend, select Remove
Legend from the Figure tab.
Add a colorbar legend to the figure.
Colorbar
To remove the colorbar legend, select Remove
Colorbar from the Figure tab.
Add grid lines to the axes.
Grid
To remove all the grid lines from the axes, select
Remove Grid from the Figure tab.
X-Grid
Y-Grid
Add a line or arrow annotation to the figure.
Line Draw the arrow from tail to head.
Double Arrow
For example, suppose that you want to add a title, axes labels, a legend, grid lines, and an arrow
annotation to the figure in patients_smoking.mlx.
•
To add a title, go to the Figure tab, and select
Title. A blue rectangle appears prompting you to enter text. Type the text Systolic Blood
Pressure vs. Age and press Enter.
• To add axes labels, go to the Figure tab, and select
19-16
Modify Figures in Live Scripts
For example, in the live script patients_smoking.mlx, after zooming in on patients between 35
and 40 years of age, click the Update Code button.
19-17
19 Live Scripts and Functions
MATLAB adds the generated code for the interaction after the line containing the code for creating
the plot.
xlim([34.92 39.97])
ylim([105.9 139.8])
If the Live Editor is unable to determine where to place the generated code, the Update Code button
is disabled. This occurs, for example, if you modify the code without running the script again. In this
case, use the Copy button to copy the generated code into the clipboard. You then can paste the code
into your script at the appropriate location.
To save the figure, click the Export button in the axes toolbar and select from the available
options. For more information on saving figures, see “Save Plot as Image or Vector Graphics File” or
“Save Figure to Reopen in MATLAB Later”.
To print the figure, click the Open in figure window button in the upper-right corner of the figure.
This opens the figure in a separate figure window. Then, select File > Print. For more information on
printing figures, see “Print Figure from File Menu”.
Note Any changes made to the figure in the separate figure window are not reflected in the live
script. Similarly, any changes made to the figure in the live script are not reflected in the open figure
window.
19-18
Modify Figures in Live Scripts
See Also
Related Examples
• “Format Text in the Live Editor” on page 19-20
• “Create and Run Sections in Code” on page 18-6
19-19
19 Live Scripts and Functions
Code Insert a blank You can insert a code line before, after, or between text lines.
line of code.
Section Insert a section You can insert a section break to divide your live script or function
Break break. into manageable sections to evaluate individually. A section can
consist of code, text, and output. For more information, see
“Create and Run Sections in Code” on page 18-6.
Text Insert a blank A text line can contain formatted text, hyperlinks, images, or
line of text. equations. You can insert a text line before, after, or between code
lines.
Insert a table of The table of contents contains a list of all the titles and headings in
Table of
contents. the document. If the document contains only one title, then it is not
Contents
included in the table of contents. Only the title of the table of
contents is editable.
You can insert a table of contents only in text lines. If you insert a
table of contents into a code line, MATLAB places it directly above
the current code section.
19-20
Format Text in the Live Editor
Table Insert a table. You can insert tables only in text lines. If you insert a table into a
code line, MATLAB places the table in a new text line directly
under the selected code line.
To specify the table size, select Table , move the cursor over the
grid to highlight the numbers of rows and columns you want, and
click to add the table. To create a larger table, click the table
button , and specify the numbers of rows and columns in the
dialog box.
After inserting the table, you can modify its rows and columns:
• Alt Text — Add text to the edit field to specify alternative text
for the image.
• Alignment — Select from the available options to specify how
the image aligns with the other items in the row.
• Size — To specify a size relative to the original image size,
select Relative (%) and specify the width and height of the
image as a percentage of the original image. To specify an
absolute size, select Absolute (px) and specify the width and
height of the image in pixels. Select Keep Aspect Ratio to
maintain the aspect ratio while resizing.
19-21
19 Live Scripts and Functions
Hyperlink Insert a You can insert hyperlinks only in text lines. If you insert a
hyperlink. hyperlink into a code line, MATLAB places the hyperlink in a new
text line directly under the selected code line.
Format Text
To format existing text, use any of the options included in the Live Editor tab Text section:
Heading 1
Heading 2
Heading 3
Title
19-22
Format Text in the Live Editor
Align center
Align right
Lists Numbered list
Bulleted list
Standard
Bold
Formatting
Italic
Underline
Monospaced
To change the case of selected text or code from all uppercase to lowercase, or vice versa, select the
text, right-click, and select Change Case. You also can press Ctrl+Shift+A. If the text contains both
uppercase and lowercase text, MATLAB changes the case to all uppercase.
Checking Spelling
You can check for spelling issues in text lines and comments in your live scripts and functions. To
enable spell checking, go to the View tab and click the Spelling button on. Words with a potential
spelling issue are underlined in blue. To resolve the issue, click the word and select one of the
suggested corrections. You also can choose to ignore the issue or add the flagged word to your local
dictionary. To navigate between issues using the keyboard, use Alt+F7 and Alt+Shift+F7.
Spell checking is supported in US English for live code files (.mlx) and MATLAB code files (.m). To
remove words from your local dictionary, go to your MATLAB preferences folder (the folder returned
when you run prefdir) and edit the file dict/en_US_userDictionary.tdi.
To customize a text or code style for the current document, go to the Live Editor tab, and in the Text
section, click the Customize styles button . Then, select the style that you want to customize and
change the font, size, color, and formatting for the selected style. The Customize Styles dialog box
shows a preview of each style.
The customized style applies only to the current document. To apply the customized style to all new
live scripts as well, select the Use this configuration for new live scripts option.
19-23
19 Live Scripts and Functions
To customize a text or code style for all open documents and all new documents, use the matlab.fonts.
The Live Editor updates all open live scripts and live functions to show the selected fonts. When you
create new live scripts or functions, the selected fonts are applied as well.
For example, this code changes the color and style of titles in the Live Editor:
s = settings;
s.matlab.fonts.editor.title.Style.PersonalValue = {'bold'};
s.matlab.fonts.editor.title.Color.PersonalValue = [0 0 255 1];
To increase or decrease the displayed font size in the Live Editor, zoom in or out using the Ctrl +
Plus (+) and Ctrl + Minus (-) keyboard shortcuts or by holding Ctrl and scrolling with the mouse.
On macOS systems, use the Command key instead of the Ctrl key. The change in the displayed font
size is not honored when exporting the live script to PDF, Microsoft Word, HTML, LaTeX, Markdown,
or Jupyter notebooks.
Autoformatting
For quick formatting in live scripts and functions, you can use a combination of keyboard shortcuts
and character sequences. Formatting appears after you enter the final character in a sequence.
19-24
Format Text in the Live Editor
This table shows a list of formatting styles and their available keyboard shortcuts and autoformatting
sequences.
--- + Enter
*** + Enter
Bulleted list * text Ctrl + Alt + U
- text
+ text
Numbered list number. text Ctrl + Alt + O
Italic *text* Ctrl + I
_text_
Bold **text** Ctrl + B
__text__
Bold and italic ***text*** Ctrl + B, then Ctrl + I
___text___
Monospace `text` Ctrl + M
|text|
Underline None Ctrl + U
LaTeX equation $LaTeX$ Ctrl + Shift + L
Hyperlink URL + Space or Ctrl + K
Enter
<URL>
[Label](URL)
19-25
19 Live Scripts and Functions
(C)
Note Title, heading, section break, and list sequences must be entered at the beginning of a line.
Sometimes you want an autoformatting sequence such as *** to appear literally. To display the
characters in the sequence, escape out of the autoformatting by pressing the Backspace key or by
clicking Undo . For example, if you type ## text + Enter, a heading in the Heading 1 style with
the word text appears. To undo the formatting style and simply display ## text, press the
Backspace key. You only can escape out of a sequence directly after completing it. After you enter
another character or move the cursor, escaping is no longer possible.
To revert the autoformatting for LaTeX equations and hyperlinks, use the Backspace key at any
point.
To force formatting to reappear after escaping out of a sequence, click the Redo button. You only
can redo an action directly after escaping it. After you enter another character or move the cursor,
the redo action is no longer possible. In this case, to force the formatting to reappear, delete the last
character in the sequence and type it again.
To disable all or certain autoformatting sequences, you can adjust the “Editor/Debugger
Autoformatting Preferences”.
See Also
export
More About
• “Insert Equations into the Live Editor” on page 19-27
• “Ways to Share and Export Live Scripts and Functions” on page 19-62
19-26
Insert Equations into the Live Editor
There are two ways to insert an equation into a live script or function.
• Insert an equation interactively — You can build an equation interactively by selecting from a
graphical display of symbols and structures.
• Insert a LaTeX equation — You can enter LaTeX commands and the Live Editor inserts the
corresponding equation.
2 Build your equation by selecting symbols, structures, and matrices from the options displayed in
the Equation tab. View additional options by clicking the drop-down arrow to the right of each
section.
19-27
19 Live Scripts and Functions
When adding or editing a matrix, a context menu appears, which you can use to delete and insert
rows and columns. You also can use the context menu to change or remove matrix delimiters.
3 Format your equation using the options available in the Text section. Formatting is only available
for text within the equation. Numbers and symbols cannot be formatted. The formatting option is
disabled unless the cursor is placed within text that can be formatted.
The equation editor provides a few shortcuts for adding elements to your equation:
• To insert symbols, structures, and matrices, type a backslash followed by the name of the symbol.
For example, type \pi to insert a π symbol into the equation. To discover the name of a symbol or
structure, hover over the corresponding button in the Equation tab. You can also type backslash
in the equation editor to bring up a completion menu of all supported names.
Note Although the \name syntax closely resembles LaTeX command syntax, entering full LaTeX
expressions is not supported when inserting equations interactively.
• To insert subscripts, superscripts, and fractions, use the symbols ‘_’, ‘^’ or ‘/’. For example:
19-28
Insert Equations into the Live Editor
The preview pane shows a preview of equation as it would appear in the live script.
3 To include a description of the LaTeX equation when exporting the live script to HTML, add text
to the Alt Text field. For example, you can enter the text Maclaurin series for sin(x).
The description specifies alternative text for the equation and is saved as an alt attribute in the
HTML document. It is used to provide additional information for the equation if, for example, a
user is using a screen reader.
4 Press OK to insert the equation into your live script.
LaTeX expressions describe a wide range of equations. This table shows several examples of LaTeX
expressions and their appearance when inserted into a live script.
19-29
19 Live Scripts and Functions
MATLAB supports most standard LaTeX math mode commands. These tables show a list of supported
LaTeX commands.
Non-ASCII Letters
Greek/Hebrew Letters
19-30
Insert Equations into the Live Editor
Operator Symbols
Relation Symbols
19-31
19 Live Scripts and Functions
Note Some commands can be combined with the not command to create the negated version of the
symbol. For example, \not\leq creates the symbol ≰. The commands that can be combined include
leq, geq, equiv, cong, approx, sim, simeq, models, ni, parallel, succ, succeq, prec,
preceq, subset, supset, subseteq, supseteq, sqsubseteq, and sqsupseteq.
Arrows
Brackets
19-32
Insert Equations into the Live Editor
Misc Symbols
Note The exists command can be combined with the not command to create the negated version
of the symbol. For example, \not\exists creates the symbol ∄.
19-33
19 Live Scripts and Functions
Text Symbols
Accents
Functions
19-34
Insert Equations into the Live Editor
Math Constructs
∑
abc ket a 2 left, middle, 10 nolimits
b
2 right
i=0
ab cd braket
Note To create a matrix using the matrix and pmatrix commands, use the & symbol to separate
columns, and \cr to separate rows. For example, to create a 2–by–2 matrix, use the expression
\matrix{a & b \cr c & d}.
For large operators, MATLAB automatically adjusts the position of limits depending on whether or not
there is text inline with the equation. To force the display of the limits above and below the operator,
use the limits command. To force the display of the limits adjacent to the operator, use the
\nolimits command. For example, the expression \sum\limits_{i=0}^{10} displays the limits
of the summation operator above and below the operator. The expression \sum
\nolimits_{i=0}^{10} displays the limits of the summation operator adjacent to the operator.
10
∑∑
10
i=0
i=0
19-35
19 Live Scripts and Functions
White Space
Text Styling
See Also
Related Examples
• “Ways to Share and Export Live Scripts and Functions” on page 19-62
External Websites
• https://www.latex-project.org/
19-36
Add Interactive Controls to a Live Script
Insert Controls
To insert a control into a live script, go to the Live Editor tab, and in the Code section, click
Control. Then, select from the available options. To replace an existing value with a control, select
the value in the live script and then insert the control. The Control menu shows only the options
available for the selected value. To configure the control, right-click the control in the live script and
then select Configure Control.
If your live script already contains a control, in some cases, you can replace that control with another
control that has similar functionality. To replace a control with another control, right-click it and
select Replace with Control Name. You also can select the control in the live script, go to the Live
Editor tab, click Control, and select from the available options. Replacing one control with another
preserves relevant configuration values, such as range and default values.
Check Box Use a check box to interactively set the Not applicable
value of a variable to either the logical
value 1 (true) or the logical value 0
(false).
19-37
19 Live Scripts and Functions
19-38
Add Interactive Controls to a Live Script
The text displayed in the edit field To display text next to the Select File
determines its current value. button, in the Label section, enter the
label text.
Range Slider Use a range slider to interactively In the Values section, specify a Min,
select a range by moving the left and Max, and Step value or select a
right range slider thumbs to the workspace variable from the drop-down
desired minimum and maximum range list.
values.
For more information about specifying
The value to the left of the range slider the range slider values using variables,
is its current value. see “Link Variables to Controls” on
page 19-40.
Slider Use a slider to interactively change the In the Values section, specify a Min,
value of a variable by moving the slider Max, and Step value or select a
thumb to the desired numeric value. workspace variable from the drop-down
list.
The value to the left of the slider is its
current value. For more information about specifying
the slider values using variables, see
“Link Variables to Controls” on page
19-40.
19-39
19 Live Scripts and Functions
When the code is hidden, labels display next to the control. To modify the label for a control, right-
click the control and select Configure Control. Then, in the Label section, enter the label text. The
label text is also the text that displays on button controls in all views. Press Tab or Enter, or click
outside of the control configuration menu to return to the live script.
To specify the minimum, maximum, and step values for a slider or spinner using variables, right-click
the control and select Configure Control. Then, in the Values section, select a workspace variable
for Min, Max, and Step. Only variables with numeric values of type double appear in the drop-down
list. If the variables that you want to select are not listed, try running the live script first to create the
variables in the workspace. Changes to the variables are automatically reflected in the slider or
spinner.
To populate the items in a drop-down list using the values stored in a variable, right-click the control
and select Configure Control. Then, in the Items section, select a workspace variable from the
Variable list. The variable must be a string array or a categorical array, character array, cell array, or
double array, to appear in the list. If the variable that you want to select is not listed, try running the
live script first to create the variable in the workspace. Changes to the variable are automatically
reflected in the drop-down list.
For example, create a live script and define the variable lastnames containing a list of last names.
19-40
Add Interactive Controls to a Live Script
lastnames = ["Houston","Vega","Obrien","Potter","Rivera","Hanson","Fowler","Tran","Briggs"];
Run the live script to create lastnames in the workspace. Then, go to the Live Editor tab, and in
the Code section, select Control > Drop Down. In the Items section of the control configuration
menu, select lastnames as the Variable.
Close the configuration menu to return to the live script. The drop-down list now contains the last
names defined in lastnames.
If you add, remove, or edit the values in lastnames, MATLAB updates the items in the drop-down list
accordingly.
Note If the items in a drop-down list are linked to a variable, and one or more of the values in the
variable are deleted while the live script is running, an error can occur if one of the deleted values
was the selected list item. To minimize the potential for this error, avoid deleting values from a linked
variable while the live script is running.
19-41
19 Live Scripts and Functions
To set the default value for a control, right-click the control and select Configure Control. Then, in
the Defaults section, specify a default value by entering the value or by selecting a workspace
variable from the list. The list shows only valid variables for the control. For drop-down lists, select
the default value from the list of items.
To restore the default value for a control, right-click the control and select Restore Default Value.
To restore the default values for all controls in a live script, right-click any control in the live script
and select Restore Default Values for All Controls.
Tip To link the value of a control to a workspace variable, set the default value for the control to that
variable. The control value is set to the default value and changes as the variable value changes. The
control value stays linked to the variable value until the control value is changed manually, for
example, by moving the slider thumb of a slider.
Field Options
Run On (sliders and spinners only) Select one of these options to specify when the
code runs:
19-42
Add Interactive Controls to a Live Script
Field Options
Run Select one of these options to specify what code
runs when the value of the control changes:
This example shows how you can use interactive controls to visualize and investigate patient data in
MATLAB. Using a variety of interactive controls, you can filter a list of patients and then plot the age
and systolic blood pressure of the filtered list, highlighting the patients over a specified blood
pressure.
The example uses variables to control the slider and spinner values, as well as the drop-down list
items. For instance, to filter the patient list by location, insert a drop-down list and select the
locationStrings variable to populate the items in the list. To filter the patient list by age, insert a
slider and select the minAge and maxAge variables as the Min and Max values. To specify a
threshold systolic blood pressure, insert a spinner and select the minPressure and maxPressure
variables as the Min and Max values.
To filter the data only when the Filter Data button is pressed, set the Run execution option for the
drop-down list, checkbox, slider, and edit field to Nothing.
19-43
19 Live Scripts and Functions
To view and interact with the controls, open this example in your browser or in MATLAB.
Use the file browser to select a file containing patient data and then create a table from the patient
data. Use the drop-down list, checkbox, slider, and edit field to specify patient filtering information
such as location, smoking status, age, and the letters present in the patient last name. Use the Filter
Data button to filter the data.
filename = ;
T = readtable(filename);
selectedLocation = ;
isSmoker = ;
maxAge = max(T.Age);
minAge = min(T.Age);
minimumAge = ;
nameContains = ;
19-44
Add Interactive Controls to a Live Script
Plot the age and systolic blood pressure of the filtered patient data, highlighting the patients over a
specified blood pressure. Use the spinner to specify the threshold blood pressure value.
minPressure = min(TFiltered.Systolic);
maxPressure = max(TFiltered.Systolic);
thresholdPressure = ;
TOverThreshold = TFiltered(TFiltered.Systolic>=thresholdPressure,:);
sp1 = scatter(TFiltered.Age,TFiltered.Systolic);
hold on
sp2 = scatter(TOverThreshold.Age,TOverThreshold.Systolic,"red");
hold off
19-45
19 Live Scripts and Functions
If you share the live script itself as an interactive document, consider hiding the code in the live
script before sharing it. When the code is hidden, the Live Editor displays only formatted text, labeled
controls, tasks, and output. If a task in the live script is configured to show only code and no controls,
then the task does not display when you hide the code. To hide the code, click the Hide code button
to the right of the live script. You also can go to the View tab, and in the View section, click Hide
Code.
If you share the live script as a PDF file, Microsoft Word document, HTML file, LaTeX file, Markdown
file, or Jupyter notebook, the Live Editor saves the controls as code. For example, if the “Create Live
Script with Multiple Interactive Controls” on page 19-43 example live script is exported to HTML
(using the Export options on the Live Editor tab), the file browser control is replaced with its
current value ("patients.xls"), the drop-down list control is replaced with its current value
(locationStrings(1)), the check box control is replaced with its current value (false), the slider
control is replaced with its current value (31), and the text box control is replaced with its current
value ("e"). The Filter Data button is not displayed.
19-46
Add Interactive Controls to a Live Script
See Also
export
More About
• “Add Interactive Tasks to a Live Script” on page 19-48
• “Ways to Share and Export Live Scripts and Functions” on page 19-62
19-47
19 Live Scripts and Functions
Tasks represent a series of MATLAB commands. You can display their output either inline or on the
right. To see the MATLAB commands that the task runs, show the generated code.
Insert Tasks
To add a task to a live script, go to the Live Editor tab, click Task , and select from the
available tasks. You also can type the name of the task in a live script code block. As you type, the
Live Editor displays possible matches, and you can select and insert the desired task. For example,
create a live script that creates a vector of data containing an outlier.
Add the Create Plot task to your live script to plot the vector of data.
19-48
Add Interactive Tasks to a Live Script
Add the Clean Outlier Data task to your live script to smooth the noisy data and avoid skewed results.
To add the task, start typing the word clean in the live script and select Clean Outlier Data from
the suggested command completions. In the task, set Input data to A. The task identifies and fills
two outliers in the data and creates the variable cleanedData in the MATLAB workspace with the
stored results. You also can see the results in the output plot for the task. Continue modifying
additional parameters until you are satisfied with the results.
19-49
19 Live Scripts and Functions
To restore all parameter values back to their defaults, click the Options button ( ) in the top-right
corner of the task and select Restore Default Values.
19-50
Add Interactive Tasks to a Live Script
When you are done modifying parameters, you can collapse the task to help with readability. To
collapse the task, click the arrow at the top-left of the task.
Delete Tasks
To delete a task, click the Options button ( ) in the top-right corner of the task and select Remove
Task. Alternatively, select the task and then press the Delete or Backspace key.
The selected Autorun checkbox in the top-right corner of the task window indicates that the task
runs automatically when you modify the task parameters.
To disable running the task automatically when you modify the task parameters, clear the Autorun
checkbox. Then, to run the task and current section, click the Run current section button to the
19-51
19 Live Scripts and Functions
left of the Autorun checkbox. Some tasks do not run automatically by default. This default setting
ensures optimal performance for those tasks.
You also can change what code runs when the values of parameters in the task change. To change
what code runs, click the Options button ( ) in the top-right corner of the task, select Run
Configuration and then select from the available options:
• Current section (default) — Run the section that contains the task. To run only the task, add
section breaks before and after the task. For more information about sections and how to add
section breaks, see “Create and Run Sections in Code” on page 18-6.
• Current section and modified or not yet run sections above — Run the current section and
any modified or not-yet-run code above the task. If the live script has not yet been run, changing
the values of parameters in the task runs the current section and all sections before it.
• Current section to end — Run the section that contains the task and any sections that follow.
• All sections — Run all sections in the live script.
You can use the resulting output argument in subsequent code, including as inputs to additional Live
Editor tasks.
To edit the generated code, click the Options button ( ) and select Convert to Code. This option
removes the task and replaces it with the generated code, which you then can edit.
19-52
Add Interactive Tasks to a Live Script
See Also
More About
• “Add Interactive Controls to a Live Script” on page 19-37
• “Clean Messy Data and Locate Extrema Using Live Editor Tasks”
• “Live Editor Task Development Overview”
• MATLAB Live Script Gallery
19-53
19 Live Scripts and Functions
Live functions are program files that contain code and formatted text together in a single interactive
environment called the Live Editor. Similar to live scripts, live functions allow you to reuse sequences
of commands by storing them in program files. Live functions provide more flexibility, though,
primarily because you can pass them input values and receive output values.
If you have an existing function, you can open it as a live function in the Live Editor. Opening a
function as a live function creates a copy of the file and leaves the original file untouched. MATLAB
converts publishing markup from the original script to formatted content in the new live function.
To open an existing function (.m) as a live function (.mlx) from the Editor, right-click the document
tab and select Open functionName as Live Function from the context menu.
Alternatively, go to the Editor tab, click Save , and select Save As. Then, set the Save as type: to
MATLAB Live Code Files (*.mlx) and click Save.
Note You must use one of the described conversion methods to convert your function to a live
function. Simply renaming the function with a .mlx extension does not work and can corrupt the file.
If you have an existing large live script or function, you can break it into smaller pieces by
automatically converting selected areas of code into functions or local functions. This is called code
refactoring.
To refactor a selected area of code, select one or more lines of code and on the Live Editor tab, in
the Code section, click Refactor. Then, select from the available options. MATLAB creates a
function with the selected code and replaces the original code with a call to the newly created
function.
Add Code
After you create the live function, add code to the function and save it. For example, add this code
and save it as a function called mymean.mlx. The mymean function calculates the average of the
input list and returns the results.
function a = mymean(v,n)
a = sum(v)/n;
end
19-54
Create Live Functions
Add Help
To document the function, add formatted help text above the function definition. For example, add a
title and some text to describe the functionality. For more information about adding help text to
functions, see “Add Help for Live Functions” on page 19-57.
To run a live function from the Command Window, enter the name of the function in the Command
Window. For example, use mymean.mlx to calculate the mean of 10 sequential numbers from 1 to 10.
mymean(1:10, 10)
ans =
5.5000
You also can call the live function from a live script. For example, create a live script called
mystats.mlx. Add this code that declares an array, determines the length of the array, and passes
both values to the function mymean.
x = 1:10;
n = length(x);
avg = mymean(x,n);
disp(['Average = ', num2str(avg)])
Run the live script. The Live Editor displays the output.
If a live function displays text or returns values, the Live Editor displays the output in the calling live
script, in line with the call to the live function. For example, add a line to mymean that displays the
calculated mean before returning the value:
function a = mymean(v,n)
a = sum(v)/n;
19-55
19 Live Scripts and Functions
When you run mystats, the Live Editor displays the output for mymean with the output from
mystats.
In MATLAB Online, you can use the Run button to run live functions interactively. When you run a
live function using the Run button, the output displays in the Command Window. To run live
functions that require input argument values or any other additional setup, configure the Run
button by clicking Run and adding one or more commands. For more information about configuring
the Run button, see “Configure the Run Button for Functions” on page 20-7.
1 On the Live Editor tab, in the File section, select Save > Save As....
2 In the dialog box that appears, select MATLAB Code files (UTF-8) (*.m) as the Save as
type.
3 Click Save.
See Also
More About
• “Add Help for Live Functions” on page 19-57
19-56
Add Help for Live Functions
function c = addme(a,b)
switch nargin
case 2
c = a + b;
case 1
c = a + a;
otherwise
c = 0;
end
Insert a line immediately before the function definition line. Then, go to the Live Editor tab, and
click the Text button. The code line becomes a text line. Add help text to describe the function.
To add "See also" links, at the end of the help text, add a blank text line and then add a line that
begins with the words See also followed by a list of function names.
If the functions exist on the search path or in the current folder, the help command displays each of
these function names as a hyperlink to its help text. Otherwise, help prints the function names as
they appear in the help text. A blank line must precede the line containing the See also text for the
links to display correctly.
19-57
19 Live Scripts and Functions
When multiple files or functions have the same name, the help command determines which help text
to display by applying the rules described in “Function Precedence Order” on page 20-37. However,
if a file has the same name as a built-in function, the Help on Selection option in context menus
displays the documentation for the built-in function.
You also can add help to live functions by inserting comments at the beginning of the file. Comments
at the beginning of the file appear as help text when you use the help and doc commands, similar to
how text at the beginning of the file appears. For more information about adding help using
comments, see “Add Help for Your Program” on page 20-5.
Type doc addme to view the formatted help text in a separate browser.
19-58
Add Help for Live Functions
For example, in the addme function, add an equation to the second syntax description and create a
section for examples by adding a header and two MATLAB code examples before the "See Also" links.
1 In the addme function, position your cursor at the end of the second syntax description, go to the
Insert tab, and select Equation. Enter the equation c = a + b and press Esc.
2 With your cursor on a blank text line before the "See Also" links, go to the Live Editor tab and
select the Heading 1 text style. Type the word Examples.
3 Go to the Insert tab and select Code Example > MATLAB. Enter example code in the block
that appears.
For more information about formatting files in the Live Editor, see “Format Text in the Live Editor” on
page 19-20.
19-59
19 Live Scripts and Functions
See Also
export
More About
• “Create Live Functions” on page 19-54
• “Format Text in the Live Editor” on page 19-20
• “Create Runnable Examples Using the Live Editor” on page 19-90
• “Ways to Share and Export Live Scripts and Functions” on page 19-62
19-60
Add Help for Live Functions
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
19-61
19 Live Scripts and Functions
This table shows the different ways to share live scripts and functions.
For more information about the different export options, see the
corresponding name-value arguments for the export function.
19-62
Ways to Share and Export Live Scripts and Functions
When using the export function, you can customize the converted
file using name-value arguments. For example, you can hide the
code in the converted file, as well as customize the resolution and
format of figures, and the document paper size, orientation, and
margins.
Show the files as a full-screen With a live script or function open in the Live Editor, go to the
presentation. View tab and click the Full Screen button on. The Live Editor
shows the file in full-screen mode.
To exit full-screen mode, move the mouse to the top of the screen
to display the View tab and click the Full Screen button off.
Save the files as MATLAB plain With a live script or function open in the Live Editor, on the Live
code files (.m). Editor tab, in the File section, select Save > Save As. In the
dialog box that appears, select MATLAB Code files (UTF-8)
(*.m) from the Save as type list.
When you distribute the file, recipients can open and view the file
in MATLAB. MATLAB converts formatted content from the live
script or function to publishing markup in the new script or
function.
To save your live scripts or functions as plain code files
programmatically, use the export function and specify the
Format name-value argument as "m".
To hide the code, click the Hide code button to the right of the live script. You also can go to the
View tab, and in the View section, click Hide Code . To show the code again, click the Output
inline button or the Output on right button . Alternatively, if you are using the export function
to share your live script, you can hide the code using the HideCode name-value argument.
Note When exporting to PDF, Microsoft Word, HTML, LaTeX, Markdown, or Jupyter notebooks, the
Live Editor saves controls and tasks as code. If you have a live script that contains controls and tasks
and you hide the code before exporting, the converted file does not contain the controls or tasks.
19-63
19 Live Scripts and Functions
See Also
Functions
export
Settings
matlab.editor
Related Examples
• “Create Live Scripts in the Live Editor” on page 19-6
• “Format Text in the Live Editor” on page 19-20
• MATLAB Live Script Gallery
19-64
Live Code File Format (.mlx)
Source Control
To determine and display code differences between live scripts or functions, use the MATLAB
Comparison Tool.
If you use source control, register the .mlx extension as binary. For more information, see “Register
Binary Files with SVN” on page 35-27 or “Register Binary Files with Git” on page 35-13.
See Also
More About
• “What Is a Live Script or Function?” on page 19-2
• “Create Live Scripts in the Live Editor” on page 19-6
External Websites
• Open Packaging Conventions Fundamentals
• Office Open XML File Formats (ECMA-376)
19-65
19 Live Scripts and Functions
This example is an introduction to the Live Editor. In the Live Editor, you can create live scripts that
show output together with the code that produced it. Add formatted text, equations, images, and
hyperlinks to enhance your narrative, and share the live script with others as an interactive
document.
Create a live script in the Live Editor. To create a live script, on the Home tab, click New Live
Script.
Divide your live script into sections. Sections can contain text, code, and output. MATLAB® code
appears with a gray background and output appears with a white background. To create a new
section, go to the Live Editor tab and click the Section Break button.
pop = 1×11
75.9950 91.9720 105.7110 123.2030 131.6690 150.6970 179.3230 213.2120 228.5050 250.6
Sections can be run independently. To run the code in a section, go to the Live Editor tab and click
the Run Section button. You can also click the blue bar that appears when you move the mouse to
the left of the section. When you run a section, output and figures appear together with the code that
produced them.
19-66
Introduction to the Live Editor
Add supporting information to the text, including equations, images, and hyperlinks.
Let's try fitting the data with polynomials. We'll use the MATLAB polyfit function to get the
coefficients.
y = ax + b linear
y= ax2 + bx + c quadratic
y = ax3 + bx2 + cx + d . cubic
x = (years-1900)/50;
coef1 = polyfit(x,pop,1)
coef1 = 1×2
98.9924 66.1296
coef2 = polyfit(x,pop,2)
coef2 = 1×3
19-67
19 Live Scripts and Functions
coef3 = polyfit(x,pop,3)
coef3 = 1×4
We can plot the linear, quadratic, and cubic curves fitted to the data. We'll use the polyval function
to evaluate the fitted polynomials at the points in x.
pred1 = polyval(coef1,x);
pred2 = polyval(coef2,x);
pred3 = polyval(coef3,x);
[pred1; pred2; pred3]
ans = 3×11
66.1296 85.9281 105.7266 125.5250 145.3235 165.1220 184.9205 204.7190 224.5174 244.3
75.1904 89.5524 105.1225 121.9007 139.8870 159.0814 179.4840 201.0946 223.9134 247.9
80.1414 88.5622 101.4918 118.1050 137.5766 159.0814 181.7944 204.8904 227.5441 248.9
hold on
plot(years,pred1)
plot(years,pred2)
plot(years,pred3)
ylim([50 300])
legend({'Data' 'Linear' 'Quadratic' 'Cubic'},'Location', 'NorthWest')
hold off
19-68
Introduction to the Live Editor
You can share your live script with other MATLAB users so that they can reproduce your results. You
also can publish your results as PDF, Microsoft® Word, or HTML documents. Add controls to your
live scripts to show users how important parameters affect the analysis. To add controls, go to the
Live Editor tab, click the Control button, and select from the available options.
We can now calculate the predicted population of a given year using our three equations.
year = ;
xyear = (year-1900)/50;
pred1 = polyval(coef1,xyear);
pred2 = polyval(coef2,xyear);
pred3 = polyval(coef3,xyear);
[pred1 pred2 pred3]
ans = 1×3
19-69
19 Live Scripts and Functions
For the year 2010 for example, the linear and cubic fits predict similar values of about 284 million
people, while the quadratic fit predicts a much higher value of about 300 million people.
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• MATLAB Live Script Gallery
19-70
Accelerate Exploratory Programming Using the Live Editor
The following is an example of how to use the Live Editor to accelerate exploratory programming.
This example demonstrates how you can use the Live Editor to:
The Live Editor displays output together with the code that produced it. To run a section, go to the
Live Editor tab and select the Run Section button. You can also click the blue bar that appears
when you move your mouse to the left edge of a section.
In this example, we explore some highway fatality data. Start by loading the data. The variables are
shown as the column headers of the table.
load fatalities
fatalities(1:10,:)
ans=10×8 table
longitude latitude deaths drivers vehicles vehicleMile
_________ ________ ______ _______ ________ ___________
The Live Editor allows you to divide your program into sections containing text, code, and output. To
create a new section, go to the Live Editor tab and click the Section Break button. The code in a
section can be run independently, which makes it easy to explore ideas as you write your program.
Calculate the fatality rate per one million vehicle miles. From these values we can find the states with
the lowest and highest fatality rates.
states = fatalities.Properties.RowNames;
rate = fatalities.deaths./fatalities.vehicleMiles;
[~, minIdx] = min(rate); % Minimum accident rate
[~, maxIdx] = max(rate); % Maximum accident rate
disp([states{minIdx} ' has the lowest fatality rate at ' num2str(rate(minIdx))])
19-71
19 Live Scripts and Functions
Distribution of Fatalities
You can include visualizations in your program. Like output, plots and figures appear together with
the code that produced them.
We can use a bar chart to see the distribution of fatality rates among the states. There are 11 states
that have a fatality rate greater than 0.02 per million vehicle miles.
histogram(rate,10)
xlabel('Fatalities per Million Vehicle Miles')
ylabel('Number of States')
You can explore your data quickly in the Live Editor by experimenting with parameter values to see
how your results will change. Add controls to change parameter values interactively. To add controls,
go to the Live Editor tab, click the Control button, and select from the available options.
19-72
Accelerate Exploratory Programming Using the Live Editor
We can experiment with the data to see if any of the variables in the table are correlated with
highway fatalities. For example, it appears that highway fatality rates are lower in states with a
higher percentage urban population.
dataToPlot = ;
close % Close any open figures
scatter(fatalities.(dataToPlot),rate) % Plot fatalities vs. selected variable
xlabel(dataToPlot)
ylabel('Percent Fatalities per Million Vehicle Miles')
hold on
xmin = min(fatalities.(dataToPlot));
xmax = max(fatalities.(dataToPlot));
p = polyfit(fatalities.(dataToPlot),rate,1); % Calculate & plot least squares line
plot([xmin xmax], polyval(p,[xmin xmax]))
19-73
19 Live Scripts and Functions
Summarize your results and share your live script with your colleagues. Using your live script, they
can recreate and extend your analysis. You can also save your analysis as HTML, Microsoft® Word, or
PDF documents for publication.
Based on this analysis, we can summarize our findings using a plot of fatality rates and urban
population on a map of the continental United States.
load usastates.mat
figure
geoplot([usastates.Lat], [usastates.Lon], 'black')
geobasemap darkwater
hold on
geoscatter(fatalities.latitude,fatalities.longitude,2000*rate,fatalities.urbanPopulation,'filled'
c = colorbar;
title(c,'Percent Urban')
19-74
Accelerate Exploratory Programming Using the Live Editor
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• MATLAB Live Script Gallery
19-75
19 Live Scripts and Functions
The following is an example of how to create an interactive narrative in the Live Editor. An interactive
narrative ties together the computations that you use to solve a problem. This example shows how to:
Overall Approach
Include formatted text as part of the interactive narrative. Use bold, italic, and underlined text to
highlight important words. Use bullets or numbers to format lists.
Estimate the power output from a typical solar panel installation on a specific date, time, and location
by calculating the following:
• Solar time
• Solar declination and solar elevation
• Air mass and the solar radiation reaching the earth's surface
• Radiation on a solar panel given its position, tilt, and efficiency
• Power generated in a day and over the entire year
Use the results of these calculations to plot solar and panel radiation for the example day and
location. Then, plot the expected panel power generation over the course of a year. To streamline the
analysis, use two MATLAB functions created for this example: solarCorrection and
panelRadiation.
Solar Time
Show output together with the code that produced it. To run a section of code, go to the Live Editor
tab and click the Run Section button.
Power generation in a solar panel depends on how much solar radiation reaches the panel. This in
turn depends on the sun's position relative to the panel as the sun moves across the sky. For example,
suppose that you want to calculate power output for a solar panel on June 1st at 12 noon in Boston,
Massachusetts.
lambda = ; % longitude
phi = ; % latitude
19-76
Create an Interactive Narrative Using the Live Editor
localTime = datetime
01-Jun-2019 12:00:00
To calculate the sun's position for a given date and time, use solar time. Twelve noon solar time is the
time when the sun is highest in the sky. To calculate solar time, apply a correction to local time. That
correction has two parts:
• A term which corrects for the difference between the observer's location and the local meridian.
• An orbital term related to the earth's orbital eccentricity and axial tilt.
solarTime = datetime
01-Jun-2019 12:18:15
Include equations to describe the underlying mathematics. Create equations using LaTeX commands.
To add a new equation, go to the Insert tab and click the Equation button. Double-click an equation
to edit it in the Equation Editor.
The solar declination (δ) is the angle of the sun relative to the earth's equatorial plane. The solar
∘ ∘
declination is 0 at the vernal and autumnal equinoxes, and rises to a maximum of 23 . 45 at the
summer solstice. Calculate the solar declination for a given day of the year (d) using the equation
−1 360
δ = sin sin(23 . 45)sin (d − 81)
365
Then, use the declination (δ), the latitude (ϕ), and the hour angle (ω) to calculate the sun's elevation
(α) at the current time. The hour angle is the number of degrees of rotation of the earth between the
current solar time and solar noon.
−1
α = sin sinδsinϕ + cosδcosϕcosω
Calculate the time of sunrise and sunset in Standard Time using the sun's declination and the local
latitude.
19-77
19 Live Scripts and Functions
midnight = dateshift(localTime,'start','day');
sr = 12 - acosd(-tand(phi)*tand(delta))/15 - solarCorr/60;
sunrise = timeofday(midnight + hours(sr));
ss = 12 + acosd(-tand(phi)*tand(delta))/15 - solarCorr/60;
sunset = timeofday(midnight + hours(ss));
sunrise.Format = 'hh:mm:ss';
sunset.Format = 'hh:mm:ss';
disp('Sunrise = ' + string(sunrise) + ' Sunset = ' + string(sunset))
Include images to illustrate important points in your story. To include an image, copy and paste an
image from another source or go to the Insert tab and click the Image button.
As light from the sun passes through the earth's atmosphere, some of the solar radiation is absorbed.
Air mass is the length of the path of light through the atmosphere (Y) relative to the shortest possible
path (X) when the sun's elevation is 90∘, as shown in the diagram below. It is a function of solar
elevation (α).
The larger the air mass, the less radiation reaches the ground. Calculate the air mass using the
equation
1
airMass = −1 . 6364
cos(90 − α) + 0 . 5057(6 . 0799 + α) .
Then, calculate the solar radiation reaching the ground (in kilowatts per square meter) using the
empirical equation
0 . 678
solarRad = 1 . 353 * 0 . 7 AM .
19-78
Create an Interactive Narrative Using the Live Editor
Use hyperlinks to reference supporting information from other sources. To add a hyperlink, go to the
Insert tab and click the Hyperlink button.
Panels installed with a solar tracker can move with the sun and receive 100% of the sun's radiation as
the sun moves across the sky. However, most solar cell installations have panels set at a fixed azimuth
and tilt. Therefore, the actual radiation reaching the panel also depends on the solar azimuth. The
solar azimuth (γ) is the compass direction of the sun's position in the sky. At solar noon in the
∘
Northern hemisphere the solar azimuth is180 corresponding to the direction south. Calculate the
solar azimuth using the equation
sinδcosϕ − cosδsinϕcosω
cos−1 for solar time ≤ 12
cosα
γ=
∘ sinδcosϕ − cosδsinϕcosω
360 − cos−1 for solar time > 12
cosα
gamma = acosd((sind(delta)*cosd(phi) - cosd(delta)*sind(phi)*cosd(omega))/cosd(alpha));
if (hour(solarTime) >= 12) && (omega >= 0)
gamma = 360 - gamma;
end
disp(['Solar Azimuth = ' num2str(gamma)])
In the northern hemisphere, a typical solar panel installation has panels oriented toward the south
∘ ∘
with a panel azimuth (β) of 180 . At northern latitudes, a typical tilt angle (τ) is 35 . Calculate the
panel radiation for fixed panels from the total solar radiation using the equation
Modify parameters using interactive controls. Display plots together with the code that produced
them.
Panel Radiation
For a given day of the year, calculate the total solar radiation and the radiation on the panel. To
simplify the analysis, use the panelRadiation function. Try different dates to see how the solar and
panel radiation change depending on the time of year.
selectedMonth = ;
selectedDay = ;
selectedDate = datetime(2019,selectedMonth,selectedDay);
[times,solarRad,panelRad] = panelRadiation(selectedDate,lambda,phi,UTCoff,tau,beta) ;
19-79
19 Live Scripts and Functions
plot(times,solarRad,times,panelRad)
Power Generation
So far, the calculations assume that all of the radiation reaching the panel is available to generate
power. However, solar panels do not convert 100% of available solar radiation into electricity. The
efficiency of a solar panel is the fraction of the available radiation that is converted. The efficiency of
a solar panel depends on the design and materials of the cell.
Typically, a residential installation includes 20m2 of solar panels with an efficiency of 25%. Modify the
parameters below to see how efficiency and size affect panel power generation.
selectedDate.Format = 'dd-MMM-yyyy';
disp('Expected daily electical output for ' + string(selectedDate) + ' = ' + num2str(dayPower) +
19-80
Create an Interactive Narrative Using the Live Editor
Hover over a plot to interact with it. Interacting with a plot in the Live Editor will generate code that
you can then add to your script.
Repeat the calculation to estimate power generation for each day of the year.
plot(yearDates,dailyPower)
title('Yearly Power Generation')
xlabel('Date');
ylabel('Power Generation, kW-hrs')
yearlyPower = sum(dailyPower);
disp(['Expected annual power output = ' num2str(yearlyPower) ' kW-hrs'])
19-81
19 Live Scripts and Functions
Use a heatmap to determine how panel tilt affects power generation. The heatmap below shows that
the optimal panel tilt for any location is about 5∘ less than the latitude.
load LatitudeVsTilt.mat
heatmap(powerTbl,'Tilt','Latitude',...
'ColorVariable','Power');
xlabel('Panel Tilt')
ylabel('Latitude')
title('Normalized Power Output')
Share your analysis with colleagues. Invite them to reproduce or extend your analysis. Work
collaboratively using the Live Editor.
In reality, true power output from a solar installation is significantly affected by local weather
conditions. An interesting extension of this analysis would be to see how cloud cover affects the
results. In the US, you can use data from these government websites.
• Use historical local weather data from the National Weather Service website.
19-82
Create an Interactive Narrative Using the Live Editor
• Use measured solar radiation data from the National Solar Radiation Database.
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• “Format Text in the Live Editor” on page 19-20
• MATLAB Live Script Gallery
19-83
19 Live Scripts and Functions
The following is an example of how to use live scripts in the classroom. This example shows how to:
Add equations to explain the underlying mathematics for concepts that you want to teach. To add an
equation, go to the Insert tab and click the Equation button. Then, select from the symbols and
structures in the Equation tab.
Today we're going to talk about finding the roots of 1. What does it mean to find the nth root of 1?
The nth roots of 1 are the solutions to the equation xn − 1 = 0.
For square roots, this is easy. The values are x = ± 1 = ± 1. For higher-order roots, it gets a bit
more difficult. To find the cube roots of 1 we need to solve the equation x3 − 1 = 0. We can factor this
equation to get
x − 1 x2 + x + 1 = 0 .
So the first cube root is 1. Now we can use the quadratic formula to get the second and third cube
roots.
2
−b ± b − 4ac
x=
2a
To execute individual sections of MATLAB code, go to the Live Editor tab and click the Run Section
button. Output appears together with the code that created it. Create sections using the Section
Break button.
In our case a, b, and c are all equal to 1. The other two roots are calculated from these formulas:
a = 1 ; b = 1 ; c = 1;
roots = [];
roots(1) = 1;
roots(2) = (-b + sqrt(b^2 - 4*a*c))/(2*a); % Use the quadratic formula
roots(3) = (-b - sqrt(b^2 - 4*a*c))/(2*a);
disp(roots.')
19-84
Create Interactive Course Materials Using the Live Editor
1.0000 + 0.0000i
-0.5000 + 0.8660i
-0.5000 - 0.8660i
Include plots in the Live Editor so students can visualize important concepts.
We can visualize the roots in the complex plane to see their location.
range = 0:0.01:2*pi;
plot(cos(range),sin(range),'k') % Plot the unit circle
axis square; box off
ax = gca;
ax.XAxisLocation = 'origin';
ax.YAxisLocation = 'origin';
hold on
plot(real(roots), imag(roots), 'ro') % Plot the roots
To add supporting information, go to the Insert tab and click the Hyperlink and Image buttons.
Students can use supporting information to explore lecture topics outside of the classroom.
Once you get past n = 3, things get even trickier. For 4th roots we could use the quartic formula
discovered by Lodovico Ferrari in 1540. But this formula is long and unwieldy, and doesn't help us
find roots higher than 4. Luckily, there is a better way, thanks to a 17th century French
mathematician named Abraham de Moivre.
19-85
19 Live Scripts and Functions
Abraham de Moivre was born in Vitry in Champagne on May 26, 1667. He was a contemporary and
friend of Isaac Newton, Edmund Halley, and James Stirling. https://en.wikipedia.org/wiki/
Abraham_de_Moivre
He is best known for de Moivre's theorem that links complex numbers and trigonometry, and for his
work on the normal distribution and probability theory. De Moivre wrote a book on probability theory,
The Doctrine of Chances, said to have been prized by gamblers. De Moivre first discovered Binet's
formula, the closed-form expression for Fibonacci numbers linking the nth power of the golden ratio
φ to the nth Fibonacci number. He was also the first to postulate the Central Limit Theorem, a
cornerstone of probability theory.
De Moivre's theorem states that for any real x and any integer n,
n
cos x + i sin x = cos nx + i sin nx .
How does that help us solve our problem? We also know that for any integer k,
Use the Live Editor to experiment with MATLAB code interactively. Add controls to show students
how important parameters affect the analysis. To add controls, go to the Live Editor tab, click the
Control button, and select from the available options.
We can use this last equation to find the nth roots of 1. For example, for any value of n, we can use
the formula above with values of k = 0…n − 1. We can use this MATLAB code to experiment with
different values of n:
n = ;
roots = zeros(1, n);
for k = 0:n-1
roots(k+1) = cos(2*k*pi/n) + 1i*sin(2*k*pi/n); % Calculate the roots
19-86
Create Interactive Course Materials Using the Live Editor
end
disp(roots.')
1.0000 + 0.0000i
0.5000 + 0.8660i
-0.5000 + 0.8660i
-1.0000 + 0.0000i
-0.5000 - 0.8660i
0.5000 - 0.8660i
Plotting the roots in the complex plane shows that the roots are equally spaced around the unit circle
at intervals of 2π/n.
cla
plot(cos(range),sin(range),'k') % Plot the unit circle
hold on
plot(real(roots),imag(roots),'ro') % Plot the roots
Use additional examples to reinforce important concepts. Modify code during the lecture to answer
questions or explore ideas in more depth.
We can find the roots of -1, i, and -i just by using extensions of the approach described above. If we
look at the unit circle we see that the values of 1, i, -1, -i appear at angles 0, π/2, π, and 3π/2
respectively.
19-87
19 Live Scripts and Functions
r = ones(1,4);
theta = [0 pi/2 pi 3*pi/2];
[x,y] = pol2cart(theta,r);
cla
plot(cos(range),sin(range),'k') % Plot the unit circle
hold on
plot(x, y, 'ro') % Plot the values of 1, i, -1, and -i
text(x(1)+0.05,y(1),'1') % Add text labels
text(x(2),y(2)+0.1,'i')
text(x(3)-0.1,y(3),'-1')
text(x(4)-0.02,y(4)-0.1,'-i')
1/n 1/n
i = cos 2k + 1/2 π + i sin 2k + 1/2 π
19-88
Create Interactive Course Materials Using the Live Editor
Homework
Use live scripts as the basis for assignments. Give students the live script used in the lecture and
have them complete exercises that test their understanding of the material.
Exercise 3: Describe the mathematical approach you would use to calculate the nth roots of an
arbitrary complex number. Include the equations you used in your approach.
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• MATLAB Live Script Gallery
19-89
19 Live Scripts and Functions
In the Live Editor, you can create documentation for your code that includes runnable code examples.
To allow your users to experiment with different inputs to your code, include interactive controls in
the examples. You can then distribute the documentation with your code to help make your code more
useable.
This example uses formatted text, equations, and runnable code to document the sample function
estimatePanelOutput. The sample documentation includes runnable examples with edit fields and
a slider that allow users of the function to experiment with different function inputs.
To view and interact with the controls in the sample documentation, open this example in MATLAB®.
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• “Add Help for Live Functions” on page 19-57
19-90
Create Runnable Examples Using the Live Editor
19-91
19 Live Scripts and Functions
In the Live Editor, you can create interactive forms or simple apps to perform small, repeatable tasks.
When creating these forms or apps, you can use interactive controls to prompt for input and perform
the tasks. To show only the formatted text, controls, and results to the user, hide the code.
This example shows how to create a basic interactive form in the Live Editor that completes a
calculation based on input provided by a user. The form uses a drop-down list and numeric sliders to
prompt the user for input, and then uses a button to run a calculation and plot a graph using the
provided input.
To view and interact with the Solar Panel Output Estimator form, open this example in MATLAB®.
19-92
Create an Interactive Form Using the Live Editor
19-93
19 Live Scripts and Functions
You can open a copy of the Solar Panel Output Estimator form by opening this example in MATLAB.
To recreate the form yourself, create a live script named SolarPanelEstimatorForm.mlx. Then,
add the descriptive text and code, configure the controls, and hide the code.
Copy the descriptive text and code in the Code for Solar Panel Output Estimator Form on page 19-95
section to calculate the output of a set of solar panels based on the location, size, and efficiency of the
panels.
The form uses a drop-down list and numeric sliders to prompt the user for input and a button to run a
calculation and plot a graph using the provided input.
When you copy the code, the controls are replaced with their current value. To add the controls back
into the code, replace the value of the location variable with a drop-down list and the values of the
pSize and eff variables with numeric sliders. Then, configure the controls by right-clicking them,
selecting Configure Control, and specifying the control options as follows:
• location drop-down list — Set the Label to Location: and the Item labels and Item values to a
set of locations and their corresponding coordinates. Set the Run execution option to Nothing.
• pSize slider — Set the Label to Panel Size (m^2): and the Min and Max values to 0 and 40,
respectively. Set the Run execution option to Nothing.
• eff slider — Set the Label to Panel Efficiency: and the Min and Max values to 0 and 100,
respectively. Set the Run execution option to Nothing.
19-94
Create an Interactive Form Using the Live Editor
To add the button back into the code, at the end of the code, insert a button. Then, configure the
button by right-clicking it and selecting Configure Control. Set the Label to Calculate and the
Run execution option to Current section. When a user presses the button, the code in the current
section runs, updating the calculation based on the current values of the drop-down list and sliders.
To view the example as a form, with the code hidden and only the controls and results visible, go to
the View tab and click Hide Code. Users can now interact with the form by choosing from the drop-
down list, adjusting the sliders, and clicking the button to view the results. The Live Editor calculates
solar panel output estimates based on user-provided inputs.
This section provides the complete contents of the SolarPanelEstimatorForm.mlx live script file,
including the descriptive text, code, and sample results.
location = ;
lambda = location(2); % Longitude
phi = location(1); % Latitude
UTCoff = location(3); % UTC offset
if(UTCoff < 0)
TZ = "UTC" + num2str(UTCoff);
else
TZ = "UTC+" + num2str(UTCoff);
end
localYear = 2018;
localMonth = 6;
localDay = 1;
localHour = 12;
localTime = datetime(localYear,localMonth,localDay,localHour,0,0,"TimeZone",TZ);
19-95
19 Live Scripts and Functions
Results:
plot(times,sRad,times,pRad)
title("Solar and Panel Radiation for " + string(date,"mmmm dd yyyy"))
xlabel("Hour of Day");
ylabel("Radiation, kW/m^2")
legend("Available Solar Radiation","Solar Radiation on Panel","Location","South")
19-96
Create an Interactive Form Using the Live Editor
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• MATLAB Live Script Gallery
19-97
19 Live Scripts and Functions
In the Live Editor, you can create dashboards to display and analyze real-time data. When creating
these dashboards, you can use buttons to retrieve and display real-time data on demand, and other
interactive controls to modify the displayed data. To show only the formatted text, controls, and
results to the dashboard user, hide the code.
This example shows how to create a simple weather dashboard in the Live Editor. The dashboard uses
a button and a check box to get and display real-time weather data.
To view and interact with the weather dashboard, open this example in MATLAB®.
You can open a copy of the weather dashboard by opening this example in MATLAB. To recreate the
dashboard yourself, create a live script named WeatherDashboard.mlx. Then, add the descriptive
text and code, configure the controls, and hide the code.
Copy the descriptive text and code in the Code for Weather Dashboard on page 19-99 section to get
and display real-time data from ThingSpeak™ channel 12397. This channel collects weather data
from an Arduino-based weather station in Natick, Massachusetts.
19-98
Create a Real-Time Dashboard Using the Live Editor
The dashboard uses a button to update the displayed weather data and a check box to toggle the
units used.
When you copy the code, the controls are replaced with their current value. To add the controls back
into the code, insert a button at the beginning of the live script and replace the useSIUnits variable
with a check box. Then, configure the controls by right-clicking them, selecting Configure Control,
and specifying the control options as follows:
• Button — Set the label to Update and set the Run execution option to Current section. When
a user presses the button, the code in the current section runs, updating the weather data
displayed in the dashboard.
• Check box — Set label to Use SI units and set the Run execution option to Current
section. When a user selects or clears the check box, the displayed weather data updates to
show the selected units.
To view the example as a dashboard, with the code hidden and only the controls and results visible,
go to the View tab and click Hide Code. Users can now interact with the dashboard by clicking the
button to get weather updates and toggling the check box to change units. The Live Editor retrieves
and displays weather data based on user-provided inputs.
This section provides the complete contents of the WeatherDashboard.mlx live script file, including
the descriptive text, code, and sample output.
Weather in Natick, MA
data = thingSpeakRead(12397,"NumDays",2,"Timeout",10,"OutputFormat","table");
latestValues = height(data);
useSIUnits = ;
if useSIUnits == 0
disp("Current conditions: Temperature " + data.TemperatureF(latestValues) + ...
"F, Humidity " + data.Humidity(latestValues) + "%, Wind " + ...
data.WindSpeedmph(latestValues) + " mph")
19-99
19 Live Scripts and Functions
plotWeatherData(data.Timestamps,data.TemperatureF,"F",data.WindSpeedmph, ...
"mph",data.Humidity)
else
tempC = (5/9)*(data.TemperatureF-32);
tempC = round(tempC,2);
windkmh = data.WindSpeedmph*1.60934;
disp("Current conditions: Temperature " + tempC(latestValues) + "C, Humidity " + ...
data.Humidity(latestValues) + "%, Wind " + windkmh(latestValues) + "vkph")
plotWeatherData(data.Timestamps,tempC,"C",windkmh,"kph",data.Humidity)
end
function plotWeatherData(timestamps,tempData,tempUnits,windData,windUnits,humidityData)
tiledlayout(3,1);
nexttile
plot(timestamps,tempData)
xlabel("Date")
ylabel("Temp (" + tempUnits + ")")
title("Temperature (past 2 days)")
nexttile
plot(timestamps,humidityData)
xlabel("Date")
19-100
Create a Real-Time Dashboard Using the Live Editor
ylabel("Humidity (%)")
title("Humidity (past 2 days)")
nexttile
plot(timestamps,windData)
xlabel("Date")
ylabel("Wind Speed (" + windUnits + ")")
title("Wind (past 2 days)")
end
See Also
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• MATLAB Live Script Gallery
19-101
19 Live Scripts and Functions
Acknowledgments
MATLAB Live Editor uses Antenna House® XSL Formatter. Antenna House is a trademark of Antenna
House, Inc.
19-102
20
Function Basics
function f = fact(n)
f = prod(1:n);
end
This type of function must be defined within a file, not at the command line. Often, you store a
function in its own file. In that case, the best practice is to use the same name for the function and
the file (in this example, fact.m), since MATLAB associates the program with the file name. Save the
file either in the current folder or in a folder on the MATLAB search path.
You can call the function from the command line, using the same syntax rules that apply to functions
installed with MATLAB. For instances, calculate the factorial of 5.
x = 5;
y = fact(5)
y =
120
Another option for storing functions is to include them in a script file. For instance, create a file
named mystats.m with a few commands and two functions, fact and perm. The script calculates
the permutation of (3,2).
x = 3;
y = 2;
z = perm(x,y)
function p = perm(n,r)
p = fact(n)/fact(n-r);
end
function f = fact(n)
f = prod(1:n);
end
Local functions in scripts must be defined at the end of the file, after the last line of script code.
mystats
z =
20-2
Create Functions in Files
The first line of every function is the definition statement, which includes the following elements.
If your function returns more than one output, enclose the output
names in square brackets.
function myFunction(x)
function [] = myFunction(x)
Function name (required) Valid function names follow the same rules as variable names. They
must start with a letter, and can contain letters, digits, or
underscores.
Note To avoid confusion, use the same name for both the function file
and the first function within the file. MATLAB associates your
program with the file name, not the function name. Script files cannot
have the same name as a function in the file.
Input arguments (optional) If your function accepts any inputs, enclose their names in
parentheses after the function name. Separate inputs with commas.
function y = myFunction(one,two,three)
Tip When you define a function with multiple input or output arguments, list any required arguments
first. This ordering allows you to call your function without specifying optional arguments.
Program files can contain multiple functions. If the file contains only function definitions, the first
function is the main function, and is the function that MATLAB associates with the file name.
Functions that follow the main function or are included in script code are called local functions. Local
functions are only available within the file.
20-3
20 Function Basics
End Statements
Functions end with either an end statement, the end of the file, or the definition line for a local
function, whichever comes first. The end statement is required if:
• Any function in the file contains a nested function (a function completely contained within its
parent).
• The function is a local function within a function file, and any local function in the file uses the end
keyword.
• The function is a local function within a script file.
See Also
function
More About
• “Files and Folders That MATLAB Accesses”
• “Base and Function Workspaces” on page 20-9
• “Types of Functions” on page 20-17
• “Add Functions to Scripts” on page 18-13
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
20-4
Add Help for Your Program
This example shows how to provide help for the programs you write. Help text appears in the
Command Window when you use the help function.
Create help text by inserting comments at the beginning of your program. If your program includes a
function, position the help text immediately below the function definition line (the line with the
function keyword). If the function contains an arguments block, you also can position the help text
immediately below the arguments block.
For example, create a function in a file named addme.m that includes help text:
function c = addme(a,b)
% ADDME Add two values together.
% C = ADDME(A) adds A to itself.
%
% C = ADDME(A,B) adds A and B together.
%
% See also SUM, PLUS.
switch nargin
case 2
c = a + b;
case 1
c = a + a;
otherwise
c = 0;
end
When you type help addme at the command line, the help text displays in the Command Window:
The first help text line, often called the H1 line, typically includes the program name and a brief
description. The Current Folder browser and the help and lookfor functions use the H1 line to
display information about the program.
Create See also links by including function names at the end of your help text on a line that begins
with % See also. If the function exists on the search path or in the current folder, the help
command displays each of these function names as a hyperlink to its help. Otherwise, help prints the
function names as they appear in the help text.
You can include hyperlinks (in the form of URLs) to Web sites in your help text. Create hyperlinks by
including an HTML <a></a> anchor element. Within the anchor, use a matlab: statement to
execute a web command. For example:
20-5
20 Function Basics
End your help text with a blank line (without a %). The help system ignores any comment lines that
appear after the help text block.
Note When multiple programs have the same name, the help command determines which help text
to display by applying the rules described in “Function Precedence Order” on page 20-37. However,
if a program has the same name as a MathWorks function, the Help on Selection option in context
menus always displays documentation for the MathWorks function.
See Also
help | lookfor
Related Examples
• “Add Comments to Code” on page 18-3
• “Add Help for Live Functions” on page 19-57
• “Create Help for Classes” on page 32-2
• “Create Help Summary Files — Contents.m” on page 32-8
• “Use Help Files with MEX Functions”
• “Display Custom Documentation” on page 32-20
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
20-6
Configure the Run Button for Functions
To configure the Run button in the Editor, click Run and add one or more run commands.
For example:
1 Create the function myfunction.m that performs a calculation using the inputs x and y and
stores the results in z.
function z = myfunction(x,y)
z = x.^2 + y;
2 Go to the Editor tab and click Run . MATLAB displays the list of commands available for
running the function.
3 Click the last item in the list and replace the text type code to run with a call to the function
including the required input arguments. For example, enter the text result =
myfunction(1:10,5) to run myfunction with the input arguments 1:10 and 5, and store the
results in the variable result. MATLAB replaces the default command with the newly added
command.
To run multiple commands at once, enter the commands on the same line. For example, enter the
text a = 1:10; b = 5; result = myfunction(a,b) to create the variables a and b and
then call myfunction with a and b as the input arguments.
Note If you define a run command that creates a variable with the same name as a variable in
the base workspace, the run command variable overwrites the base workspace variable when you
run that run command.
4
Click the Run
button. MATLAB runs the function using the first run command in the list. For example, click
20-7
20 Function Basics
Run to run
myfunction using the command result = myfunction(1:10,5). MATLAB displays the
result in the Command Window.
result =
6 9 14 21 30 41 54 69 86
To run the function using a different run command from the list, click Run and select the
desired command. When you select a run command from the list, it becomes the default for the
Run button.
To edit or delete an existing run command, click Run , right-click the command, and then select
Edit or Delete.
See Also
More About
• “Calling Functions”
• “Create Functions in Files” on page 20-2
• “Create Live Functions” on page 19-54
20-8
Base and Function Workspaces
The base workspace stores variables that you create at the command line. This includes any variables
that scripts create, assuming that you run the script from the command line or from the Editor.
Variables in the base workspace exist until you clear them or end your MATLAB session.
Functions do not use the base workspace. Every function has its own function workspace. Each
function workspace is separate from the base workspace and all other workspaces to protect the
integrity of the data. Even local functions in a common file have their own workspaces. Variables
specific to a function workspace are called local variables. Typically, local variables do not remain in
memory from one function call to the next.
When you call a script from a function, the script uses the function workspace.
Like local functions, nested functions have their own workspaces. However, these workspaces are
unique in two significant ways:
• Nested functions can access and modify variables in the workspaces of the functions that contain
them.
• All of the variables in nested functions or the functions that contain them must be explicitly
defined. That is, you cannot call a function or script that assigns values to variables unless those
variables already exist in the function workspace.
See Also
Related Examples
• “Share Data Between Workspaces” on page 20-10
More About
• “Nested Functions” on page 20-27
20-9
20 Function Basics
Introduction
This topic shows how to share variables between workspaces or allow them to persist between
function executions.
In most cases, variables created within a function are local variables known only within that function.
Local variables are not available at the command line or to any other function. However, there are
several ways to share data between functions or workspaces.
For example, create two functions, update1 and update2, that share and modify an input value.
update2 can be a local function in the file update1.m, or can be a function in its own file,
update2.m.
function y1 = update1(x1)
y1 = 1 + update2(x1);
function y2 = update2(x2)
y2 = 2 * x2;
Call the update1 function from the command line and assign to variable Y in the base workspace:
X = [1,2,3];
Y = update1(X)
Y =
3 5 7
Nested Functions
A nested function has access to the workspaces of all functions in which it is nested. So, for example,
a nested function can use a variable (in this case, x) that is defined in its parent function:
function primaryFx
x = 1;
20-10
Share Data Between Workspaces
nestedFx
function nestedFx
x = x + 1;
end
end
When parent functions do not use a given variable, the variable remains local to the nested function.
For example, in this version of primaryFx, the two nested functions have their own versions of x that
cannot interact with each other.
function primaryFx
nestedFx1
nestedFx2
function nestedFx1
x = 1;
end
function nestedFx2
x = 2;
end
end
Persistent Variables
When you declare a variable within a function as persistent, the variable retains its value from one
function call to the next. Other local variables retain their value only during the current execution of
a function. Persistent variables are equivalent to static variables in other programming languages.
Declare variables using the persistent keyword before you use them. MATLAB initializes persistent
variables to an empty matrix, [].
For example, define a function in a file named findSum.m that initializes a sum to 0, and then adds to
the value on each iteration.
function findSum(inputvalue)
persistent SUM_X
if isempty(SUM_X)
SUM_X = 0;
end
SUM_X = SUM_X + inputvalue;
When you call the function, the value of SUM_X persists between subsequent executions.
• clear all
• clear functionname
• Editing the function file
To prevent clearing persistent variables, lock the function file using mlock.
20-11
20 Function Basics
Global Variables
Global variables are variables that you can access from functions or from the command line. They
have their own workspace, which is separate from the base and function workspaces.
• Any function can access and update a global variable. Other functions that use the variable might
return unexpected results.
• If you unintentionally give a “new” global variable the same name as an existing global variable,
one function can overwrite the values expected by another. This error is difficult to diagnose.
If you use global variables, declare them using the global keyword before you access them within
any particular location (function or command line). For example, create a function in a file called
falling.m:
function h = falling(t)
global GRAVITY
h = 1/2*GRAVITY*t.^2;
global GRAVITY
GRAVITY = 32;
y = falling((0:.1:5)');
The two global statements make the value assigned to GRAVITY at the command prompt available
inside the function. However, as a more robust alternative, redefine the function to accept the value
as an input:
function h = falling(t,gravity)
h = 1/2*gravity*t.^2;
GRAVITY = 32;
y = falling((0:.1:5)',GRAVITY);
Like global variables, these functions carry risks of overwriting existing data. Use them sparingly.
evalin and assignin are sometimes useful for callback functions in graphical user interfaces to
evaluate against the base workspace. For example, create a list box of variable names from the base
workspace:
function listBox
figure
lb = uicontrol('Style','listbox','Position',[10 10 100 100],...
20-12
Share Data Between Workspaces
'Callback',@update_listBox);
update_listBox(lb)
function update_listBox(src,~)
vars = evalin('base','who');
src.String = vars;
For other programming applications, consider argument passing and the techniques described in
“Alternatives to the eval Function” on page 2-77.
See Also
More About
• “Base and Function Workspaces” on page 20-9
20-13
20 Function Basics
Scoping issues can be the source of some coding problems. For instance, if you are unaware that
nested functions share a particular variable, the results of running your code might not be as you
expect. Similarly, mistakes in usage of local, global, and persistent variables can cause unexpected
results.
The Code Analyzer does not always indicate scoping issues because sharing a variable across
functions is not an error—it may be your intent. Use MATLAB function and variable highlighting
features to identify when and where your code uses functions and variables. If you have an active
Internet connection, you can watch the Variable and Function Highlighting video for an overview of
the major features.
For conceptual information on nested functions and the various types of MATLAB variables, see
“Sharing Variables Between Parent and Nested Functions” on page 20-27 and “Share Data Between
Workspaces” on page 20-10.
To enable and disable highlighting or to change the colors, click Preferences and select MATLAB
> Colors > Programming tools. In MATLAB Online, highlighting is enabled by default and
changing the preferences for highlighting is not available.
• Highlights all instances of a given function or local variable in sky blue when you place the cursor
within a function or variable name. For instance:
• Displays a variable with shared scope in teal blue, regardless of the cursor location. For instance:
x = ones(2,10);
20-14
Check Variable Scope in Editor
[n, m] = size(x);
rowTotals = zeros(1,n);
for i = 1:n
rowTotals(i) = addToSum;
end
end
When you run this code, instead of returning the sum of the values in each row and displaying:
ans =
10 10
MATLAB displays:
ans =
0 0 0 0 0 0 0 0 0 10
1
On the Home tab in the Environment section, click Preferences and select MATLAB >
Colors > Programming tools. Ensure that Automatically highlight and Variables with
shared scope are selected.
2 Copy the rowsum code into the Editor.
Notice the variable appears in teal blue, which indicates i is not a local variable. Both the
rowTotals function and the addToSum functions set and use the variable i.
The variable n, at line 6 appears in black, indicating that it does not span multiple functions.
20-15
20 Function Basics
Every reference to i highlights in sky blue and markers appear in the indicator bar on the right
side of the Editor.
A tooltip appears and displays the name of the function or variable and the line of code
represented by the marker.
7 Click a marker to navigate to the line indicated in tooltip for that marker.
This is particularly useful when your file contains more code than you can view at one time in the
Editor.
You can see similar highlighting effects when you click a function reference. For instance, click
addToSum.
20-16
Types of Functions
Types of Functions
In this section...
“Local and Nested Functions in a File” on page 20-17
“Private Functions in a Subfolder” on page 20-18
“Anonymous Functions Without a File” on page 20-18
Local functions are subroutines that are available within the same file. Local functions are the most
common way to break up programmatic tasks. In a function file, which contains only function
definitions, local functions can appear in the file in any order after the main function in the file. In a
script file, local functions can be added anywhere except within conditional contexts, such as if
statements and for loops. For more information, see “Add Functions to Scripts” on page 18-13.
Local functions in scripts must be defined at the end of the file, after the last line of script code.
For example, create a function file named myfunction.m that contains a main function,
myfunction, and two local functions, squareMe and doubleMe:
function b = myfunction(a)
b = squareMe(a)+doubleMe(a);
end
function y = squareMe(x)
y = x.^2;
end
function y = doubleMe(x)
y = x.*2;
end
You can call the main function from the command line or another program file, although the local
functions are only available to myfunction:
myfunction(pi)
ans =
16.1528
Nested functions are completely contained within another function. The primary difference between
nested functions and local functions is that nested functions can use variables defined in parent
functions without explicitly passing those variables as arguments.
Nested functions are useful when subroutines share data, such as applications that pass data
between components. For example, create a function that allows you to set a value between 0 and 1
using either a slider or an editable text box. If you use nested functions for the callbacks, the slider
and text box can share the value and each other’s handles without explicitly passing them:
function myslider
value = 0;
f = figure;
20-17
20 Function Basics
s = uicontrol(f,'Style','slider','Callback',@slider);
e = uicontrol(f,'Style','edit','Callback',@edittext,...
'Position',[100,20,100,20]);
function slider(obj,~)
value = obj.Value;
e.String = num2str(value);
end
function edittext(obj,~)
value = str2double(obj.String);
s.Value = value;
end
end
Anonymous functions allow you to define a function without creating a program file, as long as the
function consists of a single statement. A common application of anonymous functions is to define a
mathematical expression, and then evaluate that expression over a range of values using a MATLAB®
function function, i.e., a function that accepts a function handle as an input.
For example, this statement creates a function handle named s for an anonymous function:
s = @(x) sin(1./x);
This function has a single input, x. The @ operator creates the function handle.
You can use the function handle to evaluate the function for particular values, such as
y = s(pi)
y =
0.3130
Or, you can pass the function handle to a function that evaluates over a range of values, such as
fplot:
range = [0.01,0.1];
fplot(s,range)
20-18
Types of Functions
See Also
More About
• “Local Functions” on page 20-25
• “Nested Functions” on page 20-27
• “Private Functions” on page 20-36
• “Anonymous Functions” on page 20-20
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
20-19
20 Function Basics
Anonymous Functions
In this section...
“What Are Anonymous Functions?” on page 20-20
“Variables in the Expression” on page 20-21
“Multiple Anonymous Functions” on page 20-21
“Functions with No Inputs” on page 20-22
“Functions with Multiple Inputs or Outputs” on page 20-22
“Arrays of Anonymous Functions” on page 20-23
Note You can create an anonymous function that returns multiple outputs using the deal function.
See “Return Multiple Outputs from Anonymous Function” for an example.
For example, create a handle to an anonymous function that finds the square of a number:
Variable sqr is a function handle. The @ operator creates the handle, and the parentheses ()
immediately after the @ operator include the function input arguments. This anonymous function
accepts a single input x, and implicitly returns a single output, an array the same size as x that
contains the squared values.
Find the square of a particular value (5) by passing the value to the function handle, just as you
would pass an input argument to a standard function.
a = sqr(5)
a =
25
Many MATLAB functions accept function handles as inputs so that you can evaluate functions over a
range of values. You can create handles either for anonymous functions or for functions in program
files. The benefit of using anonymous functions is that you do not have to edit and maintain a file for a
function that requires only a brief definition.
For example, find the integral of the sqr function from 0 to 1 by passing the function handle to the
integral function:
q = integral(sqr,0,1);
You do not need to create a variable in the workspace to store an anonymous function. Instead, you
can create a temporary function handle within an expression, such as this call to the integral
function:
20-20
Anonymous Functions
q = integral(@(x) x.^2,0,1);
For example, create a handle to an anonymous function that requires coefficients a, b, and c.
a = 1.3;
b = .2;
c = 30;
parabola = @(x) a*x.^2 + b*x + c;
Because a, b, and c are available at the time you create parabola, the function handle includes
those values. The values persist within the function handle even if you clear the variables:
clear a b c
x = 1;
y = parabola(x)
y =
31.5000
To supply different values for the coefficients, you must create a new function handle:
a = -3.9;
b = 52;
c = 0;
parabola = @(x) a*x.^2 + b*x + c;
x = 1;
y = parabola(x)
y =
48.1000
You can save function handles and their associated values in a MAT-file and load them in a subsequent
MATLAB session using the save and load functions, such as
save myfile.mat parabola
Use only explicit variables when constructing anonymous functions. If an anonymous function
accesses any variable or nested function that is not explicitly referenced in the argument list or body,
MATLAB throws an error when you invoke the function. Implicit variables and function calls are often
encountered in the functions such as eval, evalin, assignin, and load. Avoid using these
functions in the body of anonymous functions.
20-21
20 Function Basics
The final function allows you to solve the equation for any value of c. For example:
g(2)
ans =
2.3333
d =
26-Jan-2012 15:11:47
Omitting the parentheses in the assignment statement creates another function handle, and does not
execute the function:
d = t
d =
@() datestr(now)
Anonymous functions require that you explicitly specify the input arguments as you would for a
standard function, separating multiple inputs with commas. For example, this function accepts two
inputs, x and y:
myfunction = @(x,y) (x^2 + y^2 + x*y);
x = 1;
y = 10;
z = myfunction(x,y)
z =
111
20-22
Anonymous Functions
However, an anonymous function returns only one output. If the expression in the function returns
multiple outputs, then you can request them when you invoke the function handle.
For example, the ndgrid function can return as many outputs as the number of input vectors. This
anonymous function that calls ndgrid returns only one output (mygrid). Invoke mygrid to access
the outputs returned by the ndgrid function.
c = 10;
mygrid = @(x,y) ndgrid((-x:x/c:x),(-y:y/c:y));
[x,y] = mygrid(pi,2*pi);
You can use the output from mygrid to create a mesh or surface plot:
z = sin(x) + cos(y);
mesh(x,y,z)
Although most MATLAB fundamental data types support multidimensional arrays, function handles
must be scalars (single elements). However, you can store multiple function handles using a cell array
or structure array. The most common approach is to use a cell array, such as
f = {@(x)x.^2;
@(y)y+10;
@(x,y)x.^2+y+10};
20-23
20 Function Basics
When you create the cell array, keep in mind that MATLAB interprets spaces as column separators.
Either omit spaces from expressions, as shown in the previous code, or enclose expressions in
parentheses, such as
f = {@(x) (x.^2);
@(y) (y + 10);
@(x,y) (x.^2 + y + 10)};
Access the contents of a cell using curly braces. For example, f{1} returns the first function handle.
To execute the function, pass input values in parentheses after the curly braces:
x = 1;
y = 10;
f{1}(x)
f{2}(y)
f{3}(x,y)
ans =
1
ans =
20
ans =
21
See Also
More About
• “Create Function Handle” on page 13-2
• “Types of Functions” on page 20-17
20-24
Local Functions
Local Functions
This topic explains the term local function, and shows how to create and use local functions.
MATLAB program files can contain code for more than one function. In a function file, the first
function in the file is called the main function. This function is visible to functions in other files, or
you can call it from the command line. Additional functions within the file are called local functions,
and they can occur in any order after the main function. Local functions are only visible to other
functions in the same file. They are equivalent to subroutines in other programming languages, and
are sometimes called subfunctions.
You also can create local functions in a script file. Local functions can be added anywhere in the file
except within conditional contexts, such as if statements or for loops. For more information, see
“Add Functions to Scripts” on page 18-13.
Local functions in scripts must be defined at the end of the file, after the last line of script code.
For example, create a function file named mystats.m that contains a main function, mystats, and
two local functions, mymean and mymedian.
function [avg, med] = mystats(x)
n = length(x);
avg = mymean(x,n);
med = mymedian(x,n);
end
function a = mymean(v,n)
% MYMEAN Example of a local function.
a = sum(v)/n;
end
function m = mymedian(v,n)
% MYMEDIAN Another example of a local function.
w = sort(v);
if rem(n,2) == 1
m = w((n + 1)/2);
else
m = (w(n/2) + w(n/2 + 1))/2;
end
end
The local functions mymean and mymedian calculate the average and median of the input list. The
main function mystats determines the length of the list n and passes it to the local functions.
Although you cannot call a local function from the command line or from functions in other files, you
can access its help using the help function. Specify names of both the file and the local function,
separating them with a > character:
help mystats>mymean
Local functions in the current file have precedence over functions and class methods in other files.
That is, when you call a function or method within a program file, MATLAB checks whether the
20-25
20 Function Basics
function is a local function before looking for other main functions. Therefore, you can create an
alternate version of a particular function while retaining the original in another file.
All functions, including local functions, have their own workspaces that are separate from the base
workspace. Local functions cannot access variables used by other functions unless you pass them as
arguments. In contrast, nested functions (functions completely contained within another function)
can access variables used by the functions that contain them.
See Also
localfunctions
More About
• “Nested Functions” on page 20-27
• “Function Precedence Order” on page 20-37
• “Types of Functions” on page 20-17
20-26
Nested Functions
Nested Functions
In this section...
“What Are Nested Functions?” on page 20-27
“Requirements for Nested Functions” on page 20-27
“Sharing Variables Between Parent and Nested Functions” on page 20-27
“Using Handles to Store Function Parameters” on page 20-29
“Visibility of Nested Functions” on page 20-31
For example, this function named parent contains a nested function named nestedfx:
function parent
disp('This is the parent function')
nestedfx
function nestedfx
disp('This is the nested function')
end
end
The primary difference between nested functions and other types of functions is that they can access
and modify variables that are defined in their parent functions. As a result:
• Nested functions can use variables that are not explicitly passed as input arguments.
• In a parent function, you can create a handle to a nested function that contains the data necessary
to run the nested function.
20-27
20 Function Basics
In general, variables in one function workspace are not available to other functions. However, nested
functions can access and modify variables in the workspaces of the functions that contain them.
This means that both a nested function and a function that contains it can modify the same variable
without passing that variable as an argument. For example, in each of these functions, main1 and
main2, both the main function and the nested function can access variable x:
When parent functions do not use a given variable, the variable remains local to the nested function.
For example, in this function named main, the two nested functions have their own versions of x that
cannot interact with each other:
function main
nestedfun1
nestedfun2
function nestedfun1
x = 1;
end
function nestedfun2
x = 2;
end
end
Functions that return output arguments have variables for the outputs in their workspace. However,
parent functions only have variables for the output of nested functions if they explicitly request them.
For example, this function parentfun does not have variable y in its workspace:
function parentfun
x = 5;
nestfun;
function y = nestfun
y = x + 1;
end
end
function parentfun
x = 5;
z = nestfun;
function y = nestfun
y = x + 1;
end
20-28
Nested Functions
end
• Input arguments
• Variables defined within the nested function
• Variables defined in a parent function, also called externally scoped variables
When you create a function handle for a nested function, that handle stores not only the name of the
function, but also the values of variables explicitly referenced by the nested function. Variables in the
parent workspace that are referenced by nested functions are cleared once the last nested function
handle created by that call to the parent function has been cleared.
For example, create a function in a file named makeParabola.m. This function accepts several
polynomial coefficients, and returns a handle to a nested function that calculates the value of that
polynomial.
function p = makeParabola(a,b,c)
p = @parabola;
function y = parabola(x)
y = a*x.^2 + b*x + c;
end
end
The makeParabola function returns a handle to the parabola function that includes values for
coefficients a, b, and c.
At the command line, call the makeParabola function with coefficient values of 1.3, .2, and 30. Use
the returned function handle p to evaluate the polynomial at a particular point:
p = makeParabola(1.3,.2,30);
X = 25;
Y = p(X)
Y =
847.5000
Many MATLAB functions accept function handle inputs to evaluate functions over a range of values.
For example, plot the parabolic equation from -25 to +25:
fplot(p,[-25,25])
20-29
20 Function Basics
You can create multiple handles to the parabola function that each use different polynomial
coefficients:
firstp = makeParabola(0.8,1.6,32);
secondp = makeParabola(3,4,50);
range = [-25,25];
figure
hold on
fplot(firstp,range)
fplot(secondp,range,'r:')
hold off
20-30
Nested Functions
• From the level immediately above it. (In the following code, function A can call B or D, but not C or
E.)
• From a function nested at the same level within the same parent function. (Function B can call D,
and D can call B.)
• From a function at any lower level. (Function C can call B or D, but not E.)
function A(x, y) % Main function
B(x,y)
D(y)
20-31
20 Function Basics
The easiest way to extend the scope of a nested function is to create a function handle and return it
as an output argument, as shown in “Using Handles to Store Function Parameters” on page 20-29.
Only functions that can call a nested function can create a handle to it.
See Also
More About
• “Resolve Error: Attempt to Add Variable to a Static Workspace.” on page 20-33
• “Create Function Handle” on page 13-2
• “Checking Number of Arguments in Nested Functions” on page 21-8
• “Types of Functions” on page 20-17
20-32
Resolve Error: Attempt to Add Variable to a Static Workspace.
Issue
The workspaces for nested and anonymous functions are static. This means that all variables used
within the function must be present in the text of the code.
If you attempt to dynamically add a variable to the static workspace of an anonymous function, a
nested function, or a function that contains a nested function, then MATLAB issues an error of the
form
For more information about the differences between the base and function workspaces, see “Base
and Function Workspaces” on page 20-9. For more information about nested functions, see “Nested
Functions” on page 20-27.
Possible Solutions
Declare Variable in Advance
One way to avoid dynamically adding a variable to static workspaces is to explicitly declare the
variable in the code before dynamically assigning a value to that variable. Doing so will cause the
variable name to be visible to MATLAB, so the name will be included in the fixed set of variables that
make up the static workspace.
For example, suppose a script named makeX.m dynamically assigns a value to variable X. A function
that calls makeX and explicitly declares X avoids the dynamic adding error because X is in the
function workspace.
function noerror
nestedfx
function nestedfx
X = [];
makeX
end
end
Using eval, evalin, or assignin to assign new variables inside of a nested functions will generate
an error.
function staticWorkspaceErrors
function nest
% This will error since x is not declared outside of the eval
eval("x=2");
end
end
20-33
20 Function Basics
If possible, avoid these functions altogether. See “Alternatives to the eval Function” on page 2-77. If it
is not possible to avoid them, then explicitly declare the variable within the parent function:
function noStaticWorkspaceErrors
x = [];
function nest
% This will not error since 'x' is declared outside of the eval
eval("x=2");
end
end
Calling a MATLAB script that creates a variable inside of a nested function will generate an error. In
the example below, the script, scriptThatIntroducesZ, contains code that assigns a value to the
variable z. Since the code does not explicitly declare that z is being assigned an error will be thrown.
function staticWorkspaceErrors
function nest
% This will error since 'z' is not declared outside of this script
scriptThatIntroducesZ
end
end
To avoid an error, declare the variable within the function before calling the script that assigns a
value to it.
function noStaticWorkspaceErrors
function nest
% This will not error since 'z' is declared outside of the script
z = [];
scriptThatIntroducesZ
end
end
Alternatively, convert the script to a function and make z its output argument. This approach also
makes the code clearer.
Using load to assign variables inside of a nested function, without explicitly specifying the variable
name will generate an error. In the example below, load is used to load a MAT-file containing the
variable Y. Since the code does not explicitly declare that Y is being assigned an error will be thrown.
function staticWorkspaceErrors
function nest
% This will error since var Y is not explicitly specified
load MatFileWithVarY
end
end
To avoid an error, instead specify the variable name as an input to the load function.
function noStaticWorkspaceErrors
function nest
% This will not error since variables 'x' and 'y' are specified
load MatFileWithVarX x
y = load('MatFileWithVarY','y');
20-34
Resolve Error: Attempt to Add Variable to a Static Workspace.
end
end
Alternatively, assign the output from the load function to a structure array.
While debugging, you cannot add a variable using the debug command prompt if you are stopped in a
nested function. Assign the variable into the base workspace, which is not static.
K>> assignin('base','X',myvalue)
Anonymous functions cannot contain variable assignments. When the anonymous function is called an
error will be thrown.
Rewrite the function in such a way that variable assignments are not required.
xEquals2 = @()2;
x = xEquals2()
x =
See Also
More About
• “Base and Function Workspaces” on page 20-9
• “Nested Functions” on page 20-27
20-35
20 Function Basics
Private Functions
This topic explains the term private function, and shows how to create and use private functions.
Private functions are useful when you want to limit the scope of a function. You designate a function
as private by storing it in a subfolder with the name private. Then, the function is available only to
functions and scripts in the folder immediately above the private subfolder.
For example, within a folder that is on the MATLAB search path, create a subfolder named private.
Do not add private to the path. Within the private folder, create a function in a file named
findme.m:
function findme
% FINDME An example of a private function.
Change to the folder that contains the private folder and create a file named visible.m.
function visible
findme
Change your current folder to any location and call the visible function.
visible
Although you cannot call the private function from the command line or from functions outside the
parent of the private folder, you can access its help:
help private/findme
Private functions have precedence over standard functions, so MATLAB finds a private function
named test.m before a nonprivate program file named test.m. This allows you to create an
alternate version of a particular function while retaining the original in another folder.
See Also
More About
• “Function Precedence Order” on page 20-37
• “Types of Functions” on page 20-17
20-36
Function Precedence Order
This topic explains how MATLAB determines which function to call when multiple functions in the
current scope have the same name. The current scope includes the current file, an optional private
subfolder relative to the currently running function, the current folder, and the MATLAB path.
1 Variables
Before assuming that a name matches a function, MATLAB checks for a variable with that name
in the current workspace.
Note If you create a variable with the same name as a function, MATLAB cannot run that
function until you clear the variable from memory.
2 Function or class whose name matches an explicitly imported name
The import function allows functions with compound names (names comprised of several parts
joined by dots) to be called using only the final part of the compound name. When a function
name matches an explicit (non-wildcard) imported function, MATLAB uses the imported
compound name and gives it precedence over all other functions with the same name.
3 Nested functions within the current function
4 Local functions within the current file
5 Function or class whose name matches a wildcard-based imported name
When a function name matches a wildcard-based imported function, MATLAB uses the imported
compound name and gives it precedence over all other functions with the same name, except for
nested and local functions.
6 Private functions
Private functions are functions in a subfolder named private that is immediately below the
folder of the currently running file.
7 Object functions
An object function accepts a particular class of object in its input argument list. When there are
multiple object functions with the same name, MATLAB checks the classes of the input
arguments to determine which function to use.
8 Class constructors in @-folders
Note The precedence of classes defined in @-folders over functions with the same name will be
removed in a future release. For additional information see “Class Precedence and MATLAB
Path”.
20-37
20 Function Basics
When determining the precedence of functions within the same folder, MATLAB considers the file
type, in this order:
1 Built-in function
2 MEX-function
3 Simulink model files that are not loaded, with file types in this order:
a SLX file
b MDL file
4 Stateflow® chart with a .sfx extension
5 App file (.mlapp) created using MATLAB App Designer
6 Program file with a .mlx extension
7 P-file (that is, an encoded program file with a .p extension)
8 Program file with a .m extension
For example, if MATLAB finds a .m file and a P-file with the same name in the same folder, it uses the
P-file. Because P-files are not automatically regenerated, make sure that you regenerate the P-file
whenever you edit the program file.
To determine the function MATLAB calls for a particular input, include the function name and the
input in a call to the which function.
20-38
Function Precedence Order
See Also
import
More About
• “What Is the MATLAB Search Path?”
• Variables on page 1-5
• “Types of Functions” on page 20-17
• “Class Precedence and MATLAB Path”
20-39
20 Function Basics
These changes impact the behavior of the import function. You should analyze and possibly update
your code. To start, search your code for import statements. For example, use “Find Files” to search
for .m and .mlx files containing text import. Refer to these search results when evaluating the
effects of the following changes.
If this behavior change impacts your code, rename either the variable or the function so that they
have different names.
Consider the following code. MATLAB used to treat x as a variable because of colon-indexing.
Starting in R2019b, if a function of the same name exists on the path, MATLAB treats x as a function.
function myfunc
load data.mat; % data.mat contains variable x
disp(x(:))
end
20-40
Update Code for R2019b Changes to Function Precedence Order
If you intend to use x as a variable from data.mat instead of a function, explicitly declare it.
Similarly, to use an identifier x as a variable obtained from a script, declare it before invoking the
script. This new behavior also applies if the variable is implicitly introduced by the functions sim,
eval, evalc, and assignin.
This table shows some examples of how you can update your code.
Before After
function myfunc function myfunc
load data.mat; load data.mat x;
disp(x(:)) disp(x(:))
end end
function myfunc2 function myfunc2
myscript; % Contains variable x x = [];
disp(x(:)) myscript;
end disp(x(:))
end
For example, in the following code, identifier x in myfunc is different from variable x in the nested
function. If x is a function on the path, MATLAB treats x in myfunc as a function and the code runs.
Otherwise, MATLAB throws an error.
function myfunc
nested;
x(3) % x is not a shared variable
function nested
x = [1 2 3];
end
end
In previous releases, if x was a function on the path, MATLAB treated it as a function in myfunc and
as a variable in nested. If x was not a function on the path, MATLAB treated it as a variable shared
between myfunc and nested. This resulted in code whose output was dependent on the state of the
path.
To use an identifier as a variable shared between parent and nested functions, you might need to
update your code. For example, you can initialize the identifier to an empty array in the parent
function.
20-41
20 Function Basics
Before After
function myfunc function myfunc
nested; x = [];
x(3) nested;
function nested x(3)
x = [1 2 3]; function nested
end x = [1 2 3];
end end
end
For example, in this code, the statement local() calls myfunc/local instead of pkg1.local in the
wildcard-based import. The statement nest() calls myfunc/nest instead of pkg1.nest.
In the search results for import, look for statements that include the wildcard character (*).
Fully qualified import functions cannot have the same name as nested
functions
Starting in R2019b, fully qualified imports that share a name with a nested function in the same
scope throw an error.
20-42
Update Code for R2019b Changes to Function Precedence Order
20-43
20 Function Basics
if ~usejava('jvm') if ~usejava('jvm')
% Statement never executes % Display message
disp('This function requires Java'); disp('This function requires Java')
else else
% Do something with Java String class % Do something with Java String cla
end end
end end
% Package p1 has functions plot and bar % Package p1 has functions plot and bar
import p1.plot import p1.plot
import p1.* import p1.*
nest nest
For example, suppose a package pkg contains a class foo with a static method bar and also a
subpackage foo with a function bar.
In R2019b, a call to which pkg.foo.bar returns the path to the package function.
which pkg.foo.bar
+pkg/+foo/bar.m
Previously, a static method took precedence over a package function in cases where a package and a
class had the same name.
20-44
Update Code for R2019b Changes to Function Precedence Order
See Also
import
More About
• “Import Namespace Members into Functions”
20-45
20 Function Basics
Example
Consider the function:
function y = myStruct(x)
y = struct("Afield",x);
end
This function creates a structure with one field, named Afield, and assigns a value to the field. You
can invoke the function and create a structure with a field containing the value 1 with the command:
myStruct(1)
ans =
Afield: 1
However, if you want to return the field value directly, you can index into the function call result with
the command:
myStruct(1).Afield
ans =
After this command executes, the temporary structure created by the command myStruct(1) no
longer exists, and MATLAB returns only the field value. Conceptually, this usage is the same as
creating the structure, indexing into it, and then deleting it:
S = struct("Afield",1);
S.Afield
clear S
Supported Syntaxes
MATLAB supports dot indexing into function call results, as in foo(arg).prop. Other forms of
indexing into function call results (with parentheses such as foo(arg)(2) or with curly braces such
as foo(arg){2}) are not supported. Successful commands must meet the criteria:
20-46
Indexing into Function Call Results
MATLAB always attempts to apply the dot indexing operation to the temporary variable, even if the
function returns a variable for which dot indexing is not defined. For example, if you try to index into
the matrix created by magic(3), then you get an error.
magic(3).field
You can add more indexing commands onto the end of an expression as long as the temporary
variables can continue to be indexed. For example, consider the expression:
table(rand(10,2)).Var1(3,:)
In this expression, you index into a table to get the matrix it contains, and then index into the matrix
to get the third row:
• table(rand(10,2)) creates a table with one variable named Var1. The variable contains a 10-
by-2 matrix.
• table(rand(10,2)).Var1 returns the 10-by-2 matrix contained in Var1.
• table(rand(10,2)).Var1(3,:) returns the third row in the matrix contained in Var1.
See Also
function | subsref
More About
• “Types of Functions” on page 20-17
• “Array Indexing”
• “Access Data in Tables” on page 9-37
20-47
21
Function Arguments
Input Arguments
Create a function in a file named addme.m that accepts up to two inputs. Identify the number of
inputs with nargin.
function c = addme(a,b)
switch nargin
case 2
c = a + b;
case 1
c = a + a;
otherwise
c = 0;
end
ans =
84
addme(2,4000)
ans =
4002
addme
ans =
0
Output Arguments
Create a new function in a file named addme2.m that can return one or two outputs (a result and its
absolute value). Identify the number of requested outputs with nargout.
function [result,absResult] = addme2(a,b)
switch nargin
case 2
result = a + b;
case 1
result = a + a;
otherwise
result = 0;
end
if nargout > 1
absResult = abs(result);
end
21-2
Find Number of Function Arguments
value = addme2(11,-22)
value =
-11
[value,absValue] = addme2(11,-22)
value =
-11
absValue =
11
Functions return outputs in the order they are declared in the function definition.
See Also
nargin | narginchk | nargout | nargoutchk
21-3
21 Function Arguments
Create a function in a file named plotWithTitle.m that accepts a variable number of paired (x,y)
inputs for the plot function and an optional title. If the function receives an odd number of inputs, it
assumes that the last input is a title.
function plotWithTitle(varargin)
if rem(nargin,2) ~= 0
myTitle = varargin{nargin};
numPlotInputs = nargin - 1;
else
myTitle = 'Default Title';
numPlotInputs = nargin;
end
plot(varargin{1:numPlotInputs})
title(myTitle)
Because varargin is a cell array, you access the contents of each cell using curly braces, {}. The
syntax varargin{1:numPlotInputs} creates a comma-separated list of inputs to the plot
function.
x = [1:.1:10];
y1 = sin(x);
y2 = cos(x);
plotWithTitle(x,y1,x,y2,'Sine and Cosine')
You can use varargin alone in an input argument list, or at the end of the list of inputs, such as
function myfunction(a,b,varargin)
In this case, varargin{1} corresponds to the third input passed to the function, and nargin returns
length(varargin) + 2.
See Also
nargin | varargin
Related Examples
• “Access Data in Cell Array” on page 12-4
More About
• “Checking Number of Arguments in Nested Functions” on page 21-8
• “Comma-Separated Lists” on page 2-66
21-4
Support Variable Number of Outputs
Create a function in a file named magicfill.m that assigns a magic square to each requested
output.
for k = 1:nOutputs
varargout{k} = magic(k);
end
[first,second,third] = magicfill
first =
1
second =
1 3
4 2
third =
8 1 6
3 5 7
4 9 2
MATLAB assigns values to the outputs according to their order in the varargout array. For example,
first == varargout{1}.
You can use varargout alone in an output argument list, or at the end of the list of outputs, such as
In this case, varargout{1} corresponds to the third output that the function returns, and nargout
returns length(varargout) + 2.
See Also
nargout | varargout
Related Examples
• “Access Data in Cell Array” on page 12-4
More About
• “Checking Number of Arguments in Nested Functions” on page 21-8
21-5
21 Function Arguments
MATLAB checks whether your function receives more arguments than expected when it can
determine the number from the function definition. For example, this function accepts up to two
outputs and three inputs:
If you pass too many inputs to myFunction, MATLAB issues an error. You do not need to call
narginchk to check for this case.
[X,Y] = myFunction(1,2,3,4)
Use the narginchk and nargoutchk functions to verify that your function receives:
Define a function in a file named testValues.m that requires at least two inputs. The first input is a
threshold value to compare against the other inputs.
function testValues(threshold,varargin)
minInputs = 2;
maxInputs = Inf;
narginchk(minInputs,maxInputs)
for k = 1:(nargin-1)
if (varargin{k} > threshold)
fprintf('Test value %d exceeds %d\n',k,threshold);
end
end
testValues(10)
testValues(10,1,11,111)
21-6
Validate Number of Function Arguments
Define a function in a file named mysize.m that returns the dimensions of the input array in a vector
(from the size function), and optionally returns scalar values corresponding to the sizes of each
dimension. Use nargoutchk to verify that the number of requested individual sizes does not exceed
the number of available dimensions.
sizeVector = size(x);
varargout = cell(1,nargout-1);
for k = 1:length(varargout)
varargout{k} = sizeVector(k);
end
A = rand(3,4,2);
[fullsize,nrows,ncols,npages] = mysize(A)
fullsize =
3 4 2
nrows =
3
ncols =
4
npages =
2
A = 1;
[fullsize,nrows,ncols,npages] = mysize(A)
See Also
narginchk | nargoutchk
Related Examples
• “Support Variable Number of Inputs” on page 21-4
• “Support Variable Number of Outputs” on page 21-5
21-7
21 Function Arguments
This topic explains special considerations for using varargin, varargout, nargin, and nargout
with nested functions.
varargin and varargout allow you to create functions that accept variable numbers of input or
output arguments. Although varargin and varargout look like function names, they refer to
variables, not functions. This is significant because nested functions share the workspaces of the
functions that contain them.
If you do not use varargin or varargout in the declaration of a nested function, then varargin or
varargout within the nested function refers to the arguments of an outer function.
For example, create a function in a file named showArgs.m that uses varargin and has two nested
functions, one that uses varargin and one that does not.
function showArgs(varargin)
nested1(3,4)
nested2(5,6,7)
function nested1(a,b)
disp('nested1: Contents of varargin{1}')
disp(varargin{1})
end
function nested2(varargin)
disp('nested2: Contents of varargin{1}')
disp(varargin{1})
end
end
Call the function and compare the contents of varargin{1} in the two nested functions.
showArgs(0,1,2)
On the other hand, nargin and nargout are functions. Within any function, including nested
functions, calls to nargin or nargout return the number of arguments for that function. If a nested
function requires the value of nargin or nargout from an outer function, pass the value to the
nested function.
For example, create a function in a file named showNumArgs.m that passes the number of input
arguments from the primary (parent) function to a nested function.
function showNumArgs(varargin)
21-8
Checking Number of Arguments in Nested Functions
function nestedFx(n,varargin)
disp(['Number of inputs to nestedFx: ',int2str(nargin)]);
disp(['Number of inputs to its parent: ',int2str(n)]);
end
end
Call showNumArgs and compare the output of nargin in the parent and nested functions.
showNumArgs(0,1)
See Also
nargin | nargout | varargin | varargout
21-9
21 Function Arguments
In a file named colorButton.m, define a callback for a push button that does not use the
eventdata input. Add a tilde to the input argument list so that the function ignores eventdata.
function colorButton
figure;
uicontrol('Style','pushbutton','String','Click me','Callback',@btnCallback)
function btnCallback(h,~)
set(h,'BackgroundColor',rand(3,1))
The function declaration for btnCallback is effectively the same as the following:
function btnCallback(h,eventdata)
However, using the tilde prevents the addition of eventdata to the function workspace and makes it
clearer that the function does not use eventdata.
You can ignore any number of inputs in your function definition, in any position in the argument list.
Separate consecutive tildes with a comma. For example:
function myFunction(myInput,~,~)
See Also
More About
• “Ignore Function Outputs” on page 1-4
21-10
Check Function Inputs with validateattributes
validateattributes requires that you pass the variable to check and the supported data types for
that variable. Optionally, pass a set of attributes that describe the valid dimensions or values.
Define a function in a file named checkme.m that accepts up to three inputs: a, b, and c. Check
whether:
function checkme(a,b,c)
validateattributes(a,{'double'},{'positive','2d'})
validateattributes(b,{'numeric'},{'numel',100,'ncols',10})
validateattributes(c,{'char','cell'},{'nonempty'})
The curly braces {} indicate that the set of data types and the set of additional attributes are in cell
arrays. Cell arrays allow you to store combinations of text and numeric data, or character vectors of
different lengths, in a single variable.
checkme(pi,rand(5,10,2),'text')
Call checkme with invalid inputs. The validateattributes function issues an error for the first
input that fails validation, and checkme stops processing.
checkme(-4)
checkme(pi,rand(3,4,2))
checkme(pi,rand(5,10,2),struct)
char, cell
21-11
21 Function Arguments
The default error messages use the generic term input to refer to the argument that failed
validation. When you use the default error message, the only way to determine which input failed is
to view the specified line of code in checkme.
Define a function in a file named checkdetails.m that performs the same validation as checkme,
but adds details about the input name and position to the error messages.
function checkdetails(a,b,c)
validateattributes(a,{'double'},{'positive','2d'},'','First',1)
validateattributes(b,{'numeric'},{'numel',100,'ncols',10},'','Second',2)
validateattributes(c,{'char'},{'nonempty'},'','Third',3)
The empty character vector '' for the fourth input to validateattributes is a placeholder for an
optional function name. You do not need to specify a function name because it already appears in the
error message. Specify the function name when you want to include it in the error identifier for
additional error handling.
checkdetails(-4)
checkdetails(pi,rand(3,4,2))
See Also
validateattributes | validatestring
21-12
Parse Function Inputs
The Input Parser provides a consistent way to validate and assign defaults to inputs, improving the
robustness and maintainability of your code. To validate the inputs, you can take advantage of
existing MATLAB functions or write your own validation routines.
Create a function in a file named printPhoto.m. The printPhoto function has one required input
for the file name, and optional inputs for the finish (glossy or matte), color space (RGB or CMYK),
width, and height.
function printPhoto(filename,varargin)
In your function declaration statement, specify required inputs first. Use varargin to support
optional inputs.
p = inputParser;
Add inputs to the parsing scheme in your function using addRequired, addOptional, or
addParameter. For optional inputs, specify default values.
For each input, you can specify a handle to a validation function that checks the input and returns a
scalar logical (true or false) or errors. The validation function can be an existing MATLAB function
(such as ischar or isnumeric) or a function that you create (such as an anonymous function or a
local function).
In the printPhoto function, filename is a required input. Define finish and color as optional
inputs, and width and height as optional parameter value pairs.
defaultFinish = 'glossy';
validFinishes = {'glossy','matte'};
checkFinish = @(x) any(validatestring(x,validFinishes));
defaultColor = 'RGB';
validColors = {'RGB','CMYK'};
checkColor = @(x) any(validatestring(x,validColors));
defaultWidth = 6;
defaultHeight = 4;
addRequired(p,'filename',@ischar);
addOptional(p,'finish',defaultFinish,checkFinish)
addOptional(p,'color',defaultColor,checkColor)
addParameter(p,'width',defaultWidth,@isnumeric)
addParameter(p,'height',defaultHeight,@isnumeric)
21-13
21 Function Arguments
Inputs that you add with addRequired or addOptional are positional arguments. When you call a
function with positional inputs, specify those values in the order they are added to the parsing
scheme.
Inputs added with addParameter are not positional, so you can pass values for height before or
after values for width. However, parameter value inputs require that you pass the input name
(height or width) along with the value of the input.
If your function accepts optional input strings or character vectors and name-value arguments,
specify validation functions for the optional inputs. Otherwise, the Input Parser interprets the
optional strings or character vectors as parameter names. For example, the checkFinish validation
function ensures that printPhoto interprets 'glossy' as a value for finish and not as an invalid
parameter name.
By default, the Input Parser makes assumptions about case sensitivity, function names, structure
array inputs, and whether to allow additional parameter names and values that are not in the scheme.
Properties allow you to explicitly define the behavior. Set properties using dot notation, similar to
assigning values to a structure array.
Allow printPhoto to accept additional parameter value inputs that do not match the input scheme
by setting the KeepUnmatched property of the Input Parser.
p.KeepUnmatched = true;
If KeepUnmatched is false (default), the Input Parser issues an error when inputs do not match the
scheme.
Within your function, call the parse method. Pass the values of all of the function inputs.
parse(p,filename,varargin{:})
• Results — Structure array with names and values of all inputs in the scheme.
• Unmatched — Structure array with parameter names and values that are passed to the function,
but are not in the scheme (when KeepUnmatched is true).
• UsingDefaults — Cell array with names of optional inputs that are assigned their default values
because they are not passed to the function.
Within the printPhoto function, display the values for some of the inputs:
disp(['File name: ',p.Results.filename])
disp(['Finish: ', p.Results.finish])
if ~isempty(fieldnames(p.Unmatched))
disp('Extra inputs:')
disp(p.Unmatched)
end
if ~isempty(p.UsingDefaults)
disp('Using defaults: ')
21-14
Parse Function Inputs
disp(p.UsingDefaults)
end
• Required inputs first, in the order they are added to the parsing scheme with addRequired.
• Optional positional inputs in the order they are added to the scheme with addOptional.
• Positional inputs before parameter name and value pair inputs.
• Parameter names and values in the form Name1,Value1,...,NameN,ValueN.
Pass several combinations of inputs to printPhoto, some valid and some invalid:
printPhoto('myfile.jpg')
printPhoto(100)
printPhoto('myfile.jpg','satin')
'glossy', 'matte'
The input, 'satin', did not match any of the valid strings.
printPhoto('myfile.jpg',height=10,width=8)
When using name-value arguments before R2021a, pass names as strings or character vectors, and
separate names and values with commas. For example:
printPhoto('myfile.jpg','height',10,'width',8)
To pass a value for the nth positional input, either specify values for the previous (n – 1) inputs or
pass the input as a parameter name and value pair. For example, these function calls assign the same
values to finish (default 'glossy') and color:
printPhoto('myfile.gif','glossy','CMYK') % positional
See Also
inputParser | varargin
21-15
21 Function Arguments
More About
• “Input Parser Validation Functions” on page 21-17
21-16
Input Parser Validation Functions
The Input Parser methods addRequired, addOptional, and addParameter each accept an
optional handle to a validation function. Designate function handles with an at (@) symbol.
Validation functions must accept a single input argument, and they must either return a scalar logical
value (true or false) or error. If the validation function returns false, the Input Parser issues an
error and your function stops processing.
• Use an existing MATLAB function such as ischar or isnumeric. For example, check that a
required input named num is numeric:
p = inputParser;
checknum = @isnumeric;
addRequired(p,'num',checknum)
parse(p,'text')
• Create an anonymous function. For example, check that input num is a numeric scalar greater
than zero:
p = inputParser;
checknum = @(x) isnumeric(x) && isscalar(x) && (x > 0);
addRequired(p,'num',checknum)
parse(p,rand(3))
The value of 'num' is invalid. It must satisfy the function: @(x) isnumeric(x) && isscalar(x)
&& (x>0).
• Define your own function, typically a local function in the same file as your primary function. For
example, in a file named usenum.m, define a local function named checknum that issues custom
error messages when the input num to usenum is not a numeric scalar greater than zero:
function usenum(num)
p = inputParser;
addRequired(p,'num',@checknum);
parse(p,num);
function TF = checknum(x)
TF = false;
if ~isscalar(x)
error('Input is not scalar');
elseif ~isnumeric(x)
error('Input is not numeric');
elseif (x <= 0)
error('Input must be > 0');
else
TF = true;
end
21-17
21 Function Arguments
usenum(-1)
See Also
inputParser | validateattributes
Related Examples
• “Parse Function Inputs” on page 21-13
• “Create Function Handle” on page 13-2
• “Use is* Functions to Detect State” on page 3-5
More About
• “Anonymous Functions” on page 20-20
21-18
22
You can diagnose problems in your MATLAB code files by debugging your code interactively in the
Editor and Live Editor or programmatically by using debugging functions in the Command Window.
Before you begin debugging, to avoid unexpected results, save your code files and make sure that the
code files and any files they call exist on the search path or in the current folder. MATLAB handles
unsaved changes differently depending on where you are debugging from:
• Editor — If a file contains unsaved changes, MATLAB saves the file before running it.
• Live Editor — MATLAB runs all changes in a file, whether they are saved or not.
• Command Window — If a file contains unsaved changes, MATLAB runs the saved version of the
file. You do not see the results of your changes.
Display Output
One way to determine where a problem occurs in your MATLAB code file is to display the output. To
display the output for a line, remove the semicolon from the end of that line. In the Editor, MATLAB
displays the output in the Command Window. In the Live Editor, MATLAB displays the output with the
line of code that creates it.
For example, suppose that you have a script named plotRand.m that plots a vector of random data
and draws a horizontal line on the plot at the mean.
n = 50;
r = rand(n,1);
plot(r)
m = mean(r);
hold on
plot([0,n],[m,m])
hold off
title("Mean of Random Uniform Data")
To display the output of the rand function at line 2, remove the semicolon at the end of the line.
MATLAB displays the value of r in the Command Window.
22-2
Debug MATLAB Code Files
When debugging, the Run to Here button becomes the Continue to Here button . In functions
and classes, running to a specified line and then pausing is available only when debugging using the
Continue to Here button . In R2021a and previous releases, to run to the cursor position and pause
while debugging, go to the Editor tab, and click the Run to Cursor button .
22-3
22 Debugging MATLAB Code
For example, click the Run to Here button to the left of line 2 in plotRand.m. MATLAB runs
plotRand.m starting at line 1 and pauses before running line 2.
•
The Run button in
the Editor or Live Editor tab changes to a
Continue button.
• The prompt in the Command Window changes to K>> indicating that MATLAB is in debug mode
and that the keyboard is in control.
• MATLAB indicates the line at which it is paused by using a green arrow and green highlighting.
Tip It is a good practice to avoid modifying a file while MATLAB is paused. Changes that are made
while MATLAB is paused do not run until after MATLAB finishes running the code and the code is
rerun.
The line at which MATLAB is paused does not run until after you continue running the code. To
continue running the code, click the
Continue button.
MATLAB continues running the file until it reaches the end of the file or a breakpoint. You also can
click the Continue to Here button to the left of the line of code that you want to continue running
to.
To continue running the code line-by-line, on the Editor or Live Editor tab, click Step. MATLAB
executes the current line at which it is paused and then pauses at the next line.
22-4
Debug MATLAB Code Files
You also can view the value of a variable by typing the variable name in the Command Window. For
example, to see the value of the variable n, type n and press Enter. The Command Window displays
the variable name and its value. To view all the variables in the current workspace, use the
Workspace browser.
For more information, see “Examine Values While Debugging” on page 22-16.
22-5
22 Debugging MATLAB Code
Pause button
changes to a
Continue button. In some cases, MATLAB might not pause at all. The reason is that MATLAB is
unable to pause in some built-in code.
By default, the Step In button displays only for user-defined functions and scripts. To show the
button for all functions and scripts, on the Home tab, in the Environment section, click
Preferences. Then, select MATLAB > Editor/Debugger, and in the Debugging section, set the
Show inline Step In buttons option to Always. To never show the button, set the Show inline Step
In buttons option to Never.
Alternatively, you can step in and out of functions while debugging by using the Step In or
Step Out buttons on the Editor or Live Editor tab. These buttons do not honor the Show inline
Step In buttons preference and always step in and out of user-defined and MathWorks functions.
When you step into a called function or file, MATLAB displays the list of the functions it executed
before pausing at the current line. The list, also called the function call stack, is shown at the top of
the file and displays the functions in order, starting on the left with the first called script or function,
and ending on the right with the current script or function in which MATLAB is paused.
For each function in the function call stack, there is a corresponding workspace. Workspaces contain
variables that you create within MATLAB or import from data files or other programs. Variables that
you assign through the Command Window or create by using scripts belong to the base workspace.
Variables that you create in a function belong to their own function workspace.
You can examine the values of variables outside of the current workspace by selecting a different
workspace. For more information, see “Examine Values While Debugging” on page 22-16.
There are three types of breakpoints: standard, conditional, and error. To add a standard breakpoint
in the Editor or Live Editor, click the line number (or the gray area if line numbers are not visible) to
the left of the executable line where you want to set the breakpoint. For example, click line number 3
in plotRand.m to add a breakpoint at that line.
22-6
Debug MATLAB Code Files
When you run the file, MATLAB pauses at the line of code indicated by the breakpoint. The line at
which MATLAB is paused does not run until after you continue running your code.
For example, with the plotRand.m file open in the Editor, click the
Run button in the
Editor tab. MATLAB runs plotRand.m starting at line 1 and pauses before running line 3.
•
The Run button in
the Editor or Live Editor tab changes to a
Continue button.
• The prompt in the Command Window changes to K>> indicating that MATLAB is in debug mode
and that the keyboard is in control.
• MATLAB indicates the line at which it is paused by using a green arrow and green highlighting.
Tip It is a good practice to avoid modifying a file while MATLAB is paused. Changes that are made
while MATLAB is paused do not run until after MATLAB finished running the code and the code is
rerun.
For more information about the different types of breakpoints and how to set, clear, and disable them,
see “Set Breakpoints” on page 22-11.
22-7
22 Debugging MATLAB Code
To avoid confusion, make sure to end your debugging session every time you are done debugging. If
you make changes to a file and save it while debugging, MATLAB ends the debugging session. If
MATLAB becomes unresponsive when it pauses, press Ctrl+C to end debugging.
By default, the Debugger panel opens automatically when MATLAB enters debug mode. To open the
Debugger panel manually, go to the Editor or Live Editor tab, and in the Analyze section, click
Debugger. Alternatively, you can open the panel using the Open more panels button ( ) in a
sidebar. By default, the Debugger panel opens on the right side of the desktop. To hide the Debugger
panel, click the Debugger
icon in the sidebar.
The Breakpoints section in the panel lists the breakpoints in all MATLAB code files. The first four
breakpoints in the section, Pause on Errors, Pause on Warnings, Pause on NaN or Inf, and
Pause on Unsuppressed Output are error breakpoints. When you enable one of these breakpoints,
MATLAB pauses at any line in any file if the error condition specified occurs. The remaining
breakpoints are grouped by file.
For each breakpoint in the list, you can perform these actions:
• Enable or disable breakpoint — Select the check box next to the breakpoint to enable the
breakpoint, and clear the check box to disable the breakpoint.
22-8
Debug MATLAB Code Files
• Clear breakpoint — Select the breakpoint and at the top of the Debugger panel, click the Clear
button to clear the breakpoint. To clear all breakpoints, click the next to the Clear button
and select Clear All Breakpoints. Error breakpoints cannot be cleared.
• Go to breakpoint in file — Click the hyperlinked line number to the right of the breakpoint to open
the file and go to the code line that contains the breakpoint.
• Set or modify breakpoint condition — Right-click the breakpoint and select Set/Modify Condition
to enter or modify a condition for the selected breakpoint.
For more information about breakpoints, see “Set Breakpoints” on page 22-11.
The Function call stack section shows the list of functions MATLAB executed before pausing at the
current line. The functions display in order, with the current script or function in which MATLAB is
paused at the top of the list, and the first called script or function at the bottom of the list. For each
function in the function call stack, there is a corresponding workspace. To view the workspace for a
function in the function call stack, select that function in the list. For more information about the
function call stack, see “Function Call Stack” on page 22-6.
To disable opening the Debugger panel automatically, click the Debugger Configuration button at
the top left of the Debugger panel and clear the Open Debugger panel automatically option.
Alternatively, you can disable this option in the MATLAB > Editor/Debugger page of the
Preferences window.
22-9
22 Debugging MATLAB Code
See Also
Related Examples
• “Set Breakpoints” on page 22-11
• “Examine Values While Debugging” on page 22-16
• “Edit and Format Code” on page 24-19
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
22-10
Set Breakpoints
Set Breakpoints
Setting breakpoints pauses the execution of your MATLAB program so that you can examine values
where you think an issue might have occurred. You can set breakpoints interactively in the Editor or
Live Editor, or by using functions in the Command Window.
• Standard
• Conditional
• Error
You can set breakpoints only at executable lines in saved files that are in the current folder or in
folders on the search path. You can set breakpoints at any time, whether MATLAB is idle or busy
running a file.
By default, when MATLAB reaches a breakpoint, it opens the file containing the breakpoint. To
disable this option:
1
From the Home tab, in the Environment section, click Preferences.
2 In the Preferences window, select MATLAB > Editor/Debugger.
3 Clear the Automatically open file when MATLAB reaches a breakpoint option and click OK.
Standard Breakpoints
A standard breakpoint pauses at a specific line in a file. To set a standard breakpoint, click the gray
area to the left of the executable line where you want to set the breakpoint. Alternatively, you can
press the F12 key to set a breakpoint at the current line. If you attempt to set a breakpoint at a line
that is not executable, such as a comment or a blank line, MATLAB sets it at the next executable line.
To set a standard breakpoint programmatically, use the dbstop function. For example, to add a
breakpoint at line three in a file named plotRand.m, type:
dbstop in plotRand at 3
When debugging a file that contains a loop, set the breakpoint inside the loop to examine the values
at each increment of the loop. Otherwise, if you set the breakpoint at the start of the loop, MATLAB
pauses at the loop statement only once. For example, this code creates an array of ten ones and uses
a for loop to perform a calculation on items two through six of the array:
x = ones(1:10);
22-11
22 Debugging MATLAB Code
for n = 2:6
x(n) = 2 * x(n-1);
end
For MATLAB to pause at each increment of the for loop (a total of five times), set a breakpoint at line
four.
Conditional Breakpoints
A conditional breakpoint causes MATLAB to pause at a specific line in a file only when the specified
condition is met. For example, you can use conditional breakpoints when you want to examine results
after some iterations in a loop.
To set a conditional breakpoint, right-click the gray area to the left of the executable line where you
want to set the breakpoint and select Set Conditional Breakpoint. If a breakpoint already exists on
that line, select Set/Modify Condition. In the dialog box that opens, enter a condition and click OK.
A condition is any valid MATLAB expression that returns a logical scalar value.
When you run the code, MATLAB evaluates the condition before running the line. If the condition is
met, MATLAB enters debug mode and pauses at the line. For example, this code creates an array of
ten ones and uses a for loop to perform a calculation on items two through six of the array:
x = one(1:10)
for n = 2:6
x(n) = 2 * x(n-1);
end
Set a conditional breakpoint at line four with the condition n >= 4. When you run the code, MATLAB
runs through the for loop twice and pauses on the third iteration at line four when n is 4. If you
continue running the code, MATLAB pauses again at line four on the fourth iteration when n is 5, and
then once more, when n is 6.
You also can set a conditional breakpoint programmatically using the dbstop function. For example,
to add a conditional breakpoint in myprogram.m at line six, type:
dbstop in myprogram at 6 if n>=4
Error Breakpoints
In the Editor, you can set an error breakpoint to have MATLAB pause and enter debug mode if
MATLAB encounters an issue. Setting error breakpoints is not supported in the Live Editor.
22-12
Set Breakpoints
Unlike standard and conditional breakpoints, you do not set error breakpoints at a specific line or in a
specific file. When you set an error breakpoint, MATLAB pauses at any line in any file if the error
condition specified occurs. MATLAB then enters debug mode and opens the file containing the error,
with the execution arrow at the line containing the error.
Alternatively, you can set an error breakpoint programmatically by using the dbstop function with a
specified condition. For example, to pause execution on all errors, type:
dbstop if error
To pause execution at the first run-time error within the try portion of a try/catch block that has a
message ID of MATLAB:ls:InputsMustBeStrings, type:
To set a breakpoint on a line containing an anonymous function, click the gray area to the left of the
line. MATLAB adds a breakpoint for the line, and a disabled breakpoint for each anonymous function
in the line. To enable a breakpoint for an anonymous function, click the disabled breakpoint for that
function.
To view information about all the breakpoints on a line, place your cursor on the breakpoint icon. A
tooltip appears with available information. For example, in this code, line seven contains two
anonymous functions, with a breakpoint at each one.
When you set a breakpoint in an anonymous function, MATLAB pauses when the anonymous function
is called. The line highlighted in green is where the code defines the anonymous function. The line
highlighted in gray is where the code calls the anonymous functions. For example, in this code,
MATLAB pauses the program at a breakpoint set for the anonymous function g, defined at line seven,
and called at line eight.
22-13
22 Debugging MATLAB Code
Invalid Breakpoints
• Unsaved changes in the file. To make breakpoints valid, save the file. The gray breakpoints
become red, indicating that they are now valid.
• A syntax error in the file. When you set a breakpoint, an error message appears indicating where
the syntax error is. To make the breakpoint valid, fix the syntax error and save the file.
Disable Breakpoints
You can disable selected breakpoints so that your program temporarily ignores them and runs
uninterrupted. For example, you might disable a breakpoint after you think you identified and
corrected an issue or if you are using conditional breakpoints.
To disable a breakpoint, right-click the breakpoint icon, and select Disable Breakpoint from the
context menu.
To reenable a breakpoint, right-click the breakpoint icon and select Enable Breakpoint from the
context menu.
The gray breakpoints become red, and program execution pauses at that line.
To enable or disable all breakpoints in the file, right-click the gray area to the left of an executable
line and select Enable All Breakpoints in File or Disable All Breakpoints in File. These options
are available only if there is at least one breakpoint to enable or disable.
22-14
Set Breakpoints
Clear Breakpoints
All breakpoints remain in a file until you clear (remove) them or until they are cleared automatically
at the end of your MATLAB session.
To clear a breakpoint, right-click the breakpoint icon and select Clear Breakpoint from the context
menu. Alternatively, you can press the F12 key to clear the breakpoint.
To clear a breakpoint programmatically, use the dbclear function. For example, to clear the
breakpoint at line six in a file called myprogram.m, type:
dbclear in myprogram at 6
To clear all breakpoints in the file, right-click the breakpoint alley and select Clear All Breakpoints
in File. You can also use the dbclear all command. For example, to clear all the breakpoints in a
file called myprogram.m, type:
To clear all breakpoints in all files, including error breakpoints, right-click the breakpoint alley and
select Clear All Breakpoints. You also can use the dbclear all command.
Breakpoints clear automatically when you end a MATLAB session. To save your breakpoints for future
sessions, use the dbstatus function.
See Also
Related Examples
• “Debug MATLAB Code Files” on page 22-2
• “Examine Values While Debugging” on page 22-16
22-15
22 Debugging MATLAB Code
When debugging a code file, you can view the value of any variable currently in the workspace while
MATLAB is paused. If you want to determine whether a line of code produces the expected result or
not, examining values is useful. If the result is as expected, you can continue running the code or step
to the next line. If the result is not as you expect, then that line, or a previous line, might contain an
error.
• Workspace browser — The Workspace browser displays all variables in the current workspace.
The Value column of the Workspace browser shows the current value of the variable.
To view more details, double-click the variable. The Variables Editor opens, displaying the content
for that variable. You also can use the openvar function to open a variable in the Variables Editor.
• Editor and Live Editor — To view the value of a variable in the Editor and Live Editor, place your
cursor over the variable. The current value of the variable appears in a data tip. The data tip stays
in view until you move the cursor. If you have trouble getting the data tip to appear, click the line
containing the variable, and then move the pointer next to the variable.
Data tips are always enabled when debugging in the Editor. To disable data tips in the Live Editor
or when editing a file in the Editor, go to the View tab and click the
Datatips button
off.
You also can view the value of a variable or equation by selecting it in the Editor and Live Editor,
right-clicking, and selecting Evaluate Selection in Command Window. MATLAB displays the
value of the variable or equation in the Command Window.
22-16
Examine Values While Debugging
Note You cannot evaluate a selection while MATLAB is busy, for example, running a file.
• Command Window — To view the value of a variable in the Command Window, type the variable
name. For the example, to see the value of a variable n, type n and press Enter. The Command
Window displays the variable name and its value. To view all the variables in the current
workspace, call the who function.
You also can use the dbstack function to view the current workspace in the Command Window:
dbstack
For each function in the function call stack, there is a corresponding workspace. Workspaces contain
variables that you create within MATLAB or import from data files or other programs. Variables that
you assign through the Command Window or create by using scripts belong to the base workspace.
Variables that you create in a function belong to their own function workspace.
To examine the values of variables outside of the current workspace, select a different workspace. In
the Editor or Live Editor, select a workspace from the drop-down list to the right of the function call
stack at the top of the file.
You also can use the dbup and dbdown functions in the Command Window to select the previous or
next workspace in the function call stack. To list the variables in the current workspace, use who or
whos.
If you attempt to view the value of a variable in a different workspace while MATLAB is in the process
of overwriting it, MATLAB displays an error in the Command Window.
K>> x
Variable "x" is inaccessible. When a variable appears on both sides of an assignment
statement, the variable may become temporarily unavailable during processing.
The error occurs whether you select the workspace by using the drop-down list to the right of the
function call stack or the dbup command.
22-17
22 Debugging MATLAB Code
See Also
Related Examples
• “Debug MATLAB Code Files” on page 22-2
• “Set Breakpoints” on page 22-11
22-18
23
MATLAB software enables you to present your MATLAB code in various ways. You can share your
code and results with others, even if they do not have MATLAB software. You can save MATLAB
output in various formats, including HTML, XML, and LaTeX. If Microsoft Word or Microsoft
PowerPoint applications are on your Microsoft Windows system, you can publish to their formats as
well.
MATLAB provides options for presenting your code to others. You can publish your MATLAB Code
files (.m) to create formatted documents or you can create and share live scripts and live functions in
the Live Editor.
23-2
Publish and Share MATLAB Code
This code demonstrates the Fourier series expansion for a square wave.
1 Create a MATLAB script or function. Divide the code into steps or sections by inserting two
percent signs (%%) at the beginning of each section.
2 Document the code by adding explanatory comments at the beginning of the file and within each
section.
Within the comments at the top of each section, you can add markup that enhances the
readability of the output. For example, the code in the preceding table includes the following
markup.
Note When you have a file containing text that has characters in a different encoding than that
of your platform, when you save or publish your file, MATLAB displays those characters as
garbled text.
3 Publish the code. On the Publish tab, click Publish.
23-3
23 Presenting MATLAB Code
By default, MATLAB creates a subfolder named html, which contains an HTML file and files for
each graphic that your code creates. The HTML file includes the code, formatted comments, and
output. Alternatively, you can publish to other formats, such as PDF files or Microsoft PowerPoint
presentations. For more information on publishing to other formats, see “Specify Output File” on
page 23-20.
In MATLAB Online, to allow MATLAB to open output windows automatically when publishing,
enable pop-up windows in your Web browser.
After publishing the code, you can share the folder containing the published files. For more
information, see “Share Folders Using MATLAB Drive”.
You also can create your own documentation topics for viewing alongside the MathWorks
documentation in the system web browser. For more information, see “Display Custom
Documentation” on page 32-20
See Also
publish
More About
• “Create Live Scripts in the Live Editor” on page 19-6
• “Publishing Markup” on page 23-5
• “Output Preferences for Publishing” on page 23-20
External Websites
• Publishing MATLAB Code from the Editor video
23-4
Publishing Markup
Publishing Markup
When publishing your MATLAB code files (.m), you can enhance the readability of the published
documents by adding markup to the comments within the files. Adding markup allows you to format
the published documents and display external files and graphics.
Markup Overview
To insert markup, you can:
• Use the formatting buttons and drop-down menus on the Publish tab to format the file. This
method automatically inserts the text markup for you.
• Select markup from the Insert Text Markup list in the right click menu.
• Type the markup directly in the comments.
The following table provides a summary of the text markup options. Refer to this table if you are not
using the MATLAB Editor, or if you do not want to use the Publish tab to apply the markup.
• Spaces following the comment symbols (%) often determine the format of the text that follows.
• Starting new markup often requires preceding blank comment lines, as shown in examples.
• Markup only works in comments that immediately follow a section break.
% *BOLD TEXT*
% |MONOSPACED TEXT|
% Trademarks:
% TEXT(TM)
% TEXT(R)
23-5
23 Presenting MATLAB Code
%% Numbered List
%
% # NUMBERED ITEM 1
% # NUMBERED ITEM 2
%
“Text and Code Blocks” on page 23-9 %%
%
% PREFORMATTED
% TEXT
%
%% MATLAB(R) Code
%
% for i = 1:10
% disp x
% end
%
“External File Content” on page 23-10 %
% <include>filename.m</include>
%
“External Graphics” on page 23-11 %
% <<FILENAME.PNG>>
%
“Image Snapshot” on page 23-13 snapnow;
“LaTeX Equations” on page 23-13 %% Inline Expression
% $x^2+e^{\pi i}$
%% Block Equation
%
% $$e^{\pi i} + 1 = 0$$
%
“Hyperlinks” on page 23-15 % <https://www.mathworks.com MathWorks>
% <matlab:FUNCTION DISPLAYED_TEXT>
“HTML Markup” on page 23-17 %
% <html>
% <table border=1><tr>
% <td>one</td>
% <td>two</td></tr></table>
% </html>
%
23-6
Publishing Markup
Note You can add comments in the lines immediately following the title. However, if you want an
overall document title, you cannot add any MATLAB code before the start of the next section (a line
starting with %%).
%% Vector Operations
% You can perform a number of binary operations on vectors.
%%
A = 1:3;
B = 4:6;
%% Dot Product
% A dot product of two vectors yields a scalar.
% MATLAB has a simple command for dot products.
s = dot(A,B);
%% Cross Product
% A cross product of two vectors yields a third
% vector perpendicular to both original vectors.
% Again, MATLAB has a simple command for cross products.
v = cross(A,B);
By saving the code in an Editor and clicking the Publish button on the Publish tab, MATLAB
produces the output as shown in this figure. Notice that MATLAB automatically inserts a Contents
menu from the section titles in the MATLAB file.
23-7
23 Presenting MATLAB Code
Text Formatting
You can mark selected text in the MATLAB comments so that they display in italic, bold, or
monospaced text when you publish the file. Simply surround the text with _, *, or | for italic, bold, or
monospaced text, respectively.
For instance, these lines display each of the text formatting syntaxes if published.
Trademark Symbols
If the comments in your MATLAB file include trademarked terms, you can include text to produce a
trademark symbol (™) or registered trademark symbol (®) in the output. Simply add (R) or (TM)
directly after the term in question, without any space in between.
If you publish the file to HTML, it appears in the MATLAB web browser.
23-8
Publishing Markup
%% Two Lists
%
% * ITEM1
% * ITEM2
%
% # ITEM1
% # ITEM2
%
Preformatted text appears in monospace font, maintains white space, and does not wrap long lines.
Two spaces must appear between the comment symbol and the text of the first line of the
preformatted text.
%%
% Many people find monospaced text easier to read:
%
% A dot product of two vectors yields a scalar.
% MATLAB has a simple command for dot products.
23-9
23 Presenting MATLAB Code
Executable code appears with syntax highlighting in published documents. You also can highlight
sample code. Sample code is code that appears within comments.
To indicate sample code, you must put three spaces between the comment symbol and the start of the
first line of code. For example, clicking the Code button on the Publish tab inserts the following
sample code in your Editor.
%%
%
% for i = 1:10
% disp(x)
% end
%
Publishing this code to HTML produces output in the MATLAB web browser.
For example, this code inserts the contents of sine_wave.m into your published output:
23-10
Publishing Markup
External Graphics
To publish an image that the MATLAB code does not generate, use text markup. By default, MATLAB
already includes code-generated graphics.
This code inserts a generic image called FILENAME.PNG into your published output.
%%
%
% <<FILENAME.PNG>>
%
MATLAB requires that FILENAME.PNG be a relative path from the output location to your external
image or a fully qualified URL. Good practice is to save your image in the same folder that MATLAB
publishes its output. For example, MATLAB publishes HTML documents to a subfolder html. Save
your image file in the same subfolder. You can change the output folder by changing the publish
configuration settings. In MATLAB Online, save your image file to your Published folder, which is
located in your root folder.
This example shows how to insert surfpeaks.jpg into a MATLAB file for publishing.
saveas(surf(peaks),'surfpeaks.jpg');
saveas(surf(peaks),'html/surfpeaks.jpg');
23-11
23 Presenting MATLAB Code
%% Image Example
% This is a graphic:
%
% <<surfpeaks.jpg>>
%
The type of images you can include when you publish depends on the output type of that document as
indicated in this table. For greatest compatibility, best practice is to use the default image format for
each output type.
Output File Format Default Image Format Types of Images You Can Include
doc png Any format that your installed version of
Microsoft Office supports.
html png All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
latex png or epsc2 All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
pdf bmp bmp and jpg.
ppt png Any format that your installed version of
Microsoft Office supports.
xml png All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
23-12
Publishing Markup
Image Snapshot
You can insert code that captures a snapshot of your MATLAB output. This is useful, for example, if
you have a for loop that modifies a figure that you want to capture after each iteration.
The following code runs a for loop three times and produces output after every iteration. The
snapnow command captures all three images produced by the code.
for i=1:3
imagesc(magic(i))
snapnow;
end
If you publish the file to HTML, it resembles the following output. By default, the images in the HTML
are larger than shown in the figure. To resize images generated by MATLAB code, use the Max
image width and Max image height fields in the Publish settings pane, as described in “Output
Preferences for Publishing” on page 23-20.
LaTeX Equations
Inline LaTeX Expression
MATLAB enables you to include an inline LaTeX expression in any code that you intend to publish. To
insert an inline expression, surround your LaTeX markup with dollar sign characters ($). The $ must
immediately precede the first word of the inline expression, and immediately follow the last word of
the inline expression, without any space in between.
Note
• All publishing output types support LaTeX expressions, except Microsoft PowerPoint.
23-13
23 Presenting MATLAB Code
• MATLAB publishing supports standard LaTeX math mode directives. Text mode directives or
directives that require additional packages are not supported.
If you publish the sample text markup to HTML, this is the resulting output.
MATLAB enables you to insert LaTeX symbols in blocks that are offset from the main comment text.
Two dollar sign characters ($$) on each side of an equation denote a block LaTeX equation.
Publishing equations in separate blocks requires a blank line in between blocks.
23-14
Publishing Markup
Hyperlinks
Static Hyperlinks
You can insert static hyperlinks within a MATLAB comment, and then publish the file to HTML, XML,
or Microsoft Word. When specifying a static hyperlink to a web location, include a complete URL
within the code. This is useful when you want to point the reader to a web location. You can display or
hide the URL in the published text. Consider excluding the URL, when you are confident that readers
are viewing your output online and can click the hyperlink.
%%
% For more information, see our web site:
% <https://www.mathworks.com MathWorks>
Eliminating the text MathWorks after the URL produces this modified output.
Note If your code produces hyperlinked text in the MATLAB Command Window, the output shows the
HTML code rather than the hyperlink.
Dynamic Hyperlinks
You can insert dynamic hyperlinks, which MATLAB evaluates at the time a reader clicks that link.
Dynamic hyperlinks enable you to point the reader to MATLAB code or documentation, or enable the
reader to run code. You implement these links using matlab: syntax. If the code that follows the
matlab: declaration has spaces in it, replace them with %20.
Note Dynamic links only work when viewing HTML in the MATLAB web browser.
23-15
23 Presenting MATLAB Code
You can specify a dynamic hyperlink to run code when a user clicks the hyperlink. For example, this
matlab: syntax creates hyperlinks in the output, which when clicked either enable or disable
recycling:
%% Recycling Preference
% Click the preference you want:
%
% <matlab:recycle('off') Disable recycling>
%
% <matlab:recycle('on') Enable recycling>
When you click one of the hyperlinks, MATLAB sets the recycle command accordingly. After clicking
a hyperlink, run recycle in the Command Window to confirm that the setting is as you expect.
Dynamic Link to a File
You can specify a link to a file that you know is in the matlabroot of your reader. You do not need to
know where each reader installed MATLAB. For example, link to the function code for publish.
%%
% See the
% <matlab:edit(fullfile(matlabroot,'toolbox','matlab','codetools','publish.m')) code>
% for the publish function.
When you click the code link, the MATLAB Editor opens and displays the code for the publish
function. On the reader's system, MATLAB issues the command (although the command does not
appear in the reader's Command Window).
Dynamic Link to a MATLAB Function Reference Page
You can specify a link to a MATLAB function reference page using matlab: syntax. For example,
suppose that your reader has MATLAB installed and running. Provide a link to the publish reference
page.
23-16
Publishing Markup
%%
% See the help for the <matlab:doc('publish') publish> function.
When you click the publish hyperlink, the reference page for the publish function opens in the
system web browser. On the reader's system, MATLAB issues the command, although the command
does not appear in the Command Window.
HTML Markup
You can insert HTML markup into your MATLAB file. You must type the HTML markup since no
button on the Publish tab generates it.
Note When you insert text markup for HTML code, the HTML code publishes only when the
specified output file format is HTML.
If you publish the code to HTML, MATLAB creates a 2-row table with two columns. The table contains
the values one, two, three, and four.
If a section produces command-window output that starts with <html> and ends with </html>,
MATLAB includes the source HTML in the published output. For example, MATLAB displays the disp
command and makes a table from the HTML code if you publish this code:
23-17
23 Presenting MATLAB Code
disp('<html><table><tr><td>1</td><td>2</td></tr></table></html>')
LaTeX Markup
You can insert LaTeX markup into your MATLAB file. You must type all LaTeX markup since no button
on the Publish tab generates it.
Note When you insert text markup for LaTeX code, that code publishes only when the specified
output file format is LaTeX.
If you publish the file to LaTeX, then the Editor opens a new .tex file containing the LaTeX markup.
\documentclass{article}
\usepackage{graphicx}
\usepackage{color}
\sloppy
\definecolor{lightgray}{gray}{0.5}
\setlength{\parindent}{0pt}
\begin{document}
23-18
Publishing Markup
\begin{par}
This is a table:
\end{par} \vspace{1em}
\begin{par}
\begin{tabular}{|c|c|} \hline
$n$ & $n!$ \\ \hline
1 & 1 \\
2 & 2 \\
3 & 6 \\ \hline
\end{tabular}
\end{par} \vspace{1em}
\end{document}
MATLAB includes any additional markup necessary to compile this file with a LaTeX program.
See Also
More About
• “Publish and Share MATLAB Code” on page 23-2
• “Output Preferences for Publishing” on page 23-20
23-19
23 Presenting MATLAB Code
Use the MATLAB expression pane to specify the code that executes during publishing. Use the
Publish settings pane to specify output, figure, and code execution options.
Together, the panes make what MATLAB refers to as a publish configuration. MATLAB associates
each publish configuration with an .m file. The name of the publish configuration is displayed at
the top of the dialog box and is editable.
23-20
Output Preferences for Publishing
Format Notes
html Publishes to an HTML document. You can use an Extensible Stylesheet
Language (XSL) file.
xml Publishes to XML document. You can use an Extensible Stylesheet Language
(XSL) file.
latex Publishes to LaTeX document. Does not preserve syntax highlighting. You can
use an Extensible Stylesheet Language (XSL) file.
doc Publishes to a Microsoft Word document. Does not preserve syntax
highlighting. This format is only available on Windows platforms.
ppt Publishes to a Microsoft PowerPoint document. Does not preserve syntax
highlighting. This format is only available on Windows platforms.
pdf Publishes to a PDF document.
Note XSL files allow you more control over the appearance of the output document. For more
details, see https://docbook.sourceforge.net/release/xsl/current/doc/.
Specifying Code
By default, MATLAB executes the .m file that you are publishing. However, you can specify any valid
MATLAB code in the MATLAB expression pane. For example, if you want to publish a function that
requires input, then run the command function(input). Additional code, whose output you want
to publish, appears after the functions call. If you clear the MATLAB expression area, then MATLAB
publishes the file without evaluating any code.
Note Publish configurations use the base MATLAB workspace. Therefore, a variable in the MATLAB
expression pane overwrites the value for an existing variable in the base workspace.
Evaluating Code
Another way to affect what MATLAB executes during publishing is to set the Evaluate code option in
the Publish setting pane. This option indicates whether MATLAB evaluates the code in the .m file
that is publishing. If set to true, MATLAB executes the code and includes the results in the output
document.
Because MATLAB does not evaluate the code nor include code results when you set the Evaluate
code option to false, there can be invalid code in the file. Therefore, consider first running the file
with this option set to true.
23-21
23 Presenting MATLAB Code
For example, suppose that you include comment text, Label the plot, in a file, but forget to
preface it with the comment character. If you publish the document to HTML, and set the Evaluate
code option to true, the output includes an error.
Use the false option to publish the file that contains the publish function. Otherwise, MATLAB
attempts to publish the file recursively.
Including Code
You can specify whether to display MATLAB code in the final output. If you set the Include code
option to true, then MATLAB includes the code in the published output document. If set to false,
MATLAB excludes the code from all output file formats, except HTML.
If the output file format is HTML, MATLAB inserts the code as an HTML comment that is not visible
in the web browser. If you want to extract the code from the output HTML file, use the MATLAB
grabcode function.
grabcode('sine_wave.html')
Catching Errors
You can catch and publish any errors that occur during publishing. Setting the Catch error option to
true includes any error messages in the output document. If you set Catch error to false, MATLAB
terminates the publish operation if an error occurs during code evaluation. However, this option has
no effect if you set the Evaluate code property to false.
You can limit the number of lines of code output that is included in the output document by specifying
the Max # of output lines option in the Publish settings pane. Setting this option is useful if a
smaller, representative sample of the code output suffices.
For example, the following loop generates 100 lines in a published output unless Max # of output
lines is set to a lower value.
23-22
Output Preferences for Publishing
for n = 1:100
disp(x)
end;
When publishing, you can choose the image format that MATLAB uses to store any graphics
generated during code execution. The available image formats in the drop-down list depend on the
setting of the Figure capture method option. For greatest compatibility, select the default as
specified in this table.
Output File Format Default Image Format Types of Images You Can Include
doc png Any format that your installed version of
Microsoft Office supports.
html png All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
latex png or epsc2 All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
pdf bmp bmp and jpg.
ppt png Any format that your installed version of
Microsoft Office supports.
xml png All formats publish successfully. Ensure that the
tools you use to view and process the output
files can display the output format you specify.
You set the size of MATLAB generated images in the Publish settings pane on the Edit
Configurations dialog window. You specify the image size in pixels to restrict the width and height of
images in the output. The pixel values act as a maximum size value because MATLAB maintains an
image’s aspect ratio. MATLAB ignores the size setting for the following cases:
• When working with external graphics as described in “External Graphics” on page 23-11
• When using vector formats, such as .eps
• When publishing to .pdf
23-23
23 Presenting MATLAB Code
Capturing Figures
You can capture different aspects of the Figure window by setting the Figure capture method
option. This option determines the window decorations (title bar, toolbar, menu bar, and window
border) and plot backgrounds for the Figure window.
This table summarizes the effects of the various Figure capture methods.
Use This Figure Capture To Get Figure Captures with These Appearance Details
Method
Window Decorations Plot Backgrounds
entireGUIWindow Included for dialog boxes; Excluded for Set to white for figures; matches the
figures screen for dialog boxes
print Excluded for dialog boxes and figures Set to white
getframe Excluded for dialog boxes and figures Matches the screen plot background
entireFigureWindow Included for dialog boxes and figures Matches the screen plot background
Note Typically, MATLAB figures have the HandleVisibility property set to on. Dialog boxes are
figures with the HandleVisibility property set to off or callback. If your results are different
from the results listed in the preceding table, the HandleVisibility property of your figures or
dialog boxes might be atypical. For more information, see HandleVisibility.
MATLAB allows you to specify custom appearance for figures it creates. If the Use new figure option
in the Publish settings pane is set to true, then in the published output, MATLAB uses a Figure
window at the default size and with a white background. If the Use new figure option is set to
false, then MATLAB uses the properties from an open Figure window to determine the appearance
of code-generated figures. This preference does not apply to figures included using the syntax in
“External Graphics” on page 23-11.
Use the following code as a template to produce Figure windows that meet your needs.
% Create figure
figure1 = figure('Name','purple_background',...
'Color',[0.4784 0.06275 0.8941]);
colormap('hsv');
% Create subplot
subplot(1,1,1,'Parent',figure1);
box('on');
% Create title
title({'Title'});
23-24
Output Preferences for Publishing
By publishing your file with this window open and the Use new figure option set to false, any code-
generated figure takes the properties of the open Figure window.
Note You must set the Figure capture method option to entireFigureWindow for the final
published figure to display all the properties of the open Figure window.
Creating a Thumbnail
You can save the first code-generated graphic as a thumbnail image. You can use this thumbnail to
represent your file on HTML pages. To create a thumbnail, follow these steps:
1 On the Publish tab, click Publish and select Edit Publishing Options. The Edit
Configurations dialog box opens.
2 Set the Image Format option to a bitmap format, such as .png or .jpg. MATLAB creates
thumbnail images in bitmap formats.
3 Set the Create thumbnail option to true.
MATLAB saves the thumbnail image in the folder specified by the Output folder option in the
Publish settings pane.
23-25
23 Presenting MATLAB Code
When the Publish settings options are set, you can follow these steps to save the settings:
1 Click Save As when the options are set in the manner you want.
The Save Publish Settings As dialog box opens and displays the names of all the currently
defined publish settings. By default the following publish settings install with MATLAB:
• Factory Default
You cannot overwrite the Factory Default and can restore them by selecting Factory
Default from the Publish settings list.
• User Default
Initially, User Default settings are identical to the Factory Default settings. You can
overwrite the User Default settings.
2 In the Settings Name field, enter a meaningful name for the settings. Then click Save.
You can now use the publish settings with other MATLAB files.
You also can overwrite the publishing properties saved under an existing name. Select the name
from the Publish settings list, and then click Overwrite.
23-26
Output Preferences for Publishing
Together, the code in the MATLAB expression pane and the settings in the Publish settings pane
make a publish configuration that is associated with one file. These configurations provide a simple
way to refer to publish preferences for individual files.
To create a publish configuration, on the Publish tab, click Publish , and select Edit Publishing
Options. The Edit Configurations dialog box opens, containing the default publish preferences. In the
Publish configuration name field, type a name for the publish configuration, or accept the default
name. The publish configuration saves automatically.
After saving a publish configuration, you can run it without opening the Edit Configurations dialog
box:
1 Click Publish . If you position your mouse pointer on a publish configuration name, MATLAB
displays a tooltip showing the MATLAB expression associated with the specific configuration.
2 Select a configuration name to use for the publish configuration. MATLAB publishes the file using
the code and publish settings associated with the configuration.
You can create multiple publish configurations for a given file. You might do this to publish the file
with different values for input arguments, with different publish setting property values, or both.
Create a named configuration for each purpose, all associated with the same file. Later you can run
whichever particular publish configuration you want.
A new name appears on the configurations list, filename_n, where the value of n depends on
the existing configuration names.
23-27
23 Presenting MATLAB Code
4 If you modify settings in the MATLAB expression or Publish setting pane, MATLAB
automatically saves the changes.
Each publish configuration is associated with a specific file. If you move or rename a file, redefine its
association. If you delete a file, consider deleting the associated configurations, or associating them
with a different file.
When MATLAB cannot associate a configuration with a file, the Edit Configurations dialog box
displays the file name in red and a File Not Found message. To reassociate a configuration with
another file, perform the following steps.
1
Click the Clear search button on the left pane of the Edit Configurations dialog box.
2 Select the file for which you want to reassociate publish configurations.
3 In the right pane of the Edit Configurations dialog box, click Choose.... In the Open dialog box,
navigate to and select the file with which you want to reassociate the configurations.
You can rename the configurations at any time by selecting a configuration from the list in the left
pane. In the right pane, edit the value for the Publish configuration name.
Note To run correctly after a file name change, you might need to change the code statements in the
MATLAB expression pane. For example, change a function call to reflect the new file name for that
function.
Each time you create or save a publish configuration using the Edit Configurations dialog box, the
Editor updates the publish_configurations.m file in your preferences folder. (This is the folder
that MATLAB returns when you run the MATLAB prefdir function.)
Although you can port this file from the preferences folder on one system to another, only one
publish_configurations.m file can exist on a system. Therefore, only move the file to another
system if you have not created any publish configurations on the second system. In addition, because
23-28
Output Preferences for Publishing
the publish_configurations.m file might contain references to file paths, be sure that the
specified files and paths exist on the second system.
MathWorks recommends that you not update publish_configurations.m in the MATLAB Editor
or a text editor. Changes that you make using tools other than the Edit Configurations dialog box
might be overwritten later.
See Also
More About
• “Publish and Share MATLAB Code” on page 23-2
• “Publishing Markup” on page 23-5
23-29
24
You can save your files in the Editor and Live Editor using several methods. In the Editor, you also can
create backup copies of your files. Creating backup copies of your files ensures that you have a
known working version of the files before making changes to them, and can also be useful for
recovering lost changes after a system problem.
Depending on your needs, you can also control how the files you save are encoded and cached.
Save Code
When you modify a file in the Editor or the Live Editor, MATLAB indicates that there are unsaved
changes in the file by displaying an asterisk (*) next to the file name in the document tab.
To save the file, go to the Editor or Live Editor tab, and in the File section, click Save.
To change the name, location, or type of a file, select Save > Save As. For example, to save a live
script as a plain code file (.m), on the Live Editor tab, in the File section, select Save > Save As. In
the dialog box that appears, select MATLAB Code files (UTF-8) (*.m) as the Save as type and
click Save.
Back Up Code
You can create backup copies of your files in the Editor. Creating a backup copy of a file ensures that
you have a known working version of the file before making changes to it. To create a backup copy of
a file, on the Editor tab, in the File section, select Save > Save Copy As. This option is not available
in the Live Editor or in MATLAB Online.
In addition, when you modify files in the Editor, MATLAB automatically creates backup copies of the
files. If you lose changes to your files due to system problems, you can use the automatically created
backup copies of the files to recover the changes.
By default, MATLAB saves a backup copy of a modified file every five minutes using the same file
name but with an .asv extension. For example, filename.m would have a backup file name of
filename.asv. If you lose changes to your file, you can recover the unsaved changes by opening the
backup copy of the file, filename.asv, and saving it as filename.m.
24-2
Save and Back Up Code
To change how and when MATLAB saves backup copies of files, on the Home tab, in the
Environment section, click Preferences. Then, select MATLAB > Editor/Debugger > Backup
Files. You can specify:
• How often to save backup copies of the files you are editing.
• What file extension to use when creating backup copies of files.
• Where to save backup copies of files.
• Whether to automatically delete backup copies of files when you close the corresponding source
file in the Editor.
For more information about the available options, see the Backup Files preferences in “Editor/
Debugger Preferences”.
In MATLAB Online, every time you save a code file in the Editor, MATLAB stores the contents of your
code file in the version history. For more information about recovering a previous version of a file in
MATLAB Online, see “Access Files in MATLAB Online”.
MATLAB does not automatically create backups of files modified in the Live Editor.
If you do save files in the matlabroot folder tree, you may need to take extra steps for your changes
to take effect. At the beginning of each MATLAB session, MATLAB loads and caches in memory the
locations of files in the matlabroot folder tree. Therefore, if you add, remove, or make changes to
files in the matlabroot folder tree using an external editor or file system operations, you must
update the cache so that MATLAB recognizes the changes you made. For more information, see
“Toolbox Path Caching in MATLAB”.
File Encoding
As of R2020a, when the Editor saves a new MATLAB code file that has a .m extension, such as a
script or a function, it uses UTF-8 without a byte-order-mark (BOM). The Editor saves existing files
with their current encoding unless a different one is selected from the Save As dialog. For example, to
save a file using a legacy locale-specific encoding for compatibility with an earlier release of MATLAB,
on the Editor tab, in the File section, select Save > Save as. In the dialog box that appears, select
the desired encoding from the Save as type options.
The current encoding is displayed next to the file name in the Editor status bar or, if the Editor
Window is docked, the Desktop status bar.
24-3
24 Coding and Productivity Tips
See Also
More About
• “Editor/Debugger Preferences”
• “Manage Files and Folders”
24-4
Check Code for Errors and Warnings Using the Code Analyzer
Check Code for Errors and Warnings Using the Code Analyzer
The MATLAB Code Analyzer can automatically check your code for coding problems. You can view
warning and error messages about your code, and modify your file based on the messages. The
messages are updated automatically and continuously so you can see if your changes address the
issues noted in the messages. Some messages offer additional information, automatic code
correction, or both.
A list of all checks performed by the MATLAB Code Analyzer can be found here, “Index of Code
Analyzer Checks”.
To enable continuous code checking, on the Home tab, in the Environment section, click
Preferences. Select MATLAB > Code Analyzer, and then select the Enable integrated warning
and error messages check box. Set the Underlining option to Underline warnings and
errors.
When continuous code checking is enabled, MATLAB displays warning and error messages about
your code in the Editor and Live Editor. For example, the sample file lengthofline.m contains
several errors and warnings. Copy the code into the Editor and save the file as lengthofline.m.
lengthofline.m Code
function [len,dims] = lengthofline(hline)
%LENGTHOFLINE Calculates the length of a line object
% LEN = LENGTHOFLINE(HLINE) takes the handle to a line object as the
% input, and returns its length. The accuracy of the result is directly
% dependent on the number of distinct points used to describe the line.
%
% [LEN,DIM] = LENGTHOFLINE(HLINE) additionally tells whether the line is
% 2D or 3D by returning either a numeric 2 or 3 in DIM. A line in a
% plane parallel to a coordinate plane is considered 2D.
%
% If HLINE is a matrix of line handles, LEN and DIM will be matrices of results.
%
% Example:
% figure; h2 = plot3(1:10,rand(1,10),rand(10,5));
% hold on; h1 = plot(1:10,rand(10,5));
% [len,dim] = lengthofline([h1 h2])
len = zeros(size(hline));
for nl = 1:prod(size(hline))
% If it's a line, get the data and compute the length
if ~notline(nl)
flds = get(hline(nl));
fdata = {'XData','YData','ZData'};
for nd = 1:length(fdata)
data{nd} = getfield(flds,fdata{nd});
end
% If there's no 3rd dimension, or all the data in one dimension is
% unique, then consider it to be a 2D line.
if isempty(data{3}) | ...
(length(unique(data{1}(:)))==1 | ...
length(unique(data{2}(:)))==1 | ...
length(unique(data{3}(:)))==1)
data{3} = zeros(size(data{1}));
dim(nl) = 2;
else
dim(nl) = 3;
24-5
24 Coding and Productivity Tips
end
% Do the actual computation
temp = diff([data{1}(:) data{2}(:) data{3}(;)]);
len(nl) = sum([sqrt(dot(temp',temp'))])
end
end
% If some indices are not lines, fill the results with NaNs.
if any(notline(:))
warning('lengthofline:FillWithNaNs', ...
'\n%s of non-line objects are being filled with %s.', ...
'Lengths','NaNs','Dimensions','NaNs')
len(notline) = NaN;
dim(notline) = NaN;
end
if nargout > 1
dims = dim;
end
24-6
Check Code for Errors and Warnings Using the Code Analyzer
For example, in lengthofline.m, when you click the message indicator, the cursor moves to line 47,
where the first error occurs. MATLAB displays the errors for that line next to the error marker in the
indicator bar. Multiple messages can represent a single problem or multiple problems. Addressing
one message might address all of them. Or, after you address one, the other messages might change
or what you need to do can become clearer.
24-7
24 Coding and Productivity Tips
To go to the next code fragment containing a message, click the message indicator. You also can click
a marker in the indicator bar to go to the line that the marker represents. For example, click the first
marker in the indicator bar in lengthofline.m. The cursor moves to the beginning of line 21.
To view the message for a code fragment, move the mouse pointer within the underlined code
fragment. Alternatively, you can position your cursor within the underlined code fragment and press
Ctrl+M. If additional information is available for the message, the message includes a Details
button. Click the button to display the additional information and any suggested user actions.
For example, on line 47 in lengthofline.m, the message suggests a delimiter imbalance. When you
move the arrow keys over each delimiter, MATLAB does not appear to indicate a mismatch. However,
code analysis detects the semicolon in data{3}(;) and interprets it as the end of a statement.
To fix the problem in line 47, change data{3}(;) to data{3}(:). The single change addresses all
of the messages on line 47, and the underline no longer appears for the line. Because the change
removes the only error in the file, the message indicator at the top of the bar changes from to ,
indicating that only warnings and potential improvements remain.
For some messages, MATLAB suggests an automatic fix that you can apply to fix the problem. If an
automatic fix is available for a problem, the code fragment is highlighted and the message includes a
Fix button.
24-8
Check Code for Errors and Warnings Using the Code Analyzer
For example, on line 27 in lengthofline.m, place the mouse over the underlined and highlighted
code fragment prod. The displayed message includes a Fix button.
If you know how to fix the problem, perhaps from prior experience, click the Fix button or press Alt
+Enter. If you are unfamiliar with the problem, right-click the highlighted code. The first item in the
context menu shows the suggested fix. Select the item to apply the fix.
If multiple instances of a problem exist, MATLAB might offer to apply the suggested fix for all
instances of the problem. To apply the fix for all instances of a problem, right-click the highlighted
code and select Fix All (n) Instances of This Issue. This option is not available for all suggested
fixes.
After you modify the code to address all the messages or disable designated messages, the message
indicator becomes green. See the example file, lengthofline2.m, with all messages addressed.
lengthofline2.m Code
function [len,dims] = lengthofline2(hline)
%LENGTHOFLINE Calculates the length of a line object
% LEN = LENGTHOFLINE(HLINE) takes the handle to a line object as the
% input, and returns its length. The accuracy of the result is directly
% dependent on the number of distinct points used to describe the line.
%
% [LEN,DIM] = LENGTHOFLINE(HLINE) additionally tells whether the line is
% 2D or 3D by returning either a numeric 2 or 3 in DIM. A line in a
% plane parallel to a coordinate plane is considered 2D.
%
% If HLINE is a matrix of line handles, LEN and DIM will be matrices of results.
%
% Example:
% figure; h2 = plot3(1:10,rand(1,10),rand(10,5));
% hold on; h1 = plot(1:10,rand(10,5));
% [len,dim] = lengthofline([h1 h2])
len = zeros(size(hline));
dim = len;
for nl = 1:numel(hline)
% If it's a line, get the data and compute the length
if ~notline(nl)
24-9
24 Coding and Productivity Tips
flds = get(hline(nl));
fdata = {'XData','YData','ZData'};
data = cell(size(fdata));
for nd = 1:length(fdata)
data{nd} = flds.(fdata{nd});
end
% If there's no 3rd dimension, or all the data in one dimension is
% unique, then consider it to be a 2D line.
if isempty(data{3}) || ...
(length(unique(data{1}(:)))==1 || ...
length(unique(data{2}(:)))==1 || ...
length(unique(data{3}(:)))==1)
data{3} = zeros(size(data{1}));
dim(nl) = 2;
else
dim(nl) = 3;
end
% Do the actual computation
temp = diff([data{1}(:) data{2}(:) data{3}(:)]);
len(nl) = sum(sqrt(dot(temp',temp'))) %#ok<NOPRT>
end
end
% If some indices are not lines, fill the results with NaNs.
if any(notline(:))
warning('lengthofline2:FillWithNaNs', ...
'\n%s of non-line objects are being filled with %s.', ...
'Lengths','NaNs','Dimensions','NaNs')
len(notline) = NaN;
dim(notline) = NaN;
end
if nargout > 1
dims = dim;
end
•
MATLAB Toolstrip: On the Apps tab, under MATLAB, click the app icon: .
• MATLAB command prompt: Enter codeAnalyzer.
24-10
Check Code for Errors and Warnings Using the Code Analyzer
For example, you can generate a codeIssues object containing the issues in a specified file:
issues = codeIssues("test.m")
issues =
24-11
24 Coding and Productivity Tips
"test.m" info manual "Variable appears to change size on every loop iteratio
"test.m" info auto "Add a semicolon after the statement to hide the output
"test.m" info auto "string('...') is not recommended. Use "..." instead."
The information contained in the a codeIssues object can be exported using export.
To open the Code Issues panel, go to the Editor or Live Editor tab, and in the Analyze section, click
Code Issues. Alternatively, you can open the panel using the Open more panels button ( ) in a
sidebar. By default, the Code Issues panel opens on the right side of the desktop. To hide the Code
Issues panel, click the Code Issues
icon in the sidebar.
You can change what messages display in the Code Issues panel using the options at the top of the
panel:
• Change which files to look for issues in — In the drop-down list at the top-left of the Code Issues
panel, select Open Files to show the errors, warnings, and info messages for the current file or
Open Files to show the errors, warnings, and info messages for all open files.
• Filter messages by type — At the top-right of the Code Issues panel, click the Errors
,
Warnings
24-12
Check Code for Errors and Warnings Using the Code Analyzer
, or Infos
button to toggle whether to show messages of that type. For example, to show only errors, click
the Errors button
on and
the Warnings
and
Infos buttons off.
• Filter messages by text — Use the search field below the drop-down list to filter the list of
messages by text. For example, to display only messages that contain the word Variable, enter
the word Variable in the search field.
You also can adjust what messages you see when analyzing your code. Code analysis does not provide
perfect information about every situation. Sometimes, you might not want to change the code based
on a message. If you do not want to change the code, and you do not want to see the indicator and
message for a specific line, you can suppress them. For example, the first message on line 48 of the
sample file lengthofline.m is Terminate statement with semicolon to suppress
output (in functions). Adding a semicolon to the end of a statement suppresses output and is a
common practice. Code analysis alerts you to lines that produce output, but lack the terminating
semicolon. If you want to view output from line 48, do not add the semicolon as the message
suggests.
You can suppress (turn off) the indicators for warning and error messages in these ways:
You can suppress a specific instance of a Code Analyzer message in the current file. For example, to
suppress the message on line 48 in the sample file lengthofline.m, right-click the first underline
on line 48 and select Suppress 'Terminate statement with semicolon...' > On This Line.
The comment %#ok<NOPRT> appears at the end of the line, which instructs MATLAB to suppress the
Terminate statement with semicolon to suppress output (in functions) Code
Analyzer message for that line. The underline and mark in the indicator bar for the message
disappear.
If a line contains two messages that you do not want to display, right-click each underline separately
and select the appropriate entry from the context menu. The %#ok syntax expands. For example,
24-13
24 Coding and Productivity Tips
suppressing both messages for line 48 in the sample file lengthofline.m adds the comment
%#ok<NBRAK,NOPRT> at the end of the line.
Even if Code Analyzer preferences are set to enable this message, the specific instance of the
suppressed message does not appear because the %#ok takes precedence over the preference
setting. If you later decide you want to show the Terminate statement with semicolon to
suppress output (in functions) Code Analyzer message for that line, delete %#ok<NOPRT>
from the line.
You can suppress all instances of a specific Code Analyzer message in the current file. For example, to
suppress all instances of the message on line 48 in the sample file lengthofline.m, right-click the
first underline on line 48 and select Suppress 'Terminate statement with semicolon...' > In This
File.
The comment %#ok<*NOPRT> appears at the end of the line, which instructs MATLAB to suppress all
instances of the Terminate statement with semicolon to suppress output (in
functions) Code Analyzer message in the current file. All underlines and marks in the message
indicator bar that correspond to this message disappear.
If a line contains two messages that you do not want to display anywhere in the current file, right-
click each underline separately and select the appropriate entry from the context menu. The %#ok
syntax expands. For the example, suppressing both messages for line 48 in the sample file
lengthofline.m adds the comment %#ok<*NBRAK,*NOPRT>.
Even if Code Analyzer preferences are set to enable this message, the message does not appear
because the %#ok takes precedence over the preference setting. If you later decide you want to show
all instances of the Terminate statement with semicolon to suppress output (in
functions) Code Analyzer message in the current file, delete %#ok<*NOPRT> from the line.
You can disable all instances of a Code Analyzer message in all files. For example, to suppress all
instances in all files of the message on line 48 in the sample file lengthofline.m, right-click the
first underline on line 48 and select Suppress 'Terminate statement with semicolon...' > In All
Files. This option modifies the Code Analyzer preferences.
If you know which messages you want to suppress, you can disable them directly using Code Analyzer
preferences:
1
On the Home tab, in the Environment section, click Preferences.
2 Select MATLAB > Code Analyzer.
3 Search the messages to find the ones you want to suppress.
4 Clear the check box associated with each message you want to suppress in all files.
5 Click OK.
You can set options to enable or disable certain Code Analyzer messages, and then save those
settings to a file. When you want to use a settings file with a particular file, you select it from the
Code Analyzer preferences. The settings file remains in effect until you select another settings file.
24-14
Check Code for Errors and Warnings Using the Code Analyzer
Typically, you change the settings file when you have a subset of files for which you want to use a
particular settings file.
1
On the Home tab, in the Environment section, click Preferences.
2 Select MATLAB > Code Analyzer.
3 Enable or disable specific messages or categories of messages.
4 Click the Actions button , select Save As, and then save the settings to a txt file.
5 Click OK.
You can reuse these settings for any MATLAB file, or provide the settings file to another user. To use
the saved settings:
1
On the Home tab, in the Environment section, click Preferences.
2 Select MATLAB > Code Analyzer.
3 Open the Active settings list and select Browse.
4 Choose from any of your settings files.
The settings you choose remain in effect for all MATLAB files until you select another set of Code
Analyzer settings.
You can modify existing Code Analyzer checks, including whether the check is enabled and its
severity, message text, and parameters if the check has any, such as to limit the number of input and
output arguments for a function. You can also create custom checks that trigger when specific
functions are used. For more information on configuring Code Analyzer checks, see “Configure Code
Analyzer”.
• One or more %#ok<message-ID> directives are on a line of code that elicits a message specified
by <message-ID>.
• One or more %#ok<*message-ID> directives are in a file that elicits a message specified by
<message-ID>.
• The messages are cleared in the Code Analyzer preferences pane.
24-15
24 Coding and Productivity Tips
To determine why messages are suppressed call codeIssues with the file as the input.
issues = codeIssues("myFile.m")
The output, issues, will have a property, SuppressedIssues, contains a table listing all the
suppressed issues within the file. Review the message associated with each issue to understand why
it is suppressed.
• Code analysis sometimes fails to produce Code Analyzer messages where you expect them.
By design, code analysis attempts to minimize the number of incorrect messages it returns, even if
this behavior allows some issues to go undetected.
• Code analysis sometimes produces messages that do not apply to your situation.
Clicking the Details button to display additional information for a message can help you
determine if the message applies to your situation. Error messages are almost always problems.
However, many warnings are suggestions to look at something in the code that is unusual, but
might be correct in your case.
Suppress a warning message if you are certain that the message does not apply to your situation.
If your reason for suppressing a message is subtle or obscure, include a comment giving the
rationale. That way, those who read your code are aware of the situation.
For more information, see “Adjust Code Analyzer Message Indicators and Messages” on page 24-
13.
Code analysis cannot always distinguish function names from variable names. For the following code,
if the Code Analyzer message is enabled, code analysis returns the message, Code Analyzer
cannot determine whether xyz is a variable or a function, and assumes it is a
function. Code analysis cannot make a determination because xyz has no obvious value assigned to
it. However, the code might have placed the value in the workspace in a way that code analysis
cannot detect.
function y=foo(x)
.
.
.
y = xyz(x);
end
For example, in the following code, xyz can be a function or a variable loaded from the MAT-file.
Code analysis has no way of making a determination.
function y=foo(x)
load abc.mat
y = xyz(x);
end
24-16
Check Code for Errors and Warnings Using the Code Analyzer
Variables might also be undetected by code analysis when you use the eval, evalc, evalin, or
assignin functions.
• Initialize the variable so that code analysis does not treat it as a function.
• For the load function, specify the variable name explicitly in the load command line. For
example:
function y=foo(x)
load abc.mat xyz
y = xyz(x);
end
Code analysis cannot always distinguish structures from handle objects. In the following code, if x is
a structure, you might expect a Code Analyzer message indicating that the code never uses the
updated value of the structure. If x is a handle object, however, then this code can be correct.
function foo(x)
x.a = 3;
end
Code analysis cannot determine whether x is a structure or a handle object. To minimize the number
of incorrect messages, code analysis returns no message for the previous code, even though it might
contain a subtle and serious bug.
If some built-in functions are overloaded in a class or on the path, Code Analyzer messages might
apply to the built-in function, but not to the overloaded function you are calling. In this case, suppress
the message on the line where it appears or suppress it for the entire file.
For information on suppressing messages, see “Adjust Code Analyzer Message Indicators and
Messages” on page 24-13.
Code analysis has a limited ability to determine the type of variables and the shape of matrices. Code
analysis might produce messages that are appropriate for the most common case, such as for vectors.
However, these messages might be inappropriate for less common cases, such as for matrices.
Code Analyzer has limited capabilities to check class definitions with superclasses. For example, Code
Analyzer cannot always determine if the class is a handle class, but it can sometimes validate custom
attributes used in a class if the attributes are inherited from a superclass. When analyzing class
definitions, Code Analyzer tries to use information from the superclasses, but often cannot get
enough information to make a certain determination.
Most class methods must contain at least one argument that is an object of the same class as the
method. But this argument does not always have to be the first argument. When it is, code analysis
24-17
24 Coding and Productivity Tips
can determine that an argument is an object of the class you are defining, and can do various checks.
For example, code analysis can check that the property and method names exist and are spelled
correctly. However, when code analysis cannot determine that an object is an argument of the class
you are defining, then it cannot provide these checks.
1
On the Home tab, in the Environment section, click Preferences.
2 Select MATLAB > Code Analyzer.
3 Click the down arrow next to the search field, and then select Show Messages in Category >
MATLAB Compiler (Deployment) Messages.
4 Click the Enable Category button to the right of the MATLAB Compiler (Deployment)
Messages category title.
5 Clear individual messages that you do not want to display for your code.
6 Decide if you want to save these settings, so you can reuse them the next time you work on a file
to be deployed.
The settings txt file, which you can create as described in “Save and Reuse Code Analyzer Message
Settings” on page 24-14, includes the status of this setting.
See Also
Code Analyzer | codeIssues | checkcode
Related Examples
• “MATLAB Code Analyzer Report” on page 24-32
• “Code Analyzer Preferences”
• “Configure Code Analyzer”
• “Index of Code Analyzer Checks”
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
24-18
Edit and Format Code
Column Selection
When adding or editing code in the Editor and Live Editor, you can select and edit a rectangular area
of code (also known as column selection or block edit). If you want to copy or delete several columns
of data (as opposed to rows) or if you want to edit multiple lines at one time, selecting and editing
code is useful. To select a rectangular area, press the Alt key while making a selection with the
mouse. On macOS systems, use the Option key instead.
Column selection is available only in the Live Editor, not in the Editor.
Change Case
You can change the case of selected text or code from all uppercase to lowercase, or vice versa, in the
Editor and Live Editor. Select the text, right-click, and select Change Case. Alternatively, you can
press Ctrl+Shift+A. If the text contains uppercase and lowercase text, MATLAB changes the case to
all uppercase.
The Change Case option is available only in the Live Editor, not in the Editor.
MATLAB can also automatically complete block endings in control flow statements and function and
class definitions. To autocomplete block endings, on the Home tab, in the Environment section,
24-19
24 Coding and Productivity Tips
click Preferences. Select Editor/Debugger > Automatic Completions and in the Autocoding
options section, select one or more of the Autocomplete block endings options.
To undo an automatic code completion, press Ctrl+Z or the Undo button. To disable automatic
code completions, in the Editor/Debugger > Automatic Completions preferences, clear one or
more of the options in the Autocoding options section. For more information, see “Editor/Debugger
Preferences”.
MATLAB completes code only in the Live Editor, not in the Editor.
Refactor Code
You can break large scripts or functions into smaller pieces by converting selected areas of code into
functions or local functions, known as code refactoring.
Refactoring options are available only in the Live Editor, not in the Editor.
Indent Code
Indenting code makes functions and statements, such as while loops, easier to read. By default,
MATLAB automatically indents code in the Editor and Live Editor as you type. When you indent lines
by using tabs or spaces, MATLAB also aligns subsequent lines with those lines.
To indent selected lines of code if automatic indenting is disabled, go to the Editor or Live Editor
tab and in the Code section, click the Smart Indent button.
To manually change the indent of selected lines to be farther right or left, on the Editor or Live
Editor tab, click the Increase Indent or Decrease Indent buttons. Manually changing the
indent works whether automatic indenting is enabled or disabled. Alternatively, you can use the Tab
key or the Shift+Tab keys, respectively.
If you prefer not to use automatic indenting, you can disable it. Each language in MATLAB that
supports automatic indenting has its own option to disable it.
1
On the Home tab, in the Environment section, click Preferences.
2 Select MATLAB > Editor/Debugger > Language and in the Language drop-down list, select a
programming language.
3 In the Indenting section of the selected language, clear the Apply smart indenting while
typing option. This option is not supported for all languages.
24-20
Edit and Format Code
Indenting preferences for languages are supported only in the Editor, not in the Live Editor.
In MATLAB Online, to disable automatic indenting for individual languages, go to MATLAB > Editor/
Debugger > MATLAB Language and MATLAB > Editor/Debugger > Other Languages.
You can change the behavior of indenting in the Editor and Live Editor, including how functions in
MATLAB code files indent, whether automatic indenting formats the entire document, and whether
automatic indenting adds white space to empty lines.
To specify how functions indent in MATLAB code files, on the Home tab, in the Environment
section, click Preferences. Select MATLAB > Editor/Debugger > Language and in the
Language drop-down list, select MATLAB. Then, select from the Function indenting format
options. In MATLAB Online, this preference is located under MATLAB > Editor/Debugger >
MATLAB Language. For more information and examples of each function indenting format, see
“Editor/Debugger Preferences”.
To change the behavior of automatic indenting, use settings. For example, this code enables
formatting the entire document when automatically indenting. For more information, see
matlab.editor Settings.
s = settings;
s.matlab.editor.indent.SmartIndentEntireDocument.PersonalValue = 1;
In MATLAB Online, you also can configure the behavior of automatic indenting using the MATLAB >
Editor/Debugger > Indenting preferences. For more information, see “Editor/Debugger
Preferences”.
Fold Code
Code folding expands and collapses blocks of MATLAB code in the Editor. You can use code folding to
hide code that you are not currently working on. Code folding improves the readability of a file that
contains numerous functions or other blocks of code. Code folding is not supported in the Live Editor.
• Code sections
• for and parfor blocks
• Function code
• Class code
• Multiline comments
To expand or collapse a block of code, click the plus or minus sign that appears to the left of the
construct in the Editor. Alternatively, you can use the Ctrl+Shift+. (period) and Ctrl+. (period)
keyboard shortcuts or use the code folding buttons in the View tab.
To expand or collapse all of the code in a file, place your cursor anywhere within the file, go to the
View tab, and select the Expand All or Collapse All buttons. Alternatively, you can use the
Ctrl+Shift+, (comma) and Ctrl+, (comma) keyboard shortcuts.
24-21
24 Coding and Productivity Tips
Note If you print a file with one or more collapsed constructs, those constructs are expanded in the
printed version of the file.
You can change which programming constructs can be folded and whether a programming construct
is collapsed the first time that you open a MATLAB file. On the Home tab, in the Environment
section, click Preferences. Select Editor/Debugger > Code Folding, and then adjust the
preference options.
1
On the Home tab, in the Environment section, click Preferences.
2 In the Preferences window, select MATLAB > Editor/Debugger > Display.
3 Adjust the settings in the Right-hand text limit section.
The right-side text limit indicator is a visual cue only and does not prevent text from exceeding the
limit. To wrap comment text at a specified column number automatically, go to the Home tab and in
the Environment section, click Preferences. Select MATLAB > Editor/Debugger > Language,
and adjust the Comment formatting preferences. To adjust Comment formatting preferences in
MATLAB Online, select Editor/Debugger > MATLAB Language.
24-22
Edit and Format Code
See Also
Related Examples
• “Create Scripts” on page 18-2
• “Create Live Scripts in the Live Editor” on page 19-6
• “Format Text in the Live Editor” on page 19-20
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
24-23
24 Coding and Productivity Tips
You can search for, and optionally replace, any text within a file open in the Editor or Live Editor. To
search for text in a file, on the Editor or Live Editor tab, in the Navigate section, click Find. You
also can use the Ctrl+F keyboard shortcut.
In the Find and Replace dialog box, enter the text that you want to search for and then use the
and buttons to search backward or forward through the file. You also can use the Shift+F3 and
F3 keyboard shortcuts. To show a list of previous searches, use the Down Arrow key.
Select a search option to change how the Editor and Live Editor search for text.
Match case Search only for text with the precise case of the Alt+M
search text.
24-24
Find and Replace Text in Files and Go to Location
Find in selection Search only for text in the current selection. Alt+S
To replace text in the file, click the Show replace options button to the left of the search field to
open the replace options. Then, enter the text that you want to replace the search text with and use
the Replace and Replace All buttons to replace the text. You also can use the Alt+R and Alt+A
keyboard shortcuts. To show a list of previous replacements, use the Down Arrow key.
24-25
24 Coding and Productivity Tips
You can change the behavior of the Find and Replace dialog box using settings. For example, this
code disables the wrap-around search behavior in the Find and Replace dialog box. For more
information, see matlab.editor Settings.
s = settings;
s.matlab.editor.find.WrapAround.PersonalValue = 0;
In MATLAB Online, you also can use preferences to change the behavior of the Find and Replace
dialog box. On the Home tab, in the Environment section, click Preferences. Select MATLAB >
Editor/Debugger > Find and Replace and adjust the options as needed. For more information, see
“Editor/Debugger Preferences”.
Note If the indicator bar contains a code analyzer marker and a variable marker for the same line,
the variable marker takes precedence.
Finding functions and variables using automatic highlighting is more efficient than using text-finding
tools because when using automatic highlighting, MATLAB finds references only to that particular
function or variable, not other occurrences. For example, it does not find instances of the function or
variable name in comments. Furthermore, MATLAB finds references only to the same variable. That
is, if two variables use the same name, but are in different scopes on page 20-10, highlighting one
does not cause the other to highlight.
For example, if you select the first instance of the variable i in the rowTotals function, MATLAB
highlights that instance and the two other instances of i. In addition, MATLAB displays three variable
markers in the indicator bar.
24-26
Find and Replace Text in Files and Go to Location
To disable automatic highlighting of functions and variables, go to the Home tab and in the
Environment section, click Preferences. In MATLAB > Colors > Programming Tools, clear
the Automatically highlight option.
function foo(m)
Input or output variable name in a function Rename y or m in:
declaration
function y = foo(m)
(Except varargin and varargout)
Variable name on the left side of assignment Rename y in:
statement
y = 1
(Except global variable names)
When you rename a variable or function, if there is more than one reference to that variable or
function in the file, MATLAB prompts you to rename all instances by pressing Shift+Enter. You also
can rename only the instances from the current cursor location to the end of the file by pressing Alt
+Shift+Enter. On macOS, use Option+Shift+Enter instead. (Typically, multiple references to a
function in a file occur only when you use nested functions or local functions.)
24-27
24 Coding and Productivity Tips
To undo automatic name changes, click the button in the quick access toolbar once.
Automatic variable and function renaming is enabled by default. To disable it, on the Home tab, in
the Environment section, click Preferences. Select MATLAB > Editor/Debugger > Language
and in the Language field, select MATLAB. Then, clear the Enable automatic variable and
function renaming preference.
In MATLAB Online, the Enable automatic variable and function renaming preference is located
in MATLAB > Editor/Debugger > MATLAB Language.
Go To Location in File
You can go to a specific location in a file, set bookmarks, navigate backward and forward within the
file, and open a file or variable from within a file.
This table show how to navigate to a specific location in a file open in the Editor and Live Editor.
Go To Instructions Notes
Line Number On the Editor or Live Editor tab, in the None
Navigate section, click Go To . Select
Go to Line and specify the line that you
want to navigate to.
24-28
Find and Replace Text in Files and Go to Location
Go To Instructions Notes
Function definition On the Editor or Live Editor tab, in the Includes local functions and nested
Navigate section, click Go To . In the functions.
Function section, select the local function
For both class and function files, the
or nested function that you want to
functions list in alphabetical order—except
navigate to.
that in function files, the name of the main
You also can select the file in the Current function always appears at the top of the
Folder browser and click the up arrow at list.
the bottom of Current Folder browser to
open the Details panel. Then, in the Details
panel, double-click the function icon
corresponding to the title of the function or
local function that you want to navigate to.
Code Section On the Editor or Live Editor tab, in the For more information, see “Create and Run
Navigate section, click Go To . In the Sections in Code” on page 18-6.
Sections section, select the title of the
code section that you want to navigate to.
24-29
24 Coding and Productivity Tips
Note The Details panel does not display details for live scripts or live functions and is not available in
MATLAB Online.
Set Bookmarks
You can set a bookmark at any line in a file in the Editor and Live Editor so that you can quickly
navigate to the bookmarked line. Bookmarks are particularly useful in long files. For example,
suppose that while working on a line, you want to look at another part of the file and then return. Set
a bookmark at the current line, go to the other part of the file, and then use the bookmark to return.
To set a bookmark in the Editor and Live Editor, position the cursor on the line that you want to add
the bookmark to. Then, go to the Editor or Live Editor tab, and in the Navigate section, click
Bookmark. To clear the bookmark, click Bookmark , and select Set/Clear. You also can click the
bookmark icon to the left of the line.
In the Editor and Live Editor, you can access lines in a file in the same sequence that you previously
navigated or edited them. To navigate backward and forward in sequence, on the Editor or Live
Editor tab, in the Navigate section, click the and buttons.
Editing a line or navigating to another line using the list of features described in “Navigate to a
Specific Location” on page 24-28 interrupts the backward and forward sequence. Once the sequence
is interrupted, you can still go to the lines preceding the interruption point in the sequence, but you
cannot go to any lines after that point. Any lines that you edit or navigate to after interrupting the
sequence are added to the sequence after the interruption point.
For example, open a file containing more than 6 lines and edit lines 2, 4, and 6. Click the button to
return to line 4, and then again to return to line 2. Click the button to return to line 4. Edit line 3.
This interrupts the sequence. You can no longer use the button to return to line 6. You can,
however, click the button to return to line 2.
You can open a function, file, variable, or Simulink model from within a file in the Editor or Live
Editor. Position the cursor on the name, right-click, and select Open selection. The Editor or Live
Editor performs an action based on the selection, as described in this table.
Item Action
Local function Navigates to the local function within the current file, if that file is a
MATLAB code file. If no function by that name exists in the current file,
the Editor or Live Editor runs the open function on the selection,
which opens the selection in the appropriate tool.
Text file Opens in the Editor.
Figure file (.fig) Opens in a figure window.
24-30
Find and Replace Text in Files and Go to Location
Item Action
MATLAB variable that is in Opens in the Variables editor.
the current workspace
Model Opens in Simulink.
Other If the selection is some other type, Open selection looks for a
matching file in a private folder in the current folder and performs the
appropriate action.
See Also
lookfor
Related Examples
• “Find Files”
24-31
24 Coding and Productivity Tips
The Code Analyzer Report displays potential errors and problems, as well as opportunities for
improvement in your code through messages. Interactively browse the report using the Code
Analyzer app, which can be opened in the following ways.
•
MATLAB Toolstrip: On the Apps tab, under MATLAB, click the app icon: .
• MATLAB command prompt: Enter codeAnalyzer.
A list of all checks performed by the MATLAB Code Analyzer can be found here, “Index of Code
Analyzer Checks”.
codeAnalyzer("C:\MyCode")
This command launches the Code Analyzer app and generates a report of the issues found within
the specified code. The summary section at the top of the report provides an overview of the
information contained in the report. This section shows how many files were analyzed and the
total number of errors, warnings, and informational messages found in the analyzed code.
24-32
MATLAB Code Analyzer Report
2 Issues are grouped by severity by default. You can change how issues are grouped by using the
Group By list. Group the report by file.
24-33
24 Coding and Productivity Tips
3 You can filter the displayed messages by using the Filter by Severity and Filter by Issue Type
lists. Filter the report to show only errors.
4 Some issues can be solved with automated replacement. These issues have a Fix All button. If
you expand the issue by clicking on it, individual instances of the issues can be fixed clicking the
corresponding Fix button. Hover the cursor over the Fix or Fix All buttons to see what fix
MATLAB will implement.
24-34
MATLAB Code Analyzer Report
• Open the file in the Editor and click the Details button in the tooltip, as shown in the image
following this list. An extended message opens. However, not all messages have extended
messages.
• Search the MathWorks documentation about terms presented in the messages.
The following image shows a tooltip with a Details button. The orange line under the equals (=) sign
indicates a tooltip displays if you hover over the equals sign. The orange highlighting indicates that
an automatic fix is available.
Issues that have an automatic fix available can be fixed programmatically using the fix function on a
codeIssues object. These issues can also be fixed interactively using the Code Analyzer app.
24-35
24 Coding and Productivity Tips
• For an index of all Code Analyzer messages, see “Index of Code Analyzer Checks”.
• Access the Code Analyzer Report for a file using the Code Analyzer app.
• Run the codeIssues function, which analyzes the specified file and displays messages in the
Command Window.
• Use automatic code checking while you work on a file in the Editor. For more information, see
“Check Code for Errors and Warnings Using the Code Analyzer” on page 24-5.
See Also
Code Analyzer | codeIssues | checkcode
Related Examples
• “Check Code for Errors and Warnings Using the Code Analyzer” on page 24-5
• “Code Analyzer Preferences”
• “Configure Code Analyzer”
• “Index of Code Analyzer Checks”
24-36
MATLAB Code Compatibility Analyzer
The Code Compatibility Analyzer is a convenient tool that analyzes your code, lists the entire set of
compatibility issues in tabular format, and provides you with instructions on how to address these
compatibility issues. The report enables you to:
• Identify the compatibility issues that you must address for your code to run properly in the current
MATLAB release.
• Estimate the effort required to update your code when you upgrade to a newer MATLAB release.
• Improve your code by replacing functionality that is not recommended.
The Code Compatibility Analyzer displays the locations in your code that are affected by compatibility
issues and provides links to the documentation for more information on how to make the necessary
changes at each location.
A list of all checks performed by the MATLAB Code Analyzer, including compatibility issues, can be
found here, “Index of Code Analyzer Checks”.
1 In the Current Folder browser, navigate to and open the folder that contains the code files you
want to analyze.
2 Run codeCompatibilityReport at the command prompt to generate the report or select Code
24-37
24 Coding and Productivity Tips
3 Update your code to resolve the syntax errors for each file listed in the Syntax Errors section.
Syntax errors result in code that does not run. While most likely the code did not run properly in
previous releases, syntax errors impact compatibility analysis. For example, A '(' might be
missing a closing ')', causing invalid syntax at end of line (1)..
4 For each functionality listed in the report, click the expander to the left of the row review the
issue description and your code. Messages include the line numbers to help locate the issue in
your code. To open the file in the Editor at that line, click the line number. Then change the file
based on the message. If you are unsure what a message means or what to change in the code,
click the Help link associated with the message.
Each functionality listed in the report displays a recommended action. You also can use the
following general advice:
24-38
MATLAB Code Compatibility Analyzer
• Functionality that has been removed — Update your code to avoid compatibility errors in
the current release.
• Functionality that has changed behavior — Confirm that the change in behavior is
acceptable, and if not, update your code for the current release.
• Unsupported functionality that might cause errors — Files listed here use functionality
that is unsupported, undocumented, and not intended for customer use. Update your code to
use documented functionality to avoid errors and unexpected behavior changes.
• Functionality that will be removed — Update your code now or in a later release. Updating
your code now makes future upgrades easier.
• Functionality that will change behavior — Investigate these changes now to make future
upgrades easier.
• New functionality that might improve code — Consider updating your code. Current code
is expected to continue working in future releases but newer functionality is recommended.
The Code Compatibility Analyzer also includes information about the checks performed on your
code and the list of files that MATLAB analyzed for code compatibility.
Programmatic Use
To generate a report programmatically, use one of the following methods.
• To generate a report that opens in the MATLAB® Web Browser programmatically, use
codeCompatibilityAnalyzer and specify the folder you wish to analyze.
• To generate a report for the current folder and its subfolders, use the
codeCompatibilityReport function.
• To return a CodeCompatibilityAnalysis object that contains the report information, use the
analyzeCodeCompatibility function. You can then display a report for the stored object using
the codeCompatibilityReport function.
Unsupported Functionality
The Code Compatibility Analyzer checks for functionality that is unsupported, undocumented, and not
intended for use. Such features are subject to change or removal without notice and can cause future
errors. In some cases there is documented replacement functionality, but there might be no simple
replacement. Contact MathWorks Support to describe your usage and request supported
replacement.
See Also
Code Analyzer | analyzeCodeCompatibility | codeCompatibilityReport |
CodeCompatibilityAnalysis
24-39
24 Coding and Productivity Tips
The code generation readiness tool screens MATLAB code for features and functions that code
generation does not support. The tool provides a report that lists the source files that contain
unsupported features and functions. It is possible that the tool does not detect all code generation
issues. Under certain circumstances, it is possible that the tool can report false errors. Therefore,
before you generate code, verify that your code is suitable for code generation by generating a MEX
function.
The code generation readiness tool does not report functions that the code generator automatically
treats as extrinsic. Examples of such functions are plot, disp, and figure.
Issues Tab
• MATLAB syntax issues. These issues are reported in the MATLAB editor. To learn more about the
issues and how to fix them, use the Code Analyzer.
• Unsupported MATLAB function calls, language features, and data types.
24-40
Code Generation Readiness Tool
• View your MATLAB code inside the Code Generation Readiness Tool. When you select an issue,
the part of your MATLAB code that caused this issue gets highlighted.
• Group the readiness results either by issue or by file.
• Select the language that the code generation readiness analysis uses.
• Refresh the code generation readiness analysis if you updated your MATLAB code.
• Export the analysis report either as plain text file or as a coder.ScreenerInfo object in the
base workspace.
Files Tab
If the code that you are checking calls functions in other MATLAB code files, the Files tab shows the
call dependency between these files. If you select Show MathWorks Functions, the report also lists
the MathWorks functions that your function calls.
See Also
coder.screener | coder.ScreenerInfo Properties
Related Examples
• “MATLAB Language Features Supported for C/C++ Code Generation” (MATLAB Coder)
24-41
24 Coding and Productivity Tips
• “Functions and Objects Supported for C/C++ Code Generation” (MATLAB Coder)
24-42
25
Programming Utilities
1 Type clear functions to clear all functions from memory (see Note below).
Note clear functions does not clear functions locked by mlock. If you have locked functions
(which you can check using inmem) unlock them with munlock, and then repeat step 1.
2 Execute the function you want to check. Note that the function arguments you choose to use in
this step are important, because you can get different results when calling the same function
with different arguments.
3 Type inmem to display all program files that were used when the function ran. If you want to see
what MEX-files were used as well, specify an additional output:
[fList,pList] = matlab.codetools.requiredFilesAndProducts('myFun.m');
fList
fList =
'C:\work\myFun.m'
The only required program file, is the function file itself, myFun.
{pList.Name}'
ans =
'MATLAB'
'Image Processing Toolbox'
The file, myFun.m, requires both MATLAB and the Image Processing Toolbox.
You can use the Dependency Analyzer to analyze the dependencies between all files within a folder.
The Dependency Analyzer can identify these dependencies:
25-2
Identify Program Dependencies
• Which files in the folder are required by other files in the folder
• If any files in the current folder will fail if you delete a file
• If any called files are missing from the current folder
To analyze the dependencies within a folder, open the Dependency Analyzer by going to the Apps tab,
and under MATLAB, clicking the Dependency Analyzer icon . Then, click the Open Folder
button and select the folder that you want to analyze. The Dependency Analyzer shows the results in
the form of a dependency graph.
For more information about how to investigate the dependencies within the folder, see “Dependency
Analysis for Folders and Files”.
Note To determine which MATLAB code files someone else needs to run a particular file use the
matlab.codetools.requiredFilesAndProducts function instead.
See Also
Functions
matlab.codetools.requiredFilesAndProducts
Apps
Dependency Analyzer
Related Examples
• “Create and Share Toolboxes” on page 25-12
• “Analyze Project Dependencies” on page 33-42
25-3
25 Programming Utilities
• “Create P-Code Files” on page 25-4 — Convert plain text MATLAB files to a content-obscured
execute-only format.
• “Build Standalone Executables” on page 25-4 — Use MATLAB Compiler/Simulink Compiler to
generate standalone applications from MATLAB programs or Simulink models.
• “Use Model Protection” on page 25-5 — Use Model Protection to conceal the contents of
Simulink models.
• “Convert Code to Native Code” on page 25-5 — Compile source code and algorithms into
platform-specific binary files.
• “Host Compiled Application on Remote Protected Server” on page 25-5 — Host the compiled
application on a remote protected server using “MATLAB Web App Server” or “MATLAB
Production Server” with restricted access.
• “Utilize Secure OS Services” on page 25-6 — Host the compiled application on a protected
server on a shielded virtual machine.
For more information on generating P-code files, see “Create a Content-Obscured File with P-Code”
on page 25-7.
When MATLAB Compiler or Simulink Compiler creates an standalone executable, all the files
required for that application are bundled into an archive. In the archive, each MATLAB code file
(plain text MATLAB file or P-code file) is encrypted using the standard AES-256 algorithm. By default,
the names of files and the directory structure are not obscured and other file types (such as MAT, FIG,
MEX, and so on) are not encrypted.
Starting in R2021b, you can obscure the names of files and the directory structure, and also encrypt
other file types (such as MAT, FIG, MEX, and so on) using the -s option for mcc (MATLAB Compiler).
At run time, the encrypted files remain encrypted on the disk but are decrypted in memory to their
original form before compiling. Depending on the use case, you can combine other methods with this
one to gain an additional layer of protection. For example, you can create a P-coded file from MATLAB
code files before they are compiled.
25-4
Security Considerations to Protect Your Source Code
To build a standalone executable for your MATLAB application, develop and debug your application
following the usual workflow for MATLAB program files. For information on how to generate
executable files, see “Create Standalone Application from MATLAB Function” (MATLAB Compiler).
If a user creates a protected model for simulation only, most of the IP is hidden inside derived binary
files. If the user creates a protected model for code generation support as well, the SLXP includes
certain supporting files for code generation in either readable C/C++ code or obfuscated binary
format, depending on how the user created the SLXP.
Simulation and code generation functionalities can be optionally password-protected so that only the
recipients with the password can use these functionalities. When using password protection, the main
supporting files for that functionality are protected using AES-256 encryption. These files are
decrypted on the disk when the end user enters the password.
Not all supporting files in a package are encrypted. These files include very little of the IP but can
still reveal certain information about the model such as interfaces and sample times.
For more information, see “Protect Models to Conceal Contents” (Simulink Coder).
To achieve an additional layer of protection, you can apply binary obfuscation (using tools outside of
MathWorks) on the generated binary.
25-5
25 Programming Utilities
See Also
pcode
Related Examples
• “Create a Content-Obscured File with P-Code” on page 25-7
25-6
Create a Content-Obscured File with P-Code
Note Security Considerations: The pcode function produces MATLAB program files in a
proprietary, obfuscated code format. Consider combining multiple approaches to protect sensitive
code or data. For more information, see “Security Considerations to Protect Your Source Code” on
page 25-4.
The command produces the files file1.p, file2.p, and so on. To convert all .m source files
residing in your current folder to P-code files, use the command:
pcode *.m
See the pcode function reference page for a description of all syntaxes for generating P-code files.
Note Code with obfuscated names may behave differently from source code.
matlab.lang.obfuscateNames only obfuscates direct occurrences of names in code, such as x in x
= 1, if x < 5, and f(x+y). Occurrences in strings, character vectors, and command-syntax
arguments are not obfuscated, such as eval("f(x+y)") or clear x.
For example, you have the source-code for the function myfunc:
outputArg = sumVar/prodVar;
end
Use matlab.lang.obfuscateNames to write myfunc to a new file with local names obfuscated.
matlab.lang.obfuscateNames("SourceCode\myfunc.m","ObfuscatedCode\myfunc.m")
The new file has the names of local identifiers changed to generic names:
25-7
25 Programming Utilities
id40037619 = inputArg1*inputArg2;
outputArg = id242487092/id40037619;
end
Note that the names of the input and output arguments are not changed. The names ans, varargin,
varargout, and names that are used as literal arguments for the load function are never
obfuscated.
Thoroughly test obfuscated code to ensure it is functioning as intended. Consider making use of
MATLAB “Testing Frameworks” to write automated tests to verify the behavior of obfuscated code. If
the code does not behave as desired, use PreserveNames and other name-value arguments to
control the obfuscation process.
[out1,out2] = myfun(in1,in2);
myscript;
When you call a P-code file, MATLAB gives it execution precedence over its corresponding .m source
file. This is true even if you change the source code at generating the P-code file. Remember to
remove the .m source file before distributing your code.
P-code files built using MATLAB Version 7.4 (R2007a) and earlier have a different format than those
built with more recent versions of MATLAB. These older P-code files do not run in MATLAB V8.6
(R2015b) or later. Rebuild any P-code files that were built with MATLAB V7.4 or earlier using a more
recent version of MATLAB, and then redistribute them as necessary.
See Also
pcode
Related Examples
• “Security Considerations to Protect Your Source Code” on page 25-4
25-8
Create Hyperlinks that Run Functions
Use matlab: syntax to create a hyperlink in the Command Window that runs one or more functions.
For example, you can use disp to display the word Hypotenuse as an executable hyperlink as follows:
Clicking the hyperlink executes the three commands following matlab:, resulting in
c =
5
Executing the link creates or redefines the variables a, b, and c in the base workspace.
The argument to disp is an <a href> HTML hyperlink. Include the full hypertext text, from '<a
href= to </a>' within a single line, that is, do not continue long text on a new line. No spaces are
allowed after the opening < and before the closing >. A single space is required between a and href.
You cannot directly execute matlab: syntax. That is, if you type
matlab:a=3; b=4;c=hypot(a,b)
you receive an error, because MATLAB interprets the colon as an array operator in an illegal context:
You do not need to use matlab: to display a live hyperlink to the Web. For example, if you want to
link to an external Web page, you can use disp, as follows:
disp('<a href="http://en.wikipedia.org/wiki/Hypotenuse">Hypotenuse</a>')
The result in the Command Window looks the same as the previous example, but instead opens a
page at en.wikipedia.org:
Hypotenuse
25-9
25 Programming Utilities
x = 0:1:8;
y = sin(x);
plot(x,y)
x = -2*pi:pi/16:2*pi;
Click the hyperlink, Plot x,y again and it changes the current value of x back to 0:1:8. The code
that matlab: runs when you click the Plot x,y defines x in the base workspace.
The Command Window displays the links that follow. Depending on which link you click, MATLAB sets
state to 0 or 1.
25-10
Create Hyperlinks that Run Functions
Some symbols might not be interpreted correctly and you might need to use the ASCII value for the
symbol. For example, an alternative way to run the previous statement is to use ASCII 62 instead of
the greater than symbol:
disp('<a href="matlab:str=[''Value '' char(62) '' 0'']">Positive</a>')
25-11
25 Programming Utilities
You can package MATLAB files to create a toolbox to share with others. These files can include
MATLAB code, data, apps, examples, and documentation. When you create a toolbox, MATLAB
generates a single installation file (.mltbx) that enables you or others to install your toolbox.
Create Toolbox
1
In the Environment section of the Home tab, select Package Toolbox from the Add-Ons
menu.
2
In the Package a Toolbox dialog box, click the button and select your toolbox folder. It is good
practice to create the toolbox package from the folder level above your toolbox folder.
The .mltbx toolbox file contains information about the path settings for your toolbox files and
folders. By default, any of the included folders and files that are on your path when you create
the toolbox appear on their paths after the end users install the toolbox.
3 In the dialog box, add the following information about your toolbox.
If your toolbox folder contains a package definition file, MATLAB uses the package information
such as the description, summary, and toolbox name to automatically prepopulate some of the
toolbox information fields. You can then further edit these fields. For more information about
packages, see “Create and Manage Packages” on page 34-8.
Toolbox Description
Information
Field
Toolbox Enter the toolbox name, if necessary. By default, the toolbox name is the
Name name of the toolbox folder. The Toolbox Name becomes the .mltbx file
name.
Version Enter the toolbox version number in the Major.Minor.Bug.Build format.
Bug and Build are optional.
Author Enter contact information for the toolbox author. To save the contact
Name, Email, information, click Set as default contact.
and Company
Toolbox To select an image that represents your toolbox, click Select toolbox
Image image.
Summary and Enter the toolbox summary and description. It is good practice to keep the
Description Summary text brief and to add detail to the Description text.
4 To ensure MATLAB detects the expected components, review the toolbox contents. The following
sections of the Package a Toolbox dialog box appear after you select a toolbox folder.
25-12
Create and Share Toolboxes
Package a Description
Toolbox
Dialog Box
Section
Toolbox List of the folders and files contained in your toolbox. The listed files and
Files and folders are only those files that are located in the top level of the toolbox
Folders folder. You cannot navigate through the folders in the Toolbox Packaging
dialog box.
By default, if your toolbox contains a P-code file and a MATLAB code file (.m)
with the same name in the same folder, MATLAB excludes the .m file from the
toolbox. To include both the .p and .m files, clear the Exclude MATLAB
script or function files with matching P-files option.
To exclude other files or folders from the toolbox, register them in the text file
that is displayed when you click Exclude files and folders. It is good
practice to exclude any source control files related to your toolbox.
Requiremen Add-ons — List of add-ons required for your toolbox. Selected add-ons are
ts downloaded and installed when the toolbox is installed. MATLAB auto-
populates this list with the add-ons it thinks the toolbox requires and selects
them all by default. You can choose to omit any add-ons you do not want to
install with your toolbox.
25-13
25 Programming Utilities
Package a Description
Toolbox
Dialog Box
Section
Installation of Additional Software — List of additional software ZIP files that
are installed on the user's system when they install a toolbox.
• Display Name — The name to display to the user when they install a
toolbox.
• License URL — The URL of the additional software license agreement to
display to the user when they install a toolbox. The user is prompted to
review and agree to the license agreement during installation. You must
specify a valid URL to the license agreement.
• Download URL — The URL to the ZIP file that contains the additional
software. To specify different download URLs for different platforms,
select a platform name from the drop-down menu to the left of the
download URL. Then, click Add Platform to add a download URL for
additional platforms.
When the user installs a toolbox, MATLAB installs all additional software in
the addons\Toolboxes\AdditionalSoftware folder, where addons is the
add-ons default installation folder. For more information about the location of
the add-ons default installation folder, see “Get and Manage Add-Ons”.
If your toolbox contains code that refers to the installation folder of the
specified additional software, make these references portable to other
computers. Replace the references with calls to the generated function
toolboxname\getInstallationLocation.mlx, where toolboxname is
the name of your toolbox. For example, if you are creating a toolbox called
mytoolbox and want to reference the install location for additional software
called mysoftware, replace this code
mysoftwarelocation = 'C:\InstalledSoftware\mysoftware\'
mysoftwarelocation = mytoolbox.getInstallationLocation('mysoftware')
25-14
Create and Share Toolboxes
Package a Description
Toolbox
Dialog Box
Section
Platform Compatibility — List of platforms that support the toolbox. Consider
if your toolbox has third-party software or hardware requirements that are
platform specific. MATLAB Online cannot interact with hardware, including
devices used for image acquisition and instrument control.
Release Compatibility — List of MATLAB releases that support the toolbox.
Products — List of MathWorks products required by your toolbox. Create this
list manually.
Examples, Examples — Published MATLAB examples associated with your toolbox. To
Apps, and include .m and .mlx files as examples, click the Add examples button, select
Documentat your code file, and click Publish HTML. MATLAB publishes the code to
ion HTML and places the output files in the html folder.
Alternatively, you can manually publish code files to HTML in MATLAB and
then include the code files and the HTML files in your toolbox folder.
• For a live script (.mlx) example, export it to HTML. On the Live Editor
tab, select Save > Export to HTML and save it in a folder named html.
• For a script (.m) example, publish it to HTML with the publish function.
Do not specify an output folder when publishing your examples. For the
Package a Toolbox tool to recognize the examples, the output folder must
be the default folder (html).
• To specify which apps (.mlapp files) are also installed and registered in
the user's MATLAB Apps Gallery, select the apps.
• All .mlappinstall files in your toolbox folder are installed and
registered in the user's MATLAB Apps Gallery.
25-15
25 Programming Utilities
Package a Description
Toolbox
Dialog Box
Section
Getting Started Guide — Quick start guide for your toolbox. For the Package a
Toolbox tool to recognize a Getting Started Guide, include the guide as a live
script named GettingStarted.mlx in a doc subfolder within your toolbox
folder.
Users of your toolbox can view the Getting Started Guide through the Options
menu for the toolbox in the Add-On Manager. For more information, see “Get
and Manage Add-Ons”.
Help Browser Integration — Custom documentation for your toolbox to
display within the MathWorks documentation. For the Package a Toolbox tool
to recognize custom documentation, include an info.xml file to identify your
documentation files. If you use the builddocsearchdb function to build the
documentation database before packaging your toolbox, you can include the
generated helpsearch subfolder in your toolbox. The info.xml file and the
helpsearch folder allow recipients to access your documentation through
the Supplemental Software link on the left side of the MathWorks
documentation home page. For more information, see “Display Custom
Documentation” on page 32-20.
• To save your toolbox, click Package at the top of the Package a Toolbox dialog box. Packaging
your toolbox generates a .mltbx file in your current MATLAB folder.
• To save your toolbox and share it on MATLAB Central File Exchange, select Package and
Share from the Package menu at the top of the Package a Toolbox dialog box. This option
generates a .mltbx file in your current MATLAB folder and opens a web page for your
toolbox submission to File Exchange. MATLAB populates the File Exchange submission form
with information about the toolbox. Review and submit the form to share your toolbox on File
Exchange.
When you create a toolbox, MATLAB generates a .prj file that contains information about the
toolbox and saves it frequently. It is good practice to save this associated .prj file so that you
can quickly create future revisions of your toolbox.
Share Toolbox
To share your toolbox with others, give them the .mltbx file. All files you added when you packaged
the toolbox are included in the .mltbx file. When the end users install your toolbox, they do not need
to be concerned with the MATLAB path or other installation details. The .mltbx file manages these
details for end users.
25-16
Create and Share Toolboxes
For information on installing, uninstalling, and viewing information about toolboxes, see “Get and
Manage Add-Ons”.
You can share your toolbox with others by attaching the .mltbx file to an email message, or using
any other method you typically use to share files, such as uploading to MATLAB Central File
Exchange. If you upload your toolbox to File Exchange, your users can download the toolbox from
within MATLAB. For more information, see “Get and Manage Add-Ons”.
Alternatively, you can upload your toolbox to File Exchange when you package it. Select Package
and Share from the Package menu at the top of the Package a Toolbox dialog box.
Note While .mltbx files can contain any files you specify, MATLAB Central File Exchange places
additional limitations on submissions. If your toolbox contains any of the following, it cannot be
submitted to File Exchange:
• MEX-files.
• Other binary executable files, such as DLLs or ActiveX® controls. (Data and image files are
typically acceptable.)
See Also
publish | matlab.addons.toolbox.packageToolbox |
matlab.addons.toolbox.toolboxVersion | matlab.addons.toolbox.installToolbox |
matlab.addons.toolbox.uninstallToolbox |
matlab.addons.toolbox.installedToolboxes
Related Examples
• “Get and Manage Add-Ons”
• “Display Custom Examples” on page 32-27
• “Package Apps from the MATLAB Toolstrip”
• “Display Custom Documentation” on page 32-20
25-17
25 Programming Utilities
• parfor
• parfeval and parfevalOnAll
• DataQueue and PollableDataQueue
• afterEach and afterAll
• Constant
You do not need Parallel Computing Toolbox to run code using this functionality.
• parfor
• parfeval and parfevalOnAll
To run functions in the background, use parallel language syntaxes with backgroundPool instead.
Code that you write using backgroundPool can automatically scale to use more parallel resources if
you have Parallel Computing Toolbox. For more information, see backgroundPool.
Serial parfor
The following syntaxes run in parallel when you have Parallel Computing Toolbox, and otherwise run
in serial:
When a parfor-loop runs in serial, the iterations run in reverse order. For more information, see
parfor and parfor.
The following syntaxes run in parallel when you use Parallel Computing Toolbox, and otherwise run in
serial:
• parfeval(fcn,n,X1,...Xm)
• parfevalOnAll(fcn,n,X1,...Xm)
When a Future object runs in serial, MATLAB runs the function fcn associated with it using
deferred execution. The function runs when MATLAB becomes idle, blocking MATLAB until the
function finishes running. Examples of functionality that causes MATLAB to be temporarily idle
include:
25-18
Run Parallel Language in MATLAB
• Using pause
• Using fetchOutputs or fetchNext to get results from a Future object
• Using wait to wait for a Future object to finish
• Using afterEach or afterAll to run a function after a Future object finishes
When you create a DataQueue or PollableDataQueue object, the object is not directly associated
with the background pool or a parallel pool. You can therefore use a DataQueue or
PollableDataQueue object without any pool.
The following code updates a plot on each iteration of a parfor-loop. If you have Parallel Computing
Toolbox, the parfor-loop runs using a parallel pool. If you do not have Parallel Computing Toolbox,
the code runs in serial.
x = 1:1000
line = plot(x,NaN(size(x)));
q = parallel.pool.DataQueue;
afterEach(q,@(data)updatePlot(line,data));
parfor i = 1:numel(x)
% Simulate some work
pause(rand)
y(i) = x(i)^2;
send(q,[i y(i)])
end
function updatePlot(line,data)
line.XData(data(1)) = data(1);
line.YData(data(1)) = data(2);
drawnow
end
Constant
When you create a Constant object, the object is not directly associated with the background pool or
a parallel pool. You can therefore use a Constant object without any pool.
The following code creates a Constant object in your current MATLAB session. You can write to a
temporary file using c.Value and fprintf.
If you have Parallel Computing Toolbox, the parfor-loop runs using a parallel pool. If you use a
parallel pool, the Constant is available on each worker in the parallel pool. Otherwise, the
Constant object is created only in your current MATLAB session.
c = parallel.pool.Constant(@() fopen(tempfile(pwd),'wt'),@fclose);
parfor i = 1:10
y(i) = i^2;
fprintf(c.Value,"%03d %f\n",i,y(i));
end
25-19
25 Programming Utilities
You can use the following syntaxes without Parallel Computing Toolbox:
• parallel.pool.Constant(X)
• parallel.pool.Constant(fcn)
• parallel.pool.Constant(fcn,cleanupFcn)
25-20
Measure Code Complexity Using Cyclomatic Complexity
The cyclomatic complexity value is the number of linearly independent paths and, therefore, the
minimum number of paths that should be tested. The algorithm calculates an integer from 1 to
infinity for any function, based on the number of possible paths through the function. Files with a
complexity above 10 are candidates for simplification, and those above 50 are considered untestable.
The cyclomatic complexity value for any given piece of code starts at 1. Each statement that creates a
decision point (if, &&, for, and so on) increases the value by 1. For example:
function cyclomaticTest(a)
switch a
case 1
disp("one")
case 2
disp("two")
case 3
disp("many")
otherwise
disp("lots")
end
end
You can measure the cyclomatic complexity of the function using checkcode with the "-cyc"option.
checkcode("cyclomaticTest.m","-cyc")
This function has a cyclomatic complexity value of 4. The base value is 1, and 1 is added for each
case statement. The switch and otherwise statements do not increase the value. The cyclomatic
complexity reported by Code Analyzer for the MATLAB language is equivalent to the McCabe
cyclomatic complexity [1].
checkcode("cyclomaticTest.m","-modcyc")
This table lists the cyclomatic complexity values of various operations in MATLAB.
25-21
25 Programming Utilities
References
[1] Arthur H. Watson and Thomas J. McCabe, "Structured Testing: A Testing Methodology Using the
Cyclomatic Complexity Metric." (National Institute of Standards and Technology,
Gaithersburg, MD), NIST Special Publication (SP) 500-235 (September 1996). https://
www.mccabe.com/pdf/mccabe-nist235r.pdf.
See Also
checkcode | profile
25-22
26
Function argument validation is declarative, which enables MATLAB desktop tools to extract
information about a function by inspection of specific code blocks. By declaring requirements for
arguments, you can eliminate cumbersome argument-checking code and improve the readability,
robustness, and maintainability of your code.
The function argument validation syntax simplifies the process of defining optional, repeating, and
name-value arguments. The syntax also enables you to define default values in a consistent way.
The use of function argument validation is optional in function definitions. Argument validation is
most useful in functions that can be called by any code and where validity of the arguments must be
determined before executing the function code. Functions that are designed for use by others can
benefit from the appropriate level of restriction on arguments and the opportunity to return specific
error messages based on the argument validation checks.
In local and private functions, and in private or protected methods, the caller is aware of input
requirements, so these types of functions can be called with valid arguments.
You cannot use argument validation syntax in nested functions, abstract methods, or handle class
destructor methods. For more information on argument validation in methods, see “Method Syntax”.
Functions define argument validation in optional code blocks that are delimited by the keywords
arguments and end. If used, an arguments block must start before the first executable line of the
function.
You can use multiple arguments blocks in a function, but all blocks must occur before any code that
is not part of an arguments block.
The highlighted area in the following code shows the syntax for input argument validation.
26-2
Function Argument Validation
The function argument declaration can include any of these kinds of restrictions:
You can also define a default value for the input argument in the function validation declaration for
that argument. The default value must satisfy the declared restrictions for that argument.
Validation size is the dimensions of the argument, specified with nonnegative integer numbers or
colons (:). A colon indicates that any length is allowed in that dimension. You cannot use expressions
for dimensions. The value assigned to the argument in the function call must be compatible with the
specified size, or MATLAB throws an error.
MATLAB indexed assignment rules apply to size specifications. For example, a 1-by-1 value is
compatible with the size specified as (5,3) because MATLAB applies scalar expansion. Also,
MATLAB row-column conversion applies so that a size specified as (1,:) can accept a size of 1-by-n
and n-by-1.
If you do not specify a size, then any size is allowed unless restricted by validation functions.
Class
Validation class is the name of a single class. The value assigned to the function input must be of the
specified class or convertible to the specified class. Use any MATLAB class or externally defined class
that is supported by MATLAB, except Java, COM classes, and MATLAB class definitions that do not
use the classdef keyword (classes defined before MATLAB software Version 7.6).
26-3
26 Function Argument Validation
• char — Input must be of class char or a value that MATLAB can convert to a char, such as
string.
• double — Input can be a numeric value of any precision.
• cell — Input must be a cell array.
• A user-defined class
If you do not specify a class, then any class is allowed unless restricted by validation functions.
This arguments block specifies the size and class of the three inputs.
% Function code
...
end
• A is a string scalar.
• B is a 1-by-any length vector of doubles.
• C is a 2-by-2 cell array.
Validation Functions
A validation function is a MATLAB function that throws an error if certain requirements are not
satisfied by the argument value. Validation functions do not return values and, unlike class and size,
cannot change the value of the arguments they are validating.
During the validation process, MATLAB passes the argument value to each validation function listed
for that argument. The value passed to the validation functions is the result of any conversion made
by the class and size specifications. MATLAB calls each function from left to right and throws the first
error encountered.
For a table of predefined validation functions, see “Argument Validation Functions” on page 26-27.
Validation functions can restrict arguments in more specific ways. You can use predefined validation
functions for many common kinds of validation, and you can define your own validation function to
satisfy specific requirements.
For example, this function specifies the following validations using mustBeNumeric, mustBeReal,
mustBeMember, and the local function mustBeEqualSize.
26-4
Function Argument Validation
• Input method must be a character vector that is one of the three allowed choices. Because
method specifies a default value, this argument is optional.
function myInterp(x,v,method)
arguments
x (1,:) {mustBeNumeric,mustBeReal}
v (1,:) {mustBeNumeric,mustBeReal,mustBeEqualSize(v,x)}
method (1,:) char {mustBeMember(method,{'linear','cubic','spline'})} = 'linear'
end
% Function code
....
end
Avoid using function argument validation within custom validation functions. For more information
about defining validation functions and a list of predefined validation functions, see “Argument
Validation Functions” on page 26-27.
Default Value
An input argument default value can be any constant or expression that satisfies the size, class, and
validation function requirements. Specifying a default value in an argument declaration makes the
argument optional. MATLAB uses the default value when the argument is not included in the function
call. Default value expressions are evaluated each time the default is used.
Note Because MATLAB validates the default value only when the function is called without a value
for the argument, an invalid default value causes an error only when the function is called without
that argument.
Optional arguments must be positioned after required arguments in the function signature and in the
arguments block. For more information on optional arguments, see “Validate Required and Optional
Positional Arguments” on page 26-11.
26-5
26 Function Argument Validation
As a result, the validated value in the function body can be different from the value passed when
calling the function. For more information on class conversion, see “Implicit Class Conversion”. To
avoid class and size conversions during validation, use argument validation functions instead. For
more information, see “Use Validation Functions to Avoid Unwanted Class and Size Conversions” on
page 26-22.
The following function illustrates how inputs can be converted to match the classes specified in the
arguments block. The SpeedEnum class is an enumeration class created to define the values allowed
for the third argument.
function forwardSpeed(a,b,c)
arguments
a double
b char
c SpeedEnum
end
% Function code
disp(class(a))
disp(class(b))
disp(class(c))
end
This call to the function uses input values that MATLAB can convert to the declared types. The actual
argument types within the function are displayed as output.
forwardSpeed(int8(4),"A string",'full')
double
char
SpeedEnum
Separate arguments blocks must be used for validating input and output arguments. Define the type
of arguments block (Input) or (Output) after the arguments statement. If both (Input) and
26-6
Function Argument Validation
(Output) argument blocks are used, the (Output) block must follow the (Input) block. then If no
type is specified, then MATLAB assumes the block contains input arguments.
For example, this function validates the size and class of three input arguments and one output
argument using separate arguments blocks. Note that the (Input) block must precede the
(Output) block.
function out = myFunction(A, B, C)
arguments (Input)
A (1,1) string
B (1,:) double
C (2,2) cell
end
arguments (Output)
out (1,:) double
end
% Function code
...
end
Kinds of Arguments
Function argument validation can declare four kinds of arguments. Functions can define any of these
kinds of arguments, but the arguments must be defined in the following order:
Validated values can be different from the original values passed as inputs when the function is
called. For example, this function declares the inputs as class uint32 values. The third input
declaration assigns a default value equal to the product of the first two inputs.
function c = f(a, b,c)
arguments
26-7
26 Function Argument Validation
a uint32
b uint32
c uint32 = a.* b
end
% Function code
...
end
Calling the function with inputs that are a different numeric class (for example, double) results in a
conversion to uint32.
c = f(1.8,1.5)
Because the optional argument c is not specified in the function call, MATLAB evaluates the default
value and assigns it to c after converting a and b to uint32 values. In this case, the conversion
results in a value of 2 for both inputs. Therefore, the product of a times b is four.
c =
uint32
If you specify a value for the third input, then the function assigns a value to c and does not evaluate
the default value expression.
c = f(1.8,1.5,25)
c =
uint32
25
arguments blocks exist in the function's workspace. Any packages, classes, or functions added to the
scope of the function using the import command are added to the scope of the arguments block.
The only variables visible to validator functions and default value expressions are the input variables
already declared. In this function, the default value of c is derived from a and b.
function c = f(a,b,c)
arguments
a uint32
b uint32
c uint32 = a * b
end
% Function code
...
end
26-8
Function Argument Validation
However, you cannot refer to input variables not yet declared in an arguments block. For example,
using this declaration for argument a in the previous function is not valid because b and c have not
been declared yet.
arguments
a uint32 = b * c
b uint32
c uint32
end
Argument validation expressions can reference only previously declared, and therefore validated,
arguments. Validation functions and default values for name-value arguments cannot access other
name-value arguments.
Any references to previously declared arguments must be visible in the text of validation functions
and default values. To ensure code transparency, do not use functions that interact with the function
workspace. Specifically, do not use nested functions or any of the functions listed in the following
table in the arguments block.
These restrictions apply only within the arguments block and do not apply to variables or functions
in the body of the function.
See Also
namedargs2cell | arguments
Related Examples
• “Argument Definitions”
• “Validate Required and Optional Positional Arguments” on page 26-11
• “Validate Repeating Arguments” on page 26-13
• “Validate Name-Value Arguments” on page 26-16
• “Argument Validation Functions” on page 26-27
26-9
26 Function Argument Validation
26-10
Validate Required and Optional Positional Arguments
Positional arguments in the arguments block are required when calling the function, unless the
argument defines a default value. Specifying a default value in the argument declaration makes a
positional argument optional because MATLAB can use the default value when no value is passed in
the function call.
MATLAB evaluates the default value expression only when the argument is not included in the
function call.
All optional arguments must be positioned after all required arguments in the arguments block. For
example, in this argument block, maxval and minval have default values and are therefore optional.
function myFunction(x,y,maxval,minval)
arguments
x (1,:) double
y (1,:) double
maxval (1,1) double = max(max(x),max(y))
minval (1,1) double = min(min(x),min(y))
end
% Function code
....
end
myFunction(x,y,maxval,minval)
myFunction(x,y,maxval)
myFunction(x,y)
An optional positional argument becomes required when its position must be filled in the function call
to identify arguments that come after it. That is, if you want to specify a value for minval, you must
specify a value for maxval.
Ignored arguments cannot have default values or specify class, size, or validation functions.
26-11
26 Function Argument Validation
The tilde character (~) is treated as an optional argument unless it is followed by a required
positional argument. For example, in this function the tilde character (~) represents an optional
argument.
function c = f(~)
arguments
~
end
% Function code
end
c = f
c = f(2)
In the following function, the tilde character (~) represents a required argument.
function c = f(~,x)
arguments
~
x
end
% Function code
...
end
c = f(2,3)
For more information on calling functions with ignored inputs, see “Ignore Inputs in Function
Definitions” on page 21-10.
See Also
namedargs2cell | arguments
Related Examples
• “Argument Definitions”
• “Validate Repeating Arguments” on page 26-13
• “Validate Name-Value Arguments” on page 26-16
• “Argument Validation Functions” on page 26-27
• “Validate Property Values”
26-12
Validate Repeating Arguments
arguments (Repeating)
arg1
arg2
...
end
Functions can have one Repeating arguments block for inputs and one for outputs. A Repeating
input arguments block can contain one or more repeating arguments, while a Repeating output
arguments block can contain only one repeating argument.
A function that defines a Repeating arguments block can be called with zero or more occurrences
of all the arguments in the block. If a call to a function includes repeating arguments, then all
arguments in the Repeating arguments block must be included for each repetition.
For example, if a Repeating arguments block defines input arguments x and y, then each
repetition must contain both x and y.
Repeating input arguments cannot specify default values and therefore cannot be optional. However,
you can call the function without including any repeating arguments.
Functions must declare repeating input arguments after positional arguments and before name-value
arguments. You cannot specify name-value arguments within a Repeating block. For information on
name-value arguments, see “Validate Name-Value Arguments” on page 26-16.
In the function, each repeating argument becomes a cell array with the number of elements equal to
the number of repeats passed in the function call. The validation is applied to each element of the cell
array. If the function is called with zero occurrences of this argument, the cell array has a size of 1-
by-0. That is, it is empty.
For example, this function declares a block of three repeating arguments, x, y, and option.
% Function code
% Return cell arrays
xCell = x;
yCell = y;
optionCell = option;
end
You can call the function with no inputs or multiples of three inputs. MATLAB creates a cell array for
each argument containing all the values passes for that argument. This call to fRepeat passes two
sets of the three repeating arguments.
[xCell,yCell,optionCell] = fRepeat(1,2,"linear",3,4,"cubic")
26-13
26 Function Argument Validation
xCell =
{[1]} {[3]}
yCell =
{[2]} {[4]}
optionCell =
{["linear"]} {["cubic"]}
The following function accepts repeating arguments for x and y inputs in a Repeating arguments
block. In the body of the function, the values specified as repeating arguments are available in the
cell arrays x and y. This example interleaves the values of x and y to match the required input to the
plot function: plot(x1,y1,…).
function myPlotRepeating(x,y)
arguments (Repeating)
x (1,:) double
y (1,:) double
end
% Function code
% Interleave x and y
z = reshape([x;y],1,[]);
If you use varargin to support legacy code, it must be the only argument in a Repeating
arguments block.
26-14
Validate Repeating Arguments
For example, this function defines two required positional arguments and varargin as the repeating
argument.
% Function code
...
end
See Also
namedargs2cell | arguments
Related Examples
• “Argument Definitions”
• “Validate Required and Optional Positional Arguments” on page 26-11
• “Validate Name-Value Arguments” on page 26-16
• “Argument Validation Functions” on page 26-27
• “Validate Property Values”
26-15
26 Function Argument Validation
Declare name-value arguments in an arguments block using dot notation to define the fields of a
structure. For example, the structure named NameValueArgs defines two name-value arguments,
Name1 and Name2. You can use any valid MATLAB identifier as the structure name.
arguments
NameValueArgs.Name1
NameValueArgs.Name2
end
Call the function using the field names in the name-value structure.
myFunction(Name1=value1,Name2=value2)
Before R2021a, pass names as strings or character vectors, and separate names and values with
commas. Both syntaxes are valid in later releases.
The name of the structure used in the function signature is the name of the structure in the function
workspace that contains the names and values passed to the function.
function result = myFunction(NameValueArgs)
arguments
NameValueArgs.Name1
NameValueArgs.Name2
end
% Function code
result = NameValueArgs.Name1 * NameValueArgs.Name2;
end
r = myFunction(Name1=3,Name2=7)
r =
21
Name-value arguments support partial name matching when there is no ambiguity. For example, a
function that defines LineWidth and LineStyle as its two name-value arguments accepts LineW
and LineS, but using Line results in an error. In general, using full names is the recommended
practice to improve code readability and avoid unexpected behavior.
26-16
Validate Name-Value Arguments
The same name-value argument can be repeated in a function call without error, but the last version
specified is the one MATLAB honors. For example, this call to plot specifies the value for Color
twice. MATLAB displays the plot in red.
plot(x,y,Color="blue",LineStyle="--",Color="red")
To determine what name-value arguments have been passed in the function call, use the isfield
function.
For example, the following function defines two required positional arguments (width and height)
and two name-value arguments (LineStyle and LineWidth). In this example, the options
structure has two fields (LineStyle and LineWidth) containing either the default values or values
specified as name-value arguments when the function is called.
function myRectangle(width,height,options)
arguments
width double
height double
options.LineStyle (1,1) string = "-"
options.LineWidth (1,1) {mustBeNumeric} = 1
end
% Function code
...
end
Before R2021a, pass names as strings or character vectors, and separate names and values with
commas. For example:
myRectangle(4,5,"LineStyle",":","LineWidth",2)
myRectangle(4,5,"LineWidth",2,"LineStyle",":")
To determine if the function call includes the PlotType argument, use the isfield function to
check for the PlotType field in the scale structure.
26-17
26 Function Argument Validation
function myLinLog(x,y,scale)
arguments(Repeating)
x (1,:) double
y (1,:) double
end
arguments
scale.PlotType (1,1) string
end
z = reshape([x;y],1,[]);
if isfield(scale,"PlotType")
if scale.PlotType == "lin"
plot(z{:})
elseif scale.PlotType =="log"
loglog(z{:})
end
end
end
Before R2021a, pass names as strings or character vectors, and separate names and values with
commas. For example:
myLinLog(1:5,1:5,1:10,1:100:1000,"PlotType","log")
% Function Code
...
end
26-18
Validate Name-Value Arguments
Defining a name-value argument in an arguments block ensures that the name is a valid identifier. In
turn, this helps ensure that your arguments work with both "name",value and name=value
syntaxes. For example, a name-value argument that uses an invalid identifier can work with the
comma-separated syntax:
myFunction(data,"allow-empty",true)
However, the same call using allow-empty=true throws an error. Defining the name-value
argument in an arguments block ensures that the names you define are valid MATLAB variable names
and compatible with the name=value syntax.
Functions that include both optional text inputs and name-value arguments run the risk of MATLAB
interpreting text inputs as the names of the name-value arguments. This function includes two
optional text inputs and a name-value argument.
function mySignal(tag,unit,opts)
arguments
tag = "0"
unit = "ampere"
opts.Magnifier {mustBeMember(opts.Magnifier,["small","medium","big"])}
end
end
A user enters this function call intending to set the values of tag to "Mag" and unit to "coulomb":
mySignal("Mag","coulomb")
However, MATLAB, through partial matching, parses "Mag" as the name-value argument Magnifer.
"coulomb" is not a valid value for that name, so the function errors.
One way to avoid this is to make tag a required argument by removing its default value:
function mySignal(tag,unit,opts)
arguments
tag
unit = "ampere"
opts.Magnifier {mustBeMember(opts.Magnifier,["small","medium","big"])}
end
end
Because MATLAB does not parse required inputs as name-value arguments, the same function call
now sets the value of tag to "Mag" and does not error.
Another option is to make all three inputs name-value arguments. This helps users avoid mistakes
when specifying inputs because each value is associated with a name, and the order the user
specifies the inputs does not affect the end results.
26-19
26 Function Argument Validation
A function can use the "structName.? ClassName" syntax only once. Therefore, a function can
define only one name-value structure that gets its field names from a class, even if using different
classes and structure names.
If the class places restrictions on values that you can assign to the property by using property
validation, then the function applies the validation to the individual name-value arguments. For
information on property validation, see “Validate Property Values”.
For example, this function has two required arguments, x and y and accepts any public property
name and value for the matlab.graphics.chart.primitive.Bar class.
function myBar(x,y,propArgs)
arguments
x (:,:) double
y (:,:) double
propArgs.?matlab.graphics.chart.primitive.Bar
end
propertyCell = namedargs2cell(propArgs);
bar(x,y,propertyCell{:})
end
Call the function with the required inputs and any settable property name-value pairs.
x = [1,2,3;4,5,6];
y = x.^2;
myBar(x,y)
myBar(x,y,FaceColor="magenta",BarLayout="grouped")
Before R2021a, pass names as strings or character vectors, and separate names and values with
commas. For example:
myBar(x,y,"FaceColor","magenta","BarLayout","grouped")
You can override the class property validation by redefining the property name with a specific name-
value argument in the arguments block.
structName.?ClassName
structName.PropertyName (dim1,dim2,...) ClassName {fcn1,fcn2,...}
The specific name-value argument validation overrides the validation defined by class for the
individually specified property name.
For example, the following function defines name-value arguments as the properties of the
matlab.graphics.chart.primitive.Bar class. The function also overrides the property name
FaceColor to allow only these specific values: red or blue.
The matlab.graphics.chart.primitive.Bar class has a default value for FaceColor that is not
one of the restricted values (red or blue). Therefore, the overriding declaration must assign a
default value that satisfies the restriction placed by the mustBeMember validation function. That is,
the default value must be red or blue.
26-20
Validate Name-Value Arguments
This function converts the name-value structure to a cell array containing interleaved names and
values using the namedargs2cell function.
function myBar(x,y,propArgs)
arguments
x (:,:) double
y (:,:) double
propArgs.?matlab.graphics.chart.primitive.Bar
propArgs.FaceColor {mustBeMember(propArgs.FaceColor,{'red','blue'})} = "blue"
end
propertyCell = namedargs2cell(propArgs);
bar(x,y,propertyCell{:})
end
Call the function using the two required arguments, x and y. Optionally pass any name-value pairs
supported by the bar function and a value for FaceColor that can be either red or blue. Other
values for FaceColor are not allowed.
x = [1,2,3;4,5,6];
y = x.^2;
myBar(x,y)
myBar(x,y,FaceColor="red",BarLayout="grouped")
See Also
namedargs2cell | arguments
Related Examples
• “Argument Definitions”
• “Validate Required and Optional Positional Arguments” on page 26-11
• “Validate Repeating Arguments” on page 26-13
• “Argument Validation Functions” on page 26-27
• “Validate Property Values”
26-21
26 Function Argument Validation
For example, this function restricts the first input to a two-dimensional array of any size that is of
class double. The second input must be a 5-by-3 array of any class.
function f(a,b)
arguments
a (:,:) double
b (5,3)
end
% Function code
end
Because of standard MATLAB type conversion and scalar expansion, you can call this function with
the following inputs and not receive a validation error.
f('character vector',144)
By default, MATLAB converts the elements of the character vector to their equivalent numeric value
and applies scalar expansion to create a 5-by-3 array from the scalar value 144.
Using specialized validation functions can provide more specific argument validation. For example,
this function defines specialized validation functions that it uses in place of the class and size
specifications for the first and second arguments. These local functions enable you to avoid input
value conversions.
• mustBeOfClass restricts the input to a specific class without allowing conversion or subclasses.
For a related function, see mustBeA.
• mustBeEqualSize restricts two inputs to be of equal size without allowing scalar expansion. For
a related function, see mustBeScalarOrEmpty.
• mustBeDims restricts the input to be of a specified dimension without allowing transposition or
scalar expansion. For a related function, see mustBeVector.
function fCustomValidators(a,b)
arguments
a {mustBeOfClass(a,'double'), mustBeDims(a,2)}
b {mustBeEqualSize(b,a)}
end
% Function code
end
26-22
Use Validation Functions to Avoid Unwanted Class and Size Conversions
function mustBeEqualSize(a,b)
% Test for equal size
if ~isequal(size(a),size(b))
eid = 'Size:notEqual';
msg = 'Inputs must have equal size.';
error(eid,msg)
end
end
function mustBeDims(input,numDims)
% Test for number of dimensions
if ~isequal(length(size(input)),numDims)
eid = 'Size:wrongDimensions';
msg = ['Input must have ',num2str(numDims),' dimension(s).'];
error(eid,msg,numDims)
end
end
Use fCustomValidators to test the mustBeOfClass function. The first argument is not of class
double, so the function returns an error.
fCustomValidators('character vector',144)
In this call, the number of dimensions of the first input is wrong, so the validation function returns a
custom error message.
fCustomValidators(ones(2,2,4),144)
The mustBeEqualSize validator function checks to see if the inputs are of the same size.
fCustomValidators(ones(2,2),144)
For related predefined validation functions, see mustBeA, mustBeFloat, and mustBeVector.
See Also
namedargs2cell | arguments
26-23
26 Function Argument Validation
Related Examples
• “Argument Definitions”
• “Argument Validation Functions” on page 26-27
• “Validate Property Values”
26-24
Use nargin Functions During Argument Validation
Repeating arguments are positional arguments and therefore the number of repeating arguments
passed to the function when called is included in the value returned by nargin.
The value that nargin returns does not include optional input arguments that are not included in the
function call. Also, nargin does not count any name-value arguments.
Use nargin to determine if optional positional arguments are passed to the function when called. For
example, this function declares three positional arguments and a name-value argument. Here is how
the function determines what arguments are passed when it is called.
• nargin determines if the optional positional argument c is passed to the function with a switch
block.
• isfield determines if the name-value argument for Format is passed to the function.
function result = fNargin(a,b,c,namedargs)
arguments
a (1,1) double
b (1,1) double
c (1,1) double = 1
namedargs.Format (1,:) char
end
% Function code
switch nargin
case 2
result = a + b;
case 3
result = a^c + b^c;
end
if isfield(namedargs,"Format")
format(namedargs.Format);
end
end
result =
result =
4.3021e+04
26-25
26 Function Argument Validation
result = fNargin(3,4,7.62,Format="bank")
result =
43020.56
See Also
nargin | arguments | namedargs2cell
Related Examples
• “Argument Definitions”
• “Argument Validation Functions” on page 26-27
• “Validate Property Values”
26-26
Argument Validation Functions
26-27
26 Function Argument Validation
Data Types
Name Meaning Functions Called
on Inputs
mustBeA(value,classnam value must be of Uses class
es) specific class. definition
relationships
mustBeNumeric(value) value must be isnumeric
numeric.
mustBeNumericOrLogical value must be isnumeric,
(value) numeric or logical. islogical
mustBeFloat(value) value must be isfloat
floating-point array.
mustBeUnderlyingType(v value must have isUnderlyingTyp
alue,typename) specified underlying e
type.
Size
Name Meaning Functions Called
on Inputs
mustBeNonempty(value) value is not empty. isempty
mustBeScalarOrEmpty(va value must be a isscalar,
lue) scalar or be empty. isempty
mustBeVector(value) value must be a isvector
vector.
mustBeRow(value) value must be a 1-by- isrow
N row vector.
26-28
Argument Validation Functions
Text
Name Meaning Functions Called
on Inputs
mustBeFile(path) path must refer to a isfile
file.
mustBeFolder(folder) path must refer to a isfolder
folder.
mustBeNonzeroLengthTex value must be a piece Not applicable
t(value) of text with nonzero
length.
mustBeText(value) value must be a Not applicable
string array, character
vector, or cell array of
character vectors.
mustBeTextScalar(value value must be a Not applicable
) single piece of text.
mustBeValidVariableNam varname must be a isvarname
e(varname) valid variable name.
• Validation functions do not return outputs or modify program state. The only purpose is to check
the validity of the input value.
26-29
26 Function Argument Validation
• Validation functions must accept the value being validated as an argument. If the function accepts
more than one argument, the first input is the value to be validated.
• Validation functions rely only on the inputs. No other values are available to the function.
• Validation functions throw an error if the validation fails.
Creating your own validation function is useful when you want to provide specific validation that is
not available using the MATLAB validation functions. You can create a validation function as a local
function within the function file or place it on the MATLAB path. To avoid a confluence of error
messages, do not use function argument validation within user-defined validation functions.
For example, the mustBeRealUpperTriangular function restricts the input to real-valued, upper
triangular matrices. The validation function uses the istriu and isreal functions.
function mustBeRealUpperTriangular(a)
if ~(istriu(a) && isreal(a))
eidType = 'mustBeRealUpperTriangular:notRealUpperTriangular';
msgType = 'Input must be a real-valued, upper triangular matrix.';
error(eidType,msgType)
end
end
If the argument is not of the correct type, the function throws an error.
a = [1 2 3+2i; 0 2 3; 0 0 1];
mustBeRealUpperTriangular(a)
Input must be a real-valued, upper triangular matrix.
See Also
More About
• “Function Argument Validation” on page 26-2
26-30
Transparency in MATLAB Code
Code has transparent variable access if MATLAB can identify every variable access by scanning the
code while ignoring comments, character vectors, and string literals. Variable access includes
reading, adding, removing, or modifying workspace variables.
• Function argument validation blocks. For more information, see “Restrictions on Variable and
Function Access” on page 26-8
• The body of a parfor loop or spmd block. For more information, see “Ensure Transparency in
parfor-Loops or spmd Statements” (Parallel Computing Toolbox).
X = zeros(1,10);
for ii = 1:10
X(ii) = randi(9,1);
end
However, in the following call to the eval function, MATLAB cannot recognize the variables in the
statement that is passed to eval because the input is a character string.
X = zeros(1,10);
for ii = 1:10
eval('X(ii) = randi(9,1);')
end
Before executing this code, MATLAB sees a call to the eval function with one argument, which is the
character vector 'X(ii) = randi(9,1);'.
To be transparent, code must refer to variable names explicitly so that MATLAB can identify the
variables by inspection or static analysis. Using the eval function with the character vector 'X(ii)
= randi(9,1);' means that MATLAB must execute the code to identify X and ii as variables.
Here is a partial list of functions and coding that you cannot use with transparent variable access:
26-31
26 Function Argument Validation
Passing a variable to a function using the command form is not transparent because it is equivalent to
passing the argument as a character string. For example, these calls to the clear function are both
nontransparent.
clear X
clear('X')
If code creates workspace variables, but MATLAB can identify these new variables only after
executing the code, then this code does not have transparent variable access. For example, MATLAB
cannot determine what variables are loaded from a MAT file, so this statement is nontransparent.
load foo.mat
However, code that explicitly assigns the loaded variable to a name is transparent because MATLAB
can recognize that the name on the left-hand side refers to a workspace variable. For example, this
statement loads the variable X from the MAT file into the workspace in a variable named X.
X = load('foo.mat','X');
Access to variables must be transparent within the workspace. For example, code cannot use the
evalin or assignin functions in a workspace that requires transparency to create variables in
another workspace.
See Also
More About
• “Function Argument Validation” on page 26-2
• “Argument Definitions”
26-32
Software Development
33
27
Error Handling
Overview
No matter how carefully you plan and test the programs you write, they may not always run as
smoothly as expected when executed under different conditions. It is always a good idea to include
error checking in programs to ensure reliable operation under all conditions.
In the MATLAB software, you can decide how your programs respond to different types of errors. You
may want to prompt the user for more input, display extended error or warning information, or
perhaps repeat a calculation using default values. The error-handling capabilities in MATLAB help
your programs check for particular error conditions and execute the appropriate code depending on
the situation.
When MATLAB detects a severe fault in the command or program it is running, it collects information
about what was happening at the time of the error, displays a message to help the user understand
what went wrong, and terminates the command or program. This is called throwing an exception. You
can get an exception while entering commands at the MATLAB command prompt or while executing
your program code.
Evaluate the error message MATLAB has displayed. Most error messages attempt to explain at least
the immediate cause of the program failure. There is often sufficient information to determine the
cause and what you need to do to remedy the situation.
If the function in which the error occurred is implemented as a MATLAB program file, the error
message should include a line that looks something like this:
surf
The text includes the name of the function that threw the error (surf, in this case) and shows the
failing line number within that function's program file. Click the line number; MATLAB opens the file
and positions the cursor at the location in the file where the error originated. You may be able to
determine the cause of the error by examining this line and the code that precedes it.
27-2
Exception Handling in a MATLAB Application
You can use the MATLAB Debugger to step through the failing code. Click the underlined error text to
open the file in the MATLAB Editor at or near the point of the error. Next, click the hyphen at the
beginning of that line to set a breakpoint at that location. When you rerun your program, MATLAB
pauses execution at the breakpoint and enables you to step through the program code. The command
dbstop on error is also helpful in finding the point of error.
See the documentation on “Debug MATLAB Code Files” on page 22-2 for more information.
Some of the things you might want to do in the catch block are:
When you reach the end of the catch block, you can either continue executing the program, if
possible, or terminate it.
Use an MException object to access information about the exception in your program. For more
information, see “Respond to an Exception” on page 27-6.
• Saves information about what went wrong and what code was executing at the time of the error.
• Gathers any other pertinent information about the error.
• Instructs MATLAB to throw the exception.
Use an MException object to capture information about the error. For more information, see “Throw
an Exception” on page 27-4.
27-3
27 Error Handling
Throw an Exception
When your program detects a fault that will keep it from completing as expected or will generate
erroneous results, you should halt further execution and report the error by throwing an exception.
The basic steps to take are:
1 Detect the error. This is often done with some type of conditional statement, such as an if or
try/catch statement that checks the output of the current operation.
2 Construct an MException object to represent the error. Add an error identifier and error
message to the object when calling the constructor.
3 If there are other exceptions that may have contributed to the current error, you can store the
MException object for each in the cause field of a single MException that you intend to throw.
Use the addCause function for this.
4 If there is fix that can be suggested for the current error, you can add it to the Correction field
of the MException that you intend to throw. Use the addCorrection function for this.
5 Use the throw or throwAsCaller function to have MATLAB issue the exception. At this point,
MATLAB stores call stack information in the stack field of the MException, exits the currently
running function, and returns control to either the keyboard or an enclosing catch block in a
calling function.
Create a function, indexIntoArray, that indexes into a specified array using a specified index. The
function catches any errors that MATLAB throws and creates an exception that provides general
information about the error. When it catches an error, it detects whether the error involves the
number of inputs or the specified index. If it does, the function adds additional exceptions with more
detailed information about the source of the failure, and suggests corrections when possible.
function indexIntoArray(A,idx)
throw(baseException);
end
try
assert(isnumeric(idx),'MYFUN:notNumeric', ...
'Indexing array is not numeric.')
catch causeException
baseException = addCause(baseException,causeException);
end
27-4
Throw an Exception
If you call the function without specifying an index, the function throws a detailed error and suggests
a correction:
Caused by:
Not enough input arguments.
If you call the function with a nonnumeric index array that is too large, the function throws a detailed
error.
Caused by:
Error using assert
Indexing array is not numeric.
Indexing array is too large.
27-5
27 Error Handling
Respond to an Exception
In this section...
“Overview” on page 27-6
“The try/catch Statement” on page 27-6
“Suggestions on How to Handle an Exception” on page 27-7
Overview
The MATLAB software, by default, terminates the currently running program when an exception is
thrown. If you catch the exception in your program, however, you can capture information about what
went wrong and deal with the situation in a way that is appropriate for the particular condition. This
requires a try/catch statement.
When you have statements in your code that could generate undesirable results, put those statements
into a try/catch block that catches any errors and handles them appropriately.
A try/catch statement looks something like the following pseudocode. It consists of two parts:
• A try block that includes all lines between the try and catch statements.
• A catch block that includes all lines of code between the catch and end statements.
try
Perform one ...
or more operations
A catch ME
Examine error info in exception object ME
Attempt to figure out what went wrong
Either attempt to recover, or clean up and abort
end
B Program continues
The program executes the statements in the try block. If it encounters an error, it skips any
remaining statements in the try block and jumps to the start of the catch block (shown here as
point A). If all operations in the try block succeed, then execution skips the catch block entirely and
goes to the first line following the end statement (point B).
Specifying the try, catch, and end commands and also the code of the try and catch blocks on
separate lines is recommended. If you combine any of these components on the same line, separate
them with commas:
try, surf, catch ME, ME.stack, end
ans =
file: 'matlabroot\toolbox\matlab\graph3d\surf.m'
name: 'surf'
line: 49
Note You cannot define nested functions within a try or catch block.
27-6
Respond to an Exception
On execution, your code enters the try block and executes each statement as if it were part of the
regular program. If no errors are encountered, MATLAB skips the catch block entirely and continues
execution following the end statement. If any of the try statements fail, MATLAB immediately exits
the try block, leaving any remaining statements in that block unexecuted, and enters the catch
block.
The catch command marks the start of a catch block and provides access to a data structure that
contains information about what caused the exception. This is shown as the variable ME in the
preceding pseudocode. ME is an MException object. When an exception occurs, MATLAB creates an
MException object and returns it in the catch statement that handles that error.
You are not required to specify any argument with the catch statement. If you do not need any of the
information or methods provided by the MException object, just specify the catch keyword alone.
The MException object is constructed by internal code in the program that fails. The object has
properties that contain information about the error that can be useful in determining what happened
and how to proceed. The MException object also provides access to methods that enable you to
respond to the exception.
Having entered the catch block, MATLAB executes the statements in sequence. These statements
can attempt to
The catch block often ends with a rethrow command. The rethrow causes MATLAB to exit the
current function, keeping the call stack information as it was when the exception was first thrown. If
this function is at the highest level, that is, it was not called by another function, the program
terminates. If the failing function was called by another function, it returns to that function. Program
execution continues to return to higher level functions, unless any of these calls were made within a
higher-level try block, in which case the program executes the respective catch block.
• The first if statement checks whether the function is called with an input argument. If no input
argument is specified, the program throws an error and suggests an input argument to correct the
error.
• The try block attempts to open and read the file. If either the open or the read fails, the program
catches the resulting exception and saves the MException object in the variable ME1.
• The catch block checks to see if the specified file could not be found. If so, the program allows for
the possibility that a common variation of the filename extension (e.g., jpeg instead of jpg) was
27-7
27 Error Handling
used, by retrying the operation with a modified extension. This is done using a try/catch
statement nested within the original try/catch.
function d_in = read_image(filename)
% Did the read fail because the file could not be found?
if strcmp(idSegLast,'InvalidFid') && ...
~exist(filename,'file')
This example illustrates some of the actions that you can take in response to an exception.
• Compare the identifier field of the MException object to possible causes of the error. In this
case, the function checks whether the identifier ends in 'InvalidFid', indicating a file could not
be found.
• Use a nested try/catch statement to retry the operation with improved input. In this case, the
function retries the open and read operations using a known variation of the filename extension.
• Display an appropriate message.
• Add the first MException object to the cause field of the second.
• Add a suggested correction to an MException object.
• Rethrow the exception. This stops program execution and displays the error message.
Cleaning up any unwanted results of the error is also advisable. For example, close figures that
remained open after the error occurred.
27-8
Clean Up When Functions Complete
In this section...
“Overview” on page 27-9
“Examples of Cleaning Up a Program Upon Exit” on page 27-10
“Retrieving Information About the Cleanup Routine” on page 27-11
“Using onCleanup Versus try/catch” on page 27-12
“onCleanup in Scripts” on page 27-12
Overview
A good programming practice is to make sure that you leave your program environment in a clean
state that does not interfere with any other program code. For example, you might want to
MATLAB provides the onCleanup function for this purpose. This function, when used within any
program, establishes a cleanup routine for that function. When the function terminates, whether
normally or in the event of an error or Ctrl+C, MATLAB automatically executes the cleanup routine.
The following statement establishes a cleanup routine cleanupFun for the currently running
program:
cleanupObj = onCleanup(@cleanupFun);
When your program exits, MATLAB finds any instances of the onCleanup class and executes the
associated function handles. The process of generating and activating function cleanup involves the
following steps:
1 Write one or more cleanup routines for the program under development. Assume for now that it
takes only one such routine.
2 Create a function handle for the cleanup routine.
3 At some point, generally early in your program code, insert a call to the onCleanup function,
passing the function handle.
4 When the program is run, the call to onCleanup constructs a cleanup object that contains a
handle to the cleanup routine created in step 1.
5 When the program ends, MATLAB implicitly clears all objects that are local variables. This
invokes the destructor method for each local object in your program, including the cleanup
object constructed in step 4.
6 The destructor method for this object invokes this routine if it exists. This perform the tasks
needed to restore your programming environment.
27-9
27 Error Handling
You can declare any number of cleanup routines for a program file. Each call to onCleanup
establishes a separate cleanup routine for each cleanup object returned.
If, for some reason, the object returned by onCleanup persists beyond the life of your program, then
the cleanup routine associated with that object is not run when your function terminates. Instead, it
will run whenever the object is destroyed (e.g., by clearing the object variable).
Your cleanup routine should never rely on variables that are defined outside of that routine. For
example, the nested function shown here on the left executes with no error, whereas the very similar
one on the right fails with the error, Undefined function or variable 'k'. This results from
the cleanup routine's reliance on variable k which is defined outside of the nested cleanup routine:
MATLAB closes the file with identifier fid when function openFileSafely terminates:
function openFileSafely(fileName)
fid = fopen(fileName, 'r');
c = onCleanup(@()fclose(fid));
s = fread(fid);
.
.
.
end
This example preserves the current folder whether functionThatMayError returns an error or not:
function changeFolderSafely(fileName)
currentFolder = pwd;
c = onCleanup(@()cd(currentFolder));
functionThatMayError;
end % c executes cd(currentFolder) here.
This example extends the MATLAB path to include files in the toolbox\images folders, and then
displays a figure from one of these folders. After the figure displays, the cleanup routine
restore_env closes the figure and restores the path to its original state.
function showImageOutsidePath(imageFile)
fig1 = figure;
imgpath = genpath([matlabroot '\toolbox\images']);
27-10
Clean Up When Functions Complete
Run the function as shown here. You can verify that the path has been restored by comparing the
length of the path before and after running the function:
origLen = length(path);
showImageOutsidePath('greens.jpg')
Opening the figure greens.jpg
Closing the figure
Restoring the path
currLen = length(path);
currLen == origLen
ans =
1
@()restore_env(fig1, imgpath)
The details of that handle are then contained within the object returned by the onCleanup function:
You can access these details using the task property of the cleanup object as shown here. (Modify
the showImageOutsidePath function by adding the following code just before the comment line
that says, “% This is the cleanup routine.”)
27-11
27 Error Handling
fprintf('\n');
pause(2);
Run the modified function to see the output of the functions command and the contents of one of
the workspace cells:
showImageOutsidePath('greens.jpg')
The following program cleans up if an error occurs, but not in response to Ctrl+C:
function cleanupByCatch
try
pause(10);
catch
disp(' Collecting information about the error')
disp(' Executing cleanup tasks')
end
Unlike the try/catch statement, the onCleanup function responds not only to a normal exit from
your program and any error that might be thrown, but also to Ctrl+C. This next example replaces the
try/catch with onCleanup:
function cleanupByFunc
obj = onCleanup(@()...
disp(' Executing cleanup tasks'));
pause(10);
onCleanup in Scripts
onCleanup does not work in scripts as it does in functions. In functions, the cleanup object is stored
in the function workspace. When the function exits, this workspace is cleared thus executing the
27-12
Clean Up When Functions Complete
associated cleanup routine. In scripts, the cleanup object is stored in the base workspace (that is, the
workspace used in interactive work done at the command prompt). Because exiting a script has no
effect on the base workspace, the cleanup object is not cleared and the routine associated with that
object does not execute. To use this type of cleanup mechanism in a script, you would have to
explicitly clear the object from the command line or another script when the first script terminates.
27-13
27 Error Handling
In this section...
“Issue Warnings” on page 27-14
“Throw Errors” on page 27-14
“Add Run-Time Parameters to Your Warnings and Errors” on page 27-15
“Add Identifiers to Warnings and Errors” on page 27-15
Issue Warnings
You can issue a warning to flag unexpected conditions detected when running a program. The
warning function prints a warning message to the command line. Warnings differ from errors in two
significant ways:
Use the warning function in your code to generate a warning message during execution. Specify the
message as the input argument to the warning function:
For example, you can insert a warning in your code to verify the software version:
function warningExample1
if ~strncmp(version, '7', 1)
warning('You are using a version other than v7')
end
Throw Errors
You can throw an error to flag fatal problems within the program. Use the error function to print
error messages to the command line. After displaying the message, MATLAB stops the execution of
the current program.
For example, suppose you construct a function that returns the number of combinations of k elements
from n elements. Such a function is nonsensical if k > n; you cannot choose 8 elements if you start
with just 4. You must incorporate this fact into the function to let anyone using combinations know
of the problem:
If the combinations function receives invalid input, MATLAB stops execution immediately after
throwing the error message:
combinations(4,8)
27-14
Issue Warnings and Errors
For example, this warning uses %s and %d to mark where to insert the values of variables arrayname
and arraydims:
If you execute this command with arrayname = 'A' and arraydims = 3, MATLAB responds:
Adding run-time parameters to your warnings and errors can clarify the problems within a program.
Consider the function combinations from “Throw Errors” on page 27-14. You can throw a much
more informative error using run-time parameters:
If this function receives invalid arguments, MATLAB throws an error message and stops the program:
combinations(6,9)
Enable or disable warnings with identifiers. Use an identifying text argument with the warning
function to attach a unique tag to a message:
warning(identifier_text,message_text)
For example, you can add an identifier tag to the previous MATLAB warning about which version of
software is running:
minver = '7';
if ~strncmp(version,minver,1)
warning('MYTEST:VERCHK','Running a version other than v%s',minver)
end
Adding an identifier to an error message allows for negative testing. However, adding and recovering
more information from errors often requires working with MException objects.
27-15
27 Error Handling
See Also
warning | lastwarn | warndlg | MException
Related Examples
• “Suppress Warnings” on page 27-17
• “Restore Warnings” on page 27-20
• “Exception Handling in a MATLAB Application” on page 27-2
27-16
Suppress Warnings
Suppress Warnings
Your program might issue warnings that do not always adversely affect execution. To avoid confusion,
you can hide warning messages during execution by changing their states from 'on' to 'off'.
To suppress specific warning messages, you must first find the warning identifier. Each warning
message has a unique identifier. To find the identifier associated with a MATLAB warning, reproduce
the warning. For example, this code reproduces a warning thrown if MATLAB attempts to remove a
nonexistent folder:
rmpath('folderthatisnotonpath')
Note If this statement does not produce a warning message, use the following code to temporarily
enable the display of all warnings, and then restore the original warning state:
w = warning ('on','all');
rmpath('folderthatisnotonpath')
warning(w)
To obtain information about the most recently issued warning, use the warning or lastwarn
functions. This code uses the query state to return a data structure containing the identifier and the
current state of the last warning:
w = warning('query','last')
w =
identifier: 'MATLAB:rmpath:DirNotFound'
state: 'on'
id = w.identifier;
Note warning('query','last') returns the last displayed warning. MATLAB only displays
warning messages that have state: 'on' and a warning identifier.
Using the lastwarn function, you can retrieve the last warning message, regardless of its display
state:
lastwarn
ans =
27-17
27 Error Handling
Continuing the example from the previous section, turn the warning
'MATLAB:rmpath:DirNotFound' off, and repeat the operation.
warning('off',id)
rmpath('folderthatisnotonpath')
warning('on',id)
rmpath('folderthatisnotonpath')
Tip Turn off the most recently invoked warning with warning('off','last').
The term all refers only to those warnings that have been issued or modified during your current
MATLAB session. Modified warning states persist only through the current session. Starting a new
session restores the default settings.
Use the identifier 'all' to represent the group of all warnings. View the state of all warnings with
either syntax:
warning('query','all')
warning
warning('on','all')
warning('query','all')
To disable all warnings and verify the state, use this syntax:
warning('off','all')
warning
27-18
Suppress Warnings
See Also
Related Examples
• “Restore Warnings” on page 27-20
• “Change How Warnings Display” on page 27-22
27-19
27 Error Handling
Restore Warnings
MATLAB allows you to save the on-off warning states, modify warning states, and restore the
original warning states. This is useful if you need to temporarily turn off some warnings and later
reinstate the original settings.
The following statement saves the current state of all warnings in the structure array called
orig_state:
orig_state = warning;
To restore the original state after any warning modifications, use this syntax:
warning(orig_state);
You also can save the current state and toggle warnings in a single command. For example, the
statement, orig_state = warning('off','all'); is equivalent to the commands:
orig_state = warning;
warning('off','all')
warning('query','Control:parameterNotSymmetric')
orig_state = warning('off','Control:parameterNotSymmetric')
orig_state =
identifier: 'Control:parameterNotSymmetric'
state: 'on'
warning
The default warning state is 'on'. Warnings not set to the default are
off Control:parameterNotSymmetric
warning(orig_state)
warning('query','Control:parameterNotSymmetric')
27-20
Restore Warnings
w(1) = warning('off','MATLAB:rmpath:DirNotFound');
w(2) = warning('off','MATLAB:singularMatrix');
w(3) = warning('off','Control:parameterNotSymmetric');
warning
The default warning state is 'on'. Warnings not set to the default are
off Control:parameterNotSymmetric
off MATLAB:rmpath:DirNotFound
off MATLAB:singularMatrix
2 Restore the three warnings to their the original state, and query all warnings:
warning(w)
warning
You do not need to store information about the previous warning states in an array, but doing so
allows you to restore warnings with one command.
Note When temporarily disabling multiple warnings, using methods related to onCleanup might be
advantageous.
orig_state = warning('on','all');
2 Restore your warnings to the previous state:
warning(orig_state)
See Also
warning | onCleanup
Related Examples
• “Suppress Warnings” on page 27-17
• “Clean Up When Functions Complete” on page 27-9
27-21
27 Error Handling
You can control how warnings appear in MATLAB by modifying two warning modes, verbose and
backtrace.
• prev_state does not contain information about the backtrace or verbose modes in the
statement, prev_state = warning('query','all').
• A mode change affects all enabled warnings.
For example, you can turn on all warnings, disable backtrace, and enable verbose warnings:
warning on all
warning off backtrace
warning on verbose
rmpath('folderthatisnotonpath')
Warning: "folderthatisnotonpath" not found in path.
(Type "warning off MATLAB:rmpath:DirNotFound" to suppress this warning.)
warning on backtrace
warning off verbose
Running a command that produces an error displays a hyperlink with a line number:
27-22
Use try/catch to Handle Errors
If an error occurs within the try block, MATLAB skips any remaining commands in the try block
and executes the commands in the catch block. If no error occurs within try block, MATLAB
skips the entire catch block.
For example, a try/catch statement can prevent the need to throw errors. Consider the
combinations function that returns the number of combinations of k elements from n elements:
function com = combinations(n,k)
com = factorial(n)/(factorial(k)*factorial(n-k));
end
MATLAB throws an error whenever k > n. You cannot construct a set with more elements, k, than
elements you possess, n. Using a try/catch statement, you can avoid the error and execute this
function regardless of the order of inputs:
function com = robust_combine(n,k)
try
com = factorial(n)/(factorial(k)*factorial(n-k));
catch
com = factorial(k)/(factorial(n)*factorial(k-n));
end
end
C1 =
70
C2 =
70
Optionally, you can capture more information about errors if a variable follows your catch statement:
catch MExc
27-23
27 Error Handling
MExc is an MException class object that contains more information about the thrown error. To learn
more about accessing information from MException objects, see “Exception Handling in a MATLAB
Application” on page 27-2.
See Also
MException | onCleanup | try, catch
27-24
28
Program Scheduling
In this section...
“Overview” on page 28-2
“Example: Displaying a Message” on page 28-2
Overview
The MATLAB software includes a timer object that you can use to schedule the execution of MATLAB
commands. This section describes how you can create timer objects, start a timer running, and
specify the processing that you want performed when a timer fires. A timer is said to fire when the
amount of time specified by the timer object elapses and the timer object executes the commands you
specify.
You use timer object properties to specify this information. To learn about all the properties
supported by the timer object, see timer. You can also set timer object properties when you
create them, in step 1.
3 Start the timer object.
After you create the timer object, you must start it, using either the start or startat function.
4 Delete the timer object when you are done with it.
After you are finished using a timer object, you should delete it from memory. See delete for
more information.
Note The specified execution time and the actual execution of a timer can vary because timer objects
work in the MATLAB single-threaded execution environment. The length of this time lag is dependent
on what other processing MATLAB is performing. To force the execution of the callback functions in
the event queue, include a call to the drawnow function in your code. The drawnow function flushes
the event queue.
28-2
Schedule Command Execution Using Timer
After creating the timer object, the example uses the start function to start the timer object. (The
additional commands in this example are included to illustrate the timer but are not required for
timer operation.)
stat=true;
while(stat==true)
disp('.')
pause(1)
end
.
.
.
.
.
.
.
.
.
Timer!
See Also
timer
More About
• “Timer Callback Functions” on page 28-4
• “Handling Timer Queuing Conflicts” on page 28-8
28-3
28 Program Scheduling
Note Callback function execution might be delayed if the callback involves a CPU-intensive task such
as updating a figure.
The following diagram shows when the events occur during execution of a timer object and give the
names of the timer object properties associated with each event. For example, to associate MATLAB
commands with a start event, assign a value to the StartFcn callback property. Error callbacks can
occur at any time.
When the time period specified by a timer object elapses, the timer object executes one or more
MATLAB functions of your choosing. You can specify the functions directly as the value of the callback
28-4
Timer Callback Functions
property. You can also put the commands in a function file and specify the function as the value of the
callback property.
This example creates a timer object that displays a greeting after 5 seconds. The example specifies
the value of the TimerFcn callback property directly, putting the commands in a character vector.
t = timer('TimerFcn',@(x,y)disp('Hello World!'),'StartDelay',5);
Note When you specify the callback commands directly as the value of the callback function
property, the commands are evaluated in the MATLAB workspace.
Instead of specifying MATLAB commands directly as the value of a callback property, you can put the
commands in a MATLAB program file and specify the file as the value of the callback property.
When you create a callback function, the first two arguments must be a handle to the timer object
and an event structure. An event structure contains two fields: Type and Data. The Type field
contains a character vector that identifies the type of event that caused the callback. The value of this
field can be any of the following: 'StartFcn', 'StopFcn', 'TimerFcn', or 'ErrorFcn'. The Data
field contains the time the event occurred.
In addition to these two required input arguments, your callback function can accept application-
specific arguments. To receive these input arguments, you must use a cell array when specifying the
name of the function as the value of a callback property. For more information, see “Specifying the
Value of Callback Function Properties” on page 28-5.
This example implements a simple callback function that displays the type of event that triggered the
callback and the time the callback occurred. To illustrate passing application-specific arguments, the
example callback function accepts as an additional argument a character vector and includes this text
in the display output. To see this function used with a callback property, see “Specifying the Value of
Callback Function Properties” on page 28-5.
event_type = event.Type;
event_time = datestr(event.Data.time);
28-5
28 Program Scheduling
You associate a callback function with a specific event by setting the value of the appropriate callback
property. You can specify the callback function as a cell array or function handle. If your callback
function accepts additional arguments, you must use a cell array.
The following table shows the syntax for several sample callback functions and describes how you call
them.
This example illustrates several ways you can specify the value of timer object callback function
properties, some with arguments and some without. To see the code of the callback function,
my_callback_fcn, see “Example: Writing a Callback Function” on page 28-5:
start(t)
delete(t)
See Also
timer
28-6
Timer Callback Functions
More About
• “Handling Timer Queuing Conflicts” on page 28-8
28-7
28 Program Scheduling
During busy times, in multiple-execution scenarios, the timer might need to add the timer callback
function (TimerFcn) to the MATLAB execution queue before the previously queued execution of the
callback function has been completed. The BusyMode property affects behavior only when the
ExecutionMode property is set to FixedRate. For other values of ExecutionMode, there cannot be
overlapping attempts to execute the timer callback function because the delay between executions is
always relative to the completion of the previous execution.
You can determine how the timer object handles this scenario by setting the BusyMode property to
use one of these modes:
For example, suppose you create a timer with a period of 1 second, but a callback that requires at
least 1.6 seconds, as shown here for mytimer.m.
function mytimer()
t = timer;
t.Period = 1;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @mytimer_cb;
t.BusyMode = 'drop';
t.TasksToExecute = 5;
t.UserData = tic;
start(t)
end
function mytimer_cb(h,~)
timeStart = toc(h.UserData)
pause(1.6);
timeEnd = toc(h.UserData)
end
This table describes how the timer manages the execution queue.
28-8
Handling Timer Queuing Conflicts
Error Mode
The 'error' mode for the BusyMode property is similar to the 'drop' mode: In both modes, the
timer allows only one instance of the callback in the execution queue. In 'error' mode, when the
queue is nonempty, the timer calls the function that you specify by using the ErrorFcn property, and
then stops processing. The currently running callback function completes, but the callback in the
queue does not execute.
For example, modify mytimer.m (described in the previous section) so that it includes an error
handling function and sets BusyMode to 'error'.
function mytimer()
t = timer;
t.Period = 1;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @mytimer_cb;
t.ErrorFcn = @myerror;
t.BusyMode = 'error';
t.TasksToExecute = 5;
t.UserData = tic;
start(t)
28-9
28 Program Scheduling
end
function mytimer_cb(h,~)
timeStart = toc(h.UserData)
pause(1.6);
timeEnd = toc(h.UserData)
end
function myerror(h,~)
disp('Reached the error function')
end
This table describes how the timer manages the execution queue.
Queue Mode
If you specify 'queue', the timer object waits until the currently executing callback function finishes
before queuing the next execution of the timer callback function.
In 'queue' mode, the timer object tries to make the average time between executions equal the
amount of time specified in the Period property. If the timer object has to wait longer than the time
specified in the Period property between executions of the timer function callback, it shortens the
time period for subsequent executions to make up the time.
For example, modify mytimer.m (described in the previous section) so that BusyMode is set to
'queue'.
function mytimer()
t = timer;
t.Period = 1;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @mytimer_cb;
t.ErrorFcn = @myerror;
t.BusyMode = 'queue';
t.TasksToExecute = 5;
t.UserData = tic;
start(t)
28-10
Handling Timer Queuing Conflicts
end
function mytimer_cb(h,~)
timeStart = toc(h.UserData)
pause(1.6);
timeEnd = toc(h.UserData)
end
function myerror(h,~)
disp('Reached the error function')
end
This table describes how the timer manages the execution queue.
28-11
28 Program Scheduling
See Also
timer
More About
• “Timer Callback Functions” on page 28-4
28-12
29
Performance
For additional details about the performance of your code, such as function call information and
execution time of individual lines of code, use the MATLAB Profiler. For more information, see “Profile
Your Code to Improve Performance” on page 29-4.
Time Functions
To measure the time required to run a function, use the timeit function. The timeit function calls
the specified function multiple times, and returns the median of the measurements. It takes a handle
to the function to be measured and returns the typical execution time, in seconds. Suppose that you
have defined a function, computeFunction, that takes two inputs, x and y, that are defined in your
workspace. You can compute the time to execute the function using timeit.
tic
% The program section to time.
toc
Sometimes programs run too fast for tic and toc to provide useful data. If your code is faster than
1/10 second, consider measuring it running in a loop, and then average to find the time for a single
run.
29-2
Measure the Performance of Your Code
The cputime function measures the total CPU time and sums across all threads. This measurement is
different from the wall-clock time that timeit or tic/toc return, and could be misleading. For
example:
• The CPU time for the pause function is typically small, but the wall-clock time accounts for the
actual time that MATLAB execution is paused. Therefore, the wall-clock time might be longer.
• If your function uses four processing cores equally, the CPU time could be approximately four
times higher than the wall-clock time.
• Time a significant enough portion of code. Ideally, the code you are timing should take more than
1/10 second to run.
• Put the code you are trying to time into a function instead of timing it at the command line or
inside a script.
• Unless you are trying to measure first-time cost, run your code multiple times. Use the timeit
function.
• Avoid clear all when measuring performance. For more information, see the clear function.
• Assign your output to a variable instead of letting it default to ans.
See Also
timeit | tic | toc | profile
Related Examples
• “Profile Your Code to Improve Performance” on page 29-4
• “Techniques to Improve Performance” on page 29-12
29-3
29 Performance
What Is Profiling?
Profiling is a way to measure the time it takes to run your code and identify where MATLAB spends
the most time. After you identify which functions are consuming the most time, you can evaluate
them for possible performance improvements. You also can profile your code to determine which lines
of code do not run. Determining which lines of code do not run is useful when developing tests for
your code, or as a debugging tool to help isolate a problem in your code.
You can profile your code interactively using the MATLAB Profiler or programmatically using the
profile function. For more information about profiling your code programmatically, see profile. If
you are profiling code that runs in parallel, for best results use the Parallel Computing Toolbox
parallel profiler. For details, see “Profiling Parallel Code” (Parallel Computing Toolbox).
Tip Code that is prematurely optimized can be unnecessarily complex without providing a significant
gain in performance. Make your first implementation as simple as possible. Then, if speed is an issue,
use profiling to identify bottlenecks.
To profile your code and improve its performance, use this general process:
For example, you may want to investigate functions and lines of code that use a significant
amount of time or that are called most frequently.
4 Save the profiling results.
5 Implement potential performance improvements in your code.
For example, if you have a load statement within a loop, you might be able to move the load
statement outside the loop so that it is called only once.
6 Save the files, and run clear all. Run the Profiler again and compare the results to the original
results.
7 Repeat the above steps to continue improving the performance of your code. When your code
spends most of its time on calls to a few built-in functions, you have probably optimized the code
as much as possible.
1 Open the Profiler by going to the Apps tab, and under MATLAB, clicking the Profiler app icon.
You also can type profile viewer in the Command Window.
29-4
Profile Your Code to Improve Performance
2 Go to the Profiler tab, and in the Profile section, enter the code that you want to profile in the
edit box.
For example, create a function solvelotka.m that finds the prey and predator population peaks
for the Lotka-Volterra example provided with MATLAB:
preypeaks = calculatepeaks(y(:,1));
predatorpeaks = calculatepeaks(y(:,2));
end
Enter this statement in the edit box to profile the solvelotka function:
[preypeaks,predatorpeaks] = solvelotka(0,15,[20;20])
If you previously profiled the statement in the current MATLAB session, you also can select it
from the edit box drop down list.
3
Click Run and Time.
When profiling is complete, the Profiler displays the results in Profile Summary. The statements
you profiled also display as having been run in the Command Window.
To profile a code file open in the Editor, on the Editor tab, in the Run section, select Run > Run and
Time. The Profiler profiles the code file open in the current Editor tab and displays the results in the
Profile Summary.
After running the Profiler on your code, the Profile Summary presents statistics about the overall
execution of your code and provides summary statistics for each function called. For example, the
image below shows the Profile Summary for the solvelotka function.
29-5
29 Performance
At the top of the Profile Summary results, a flame graph shows a visual representation of the time
MATLAB spent running the code. Each function that was run is represented by a bar in the flame
graph. User-defined functions display in blue, and MathWorks functions display in gray.
The functions in the graph display in hierarchical order, with parent functions appearing lower on the
graph, and child functions appearing higher on the graph. The bar that spans the entire bottom of the
graph labeled Profile Summary represents all of the code that ran. The width of a bar on the graph
represents the amount of time it took for the function to run as a percentage of the total run time.
To see the actual percentage and time values as well as the full function name, hover over the bar in
the graph. To display detailed information about a function including information about individual
code lines, click the bar representing that function.
29-6
Profile Your Code to Improve Performance
The function table below the flame frame displays similar information to the flame graph. Initially the
functions appear in order of time they took to process. This table describes the information in each
column.
Column Description
Function Name Name of the function called by the profiled code.
Calls Number of times the profiled code called the function.
Total Time Total time spent in the function, in seconds. The time for the function includes time
spent in child functions. The Profiler itself takes some time, which is included in
the results. The total time can be zero for files whose run time is inconsequential.
Self Time Total time in seconds spent in a function, excluding time spent in any child
functions. Self time also includes some overhead resulting from the process of
profiling.
Total Time Plot Graphic display showing self time compared to total time.
To sort the function table by a specific column, click the arrow in the column header. For example,
click the arrow in the Function Name column to sort the functions alphabetically. Initially the results
appear in order by Total Time. To display detailed information about a function including information
about individual code lines, click the function name.
To find potential improvements in your code, look for functions in the flame graph or function table
that use a significant amount of time or that are called most frequently. Click a function name to
display detailed information about the function, including information about individual code lines. For
example, click the solvelotka>calculatepeaks function. The Profiler displays detailed
information for the function.
29-7
29 Performance
At the top of the page, next to the name of the current function, the Profiler displays the number of
times the function was called by a parent function and the total time spent in the function. Use the
displayed links underneath the flame graph to open the function in your default editor or copy the
displayed results to a separate window.
Once you have clicked an individual function, the Profiler displays additional information in these
sections:
29-8
Profile Your Code to Improve Performance
Section Details
Flame Graph Flame graph showing visual representation of the time MATLAB spent
running the profiled function. The graph shows the hierarchy of the
profiled function, including child functions (displayed above the
current function) and parent functions (displayed below the current
function). User-defined functions display in blue ( ), and MathWorks
functions display in gray ( ).
Hover over the bar in the graph to see the actual percentage and time
values as well as the full function name. Click a bar representing a
function to display detailed information about the function.
Parents List of functions that call the profiled function, including the number
of times the parent function called the profiled function.
Click a code line to see it in the Function Listing section, within the
context of the rest of the function code.
Children List of all the functions called by the profiled function.
29-9
29 Performance
Section Details
Function listing Source code for the function, if it is a MATLAB code file.
For each line of code, the Function listing includes these columns:
To compare the impact of changes after you have made improvements to your code, save your
profiling results. To save your results, use the displayed link underneath the flame graph to copy the
displayed results to a separate window.
You also can print your results from the Profiler by going to the Profiler tab and clicking the Print
button.
29-10
Profile Your Code to Improve Performance
Profile an App
You can profile apps that you create in App Designer. You also can profile apps that ship with
MathWorks products, such as the Filter Design and Analysis tool included with Signal Processing
Toolbox™.
To profile an app:
1 Open the Profiler by going to the Apps tab, and under MATLAB, clicking the Profiler app icon.
You also can type profile viewer in the Command Window.
2
In the Profile section of the Profiler toolstrip, click Start Profiling. Make sure that there is
no code in the edit box to the right of the button.
3 Start the app.
4 Use the app.
5 When you are finished, click Stop Profiling in the Profiler toolstrip.
6 Review the Profile Summary results.
Note To exclude the app startup process in the profile, reverse steps 2 and 3. In other words, start
the app before you click Start Profiling.
See Also
Apps
Profiler
Functions
profile | profsave
More About
• “Measure the Performance of Your Code” on page 29-2
• “Techniques to Improve Performance” on page 29-12
• “Collect Statement and Function Coverage Metrics for MATLAB Source Code” on page 36-220
29-11
29 Performance
In this section...
“Environment” on page 29-12
“Code Structure” on page 29-12
“Programming Practices for Performance” on page 29-12
“Tips on Specific MATLAB Functions” on page 29-13
Environment
Be aware of background processes that share computational resources and decrease the performance
of your MATLAB code.
Code Structure
While organizing your code:
29-12
Techniques to Improve Performance
• Avoid using “data as code” — If you have large portions of code (for example, over 500 lines) that
generate variables with constant values, consider constructing the variables and saving them, for
example, in a MAT-file or .csv file. Then you can load the variables instead of executing code to
generate them.
• Run code in the background — Use parfeval with backgroundPool to run a function in the
background. You can simultaneously run other code in MATLAB and make your apps more
responsive. For more information, see “Run Functions in the Background” on page 30-6.
• Run code on a GPU or in parallel — If you have a Parallel Computing Toolbox license, run code on
a GPU by passing gpuArray data to a supported function or run code in parallel using, for
example, a parfor-loop. For more information, see “Choose a Parallel Computing Solution”
(Parallel Computing Toolbox).
• Avoid clearing more code than necessary. Do not use clear all programmatically. For more
information, see clear.
• Avoid functions that query the state of MATLAB such as inputname, which, whos, exist(var),
and dbstack. Run-time introspection is computationally expensive.
• Avoid functions such as eval, evalc, evalin, and feval(fname). Use the function handle input
to feval whenever possible. Indirectly evaluating a MATLAB expression from text is
computationally expensive.
• Avoid programmatic use of cd, addpath, and rmpath, when possible. Changing the MATLAB path
during run time results in code recompilation.
See Also
More About
• “Measure the Performance of Your Code” on page 29-2
• “Profile Your Code to Improve Performance” on page 29-4
• “Preallocation” on page 29-14
• “Vectorization” on page 29-16
• “Graphics Performance”
• “Measure and Improve GPU Performance” (Parallel Computing Toolbox)
29-13
29 Performance
Preallocation
for and while loops that incrementally increase the size of a data structure each time through the
loop can adversely affect performance and memory use. Repeatedly resizing arrays often requires
MATLAB to spend extra time looking for larger contiguous blocks of memory, and then moving the
array into those blocks. Often, you can improve code execution time by preallocating the maximum
amount of space required for the array.
The following code displays the amount of time needed to create a scalar variable, x, and then to
gradually increase the size of x in a for loop.
tic
x = 0;
for k = 2:1000000
x(k) = x(k-1) + 5;
end
toc
If you preallocate a 1-by-1,000,000 block of memory for x and initialize it to zero, then the code runs
much faster because there is no need to repeatedly reallocate memory for the growing data
structure.
tic
x = zeros(1,1000000);
for k = 2:1000000
x(k) = x(k-1) + 5;
end
toc
Use the appropriate preallocation function for the kind of array you want to initialize:
A = int8(zeros(100));
This statement preallocates a 100-by-100 matrix of int8, first by creating a full matrix of double
values, and then by converting each element to int8. Creating the array as int8 values saves time
and memory. For example:
A = zeros(100,'int8');
29-14
Preallocation
See Also
Related Examples
• “Reshaping and Rearranging Arrays”
• “Preallocate Memory for Cell Array” on page 12-11
• “Access Data Using Categorical Arrays” on page 8-33
• “Preallocate Arrays of Graphics Objects”
• “Create and Initialize Object Arrays”
More About
• “Techniques to Improve Performance” on page 29-12
29-15
29 Performance
Vectorization
In this section...
“Using Vectorization” on page 29-16
“Array Operations” on page 29-17
“Logical Array Operations” on page 29-18
“Matrix Operations” on page 29-19
“Ordering, Setting, and Counting Operations” on page 29-20
“Functions Commonly Used in Vectorization” on page 29-21
Using Vectorization
MATLAB is optimized for operations involving matrices and vectors. The process of revising loop-
based, scalar-oriented code to use MATLAB matrix and vector operations is called vectorization.
Vectorizing your code is worthwhile for several reasons:
• Appearance: Vectorized mathematical code appears more like the mathematical expressions found
in textbooks, making the code easier to understand.
• Less Error Prone: Without loops, vectorized code is often shorter. Fewer lines of code mean fewer
opportunities to introduce programming errors.
• Performance: Vectorized code often runs much faster than the corresponding code containing
loops.
This code computes the sine of 1,001 values ranging from 0 to 10:
i = 0;
for t = 0:.01:10
i = i + 1;
y(i) = sin(t);
end
t = 0:.01:10;
y = sin(t);
The second code sample usually executes faster than the first and is a more efficient use of MATLAB.
Test execution speed on your system by creating scripts that contain the code shown, and then use
the tic and toc functions to measure their execution time.
This code computes the cumulative sum of a vector at every fifth element:
x = 1:10000;
ylength = (length(x) - mod(length(x),5))/5;
y(1:ylength) = 0;
for n= 5:5:length(x)
29-16
Vectorization
y(n/5) = sum(x(1:n));
end
Using vectorization, you can write a much more concise MATLAB process. This code shows one way
to accomplish the task:
x = 1:10000;
xsums = cumsum(x);
y = xsums(5:5:length(x));
Array Operations
Array operators perform the same operation for all elements in the data set. These types of
operations are useful for repetitive calculations. For example, suppose you collect the volume (V) of
various cones by recording their diameter (D) and height (H). If you collect the information for just
one cone, you can calculate the volume for that single cone:
V = 1/12*pi*(D^2)*H;
Now, collect information on 10,000 cones. The vectors D and H each contain 10,000 elements, and you
want to calculate 10,000 volumes. In most programming languages, you need to set up a loop similar
to this MATLAB code:
for n = 1:10000
V(n) = 1/12*pi*(D(n)^2)*H(n);
end
With MATLAB, you can perform the calculation for each element of a vector with similar syntax as the
scalar case:
% Vectorized Calculation
V = 1/12*pi*(D.^2).*H;
Note Placing a period (.) before the operators *, /, and ^, transforms them into array operators.
Array operators also enable you to combine matrices of different dimensions. This automatic
expansion of size-1 dimensions is useful for vectorizing grid creation, matrix and vector operations,
and more.
Suppose that matrix A represents test scores, the rows of which denote different classes. You want to
calculate the difference between the average score and individual scores for each class. Using a loop,
the operation looks like:
mA = mean(A);
B = zeros(size(A));
for n = 1:size(A,2)
B(:,n) = A(:,n) - mA(n);
end
A more direct way to do this is with A - mean(A), which avoids the need of a loop and is
significantly faster.
29-17
29 Performance
devA = A - mean(A)
devA =
18 11 0
16 4 8
-15 2 15
-3 -1 -17
9 -19 -10
-1 -12 3
-24 15 1
Even though A is a 7-by-3 matrix and mean(A) is a 1-by-3 vector, MATLAB implicitly expands the
vector as if it had the same size as the matrix, and the operation executes as a normal element-wise
minus operation.
The size requirement for the operands is that for each dimension, the arrays must either have the
same size or one of them is 1. If this requirement is met, then dimensions where one of the arrays has
size 1 are expanded to be the same size as the corresponding dimension in the other array. For more
information, see “Compatible Array Sizes for Basic Operations” on page 2-12.
Another area where implicit expansion is useful for vectorization is if you are working with
multidimensional data. Suppose you want to evaluate a function, F, of two variables, x and y.
To evaluate this function at every combination of points in the x and y vectors, you need to define a
grid of values. For this task you should avoid using loops to iterate through the point combinations.
Instead, if one of the vectors is a column and the other is a row, then MATLAB automatically
constructs the grid when the vectors are used with an array operator, such as x+y or x-y. In this
example, x is a 21-by-1 vector and y is a 1-by-16 vector, so the operation produces a 21-by-16 matrix
by expanding the second dimension of x and the first dimension of y.
x = (-2:0.2:2)'; % 21-by-1
y = -1.5:0.2:1.5; % 1-by-16
F = x.*exp(-x.^2-y.^2); % 21-by-16
In cases where you want to explicitly create the grids, you can use the meshgrid and ndgrid
functions.
For example, suppose while collecting data from 10,000 cones, you record several negative values for
the diameter. You can determine which values in a vector are valid with the >= operator:
ans =
0 1 1 1 0 1 1
29-18
Vectorization
You can directly exploit the logical indexing power of MATLAB to select the valid cone volumes,
Vgood, for which the corresponding elements of D are nonnegative:
MATLAB allows you to perform a logical AND or OR on the elements of an entire vector with the
functions all and any, respectively. You can throw a warning if all values of D are below zero:
if all(D < 0)
warning('All values of diameter are negative.')
return
end
MATLAB can also compare two vectors with compatible sizes, allowing you to impose further
restrictions. This code finds all the values where V is nonnegative and D is greater than H:
To aid comparison, MATLAB contains special values to denote overflow, underflow, and undefined
operators, such as Inf and NaN. Logical operators isinf and isnan exist to help perform logical
tests for these special values. For example, it is often useful to exclude NaN values from
computations:
xvalid =
2 -1 0 3 2 11 4 Inf
Note Inf == Inf returns true; however, NaN == NaN always returns false.
Matrix Operations
When vectorizing code, you often need to construct a matrix with a particular size or structure.
Techniques exist for creating uniform matrices. For instance, you might need a 5-by-5 matrix of equal
elements:
A = ones(5,5)*10;
v = 1:5;
A = repmat(v,3,1)
A =
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
The function repmat possesses flexibility in building matrices from smaller matrices or vectors.
repmat creates matrices by repeating an input matrix:
29-19
29 Performance
A = repmat(1:3,5,2)
B = repmat([1 2; 3 4],2,2)
A =
1 2 3 1 2 3
1 2 3 1 2 3
1 2 3 1 2 3
1 2 3 1 2 3
1 2 3 1 2 3
B =
1 2 1 2
3 4 3 4
1 2 1 2
3 4 3 4
A number of different ways exist for finding the redundant elements of a vector. One way involves the
function diff. After sorting the vector elements, equal adjacent elements produce a zero entry when
you use the diff function on that vector. Because diff(x) produces a vector that has one fewer
element than x, you must add an element that is not equal to any other element in the set. NaN
always satisfies this condition. Finally, you can use logical indexing to choose the unique elements in
the set:
x = [2 1 2 2 3 1 3 2 1 3];
x = sort(x);
difference = diff([x,NaN]);
y = x(difference~=0)
y =
1 2 3
Alternatively, you could accomplish the same operation by using the unique function:
y=unique(x);
However, the unique function might provide more functionality than is needed and slow down the
execution of your code. Use the tic and toc functions if you want to measure the performance of
each code snippet.
Rather than merely returning the set, or subset, of x, you can count the occurrences of an element in
a vector. After the vector sorts, you can use the find function to determine the indices of zero values
29-20
Vectorization
in diff(x) and to show where the elements change value. The difference between subsequent
indices from the find function indicates the number of occurrences for a particular element:
x = [2 1 2 2 3 1 3 2 1 3];
x = sort(x);
difference = diff([x,max(x)+1]);
count = diff(find([1,difference]))
y = x(find(difference))
count =
3 4 3
y =
1 2 3
The find function does not return indices for NaN elements. You can count the number of NaN and
Inf values using the isnan and isinf functions.
count_nans = sum(isnan(x(:)));
count_infs = sum(isinf(x(:)));
29-21
29 Performance
See Also
More About
• “Array Indexing”
• “Techniques to Improve Performance” on page 29-12
• “Array vs. Matrix Operations” on page 2-7
External Websites
• MathWorks Newsletter: Matrix Indexing in MATLAB
29-22
30
Background Processing
Asynchronous Functions
MATLAB either runs code synchronously or asynchronously. You can use the following functions to
run code asynchronously:
Calculate the maximum of two random matrices. MATLAB runs each line consecutively.
tic
A = rand(10000);
B = ones(10000);
C = max(A,B);
toc
Asynchronous Code
When you run a function asynchronously, MATLAB can run other code in the foreground at the same
time.
Use parfeval or parfevalOnAll to run functions asynchronously. Use afterEach and afterAll
to run functions asynchronously after a previous function completes.
• When you run a function asynchronously, MATLAB immediately returns a Future object. MATLAB
schedules the function to run in the background or on a parallel pool.
30-2
Asynchronous Functions
Calculate the maximum of two random matrices: one created in the background, and one created in
the foreground. Matrix A is created in the background, and matrix B is calculated in the foreground at
the same time.
Note Generally, you do not need to use wait. fetchOutputs will implicitly wait for MATLAB to
finish running the function in the background before collecting results. The function wait is used
here to explicitly show waiting for results before collecting them.
tic
fA = parfeval(backgroundPool,@rand,1,10000);
B = ones(10000);
wait(fA)
C = max(fetchOutputs(fA),B);
toc
a Use parfeval to schedule the function rand to run in the background, with 1 output and a
single input 10000. Return a future fA in the foreground.
b Run the function rand in the background.
30-3
30 Background Processing
a Use wait to explicitly wait for the future fA to finish running in the background.
b Use fetchOutputs to get rand(10000) from the future fA.
c Calculate the final result C from matrices fetchOutputs(fA) and B.
Background Workers
When you use parfeval or parfevalOnAll to run a function asynchronously, MATLAB runs the
function on a pool.
When you use backgroundPool to run code in the background, MATLAB uses the background pool
to run that code.
The background pool has a fixed number of workers. MATLAB uses these workers to run functions.
Each worker can only run one function at a time. Therefore when you run multiple functions in the
background, you must wait for a worker to be available to run each function.
Use the NumWorkers property of a backgroundPool to find out how many workers you have.
• If you do not have a license for Parallel Computing Toolbox, the background pool has 1 worker.
• If you have a license for Parallel Computing Toolbox, the background pool has multiple workers.
The number of workers in the background pool is the number of physical cores on your machine.
For example if your machine has 4 cores, the background pool has 4 workers. You can reduce this
value using maxNumCompThreads before the first usage of backgroundPool.
See Also
parfeval | backgroundPool
Related Examples
• “Update Wait Bar While Functions Run in the Background” on page 30-14
30-4
Asynchronous Functions
More About
• “Run MATLAB Functions in Thread-Based Environment” on page 30-6
• “Write Portable Parallel Code” (Parallel Computing Toolbox)
30-5
30 Background Processing
Use the rand function to generate a 100-by-100 matrix of random numbers in the background.
f = parfeval(backgroundPool,@rand,1,100);
For more information about running code in the background, see backgroundPool.
parpool("threads");
parfor i = 1:100
A{i} = rand(100);
end
Automatically Scale Up
If you have Parallel Computing Toolbox, your code that uses backgroundPool automatically scales
up to use more available cores.
For information about the number of cores that you can use, see the NumWorkers property of
BackgroundPool.
By running multiple functions in the background at the same time when you use Parallel Computing
Toolbox, you can speed up the following code.
for i = 1:100
f(i) = parfeval(backgroundPool,@rand,1,100);
end
30-6
Run MATLAB Functions in Thread-Based Environment
Tip For a filtered list of MATLAB functions that have thread support, see Function List (Thread-Based
Environment).
In general, functionality in “Graphics”, “App Building”, “External Language Interfaces”, “Files and
Folders”, and “Environment and Settings” is not supported.
MATLAB and several toolboxes include functions with built-in thread support. To view lists of all
functions in MATLAB and these toolboxes that have thread support, use the links in the following
table. Functions in the lists with warning indicators have limitations or usage notes specific to
running the function on threads. You can check the usage notes and limitations in the Extended
Capabilities section of the function reference page. For information about updates to individual
thread-supported functions, see the release notes.
See Also
parfeval | backgroundPool
More About
• “Run MATLAB Functions on a GPU” (Parallel Computing Toolbox)
30-7
30 Background Processing
If you want to modify an existing app that runs code in the background, see “Responsive App That
Calculates and Plots Simple Curves” on page 30-11.
• Open an existing app that does not run any code in the background.
• Modify a function to allow the app to run code in the background.
• Write a function to automatically update a plot after code finishes running in the background.
• Modify existing callbacks to allow your app to immediately respond to user interface interactions
and interrupt calculations.
openExample('matlab/PlotCurveAppExample')
Use this app as a starting point as you modify and reorganize the app code. The app has five
functions:
• getFunction — Use the value from the drop-down fcnDropDown to select a function fcn. The
custom functions available as supporting files use pause(rand) to simulate a nontrivial
calculation.
• createData — Use getFunction to get a function fcn, then use that function to compute y =
fcn(x) in iterations of a for-loop. The for-loop suspends MATLAB execution until it is finished.
• updatePlot — Update the plot represented by app.UIAxes with each y-axis data point after it is
calculated.
• clearPlot — Clear the plot.
• toggleButtons — Switch between enabling the Start button or Stop button.
30-8
Create Responsive Apps by Running Calculations in the Background
To make your app responsive, you need to store all of the Future objects the app creates. Then, you
can use cancel to stop the calculations running in the background when the user of the app clicks
the Stop button or uses the drop down fcnDropDown.
To store the Future objects the app creates, you must add a private property to your app. In the App
Designer toolstrip, click Property > Private Property, then name the property F.
properties (Access = private)
h % Line object
X % x-axis data
F % Futures for calculation
end
% Get function
fcn = app.getFunction;
% x-axis data
app.X = 5 * 1:100;
% y-axis data
for i = 1:numel(app.X)
% Run fcn(x) in the background
f(i) = parfeval(backgroundPool,fcn,1,app.X(i));
end
30-9
30 Background Processing
1 In the App Designer toolstrip, click Function > Private Function, then name the function
onFutureDone.
2 If the Future object finished with an error, immediately return from the function.
3 If the Future object did not finish with an error, use the ID property of f to find the index of the
element f in the array app.F. The index of the Future object f must match the index of the x-
axis data point.
4 Update the plot with the result from f and the matching x-axis data point by, using the index
idx.
function onFutureDone(app,f)
% Do not update the plot if there was an error
if ~isempty(f.Error)
return
end
app.clearPlot
if app.StartButton.Enable == false
app.createData
end
end
• Push the Stop button.
function StopButtonPushed(app, event)
% Stop futures
if ~isempty(app.F)
cancel(app.F)
end
app.toggleButtons
end
• Request the app to close.
function UIFigureCloseRequest(app, event)
% Stop futures
if ~isempty(app.F)
30-10
Create Responsive Apps by Running Calculations in the Background
cancel(app.F)
end
delete(app)
end
This example shows an app that calculates and plots simple curves. You can select a function to plot,
then plot that function. The app uses a for-loop to calculate the y-axis data in the background.
MATLAB does not suspend execution while calculating the data, and therefore you are able to stop
the app or update the type of plot while the data is being calculated.
Run the PlotCurveBackground app by clicking the Run button in App Designer.
See Also
parfeval | backgroundPool | appdesigner
30-11
30 Background Processing
Related Examples
• “Run Functions in Background” on page 30-13
• “Update Wait Bar While Functions Run in the Background” on page 30-14
30-12
Run Functions in Background
This example shows how to run a function in the background using parfeval and backgroundPool.
When you run a function in the background, you can run other MATLAB® code at the same time.
Use parfeval to run the function magic(3) and retrieve one output. Specify backgroundPool as
the first argument to run the function in the background. When you use parfeval, you create a
Future object.
f = parfeval(backgroundPool,@magic,1,3);
To retrieve the output from the background, use fetchOutputs. MATLAB returns the output once
the execution of magic is complete.
fetchOutputs(f)
ans = 3×3
8 1 6
3 5 7
4 9 2
See Also
parfeval | backgroundPool
Related Examples
• “Update Wait Bar While Functions Run in the Background” on page 30-14
More About
• “Run MATLAB Functions in Thread-Based Environment” on page 30-6
• “Create Responsive Apps by Running Calculations in the Background” on page 30-8
30-13
30 Background Processing
This example shows how to use afterEach to update a wait bar with the progress of functions
running in the background.
Set the number of iterations for your for-loop, N. Store the current number of completed iterations,
0, and the total number of iterations, N, in the UserData property of the wait bar.
N = ;
w.UserData = [0 N];
Run a for-loop with N iterations. In each iteration, use parfeval and backgroundPool to run
pause in the background for a random number of seconds. Store each Future object in an array.
for i = 1:N
delay = rand;
f(i) = parfeval(backgroundPool,@pause,0,delay);
end
Use the helper function updateWaitbar to update the waitbar after each Future finishes.
afterEach(f,@(~)updateWaitbar(w),0);
Use delete to close the wait bar after all the Future objects finish.
afterAll(f,@(~)delete(w),0);
Define the helper function updateWaitbar. The function increments the first element of the
UserData property, then uses the vector to calculate the progress.
function updateWaitbar(w)
% Update a waitbar using the UserData property.
30-14
Update Wait Bar While Functions Run in the Background
See Also
parfeval | backgroundPool
More About
• “Run MATLAB Functions in Thread-Based Environment” on page 30-6
• “Create Responsive Apps by Running Calculations in the Background” on page 30-8
30-15
31
Memory Usage
The numeric class you should use in MATLAB depends on your intended actions. The default class
double gives the best precision, but requires 8 bytes per element of memory to store. If you intend
to perform complicated math such as linear algebra, you must use a floating-point class such as a
double or single. The single class requires only 4 bytes. There are some limitations on what you
can do with the single class, but most MATLAB Math operations are supported.
If you just need to carry out simple arithmetic and you represent the original data as integers, you
can use the integer classes in MATLAB. The following is a list of numeric classes, memory
requirements (in bytes), and the supported operations.
MATLAB arrays (implemented internally as mxArrays) require room to store meta information about
the data in memory, such as type, dimensions, and attributes. This takes about 104 bytes per array.
This overhead only becomes an issue when you have a large number (e.g., hundreds or thousands) of
small mxArrays (e.g., scalars). The whos command lists the memory used by variables, but does not
include this overhead.
Because simple numeric arrays (comprising one mxArray) have the least overhead, you should use
them wherever possible. When data is too complex to store in a simple array (or matrix), you can use
other data structures.
Cell arrays are comprised of separate mxArrays for each element. As a result, cell arrays with many
small elements have a large overhead.
Structures require a similar amount of overhead per field. Structures with many fields and small
contents have a large overhead and should be avoided. A large array of structures with numeric
31-2
Strategies for Efficient Use of Memory
scalar fields requires much more memory than a structure with fields containing large numeric
arrays.
Also note that while MATLAB stores numeric arrays in contiguous memory, this is not the case for
structures and cell arrays. For more information, see “How MATLAB Allocates Memory” on page 31-
12.
When reading data from a binary file with fread, it is a common error to specify only the class of the
data in the file, and not the class of the data MATLAB uses once it is in the workspace. As a result, the
default double is used even if you are reading only 8-bit values. For example,
If your data contains many zeros, consider using sparse arrays, which store only nonzero elements.
The following example compares sparse and full storage requirements:
You can see that this array requires only about 24 KB to be stored as sparse, but approximately 8 MB
as a full matrix. In general, for a sparse double array with nnz nonzero elements and ncol columns,
the memory required is:
Note that MATLAB supports most, but not all, mathematical operations on sparse arrays.
31-3
31 Memory Usage
Avoid creating large temporary variables, and also make it a practice to clear temporary variables
when they are no longer needed. For example, this code creates an array of zeros stored as a
temporary variable A, and then converts A to single-precision:
A = zeros(1e6,1);
As = single(A);
A = zeros(1e6,1,'single');
Using the repmat function, array preallocation, and for loops are other ways to work on non-double
data without requiring temporary storage in memory.
When working with large data sets, be aware that MATLAB makes a temporary copy of an input
variable if the called function modifies its value. This temporarily doubles the memory required to
store the array, which causes MATLAB to generate an error if sufficient memory is not available.
One way to use less memory in this situation is to use nested functions. A nested function shares the
workspace of all outer functions, giving the nested function access to data outside of its usual scope.
In the example shown here, nested function setrowval has direct access to the workspace of the
outer function myfun, making it unnecessary to pass a copy of the variable in the function call. When
setrowval modifies the value of A, it modifies it in the workspace of the calling function. There is no
need to use additional memory to hold a separate array for the function being called, and there also is
no need to return the modified value of A:
function myfun
A = magic(500);
setrowval(400,0)
disp('The new value of A(399:401,1:10) is')
A(399:401,1:10)
function setrowval(row,value)
A(row,:) = value;
end
end
If your program generates very large amounts of data, consider writing the data to disk periodically.
After saving that portion of the data, use the clear function to remove the variable from memory and
continue with the data generation.
31-4
Strategies for Efficient Use of Memory
When you are working with a very large data set repeatedly or interactively, clear the old variable
first to make space for the new variable. Otherwise, MATLAB requires temporary storage of equal
size before overriding the variable. For example,
a = rand(1e5);
b = rand(1e5);
Out of memory.
More information
clear a
a = rand(1e5); % New array
See Also
More About
• “Resolve “Out of Memory” Errors” on page 31-6
31-5
31 Memory Usage
Issue
When your code operates on large amounts of data or does not use memory efficiently, MATLAB
might produce an error in response to an unreasonable array size, or it might run out of memory.
MATLAB has built-in protection against creating arrays that are too large. For example, this code
results in an error, because MATLAB cannot create an array with the requested number of elements.
A = rand(1e9);
By default, MATLAB can use up to 100% of the RAM (not including virtual memory) of your computer
to allocate memory for arrays, and if an array size would exceed that threshold, then MATLAB
produces an error. For example, this code attempts to create an array whose size exceeds the
maximum array size limit.
B = rand(1e6);
Requested 1000000x1000000 (7450.6GB) array exceeds maximum array size preference (63.7GB). This might cause MATLAB to bec
unresponsive.
If you turn off the array size limit in MATLAB Workspace Preferences, attempting to create an
unreasonably large array might cause MATLAB to run out of memory, or it might make MATLAB or
even your computer unresponsive due to excessive memory paging (that is, moving memory pages
between RAM and disk).
B = rand(1e6);
Out of memory.
Possible Solutions
No matter how you run into memory limits, MATLAB provides several solutions depending on your
situation and goals. For example, you can improve the way your code uses memory, leverage
specialized data structures such as datastores and tall arrays, take advantage of pooled resources
within a computing cluster, or make adjustments to your settings and preferences.
Note The solutions presented here are specific to MATLAB. To optimize system-wide memory
performance, consider adding more physical memory (RAM) to your computer or making adjustments
at the operating system level.
Make it a practice to clear variables when they are no longer needed. To clear items from memory,
use the clear function.
31-6
Resolve “Out of Memory” Errors
Before After
A = rand(1e4); A = rand(1e4);
disp(max(A,[],"all")) disp(max(A,[],"all"))
B = rand(1e4); clear A
B = rand(1e4);
For more information, see “Strategies for Efficient Use of Memory” on page 31-2.
Memory requirements differ for MATLAB data types. You might be able to reduce the amount of
memory used by your code by using the appropriate data type and storage. For more information
about the solutions in this section, see “Strategies for Efficient Use of Memory” on page 31-2.
Use the Appropriate Numeric Class
The numeric class you should use depends on your intended actions. In MATLAB, double is the
default numeric data type and provides sufficient precision for most computational tasks:
• If you want to perform complicated math such as linear algebra, use floating-point numbers in
either double-precision (double) or single-precision (single) format. Numbers of type single
require less memory than numbers of type double, but are also represented to less precision.
• If you just need to carry out simple arithmetic and you represent the original data as integers, use
the integer classes in MATLAB.
When you create a numeric or character array, MATLAB allocates a block of memory to store the
array data. MATLAB also stores information about the array data, such as its class and dimensions, in
a small, separate block of memory called a header. Because simple numeric and character arrays
have the least overhead, use them whenever possible. Use other data structures only for data that is
too complex to store in a simple array.
For structures and cell arrays, MATLAB creates a header not only for the array, but also for each field
of the structure or each cell of the cell array. Therefore, the amount of memory required to store a
structure or cell array depends not only on how much data it holds, but also on how it is constructed.
As a result, cell arrays with many small elements or structures with many fields containing little
content have large overhead and should be avoided.
31-7
31 Memory Usage
Before After
% S has 15,000 fields (3 fields per array element)
% S has 3 fields
for i = 1:100 S.R = zeros(100,50); % Each field contains a numeric
for j = 1:50 S.G = zeros(100,50);
S(i,j).R = 0; % Each field containsS.B
a numeric
= zeros(100,50);
scalar
S(i,j).G = 0;
S(i,j).B = 0;
end
end
A good practice is to store matrices with few nonzero elements using sparse storage. When a full
matrix has a small number of nonzero elements, converting the matrix to sparse storage typically
improves memory usage and code execution time. MATLAB has several functions that support sparse
storage. For example, you can use the speye function to create a sparse identity matrix.
Before After
I = eye(1000); I = speye(1000);
When reading data from a binary file with fread, a common mistake is to specify only the class of the
data in the file and not the class of the data MATLAB uses once it is in the workspace. If you do not
specify the class of the data in memory, MATLAB uses double even if you read 8-bit values.
Before After
fileID = fopen("large_file_of_uint8s.bin","r");
fileID = fopen("large_file_of_uint8s.bin","r");
A = fread(fileID,1e3,"uint8"); A = fread(fileID,1e3,"uint8=>uint8");
To improve memory usage and execution speed, make sure your code does not result in unnecessary
copies of data. For more information about the solutions in this section, see “Avoid Unnecessary
Copies of Data” on page 31-15 and “Strategies for Efficient Use of Memory” on page 31-2.
Avoid Creating Temporary Arrays
Avoid creating temporary arrays when they are not necessary. For example, instead of creating an
array of zeros as a temporary variable and then passing that variable to a function, use one command
to do both operations.
Before After
A = zeros(1e6,1); As = zeros(1e6,1,"single");
As = single(A);
Preallocate Memory
When you work with large data sets, repeatedly resizing arrays might cause your program to run out
of memory. If you expand an array beyond the available contiguous memory of its original location,
MATLAB must make a copy of the array and move the copy into a memory block with sufficient space.
During this process, two copies of the original array exist in memory. You can improve the memory
usage and code execution time by preallocating the maximum amount of space required for the array.
For more information, see “Preallocation” on page 29-14.
31-8
Resolve “Out of Memory” Errors
Before After
x = 0; x = zeros(1,1000000);
for k = 2:1000000 for k = 2:1000000
x(k) = x(k-1) + 5; x(k) = x(k-1) + 5;
end end
When calling a function, MATLAB typically makes a temporary copy of the variable in the caller's
workspace if the function modifies its value. MATLAB applies various techniques to avoid making
unnecessary copies, but avoiding a temporary copy of an input variable is not always possible.
One way to avoid temporary copies in function calls is to use nested functions. A nested function
shares the workspace of all outer functions, so you do not need to pass a copy of variables in the
function call. For more information, see “Nested Functions” on page 20-10.
One way to fix memory issues is to import into MATLAB only as much of a large data set as you need
for the problem you are trying to solve. Data set size is not usually a problem when importing from
sources such as a database, where you can explicitly search for elements matching a query. But it is a
common problem with loading large flat text or binary files.
The datastore function lets you work with large data sets incrementally. Datastores are useful any
time you want to load only some portions of a data set into memory at a time.
To create a datastore, provide the name of a file or a directory containing a collection of files with
similar formatting. For example, with a single file, use the following.
ds = datastore("path/to/file.csv");
ds = datastore("path/to/folder/");
You also can use the wildcard character * to select all files of a specific type.
ds = datastore("path/to/*.csv");
Datastores support a wide variety of file formats (tabular data, images, spreadsheets, and so on). For
more information, see “Select Datastore for File Format or Application”.
Aside from datastores, MATLAB also has several other functions to load parts of files. This table
summarizes the functions by the type of files they operate on.
31-9
31 Memory Usage
Tall arrays help you work with data sets that are too large to fit in memory. MATLAB works with small
blocks of the data at a time, automatically handling all of the data chunking and processing in the
background. You can use tall arrays in two primary ways:
• If you have a large array that fits in memory, but you run out of memory when you try to perform
calculations, you can cast the array to a tall array.
t = tall(A);
This approach lets you work with large arrays that can fit in memory, but that consume too much
memory to allow for copies of the data during calculations. For example, if you have 8 GB of RAM
and a 5 GB matrix, casting the matrix to a tall array enables you to perform calculations on the
matrix without running out of memory. For an example of this usage, see tall.
• If you have file- or folder-based data, you can create a datastore and then create a tall array on top
of the datastore.
ds = datastore("path/to/file.csv");
t = tall(ds);
This approach gives you the full power of tall arrays in MATLAB. The data can have any number of
rows and MATLAB does not run out of memory. And because datastore works with both local
and remote data locations, the data you work with does not need to be on the computer you use to
analyze it. See “Work with Remote Data” for more information.
To learn more about tall arrays, see “Tall Arrays for Out-of-Memory Data”.
If you have a cluster of computers, you can use distributed arrays (requires Parallel Computing
Toolbox) to perform calculations using the combined memory of all the machines in the cluster.
Depending on how your data fits in memory, different ways to partition data among workers of a
parallel pool exist. For more information, see “Distributing Arrays to Parallel Workers” (Parallel
Computing Toolbox).
31-10
Resolve “Out of Memory” Errors
Generally, rewriting code is the most effective way to improve memory performance. However, if you
cannot make changes to your code, these solutions might provide it with the required amount of
memory.
Start MATLAB Without Java Virtual Machine or Decrease the Java Heap Size
If you either start MATLAB without the Java Virtual Machine (JVM®) software or decrease the Java
heap size, you can increase the available workspace memory. To start MATLAB without JVM, use the
command-line option -nojvm. For information on how to decrease the Java heap size, see “Java Heap
Memory Preferences”.
Using -nojvm comes with a penalty in that you lose several features that rely on JVM, such as the
desktop tools and graphics. Starting MATLAB with the -nodesktop option does not save any
substantial amount of memory.
Adjust the Array Size Limit
If you face an error stating that the array size exceeds the maximum array size preference, you can
adjust this array size limit in MATLAB. For information on adjusting the array size limit, see
“Workspace and Variable Preferences”. This solution is helpful only if the array you want to create
exceeds the current maximum array size limit but is not too large to fit in memory. Even if you turn
off the array size limit, attempting to create an unreasonably large array might cause MATLAB to run
out of memory, or it might make MATLAB or even your computer unresponsive due to excessive
memory paging.
See Also
memory | whos | datastore | tall
Related Examples
• “How MATLAB Allocates Memory” on page 31-12
• “Strategies for Efficient Use of Memory” on page 31-2
• “Avoid Unnecessary Copies of Data” on page 31-15
• “Large Files and Big Data”
31-11
31 Memory Usage
This topic provides information on how MATLAB® allocates memory when working with variables.
This information, like any information on how MATLAB treats data internally, is subject to change in
future releases.
When you assign a numeric or character array to a variable, MATLAB allocates a contiguous block of
memory and stores the array data in that block. MATLAB also stores information about the array
data, such as its class and dimensions, in a small, separate block of memory called a header. For most
arrays, the memory required to store the header is insignificant. However, there could be some
advantage to storing large data sets in a small number of large arrays as opposed to a large number
of small arrays. This is because fewer arrays require fewer array headers.
If you add new elements to an existing array, MATLAB expands the array in memory in a way that
keeps its storage contiguous. This usually requires finding a new block of memory large enough to
hold the expanded array. MATLAB then copies the contents of the array from its original location to
this new block in memory, adds the new elements to the array in this block, and frees up the original
array location in memory.
If you remove elements from an existing array, MATLAB keeps the memory storage contiguous by
removing the deleted elements, and then compacting its storage in the original memory location.
Copying Arrays
When you assign an array to a second variable (for instance, when you execute B = A), MATLAB
does not allocate new memory right away. Instead, it creates a copy of the array reference. As long as
you do not modify the contents of the memory block being referenced by A and B, there is no need to
store more than one copy of data. However, if you modify any elements of the memory block using
either A or B, MATLAB allocates new memory, copies the data into it, and then modifies the created
copy.
Function Arguments
MATLAB handles arguments passed in function calls in the same way that it handles arrays being
copied. When you pass a variable to a function, you actually pass a reference to the data that the
variable represents. As long as the data is not modified by the called function, the variable in the
calling function or script and the variable in the called function point to the same location in memory.
If the called function modifies the value of the input data, then MATLAB makes a copy of the original
variable in a new location in memory, updates that copy with the modified value, and points the input
argument in the called function to this new location.
For example, consider the function myfun, which modifies the value of the array passed to it.
MATLAB makes a copy of A in a new location in memory, sets the variable X as a reference to this
copy, and then sets one row of X to zero. The array referenced by A remains unchanged.
A = magic(5);
myfun(A)
function myfun(X)
X(4,:) = 0;
disp(X)
end
31-12
How MATLAB Allocates Memory
If the calling function or script needs the modified value of the array it passed to myfun, you need to
return the updated array as an output of the called function.
Memory requirements differ for MATLAB data types. You might be able to reduce the amount of
memory used by your code by learning how MATLAB treats various data types.
Numeric Arrays
MATLAB allocates 1, 2, 4, or 8 bytes to 8-bit, 16-bit, 32-bit, and 64-bit signed and unsigned integers,
respectively. It represents floating-point numbers in either double-precision (double) or single-
precision (single) format. Because MATLAB stores numbers of type single using 4 bytes, they
require less memory than numbers of type double, which use 8 bytes. However, because they are
stored with fewer bits, numbers of type single are represented to less precision than numbers of
type double. In MATLAB, double is the default numeric data type and provides sufficient precision
for most computational tasks. For more information, see “Floating-Point Numbers” on page 4-7.
While numeric arrays must be stored in a contiguous block of memory, structures and cell arrays can
be stored in noncontiguous blocks. For structures and cell arrays, MATLAB creates a header not only
for the array, but also for each field of the structure or each cell of the cell array. Therefore, the
amount of memory required to store a structure or cell array depends not only on how much data it
holds, but also on how it is constructed.
For example, consider a scalar structure S1 with fields R, G, and B, where each field contains a 100-
by-50 array. S1 requires one header to describe the overall structure, one header for each unique
field name, and one header for each field. This makes a total of seven headers for the entire
structure.
S1.R = zeros(100,50);
S1.G = zeros(100,50);
S1.B = zeros(100,50);
On the other hand, consider a 100-by-50 structure array S2 in which each element has scalar fields R,
G, and B. In this case, S2 needs one header to describe the overall structure, one header for each
unique field name, and one header for each field of the 5,000 elements, making a total of 15,004
array headers for the entire structure array.
for i = 1:100
for j=1:50
S2(i,j).R = 0;
S2(i,j).G = 0;
S2(i,j).B = 0;
end
end
Use the whos function to compare the amount of memory allocated to S1 and S2 on a 64-bit system.
Even though S1 and S2 hold the same data, S1 uses significantly less memory.
whos S1 S2
31-13
31 Memory Usage
Complex Arrays
MATLAB uses an interleaved storage representation of complex numbers, where the real and
imaginary parts are stored together in a contiguous block of memory. If you make a copy of a complex
array, and then modify only the real or imaginary part of the array, MATLAB creates an array
containing both real and imaginary parts. For more information about the representation of complex
numbers in memory, see “MATLAB Support for Interleaved Complex API in MEX Functions”.
Sparse Matrices
It is a good practice to store matrices with few nonzero elements using sparse storage. When a full
matrix has a small number of nonzero elements, converting the matrix to sparse storage typically
improves memory usage and code execution time. You can convert a full matrix to sparse storage
using the sparse function.
For example, let matrix A be a 1,000-by-1,000 full storage identity matrix. Create B as a sparse copy
of A. In sparse storage, the same data uses a significantly smaller amount of memory.
A = eye(1000);
B = sparse(A);
whos A B
When you work with large data sets, repeatedly resizing arrays might cause your program to run out
of memory. If you expand an array beyond the available contiguous memory of its original location,
MATLAB must make a copy of the array and move the copy into a memory block with sufficient space.
During this process, there are two copies of the original array in memory. This temporarily doubles
the amount of memory required for the array and increases the risk of your program running out of
memory. You can improve the memory usage and code execution time by preallocating the maximum
amount of space required for the array. For more information, see “Preallocation” on page 29-14.
See Also
memory | whos
Related Examples
• “Strategies for Efficient Use of Memory” on page 31-2
• “Resolve “Out of Memory” Errors” on page 31-6
• “Avoid Unnecessary Copies of Data” on page 31-15
31-14
Avoid Unnecessary Copies of Data
MATLAB does not provide a way to define a reference to a value, as in languages like C++. Instead,
MATLAB allows multiple output as well as multiple input parameters so that you know what values
are going into a function and what values are coming out of the function.
Copy-on-Write
If a function does not modify an input argument, MATLAB does not make a copy of the values
contained in the input variable.
A = rand(1e7,1);
B = f1(A);
The function f1 multiplies each element in the input array X by 1.1 and assigns the result to the
variable Y.
function Y = f1(X)
Y = X.*1.1; % X is a shared copy of A
end
Because the function does not modify the input values, the local variable X and the variable A in the
caller's workspace share the data. After f1 executes, the values assigned to A have not changed. The
variable B in the caller's workspace contains the result of the element-wise multiplication. The input
is passed by value. However, no copy is made when calling f1.
The function f2 does modify its local copy of the input variable, causing the local copy to be unshared
with input A. The value of X in the function is now an independent copy of the input variable A in the
caller's workspace. When f2 returns the result to the caller's workspace, the local variable X is
destroyed.
A = rand(1e7,1);
B = f2(A);
function Y = f2(X)
X = X.*1.1; % X is an independent copy of A
Y = X; % Y is a shared copy of X
end
31-15
31 Memory Usage
You can use the value returned from a function as an input argument to another function. For
example, use the rand function to create the input for the function f2 directly.
B = f2(rand(1e7,1));
The only variable holding the value returned by rand is the temporary variable X in the workspace of
the function f2. There is no shared or independent copy of these values in the caller's workspace.
Directly passing function outputs saves the time and memory required to create a copy of the input
values in the called function. This approach makes sense when the input values are not used again.
Assigning In-Place
When you do not need to preserve the original input values, you can assign the output of a function to
the same variable that you provided as input.
A = f2(A);
In-place assignment follows the copy-on-write behavior described previously: modifying the input
variable values results in a temporary copy of those values.
MATLAB can apply memory optimizations under certain conditions. Consider the following example.
The canBeOptimized function creates a large array of random numbers in the variable A. Then it
calls the local function fLocal, passing A as the input, and assigning the output of the local function
to the same variable name.
function canBeOptimized
A = rand(1e7,1);
A = fLocal(A);
end
function X = fLocal(X)
X = X.*1.1;
end
Because the call to the local function, A = fLocal(A), assigns the output to the variable A, MATLAB
does not need to preserve the original value of A during execution of the function. Modifications made
to X inside fLocal do not result in a copy of the data. The assignment X = X.*1.1 modifies X in
place, without allocating a new array for the result of the multiplication. Eliminating the copy in the
local function saves memory and improves execution speed for large arrays.
However, MATLAB cannot apply this optimization if the assignment in the local function requires
array indexing. For example, modifying the cell array created in updateCells requires indexing into
X in the local function gLocal. For every loop iteration i, the looped assignment in the form X{i} =
X{i}*1.1 results in a temporary variable the same size as X{i} for evaluating and storing the value
of X{i}*1.1. MATLAB destroys the temporary variable after assigning its value to X{i}.
function updateCells
C = num2cell(rand(1e7,1));
C = gLocal(C);
end
function X = gLocal(X)
for i = 1:length(X)
X{i} = X{i}*1.1;
end
end
31-16
Avoid Unnecessary Copies of Data
Several additional restrictions apply. MATLAB cannot apply memory optimization when it is possible
to use the variable after the function throws an error. Therefore, this optimization is not applied in
scripts, on the command line, in calls to eval, or to code inside try/catch blocks. Also, MATLAB
does not apply memory optimization when the original variable is directly accessible during execution
of the called function. For example, if fLocal was a nested function, MATLAB could not apply the
optimization because variables can be shared with the parent function. Finally, MATLAB does not
apply memory optimization when the assigned variable is declared as global or persistent.
When MATLAB applies in-place optimization to an assignment statement, the variable on the left side
of the assignment is set to a temporary state that makes it inaccessible before MATLAB executes the
right side of the assignment statement. If MATLAB stops in the debugger before the result of
executing the right-side of the statement has been assigned to the variable, examining the left-side
variable can produce an error indicating that the variable is unavailable.
For example, this function has a mismatch in the dimensions of variables A and B.
function A = inPlace
A = rand(100);
B = rand(99);
dbstop if error
A = A.*B;
end
inPlace
Attempting to see the value of the variable A while in debug mode results in an error because the
variable is temporarily unavailable.
K>> A
To gain more flexibility when debugging, refactor your code to remove the in-place assignment. For
example, assign the result to another variable.
function A = inPlace
A = rand(100);
B = rand(99);
dbstop if error
% Assign result to C instead of A
C = A.*B;
A = C;
end
31-17
31 Memory Usage
When calling functions, you know that the input variables are not modified in the caller's workspace.
Therefore, you do not need to make copies of inputs inside a function or at a call site just to guard
against the possibility that these values might be modified. Only the variables assigned to returned
values are modified.
Also, you avoid the possibility of corrupting workspace variables if an error occurs within a function
that has been passed a variable by reference.
Handle Objects
There are special kinds of objects called handles. All variables that hold copies of the same handle
can access and modify the same underlying object. Handle objects are useful in specialized
circumstances where an object represents a physical object such as a window, plot, device, or person
rather than a mathematical object like a number or matrix.
Handle objects derive from the handle class, which provides functionality such as events and
listeners, destructor methods, and support for dynamic properties.
For more information about values and handles, see “Comparison of Handle and Value Classes” and
“Which Kind of Class to Use”.
See Also
handle
Related Examples
• “Handle Object Behavior”
• “Avoid Copies of Arrays in MEX Functions”
• “Strategies for Efficient Use of Memory” on page 31-2
31-18
32
For example, create a class definition file named someClass.m with several properties and methods,
as shown.
classdef someClass
% someClass Summary of this class goes here
% Detailed explanation goes here
properties
One % First public property
Two % Second public property
end
properties (Access=private)
Three % Do not show this property
end
methods
function obj = someClass
% Summary of constructor
end
function myMethod(obj)
% Summary of myMethod
disp(obj)
end
end
methods (Static)
function myStaticMethod
% Summary of myStaticMethod
end
end
end
View the help text and the details from the class definition using the doc command.
doc someClass
32-2
Create Help for Classes
Classes
Create help text for classes by including comments on lines immediately after the classdef
statement in a file. For example, create a file named myClass.m, as shown.
classdef myClass
% myClass Summary of myClass
% This is the first line of the description of myClass.
% Descriptions can include multiple lines of text.
%
% myClass Properties:
% a - Description of a
% b - Description of b
%
% myClass Methods:
32-3
32 Custom Help and Documentation
properties
a
b
end
methods
function obj = myClass
end
function doThis(obj)
end
function doThat(obj)
end
end
end
Lists and descriptions of the properties and methods in the initial comment block are optional. If you
include comment lines containing the class name followed by Properties or Methods and a colon
(:), then MATLAB creates hyperlinks to the help for the properties or methods.
View the help text for the class in the Command Window using the help command.
help myClass
myClass Properties:
a - Description of a
b - Description of b
myClass Methods:
doThis - Description of doThis
doThat - Description of doThat
Methods
Create help for a method by inserting comments immediately after the function definition statement.
For example, modify the class definition file myClass.m to include help for the doThis method.
function doThis(obj)
% doThis Do this thing
% Here is some help text for the doThis method.
%
% See also DOTHAT.
disp(obj)
end
View the help text for the method in the Command Window using the help command. Specify both
the class name and method name, separated by a dot.
help myClass.doThis
32-4
Create Help for Classes
Properties
• Insert comment lines above the property definition. Use this approach for multiline help text.
• Add a single-line comment next to the property definition.
Comments above the definition have precedence over a comment next to the definition.
For example, modify the property definitions in the class definition file myClass.m.
properties
a % First property of myClass
View the help for properties in the Command Window using the help command. Specify both the
class name and property name, separated by a dot.
help myClass.a
help myClass.b
Enumerations
Like properties, there are two ways to create help for enumerations:
• Insert comment lines above the enumeration definition. Use this approach for multiline help text.
• Add a single-line comment next to the enumeration definition.
Comments above the definition have precedence over a comment next to the definition.
classdef myEnumeration
enumeration
uno, % First enumeration
32-5
32 Custom Help and Documentation
end
end
View the help in the Command Window using the help command. Specify both the class name and
enumeration member, separated by a dot.
help myEnumeration.uno
help myEnumeration.dos
Events
Like properties and enumerations, there are two ways to create help for events:
• Insert comment lines above the event definition. Use this approach for multiline help text.
• Add a single-line comment next to the event definition.
Comments above the definition have precedence over a comment next to the definition.
methods
function fireEventAlpha(h)
notify(h,'Alpha')
end
function fireEventBeta(h)
notify(h,'Beta')
end
end
end
View the help in the Command Window using the help command. Specify both the class name and
event, separated by a dot.
help hasEvents.Alpha
help hasEvents.Beta
32-6
Create Help for Classes
See Also
help | doc
More About
• “Role of Classes in MATLAB”
• “User-Defined Classes”
32-7
32 Custom Help and Documentation
Contents.m files contain only comment lines. The first two lines are headers that describe the folder.
Subsequent lines list the program files in the folder, along with their descriptions. Optionally, you can
group files and include category descriptions. For example, view the functions available in the
codetools folder:
help codetools
Directory tools
visdiff - Compare two files (text, MAT, or binary) or folders
...
If no Contents.m file exists in a folder, the help and doc functions display a generated list of all
program files in the folder. For example, the folder myfiles contains five program files and no
Contents.m file. When you call the help function on the folder, it displays the list of program files in
the folder and a brief description for each one.
help myfiles
Contents of myfiles:
If you do not want the help and doc functions to display the generated list, place an empty
Contents.m file in the folder. If a folder contains an empty Contents.m file, the help and doc
functions display foldername is a folder. If there is another folder with the same name, the
help and doc functions display the information for that folder instead.
1 In the folder that contains your program files, create a file named Contents.m.
2 Copy this template into the Contents.m file.
% Folder summary
% Version xxx dd-mmm-yyyy
%
% Description of first group of files
% file1 - file1 description
% file2 - file2 description
32-8
Create Help Summary Files — Contents.m
%
% Description of second group of files
% file3 - file3 description
% file4 - file4 description
3 Modify the template to match the contents of your folder. When modifying the template, do not
include any spaces in the date field in the second comment line.
For example, this Contents.m file describes the contents of the myfiles folder.
% Folder containing my program files
% Version 1.2.0 09-Nov-2022
%
% My Functions
% estimatePanelOutput - Calculate solar time
% lengthofline - Calculate the length of a line object
% solarCorrection - Calculate the difference between local and solar time
%
% My Live Scripts
% SolarPanelEstimatorForm - Estimate solar panel output
% WeatherDashboard - Display weather data for Natick, MA
4 Optionally, you can include See also links in the Contents.m file. To include See also links,
add a line at the end of the file that begins with % See also followed by a list of function
names. If the functions exist on the search path or in the current folder, the help and doc
functions display each of these function names as a hyperlink to its help. Otherwise, the help
and doc functions print the function names as they appear in the Contents.m file.
For example, this code adds See also links to the files myfile1.m and myfile2.m, which are
on the path.
%
% See also MYFILE1, MYFILE2
You also can include hyperlinks (in the form of URLs) to websites in your help text. Create
hyperlinks by including an HTML <a></a> anchor element. Within the anchor, use a matlab:
statement to execute a web command.
Once you have created your Contents.m file, use the help and doc functions to display the contents
of your folder. For example, display the contents of the myfiles folder.
help myfiles
My Functions
estimatePanelOutput - Calculate solar time
lengthofline - Calculate the length of a line object
solarCorrection - Calculate the difference between local and solar time
My Live Scripts
SolarPanelEstimatorForm - Estimate solar panel output
WeatherDashboard - Display weather data for Natick, MA
See Also
doc | help | ver
32-9
32 Custom Help and Documentation
More About
• “Add Help for Your Program” on page 20-5
• “Add Help for Live Functions” on page 19-57
• “Display Custom Documentation” on page 32-20
32-10
Customize Code Suggestions and Completions
The functionSignatures.json file contains a single JSON object. JSON uses braces to define
objects, and refers to objects as collections of name and value pairs. Since these terms are
overloaded in the context of function signatures, "property" is used instead of "name." The JSON
object in functionSignatures.json contains an optional schema version and a list of function
objects. Each function object contains a list of signature objects, and each signature object contains
an array of argument objects. JSON uses brackets to define arrays.
32-11
32 Custom Help and Documentation
To specify the optional schema version use _schemaVersion as the first property and the version
number as its value. Specify the version number as a JSON string in the format
major#.minor#.patch#, with each number specified as a nonnegative integer. The current schema
version is 1.0.0. If the file does not specify a schema version, MATLAB assumes version 1.0.0.
Function Objects
To define information for a function, create a property that is the same as the function name. Its value
is a signature object on page 32-12.
{
"functionName1": { signatureObj1 },
"functionName2": { signatureObj2 }
}
To define information for a class constructor, class method, or namespace function, use the full name
of the function or method. For example, define a class constructor, class method myMethod, and a
namespace function myFunction.
{
"myClass.myClass": { signatureObj },
"myClass.myMethod": { signatureObj },
"myNamespace.myFunction": { signatureObj }
}
You can define multiple function signatures for the same function or method by defining multiple
function objects with the same property (function or method name). For more information, see
“Multiple Signatures” on page 32-18.
Signature Objects
A signature object defines the input and output arguments and supported platforms for the function.
The value of each property, except for the platforms property, is an array of argument objects on
page 32-13.
{
"functionName1":
{
"inputs": [ argumentObj1, argumentObj2 ]
}
}
If you specify an instance method such as myClass.myMethod in the JSON file, one of the elements
in inputs must be an object of myClass. Typically, this object is the first element. MATLAB supports
code suggestions and completions for a specified method when you call it using either dot notation (b
= myObj.myMethod(a)) or function notation (b = myMethod(myObj,a)) syntax.
Each signature in the JSON file can include the following properties.
32-12
Customize Code Suggestions and Completions
Argument Objects
Argument objects define the information for each of the input and output arguments.
{
"functionName1":
{
"inputs":
[
{"name":"in1", "kind":"required", "type":["numeric"]},
{"name":"in2", "kind":"required", "type":["numeric","integer","scalar"]}
]
}
}
The order that the inputs appear in the JSON file is significant. For example, in a call to the
functionName1 function, in1 must appear before in2.
The name of the input or output argument, specified as a JSON string. This property and value is
required. The name property does not need to match the argument name in the source code, but it is
a best practice for it to match any help or documentation.
Example: "name":"myArgumentName"
The kind of argument, specified as a JSON string with one of the following values. MATLAB uses the
value of the kind property to determine if and when to display the arguments within the function
signature.
Value Description
required Argument is required, and its location is relative to other required arguments in
the signature object.
32-13
32 Custom Help and Documentation
Value Description
ordered Argument is optional, and its location is relative to the required and preceding
optional arguments in the signature object.
namevalue Argument is an optional name-value argument. Name-value arguments occur at
the end of a function signature, but can be specified in any order.
Arguments that are required and ordered appear first in the function signature, and are followed
by any namevalue arguments.
required, ordered, and namevalue arguments are most common. You can also specify the
following values for kind.
• positional – Argument is optional if it occurs at the end of the argument list, but becomes
required to specify a subsequent positional argument. Any positional arguments must appear
with the required and ordered arguments, before any namevalue arguments.
• flag – Argument is an optional, constant string, typically used as a switch. For example,
'ascend' or 'descend'. Flags occur at the end of a function signature. All flag arguments
must appear before any namevalue arguments.
• properties – Argument is optional and is used to specify public, settable properties of a different
MATLAB class. Indicate the class using the argument object type property. In code suggestions,
these properties appear as name-value arguments. Any properties arguments must be the last
argument in the signature.
Class or attributes of the argument, specified as a JSON string, list, or list of lists.
The type property can define what class the argument is and what attributes the argument must
have.
• To match one class or attribute, use a single JSON string. For example, if an argument must be
numeric, then specify "type":"numeric".
• To match all classes or attributes, use a list of JSON strings. For example, if an argument must be
both numeric and positive, then specify "type":["numeric", ">=0"].
• To match any of multiple classes or attributes, use a list of lists of JSON strings. For the inner lists,
MATLAB uses a logical AND of the values. For the outer list, MATLAB uses a logical OR of the
values. For example, if an argument must be either a positive number or a containers.Map
object, then specify "type":[["numeric", ">=0"],["containers.Map"]].
32-14
Customize Code Suggestions and Completions
expression can refer by name to other input arguments that appear in the
argument list. Since expression is evaluated at run time, allowable choices
can vary dynamically with the value of other input arguments.
"file=*.ext,..." Must be a string or character vector that names an existing file with the
specified extension. File names are relative to the current working folder.
For example, to allow all .m and .mlx files in the current folder, use
"file=*.m,*.mlx". To match all files in the current folder, use "file".
"folder" Must be a string or character vector that is the name of an existing folder
relative to the current working folder.
"matlabpathfile=*. Must be a string or character vector that names an existing file on the
ext,..." MATLAB path. This value requires at least one file extension. For example,
to allow all .mat files on the path, use "matlabpathfile=*.mat".
"size=size1,size2, Must match size constraints. This value requires two or more dimensions.
…,sizeN" Each size dimension must be either a positive integer that indicates the
allowable size of the dimension, or a colon to allow any size. For example,
"size=2,:,2" constrains the argument to have a size of 2 in the 1st and
3rd dimensions.
"numel=integerValu Must have a specified number of elements.
e"
"nrows=integerValu Must have a specified number of rows.
e"
"ncols=integerValu Must have a specified number of columns.
e"
"numeric" Must be numeric. A numeric value is one for which the isa function with
the 'numeric' class category returns true.
"logical" Must be numeric or logical.
"real" Must be a real-valued numeric or a character or logical value.
"scalar" Must be scalar.
"integer" Must be an integer of type double.
"square" Must be a square matrix.
"vector" Must be a column or row vector.
"column" Must be a column vector.
"row" Must be a row vector.
"2d" Must be 2-dimensional.
"3d" Must have no more than three dimensions.
"sparse" Must be sparse.
"positive" Must be greater than zero.
32-15
32 Custom Help and Documentation
"<expression"
"<=expression"
@(args) expression Must satisfy the function handle. For a value to satisfy the function handle,
the handle must evaluate to true.
Indicator that an argument can be specified multiple times, specified as a JSON true or false
(without quotes). The default is false. If specified as true, the argument or set of arguments (tuple)
can be specified multiple times. A required repeating argument must appear one or more times, and
an optional repeating argument can appear zero or more times.
Example: "repeating":true
Description of argument, specified as a JSON string. Use this property to communicate the purpose of
the argument.
For more complicated function signatures, the following properties are available for each argument
object.
List of platforms that support the argument, specified as a JSON string. The default is all platforms.
Elements of the list must match an archstr returned from the computer function. The list can be
inclusive or exclusive, but not both.
Definition of a set of arguments that must always appear together, specified as a list of argument
objects. This property is only used to define sets of multiple repeating arguments. For these function
signatures, define tuples and set the repeating property to true.
Definition of a set of sets of arguments that cannot be used together, specified as a list of argument
objects. This property is used to provide information about functions with multiple function
signatures. However, typically it is easier to define multiple function signatures using multiple
function objects. For more information, see “Multiple Signatures” on page 32-18.
32-16
Customize Code Suggestions and Completions
Create a function whose signature you will describe in a JSON file in later steps. The following
function accepts:
myFunc is presented to demonstrate code suggestions and does not include argument checking.
% myFunc Example function
% This function is called with any of these syntaxes:
%
% myFunc(in1, in2) accepts 2 required arguments.
% myFunc(in1, in2, in3) also accepts an optional 3rd argument.
% myFunc(___, NAME, VALUE) accepts one or more of the following name-value
% arguments. This syntax can be used in any of the previous syntaxes.
% * 'NAME1' with logical value
% * 'NAME2' with 'Default', 'Choice1', or 'Choice2'
function myFunc(reqA,reqB,varargin)
% Initialize default values
NV1 = true;
NV2 = 'Default';
posA = [];
if nargin > 3
if rem(nargin,2)
posA = varargin{1};
V = varargin(2:end);
else
V = varargin;
end
for n = 1:2:size(V,2)
switch V{n}
case 'Name1'
NV1 = V{n+1};
case 'Name2'
NV2 = V{n+1}
otherwise
error('Error.')
end
end
end
end
In a resources folder in the same folder as myFunc, create the following function signature
description in a file called functionSignatures.json. The input names do not match the names in
the body of myFunc, but are consistent with the help text.
{
"_schemaVersion": "1.0.0",
"myFunc":
{
"inputs":
[
{"name":"in1", "kind":"required", "type":["numeric"], "purpose":"ID of item"},
{"name":"in2", "kind":"required", "type":["numeric"], "purpose":"# Items"},
{"name":"in3", "kind":"ordered", "type":["numeric"], "purpose":"Input Value"},
{"name":"Name1", "kind":"namevalue", "type":["logical","scalar"],"purpose":"Option"},
{"name":"Name2", "kind":"namevalue", "type":["char", "choices={'Default','Choice1','Choice2'}"]}
]
}
}
32-17
32 Custom Help and Documentation
MATLAB uses this function signature description to inform code suggestions and completion.
To experiment with code suggestions, start to call myFunc from a script or live script. The names and
purposes from the JSON file appear. MATLAB indicates when arguments are optional and if there are
multiple suggestions available (such as the third positional argument or a name-value argument).
Name-value argument options are listed.
When adding a name-value argument to the function call, MATLAB presents the choices from the
JSON file. Since 'Name1' is defined as a logical scalar, MATLAB populates the choices automatically
(true or false). MATLAB takes the three values for the 'Name2' argument from the JSON file.
Multiple Signatures
If a function has many syntaxes, it can be helpful for code suggestions to group syntaxes as multiple
function signatures (regardless of the implementation of the function). To provide code suggestions
and completions for multiple signatures, create multiple function objects with the same property in
the JSON file.
Consider the following function that follows different code paths depending on the class of the second
input. This function is presented as an example for code suggestions, and, therefore, does not
perform any computations or error checking.
function anotherFunc(arg1,arg2,arg3)
switch class(arg2)
case 'double'
% Follow code path 1
case {'char','string'}
% Follow code path 2
32-18
Customize Code Suggestions and Completions
otherwise
error('Invalid syntax.')
end
end
From a code suggestions perspective, consider the function as having two function signatures. The
first signature accepts two required numeric values. The second signature accepts a required
numeric, followed by a character or string, and finally a required numeric. To define multiple function
signatures, define multiple function objects in the JSON file with the same property (function name).
{
"_schemaVersion": "1.0.0",
"anotherFunc":
{
"inputs":
[
{"name":"input1", "kind":"required", "type":["numeric"]},
{"name":"input2", "kind":"required", "type":["numeric"]}
]
},
"anotherFunc":
{
"inputs":
[
{"name":"input1", "kind":"required", "type":["numeric"]},
{"name":"input2", "kind":"required", "type":[["char"],["string"]]},
{"name":"input3", "kind":"required", "type":["numeric"]}
]
}
}
Alternatively, you can define multiple function signatures using the mutuallyExclusiveGroup
property of the argument object. Typically, it is easier and more readable to implement multiple
function objects, but using mutually exclusive groups enables reuse of common argument objects,
such as input1.
{
"_schemaVersion": "1.0.0",
"anotherFunc":
{
"inputs":
[
{"name":"input1", "kind":"required", "type":["numeric"]},
{"mutuallyExclusiveGroup":
[
[
{"name":"input2", "kind":"required", "type":["numeric"]}
],
[
{"name":"input2", "kind":"required", "type":[["char"],["string"]]},
{"name":"input3", "kind":"required", "type":["numeric"]}
]
]
}
]
}
}
See Also
validateFunctionSignaturesJSON
More About
• “Check Syntax and Autocomplete Code as You Type”
External Websites
• https://www.json.org/
32-19
32 Custom Help and Documentation
Overview
If you create a toolbox that works with MathWorks products, even if it only contains a few functions,
you can include custom documentation in the form of HTML help files. Custom documentation for
your toolbox can include figures, diagrams, screen captures, equations, and formatting to make your
toolbox help more usable.
• HTML help files — These files contain your custom documentation information.
• info.xml file — This file enables MATLAB to find and identify your HTML help files.
• helptoc.xml file — This file contains the Table of Contents for your documentation that displays
in the Contents pane of the MathWorks documentation home page. This file must be stored in the
folder that contains your HTML help files.
• Search database (optional) — These files enable searching in your HTML help files.
To view your custom documentation, open your system web browser and navigate to the MathWorks
documentation home page. On the left side of the home page, click Supplemental Software.
Then, click the name of your toolbox. Your documentation opens in the current tab of your system
browser.
32-20
Display Custom Documentation
• Create a live script (*.mlx) and export it to HTML. For more information, see “Ways to Share and
Export Live Scripts and Functions” on page 19-62.
• Create a script (*.m), and publish it to HTML. For more information, see “Publish and Share
MATLAB Code” on page 23-2.
Store all your HTML help files for your toolbox and any additional custom documentation files
referenced by your HTML help files (such as PNG, CSS, and JS files) in one folder, for example, an
html subfolder in your toolbox folder.
• A roadmap page (that is, an initial landing page for the documentation)
• Examples and topics that explain how to use the toolbox
• Function or block reference pages
To create info.xml to describe your toolbox, you can adapt this template:
<productinfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="optional">
<?xml-stylesheet type="text/xsl"href="optional"?>
<matlabrelease>R2016b</matlabrelease>
<name>MyToolbox</name>
<type>toolbox</type>
<icon></icon>
32-21
32 Custom Help and Documentation
<help_location>html</help_location>
</productinfo>
You can also create info.xml by using the template info_template.xml included with the
MATLAB documentation. To create and edit a copy of the template file in your current folder, run this
code in the command window:
copyfile(fullfile(matlabroot,'help','techdoc','matlab_env',...
'examples','templates','info_template.xml'),pwd)
fileattrib('info_template.xml','+w')
edit('info_template.xml')
The following table describes the required elements of the info.xml file.
You also can include comments in your info.xml file, such as copyright and contact information.
Create comments by enclosing the text on a line between <!-- and -->.
32-22
Display Custom Documentation
Note MATLAB parses the info.xml file and displays your documentation when you add the
folder that contains info.xml to the path. If you created an info.xml file in a folder already on
the path, remove the folder from the path. Then add the folder again, so that MATLAB parses the
file. Make sure that the folder you are adding is not your current folder.
You can create a helptoc.xml file by using the template included with the MATLAB documentation.
To create and edit a copy of the template file helptoc_template.xml in your current folder, run
this code in the Command Window:
copyfile(fullfile(matlabroot,'help','techdoc','matlab_env',...
'examples','templates','helptoc_template.xml'),pwd)
fileattrib('helptoc_template.xml','+w')
edit('helptoc_template.xml')
Place the helptoc.xml file in the folder that contains your HTML documentation files. This folder
must be referenced as the <help_location> in your info.xml file.
Each <tocitem> entry in the helptoc.xml file references one of your HTML help files. The first
<tocitem> entry in the helptoc.xml file serves as the initial landing page for your documentation.
Within the top-level <toc> element, the nested <tocitem> elements define the structure of your
table of contents. Each <tocitem> element has a target attribute that provides the filename. File
and path names are case-sensitive.
• The location of the helptoc.xml files is listed as the <help_location> in your info.xml file.
• All file and path names exactly match the names of the files and folders, including capitalization.
• All path names use URL file path separators (/). Windows style file path separators (\) can cause
the table of contents to display incorrectly. For example, if you have an HTML help page
firstfx.html located in a subfolder called refpages within the main documentation folder, the
<tocitem> target attribute value for that page would be refpages/firstfx.html.
32-23
32 Custom Help and Documentation
</toc>
This helptoc.xml file, paired with a properly formulated info.xml file, produced this display in the
documentation.
For example, suppose that your HTML files are in C:\MATLAB\MyToolbox\html. This command
creates a searchable database for those files:
builddocsearchdb('C:\MATLAB\MyToolbox\html')
To search for terms in your toolbox, open the MathWorks documentation in your system web browser
and in the Search Documentation field, enter the term you want to search for. Then, on the left side
of the page, under Refine by Source, select Supplemental Software to view the results for your
toolbox.
32-24
Display Custom Documentation
Beginning with MATLAB R2014b, you can maintain search indexes side by side. To ensure the
documentation for the custom toolbox is searchable in a given release, run builddocsearchdb
against your help files using that release of MATLAB. If you run builddocsearchdb using R2021b
or a previous release, builddocsearchdb creates the subfolder helpsearch-v3 to contain the
search database files. Maintain both the helpsearch-v4 subfolder and the helpsearch-v3
subfolder side by side. Then, when you run any MATLAB release, MATLAB automatically uses the
appropriate database for searching your documentation.
When MATLAB finds an info.xml file on the search path or in the current folder, it automatically
validates the file against the supported schema. If there is an invalid construct in the info.xml file,
MATLAB displays an error in the Command Window. The error is typically of the form:
Warning: File <yourxmlfile.xml> did not validate.
...
An info.xml validation error can occur when you start MATLAB or add folders to the search path.
If you do not list required XML elements in the prescribed order, you receive an XML validation error:
Often, errors result from incorrect ordering of XML tags. Correct the error by updating
the info.xml file contents to follow the guidelines in the MATLAB help documentation.
For a description of the elements you need in an info.xml file and their required ordering, see
“Create info.xml File” on page 32-21.
Suppose that you have a file named info.xml that has nothing to do with custom documentation.
Because this info.xml file is an unrelated file, if it causes an error, you can safely ignore it. To
32-25
32 Custom Help and Documentation
prevent the error message from reoccurring, rename the unrelated info.xml file. Alternatively,
ensure that the file is not on the search path or in the current folder.
Use the error message to isolate the problem or use any XML schema validator. For more information
about the structure of the info.xml file, consult its schema at matlabroot/sys/namespace/
info/v1/info.xsd.
If you have an info.xml file from a different version of MATLAB, that file could contain constructs
that are not valid with your version. To identify an info.xml file from another version, look at the
full path names reported in the error message. The path usually includes a version number, for
example, ...\MATLAB\R14\.... In this situation, the error is not actually causing any problems, so
you can safely ignore the error message. To ensure that the error does not reoccur, remove the
offending info.xml file. Alternatively, remove the outdated info.xml file from the search path and
out of the current folder.
See Also
builddocsearchdb
Related Examples
• “Display Custom Examples” on page 32-27
• “Create and Share Toolboxes” on page 25-12
• “Add Help for Your Program” on page 20-5
32-26
Display Custom Examples
1 Create your example files. To create examples from scripts or functions, you can convert the files
to formatted HTML files in MATLAB using either of these two methods:
• Create a live script (*.mlx) and export it to HTML. For more information, see “Ways to Share
and Export Live Scripts and Functions” on page 19-62.
• Create a script (*.m), and publish it to HTML. For more information, see “Publish and Share
MATLAB Code” on page 23-2.
Store all your example files and any supporting files (such as PNG and CSS files) for your toolbox
in the folder (of a subfolder of the folder) that contains your demos.xml file. This folder must be:
For example, suppose that you have a toolbox named My Sample, which contains a script named
my_example that you published to HTML. This demos.xml file allows you to display
my_example:
<?xml version="1.0" encoding="utf-8"?>
<demos>
<name>My Sample</name>
<type>toolbox</type>
<icon>HelpIcon.DEMOS</icon>
<description>This text appears on the main page for your examples.</description>
<website><a href="https://www.mathworks.com">Link to your Web site</a></website>
<demosection>
<label>First Section</label>
<demoitem>
<label>My Example Title</label>
<type>M-file</type>
<source>my_example</source>
</demoitem>
</demosection>
</demos>
3 View your examples.
In your system web browser, navigate to the MathWorks documentation home page. On the left
side of the home page, under Supplemental Software, click the link for your example.
If your examples do not display under Supplemental Software, the demos.xml file might
contain an invalid construct.
32-27
32 Custom Help and Documentation
Within the demos.xml file, the root tag is <demos>. This tag includes elements that determine the
contents of the main page for your examples.
In previous releases, this icon was the icon for your example. In
those releases, you can use a standard icon, HelpIcon.DEMOS. Or,
you can provide a custom icon by specifying a path to the icon
relative to the location of the demos.xml file.
<description> The description that appears on the main page for your examples.
32-28
Display Custom Examples
Optionally, define categories for your examples by including a <demosection> for each category. If
you include any categories, then all examples must be in categories.
Each <demosection> element contains a <label> that provides the category name, and the
associated <demoitem> elements.
See Also
patchdemoxmlfile
Related Examples
• “Display Custom Documentation” on page 32-20
32-29
33
Projects
Create Projects
Projects can help you organize your work and collaborate. Projects promote productivity and
teamwork by helping you with common tasks.
Create Project
To create a blank project, on the Home tab, click New > Project > Blank Project. To create a
project from an existing folder, on the Home tab, click New > Project > From Folder.
The New Project dialog box opens. Enter a project name, select a project folder, and click Create.
Open Project
To open an existing project, on the Home tab, click Open and browse to an existing project .prj file.
Alternatively, in the Current Folder browser, double-click the project .prj file.
Note To avoid conflicts, you can have only one project open at a time. If you open another project,
any currently open project closes.
To open a recent project, on the Home tab, click the Open arrow and select your project under the
Recent Projects list.
33-2
Create Projects
In MATLAB Online, when you open a project from an unknown source for the first time, MATLAB
warns that the content might be unsafe. Projects from unknown sources include projects you clone
from a remote repository, download, or receive as an archive.
A project can be configured to execute code automatically on startup and change the MATLAB path.
To protect yourself from malicious attacks, make sure you trust the sender or the author of the
project before you open the project.
After you open a project for the first time, MATLAB remembers your choice and does not show a
warning for the same project again. If you open and trust a project that references other projects,
MATLAB trusts all projects in the hierarchy.
To disable these warnings altogether, on the Home tab, in the Environment section, click
Preferences. In the MATLAB > Project section, clear Warn when opening projects from
unknown sources.
Set Up Project
After you create a project, the Welcome to your project dialog box opens and prompts you to set up
the project.
2 In the Set Up Project (Step 1 of 2) dialog box, you can choose folders to add to the project path.
Adding project folders to the project path ensures that all users of the project can access the files
within them. MATLAB adds these folders to the search path when you open the project, and
removes them when you close the project.
To add all the folders in project folder to the project path, click Add with Subfolders and then
select the root project folder containing all your subfolders.
33-3
33 Projects
For more information about adding folders to the project path, including how to add them after
completing the project setup, see “Specify Project Path” on page 33-8.
3 After specifying the project path, click the Next button to continue.
4 In the Set Up Project (Step 2 of 2) dialog box, you can specify startup and shutdown files. Startup
files help you set up the environment for your project. Shutdown files help you clean up the
environment when you are done. Use shutdown files to undo the setup that occurs in startup
files.
Use the Add and Remove buttons to manage the startup and shutdown file lists. The files run
from the top down. If the order in which the files are run is important, use the arrow buttons to
move files up or down in the list.
For more information about specifying startup and shutdown files, including how to specify them
after completing the project setup, see “Specify Startup and Shutdown Files” on page 33-8.
33-4
Create Projects
5 Click Finish to complete the project setup and open your new project.
To create a new file or folder in the project, in the Files view, right-click in white space and select
New Folder or New File. The new file or folder is created and added to the project.
To add existing files to a project, on the Project tab, click the down arrow to expand the Tools
gallery. Under Project Files, click Add Files. Then, select from the list of files in the project folder
that are not yet added to the project. To add existing files from the Files view, click All. Then, right-
click one or more files and folders, and select Add to Project or Add Folder to Project (Including
Child Files). To add existing files from a file browser or the Current Folder browser, cut and paste or
drag and drop the files into the project Files view. If you drag a file from outside the project root
folder, this moves the file and adds it to your project. Drag files within the project root to move them.
To add and remove project files programmatically, use the addFile function.
You might not want to include all files in your project. For example, you might want to exclude some
files in the project root folder, such as SVN or CVS source control folders. To determine which files
need to be included in your project, see “Analyze Project Dependencies” on page 33-42.
33-5
33 Projects
Some projects are shared as archived projects. An archived project is useful for sharing with users
who do not have access to a connected source control tool. To view and edit the contents of an
archived project, create a new project from the archived project.
To create a new project from an archived project, in the Current Folder browser, double-click the
archived project file which has an .mlproj extension. The Extract Project dialog box opens. Specify
the location for the new project and click Select Folder. For example, C:\myNewProject.
The new project opens. The current folder (for example, C:\myNewProject) contains the imported
project folders. If the archived project contains referenced projects, MATLAB imports files into two
subfolders, mains and refs. The mains project folder (for example, C:\myNewProject\mains)
contains the project folders. The refs folder (for example C:\myNewProject\refs) contains the
referenced project folders.
If you have Simulink, you can use a Simulink template to create and reuse a standard project
structure.
1 On the Home or Project tab, click New > Project > From Simulink Template. The Simulink
Start Page opens.
2 The start page shows all project templates (*.sltx) on the MATLAB path. Select a template in
the list to read the template description.
If your templates do not appear, locate them by clicking Open. In the Open dialog box, make
*.sltx files visible by setting the file type to All MATLAB files, and browse to your template.
3 Select a template and click Create Project. The Create Project dialog box opens.
Templates created in R2017b or later warn you if required products are missing. Click the links
to open Add-On Explorer and install required products.
4 Specify the root project folder, edit the project name, and click Create Project.
To use project templates created in R2014a or earlier (.zip files), upgrade them to .sltx files using
Simulink.exportToTemplate.
33-6
Create Projects
See Also
More About
• “Manage Project Files” on page 33-21
• “Analyze Project Dependencies” on page 33-42
• “Share Projects” on page 33-35
• “Use Source Control with Projects” on page 33-60
• “Create and Edit Projects Programmatically” on page 33-70
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
33-7
33 Projects
When you open a project, MATLAB adds the project path to the MATLAB search path and then runs
or loads specified startup files. The project path and startup files help you set up the environment for
your project. Similarly, when you close a project, MATLAB removes the project path from the
MATLAB search path and runs specified shutdown files. Shutdown files help you clean up the
environment for your project. Use shutdown files to undo the setup that occurs in startup files.
More specifically, when you open a project, MATLAB changes the current folder to the project startup
folder, and runs (.m and .p files) or loads (.mat files) any specified startup file. For more information
about configuring the startup folder, see “Set Startup Folder” on page 33-8.
To add a folder to the project path, on the Project tab, in the Environment section, click Project
Path. Click Add Folder and select the folder that you want to add. To add a folder and all of its
subfolders, click Add with Subfolders.
To remove a folder from the project path, select the folder from the displayed list and click Remove.
You also can add or remove a folder from the project Files view. Right-click the folder, select Project
Path, and select from the available options.
Folders on the project path appear with the project path icon in the Status column of the Files
view.
To edit the project startup folder, on the Project tab, in the Environment section, click
Details.
Then, in the General section, enter a path for the project startup folder.
To stop a file from running at startup or shutdown, right-click the file and select Remove from
Startup or Remove from Shutdown.
Alternatively, go to the Project tab and click Startup Shutdown. Then, in the Manage Project
Startup and Shutdown dialog box, use the Add and Remove buttons to manage the startup and
33-8
Automate Startup and Shutdown Tasks
shutdown file lists. The files run from the top down. If the order in which the files are run is
important, use the arrow buttons to move files up or down in the list.
Note Startup and shutdown files are included when you commit modified files to source control.
When you configure startup and shutdown files, they run for all other project users.
Startup files can have any name except startup.m. A file named startup.m on the MATLAB path
runs when you start MATLAB. If your startup.m file calls the project, an error occurs because the
project is not yet loaded. For more information about using startup.m files, see “Startup Options in
MATLAB Startup File”.
To create new startup and shutdown files programmatically, see addStartupFile and
addShutdownFile.
In Simulink, you can specify additional project startup options. For more information, see “Automate
Startup Tasks” (Simulink).
See Also
addStartupFile
More About
• “Manage Project Files” on page 33-21
• “Create and Edit Projects Programmatically” on page 33-70
• “What Is the MATLAB Search Path?”
33-9
33 Projects
You can set MATLAB projects preferences to specify project definition files type, detect project files
that are shadowed by open models, and detect project-wide references when you rename, remove,
and delete files.
On the Home tab, in the Environment section, click Preferences. Select MATLAB > Project.
Then, adjust preference options as this table describes. Not all project preferences are available in
MATLAB Online.
Preference Usage
New Projects To specify where to create new projects, in Default folder, browse to a
folder on your system.
To specify the Project definition files type for new projects, select an
option based on your use case:
For details, see “Manage Shadowed and Dirty Models and Other Project
Files” (Simulink).
Git does not track empty folders and ignores them when you commit.
MATLAB enables you to recreate an empty folder structure in your
project. Doing so is useful for small projects intended for training or as
procedure templates.
33-10
Set MATLAB Projects Preferences
Preference Usage
To disable the warning you receive when opening a project from an
unknown source for the first time, clear Warn when opening projects
from unknown sources.
33-11
33 Projects
Preference Usage
When you add project files to a folder that is not on the path, you can
choose whether MATLAB notifies you before adding the folder to the
project path. In Update project path when adding files to a folder
that is not on the path, select one of these options:
To save project action messages, such as how long shortcuts take to start
up, select Log messages.
To specify where to store your project log files, in Log folder, browse to a
folder on your system.
If you enabled Log messages, the project stores the events in a date-
stamped file in the location you specified in Log folder.
See Also
More About
• “Create Projects” on page 33-2
• “Manage Project Files” on page 33-21
• “Project Definition Files” on page 33-65
33-12
Set MATLAB Projects Preferences
• “Manage Shadowed and Dirty Models and Other Project Files” (Simulink)
33-13
33 Projects
MATLAB projects provide tools to improve productivity, portability, collaboration, and maintainability
of your MATLAB and Simulink code. Testing is an important aspect of software development and
maintenance. To ensure the reproducibility, reliability, and accuracy of your code, MATLAB projects
helps you identify and run tests easily.
Label other test files manually using the Test classification label.
1 In the project Files view or in the Dependency Analyzer graph, select and right-click the files,
and then click Add Label.
2 From the list, select the Test label and click OK.
Alternatively, add the Test label programmatically using the addLabel function.
For projects under source control, the labels you add persist across file revisions.
33-14
Identify and Run Tests in MATLAB Projects
To show only the files with the Test label in the project view, follow these steps.
33-15
33 Projects
Alternatively, run all the tests with the Test label in the current project by using the runtests
function.
To create a test suite from all files with the Test label in the opened project and its referenced
projects, use the testsuite function.
33-16
Identify and Run Tests in MATLAB Projects
proj = currentProject;
suite = testsuite(proj.RootFolder,IncludingReferencedProjects=true);
results = run(suite)
results =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
9 Passed, 0 Failed, 0 Incomplete.
1.2533 seconds testing time.
For projects with a large number of tests, running all tests is often time consuming.
To reduce qualification run time locally or in CI jobs, run only the tests that are impacted by the
changes you make to your project.
proj = currentProject;
modifiedFiles = listModifiedFiles(proj);
The listModifiedFiles function lists only local modifications. If you need the list of modified
files between revision identifiers for CI workflows, for example, when you want to run tests after
you merge your Git branch into the main branch, use these commands instead.
proj = currentProject;
[status,modifiedFiles] = system("git diff --name-only main..newBranch :!resources");
modifiedFiles = split(modifiedFiles);
modifiedFiles = modifiedFiles(1:(end-1));
2 Find all files that are impacted by the modified files in your project.
impactedFiles = listImpactedFiles(proj,modifiedFiles);
Tip
• You can use the Dependency Analyzer to interactively identify and create a test suite from the
tests you need to run to qualify your change. For more information, see “Perform Impact
Analysis with a Project” (Simulink).
• To reduce qualification time on local machines and CI servers, you can also share the
dependency cache file. Using a prepopulated dependency cache file, you can perform an
incremental impact analysis and cut down the runtime of a full impact analysis. For more
information, see “Reduce Test Runtime Using Dependency Cache and Impact Analysis” on
page 35-47.
33-17
33 Projects
testFiles = findFiles(proj,Label="Test");
4 Find and run test files that are impacted by the modified project files.
impactedTests = intersect(testFiles,impactedFiles);
runtests(impactedTests);
Alternatively, you can create a filtered test suite based on source code dependency by using the
matlabtest.selectors.DependsOn class. For an example, see “Select Tests That Depend on
Modified Files in Project” (MATLAB Test).
See Also
Apps
Dependency Analyzer
Functions
addLabel | findFile | runtests | run (TestSuite) | testsuite | listModifiedFiles |
listImpactedFiles
More About
• “Find Project Files” on page 33-23
• “Add Labels to Project Files” on page 33-28
• “Create and Edit Projects Programmatically” on page 33-70
• “Create Shortcuts to Frequent Tasks” on page 33-26
• “Create Custom Tasks” on page 33-30
• “Continuous Integration Using MATLAB Projects and Jenkins” on page 35-46
33-18
Determine Order for Resolving Conflicts Using Dependency Analyzer
When collaborating on a project, a branch merge can lead to conflicted files. For a smoother merge,
you can determine the optimal order in which to resolve conflicts by running a dependency analysis.
Conflicts in files that are used by other files should be resolved first. Conflicts in files that do not have
dependencies do not affect other files, so the conflict resolve order does not matter.
Note If the project dependency graph contains circular dependencies, there might not be an optimal
order in which to resolve conflicts.
You can use the Dependency Analyzer to programmatically determine the optimal order in which to
resolve conflicts. In the MATLAB Command Window, run the getProjectResolveOrder function.
if ~isdag(graph)
error("Unable to recommend an optimal resolve order. The dependency graph contains circul
end
topologicalOrder = toposort(graph);
topologicalFiles = graph.Nodes.Name(topologicalOrder);
fileIndices = ismember(topologicalFiles, [conflictingFiles.Path]);
files = flip(topologicalFiles(fileIndices));
nodependencyFiles = setdiff(cellstr([conflictingFiles.Path])',files);
33-19
33 Projects
fileOrder = [files;nodependencyFiles];
end
getProjectResolveOrder
ans =
{'C:\workSpace\examples\TimesTableApp\source\timesTableGame.m' }
{'C:\workSpace\examples\TimesTableApp\source\timestable.mlapp' }
{'C:\workSpace\examples\TimesTableApp\tests\tAnswerIsCorrect.m' }
{'C:\workSpace\examples\TimesTableApp\utilities\openRequirementsDocument.m'}
{'C:\workSpace\examples\TimesTableApp\utilities\runTheseTests.m' }
Resolve conflicts according to the listed order. For more details, see “Commit Modified Project Files”
on page 33-66.
See Also
More About
• “Set Up Git Source Control” on page 35-13
• “Commit Modified Project Files” on page 33-66
• “Analyze Project Dependencies” on page 33-42
• “Explore an Example Project” on page 33-77
33-20
Manage Project Files
Action Procedure
View project files. In the Files view, click Project to display only the files and
folders that are included in the project.
View all files in a project folder. To display all files and folders in the project folder, in the Files
view, click All.
You might not want to include all files in your project. For
example, you might want to exclude SVN or CVS source control
folders. For more information, see “Work with Derived Files in
Projects” on page 33-68.
Create a new project folder. In the Files view, right-click in white space, and then click New
> Folder.
Add files to a project. On the Project tab, click the down arrow to expand the Tools
gallery. Under Project Files, click Add Files. Select from the
list of unmanaged files in the project folder.
You also can paste or drag files and folders from your operating
system file browser or the Current Folder browser to the
project Files view. When you drag a file to the Files view,
MATLAB adds the file to the project.
33-21
33 Projects
Action Procedure
Undo or redo an action Click or at the upper right corner of the toolstrip.
When renaming files, the project offers to automatically update references to the file. Automatically
updating references to a file when renaming prevents errors that result from changing names or
paths manually and overlooking or mistyping the name.
For example:
• When renaming a class, the project offers to automatically update all classes that inherit from it.
• When renaming a .m or .mlx file, the project offers to automatically update files and callbacks
that call it. The project does not automatically update .mlx files. You need to update them
manually.
• When renaming a C file, the project prompts you to update the S-function that uses it.
You can disable the automatic updates when renaming, deleting, or removing files in a project. On the
MATLAB Home tab, in the Environment section, click Preferences. Select MATLAB > Project and
clear the Detect project-wide references when renaming, removing, and deleting files option.
For more information about automatic updates when renaming, deleting, or removing Simulink files
such as library links, model references, and model callbacks, see “Automatic Updates When
Renaming, Deleting, or Removing Files” (Simulink).
See Also
More About
• “Find Project Files” on page 33-23
• “Add Labels to Project Files” on page 33-28
• “Create Custom Tasks” on page 33-30
33-22
Find Project Files
For example, to group files by type, in the Layout field, select List. Then, click the Actions button
and select Group By > Type. To sort the grouped files by size, click the actions button and select
Sort By > Size.
To search for a file or folder, in the search field at the top of the view, begin typing the file or folder
name. The asterisk character (*) is a wildcard. For example, to show only file names that begin with
coll and have a .m extension, type coll*.m.
To filter the files and folders in the current view, click the Filter button next to the search field. In
the Filter Builder dialog box, select the names, file types, project statuses, and labels to filter by.
Click Apply to filter the files and folders in the current view. The search field displays the applied
filter.
To clear a search or filter, click the Clear button to the right of the search field.
33-23
33 Projects
1 On the Project tab, click the down arrow to expand the Tools gallery. Under Project Files, click
Search. The Search Inside Project Files dialog box opens.
2 Enter the text to search. MATLAB searches the project files for the exact text in the search field
and displays the results.
In MATLAB Online, to find files and folders in projects, click the Find Files icon in the sidebar. If
the Find Files icon is not in the left or right sidebar, go to the Home tab, and in the File section, click
Find Files.
33-24
Find Project Files
To change how the Find Files tool searches for text, select a search option:
• Match case – Search only for text with the precise case of the search text.
• Match whole word – Search only for exact full-word matches.
To only search for files within the project, click the Filters button and set the Look in option to
Current project. If a project is open when you open the Find Files tool, this option is set to Current
project by default. You also can use the Filters button to specify whether to search for file names
or file content, and what file types to include in the results.
See Also
More About
• “Manage Project Files” on page 33-21
• “Create Shortcuts to Frequent Tasks” on page 33-26
• “Add Labels to Project Files” on page 33-28
33-25
33 Projects
Run Shortcuts
To run a shortcut, in the Project Shortcuts tab, click the shortcut. Clicking a shortcut in the Project
Shortcuts tab performs the default action for the file type. For example, MATLAB runs .m shortcut
files and loads .mat shortcut files. If the shortcut file is not on the path, MATLAB changes the current
folder to the parent folder of the shortcut file, runs the shortcut, and then changes the current folder
back to the original folder.
Alternatively, in the Files view, you can right-click the shortcut file and select Run. If the script is not
on the path, then MATLAB asks if you want to change folder or add the folder to the path.
Create Shortcuts
To create a shortcut from an existing project file:
1 In the Files view, right-click the file and select Create Shortcut. Alternatively, on the Project
Shortcuts tab, click New Shortcut and browse to select a file.
The shortcut appears with the selected name and icon on the Project Shortcuts tab. In the Files
view, the Status column displays an icon indicating that the file is a shortcut.
Note Shortcuts are included when you commit your modified files to source control, so you can share
shortcuts with other project users.
Organize Shortcuts
You can organize shortcuts by categorizing them into groups. For example, you might create one
group of shortcuts for loading data, another for opening files, another for generating code, and
another for running tests.
33-26
Create Shortcuts to Frequent Tasks
1 On the Project Shortcuts tab, right-click a shortcut and select Edit Shortcut. Alternatively, in
the Files view, right-click a file and select Edit Shortcut.
See Also
More About
• “Manage Project Files” on page 33-21
• “Find Project Files” on page 33-23
• “Add Labels to Project Files” on page 33-28
33-27
33 Projects
Add Labels
To add a label to a project file, in the Files view, select the file. Then, drag the desired label from the
Labels panel at the bottom left of the project into the Label Editor panel for the selected file. The
Label Editor panel is located at the bottom right of the Files view. To restore the panel if it is
minimized, click the icon.
To add a label to multiple project files, in the Files view or in the Dependency Analyzer graph, select
the files, right-click, and select Add Label. Choose a label from the list and click OK.
Note After you add a label to a file, the label persists across file revisions.
To add labels programmatically (for example, in custom task functions) see addLabel.
To change a label that belongs to a single-valued category, select the new value from the label list.
You can add additional annotations to labels from categories that you create. In the Label Editor
panel, click a label and insert or modify text. Then, click Apply.
33-28
Add Labels to Project Files
Create Labels
Labels exist in two types of categories:
• Single-valued — You can attach only one label from the category to a file.
• Multi-valued — You can attach multiple labels from the category to a file.
All projects contain a built-in label category called Classification with several built-in labels. These
built-in labels are read-only.
1 In the Labels panel at the bottom left of the project, right-click and select Create New
Category. The Create Category dialog box opens.
2 Enter a name for the new category.
3 To create a single-valued label category, select the Single Valued check box. Otherwise,
MATLAB creates a multi-valued label category.
4 To specify a label data type other than the default String data type, from the Type list, select
from the available options.
5 Click Create.
1 In the Labels panel at the bottom left of the project, right-click the label category and select
Create New Label. The Create Label dialog box opens.
2 Enter a name for the new label and click OK.
See Also
More About
• “Manage Project Files” on page 33-21
• “Find Project Files” on page 33-23
33-29
33 Projects
1 On the Project tab, click the down arrow to expand the Tools gallery. Under Project Checks,
click Custom Tasks. In the Custom Task dialog box, click Manage.
2 Click Add and then select Add Using New Function. If you want to add an existing script as a
custom task, select Add Using Existing Function.
3 Specify a file name for the script and save the new file on the MATLAB path. The MATLAB Editor
opens the new file containing an example custom task function.
4 Edit the function to perform the desired action on each file. Use the instructions at the top of the
file to guide you to create a custom task with the correct function signature. Your custom tasks
must accept a full path to a file as the single input argument and return a single output
argument.
For example, this custom task function extracts Code Analyzer information for each file using the
checkcode function.
[~,~,ext] = fileparts(file);
switch ext
case {'.m', '.mlx', '.mlapp'}
result = checkcode(file, '-string');
otherwise
result = [];
end
5 Save the file.
You can use the MATLAB editor to set breakpoints and debug a custom task function, just as with any
other MATLAB function.
1 On the Project tab, click the down arrow to expand the Tools gallery. Under Project Checks,
click Custom Tasks.
2 In the Include column of the table, select which project files you want to run the custom task on.
To include or exclude multiple files in the table at once, press the Shift or Ctrl key, select the
files, and then right-click and select Include or Exclude. If the custom task function can identify
the files to operate on, include all files.
3 In the Custom task field, select from the available custom task functions. You also can enter the
name of a task directly in the field, or click Browse.
33-30
Create Custom Tasks
4 Click Run Task to run the task. The Custom Task Report window displays the results.
5 Examine the Results column in the table to ensure that the custom task ran correctly on all files.
To view detailed result information for a file, select the file in the table. The results pane at the
bottom of the Custom Task Report displays the details.
To save the Custom Task Report, click the Publish Report button at the bottom of the Custom Task
Report. You can either save the report as an HTML file or a Microsoft Word file. If you have MATLAB
Report Generator™, you also can save the report as a PDF file.
To see the report file and add it to your project, switch to the All files view.
See Also
More About
• “Create Shortcuts to Frequent Tasks” on page 33-26
• “Manage Project Files” on page 33-21
33-31
33 Projects
MATLAB supports large-scale project componentization by allowing you to reference other projects
from a parent project. Organizing large projects into components facilitates code reuse, modular and
team-based development, unit testing, and independent release of components. For more information,
watch How to Organize Large Projects into Components (3 min, 32 sec).
Projects can reference multiple other projects in a hierarchical manner. The project reference
hierarchy appears as a tree in the References view.
• Access the project paths, entry-point shortcuts, and source control information for all referenced
projects.
• View, edit, and run files that belong to a referenced project.
• Detect changes in referenced projects using checkpoints.
1
On the Project tab, in the Environment section, click References. The Add Reference
dialog box opens.
2 Browse to select the required project (.prj) file.
3 In the Reference type field, select either Relative or Absolute. Select Relative if your project
hierarchy has a well-defined root relative to your project root. For example, your project root
might be a folder under source control. Select Absolute if the project you want to reference is in
a location accessible to your computer, for example, a network drive.
4 To create a checkpoint when you add the project, select Set a checkpoint to detect future
changes. For more information about checkpoints, see “Manage Changes in Referenced Project
Using Checkpoints” on page 33-33.
5 Click Add.
When the referenced project loads, MATLAB adds the referenced project path to the MATLAB search
path and then runs or loads specified startup files. Similarly, when the referenced project closes,
MATLAB removes the project path from the search path and runs specified shutdown files. MATLAB
loads referenced projects before their parent projects. This allows the parent project to access the
referenced project in startup and shutdown files.
To remove a referenced project from your project hierarchy, in the References tree, right-click the
referenced project and select Remove Reference.
33-32
Componentize Large Projects
To view a referenced project, in the parent project, select the References view. In the References
tree, select a referenced project.
To display the referenced project files, at the top right of the References view, click Show Files.
To modify or run a file, right-click the file and select from the list of available options.
You can extract an existing folder in a project to create a referenced project. After extracting a folder,
file and folder contents and shortcuts in the referenced project remain accessible from the parent
project.
To extract a folder from a project and convert the folder into a referenced project:
1 In the Files view, right-click the folder and select Extract to Referenced Project. The Extract
Folder to New Project dialog box opens.
2 Specify a project name and location
3 In the Reference type field, select either Relative or Absolute. Select Relative if you specify
the new project location with reference to the current project root. Select Absolute if you specify
the full path for the new location, which is, for example, on a network drive
4 To disable any of the default content migration actions, click More Options and clear the
corresponding check boxes.
5 Click Extract.
6 In the two Warning dialog boxes that open, click OK.
The selected folder and its contents are removed from the project. On the Project Shortcuts tab, the
Referenced Projects section shows a new shortcut for the referenced project.
By default, MATLAB creates a checkpoint when you add a reference to a project. To create additional
checkpoints:
To detect changes in a referenced project, go to the References tab, and in the Checkpoint section,
click Checkpoint Report. The Difference to Checkpoint dialog box displays the files that have
changed on disk since you created the checkpoint.
To remove the checkpoint, in the Checkpoint section of the References tab, click Clear.
33-33
33 Projects
See Also
More About
• How to Organize Large Projects into Components (3 min, 32 sec)
• “Organize Projects into Components Using References and Git Submodules” (Simulink)
• “Create Projects” on page 33-2
• “Share Projects” on page 33-35
33-34
Share Projects
Share Projects
You can collaborate with others by packaging and sharing projects. You can also control which files
are included in a shared project by using labels and an export profile. (For more information, see
“Create an Export Profile” on page 33-38.)
To archive a project:
1 With the project loaded, on the Project tab, click Share >
Archive.
2 If you want to export only a set of specified files, choose an
Export profile. For more information, see “Create an Export
Profile” on page 33-38.
3 If you have referenced projects and want to export the
referenced project files, select Include referenced projects.
4 Click Save As and specify a file path.
5 In the Save as type field, select the archived project file type.
By default, MATLAB archives the project as an .mlproj file.
You can choose to archive the project as a ZIP file.
6 Click Save to create the project archive.
You can now share the archive file the way you would any other
file.
33-35
33 Projects
1 With the project loaded, on the Project tab, select Share >
Email.
2 If you want to export only a set of specified files, choose an
Export profile. For more information, see “Create an Export
Profile” on page 33-38.
3 If you have referenced projects and want to export the
referenced project files, select the Include referenced
projects check box.
4 Click Attach to Email. MATLAB opens a new email in your
default email client with the project attached as an .mlproj
file.
5 Edit and send the email.
Create a toolbox to share. You can create a toolbox from your project and share the toolbox
with collaborators.
The packager adds all project files to the toolbox and opens
the Package a Toolbox dialog box.
2 The Toolbox Information fields are populated with the
project name, author, and description. Edit the information as
needed.
3 To include files not already included in the project files, edit
the excluded files and folders.
4 Click Package.
You can now share the toolbox file the way you would any other
file.
33-36
Share Projects
To view the URL for the remote repository, on the Project tab, in
the Source Control section, click the Git Details button.
Before sharing a project with others, it can be useful to examine the required add-ons for your project
by performing a dependency analysis. For more information, see “Find Required Products and Add-
Ons” on page 33-53.
33-37
33 Projects
If the files you need to share are only a small subset of a large project, choose the include option.
4 In the Files pane, click + and select the labels for the files you want to exclude or include, and
then click OK.
5 You can also exclude user-defined labels from the exported project. In the Labels pane, click +
and select the custom labels you do not want to export, and then click OK.
6 Click Apply and close the Manage Export Profiles dialog box.
Note Export profiles do not apply changes to referenced projects. When you share your project,
MATLAB exports the entire referenced projects.
See Also
More About
• “Add Labels to Project Files” on page 33-28
• “Create Projects” on page 33-2
• “Analyze Project Dependencies” on page 33-42
33-38
Check for Compatibility Issues Using Project Upgrade
The Upgrade Project tool helps you check for compatibility issues or upgrade your project to the
current MATLAB release. The tool applies fixes automatically when possible and produces a report.
• For MATLAB files, the tool checks only for code compatibility issues with the current MATLAB
release. The tool does not apply fixes automatically.
• For Simulink models and libraries, the tool applies fixes and automatically upgrades the model
files to the current MATLAB release. For more information on upgrading models and libraries and
applying fixes automatically, see “Check for Compatibility Issues and Upgrade Simulink Models
Using Project Upgrade” (Simulink).
33-39
33 Projects
By default, the Project Upgrade tool runs the code compatibility checks on all files in your project. If
you want to run the check on a subset of files, adjust the selection in the Files tab. The tool notifies
you if your file selection does not include all required dependencies.
1 For each file in the Project Upgrade report, examine the checks marked as Need attention.
Select a check in the Check Name column to display the check results.
2 The tool does not apply fixes for MATLAB code automatically. Apply the recommended fix in the
Details pane manually.
3 Rerun the check by clicking Rerun Checks.
If your project is under source control, you can examine the fixes you applied. To see the differences,
select a file and click View Changes. A comparison report opens.
33-40
Check for Compatibility Issues Using Project Upgrade
See Also
More About
• “Use Source Control with Projects” on page 33-60
• “Analyze Project Dependencies” on page 33-42
• “Check for Compatibility Issues and Upgrade Simulink Models Using Project Upgrade”
(Simulink)
33-41
33 Projects
To explore a project and visualize its structure using different views, see “Explore the Dependency
Graph, Views, and Filters” on page 33-44.
To find and fix problems in your project, see “Investigate and Resolve Problems” on page 33-50.
To assess how a change will affect other project files, see “Find File Dependencies” on page 33-54.
To find add-ons and products required by your project to run properly, see “Find Required Products
and Add-Ons” on page 33-53.
To start analyzing your project, on the Project tab, in the Tools gallery, click Dependency Analyzer.
Alternatively, in the project Views pane, select Dependency Analyzer and click Analyze.
To analyze the dependencies of specific files, in the dependency graph, select the files. In the Impact
Analysis section, click All Dependencies or use the context menu and select Find All
Dependencies.
To analyze the dependencies inside add-ons, select Analyze > Add-Ons. For more details about
available options, see “Analysis Scope” (Simulink).
You can also check dependencies directly in Project. In the Project Files view, right-click the project
files you want to analyze and select Find Dependencies.
33-42
Analyze Project Dependencies
• Your project structure and its file dependencies, including how files such as models, libraries,
functions, data files, source files, and derived files relate to each other.
• Required products and add-ons.
• Relationships between source and derived files (such as .m and .p files, .slx and .slxp, .ssc
and .sscp, or .c and .mex files), and between C/C++ source and header files. You can see what
code is generated by each model, and find what code needs to be regenerated if you modify a
model.
• Warnings about problem files, such as missing files, files not in the project, files with unsaved
changes, and out-of-date derived files.
You can examine project dependencies and problem files using the File List. In the toolstrip, click
File List.
After you run the first dependency analysis of your project, subsequent analyses incrementally update
the results. The Dependency Analyzer determines which files changed since the last analysis and
updates the dependency data for those files. However, if you update add-ons or installed products and
want to discover dependency changes in them, you must perform a complete analysis. To perform a
complete analysis, in the Dependency Analyzer, click Analyze > Reanalyze All.
33-43
33 Projects
For more information about running a dependency analysis on Simulink models and libraries, see
“Perform an Impact Analysis” (Simulink).
By default, the dependency graph shows all files required by your project. To help you investigate
dependencies or a specific problem, you can simplify the graph using one of the following filters:
• Use the filtered Views to color the files in the graph by type, class, source control status, and
label. See “Color Files by Type, Status, or Label” on page 33-45.
• Use the check boxes in the Legend pane to filter out a group of files.
• Use the Impact Analysis tools to simplify the graph. See “Find File Dependencies” on page 33-
54.
To select all files of a certain type, hover the pointer over the corresponding item in the Legend
pane and click the Add to selection icon.
To remove all files of a certain type from the current selection, hover the pointer over the
corresponding item in the Legend pane and click the Remove from selection icon.
• To open a file, double-click it.
• To pan the dependency graph, hold the Space key, click and drag the mouse. Alternatively, press
and hold the mouse wheel and drag.
To see more information about how two files are related, select their dependency arrow. In the
Properties pane, in the Details section, you can see the full paths of the files you are examining, the
dependency type (such as function call, inheritance, and property type), and where the dependency is
introduced.
33-44
Analyze Project Dependencies
To open the file and highlight where the dependency is introduced, in the Details section, click the
link under Impacted.
Explore the different views in the Views section of the Dependency Analyzer toolstrip to explore your
project files dependencies.
• The MATLAB Files view shows only MATLAB files (such as .m, .mlx, .p, .mlapp, .fig, .mat,
and .mex) in the view and colors them by type.
33-45
33 Projects
• The Class Hierarchy view shows the class inheritance graph and colors the files by type (class,
enumeration class, or abstract class). If the class is not on the search path, the Dependency
Analyzer cannot determine the class type.
33-46
Analyze Project Dependencies
• The Classification view shows all files in the graph and colors them by file label (such as test,
design, and artifact).
Use the classification view to identify which tests you need to run to validate the changes in your
design. For more information, see “Identify Tests to Run” on page 33-55.
33-47
33 Projects
• The Source Control view shows all files in the graph and colors them by source control status.
This view is only enabled if your project is under source control.
Use the source control view to find modified files in your project and to examine the impact of
these changes on the rest of the project files. For more information, see “Investigate Impact of
Modified Files” on page 33-55.
33-48
Analyze Project Dependencies
• The Project Hierarchy view shows all projects in your project hierarchy in the graph and colors
them by project type, top-level or referenced project. This view is available only in MATLAB
Online.
Use the project hierarchy view to investigate how projects in your hierarchy relate to each other
and identify projects that introduce circular dependencies.
This is equivalent to manually removing all of the filters. Filters appear at the top of the graph. For
example, if you have the Source Control view selected, you can remove it by clicking
33-49
33 Projects
In large projects, when investigating problems or dependencies, use the different filters to show only
the files you want to investigate:
• To filter out a subgroup of files from the graph, such as files labeled test or modified files, use the
check boxes in the Legend pane. To remove the legend filter, click the Legend Filter
.
• To color the files in the graph by type, class, label, or source control status, use the Views. To
remove the view filter, click View: viewName at the top of the graph. For example, if you have the
.
• To clear all filters and restore the graph to show all analyzed dependencies in the project, click
Restore to Default. Alternatively, manually remove all filters at the top of the graph.
33-50
Analyze Project Dependencies
1 In the Properties pane, in the Problems section, point to a problem, such as File not in
project, and click the magnifying glass icon . The graph highlights the files with this
specific problem.
To go through these files, use the arrows in the search box (e.g., Problem: File not in
project).
2 To see more information about a specific problem file, select the file in the graph. In the
Properties pane, in the Problems section, you can see details including the path, type, and the
problems for this file.
For example, if a file is File not in project, right-click the problem file in the graph and
select Add to Project.
3 Investigate the next problem listed in the Problems section. Repeat the steps until you resolve
all problems. For more details on how to fix problems, see “Resolve Problems” on page 33-51.
Tip For large projects, viewing the results in a list can make navigation easier.
For large projects, use the File List to investigate your project problem files.
The File List shows only files with the specific problem. Select all the files in the list and use the
context menu to Add to Project.
3 Investigate the next problem listed in the Problems section, for example Missing file. Repeat
the steps until you resolve all problems.
Resolve Problems
33-51
33 Projects
For each problem file, take actions to resolve the problem. This table lists common problems and
describes how to fix them. To resolve Simulink-specific problems, see “Investigate and Resolve
Problems” on page 33-50.
33-52
Analyze Project Dependencies
33-53
33 Projects
In the Dependency Analyzer, in the Properties pane, the Products and Add-Ons sections display the
required products and add-ons and packages for the whole project. To view products or add-ons
required by a specific file, select a file by clicking the graph.
To find which file is introducing a product dependency, point to the product or add-on name and click
the magnifying glass icon . The graph highlights the files that use the selected product.
To go through these files, use the arrows in the search box (e.g., Files using "productName").
To investigate further, you can list the files that use a product and examine where in these files the
dependency is introduced. In the Products and Add-Ons sections, point to product or add-on name
If a required product is missing, the products list labels it as missing. The product is also listed in the
Problems section as productName not installed. To resolve a missing product, install the product
and rerun the dependency analysis.
• In the Impact Analysis section, click All Dependencies. The graph shows the selected file and
all its dependencies.
• To show only files needed by the selected file to run properly, click Required.
• To show only files impacted by a potential change to the selected file, click Impacted.
33-54
Analyze Project Dependencies
Finding these dependencies can help you identify the impact of a change and identify the tests you
need to run to validate your design before committing the changes.
To investigate the dependencies of multiple files, click files while holding the Shift key. The Impact
Analysis section displays how many files are selected.
To reset the graph, click the filter at the top of the graph. For example, if you had filtered by files
To examine the impact of the changes you made on the rest of the project files, perform an impact
analysis on the modified files in your project.
1 In the Views section, select the Source Control view. The graph colors the files by their source
control status. The modified files are in light blue.
2 Select all the modified files in the graph.
Alternatively, add all modified files to selection by clicking the Add to selection icon of an item
in the Legend pane.
Tip If you changed a large number of files, you can also use the file list.
In the Dependency Analyzer toolstrip, click File List. Point to Status and click the arrow to sort
the list by the source control status. Select all the modified files.
3 In the Impact Analysis section, click Impacted. Alternatively, use the context menu and select
Find Impacted.
To identify the tests you need to run to validate your design before committing the changes, use the
Classification view when you perform an impact analysis on the file you changed.
33-55
33 Projects
1 In the Views section, select the Classification view. The graph colors the files by their project
label.
2 Select the file you changed, for example timesTableGame.m.
3 In the Impact Analysis section, click Impacted. Alternatively, use the context menu and select
Find Impacted.
The example graph shows three tests you need to run to qualify the change made to
timesTableGame.m.
33-56
Analyze Project Dependencies
Tip You can compare different analysis results without having to repeat the analysis. To compare
previously saved graphs, in MATLAB, in the Current Folder, right-click two GraphML files and
select Compare Selected Files/Folders.
• Save As Image — Save displayed dependency graph as an image.
To export a subset of files in the graph, select the files, then click Export.
• Use the Legend check boxes, the filtered Views, or the Impact Analysis tools to simplify the
graph.
• To select multiple files, press Shift and select the files.
• To select all files in the filtered graph, press Ctrl+A.
The menu displays how many files are selected. The Dependency Analyzer exports only the selected
files.
Note When you use Package As Archive, the Dependency Analyzer includes the selected files and
all their dependencies in the archive.
You can send files to other Project tools using the Project menu. The Dependency Analyzer exports
only the selected files in the current filtered view.
Select the desired files. In the Dependency Analyzer toolstrip, in the Export section, click Project.
Select from the available options:
• Show in Project — Switch to the project Files view with the files selected.
• Send to Custom Task — Run a project custom task on the selected files.
See Also
More About
• “Share Projects” on page 33-35
33-57
33 Projects
33-58
Clone Remote Git Repository into New Project
1 On the Home tab, click New > Project > From Git. The New Project From Source Control
dialog box opens.
2 Enter your HTTPS repository path into the Repository path field.
3 In the Sandbox field, select the working folder where you want to put the retrieved files for your
new project.
4 Click Retrieve.
If an authentication dialog box for your repository appears, enter the login information for your
Git repository account -- for instance, your GitHub user name and personal access token.
If your repository already contains a project, the project is ready when the tool finishes retrieving
files to your selected sandbox folder.
If your sandbox does not yet contain a project, then a dialog box asks whether you want to create
a project in the folder. To create a project, specify a project name and click OK. The Welcome
screen appears to help you set up your new project. For more information about setting up a
project, see “Set Up Project” on page 33-3.
You can now add, delete, and modify your project files. For details on how to commit and push the
modified project files, see “Commit Modified Project Files” on page 33-66.
Tip Alternatively, to prevent frequent login prompts when you interact with your remote repository,
you can clone a remote repository using SSH instead of HTTPS or install a credential helper. To avoid
problems connecting using SSH, set the HOME environment variable and use it to store your SSH
keys. For more information, see “Configure MATLAB to Use Git SSH Authentication” on page 35-14
and “Manage Git Credentials” on page 35-18.
If you encounter errors like OutOfMemoryError: Java heap space when cloning large Git
repositories, edit your MATLAB preferences to increase the heap size.
See Also
Related Examples
• “Configure MATLAB to Use Git SSH Authentication” on page 35-14
• “Commit Modified Project Files” on page 33-66
33-59
33 Projects
Projects integrate with two source control systems, Git and Subversion (SVN).
Then, when your project is under source control, you can perform operations from within MATLAB
such as checking files in and out, running checks, and committing and reverting changes.
Create a new local copy of a project from an existing repository by retrieving files from source
control. You can clone a Git repository, or check out files from an SVN repository, or use another
source control integration.
1 On the Home tab, click New > Project > From Git or New > Project > From SVN. The New
Project From Source Control dialog box opens.
2 If you know your repository location, paste it into the Repository path field.
Otherwise, to browse for and validate the repository path to retrieve files from, click Change.
a In the dialog box, specify the repository URL by entering or pasting a URL into the field, by
33-60
Use Source Control with Projects
4 Click Retrieve.
If your repository already contains a project, the project is ready when the tool finishes retrieving
files to your selected sandbox folder.
If your sandbox does not yet contain a project, then a dialog box asks whether you want to create
a project in the folder. To create a project, specify a project name and click OK. The Welcome
screen appears to help you set up your new project. For more information about setting up a
project, see “Set Up Project” on page 33-3.
If you encounter errors like OutOfMemoryError: Java heap space when cloning large Git
repositories, edit your MATLAB preferences to increase the heap size.
If you have an existing project, you can add it to Git or SVN source control.
1 On the Project tab, in the Source Control section, click Use Source Control. The Source
Control Information dialog box opens.
2 Click the Add Project to Source Control button. The Add to Source Control dialog box opens.
3 In the Source control tool list, select the right tool for your repository. If you choose Git, then
skip step 4 and go straight to step 5.
4
If you are using an SVN remote repository, to specify an existing repository, click the button
to browse for your repository, paste a URL into the field, or use the list to select a recent
repository.
Click Validate to check the path to the selected repository, and then click OK.
5 Click Convert to finish adding the project to source control.
The project displays details of the current source control tool and the repository location.
7 If you created a new repository, select the Files > Modified view and click Commit to commit
the first version of your files to the new repository. In the dialog box, enter a comment if you
want, and click Submit.
If you want to merge branches with Git, you need to follow additional setup steps. For more
information, see “Set Up Git Source Control” on page 35-13.
If you want to use a version of SVN other than the built-in version, see “Set Up SVN Source Control”
on page 35-27.
33-61
33 Projects
If you create a new project from a folder that is already under source control, MATLAB automatically
adds the new project to source control. For more information about creating a project from a folder,
see “Create Projects” on page 33-2.
Creating a GitHub repository adds Git source control to your new or existing project. The GitHub
repository you create becomes the project remote repository. To create a GitHub repository, you must
have a GitHub account.
1 On the Home tab, click New > Project > From Git.
2 Select New > GitHub Repository. In the GitHub dialog box, enter your User name and
Personal access token. Fill the Repository name and Description fields and click Create.
MATLAB creates a new public GitHub repository and populates the Repository path field with
information in the https://github.com/myusername/mynewrepository format.
3 In the Sandbox field, specify the location for your sandbox. The selected folder must be empty.
Click Retrieve to create the sandbox.
After creating the GitHub repository and sandbox, add your files to the sandbox. Commit the first
version of your files to your local repository, then push all modifications to your remote GitHub
repository. For more information, see “Use Git in MATLAB” on page 35-5.
Tip If you want to create a remote GitHub repository for an existing project, share your project to
GitHub instead.
With your project loaded, on the Project tab, select Share > GitHub. For detailed instructions, see
Publish on GitHub in “Share Projects” on page 33-35.
This table shows how to check for modified project files, update revisions, get and manage file locks,
and tag project files.
Action Procedure
Refresh status of project files. To check for locally modified files, on the Project tab, in the
Source Control section, click Refresh. Refreshing queries the
local sandbox state and checks for changes made with another tool
outside of MATLAB.
33-62
Use Source Control with Projects
Action Procedure
Check for modifications in To find out if there is a new version of the project in the repository,
project files. in the Files view, right-click the file and select Source Control >
Check for Modifications.
With SVN, this option contacts the repository to check for external
modifications. The project compares the revision numbers of the
local file and the repository version. If the revision number in the
repository is larger than that in the local sandbox folder, then the
project displays (not latest) next to the revision number of the local
file.
Update all project files. Using SVN, to get the latest changes of all project files, go to the
Project tab, and in the Source Control section, click Update. The
project displays a dialog box listing all the files that have changed
on disk. You can control this behavior using the project preference
Show changes on source control update. For more information,
see “Work with Files Under SVN in MATLAB” on page 35-32.
Using Git, to get the latest changes for all project files from a
source control repository and merge them into your current
branch, go to the Project tab, and in the Source Control section,
click Pull. To get changes and merge manually, on the Project tab,
in the Source Control section, click Fetch. This updates all of the
origin branches in the local repository. When you click Fetch, your
sandbox files are not changed. To see the changes from others,
merge in the origin changes to your local branches. For more
information, see “Use Git in MATLAB” on page 35-5.
Update revision for selected To update a selected set of files, in the Files view, right-click the
project files. files, and select the Source Control > Update command for the
source control system you are using. For example, if you are using
SVN, select Source Control > Update from SVN to get fresh
local copies of the selected files from the repository.
Clear SVN login information. To clear any stored login credentials, on the Project tab, in the
Source Control section, click Clear Login.
Get SVN file locks. To get SVN file locks, in the Files view, select the files that you
want to check out. Right-click the selected files and select Source
Control > Get File Lock. A lock symbol appears in the SVN
source control column. Other users do not see the lock symbol in
their sandboxes, but they cannot get a file lock or check in a
change when you have the lock. To view or break locks, on the
Project tab, click Locks.
Get File Lock is only for SVN. Git does not have locks.
Manage SVN repository locks. To manage global SVN locks for a repository, on the Project tab, in
the Source Control section, click Locks. For more information,
see “Get SVN File Locks” on page 35-36.
33-63
33 Projects
Action Procedure
Tag versions of project files. To identify specific revisions of all project files, on the Project tab,
in the Source Control section, click Tag. Specify the tag text and
click OK. The tag is added to every project file. Errors appear if
you do not have a tags folder in your repository. For more
information, see “Set Up SVN Source Control” on page 35-27.
You can review changes in project files using the Files > Modified view. This table shows how to
view the list of modified project files, review the history of a file, and compare two files' revisions.
Action Procedure
View modified project files. In the Files view, select the Modified (number of files) tab. The
Files > Modified view is visible only if you are using source
control with your project.
Tip Use the List layout to view files without needing to expand
folders.
33-64
Use Source Control with Projects
The files in the resources/project folder are project definition files generated when you first
create or make changes to your project. The project definition files enable you to add project
metadata to files without checking them out. Some examples of metadata you can change this way
are shortcuts, labels, and project descriptions. Project definition files also specify the files added to
your project. These files are not part of the project.
Any changes you make to your project generate changes in the resources/project folder. These
files store the definition of your project in XML files whose format is subject to change.
You do not need to view project definition files directly, except when the source control tool requires a
merge. The files are shown so that you know about all the files being committed to the source control
system.
Starting in R2020b, the default project definition file type is Use multiple project files (fixed-path
length). To change the project definition file management from the type selected when the project
was created, use matlab.project.convertDefinitionFiles.
matlab.project.convertDefinitionFiles preserves the source control history of your project.
Warning To avoid merge issues, do not convert the definition file type more than once for a project.
For releases before R2020b, if you want to change the project definition file management from the
type selected when the project was created:
1 On the Home tab, in the Environment section, click Preferences. Select MATLAB > Project
and in the New Projects section, select one of the options under Project definition files:
• Use multiple project files - Helps to avoid file conflicts when performing merge on shared
projects
• Use multiple project files (fixed-path length) - Is better if you need to work with long
paths
• Use a single project file (not recommended for source control) - Is faster but is likely to
cause merge issues when two users submit changes in the same project to a source control
tool
2 Create a project archive file (.mlproj). For more information, see “Share Projects” on page 33-
35 or export.
3 Create a new project from the archived project. For more information, see “Create Projects” on
page 33-2.
To stop managing your folder with a project and delete the resources/project folder, see
matlab.project.deleteProject.
To run checks for a project, on the Project tab, click the down arrow to expand the Tools gallery.
Under Project Checks, click Check Project. The project checks for problems with project integrity
such as missing files, unsaved files, or files not under source control. A dialog box reports the results.
You can click for details and follow prompts to fix problems.
If you want to check for required files, click Dependency Analyzer to analyze the dependencies of
the modified files. Use the dependency tools to analyze the structure of your project.
33-65
33 Projects
For details on problems the checks can fix, see “Work with Derived Files in Projects” on page 33-68,
and “Analyze Project Dependencies” on page 33-42.
After reviewing changes and running project checks, you are ready to commit your modified project
files to source control. This table shows how to commit modified project files.
Action Procedure
Commit all modified files to In the Files view, select the Modified (number of files) tab. On
source control. the Project tab, in the Source Control section, click Commit.
Enter comments in the dialog box, and click Submit. If you are
using Git source control, this commits to your local repository. If
you are using SVN source control, this commits changes to your
repository.
If you commit individual files, you risk not committing the related
project definition files that keep track of your files. To avoid this,
commit all modified files.
Push project files with Git. To send local commits to the remote repository, on the Project tab,
in the Source Control section, click Push. A message appears if
you cannot push your changes directly because the repository has
moved on. Click Fetch to fetch all changes from the remote
repository. Merge branches and resolve conflicts, and then you can
push your changes. For more information, see “Use Git in
MATLAB” on page 35-5.
Push empty project folders with You cannot add empty folders to Git source control, so you cannot
Git. click Push and then clone an empty folder. You can create an
empty folder in a project, but if you push changes and then sync a
new sandbox, the empty folder does not appear in the new
sandbox. Instead, run Check Project, which creates the empty
folder for you.
33-66
Use Source Control with Projects
Action Procedure
Create a branch with Git. To create a branch, on the Project tab, in the Source Control
section, click Branches. The Branches dialog box appears, where
you can view, switch, create, and merge branches.
Select a source for the new branch. Click a node in the Branch
Browser diagram, or enter a unique identifier in the Source text
box. You can enter a tag, branch name, or a unique prefix of the
SHA1 hash (for example, 73c637) to identify a specific commit.
Leave the default values to create a branch from the head of the
current branch. Enter a name in the Branch name text box and
click Create.
Switch, compare, save, and To switch, compare, save, and merge branches, on the Project tab,
merge branches with Git. in the Source Control section, click Branches. The Branches
dialog box appears, where you can view, switch, create, and merge
branches. For more information, see “Branch and Merge with Git”
on page 35-21.
Resolve conflicts. If you and another user change the same file in different sandboxes
or on different branches, a conflict message appears when you try
to commit your modified files. Extract conflict markers if
necessary, compare the differences causing the conflict, and
resolve the conflict. If you have several conflicted files, see
“Determine Order for Resolving Conflicts Using Dependency
Analyzer” on page 33-19.
Look for conflicted files in the Files > Modified view. Identify
conflicted folder contents using the source control summary
status. Folders display the rolled-up source control status. This
makes it easier to locate changes in files, particularly conflicted
files. You can hover over the source control status for a folder to
view a tooltip displaying how many files inside are modified,
conflicted, added, and deleted.
Tip Use the List layout to view files without needing to expand
folders.
Check the source control status column (Git or SVN) for files with
a red warning symbol, which indicates a conflict. Right-click the
conflicted file and select View Conflicts to compare versions. A
comparison report opens showing the differences between the
conflicted files.
When you have resolved the changes and want to commit the
version in your sandbox, right-click the file and select Source
Control > Mark Conflict Resolved.
For Git, the Branch status in the Git pane changes from
MERGING to SAFE.
33-67
33 Projects
Revert Changes
This table shows how to revert changes in project files. For more information about reverting
changes, see “Commit or Revert Changes to Modified Files under SVN Source Control” on page 35-
34 and “Use Git in MATLAB” on page 35-5.
Action Procedure
Revert local changes. To release locks and revert to the version in the last sandbox
update (that is, the last version you synchronized or retrieved from
the repository), in the Files view, right-click the files to revert and
select Source Control > Discard Local Changes and Release
Locks.
In the Revert Files dialog box, choose a revision to revert to. Select
a revision to view information about the change, such as the
author, date, log message. Click Revert.
Once you have chosen a revision and are satisfied that the
information is correct, click Revert.
It is also a best practice to exclude derived files such as .mex*, the contents of the slprj folder,
sccprj folder, or other code generation folders from source control, because they can cause
problems. For example:
33-68
Use Source Control with Projects
• With a source control system that can do file locking, you can encounter conflicts. If slprj is
under source control and you generate code, most of the files under slprj change and become
locked. Other users cannot generate code because of file permission errors. The slprj folder is
also used for simulation via code generation, so locking these files can have an impact on a team.
The same problems arise with binaries, such as .mex*.
• Deleting slprj is often required. However, deleting slprj causes problems such as “not a
working copy“ errors if the folder is under some source control tools (for example, SVN).
• If you want to check in the generated code as an artifact of the process, it is common to copy some
of the files out of the slprj cache folder and into a separate location that is part of the project.
That way, you can delete the temporary cache folder when you need to. Use the packNGo function
to list the generated code files, and use the project API to add them to the project with
appropriate metadata.
• The slprj folder can contain many small files. This can affect performance with some source
control tools when each of those files is checked to see if it is up-to-date.
In the Unsaved Changes dialog box, you can see the project files with unsaved changes. Project only
detects unsaved changes edited in the MATLAB and Simulink editors. Manually examine changes
edited in other tools. If you have referenced projects, files are grouped by project. You can save or
discard all detected changes.
To control this behavior, on the Home tab, in the Environment section, click Preferences. Go to
MATLAB > Project and in the Project Shutdown section, select or clear the check box labeled
Check for open project models and close them, unless they are dirty.
See Also
More About
• “Source Control Integration in MATLAB” on page 35-2
• “Set Up Git Source Control” on page 35-13
• “Use Git in MATLAB” on page 35-5
• “Set Up SVN Source Control” on page 35-27
33-69
33 Projects
This example shows how to use the command line to automate project tasks for manipulating files.
The example covers how to create a referenced project existing project files, set up the project path,
and define project shortcuts. It also shows how to work with modified files, dependencies, and labels.
The Times Table App example project is under Git™ source control. To create a project object, use
currentProject or openProject.
mainProject = openProject("TimesTableApp");
files = mainProject.Files
Use indexing to access files in this list. For example, get file number 9. Each file has properties
describing its path and attached labels.
mainProject.Files(9)
ans =
ProjectFile with properties:
Path: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\T
Revision: "23397356ea2734fa2e269ea867e783cd71a702b5"
SourceControlStatus: Unmodified
Labels: [1x1 matlab.project.Label]
mainProject.Files(9).Revision
ans =
"23397356ea2734fa2e269ea867e783cd71a702b5"
mainProject.Files(9).Labels
ans =
Label with properties:
File: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\TimesTab
DataType: "none"
Data: []
33-70
Create and Edit Projects Programmatically
Name: "Test"
CategoryName: "Classification"
myfile = findFile(mainProject,"source/timestable.mlapp")
myfile =
ProjectFile with properties:
Path: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\T
Revision: "23397356ea2734fa2e269ea867e783cd71a702b5"
SourceControlStatus: Unmodified
Labels: [1x1 matlab.project.Label]
Create the Times Table Game project. This project will store the game logic behind the Times Table
App. The Times Table Game project will be used by the Times Table App project through a project
reference.
timesTableGameFolder = fullfile(mainProject.RootFolder,"refs","TimesTableGame");
timesTableGame = matlab.project.createProject(timesTableGameFolder);
timesTableGame.Name = "Times Table Game";
Move the Times Table App game logic from the main project folder to the new project folder, and add
it to the Times Table Game project. Then, remove the file from the Times Table App project.
movefile("../../source/timesTableGame.m");
addFile(timesTableGame,"timesTableGame.m");
reload(mainProject);
removeFile(mainProject,"source/timesTableGame.m");
Add the Times Table Game project root folder to the Times Table Game project path. This makes the
timesTableGame.m file available when the Times Table App project or any project that references
the Times Table App project is loaded.
reload(timesTableGame);
addPath(timesTableGame,timesTableGame.RootFolder);
Add the new Times Table Game project to the Times Table App project as a project reference. This
allows the Time Table App project to view, edit, and run files in the Times Table Game project.
reload(mainProject);
addReference(mainProject,timesTableGame);
Get all the modified files in the Times Table App project. Compare this list with the Files > Modified
view in the project. You can see the files for the new Times Table Game project, as well as the
removed and modified files in the Times Table App project.
33-71
33 Projects
modifiedfiles = listModifiedFiles(mainProject)
Get the second modified file in the list. Observe that the SourceControlStatus property is Added.
The listModifiedFiles function returns any files that are added, modified, conflicted, deleted,
and so on.
modifiedfiles(2)
ans =
ProjectFile with properties:
Path: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\T
Revision: ""
SourceControlStatus: Added
Refresh the source control status before querying individual files. You do not need to do this before
calling listModifiedFiles.
refreshSourceControl(mainProject)
Get all the project files that are Unmodified. Use the ismember function to get an array of logicals
stating which files in the Times Table App project are unmodified. Use the array to get the list of
unmodified files.
unmodifiedStatus = ismember([mainProject.Files.SourceControlStatus],matlab.sourcecontrol.Status.U
mainProject.Files(unmodifiedStatus)
Run a dependency analysis to update the known dependencies between project files.
updateDependencies(mainProject)
Get the list of dependencies in the Times Table App project. The Dependencies property contains
the graph of dependencies between project files, stored as a MATLAB digraph object.
g = mainProject.Dependencies
g =
digraph with properties:
33-72
Create and Edit Projects Programmatically
Get the top-level files of all types in the graph. The indegree function finds all the files that are not
depended on by any other file.
top = g.Nodes.Name(indegree(g)==0)
Get the top-level files that have dependencies. The indegree function finds all the files that are not
depended on by any other file, and the outdegree function finds all the files that have dependencies.
Find impacted (or "upstream") files by creating a transposed graph. Use the flipedge function to
reverse the direction of the edges in the graph.
transposed = flipedge(g)
transposed =
digraph with properties:
impacted = bfsearch(transposed,which('source/timestable.mlapp'))
Get information on the project files, such as the number of dependencies and orphans.
33-73
33 Projects
averageNumDependencies = mean(outdegree(g));
numberOfOrphans = sum(indegree(g)+outdegree(g)==0);
Change the sort order of the dependency graph to show project changes from the bottom up.
ordered = g.Nodes.Name(flip(toposort(g)));
Query Shortcuts
You can use shortcuts to save frequent tasks and frequently accessed files, or to automate startup and
shutdown tasks.
shortcuts = mainProject.Shortcuts
shortcuts(2)
ans =
Shortcut with properties:
shortcuts(3).File
ans =
"C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\TimesTableApp\utilities\op
{shortcuts.File}'
Label Files
Create a new category of labels of type char. In the Times Table App project, the new Engineers
category appears in the Labels pane.
createCategory(mainProject,'Engineers','char')
33-74
Create and Edit Projects Programmatically
ans =
Category with properties:
SingleValued: 0
DataType: "char"
Name: "Engineers"
LabelDefinitions: [1x0 matlab.project.LabelDefinition]
category = findCategory(mainProject,'Engineers');
createLabel(category,'Bob');
ld = findLabel(category,'Bob')
ld =
LabelDefinition with properties:
Name: "Bob"
CategoryName: "Engineers"
Attach a label to a project file. If you select the file in the Times Table App project, you can see this
label in the Label Editor pane.
myfile = findFile(mainProject,"source/timestable.mlapp");
addLabel(myfile,'Engineers','Bob');
label = findLabel(myfile,'Engineers','Bob');
label.Data = 'Email: Bob.Smith@company.com'
label =
Label with properties:
File: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\TimesTab
DataType: "char"
Data: 'Email: Bob.Smith@company.com'
Name: "Bob"
CategoryName: "Engineers"
mydata = label.Data
mydata =
'Email: Bob.Smith@company.com'
Create a new label category with data type double, the type MATLAB commonly uses for numeric
data.
createCategory(mainProject,'Assessors','double');
category = findCategory(mainProject,'Assessors');
createLabel(category,'Sam');
33-75
33 Projects
Attach the new label to a specified file and assign data value 2 to the label.
myfile = mainProject.Files(10);
addLabel(myfile, 'Assessors', 'Sam', 2)
ans =
Label with properties:
File: "C:\TEMP\Bdoc24b_2855429_12644\ib503FBD\2\tpd1cdea0e\matlab-ex45698718\TimesTab
DataType: "double"
Data: 2
Name: "Sam"
CategoryName: "Assessors"
Close Project
Close the project to run shutdown scripts and check for unsaved files.
close(mainProject)
See Also
currentProject
More About
• “Create Projects” on page 33-2
• “Manage Project Files” on page 33-21
• “Analyze Project Dependencies” on page 33-42
33-76
Explore an Example Project
This example opens the Times Table App example project to explore how project tools can help you
organize your work.
1 Set up and browse some example project files under source control.
2 Examine project shortcuts to access frequently used files and tasks.
3 Analyze dependencies in the project and locate required files that are not yet in the project.
4 Modify some project files, find and review modified files, compare them to an earlier version, and
commit modified files to source control.
5 Explore views of project files only, modified files, and all files under the project root folder.
You can view, search, and sort project files by using the Files view.
To view the files in the project, in the Files view, click Project (number of files). When the view
is selected, only the files in your project are shown.
To see all the files in your project folder, click All. This view shows all the files that are under the
project root, not just the files that are in the project. As a result, this view is useful for adding files to
the project.
To view files as a list instead of a tree, in the Layout field at the top right of the Files view, select
List.
• To search for particular files or file types by name, in any file view, type in the search box or click
the Filter button. For example, in the search field, enter the text timestable. The project
returns all files and folders that contain the word timestable. Click the to clear the search.
• To search the content of files, go to the Project tab and click the Search button. Enter a value in
the search field and click Enter. For example, enter the word tests. The project displays all files
and folders that contain the word tests. Click the to clear the search.
•
To change how files are grouped or sorted, and to customize the columns, click the actions
button and select from the available options.
You can use shortcuts to make files easier to find in a large project. View and run shortcuts on the
Project Shortcuts tab. You can organize the shortcuts into groups.
The Times Table App project contains several shortcuts, including a shortcut to open the project
requirements, and another to run all the tests in the project. The shortcuts make these tasks easier
for users of the project.
33-77
33 Projects
To perform an action, on the Project Shortcuts tab, click the associated shortcut. For example, to
open project requirements, click Documentation > Requirements. To run tests, click Test > Run
All Tests.
To create a new shortcut, select the Files view, right-click a file, and select Create Shortcut.
Create a new folder and add it to the project path. Adding a project folder to the project path ensures
that all users of the project can access the files within it.
1 Select the Files view.
2 Right-click in white space and then select New > Folder. Enter a name for the folder. The folder
is automatically added to the project.
3 Right-click the new folder and select Project Path > Add to the Project Path (Including
Subfolders).
* Note - When you open the Times Table App example project, the project shows a modified file in the
resources folder. This is a side effect of opening the example project. When editing files in your own
projects, only changes that affect file metadata, such as adding a label to a file, create modified files
in the resources folder.
Analyze Dependencies
To check that all required files are in the project, run a file dependency analysis on the modified files.
1 On the Project tab, click the down arrow to expand the Tools gallery. Under Apps, click
Dependency Analyzer.
2 The dependency graph displays the structure of all analyzed dependencies in the project. The
right pane lists required add-ons and any problem files. Observe that there are no problem files
listed.
Now, remove one of the required files. Select the project Files view, right click the source/
timesTableGame.m file, and select Remove from Project. Click Remove in the Remove from
Project dialog box.
The Dependency Analyzer automatically updates the graph and the Problems section in the
Properties pane.
33-78
Explore an Example Project
1 In the Dependency Analyzer, in the Properties pane, point to the problem message, Not in
project, under Problems and click the magnifying glass . The graph updates to highlight the
problem file, timesTableGame.m.
2 To view the dependencies of the problem file, in the Impact Analysis section, click All
Dependencies.
Now that you have seen the problem, fix it by returning the missing file to the project. Right-click the
file and select Add to Project. The next time you run a dependency analysis, the file does not appear
as a problem file.
After running a dependency analysis, to investigate the dependencies of modified files, perform an
impact analysis.
1 In the Views section, click Source Control. The graph colors the files by source control status.
2 Select the modified files in the graph or in the File List.
3 To view the dependencies of the modified files, in the Impact Analysis section, click All
Dependencies.
To make sure that your changes are ready to commit, check your project. To run the project integrity
checks, on the Project tab, click the down arrow to expand the Tools gallery. Under Project Checks,
click Check Project. The checks look for missing files, files to add to source control or retrieve from
source control, and other issues. The Checks dialog box offers automatic fixes to problems found,
when possible. When you click a Details button in the Checks dialog box, you can view recommended
actions and decide whether to make the changes.
After you modify files and you are satisfied with the results of the checks, you can commit your
changes to the source control repository.
1 In the Files view, select the Modified (number of files) tab. The files you changed appear in
the list.
2 To commit your changes to source control, on the Project tab, in the Source Control section,
click Commit.
3 Enter a comment for your submission, and click Submit. Watch the messages in the status bar as
the source control commits your changes. In Git, you can have both local and remote
repositories. These instructions commit to the local repository. To commit to the remote
repository, in the Source Control section, click Push.
To view and edit project details, on the Project tab, in the Environment section, click Details. View
and edit project details such as the name, description, project root, startup folder, and location of
folders containing generated files.
To view details about the source control integration and repository location, on the Project tab, in
the Source Control section, click Git Details. The Times Table App example project uses Git source
control.
33-79
33 Projects
Click the at the top right corner of the project window to close the project.
See Also
More About
• “Create Projects” on page 33-2
• “Manage Project Files” on page 33-21
• “Analyze Project Dependencies” on page 33-42
33-80
Merge Git Branches and Resolve Conflicts Programmatically
This example shows how to use the MATLAB® source control API to create and merge branches, and
resolve conflicts.
repo=gitinit();
writelines("Questions?","README.md");
add(repo,"README.md");
Create Branches
Task1Branch = createBranch(repo,"Task1");
Task2Branch = createBranch(repo,"Task2");
On the Task1 branch, update the README file with the additional line "Contact
example@mailinglist.com". Then, commit the change.
switchBranch(repo,"Task1");
writelines("Contact example@mailinglist.com","README.md",WriteMode="append");
commit(repo,Message="Modify README in Task1 branch");
On the Task2 branch, update the README file with the additional line "Create an issue". Then,
commit the change.
switchBranch(repo,"Task2");
writelines("Create an issue","README.md",WriteMode="append");
commit(repo,Message="Modify README in Task2 branch");
Merge Branches
Merge the Task1 branch into the Task2 branch. The merge function reports that it cannot complete
the merge due to a conflict in the README file.
try
merge(repo,"Task1")
catch
% The merge function throws an expected error because this branch merge
% results in a conflict.
fprintf("Unable to merge Task1 into Task2.\n\nCaused by:\n" + ...
"Conflicted files: README.md\n\nResolve and " + ...
33-81
33 Projects
Caused by:
Conflicted files: README.md
edit README.md
Questions?
<<<<<<< HEAD
Create an issue
=======
Contact example@mailinglist.com
>>>>>>> ebc20d468cc6b8255130ccb2350b7d5db8d863f3
Resolve Conflict
Resolve the conflicts using the Comparison and Merge Tool or by editing the README file. For
instructions on how to resolve the conflict interactively, see “Merge Text Files”.
In this example, suppose you want to keep both changes. To keep both changes, simply delete the
conflict markers.
33-82
Merge Git Branches and Resolve Conflicts Programmatically
writelines("Questions?","README.md");
writelines("Contact example@mailinglist.com","README.md",WriteMode="append");
writelines("Create an issue","README.md",WriteMode="append");
Mark the conflict in the README file resolved using the add function. Then, commit the merge
resolution.
add(repo,"README.md")
commit(repo,Message="Resolve Conflict");
See Also
Related Topics
Related Examples
33-83
34
Packages
• “Organize and Distribute Code Using MATLAB Package Manager” on page 34-2
• “Find and Install Packages” on page 34-5
• “Create and Manage Packages” on page 34-8
• “Distribute Packages Using Folder-Based Repositories” on page 34-11
• “Semantic Version Syntax for Packages” on page 34-14
34 Packages
The MATLAB Package Manager is a set of objects and functions for creating, finding, installing, and
managing MATLAB packages. After creating a package, you can distribute it to your end users by
adding it to a package repository.
If you instead want to install MATLAB, Simulink, and other MathWorks products or support packages,
see “Install Programmatically Using MATLAB Package Manager”.
What Is a Package?
A package is a collection of MATLAB code, related files, and a package definition file that defines the
package identity and dependencies. The purpose of a package is to compartmentalize code so that it
can be shared while maintaining its intended functionality. When installing a package, the MATLAB
Package Manager installs all of the code, supporting files, and any other packages that it depends on
and adds them to the path. For information on finding and installing packages, see “Find and Install
Packages” on page 34-5.
A package consists of a root folder, which contains the files and member folders of the package.
When installing a package, the MATLAB Package Manager adds the root folder and all member
folders to the path. The root folder contains a resources folder, which contains the package
definition file named mpackage.json file.
The package definition file contains identifying information, descriptive information, and package
properties. Identifying information can include the package name, version, and unique identifier.
Descriptive information can include a summary of the package purpose, its provider, and the MATLAB
release compatibility. The properties of a package can include its status, member folders, and any
dependencies.
For more information on the package definition file and how to manage package properties, see
“Create and Manage Packages” on page 34-8.
Package Dependencies
Some packages use code that is contained in a second package. These packages depend on the
second package, and the second package is referred to as a dependency. When installing a package,
the MATLAB Package Manager checks that all required dependencies are also installed. In this
diagram, package A depends on package B and package B depends on packages C and D. When
package A is installed, packages B, C, and D are installed as well.
34-2
Organize and Distribute Code Using MATLAB Package Manager
When uninstalling a package, the MATLAB Package Manager checks each of the package
dependencies and uninstalls them if they are unused. A dependency is considered unused if it was not
installed directly and no installed packages depend on it.
View the current list of known repositories using mpmListRepositories. Add and remove
repositories from the list of known repositories using mpmAddRepository and
mpmRemoveRepository. For more information, see “Distribute Packages Using Folder-Based
Repositories” on page 34-11.
See Also
Objects
matlab.mpm.Package
Functions
mpmcreate | mpminstall | mpmuninstall | mpmsearch | mpmlist | mpmAddRepository |
mpmListRepositories | mpmRemoveRepository
34-3
34 Packages
Related Examples
• “Find and Install Packages” on page 34-5
• “Create and Manage Packages” on page 34-8
• “Distribute Packages Using Folder-Based Repositories” on page 34-11
• “Semantic Version Syntax for Packages” on page 34-14
34-4
Find and Install Packages
You can use the MATLAB Package Manager to find and install packages. This example shows how to
find an install a package with tools related to astronomy.
Find Package
You can search for packages in the list of known repositories by using the mpmsearch function. (To
learn more about how to add a repository to this list, see “Distribute Packages Using Folder-Based
Repositories” on page 34-11.)
For example, find packages that might be related to astronomy by searching with the keyword
"astro".
mpmsearch("astro")
Install Package
Once you find the package you want, you can install it using the mpminstall function. The function
displays a confirmation prompt before installing the package.
For example, after identifying the astronomy package in the search results as the package you want,
install it.
mpminstall("astronomy")
The prompt lists more than one package to be installed because the astronomy package depends on
three additional packages: astrophysics, physics, and LinearAlgebra. Respond YES to the
prompt to confirm the installation of astronomy and its required dependencies.
34-5
34 Packages
astrophysics (help)
LinearAlgebra (help)
Installation complete.
Then display the currently installed packages by using the mpmlist function.
mpmlist
• The package identifier matches the specified package name or ID. Package names are matched
case-insensitively.
• The version is compatible with the specified version range.
• The ReleaseCompatibility property value is compatible with the MATLAB release being used.
MATLAB searches each repository on the known repository list in order. If a repository has multiple
packages that meet these conditions, then MATLAB selects the package with the latest semantic
version. Once a package that meets the conditions has been found, other repositories on the list of
known repositories are not searched.
For each required dependency, MATLAB determines if a package matching the dependency package
ID and a version compatible with the package version range is already installed or on the install list.
If so, MATLAB skips the dependency and advances to the next required dependency. If not, MATLAB
searches the known repositories for the dependency package following the same process as for the
original package.
If installed dependencies have their own dependencies, MATLAB follows the same process recursively
until it finds and installs all required packages.
During package installation, MATLAB creates a folder in the installation area named for the package
name, version, and ID. The folder name can be truncated or modified to comply with the naming
conventions of the local file system.
34-6
Find and Install Packages
If the package source is a folder and the package InPlace property is true, then MATLAB does not
copy the package.
See Also
Objects
matlab.mpm.Package
Functions
mpmcreate | mpminstall | mpmuninstall | mpmsearch | mpmlist | mpmAddRepository |
mpmListRepositories | mpmRemoveRepository
Related Examples
• “Organize and Distribute Code Using MATLAB Package Manager” on page 34-2
• “Create and Manage Packages” on page 34-8
• “Distribute Packages Using Folder-Based Repositories” on page 34-11
• “Semantic Version Syntax for Packages” on page 34-14
34-7
34 Packages
Create Package
You can create a new package using the mpmcreate function. For example, to create a package
named MyPackage. Specify the package root folder. Any folders within the specified root folder
become member folders of the new package. If the specified location does not exist, the function
creates a new folder and an empty package. If the root folder does not contain a resources folder
the function creates one. The function adds the package definition file mpackage.json to the
resources folder.
pkg = mpmcreate("MyPackage","C:\MyCode\MyPackage");
When you create a package using mpmcreate, the package is installed in place. In other words, the
installed package files and folders are located in the specified folder, not in the default installation
area.
Newly created packages have their Editable property set to true. So, you can change package
properties, and the package definition file updates accordingly.
pkg = mpminstall("MyPackage",Authoring=true);
For additional information about finding and installing packages, see “Find and Install Packages” on
page 34-5.
When you make changes to an installed package, it is recommended that you update the version of
the package to support backward compatibility. When installing a package, the mpminstall function
copies the metadata stored in the package definition file mpackage.json and stores it. Changes to
mpackage.json do not affect installed packages unless the package is in editable mode.
When a package is in editable mode, the package definition file can change when you change the
properties of the matlab.mpm.Package object corresponding to that package. The MATLAB
34-8
Create and Manage Packages
Package Manager automatically updates the package definition file mpackage.json according to the
changes you make to the package object properties. For example, add a description to MyPackage by
editing the Description property on the package object pkg.
pkg.Description = "This is my first package"
pkg =
Package Definition
Name: "MyPackage"
DisplayName: "MyPackage"
Version: 1.0.0 (1×1 Version)
Summary: ""
Description: "This is my first Package"
Provider: <missing>
Folders: [1×0 PackageFolder] (1×0 PackageFolder)
Dependencies: ""
ReleaseCompatibility: "*"
FormerNames: ""
ID: "cabe1581-671d-40a2-8137-2b17847a9c65"
Package Installation
Installed: 1
Editable: 1
InstalledAsDependency: 0
PackageRoot: "C:\MyCode\MyPackage"
InstalledDependencies: ""
MissingDependencies: ""
Repository
Repository: [0×0 Repository]
help MyPackage
For example, create a subfolder in MyPackage named NewFolder and add it to the package.
mkdir("MyPackage/NewFolder")
addFolder(pkg,"NewFolder")
You can remove member folders from the package and its definition file by using the removeFolder
function. The function removes the folder from mpackage.json but does not delete the folder or its
contents. Subfolders in a package that are not included in the package definition file are not added to
the path when the package is installed.
34-9
34 Packages
You can add dependencies to a package using the addDependency function, and the MATLAB
Package Manager updates the package definition file accordingly. When installing a package, the
MATLAB Package Manager also installs package dependencies by default.
addDependency(pkg,"MyOtherPackage")
You can remove dependencies from a package and its definition file by using the removeDependency
function. The function removes dependencies from the package but does not uninstall them. You can
update the version of an existing dependency by using the updateDependency function.
If you want to make MyPackage available to other users, add it to a repository. For more information
about sharing packages, see “Distribute Packages Using Folder-Based Repositories” on page 34-11.
See Also
Objects
matlab.mpm.Package
Functions
mpmcreate | mpminstall | mpmuninstall | addFolder | removeFolder | addDependency |
removeDependency | updateDependency
Related Examples
• “Organize and Distribute Code Using MATLAB Package Manager” on page 34-2
• “Find and Install Packages” on page 34-5
• “Distribute Packages Using Folder-Based Repositories” on page 34-11
• “Semantic Version Syntax for Packages” on page 34-14
34-10
Distribute Packages Using Folder-Based Repositories
For example, create a package named MyPkg from the folder PkgRootDir and then add it to the
repository located at C:\MyCode\MyRepository.
pkg = mpmcreate("MyPkg","PkgRootDir")
copyfile("PkgRootDir","C:\MyCode\MyRepository")
Then, end users can install the package from the repository.
mpminstall("MyPkg")
For more information about searching for and installing packages, see “Find and Install Packages” on
page 34-5.
repo = mpmAddRepository("MyRepo","C:\MyCode\MyRepository")
repo =
Name: "MyRepo"
Location: "C:\MyCode\MyRepository"
By default, the function adds repositories to the end of the MATLAB repository list. You can add a
repository to the top or the bottom of the list using the optional Position argument. For example,
add the repository to the beginning of the list.
repo = mpmAddRepository("MyRepo","C:\MyCode\MyRepository",Position="begin")
When the MATLAB Package Manager searches for or installs packages, it checks repositories in order
from the beginning of the list to the end. If the MATLAB Package Manager finds a package that meets
the requirements in a repository, then no further repositories are checked. For additional information,
see “Package Resolution During Installation” on page 34-6.
34-11
34 Packages
mpmListRepositories
Name Location
_____________ _______________________________
"MyRepo" "C:\MyCode\MyRepository"
"SharedRepo" "M:\SharedCode\SharedRepository"
"DepartmentRepo" "Z:\Astro\PackageRepo"
mpmRemoveRepository("C:\MyCode\MyRepository")
mpmListRepositories
Name Location
_____________ _______________________________
"SharedRepo" "M:\SharedCode\SharedRepository"
"DepartmentRepo" "Z:\Astro\PackageRepo"
Additionally, you can provide package checksums to end users of the repository to help detect
package tampering. Use digest to compute the SHA-256 digests of the packages in the repository,
and distribute those digests to end users alongside the packages or through some other secure
distribution channel, such as a secure website.
pkg = mpmlist("MyPackage");
SHA = digest(pkg)
SHA =
"ab0863fa6a1eeb0fade092abd583323bee73d1dd5ce4a74aa031e4995ae2bb79"
When installing a package, use mpminstall with the option Verbosity="detailed". mpminstall
recomputes and displays the current digest value for each installed package.
mpminstall("MyPackage",Verbosity="detailed")
34-12
Distribute Packages Using Folder-Based Repositories
If this value does not match the originally computed digest value, the package has been altered.
Cancel the installation by responding “no” at the “Do you want to continue?” prompt. Report any
discrepancies to the administrator of the shared repository.
Finally, it is recommended that a secure backup be maintained of the files in the repository, to
facilitate restoration of the original files in the event that tampering is detected.
See Also
Objects
matlab.mpm.Package | matlab.mpm.Repository
Functions
mpmAddRepository | mpmListRepositories | mpmRemoveRepository | digest
Related Examples
• “Organize and Distribute Code Using MATLAB Package Manager” on page 34-2
• “Find and Install Packages” on page 34-5
• “Create and Manage Packages” on page 34-8
• “Semantic Version Syntax for Packages” on page 34-14
34-13
34 Packages
Semantic Versions
Version syntax follows the Semantic Versioning 2.0.0 standard where versions are presented in the
following format: <Major Version>.<Minor Version>.<Patch Version> where each version
number must be a non-negative integer, for example 1.2.3. Pre-release status is optional and is
specified by adding -<pre-release version> to the end of the version range, for example 1.2.3-
alpha. A specific build is optional and specified by adding +<build version>.
1.0.0
1.2.3-alpha
1.2.3-alpha+exp
3.5.1+latest
Version Ranges
In some cases, such as for package dependencies, a range of versions can be specified. A version
range can include the <, <=, >, or >= operators in front of a version number. For example >2.1.13
would specify all versions greater than 2.1.13. Multiple ranges separated by whitespace can be
specified to further limit matches. For example, >2.1.13 <=2.1.15 would include versions 2.1.14
and 2.1.15 but would not include 2.1.13 or 2.1.16. Use the || operator to designate multiple
acceptable version ranges. For example, <2.1.13 || >2.1.15 would include versions less than
2.1.13 and greater than 2.1.15 but would not include 2.1.14.
>2.1.13
>2.1.13 <=2.1.15
<2.1.13 || >2.1.15
34-14
Semantic Version Syntax for Packages
See Also
Objects
matlab.mpm.Package
Checks
mpmcreate | mpminstall | mpmuninstall | mpmsearch | mpmlist | mpmAddRepository |
mpmListRepositories | mpmRemoveRepository
Related Examples
• “Organize and Distribute Code Using MATLAB Package Manager” on page 34-2
• “Find and Install Packages” on page 34-5
• “Create and Manage Packages” on page 34-8
• “Distribute Packages Using Folder-Based Repositories” on page 34-11
34-15
35
The source control interface provides access to your source control system from MATLAB.
• To get started using Git source control in MATLAB see “Use Git in MATLAB” on page 35-5.
• To get started using SVN source control, see “Work with Files Under SVN in MATLAB” on page
35-32.
• To integrate other source control tools such as Perforce with MATLAB, you can write a source
integration using the Software Development Kit (SDK) available on File Exchange. For more
information, see “Write a Source Control Integration with the SDK” on page 35-55.
See Also
Related Examples
• “Use Git in MATLAB” on page 35-5
• “Set Up SVN Source Control” on page 35-27
• “Write a Source Control Integration with the SDK” on page 35-55
35-2
Set Source Control Preferences
MathWorks source control integration, accessible through Projects and the Current Folder browser, is
enabled by default.
To disable source control, on the Home tab, in the Environment section, click Preferences. Select
MATLAB > General > Source Control and click None.
When you disable source control, MATLAB does not destroy repository information. For example, it
does not remove the .svn folders.
On the Home tab, in the Environment section, click Preferences. Select MATLAB > Source
Control. Then, set your preferences.
To set Git-specific source control preferences, see “Set Git Preferences in MATLAB Online” on page
35-3.
Preference Usage
New Working Folder When you interactively clone or check out a working copy from a
repository, by default, MATLAB Online downloads files into the currently
opened folder. To use a folder of your choice, select Use specified folder
and specify the folder by using the browser or pasting the path.
Source Control Integrations In MATLAB Online, MathWorks source control integration, accessible
through Project browser and the Current Folder browser, is enabled by
default.
When you disable source control, MATLAB Online does not destroy
repository information. For example, it does not remove the .svn
and .git folders.
If you want to use other source control tools such as Perforce® P4V with
MATLAB instead of the built-in source control integration, write your own
source integration using the Software Development Kit (SDK) available on
File Exchange and make sure you select Enable 3rd-party source
control integrations (requires Java). For more information, see “Write
a Source Control Integration with the SDK” on page 35-55.
In MATLAB Online, you can use the Git source control preferences to specify your username and
email, remember credentials for the current MATLAB session, and enable SSH authentication.
35-3
35 Source Control Interface
On the Home tab, in the Environment section, click Preferences. Select MATLAB > Source
Control > Git. Then, set your preferences.
Preference Usage
User Specify your username and email in Name and Email. Doing so overrides
information you already specified in your global Git configuration file.
MATLAB Git integration is configured by default to Generate local
avatars using your initials. An avatar appears next to your username and
email in the Branch Manager.
If an SSH agent is running, MATLAB Online looks for keys in the agent
before using the keys you specified in Public key file and Private key
file.
Branch Manager To control the number of commits that the Branch Manager shows,
specify the Maximum number of commits to show.
See Also
More About
• “Use Git in MATLAB” on page 35-5
35-4
Use Git in MATLAB
Once you have cloned a remote Git repository, the basic workflow for working with the remote
repository is:
Alternatively, to track changes to your files without sharing with others, you can create a local Git
repository that is not synced with a remote repository. The same basic workflow applies when
working with a local repository that is not synced with a remote repository, except for the omission of
the Pull and Push actions.
Note Before using Git in MATLAB, to setup your system and avoid file corruption, follow the steps
described in “Set Up Git Source Control” on page 35-13.
1 In the Current Folder browser, right-click the white space and select Source Control > Manage
Files. MATLAB opens the Manage Files Using Source Control dialog box.
2 Set the Source control integration option to Git.
3 Click the Change button next to the Repository path field. MATLAB opens the Select a
Repository dialog box.
4 Enter the path to the remote repository.
35-5
35 Source Control Interface
5 Click the Validate button to check the remote repository path. If prompted, enter the login
information for the remote repository (for example, your GitHub user name and personal access
token). If the path is valid, click OK to select the remote repository and return to the Manage
Files Using Source Control dialog box.
6 In the Sandbox field, enter the path of the working folder in which to store the retrieved files.
The specified folder must be empty.
7 Click the Retrieve button. If prompted, enter the login information for the remote repository.
After cloning a remote repository, to change the path to the remote repository, right-click in the
working folder, select Source Control > Remote, and specify the new path.
To prevent frequent login prompts when you interact with your remote repository using HTTPS,
configure a Git credential manager to remember credentials. For more information, see “Manage Git
Credentials” on page 35-18. Alternatively, you can add a new public key and clone the remote
repository using SSH instead. For more information, see “Configure MATLAB to Use Git SSH
Authentication” on page 35-14.
You also can clone a remote repository into a new project. For more information, see “Clone Remote
Git Repository into New Project” on page 33-59.
To mark a file for addition, right-click the file in the Current Folder browser and select Source
Control > Add to Git. MATLAB indicates the file is marked for addition using the Added icon ( ).
Review Changes
When you make changes to a file in your working folder, MATLAB indicates that the file is modified
using the Modified icon ( ) in the Git column of the Current Folder browser. The Unmodified icon
( ) indicates that a file has no changes.
35-6
Use Git in MATLAB
Before committing a modified file, review the changes to the file using one of the methods described
in this table:
Action Procedure
Compare the changed file to the Right-click the file in the Current Folder browser and select
latest revision of the file in your Source Control > Compare to Ancestor. The Comparison Tool
local repository. displays the differences.
Compare the changed file to a Right-click the file in the Current Folder browser and select
revision of the file in your local Source Control > Compare to Revision. Then, select a revision
repository. to compare the modified file to and click the Compare to Local
button. The Comparison Tool displays the differences.
Compare two previous revisions Right-click the file in the Current Folder browser and select
of a file in your local repository. Source Control > Compare to Revision. Then, select the two
revisions to compare and click the Compare Selected button. The
Comparison Tool displays the differences.
Browse the revisions for a file in Right-click the file in the Current Folder browser and select
the local repository. Source Control > Show Revisions. You can view information
about who previously committed the file, when they committed it,
the log messages, and the list of files in each change set. You can
select multiple files and view revision history for each file.
If the remote repository has moved ahead, you are prompted to update the revision of your files. To
update the revision, right-click in the Current Folder browser and select Source Control > Pull.
Resolve any conflicts before you commit.
Push Files
If your local repository contains committed changes that are not in your remote repository, you can
push those changes to your remote repository. To check whether your local repository contains
changes that are not in your remote repository, right-click in the Current Folder browser and select
Source Control > View Details. The Git information field indicates whether your committed local
changes are ahead of, behind, or coincident with the remote repository.
If your local repository is ahead of your remote repository, to push the changes, right-click in the
Current Folder browser and select Source Control > Push. A message appears if you cannot push
your changes directly because the repository has moved on. To continue, pull the latest changes from
the remote repository into your local repository.
35-7
35 Source Control Interface
Git does not support empty folders in remote repositories. Therefore, if you create an empty folder in
MATLAB and push the changes to the remote repository, when you clone the remote repository into a
new local repository, the empty folder is not included. To push empty folders to the remote repository
for other users to use, create an empty gitignore file in the folder and then push your changes.
Pull Files
If your remote repository has moved on and your local repository is behind, you can pull the latest
changes into your local repository. To pull the latest changes, in the Current Folder browser, right-
click and select Source Control > Pull. Pull might fail if you have conflicts. With a complicated
change, consider creating a branch from the origin (local repository), making some changes, and then
merging that branch into the main tracking branch.
A pull action fetches the latest changes and merges them into your current branch. If you are not
sure what is going to come in from the repository, fetch the files first to examine the changes and
then merge the changes manually.
Fetch Files
To fetch the latest changes from your remote repository, in the Current Folder browser, right-click
and select Source Control > Fetch. Fetch updates all of the origin branches into your local
repository. Your working folder files do not change. To see the changes from the remote repository,
you must merge in the origin changes to your local branches.
To check whether your local repository contains fetched changes that need to be merged, right-click
in the Current Folder browser and select Source Control > View Details. The Git information
field indicates whether your committed local changes are ahead of, behind, or coincident with the
remote repository. If your committed local changes are behind, you need to fetch and merge in the
latest changes from the remote repository.
For example, if you are on the main branch, get all changes from the main branch in the remote
repository.
1 Right-click in the Current Folder browser and select Source Control > Fetch.
2 Right-click in the Current Folder browser and select Source Control > Branches.
3 In the Branches dialog box, select origin/main in the Branches list.
4 Click Merge. The origin branch changes merge into the main branch in your working folder.
To check whether the merge was successful, right-click in the Current Folder browser and select
Source Control > View Details. If the Git information field indicates Coincident with /
origin/main, the changes were merged successfully, and you can now view the changes that you
fetched and merged from the remote repository in your working folder.
Resolve Conflicts
If you and another user change the same file in different working folders or on different branches, a
conflict message appears when you try to commit your modified files. To resolve the conflict, compare
the differences causing the conflict and then merge or overwrite the conflicting changes. After
resolving the conflict, you can mark it resolved and commit the file.
MATLAB indicates conflicts in the Git column of the Current Folder browser with a red warning icon
( ). To resolve conflicts in a file:
35-8
Use Git in MATLAB
1 Right-click the conflicted file and select Source Control > View Conflicts. The Comparison Tool
opens and shows the differences between the two conflicting revisions of the file.
2 Use the Comparison Tool to determine how to resolve the conflicts. To merge changes between
the two revisions, see “Compare Files and Folders and Merge Files”.
3 After you have resolved the conflicts, in the Current Folder browser, right-click the file and select
Source Control > Mark Conflict Resolved.
4 Commit the modified files.
If you are working with files that are not registered as binary (text files, for example), Git might insert
conflict markers into those files. Conflict markers have this format:
You can use MATLAB to extract the conflict markers from a file before resolving the conflicts.
When you open a conflicted file or select View Conflicts, MATLAB checks the file for conflict
markers. If the file contains conflict markers, the Conflict Marker Found dialog box opens. Follow the
prompts to extract the conflict markers and fix the file.
To view the conflict markers, in the Conflict Markers Found dialog box, click Load File. Do not try to
open the file because MATLAB does not recognize conflict markers. Instead, click Fix File to extract
the conflict markers.
Files that do not have a conflict can still contain conflict markers. This situation can happen if a file
with conflicts is marked as resolved and committed to the local repository. If you see conflict markers
in a file that is not marked conflicted, you can extract the conflict markers manually.
1 In the Current Folder browser, right-click the file and select Source Control > Extract Conflict
Markers to File.
2 In the Extract Conflict Markers to File dialog box, ensure that the default option to copy "mine"
file version over the conflicted file and the Compare extracted files option are selected.
3 Click Extract.
4 Use the Comparison Tool to resolve any conflicts.
Manage Files
There are several actions that you can take to manage the files in your local Git repository from the
Current Folder browser. You can refresh the source control status of your files, as well as move,
rename, delete, and revert the files.
This table describes the actions that you can take to manage your files.
Action Procedure
Refresh source control status of In the Current Folder browser, select one or more files, right-click
one or more files and select Source Control > Refresh Git status.
35-9
35 Source Control Interface
Action Procedure
Refresh source control status of In the Current Folder browser, right-click the white space and
all files in local repository select Source Control > Refresh Git status.
Move file In the Current Folder browser, right-click the file, select Source
Control > Move, and enter a new file location.
Rename file In the Current Folder browser, right-click the file, select Source
Control > Rename, and enter a new file name.
Delete file from local repository In the Current Folder browser, right-click the file and select
and retain a copy in working Source Control > Delete from Git. When the file is marked for
folder deletion from source control, the symbol changes to Deleted ( ).
The file is removed from the repository at the next commit.
Delete file from local repository In the Current Folder browser, right-click the file and select
and from working folder Source Control > Delete from Git and disk. The file disappears
from the Current Folder browser and is immediately deleted from
your working folder. The file is removed from the repository at the
next commit.
Revert changes to file in local In the Current Folder browser, right-click the file and select
repository Source Control > Revert Local Changes.
Revert local changes to all files In the Current Folder browser, right-click the white space and
in local repository select Source Control > Branches. In the Branches dialog box,
click Revert to Head.
Revert file to specified revision In the Current Folder browser, right-click the file and select
Revert using Git. Then, select a revision and click the Revert
button. If you revert a file to an earlier revision and then make
changes, you cannot commit the file until you resolve the conflict
with the repository history.
To create a stash, in the Current Folder browser, right-click the white space in your working folder
and select Source Control > Stashes. Then, click the New Stash button.
To view modified files in a stash, in the Current Folder browser, right-click the white space and select
Source Control > Stashes. In the Available Stashes section, select a stash and then right-click a
modified file to view the changes or save a copy.
To apply the stash to your current branch and then delete the stash, click Pop. To apply the stash and
keep it, click Apply.
See Also
Functions
gitrepo | gitclone | add | rm | commit | createBranch | switchBranch | fetch | merge | push
35-10
Use Git in MATLAB
Related Examples
• “Set Up Git Source Control” on page 35-13
• “Branch and Merge with Git” on page 35-21
• “Add Git Submodules” on page 35-25
• “Clone Remote Git Repository into New Project” on page 33-59
External Websites
• Programming: Structuring Code (MathWorks Teaching Resources)
35-11
35 Source Control Interface
1 In the Current Folder browser, right-click the white space and select Source Control > Manage
Files. MATLAB opens the Manage Files Using Source Control dialog box.
2 Set the Source control integration option to Git.
3 Click the Change button next to the Repository path field. MATLAB opens the Select a
Repository dialog box.
4
Click the Create a Git repository on disk button.
5 Select the folder in which to create and store the local repository and click Select Folder. The
selected folder must be empty.
6 Click the Validate button to validate the repository path. If the path is valid, click the OK button
to return to the Manage Files Using Source Control dialog box.
7 Enter the path of the working folder in which to store your files in the Sandbox field. The
specified folder must be empty.
8 Click the Retrieve button.
After creating a local repository and working folder, to change the path of the local repository, right-
click in the working folder, select Source Control > Remote, and specify the new path.
To use a Git server for the repository on your local system, you can use a Git server hosting solution
or set up your own Apache® Git server.
Note In a production environment, do not rely on remote repositories via the file system using the
file:/// protocol. The file protocol is not safe. Concurrent access might corrupt repositories.
See Also
Functions
gitrepo | gitclone | add | rm | commit | createBranch | switchBranch | fetch | merge | push
Related Examples
• “Set Up Git Source Control” on page 35-13
• “Use Git in MATLAB” on page 35-5
• “Clone Remote Git Repository into New Project” on page 33-59
35-12
Set Up Git Source Control
• Register your binary files with Git to avoid file corruption. (Required for all systems)
• Enable support for long paths for Git on a Windows system. (Recommended for Windows Systems)
• Configure MATLAB to sign commits. (Optional)
• Configure MATLAB to use Git SSH authentication or install a Git credential helper to prevent
frequent login prompts. (Optional)
• Configure Git to use Git LFS if you are working with large files. (Optional)
• Configure external Git tools to use MATLAB for Diff and Merge. (Optional)
Starting in R2024a, MATLAB Git integration runs Git hooks with no additional setup. Supported
hooks are pre-commit, commit-msg, post-commit, prepare-commit-msg, pre-push, pre-
merge-commit, post-checkout, and post-merge. For an example, see “Use Git Hooks in
MATLAB” on page 35-40.
Before R2024a, to use some Git hooks with MATLAB, install Cygwin™ and add it to the MATLAB
library path. For instructions, see “Install Cygwin (Before R2024a)” on page 35-20.
Before R2020b, a command-line Git client must be installed to use Git to merge branches in MATLAB.
For more information, see “Install Command-Line Git Client” on page 35-19.
Also check that other file extensions are registered as binary to avoid corruption at check-in. Check
and register file extensions such as .xlsx, .jpg, .pdf, .docx, and so on.
To register your binary file extensions with Git, add them to the .gitattributes file in your
repository. If you create a new project that uses Git source control or switch an existing project from
another source control system to Git source control, MATLAB automatically creates
a .gitattributes file and populates it with a list of common binary files to register.
If a .gitattributes file is not automatically created, you can create one that contains the list of
common binary files to register. In the MATLAB Command Window, enter:
copyfile(fullfile(matlabroot,'toolbox','shared','cmlink','git','auxiliary_files', ...
'mwgitattributes'),fullfile(pwd,'.gitattributes'))
Alternatively, create a blank .gitattributes file in your repository and populate its content.
35-13
35 Source Control Interface
To prevent frequent login prompts when you interact with your remote repository using HTTPS, add a
new public key and clone the repository using SSH instead. This table provides instructions on how to
configure MATLAB to use SSH authentication based on your operating system.
35-14
Set Up Git Source Control
Operating Instructions
System
Windows 1 Install a command-line Git client and make it available system-wide. To check if
Git is installed, enter the command !git in the MATLAB Command Window. If
the command does not return anything, you need to install command-line Git. For
more information, see “Install Command-Line Git Client” on page 35-19.
2 Close all MATLAB sessions.
3 Generate an SSH key using the ssh-keygen command. For example, at a
Windows command prompt, enter this command:
ssh-keygen prompts you to confirm where to save the key and asks for a
passphrase. If you do not want to type a password when you use the key, leave
the passphrase empty.
If you already have keys in the specified folder, ssh-keygen asks if you want to
override them.
Before R2021a, specify the -m PEM option to generate an SSH key in the RSA
format. Otherwise, ssh-keygen creates the SSH key using the default OpenSSH
format, which is not supported in MATLAB versions before R2021a. For example,
at a Windows command prompt, enter this command:
ssh-keygen -m PEM
If you generate an SSH key without specifying the -m PEM option, you can
convert your key to the supported RSA format using this command, where
~/.ssh/id_rsa is the name of the SSH key file.
getenv('USERPROFILE')
Before R2021a, if you created the SSH key using the -m PEM option, you can
skip step 5.
5 To make sure that MATLAB detects the SSH keys, in the MATLAB Command
Window, enter:
git = settings().matlab.sourcecontrol.git;
git.PrivateKeyFile.PersonalValue = "C:\Users\username\.ssh\id_ed25519";
git.PublicKeyFile.PersonalValue = "C:\Users\username\.ssh\id_ed25519.pub";
If you entered a passphrase when generating the SSH key, configure MATLAB to
use the passphrase and receive a prompt only once per session. To do so, use
Pageant or, in the MATLAB Command Window, enter:
git.KeyHasPassphrase.PersonalValue = true;
35-15
35 Source Control Interface
Operating Instructions
System
To use multiple keys, use Pageant as the SSH agent. If Pageant is running,
MATLAB looks for keys in Pageant before using the key you define in the
settings.
6 Configure your GitHub or GitLab account to use the SSH keys. To do so, go to
the .ssh folder and copy the contents of the .pub file. Then, go to your account
settings, and in the SSH keys section, paste the contents of the .pub file into
the Add SSH key field.
35-16
Set Up Git Source Control
Operating Instructions
System
Linux and 1 Close all MATLAB sessions.
macOS 2 Generate an SSH key using the ssh-keygen command. For example, in a
Terminal window, enter this command:
ssh-keygen prompts you to confirm where to save the key and asks for a
passphrase. If you do not want to type a password when you use the key, leave
the passphrase empty.
If you already have keys in the specified folder, ssh-keygen asks if you want to
override them.
Before R2021a, specify the -m PEM option to generate an SSH key in the RSA
format. Otherwise, ssh-keygen creates the SSH key using the default OpenSSH
format, which is not supported in MATLAB versions before R2021a. For example,
in a Terminal window, enter this command:
ssh-keygen -m PEM
If you generate an SSH key without specifying the -m PEM option, you can
convert your key to the supported RSA format using this command, where
~/.ssh/id_rsa is the name of the SSH key file.
getenv('HOME')
Before R2021a, if you created the SSH key using the -m PEM option, you can
skip step 4.
4 To make sure that MATLAB detects the SSH keys, in the MATLAB Command
Window, enter:
git = settings().matlab.sourcecontrol.git;
git.PrivateKeyFile.PersonalValue = "~/.ssh/id_ed25519";
git.PublicKeyFile.PersonalValue = "~/.ssh/id_ed25519.pub";
If you entered a passphrase when generating the SSH key, configure MATLAB to
use the passphrase and receive a prompt only once per session. To do so, use an
SSH agent or, in the MATLAB Command Window, enter:
git.KeyHasPassphrase.PersonalValue = true;
To use multiple keys, use an SSH agent. If an SSH agent is running, MATLAB
looks for keys in the agent before using the key you define in the settings.
5 Configure your GitHub or GitLab account to use the SSH keys. To do so, go to
the .ssh folder and copy the contents of the .pub file. Then, go to your account
settings, and in the SSH keys section, paste the contents of the .pub file into
the Add SSH key field.
35-17
35 Source Control Interface
MATLAB remembers your user names and tokens when you interact with Git repositories.
Alternatively, you can install an external Git credential helper and configure MATLAB to use it
instead. The recommended credential helper for all platforms is Git Credential Manager Core. For
more information, see “Configure MATLAB to Use Git Credential Helper” on page 35-18.
matlab.git.clearCredential("https://github.com/myrepo.git")
To install Git Credential Manager Core on a Windows system and configure MATLAB to use it to store
Git credentials, follow these steps:
1 Download and run the Git for Windows installer using the instructions described in “Install
Command-Line Git Client” on page 35-19.
2 In the Choose a credential helper section of the installer, select Git Credential Manager
Core as the credential helper. This defines the value of credential.helper in your
global .gitconfig file.
Alternatively, you can set the value of credential.helper in your global .gitconfig file
manually.
To use this setting with new SLX files, create your models using a model template with SLX
Compression set to none. For existing SLX files, set the compression and then save the model. For
more information, see “Set SLX Compression Level” (Simulink).
Note Starting in R2023b, by default, Simulink applies no compression during the save operation.
For example, to use Git LFS on a Windows system, download and run the Git for Windows installer
using the instructions described in “Install Command-Line Git Client” on page 35-19. In the Select
Components section of the Git for Windows installer, select the Git LFS (Large File Support) and
Associate .sh files to be run with Bash options.
MATLAB does not support Git LFS locking. In addition, MATLAB does not support LFS commands
such as git lfs track. Use !git lfs track instead.
35-18
Set Up Git Source Control
Configure External Git Tools to use MATLAB for Diff and Merge
You can configure Git to use the MATLAB Comparison Tool for diff and merge. The MATLAB
Comparison Tool provides tools for merging MathWorks files such as live scripts, MAT, SLX, or MDL
files. You can use the automerge tool with Git to automatically merge branches that contain changes
in different subsystems in the same SLX file.
For more information about how to configure External Git tools to use the MATLAB Comparison Tool,
see “Customize External Source Control to Use MATLAB for Diff and Merge” on page 35-50.
Additional Setup
Install Command-Line Git Client
To use Git LFS or a credential helper, you must install a command-line Git client and make it available
system-wide. Before R2020b, a command-line Git client must be installed to use Git to merge
branches in MATLAB.
To check if Git is installed, enter the command !git in the MATLAB Command Window. If the
command does not return anything, you need to install command-line Git. This table provides
instructions on how to install command-line Git based on your operating system.
35-19
35 Source Control Interface
Before R2024a, to run some Git hooks from within MATLAB, you must install Cygwin. Supported
hooks are pre-commit, commit-msg, post-commit, and pre-push.
Follow these steps to install Cygwin on a Windows system and add it to the MATLAB library path and
the system path.
edit(fullfile(matlabroot,"toolbox","local","librarypath.txt"))
3 Add the Cygwin bin folder location to the end of librarypath.txt, for example,
C:\cygwin64\bin.
##
## FILE: librarypath.txt
##
## Entries:
## o path_to_jnifile
## o [alpha,glnx86,sol2,unix,win32,mac]=path_to_jnifile
## o $matlabroot/path_to_jnifile
## o $jre_home/path_to_jnifile
##
$matlabroot/bin/$arch
$matlabroot/sys/jxbrowser/$arch/lib
C:\cygwin64\bin
If you do not have permission to edit the librarypath.txt file, see “Locate Native Method
Libraries”.
4 Add the Cygwin bin folder to the system path. For more information, see https://
www.mathworks.com/matlabcentral/answers/94933-how-do-i-edit-my-system-path-in-windows.
5 Restart MATLAB.
See Also
Functions
gitclone | gitrepo | gitinit
Related Examples
• “Use Git in MATLAB” on page 35-5
• “Branch and Merge with Git” on page 35-21
• “Customize External Source Control to Use MATLAB for Diff and Merge” on page 35-50
35-20
Branch and Merge with Git
In this section...
“Create Branch” on page 35-21
“Switch Branch” on page 35-22
“Compare Branches” on page 35-22
“Merge Branches” on page 35-23
“Revert to Head” on page 35-23
“Delete Branches” on page 35-23
Create Branch
1 From within your Git repository folder, right-click the white space of the Current Folder browser
and select Source Control > Branches. In the Branches dialog box, you can view, switch,
create, and merge branches.
Tip You can inspect information about each commit node. Select a node in the Branch Browser
diagram to view the author, date, commit message, and changed files.
35-21
35 Source Control Interface
2 Select a source for the new branch. Click a node in the Branch Browser diagram, or enter a
unique identifier in the Source text box. You can enter a tag, branch name, or a unique prefix of
the SHA1 hash (for example, 73c637 to identify a specific commit). Leave the default to create a
branch from the head of the current branch.
3 Enter a name in the Branch name text box and click Create.
4 To work on the files on your new branch, switch your project to the branch.
In the Branches drop-down list, select the branch you want to switch to and click Switch.
5 Close the Branches dialog box and work on the files on your branch.
Switch Branch
1 From within your Git repository folder, right-click the white space of the Current Folder browser
and select Source Control > Branches.
2 In the Branches dialog box, in the Branches drop-down list, select the branch you want to and
click Switch.
3 Close the Branches dialog box and work on the files on your branch.
Compare Branches
From within your Git repository folder, right-click the white space of the Current Folder browser and
select Source Control > Branches.
35-22
Branch and Merge with Git
• To examine differences in a file between the current revision and its parent, right-click a file in the
tree under Differences from parent and select Show Difference.
• To examine differences in a file between any two revisions including revisions on two different
development branches, hold the Ctrl key and select the two different revisions. Right-click a file in
the tree under Differences from selection and select Show Difference.
MATLAB opens a comparison report. You can save a copy of the selected file on either revision. Right-
click a file and select Save As to save a copy of the file on the selected revision. Select Save Original
As to save a copy of the file on the prior revision. This is useful if you want to test how the code ran in
previous revisions or on other branches.
Merge Branches
To merge any branches:
1 From within your Git repository folder, right-click the white space of the Current Folder browser
and select Source Control and Branches.
2 In the Branches dialog box, from the Branches drop-down list, select a branch you want to
merge into the current branch, and click Merge.
3 Close the Branches dialog box and work on the files on your branch.
If the branch merge causes a conflict that Git cannot resolve automatically, an error dialog box
reports that automatic merge failed. Resolve the conflicts before proceeding.
Caution Do not move or delete files outside of MATLAB because this can cause errors on merge.
1 To keep your version of the file, right-click the file and select Mark Conflict Resolved.
2 Click Commit Modified Files to commit your change that marks the conflict resolved.
If you merge a branch and there is a conflict in a file, Git marks the file as conflicted and does not
modify the contents. Right-click the file and select Source Control > View Conflicts. A comparison
report opens that shows the differences between the file on your branch and the branch you want to
merge into. Decide how to resolve the conflict. See “Resolve SVN Source Control Conflicts” on page
35-37.
Revert to Head
1 From within your Git repository folder, right-click the white space of the Current Folder browser
and select Source Control > Branches.
2 In the Branches dialog box, click Revert to Head to remove all local changes.
Delete Branches
1 In the Branches dialog box under Branch Browser, expand the Branches drop-down list, and
select the branch you want to delete.
35-23
35 Source Control Interface
2 On the far right, click the down arrow and select Delete Branch.
See Also
Functions
gitrepo | gitclone | createBranch | switchBranch | fetch | merge | push
Related Examples
• “Set Up Git Source Control” on page 35-13
• “Use Git in MATLAB” on page 35-5
• “Customize External Source Control to Use MATLAB for Diff and Merge” on page 35-50
35-24
Add Git Submodules
1 Right-click in the MATLAB Current Folder browser, and select Source Control > Submodules.
2 In the Submodules dialog box, click Add.
3 In the Add Submodule dialog box, in the Remote box, specify a repository location. Optionally,
click Validate.
4 In the Path box, specify a location for the submodule and click OK. The Submodules dialog box
displays the status and details of the submodule.
5 Check the status message, and click Close.
Tip You can use Git submodules to populate a referenced project. For more information, see
“Organize Projects into Components Using References and Git Submodules” (Simulink) and watch
How to Organize Large Projects into Components (3 min, 32 sec).
Update Submodules
After using Pull to get the latest changes from a remote repository, check that submodules are up to
date by clicking Submodules and then click Update. If any submodule definition have changed, then
the update ensures that the submodule folder contains the correct files. Update applies to all child
submodules in the submodule hierarchy.
1 To get the latest version of a submodule, in the Submodules dialog box, click Fetch.
2 After fetching, you must merge. Check the Status message in the Submodules dialog box for
information about your current branch relative to the remote tracking branch in the repository.
When you see the message Behind, you need to merge in changes from the repository to your
local branch.
3 Click Branches and merge in the origin changes to your local branch using the Branches dialog
box.
If you want other users to obtain your changes in the submodule when they clone the parent folder,
make sure the index and head match.
35-25
35 Source Control Interface
1 In the Submodules dialog box, check the index and head values. The index points to the head
commit at the time you first cloned the submodule, or when you last committed the parent folder.
If the index and head do not match, you must update the index.
2 To update the index, commit your changes in the parent folder, and then click Push in the
Submodules dialog box. This action makes the index and head the same.
See Also
Functions
gitrepo | gitclone
Related Examples
• “Set Up Git Source Control” on page 35-13
• “Use Git in MATLAB” on page 35-5
• How to Organize Large Projects into Components (3 min, 32 sec)
35-26
Set Up SVN Source Control
To use the version of SVN provided with MATLAB, when you retrieve a file from source control, select
SVN in the Source control integration list. For instructions, see “Work with Files Under SVN in
MATLAB” on page 35-32. When you create a new sandbox using the MATLAB built-in SVN
integration, the new sandbox uses the latest version of SVN provided by MATLAB.
Caution Before using source control, you must register binary files with the source control tools to
avoid corruption. See “Register Binary Files with SVN” on page 35-27.
Also check that other file extensions are registered as binary to avoid corruption at check-in. Check
and register file extensions such as .xlsx, .jpg, .pdf, .docx, and so on.
You must register binary files if you use any version of SVN, including the built-in SVN integration
provided by MATLAB. If you do not register your extensions as binary, SVN might add annotations to
conflicted MATLAB files and attempt automerge. To avoid this problem when using SVN, register file
extensions.
1 Locate your SVN config file. Look for the file in these locations:
35-27
35 Source Control Interface
After you create the SVN config file, SVN treats new files with these extensions as binary. If you
already have binary files in repositories, see “Register Files Already in Repositories” on page 35-29.
If you find an existing config file, you have previously installed SVN. Edit the config file to register
files as binary.
1 Edit the config file in a text editor.
2 Locate the [miscellany] section, and verify the following line enables auto-props with yes:
enable-auto-props = yes
Ensure that this line is not commented (that is, that it does not start with #). Config files can
contain example lines that are commented out. If there is a # character at the beginning of the
line, delete it.
3 Locate the [auto-props] section. Ensure that [auto-props] is not commented. If there is a #
character at the beginning, delete it.
4 Add the following lines at the end of the [auto-props] section:
*.mlx = svn:mime-type=application/octet-stream
*.mat = svn:mime-type=application/octet-stream
*.fig = svn:mime-type=application/octet-stream
*.mdl = svn:mime-type=application/octet-stream
35-28
Set Up SVN Source Control
These lines prevent SVN from adding annotations to MATLAB and Simulink files on conflict and
from automerging.
5 Check for other file types you use that you also need to register as binary to avoid corruption at
check-in. Check for files such as MEX-files
(.mexa64, .mexmaci64, .mexw64), .xlsx, .jpg, .pdf, .docx, etc. Add a line to the config
file for each file type you use. Examples:
*.mexa64 = svn:mime-type=application/octet-stream
*.mexw64 = svn:mime-type=application/octet-stream
*.mexmaci64 = svn:mime-type=application/octet-stream
*.xlsx = svn:mime-type=application/octet-stream
*.docx = svn:mime-type=application/octet-stream
*.pdf = svn:mime-type=application/octet-stream
*.jpg = svn:mime-type=application/octet-stream
*.png = svn:mime-type=application/octet-stream
6 Save the config file.
After you create or update the SVN config file, SVN treats new files as binary. If you already have
files in repositories, register them as described in “Register Files Already in Repositories” on page
35-29.
Caution Changing your SVN config file does not affect files already committed to an SVN
repository. If a file is not registered as binary, use svn propset to manually register the files as
binary.
To manually register a file in a repository as binary, use the following command with command-line
SVN:
svn propset svn:mime-type application/octet-stream binaryfilename
After you create a repository with this structure, you can click Tag in the Source Control context
menu to add tags to all of your files. For more information, see “Tag Versions of Files” on page 35-
30.
35-29
35 Source Control Interface
1 Right-click in the Current Folder browser, and select Source Control > Tag.
2 Specify the tag text and click Submit. The tag is added to every file in the folder. Errors appear if
you do not have a tags folder in your repository.
Note You can retrieve a tagged version of your files from source control, but you cannot tag them
again with a new tag. You must check out from trunk to create new tags.
To enforce locking files, modify entries in the SVN config file. To locate your SVN config file, see
“Register Binary Files with SVN” on page 35-27.
1 To make files with a .m extension read only, add a property to your SVN config file in the
[auto-props] section. If there is no entry for files with a .m extension, add one with the
needs-lock property.
*.m = svn:needs-lock=yes
If an entry exists, you can combine properties in any order, but multiple entries must be on a
single line separated by semicolons.
2 To make files with a .mlx extension read only, add a property to your SVN config file in the
[auto-props] section. Since you must register files with a .mlx extension as binary, there is an
entry for the file type. Add the needs-lock property to the entry in any order, but on the same
line and separated by a semicolon.
*.mlx = svn:mime-type=application/octet-stream;svn:needs-lock=yes
3 Re-create the sandbox for the configuration to take effect.
With this setting, you need to select Get File Lock before you can edit files with a .m extension. See
“Get SVN File Locks” on page 35-36.
When you want to share a repository, you need to set up a server. You can use svnserve or the
Apache SVN module. See the Web page references:
https://svnbook.red-bean.com/en/1.7/svn-book.html#svn.serverconfig.svnserve
https://svnbook.red-bean.com/en/1.7/svn-book.html#svn.serverconfig.httpd
35-30
Set Up SVN Source Control
Note In a production environment, do not rely on remote repositories via the file system using the
file:/// protocol. The file protocol is not safe. Concurrent access might corrupt repositories.
See Also
Related Examples
• “Work with Files Under SVN in MATLAB” on page 35-32
35-31
35 Source Control Interface
Otherwise, to browse for and validate the repository path to retrieve files from, click Change.
a In the Specify SVN Repository URL dialog box, specify the repository URL by entering a URL
in the box, using the list of recent repositories.
b Click Validate to check the repository path.
If you see an authentication dialog box for your repository, enter the login information to
continue.
c If the path is invalid, check the URL against your source control repository browser.
If necessary, select a deeper folder in the repository tree. You might want to check out from
trunk or from a branch folder under tags, if your repository contains tagged versions of
files. You can check out from a branch, but the built-in SVN integration does not support
branch merging. Use an external tool such as TortoiseSVN to perform branch merging.
d When you have finished specifying the URL path you want to retrieve, click OK. The dialog
box closes and you return to the Manage Files Using Source Control dialog box.
4 In the Manage Files Using Source Control dialog box, select the sandbox folder to store the
retrieved files and click Retrieve.
If you see an authentication dialog box for your repository, enter the login information to
continue.
Caution Use local sandbox folders. Using a network folder with SVN slows source control
operations.
35-32
Work with Files Under SVN in MATLAB
The Manage Files Using Source Control dialog box displays messages as it retrieves the files
from source control.
To use tags with SVN, you need the standard folder structure in your repository. For more
information, see “Standard Repository Structure” on page 35-29.
1 Right-click in the white space in the Current Folder browser, and select Source Control >
Manage Files.
2 In the Manage Files Using Source Control dialog box, select the source control interface from the
Source control integration list. To use SVN, leave the default SVN.
3 Click Change to select the repository path that you want to retrieve files from.
4 In the Specify SVN Repository URL dialog box:
a
Select a recent repository from the Repository list, or click the Repository button to
browse for the repository location.
b Click Validate to show the repository browser.
c Expand the tags folder in the repository tree, and select the tag version you want. Navigate
up a level in the repository if the URL contains the trunk.
d Click OK to continue and return to the Manage Files Using Source Control dialog box.
5 Select the sandbox folder to receive the tagged files. You must use an empty sandbox folder or
specify a new folder.
6 Click Retrieve.
When you create a new file in a folder under source control, the Not Under Source Control symbol
appears in the status column of the Current Folder browser. To add a file to source control, right-click
the file in the Current Folder browser, and select Source Control > Add to SVN.
When you mark a file for addition to source control, the symbol changes to Added .
To refresh the status of all files in a folder, right-click the white space of the Current Folder browser
and select Source Control > Refresh SVN status.
Note Refreshing the SVN source control status does not contact the repository to get the latest file
revisions.
To update the local copies of selected files, select one or more files in the Current Folder browser,
right-click and select Source Control > Update Selection from SVN.
35-33
35 Source Control Interface
To update all files in a folder, right-click the Current Folder browser and select Source Control >
Update All from SVN.
The files under source control that you have changed display the Modified File symbol in the
Current Folder browser. Right-click the file in the Current Folder browser, select Source Control,
and select:
• Show Revisions to open the File Revisions dialog box and browse the history of a file. You can
view information about who previously committed the file, when they committed it, the log
messages, and the list of files in each change set. You can select multiple files and view revision
history for each file.
You also can select a revision and browse the lower list of files in the change set. Right-click files
to view changes or save revisions.
• Compare to Revision to open a dialog box where you can select the revisions you want to
compare and view a comparison report. You can either:
You also can select a revision and browse the lower list of files in the change set. Right-click files
to view changes or save revisions.
• Compare to Ancestor to run a comparison with the last checked-out version in the sandbox. The
Comparison Tool displays a report.
If you need to update the status of the modified files, see “Update SVN File Status and Revision” on
page 35-33.
To update the revision, right-click in the Current Folder browser and select Source Control >
Update All from SVN. Resolve any conflicts before you commit.
If you do want to commit changes to modified files under SVN source control and want to revert local
changes instead, right-click the file and select Source Control > Revert Local Changes and
Release Locks. This command releases locks and reverts to the version in the last sandbox update. If
your file is not locked, the menu option is Source Control > Revert Local Changes. To abandon all
local changes, select all the files in the Current Folder browser before you select the command.
35-34
Work with Files Under SVN in MATLAB
1 Right-click the file in the Current Folder browser and select Source Control > Revert using
SVN.
2 In the Revert Files dialog box, choose a revision to revert to. Select a revision to view information
about the change such as the author, date, and log message.
3 Click Revert.
See Also
Related Examples
• “Set Up SVN Source Control” on page 35-27
• “Resolve SVN Source Control Conflicts” on page 35-37
35-35
35 Source Control Interface
In the Current Folder browser, select the files you want to check out. Right-click the selected files and
select Source Control > Get File Lock. A lock symbol appears in the source control status
column. Other users cannot see the lock symbol in their sandboxes, but they cannot get a file lock or
check in a change when you have the lock. To view or break locks, right-click in the Current Folder
browser and select Source Control > Locks.
If you see an SVN message reporting a working copy locked error, remove stale locks. In the
Current Folder browser, right-click and select Source Control > SVN Cleanup. SVN uses working
copy locks internally and they are not the file locks you control using Source Control > Get File
Lock.
Note Starting in R2020a Update 5, SVN cleanup only removes stale locks and unfinished
transactions. It does not remove unversioned or ignored files.
1 In the Current Folder browser, click the SVN header to sort files by their SVN status.
2 Select the Not Under Source Control files.
3 Right-click and select Delete.
See Also
Related Examples
• “Work with Files Under SVN in MATLAB” on page 35-32
• “Set Up SVN Source Control” on page 35-27
35-36
Resolve SVN Source Control Conflicts
For details on using the Comparison Tool to merge changes, see “Merge Text Files” on page 35-37.
After you are satisfied with the file that is marked conflicted, you can mark the conflict resolved and
commit the file.
Resolve Conflicts
1 Look for conflicted files in the Current Folder browser.
2
Check the SVN status column for files with a red warning symbol , which indicates a conflict.
3 Right-click the conflicted file and select Source Control > View Conflicts to compare versions.
4 Examine the conflict. A comparison report opens that shows the differences between the file and
the version of the file in conflict.
5 Use the Comparison Tool report to determine how to resolve the conflict.
You can use the Comparison Tool to merge changes between revisions, for text files, MLX files
and model files (SLX and MDL files). See “Merge Text Files” on page 35-37 and “Model
Comparison” (Simulink).
6 When you have resolved the changes and want to commit the version in your sandbox, in the
Current Folder browser, right-click the file and select Source Control > Mark Conflict
Resolved.
7 Commit the modified files.
<<<<<<< .mine
then extract the conflict markers before merging, as described in “Extract Conflict Markers” on page
35-38.
Tip You can merge only from left to right. When comparing to another version in source control, the
right file is the version in your sandbox. The left file is either a temporary copy of the previous version
35-37
35 Source Control Interface
or another version causing a conflict (e.g., filename_theirs). Observe the file paths of the left and
right file at the top of the comparison report. Merge differences from the left (temporary copy) file to
the right file to resolve conflicts.
1 In the Comparison Tool report, select a difference in the report and click Replace Content. The
selected difference is copied from the left file to the right file.
The merged file name at the top of the report displays the dirty flag (filename.m*) to show you
that the file contains unsaved changes.
2 Click Accept & Close to save the merge changes and mark the conflicts resolved.
Caution Register files with source control tools to prevent them from inserting conflict markers and
corrupting files. For more information, see “Register Binary Files with SVN” on page 35-27. If your
files already contains conflict markers, the MATLAB tools can help you to resolve the conflict.
If you try to open a file containing conflict markers, the Conflict Markers Found dialog box opens.
Follow the prompts to fix the file by extracting the conflict markers. After you extract the conflict
markers, resolve the conflicts as described in “Resolve Conflicts” on page 35-37.
To view the conflict markers, in the Conflict Markers Found dialog box, click Load File. Do not try to
load files, because MATLAB does not recognize conflict markers. Instead, click Fix File to extract the
conflict markers.
When you open a conflicted file or select View Conflicts, MATLAB checks files for conflict markers
and offers to extract the conflict markers. MATLAB checks only conflicted files for conflict markers.
35-38
Resolve SVN Source Control Conflicts
However, some files that are not marked as conflicted can still contain conflict markers. This can
happen if you or another user marked a conflict resolved without removing the conflict markers and
then committed the file. If you see conflict markers in a file that is not marked conflicted, you can
extract the conflict markers.
1 In the Current Folder browser, right-click the file, and select Source Control > Extract Conflict
Markers to File.
2 In the Extract Conflict Markers to File dialog box, leave the default option to copy "mine" file
version over the conflicted file. Leave the Compare extracted files check box selected. Click
Extract.
3 Use the Comparison Tool report as usual to continue to resolve the conflict.
See Also
Related Examples
• “Work with Files Under SVN in MATLAB” on page 35-32
• “Set Up SVN Source Control” on page 35-27
• “Model Comparison” (Simulink)
35-39
35 Source Control Interface
This example shows how to use Git™ hooks in MATLAB® to standardize your commit workflows. Git
hooks are custom scripts that can be triggered by operations such as committing, merging, and
pushing commits.
To use Git hooks in MATLAB on a Windows® system, make sure you enable .sh files to run with Bash
when you install command-line Git. For more information, see “Install Command-Line Git Client” on
page 35-19.
Open the example to download the supporting files. This repository includes three example hooks.
The .git/hooks folder contains the commit-msg, the pre-commit, and the prepare-commit-msg
hooks. Explore and edit the content of these example hooks or use them as templates to create your
own hooks.
35-40
Use Git Hooks in MATLAB
Use the prepare-commit-msg hook to modify the default commit message and customize it to
include information such as branch names and issue tracker IDs. In this example, prepare-commit-
msg appends the project name -PROJ123- to your commit message.
In the Current Folder browser, right-click and select Source Control > View and Commit
Changes. In the View and Commit Changes dialog box, the default commit message includes -
PROJ123- at the end.
35-41
35 Source Control Interface
35-42
Use Git Hooks in MATLAB
Use the commit-msg hook to inspect and validate the final commit message. commit-msg cancels
the commit if the final commit message does not adhere to the guidelines you enforce. In this
example, commit-msg requires every commit message to start with "fix:", "feat:", "doc:", or "test:" to
specify the type of the commit.
If you attempt to commit without including the commit type at the beginning of the commit message,
the commit operation throws the error you specify in the commit-msg hook. In the View and Commit
Changes dialog box, in the Comment field, enter "Add saveUnsavedFiles utility" and click Commit.
Caused by:
ERROR: Commit message does not start with 'fix:', 'feat:', 'doc:', or 'test:'
Use the pre-commit hook to inspect the files you are about to commit. You can customize pre-
commit to check for code quality, formatting issues, and typos. pre-commit cancels the commit if the
checks you specify in the hook fail. In this example, pre-commit checks for the text "TODO" in your
modified files.
In this example, the saveUnsavedMFiles.m file contains "TODO" comments. When you attempt to
commit your changes, the commit operation throws the error you specify in the pre-commit hook.
35-43
35 Source Control Interface
Open the saveUnsavedMFiles.m file and delete occurrences of "TODO". Then, commit again.
To use Git hooks to improve other workflows, such as the merge and push workflows, add more hooks
in the .git/hooks folder. MATLAB Git integration supports these hooks: pre-commit, commit-
msg, post-commit, prepare-commit-msg, pre-push, pre-merge-commit, post-checkout, and
post-merge.
See Also
commit
35-44
Use Git Hooks in MATLAB
Related Examples
• “Set Up Git Source Control” on page 35-13
• “Use Git in MATLAB” on page 35-5
35-45
35 Source Control Interface
This example shows how to set up a MATLAB project for continuous integration and run a suite of
MATLAB unit tests with Jenkins.
• Configure a freestyle Jenkins project to access a MATLAB project hosted in a remote repository.
• Add a build step to the Jenkins project to run all project tests.
• Add a build step to the Jenkins project to run tests impacted by the latest change.
• Add a post-build step to archive and reuse the dependency analysis cache file to reduce test suite
runtime when qualifying a change.
• Build the project and examine the test results.
Note You can use different continuous integration (CI) platforms such as Azure® DevOps, Bamboo®,
and GitHub Actions to run MATLAB code and Simulink models as part of your automated workflow.
For a list of supported CI platforms, see “Continuous Integration with MATLAB on CI Platforms” on
page 36-237.
Prerequisites
Before you start:
1 Install Jenkins. See https://www.jenkins.io/doc/book/installing/.
2 Install the MATLAB plugin for Jenkins:
a From within Jenkins, on the Manage Jenkins page, click Manage Plugins.
b On the Available tab, search for "MATLAB".
c Download and install the plugin.
Your MATLAB project is publicly available on GitHub. You can make your repository private by
changing the settings in your GitHub account.
35-46
Continuous Integration Using MATLAB Projects and Jenkins
Alternatively, use the Run MATLAB Command step to run all tests using the MATLAB project
label. In the Build section, select Add Build Step > Run MATLAB Command. In the
Command field, enter this script.
proj = openProject("ProjectAirframeExample.prj");
testFiles = findFiles(proj,Label="Test");
runtests(testFiles)
5 To save the Jenkins project configuration, click Save.
6 To build your project and run all tests, click Build Now. Jenkins triggers a build, assigns it a
number under Build History, and runs the build. If the build is successful, a blue circle icon
appears next to the build number. If the build fails, a red circle icon appears. For more
information, see Run MATLAB Tests on Jenkins Server (GitHub).
To set the project dependency cache file, in MATLAB, on the Project tab, in the Environment
section, click Details. In Dependency cache file, browse to and specify a GraphML file. If the cache
file does not exist, the project creates it for you when you run a dependency analysis.
Alternatively, you can create and set the project dependency cache programmatically.
proj = currentProject;
proj.DependencyCacheFile = "work/dependencyanalysis/projectcache.graphml";
Commit and push the change to make it available on GitHub and Jenkins. On the Project tab, in the
Source Control section, click Commit, then click Push.
To configure your Jenkins project to generate and archive the dependency analysis cache file, on your
Jenkins project configuration page:
35-47
35 Source Control Interface
1 Add a new build step. In the Build section, select Add Build Step > Run MATLAB Command.
In the Command field, enter this script.
proj = openProject("ProjectAirframeExample.prj");
updateDependencies(proj);
This script launches MATLAB, loads your MATLAB project, runs a dependency analysis, and
caches the results in the dependency cache file.
2 In the Post-build Actions section, under Archive the artifacts, in the Files to archive field,
enter: work/dependencyanalysis/*.graphml. After the build, Jenkins copies the GraphML
file from the Jenkins workspace to the build archive location.
If you configured Jenkins to perform frequent builds, team members can sync their working copy
based on the last successful build. Team members check out the design changes from Git, retrieve the
associated dependency cache file from the build archive area, and place the GraphML file in the
specified location.
On a local machine, MATLAB projects use the prepopulated dependency cache file to run an
incremental dependency analysis. This action saves time for workflows running a dependency
analysis in the background, such as automatic renaming, sharing a project, and performing an impact
analysis.
On a CI server, for large projects, you can use the prepopulated dependency cache to perform an
incremental impact analysis. You can configure your project build to run only impacted tests and
significantly reduce runtime when qualifying a code change.
To configure your Jenkins project to only run tests impacted by the last change, in the Build section,
select Add Build Step > Run MATLAB Command. In the Command field, enter this script.
proj = openProject("ProjectAirframeExample.prj");
[status,modifiedFiles] = system("git diff --name-only HEAD~1..HEAD :!resources");
updateDependencies(proj);
modifiedFiles = split(modifiedFiles);
modifiedFiles = modifiedFiles(1:(end-1))';
impactedFiles = listImpactedFiles(proj,modifiedFiles);
testFiles = findFiles(proj,Label="Test");
impactedTests = intersect(testFiles,impactedFiles);
runtests(impactedTests)
This script launches MATLAB, loads your MATLAB project, retrieves the list of files that changed in
the last commit, runs an impact analysis to determine the subset of tests you need to run to qualify
the change, and runs the list of impacted tests.
Enhance Workflow
You can apply several additional steps to improve the workflow and make building and qualifying the
project faster.
• Similar to the GraphML file, you also can generate and archive SLXC files to reuse and reduce
simulation time. For more information, see “Share Simulink Cache Files for Faster Simulation”
(Simulink).
35-48
Continuous Integration Using MATLAB Projects and Jenkins
• To easily manage SLXC and GraphML files from multiple Jenkins builds, you can use a database or
a repository management tool such as JFrog Artifactory. For more information, see https://
jfrog.com/help/r/get-started-with-the-jfrog-platform/jfrog-artifactory.
• You can set up a script to automatically retrieve the associated dependency cache file and place a
copy in your working copy.
See Also
More About
• “Analyze Project Dependencies” on page 33-42
• “Develop and Integrate Software with Continuous Integration” on page 36-229
• “Continuous Integration with MATLAB on CI Platforms” on page 36-237
35-49
35 Source Control Interface
You can customize external source control tools to use the MATLAB Comparison Tool for diff and
merge. To compare MATLAB files such as MLX, MAT, SLX, or MDL files from your source control tool,
configure your source control tool to open the MATLAB Comparison Tool. For a more complete list of
supported files, see visdiff. The MATLAB Comparison Tool provides tools for merging MathWorks
files and is compatible with popular software configuration management and version control systems.
You can use the automerge tool with Git to automatically merge branches that contain changes in
different subsystems in the same SLX, SLMX, SLREQX, and SLTX files.
To set up your source control tool to use MATLAB as the application for diff and merge, you must first
determine the full paths of the mlDiff, mlMerge, and mlAutoMerge executable files, and then
follow the recommended steps for the source control tool you are using.
Finding the Full Paths for MATLAB Diff, Merge, and AutoMerge
To get the required file paths and enable external source control tools to reuse open MATLAB
sessions, run this command in MATLAB:
comparisons.ExternalSCMLink.setup()
This command sets the MATLAB preference, under Comparison, called Allow external source
control tools to use open MATLAB sessions for diffs and merges.
This command also displays the file paths to copy and paste into your source control tool setup.
Example paths are:
• On Windows:
Diff: matlabroot\bin\win64\mlDiff.exe
Merge: matlabroot\bin\win64\mlMerge.exe
AutoMerge: matlabroot\bin\win64\mlAutoMerge.bat
• On Linux:
Diff: matlabroot/bin/glnxa64/mlDiff
Merge: matlabroot/bin/glnxa64/mlMerge
AutoMerge: matlabroot/bin/glnxa64/mlAutoMerge
• On Mac:
35-50
Customize External Source Control to Use MATLAB for Diff and Merge
Diff: matlabroot/bin/maci64/mlDiff
Merge: matlabroot/bin/maci64/mlMerge
AutoMerge: matlabroot/bin/maci64/mlAutoMerge
where matlabroot is replaced with the full path to your installation, for example, C:\Program
Files\MATLAB\R2020b.
Note Your diff and merge operations use open MATLAB sessions when available, and only open
MATLAB when necessary. The operations only use the specified MATLAB installation.
comparisons.ExternalSCMLink.setupGitConfig()
This command displays the full paths of the mlDiff, mlMerge, and mlAutoMerge executable
files. It also automatically populates the global .gitconfig file. For example:
[difftool "mlDiff"]
cmd = \"C:/Program Files/MATLAB/R20xxb/bin/win64/mlDiff.exe\" $LOCAL $REMOTE
[mergetool "mlMerge"]
cmd = \"C:/Program Files/MATLAB/R20xxb/bin/win64/mlMerge.exe\" $BASE $LOCAL $REMOTE $MERGED
[merge "mlAutoMerge"]
driver = \"C:/Program Files/MATLAB/R20xb/bin/win64/mlAutoMerge.bat\" %O %A %B %A
Note You need to do step 1 only once for your Git setup.
2 Configure your repository to use the mlAutoMerge executable file. Open the .gitattributes
file in your repository and add:
Now, when you merge branches that contain changes in different subsystems in the same SLX
file, MATLAB handles the merge automatically.
To run the MATLAB diff and merge tools from command-line Git, use git difftool and git
mergetool:
• To compare two revisions of a model using the MATLAB diff tool, type:
git difftool -t mlDiff <revisonID1> <revisionID2> myModel.slx
If you do not provide revision IDs, git difftool compares the working copy to the repository
copy.
If you do not specify which model you want to compare, command-line Git will go through all
modified files and ask you if you want to compare them one by one.
• To resolve a merge conflict in a model using the MATLAB merge tool, type:
git mergetool -t mlMerge myModel.slx
35-51
35 Source Control Interface
If you do not specify which model you want to merge, command-line Git will go through all files
and ask you if you want to merge them one by one.
SourceTree
SourceTree is an interactive GUI tool that visualizes and manages Git repositories for Windows and
Mac.
1 Configure the MATLAB diff and merge tools as SourceTree external tools:
2 Configure your repository to automerge changes in different subsystems in the same SLX file
using the mlAutoMerge executable file:
Tip Customize the full path of the mlDiff, mlMerge, and mlAutoMerge executables to match both
the MATLAB installation and the operating system you are using. For more information, see “Finding
the Full Paths for MATLAB Diff, Merge, and AutoMerge” on page 35-50.
To use the MATLAB diff tool from within SourceTree, right-click a modified file under Unstaged files
and select External Diff.
To use the MATLAB merge tool when SourceTree detects a merge conflict, select the Uncommitted
changes branch, right-click a modified file, and select Resolve Conflicts > Launch External
Merge Tool.
With TortoiseSVN, you can customize your diff and merge tools based on the file extension. For
example, to use MATLAB diff and merge tools for SLX files:
1 Right-click in any file explorer window and select TortoiseSVN > Settings to open TortoiseSVN
settings.
2 In the Settings sidebar, select Diff Viewer. Click Advanced to specify the diff application based
on file extensions.
3 Click Add and fill the fields with the extension and the mlDiff executable path:
35-52
Customize External Source Control to Use MATLAB for Diff and Merge
4 Click OK and repeat the same steps to add another file extension.
5 In the Settings sidebar, select Diff ViewerMerge Tool. Click Advanced to specify the merge
application based on file extensions.
6 Click Add and fill the fields with the extension and mlMerge executable path:
Filename, extension or mime-type: .slx
External Program: "C:\Program Files\MATLAB\R20xxb\bin\win64\mlMerge.exe" %base %mine %theirs %merged
7 Click OK and repeat the same steps to add another file extension.
You can now use the MATLAB tools for diff and merge the same way you would use the TortoiseSVN
default diff and merge applications.
Note Automerging binary files with SVN , such as SLX files, is not supported.
With Perforce P4V, you can customize your diff and merge tools based on the file extension. To use
MATLAB diff and merge tools for SLX files, for example:
Tip Customize the full path of the mlDiff and mlMerge executables to match both the MATLAB
installation and the operating system you are using. For more information, see “Finding the Full
Paths for MATLAB Diff, Merge, and AutoMerge” on page 35-50.
You can now use the MATLAB tools for diff and merge the same way you would use the Perforce
default diff and merge applications.
35-53
35 Source Control Interface
See Also
Related Examples
• “Compare Files and Folders and Merge Files”
• “Automatically Merge Models” (Simulink)
• “Configure Git Environment to Merge Requirement and Link Set Files” (Requirements Toolbox)
• “Compare and Merge MAT-Files”
• “Port or Restore Model Changes in Comparison Report” (Simulink)
35-54
Write a Source Control Integration with the SDK
The SDK provides instructions for writing an integration to a source control tool that has a published
API you can call from Java.
You must create a .jar file that implements a collection of Java interfaces and a Java file, that defines
a set of required properties.
The SDK provides example source code, Javadoc, and files for validating, building, and testing your
source control integration. Build and test your own interfaces using the example as a guide. Then,
you can use your source control integration in MATLAB to work with files and projects under source
control. Download the SDK and follow the instructions.
After you write a source control integration, you can access functionality of your source control tool
directly in the Current Folder and the Current Project browsers.
Tip You can check for updated source control integration downloads on the projects Web page:
https://www.mathworks.com/products/simulink/projects.html
See Also
More About
• https://www.mathworks.com/matlabcentral/fileexchange/61483-source-control-integration-
software-development-kit
35-55
36
Unit Testing
36-2
Write Test Using Live Script
This example shows how to test a function that you create by writing a live script,
'TestRightTriLiveScriptExample.mlx'. The example function computes the angles of a right
triangle, and you create a live-script-based unit test to test the function.
• The name of the test file must start or end with the word 'test', which is case-insensitive. If the file
name does not start or end with the word 'test', the tests in the file might be ignored in certain
cases.
• Place each unit test into a separate section of the live-script file. If a section has a heading in the
Heading 1 style, the heading becomes the name of the test element. Otherwise, MATLAB® assigns
a name to the test.
• Consider how you are running your live-script-based test. If you run the test using the Run
buttons in the Live Editor and MATLAB encounters a test failure, then it stops execution of the
script and does not run any remaining tests. If you run the live script using the unit testing
framework, such as with the runtests function, then if MATLAB encounters a test failure, it still
runs remaining tests.
• When a live script runs as a test, variables defined in one test are not accessible within other
tests. Similarly, variables defined in other workspaces are not accessible to the tests.
Outside of this example, in your current MATLAB folder, create a function in a file, rightTri.m. This
function takes lengths of two sides of a triangle as input and returns the three angles of the
corresponding right triangle. The input sides are the two shorter edges of the triangle, not the
hypotenuse.
type rightTri.m
A = atand(sides(1)/sides(2));
B = atand(sides(2)/sides(1));
hypotenuse = sides(1)/sind(A);
C = asind(hypotenuse*sind(A)/sides(1));
angles = [A B C];
end
You can include equations and images in your live script to help document the test. Create the
following test for the small angle approximation. Typically, when you compare floating-point values,
you specify a tolerance for the comparison.
The rightTri function should return values consistent with the small angle approximation, such that
sin(θ) ≈ θ.
36-3
36 Unit Testing
∑ ak = 180∘
k
You can have multiple assert statements in the same test. However, if the first assertion fails, the
MATLAB does not evaluate the remaining statements.
The sum of all angles of the resulting right triangle should always be 180 degrees.
∘ ∘ ∘
Test that the sides of the triangle reduce to 1 and 3. In which case, the angles are 30 , 60 , and 90 .
tol = 1e-10;
angles = rightTri([2 2*sqrt(3)]);
assert(abs(angles(1)-30) <= tol)
assert(abs(angles(2)-60) <= tol)
assert(abs(angles(3)-90) <= tol)
For isosceles triangles, both of the non-right angles must be 45 degrees; otherwise assert throws an
error.
Test that two sides of the triangle are equal. In which case, the corresponding angles are equal.
To run your tests, best practice is to use the testing framework via the runtests function instead of
the Run button in the Live Editor. The testing framework provides additional diagnostic information.
In the event of a test failure, the framework runs subsequent tests but the Run button in the Live
36-4
Write Test Using Live Script
Editor does not. For example, to run this test at the MATLAB command prompt, type result =
runtests('TestRightTriLiveScriptExample'). For more information, see runtests.
See Also
runtests | assert
Related Examples
• “Write Script-Based Unit Tests” on page 36-6
• “Function-Based Unit Tests” on page 36-28
36-5
36 Unit Testing
This example shows how to write a script that tests a function that you create. The example function
computes the angles of a right triangle, and you create a script-based unit test to test the function.
Create this function in a file, rightTri.m, in your current MATLAB® folder. This function takes
lengths of two sides of a triangle as input and returns the three angles of the corresponding right
triangle. The input sides are the two shorter edges of the triangle, not the hypotenuse.
A = atand(sides(1)/sides(2));
B = atand(sides(2)/sides(1));
hypotenuse = sides(1)/sind(A);
C = asind(hypotenuse*sind(A)/sides(1));
angles = [A B C];
end
In your working folder, create a new script, rightTriTest.m. Each unit test checks a different
output of the rightTri function. A test script must adhere to the following conventions:
• The name of the test file must start or end with the word 'test', which is case-insensitive. If the file
name does not start or end with the word 'test', the tests in the file might be ignored in certain
cases.
• Place each unit test into a separate section of the script file. Each section begins with two percent
signs (%%), and the text that follows on the same line becomes the name of the test element. If no
text follows the %%, MATLAB assigns a name to the test. If MATLAB encounters a test failure, it
still runs remaining tests.
• In a test script, the shared variable section consists of any code that appears before the first
explicit code section (the first line beginning with %%). Tests share the variables that you define in
this section. Within a test, you can modify the values of these variables. However, in subsequent
tests, the value is reset to the value defined in the shared variables section.
• In the shared variables section (first code section), define any preconditions necessary for your
tests. If the inputs or outputs do not meet this precondition, MATLAB does not run any of the
tests. MATLAB marks the tests as failed and incomplete.
• When a script is run as a test, variables defined in one test are not accessible within other tests
unless they are defined in the shared variables section (first code section). Similarly, variables
defined in other workspaces are not accessible to the tests.
• If the script file does not include any code sections, MATLAB generates a single test element from
the full contents of the script file. The name of the test element is the same as the script file name.
In this case, if MATLAB encounters a failed test, it halts execution of the entire script.
36-6
Write Script-Based Unit Tests
In rightTriTest.m, write four tests to test the output of rightTri. Use the assert function to
test the different conditions. In the shared variables section, define four triangle geometries and
define a precondition that the rightTri function returns a right triangle.
% test triangles
tri = [7 9];
triIso = [4 4];
tri306090 = [2 2*sqrt(3)];
triSkewed = [1 1500];
% preconditions
angles = rightTri(tri);
assert(angles(3) == 90,'Fundamental problem: rightTri not producing right triangle')
angles = rightTri(triIso);
assert(sum(angles) == 180)
angles = rightTri(tri306090);
assert(sum(angles) == 180)
angles = rightTri(triSkewed);
assert(sum(angles) == 180)
Test 1 tests the summation of the triangle angles. If the summation is not equal to 180 degrees,
assert throws an error.
Test 2 tests that if two sides are equal, the corresponding angles are equal. If the non-right angles are
not both equal to 45 degrees, the assert function throws an error.
Test 3 tests that if the triangle sides are 1 and sqrt(3), the angles are 30, 60, and 90 degrees. If this
condition is not true, assert throws an error.
Test 4 tests the small-angle approximation. The small-angle approximation states that for small angles
the sine of the angle in radians is approximately equal to the angle. If it is not true, assert throws an
error.
36-7
36 Unit Testing
Run Tests
Execute the runtests function to run the four tests in rightTriTest.m. The runtests function
executes each test in each code section individually. If Test 1 fails, MATLAB still runs the remaining
tests. If you execute rightTriTest as a script instead of by using runtests, MATLAB halts
execution of the entire script if it encounters a failed assertion. Additionally, when you run tests using
the runtests function, MATLAB provides informative test diagnostics.
result = runtests('rightTriTest');
Running rightTriTest
..
================================================================================
Error occurred in rightTriTest/Test3_30_60_90Triangle and it did not run to completion.
---------
Error ID:
---------
'MATLAB:assertion:failed'
--------------
Error Details:
--------------
Error using rightTriTest (line 31)
Assertion failed.
================================================================================
.
================================================================================
Error occurred in rightTriTest/Test4_SmallAngleApproximation and it did not run to completion.
---------
Error ID:
---------
''
--------------
Error Details:
--------------
Error using rightTriTest (line 39)
Problem with small angle approximation
================================================================================
.
Done rightTriTest
__________
Failure Summary:
The test for the 30-60-90 triangle and the test for the small-angle approximation fail in the
comparison of floating-point numbers. Typically, when you compare floating-point values, you specify
a tolerance for the comparison. In Test 3 and Test 4, MATLAB throws an error at the failed assertion
and does not complete the test. Therefore, the test is marked as both Failed and Incomplete.
To provide diagnostic information (Error Details) that is more informative than 'Assertion
failed' (Test 3), consider passing a message to the assert function (as in Test 4). Or you can also
consider using function-based unit tests.
36-8
Write Script-Based Unit Tests
Save rightTriTest.m as rightTriTolTest.m, and revise Test 3 and Test 4 to use a tolerance. In
Test 3 and Test 4, instead of asserting that the angles are equal to an expected value, assert that the
difference between the actual and expected values is less than or equal to a specified tolerance.
Define the tolerance in the shared variables section of the test script so it is accessible to both tests.
For script-based unit tests, manually verify that the difference between two values is less than a
specified tolerance. If instead you write a function-based unit test, you can access built-in constraints
to specify a tolerance when comparing floating-point values.
% test triangles
tri = [7 9];
triIso = [4 4];
tri306090 = [2 2*sqrt(3)];
triSkewed = [1 1500];
% preconditions
angles = rightTri(tri);
assert(angles(3) == 90,'Fundamental problem: rightTri not producing right triangle')
angles = rightTri(triIso);
assert(sum(angles) == 180)
angles = rightTri(tri306090);
assert(sum(angles) == 180)
angles = rightTri(triSkewed);
assert(sum(angles) == 180)
36-9
36 Unit Testing
result = runtests('rightTriTolTest');
Running rightTriTolTest
....
Done rightTriTolTest
__________
rt = table(result)
rt =
4×6 table
See Also
runtests | assert
Related Examples
• “Write Script-Based Test Using Local Functions” on page 36-11
• “Function-Based Unit Tests” on page 36-28
36-10
Write Script-Based Test Using Local Functions
This example shows how to write a script-based test that uses local functions as helper functions. The
example function approximates the sine and cosine of an angle. The script-based test checks the
approximation using local functions to check for equality within a tolerance.
Create this function in a file, approxSinCos.m, in your current MATLAB folder. This function takes
an angle in radians and approximates the sine and cosine of the angle using Taylor series.
%% Test 0rad
% Test expected values of 0
[sinApprox,cosApprox] = approxSinCos(0);
assertWithAbsTol(sinApprox,0)
assertWithRelTol(cosApprox,1)
%% Test 2pi
% Test expected values of 2pi
[sinApprox,cosApprox] = approxSinCos(2*pi);
assertWithAbsTol(sinApprox,0)
assertWithRelTol(cosApprox,1)
36-11
36 Unit Testing
function assertWithAbsTol(actVal,expVal,varargin)
% Helper function to assert equality within an absolute tolerance.
% Takes two values and an optional message and compares
% them within an absolute tolerance of 1e-6.
tol = 1e-6;
tf = abs(actVal-expVal) <= tol;
assert(tf, varargin{:});
end
function assertWithRelTol(actVal,expVal,varargin)
% Helper function to assert equality within a relative tolerance.
% Takes two values and an optional message and compares
% them within a relative tolerance of 0.1%.
relTol = 0.001;
tf = abs(expVal - actVal) <= relTol.*abs(expVal);
assert(tf, varargin{:});
end
Each unit test uses assert to check different output of the approxSinCos function. Typically, when
you compare floating-point values, you specify a tolerance for the comparison. The local functions
assertWithAbsTol and assertWithRelTol are helper functions to compute whether the actual
and expected values are equal within the specified absolute or relative tolerance.
• Test 0rad tests whether the computed and expected values for an angle of 0 radians are within
an absolute tolerance of 1e-6 or a relative tolerance 0.1%. Typically, you use absolute tolerance to
compare values close to 0.
• Test 2pi tests whether the computed and expected values for an angle of radians are equal
within an absolute tolerance of 1e-6 or a relative tolerance 0.1%.
• Test pi over 4 equality tests whether the sine and cosine of are equal within a relative
tolerance of 0.1%.
• Test matches MATLAB fcn tests whether the computed sine and cosine of are equal to
the values from the sin and cos functions within a relative tolerance of 0.1%.
Run Tests
Execute the runtests function to run the four tests in approxSinCosTest.m. The runtests
function executes each test individually. If one test fails, MATLAB still runs the remaining tests. If you
execute approxSinCosTest as a script instead of using runtests, MATLAB halts execution of the
entire script if it encounters a failed assertion. Additionally, when you run tests using the runtests
function, MATLAB provides informative test diagnostics.
results = runtests('approxSinCosTest');
Running approxSinCosTest
....
Done approxSinCosTest
__________
rt = table(results)
36-12
Write Script-Based Test Using Local Functions
rt =
4x6 table
See Also
runtests | assert
Related Examples
• “Write Script-Based Unit Tests” on page 36-6
More About
• “Add Functions to Scripts” on page 18-13
36-13
36 Unit Testing
Typically, with script-based tests, you create a test file, and pass the file name to the runtests
function without explicitly creating a suite of Test objects. If you create an explicit test suite, there
are additional features available in script-based testing. These features include selecting tests and
using plugins to customize the test runner. For additional functionality, consider using function-based
or class-based unit tests. For more information, see “Ways to Write Unit Tests” on page 36-212.
Also, you can create a test suite from all the test files in a specified folder using the
matlab.unittest.TestSuite.fromFolder method. If you know the name of a particular test in
your script-based test file, you can create a test suite from that test using
matlab.unittest.TestSuite.fromName.
Test Selection
With an explicit test suite, use selectors to refine your suite. Several of the selectors are applicable
only for class-based tests, but you can select tests for your suite based on the test name:
• Use the 'Name' name-value pair argument in a suite generation method, such as
matlab.unittest.TestSuite.fromFile.
• Use a selectors instance and optional constraints instance.
36-14
Extend Script-Based Tests
import matlab.unittest.selectors.HasName
import matlab.unittest.constraints.ContainsSubstring
import matlab.unittest.TestSuite.fromFile
f = 'rightTriTolTest.m';
selector = HasName(ContainsSubstring('Triangle'));
% fromFile, selector
suite = TestSuite.fromFile(f,selector)
% selectIf, selector
fullSuite = TestSuite.fromFile(f);
suite = selectIf(fullSuite,selector)
If you use one of the suite creation methods with a selector or name-value pair, the testing framework
creates the filtered suite. If you use the selectIf method, the testing framework creates a full test
suite and then filters it. For large test suites, this approach can have performance implications.
After you run tests, you can access recorded diagnostics using the DiagnosticRecord field in the
Details property on the TestResult object. For example, if your test results are stored in the
variable results, then result(2).Details.DiagnosticRecord contains the recorded
diagnostics for the second test in the suite.
The recorded diagnostics are DiagnosticRecord objects. To access particular types of test
diagnostics for a test, use the selectFailed, selectPassed, selectIncomplete, and
selectLogged methods of the DiagnosticRecord class.
36-15
36 Unit Testing
For example,use test suite, suite, to create a silent test runner and run the tests with the run
method of TestRunner.
runner = matlab.unittest.TestRunner.withNoPlugins;
results = runner.run(suite);
Use plugins to customize the test runner further. For example, you can redirect output, determine
code coverage, or change how the test runner responds to warnings. For more information, see “Add
Plugin to Test Runner” on page 36-112 and the plugins classes.
See Also
plugins | selectors | matlab.unittest.constraints | TestRunner | TestSuite
Related Examples
• “Add Plugin to Test Runner” on page 36-112
36-16
Run Tests in Editor
In your current folder, create a function-based test file named sampleTest.m (or sampleTest.mlx).
function testA(testCase)
verifyEqual(testCase,2+3,5)
end
function testB(testCase)
verifyGreaterThan(testCase,42,13)
end
function testC(testCase)
verifySubstring(testCase,"Hello World!","llo")
end
When you save the test file, the Run section in the Editor (or Live Editor) tab changes and lets you
run the tests in the file.
Click the Run Tests icon. MATLAB adds all the tests in the file to Test Browser and runs them. The
Command Window displays the test run progress. In this example, all the tests pass.
Running sampleTest
...
Done sampleTest
__________
Now, place your cursor in the testB function and click Run Current Test. MATLAB includes only
testB in the test browser and runs it.
Running sampleTest
.
Done sampleTest
__________
In addition to running tests, you can customize the test run by using the test options under Run
Tests. To access the full list of test options, click the drop-down arrow under Run Tests, and then
click Customize Test Run. MATLAB uses the selected test options whether you run all the tests in a
file or just the test at your cursor location.
36-17
36 Unit Testing
36-18
Run Tests in Editor
Note The Strict, Parallel, Output Detail, and Logging Level options are synchronized across the Run
section in the Editor (or Live Editor) tab and the Test Browser toolbar. If you select an option in one
of these interfaces, the selection applies to the other interface as well. For example, if you enable
parallel test execution in the test browser, MATLAB automatically selects the Parallel test option in
the Run section of the toolstrip.
See Also
Apps
Test Browser
Functions
runtests
More About
• “Run Tests Using Test Browser” on page 36-20
• “Insert Test Code Using Editor” on page 36-225
36-19
36 Unit Testing
For example, create a function-based test file named sampleTest.m in your current folder.
function testA(testCase)
verifyEqual(testCase,2+3,5)
end
function testB(testCase)
verifyGreaterThan(testCase,13,42)
end
function testC(testCase)
verifySubstring(testCase,"Hello World!","llo")
end
function testD(testCase)
assumeTrue(testCase,1)
end
function testE(testCase)
assertSize(testCase,ones(2,5,3),[2 5 3])
end
testBrowser
Add the tests to the test browser by clicking the Add tests button on the toolbar and then selecting
the sampleTest.m file. The test browser imports the tests and creates a test suite. The tests in the
suite appear as a test tree, where the parent node is a link pointing to the test file and the child nodes
are the names of the test procedures. To open the test file from the test browser, click the link in the
tree. To view the code for a specific test, right-click the test name and select Open Test.
36-20
Run Tests Using Test Browser
When you create a test tree by adding tests to the test browser, child nodes in the tree display a Not
Run status . After the test that corresponds to a child node runs, the test browser updates its
status to Passed , Failed , or Incomplete . The status buttons on the toolbar provide a
summary of the current test suite. In this example, the test suite contains five tests, corresponding to
the local functions in the test file. The number, 5, next to the Not Run status on the toolbar
indicates that none of the tests have run.
You can also add tests to the test browser by clicking the drop-down arrow and selecting an option
from the list. The list lets you add tests from files or folders:
• To add the tests from specified test files, select Select Files.
• To add the tests from the currently open test file, select Current File.
• To add the tests from a specified folder, select Select Folder.
• To add the tests from your current folder, select Current Folder.
• To include the tests in the subfolders of the folder you specify, select Include Subfolders.
36-21
36 Unit Testing
When you add multiple files, the test tree includes multiple parent nodes, each pointing to a different
test file. You can remove a parent node and its children from the test tree by right-clicking the parent
node and selecting Remove Test File. To remove all the tests from the test browser, click the three-
dot button and select Remove all tests, or right-click a top-level parent node and select Remove
All Tests.
Run Tests
You can run the tests added to the test browser interactively. You can run all the tests, or you can run
any of the tests in isolation:
• To run all the tests that appear in the Test Browser panel, click the Run current suite button on
the toolbar.
• To run a test file, right-click its node in the test tree and select Run Test File.
• To run a single test, right-click its name in the test tree and select Run Test.
• To run multiple tests, press the Ctrl key while making test selections with the mouse. (On macOS
systems, use the Command key instead.) Then, right-click one of the selected nodes and select
Run Tests.
For example, run the tests in the sampleTest.m file by clicking the Run current suite button . The
test browser runs the tests and updates their statuses. As the tests run, the Command Window
displays the test run progress and diagnostics. In this example, three tests pass, one test fails due to
a verification failure, and one test remains incomplete due to an assumption failure. The status
buttons on the toolbar provide a summary of the test results.
Even though the Command Window displays diagnostic information for your tests, you can access this
information directly in the test browser. To access the diagnostics for a test, click its node in the test
36-22
Run Tests Using Test Browser
tree. For example, click the name of the incomplete test. The Test Diagnostics Viewer section at the
bottom of the Test Browser panel indicates that the test did not run to completion due to an
assumption failure. You can collapse and expand the Test Diagnostics Viewer section.
You can use the status buttons on the toolbar as filters to focus on a specific group of tests. Using
these filters, you can display tests that passed, failed, remained incomplete, or did not run. To set a
filter, click its button on the toolbar. For example, display only the failed or incomplete tests.
36-23
36 Unit Testing
You can interact with a filtered suite the same way you interact with the original test suite. For
example, you can run the filtered suite by clicking the Run current suite button . To clear a filter,
click its button on the toolbar. To clear all the filters, click the three-dot button and select Clear
status filters.
To debug a test failure, set a breakpoint on the highlighted line of code. Then, run the test by right-
clicking its node in the test tree and selecting Run Test. MATLAB enters debug mode and enables
debugging capabilities that you can use to investigate the cause of the test failure. For more
information on debugging MATLAB files, see “Debug MATLAB Code Files” on page 22-2.
36-24
Run Tests Using Test Browser
36-25
36 Unit Testing
Note The parallel execution, strictness, output detail, and logging level options are synchronized
across the Test Browser toolbar and the Run section in the Editor (or Live Editor) tab of the
MATLAB Toolstrip. If you select an option in one of these interfaces, the selection applies to the other
interface as well. For example, if you enable parallel test execution in the test browser, MATLAB
automatically selects this option in the Run section of the toolstrip.
To generate a code coverage report, click the Open coverage settings button on the toolbar, and
then select Enable coverage reporting. The Coverage Settings section expands and lets you
specify source code and choose whether to automatically open the coverage report after the test run.
The coverage settings persist for the duration of your current MATLAB session.
• To specify source files, under Source, click the Add Files button and select the files.
• To specify a source folder, under Source, click the Add Folder button and select the folder. To
include source code in the subfolders of the specified folder, right-click the folder path and then
select Include Subfolders.
• To automatically open the generated code coverage report after the test run, under Report, select
Open coverage report after run. If you clear the check box, you can access the report by using
the file path in the Command Window.
36-26
Run Tests Using Test Browser
If you run all your tests or a subset of them with coverage reporting enabled, the test browser
generates a code coverage report for your source code based on the tests that ran. If you do not
specify any source code, the tests still run, but the test browser does not generate a report.
See Also
Apps
Test Browser
Functions
runtests
More About
• “Run Tests in Editor” on page 36-17
• “Insert Test Code Using Editor” on page 36-225
• “Collect Statement and Function Coverage Metrics for MATLAB Source Code” on page 36-220
External Websites
• What Is Test Browser?
• Get Started with MATLAB Unit Testing Framework
36-27
36 Unit Testing
The main function collects all of the local test functions into a test array. The name of the main
function corresponds to the name of your test file and should start or end with the word 'test', which
is case-insensitive. If the file name does not start or end with the word 'test', the tests in the file
might be ignored in certain cases. In this sample case, the MATLAB file is exampleTest.m. The main
function needs to make a call to functiontests to generate a test array, tests. Use
localfunctions as the input to functiontests to automatically generate a cell array of function
handles to all the local functions in your file. This is a typical main function.
Individual test functions are included as local functions in the same MATLAB file as the main (test-
generating) function. These test function names must begin or end with the case-insensitive word,
‘test’. Each of the local test functions must accept a single input, which is a function test case object,
testCase. The testing framework automatically generates this object. For more information on
creating test functions, see “Write Simple Test Case Using Functions” on page 36-32 and “Table of
Verifications, Assertions, and Other Qualifications” on page 36-59. This is a typical example of
skeletal local-test functions.
function testFunctionOne(testCase)
% Test specific code
end
function testFunctionTwo(testCase)
% Test specific code
end
Setup and teardown code, also referred to as test fixture functions, set up the pretest state of the
system and return it to the original state after running the test. There are two types of these
functions: file fixture functions that run once per test file, and fresh fixture functions that run before
36-28
Function-Based Unit Tests
and after each local test function. These functions are not required to generate tests. In general, it is
preferable to use fresh fixtures over file fixtures to increase unit test encapsulation.
A function test case object, testCase, must be the only input to file fixture and fresh fixture
functions. The testing framework automatically generates this object. The TestCase object is a
means to pass information between setup functions, test functions, and teardown functions. Its
TestData property is, by default, a struct, which allows easy addition of fields and data. Typical
uses for this test data include paths and graphics handles. For an example using the TestData
property, see “Write Test Using Setup and Teardown Functions” on page 36-35.
File Fixture Functions
Use file fixture functions to share setup and teardown functions across all the tests in a file. The
names for the file fixture functions must be setupOnce and teardownOnce, respectively. These
functions execute a single time for each file. You can use file fixtures to set a path before testing, and
then reset it to the original path after testing. This is a typical example of skeletal file fixture setup
and teardown code.
Use fresh fixture functions to set up and tear down states for each local test function. The names for
these fresh fixture functions must be setup and teardown, respectively. You can use fresh fixtures to
obtain a new figure before testing and to close the figure after testing. This is typical example of
skeletal test function level setup and teardown code.
%% Test Functions
function testFunctionOne(testCase)
% Test specific code
end
function testFunctionTwo(testCase)
% Test specific code
end
36-29
36 Unit Testing
To run tests from the command prompt, use the runtests function with your MATLAB test file as
input. For example:
results = runtests('exampleTest.m')
For more information on running tests see runtests and “Run Tests for Various Workflows” on page
36-108.
36-30
Function-Based Unit Tests
time it took to run the test. For more information, see “Analyze Test Case Results” on page 36-143
and “Analyze Failed Test Results” on page 36-146.
See Also
runtests | functiontests | localfunctions
Related Examples
• “Write Simple Test Case Using Functions” on page 36-32
• “Write Test Using Setup and Teardown Functions” on page 36-35
36-31
36 Unit Testing
You can test your MATLAB® program by defining unit tests within a single file that contains a main
function and local test functions. In a function-based test, each local function executes a portion of
the software and qualifies the correctness of the produced result. For more information about
function-based tests, see “Function-Based Unit Tests” on page 36-28.
This example shows how to write a function-based test to qualify the correctness of a function defined
in a file in your current folder. The quadraticSolver function takes as inputs the coefficients of a
quadratic polynomial and returns the roots of that polynomial. If the coefficients are specified as
nonnumeric values, the function throws an error.
function r = quadraticSolver(a,b,c)
% quadraticSolver returns solutions to the
% quadratic equation a*x^2 + b*x + c = 0.
end
Create Tests
To test the quadraticSolver function, create the test file quadraticSolverTest.m in your
current folder. Then, define a main function and two local functions in the file to test
quadraticSolver against real and imaginary solutions. The name of the main and local functions
must start or end with the word "test", which is case-insensitive. Additionally, the name of the main
function must correspond to the name of your test file.
To run function-based unit tests, you must define a main function that collects all of the local test
functions into a test array. Define the main function quadraticSolverTest in your test file. The
main function calls functiontests to generate the test array tests. Pass localfunctions to
functiontests to automatically generate a cell array of function handles to the local functions in
your file.
Add local functions to the test file to test the quadraticSolver function against real and imaginary
solutions. The order of the tests within the file does not matter. Each local function must accept a
single input testCase, which is a matlab.unittest.FunctionTestCase object. The testing
framework automatically generates this object. The function uses the object to perform qualifications
for testing values and responding to failures.
36-32
Write Simple Test Case Using Functions
Define a local function testRealSolution to verify that quadraticSolver returns the correct real
solutions for specific coefficients. For example, the equation x2 − 3x + 2 = 0 has real solutions x = 1
and x = 2. The function calls quadraticSolver with the coefficients of this equation. Then, it uses
the verifyEqual qualification function to compare the actual output actSolution to the expected
output expSolution.
function testRealSolution(testCase)
actSolution = quadraticSolver(1,-3,2);
expSolution = [2 1];
verifyEqual(testCase,actSolution,expSolution)
end
function testRealSolution(testCase)
actSolution = quadraticSolver(1,-3,2);
expSolution = [2 1];
verifyEqual(testCase,actSolution,expSolution)
end
function testImaginarySolution(testCase)
actSolution = quadraticSolver(1,2,10);
expSolution = [-1+3i -1-3i];
verifyEqual(testCase,actSolution,expSolution)
end
Use the runtests function to run the tests defined in the quadraticSolverTest.m file. In this
example, both of the tests pass.
results = runtests('quadraticSolverTest.m')
Running quadraticSolverTest
..
Done quadraticSolverTest
__________
results =
1×2 TestResult array with properties:
Name
Passed
Failed
36-33
36 Unit Testing
Incomplete
Duration
Details
Totals:
2 Passed, 0 Failed, 0 Incomplete.
0.016572 seconds testing time.
results = run(quadraticSolverTest)
Running quadraticSolverTest
..
Done quadraticSolverTest
__________
results =
1×2 TestResult array with properties:
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
2 Passed, 0 Failed, 0 Incomplete.
0.0072908 seconds testing time.
See Also
runtests | functiontests | localfunctions
More About
• “Function-Based Unit Tests” on page 36-28
• “Table of Verifications, Assertions, and Other Qualifications” on page 36-59
• “Analyze Test Case Results” on page 36-143
• “Create Simple Test Suites” on page 36-106
36-34
Write Test Using Setup and Teardown Functions
This example shows how to write unit tests for a couple of MATLAB® figure properties using file
fixtures and fresh fixtures.
Create a file containing the main function that tests figure properties and include two test functions.
One function verifies that the x-axis limits are correct, and the other one verifies that the face color of
a surface is correct.
In a folder on your MATLAB path, create axesPropertiesTest.m. In the main function of this file,
have functiontests create an array of tests from each local function in axesPropertiesTest.m
with a call to the localfunctions function.
File fixture functions are setup and teardown code that runs a single time in your test file. These
fixtures are shared across the test file. In this example, the file fixture functions create a temporary
folder and set it as the current working folder. They also create and save a new figure for testing.
After tests are complete, the framework reinstates the original working folder and deletes the
temporary folder and saved figure.
In this example, a helper function creates a simple figure — a red cylinder. In a more realistic
scenario, this code is part of the product under test and is computationally expensive, thus motivating
the intent to create the figure only once and to load independent copies of the result for each test
function. For this example, however, you want to create this helper function as a local function to
axesPropertiesTest. Note that the test array does not include the function because its name does
not start or end with ‘test’.
Write a helper function that creates a simple red cylinder and add it as a local function to
axesPropertiesTest.
function f = createFigure
f = figure;
ax = axes('Parent',f);
cylinder(ax,10)
h = findobj(ax,'Type','surface');
h.FaceColor = [1 0 0];
end
You must name the setup and teardown functions of a file test fixture setupOnce and
teardownOnce, respectively. These functions take a single input argument testCase into which the
testing framework automatically passes a function test case object. This test case object contains a
TestData structure that allows data to pass between setup, test, and teardown functions. In this
example, the TestData structure uses assigned fields to store the original path, the temporary folder
name, and the figure file name.
36-35
36 Unit Testing
function setupOnce(testCase)
% Create and change to temporary folder
testCase.TestData.origPath = pwd;
testCase.TestData.tmpFolder = "tmpFolder" + ...
string(datetime('now','Format',"yyyyMMdd'T'HHmmss"));
mkdir(testCase.TestData.tmpFolder)
cd(testCase.TestData.tmpFolder)
% Create and save a figure
testCase.TestData.figName = 'tmpFig.fig';
aFig = createFigure;
saveas(aFig,testCase.TestData.figName)
close(aFig)
end
function teardownOnce(testCase)
delete(testCase.TestData.figName)
cd(testCase.TestData.origPath)
rmdir(testCase.TestData.tmpFolder)
end
Fresh fixtures are function-level setup and teardown code that runs before and after each test
function in your file. In this example, the functions open the saved figure and find the handles. After
testing, the framework closes the figure.
You must name fresh fixture functions setup and teardown, respectively. Similar to the file fixture
functions, these functions take a single input argument testCase. In this example, these functions
create a new field in the TestData structure that includes handles to the figure and to the axes. This
allows information to pass between setup, test, and teardown functions.
Create the setup and teardown functions as local functions to axesPropertiesTest. Open the
saved figure for each test to ensure test independence.
function setup(testCase)
testCase.TestData.Figure = openfig(testCase.TestData.figName);
testCase.TestData.Axes = findobj(testCase.TestData.Figure, ...
'Type','Axes');
end
function teardown(testCase)
close(testCase.TestData.Figure)
end
In addition to custom setup and teardown code, the testing framework provides some classes for
creating fixtures. For more information, see matlab.unittest.fixtures.
Each test is a local function that follows the naming convention of having ‘test’ at the beginning or
end of the function name. The test array does not include local functions that do not follow this
convention. Similar to setup and teardown functions, individual test functions must accept a single
input argument testCase. Use this test case object for verifications, assertions, assumptions, and
fatal assertions.
The testDefaultXLim function verifies that the x-axis limits are large enough to display the
cylinder. The lower limit needs to be less than -10, and the upper limit needs to be greater than 10.
36-36
Write Test Using Setup and Teardown Functions
These values come from the figure generated in the helper function — a cylinder with a 10 unit radius
centered on the origin. This test function opens the figure created and saved in the setupOnce
function, queries the axes limit, and verifies the limits are correct. The qualification functions
verifyLessThanOrEqual and verifyGreaterThanOrEqual take as inputs the test case, the
actual value, the expected value, and optional diagnostic information to display in the case of failure.
function testDefaultXLim(testCase)
xlim = testCase.TestData.Axes.XLim;
verifyLessThanOrEqual(testCase,xlim(1),-10, ...
'Minimum x-limit was not small enough')
verifyGreaterThanOrEqual(testCase,xlim(2),10, ...
'Maximum x-limit was not large enough')
end
The surfaceColorTest function accesses the figure that you created and saved in the setupOnce
function. surfaceColorTest queries the face color of the cylinder and verifies that it is red. The
color red has an RGB value of [1 0 0]. The qualification function verifyEqual takes as inputs the
test case, the actual value, the expected value, and optional diagnostic information to display in the
case of failure. Typically when using verifyEqual on floating-point values, you specify a tolerance
for the comparison. For more information, see matlab.unittest.constraints.
function surfaceColorTest(testCase)
h = findobj(testCase.TestData.Axes,'Type','surface');
co = h.FaceColor;
verifyEqual(testCase,co,[1 0 0],'Face color is incorrect')
end
Now the axesPropertiesTest.m file is complete with a main function, a helper function, file fixture
functions, fresh fixture functions, and two test functions. You are ready to run the tests.
Run Tests
The next step is to run the tests using the runtests function. In this example, the call to runtests
results in the following steps:
36-37
36 Unit Testing
results = runtests('axesPropertiesTest.m')
Running axesPropertiesTest
..
Done axesPropertiesTest
__________
results =
1×2 TestResult array with properties:
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
2 Passed, 0 Failed, 0 Incomplete.
0.5124 seconds testing time.
To access functionality available to tables, create one from the TestResult objects.
rt = table(results)
rt=2×6 table
Name Passed Failed Incomplete Duration De
_______________________________________ ______ ______ __________ ________ ____
sortrows(rt,'Duration')
ans=2×6 table
Name Passed Failed Incomplete Duration De
_______________________________________ ______ ______ __________ ________ ____
writetable(rt,'myTestResults.xls')
See Also
matlab.unittest.fixtures | matlab.unittest.constraints
36-38
Write Test Using Setup and Teardown Functions
More About
• “Function-Based Unit Tests” on page 36-28
• “Write Simple Test Case Using Functions” on page 36-32
• “Table of Verifications, Assertions, and Other Qualifications” on page 36-59
36-39
36 Unit Testing
Typically, with function-based tests, you create a test file and pass the file name to the runtests
function without explicitly creating a suite of Test objects. However, if you create an explicit test
suite, additional features are available in function-based testing. These features include:
For additional functionality, consider using class-based unit tests. For more information, see “Ways to
Write Unit Tests” on page 36-212.
These fixtures take the place of manually coding the actions in the setupOnce, teardownOnce,
setup, and teardown functions of your function-based test.
For example, if you manually write setup and teardown code to set up a temporary folder for each
test, and then you make that folder your current working folder, your setup and teardown functions
could look like this.
function setup(testCase)
% store current folder
testCase.TestData.origPath = pwd;
36-40
Extend Function-Based Tests
end
function teardown(testCase)
% change to original folder
cd(testCase.TestData.origPath)
However, you also can use a fixture to replace both of those functions with just a modified setup
function. The fixture stores the information necessary to restore the initial state and performs the
teardown actions.
function setup(testCase)
% create temporary folder
f = testCase.applyFixture(matlab.unittest.fixtures.TemporaryFolderFixture);
Test Selection
With an explicit test suite, use selectors to refine your suite. Several of the selectors are applicable
only for class-based tests, but you can select tests for your suite based on the test name:
• Use the 'Name' name-value pair argument in a suite generation method, such as
matlab.unittest.TestSuite.fromFile.
• Use a selectors instance and optional constraints instance.
import matlab.unittest.selectors.HasName
import matlab.unittest.constraints.ContainsSubstring
import matlab.unittest.TestSuite.fromFile
f = 'rightTriTolTest.m';
36-41
36 Unit Testing
selector = HasName(ContainsSubstring('Triangle'));
% fromFile, selector
suite = TestSuite.fromFile(f,selector)
% selectIf, selector
fullSuite = TestSuite.fromFile(f);
suite = selectIf(fullSuite,selector)
If you use one of the suite creation methods with a selector or name-value pair, the testing framework
creates the filtered suite. If you use the selectIf method, the testing framework creates a full test
suite and then filters it. For large test suites, this approach can have performance implications.
Test Running
There are several ways to run a function-based test.
For more information, see “Run Tests for Various Workflows” on page 36-108.
After you run tests, you can access recorded diagnostics using the DiagnosticRecord field in the
Details property on the TestResult object. For example, if your test results are stored in the
variable results, then result(2).Details.DiagnosticRecord contains the recorded
diagnostics for the second test in the suite.
The recorded diagnostics are DiagnosticRecord objects. To access particular types of test
diagnostics for a test, use the selectFailed, selectPassed, selectIncomplete, and
selectLogged methods of the DiagnosticRecord class.
36-42
Extend Function-Based Tests
For example,use test suite, suite, to create a silent test runner and run the tests with the run
method of TestRunner.
runner = matlab.unittest.TestRunner.withNoPlugins;
results = runner.run(suite);
Use plugins to customize the test runner further. For example, you can redirect output, determine
code coverage, or change how the test runner responds to warnings. For more information, see “Add
Plugin to Test Runner” on page 36-112 and the plugins classes.
See Also
matlab.unittest.TestCase | matlab.unittest.TestSuite |
matlab.automation.diagnostics.Diagnostic | matlab.unittest.qualifications |
matlab.unittest.constraints | matlab.unittest.selectors
Related Examples
• “Write Simple Test Case Using Functions” on page 36-32
• “Run Tests for Various Workflows” on page 36-108
• “Add Plugin to Test Runner” on page 36-112
36-43
36 Unit Testing
Write your class-based unit tests as Test methods within your test class definition file. A Test
method is a method defined in a methods block with the Test attribute. Test methods can use
qualifications for testing values and responding to failures. In addition to the Test attribute,
TestCase subclasses can leverage a variety of framework-specific attributes to specify tests and test
fixtures. For example, you can use the TestMethodSetup and TestMethodTeardown method
attributes to specify setup and teardown code for each test in your test class.
In addition, the MyTestClass class uses framework-specific method attributes to define the setup
and teardown methods. The testing framework runs these methods before and after each test,
respectively. For more information about setup and teardown code in test classes, see “Write Setup
and Teardown Code Using Classes” on page 36-56.
methods (TestMethodTeardown)
function teardown(testCase)
% Teardown code
end
end
methods (Test)
function test1(testCase)
% Test code
end
function test2(testCase)
% Test code
end
end
end
Unit tests typically include qualifications for testing values and responding to failures. For example,
to test a function, a Test method can specify the actual and expected returned values of the function
36-44
Class-Based Unit Tests
and then use a qualification method to test for their equality. For illustrative purposes, the PlusTest
test class has a Test method for testing the plus function. (In practice, a test class tests user-
defined code.) The myTest method calls the verifyEqual qualification method to verify that
plus(2,3) produces the expected value 5. When creating your own test class, you have access to
the full library of qualifications in the matlab.unittest.qualifications namespace. To
determine which qualification to use, see “Table of Verifications, Assertions, and Other Qualifications”
on page 36-59.
For a simple example of how to write and run class-based unit tests, see “Write Simple Test Case
Using Classes” on page 36-53.
1 Sets up the shared test fixtures before running any of the test classes in the group
2 Runs each test class in the group
3 Tears down the shared test fixtures after running all the test classes in the group
This diagram shows how the testing framework runs each test class in step 2.
36-45
36 Unit Testing
Create class-l evel Run class-l evel Loop over Run class-l evel Delete class-l evel
TestCase object setup code tests teardown code TestCase object
36-46
Class-Based Unit Tests
1 Create class-level TestCase object — The framework creates an object of the test class.
2 Run class-level setup code — The framework uses the class-level TestCase object to run the
class-level setup code specified in the TestClassSetup methods block. The class-level
TestCase object reflects the updated environment as a result of the class-level setup code.
3 Loop over tests:
Note To prevent a test from affecting the environment of other tests, TestCase instances
passed to different Test methods are independent copies. In other words, modifications to
the test case in a Test method remain scoped to that method and do not propagate to other
Test methods in the test class.
b Run method-level setup code — The framework uses the method-level TestCase object to
run the method-level setup code specified in the TestMethodSetup methods block. The
method-level TestCase object reflects the updated environment as a result of the method-
level setup code.
c Run test — The framework uses the method-level TestCase object to run the Test method
corresponding to the test. If the test is parameterized, the framework uses the
parameterization information to run the method.
d Run method-level teardown code — The framework uses the method-level TestCase object
to run the method-level teardown code specified using a call to the addTeardown method in
the TestMethodSetup methods block or in the TestMethodTeardown methods block.
e Delete method-level TestCase object — The framework discards the method-level
TestCase object used to run the test and its corresponding method-level setup and
teardown code.
4 Run class-level teardown code — The framework uses the class-level TestCase object to run the
class-level teardown code specified using a call to the addTeardown method in the
TestClassSetup methods block or in the TestClassTeardown methods block.
5 Delete class-level TestCase object — The framework discards the class-level TestCase object
used to run the tests in the test class.
Note Uncaught errors and qualification failures can affect the test run workflow. For instance, if an
assumption failure occurs in the TestClassSetup or TestClassTeardown methods block, the
testing framework marks the entire test class as filtered and skips looping over the Test methods.
36-47
36 Unit Testing
• If you add code to your test class for setting up the test environment, also include code to restore
the environment to its original state by performing teardown actions symmetrically in the reverse
order of their corresponding setup actions.
• To access a global state, such as the MATLAB search path or output display format, use a method
instead of a default property value.
• To specify test parameter values, use value objects instead of handle objects.
For more information, see “Write Independent and Repeatable Tests” on page 36-49.
• Share fixtures among test classes. For more information, see “Write Tests Using Shared Fixtures”
on page 36-66.
• Group tests into categories and then run the tests with specified tags. For more information, see
“Tag Unit Tests” on page 36-62.
• Write parameterized tests to combine and execute tests on specified lists of parameters. For more
information, see “Use Parameters in Class-Based Tests” on page 36-76.
• Use subclassing and inheritance to share and reuse test content. For example, you can reuse the
parameters and methods defined in a test class by deriving subclasses. For more information, see
“Hierarchies of Classes — Concepts”.
See Also
Classes
matlab.unittest.TestCase
Related Examples
• “Write Simple Test Case Using Classes” on page 36-53
• “Write Setup and Teardown Code Using Classes” on page 36-56
• “Insert Test Code Using Editor” on page 36-225
• “Write Independent and Repeatable Tests” on page 36-49
36-48
Write Independent and Repeatable Tests
• For setup code specified in a TestClassSetup methods block, specify the corresponding
teardown code by using the addTeardown method in the same block or by specifying a
TestClassTeardown methods block.
• For setup code specified in a TestMethodSetup methods block, specify the corresponding
teardown code by using the addTeardown method in the same block or by specifying a
TestMethodTeardown methods block.
• For setup code specified using a shared test fixture, do not add separate teardown code to your
test class. The fixture automatically restores the environment when the testing framework tears it
down. Shared test fixtures are specified using the SharedTestFixtures attribute of TestCase
subclasses.
For example, in the AsymmetryExampleTest class, the setFormat method runs a single time
before the tests because it is defined in a TestClassSetup methods block. However, the
restoreFormat method runs after each test in the test class because it is defined in a
TestMethodTeardown methods block. If you set the line spacing format to its default value
(format loose) and then run the AsymmetryExampleTest class, one of the tests in the test class
fails because the restoreFormat method restores the format to its original state after running the
first test. In other words, the teardown code runs earlier than expected. In contrast, the tests in the
SymmetryExampleTest class pass because the addTeardown method call runs the teardown code
only after both the tests in the class run. Therefore, the format remains the same during testing.
36-49
36 Unit Testing
function formatTest2(testCase)
testCase.verifyEqual(format().LineSpacing,"compact")
end
end
end
It is recommended that you perform all teardown actions from within the TestMethodSetup and
TestClassSetup methods blocks using the addTeardown method instead of implementing
corresponding teardown methods in the TestMethodTeardown and TestClassTeardown methods
blocks. Call addTeardown immediately before or after the original state change, without any other
code in between that can throw an exception. Using addTeardown allows the testing framework to
execute the teardown code in the reverse order of the setup code and also creates exception-safe test
content.
For more information about setup and teardown code in test classes, see “Write Setup and Teardown
Code Using Classes” on page 36-56 and “Write Tests Using Shared Fixtures” on page 36-66.
For example, in the PropertyExampleTest class, the OriginalFormat property is set to the
display format at class parse time, and its value remains the same in different runs of the test class. If
you change the line spacing format after the first run, the property still points to the original line
spacing format from class parse time. As a result, a second run of the test class corrupts the display
format because the addTeardown method call always restores the format to its value at class parse
time and not the value prior to the test run. In contrast, in the MethodExampleTest class, the
36-50
Write Independent and Repeatable Tests
current display format is correctly captured because the formatTest method runs every time the
test class runs. Therefore, the addTeardown method call in the MethodExampleTest class can
restore the display format to its value prior to the test run, and the test does not corrupt the display
format.
For example, the first time you run the HandleExampleTest class, the parameterized tests
successfully run using the figures created in the properties block. After testing, each test closes
the figure passed to it as a parameter value using a call to the addTeardown method. If you run the
test class again, the tests fail because MATLAB evaluates default property values a single time, when
parsing the class. In other words, there are no figures to test with in subsequent runs of the
HandleExampleTest class. In contrast, the tests in the ValueExampleTest class are repeatable
because each parameterized test creates its own figure by invoking a function handle and then closes
the figure after testing.
For more information about test parameters, see “Use Parameters in Class-Based Tests” on page 36-
76.
36-51
36 Unit Testing
See Also
Classes
matlab.unittest.TestCase
Related Examples
• “Class-Based Unit Tests” on page 36-44
36-52
Write Simple Test Case Using Classes
You can test your MATLAB® program by defining unit tests within a test class that inherits from the
matlab.unittest.TestCase class. A unit test in a class-based test is a method that determines the
correctness of a unit of software. It is defined within a methods block with the Test attribute and
can use qualifications for testing values and responding to failures. For more information about class-
based tests, see “Class-Based Unit Tests” on page 36-44.
This example shows how to write class-based unit tests to qualify the correctness of a function
defined in a file in your current folder. The quadraticSolver function takes as inputs the
coefficients of a quadratic polynomial and returns the roots of that polynomial. If the coefficients are
specified as nonnumeric values, the function throws an error.
function r = quadraticSolver(a,b,c)
% quadraticSolver returns solutions to the
% quadratic equation a*x^2 + b*x + c = 0.
end
In a file named SolverTest.m in your current folder, create the SolverTest class by subclassing
the matlab.unittest.TestCase class. This class provides a place for tests for the
quadraticSolver function. Add three unit tests inside a methods block with the Test attribute.
These test the quadraticSolver function against real solutions, imaginary solutions, and error
conditions. Each Test method must accept a TestCase instance as an input. The order of the tests
within the block does not matter.
First, create a Test method realSolution to verify that quadraticSolver returns the correct
real solutions for specific coefficients. For example, the equation x2 − 3x + 2 = 0 has real solutions
x = 1 and x = 2. The method calls quadraticSolver with the coefficients of this equation. Then, it
uses the verifyEqual method of matlab.unittest.TestCase to compare the actual output
actSolution to the expected output expSolution.
Create a second Test method imaginarySolution to verify that quadraticSolver returns the
correct imaginary solutions for specific coefficients. For example, the equation x2 + 2x + 10 = 0 has
36-53
36 Unit Testing
imaginary solutions x = − 1 + 3i and x = − 1 − 3i. Just like the previous method, this method calls
quadraticSolver with the coefficients of this equation, and then uses the verifyEqual method to
compare the actual output actSolution to the expected output expSolution.
Finally, add a Test method nonnumericInput to verify that quadraticSolver produces an error
for nonnumeric coefficients. Use the verifyError method of matlab.unittest.TestCase to test
that the function throws the error specified by 'quadraticSolver:InputMustBeNumeric' when
it is called with inputs 1, '-3', and 2.
To run all of the tests in the SolverTest class, create a TestCase object from the class and then
call the run method on the object. In this example, all three tests pass.
testCase = SolverTest;
results = testCase.run
Running SolverTest
...
Done SolverTest
__________
results =
1×3 TestResult array with properties:
36-54
Write Simple Test Case Using Classes
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
3 Passed, 0 Failed, 0 Incomplete.
0.018753 seconds testing time.
You also can run a single test specified by one of the Test methods. To run a specific Test method,
pass the name of the method to run. For example, run the realSolution method.
result = run(testCase,'realSolution')
Running SolverTest
.
Done SolverTest
__________
result =
TestResult with properties:
Name: 'SolverTest/realSolution'
Passed: 1
Failed: 0
Incomplete: 0
Duration: 0.0026
Details: [1×1 struct]
Totals:
1 Passed, 0 Failed, 0 Incomplete.
0.0026009 seconds testing time.
See Also
matlab.unittest.TestCase
Related Examples
• “Class-Based Unit Tests” on page 36-44
• “Table of Verifications, Assertions, and Other Qualifications” on page 36-59
• “Analyze Test Case Results” on page 36-143
• “Create Simple Test Suites” on page 36-106
36-55
36 Unit Testing
This example shows how to implement setup and teardown code at the method level and the class
level for class-based testing.
Test Fixtures
Test fixtures are setup and teardown code that sets up the pretest state of the system and returns it
to the original state after running the test. Setup and teardown methods are defined in the TestCase
class by these method attributes:
• TestMethodSetup and TestMethodTeardown methods run before and after each Test method.
• TestClassSetup and TestClassTeardown methods run before and after all Test methods in
the test class.
It is recommended that you perform all teardown actions from within the TestMethodSetup and
TestClassSetup methods blocks using the addTeardown method instead of implementing
corresponding teardown methods in the TestMethodTeardown and TestClassTeardown methods
blocks. Call addTeardown immediately before or after the original state change, without any other
code in between that can throw an exception. Using addTeardown allows the testing framework to
execute the teardown code in the reverse order of the setup code and also creates exception-safe test
content.
methods (TestMethodSetup)
function createFigure(testCase)
testCase.TestFigure = figure;
end
end
methods (TestMethodTeardown)
36-56
Write Setup and Teardown Code Using Classes
function closeFigure(testCase)
close(testCase.TestFigure)
end
end
methods (Test)
function defaultCurrentPoint(testCase)
cp = testCase.TestFigure.CurrentPoint;
testCase.verifyEqual(cp,[0 0], ...
"Default current point must be [0 0].")
end
function defaultCurrentObject(testCase)
import matlab.unittest.constraints.IsEmpty
co = testCase.TestFigure.CurrentObject;
testCase.verifyThat(co,IsEmpty, ...
"Default current object must be empty.")
end
end
end
methods (Test)
function truncationTest(testCase)
actual = strtrim(formattedDisplayText(pi));
expected = "3.14";
testCase.verifyEqual(actual,expected)
end
function divisionTest(testCase)
actual = strtrim(formattedDisplayText(100/3));
expected = "33.33";
testCase.verifyEqual(actual,expected)
end
function negativeValueTest(testCase)
actual = strtrim(formattedDisplayText(-1));
expected = "-1.00";
testCase.verifyEqual(actual,expected)
36-57
36 Unit Testing
end
end
end
See Also
matlab.unittest.TestCase | addTeardown
Related Examples
• “Class-Based Unit Tests” on page 36-44
• “Write Simple Test Case Using Classes” on page 36-53
36-58
Table of Verifications, Assertions, and Other Qualifications
• Verifications — Produce and record failures without returning an exception. When a verification
failure occurs, the remaining tests run to completion.
• Assumptions — Ensure that the test environment meets preconditions that otherwise do not result
in a test failure. When an assumption failure occurs, the testing framework marks the test as
filtered.
• Assertions — Ensure that the preconditions of the current test are met. When an assertion failure
occurs, the framework marks the current test as failed and incomplete. However, the failure does
not prevent the execution of subsequent tests.
• Fatal assertions — Ensure that the remainder of the current test session is valid and the state is
recoverable. When a fatal assertion failure occurs, the testing framework aborts the test session.
These qualification types have parallel methods for the same types of tests. The methods use a
common naming convention. For instance, the methods that test for a true value use the form
<qualify>True, where <qualify> can be verify, assume, assert, or fatalAssert. That is:
General Purpose
36-59
36 Unit Testing
Inequalities
Array Size
Type
Strings
36-60
Table of Verifications, Assertions, and Other Qualifications
See Also
matlab.unittest.qualifications.Verifiable |
matlab.unittest.qualifications.Assumable |
matlab.unittest.qualifications.Assertable |
matlab.unittest.qualifications.FatalAssertable | matlab.unittest.qualifications
36-61
36 Unit Testing
Tag Tests
To define test tags, use a cell array of meaningful character vectors or a string array. For example,
TestTags = {'Unit'} or TestTags = ["Unit","FeatureA"].
This sample test class, ExampleTagTest, uses the TestTags method attribute to tag individual
tests.
Several of the tests in class ExampleTagTest are tagged. For example, testD is tagged with
'Unit' and 'FeatureA'. One test, testA, is not tagged.
This sample test class, ExampleTagClassTest, uses a TestTags class attribute to tag all the tests
within the class, and a TestTags method attribute to add tags to individual tests.
36-62
Tag Unit Tests
end
methods (Test, TestTags = {'FeatureC','System'})
function testG (testCase)
% test code
end
end
methods (Test, TestTags = {'System','FeatureA'})
function testH (testCase)
% test code
end
end
end
Each test in class ExampleTagClassTest is tagged with 'FeatureB'. Additionally, individual tests
are tagged with various tags including 'FeatureA', 'FeatureC', and 'System'.
Use the runtests function to select and run tests without explicitly creating a test suite. Select and
run all the tests from ExampleTagTest and ExampleTagClassTest that include the 'FeatureA'
tag.
results = runtests({'ExampleTagTest','ExampleTagClassTest'},'Tag','FeatureA');
Running ExampleTagTest
..
Done ExampleTagTest
__________
Running ExampleTagClassTest
.
Done ExampleTagClassTest
__________
table(results)
ans =
3×6 table
36-63
36 Unit Testing
The selected tests are testE and testD from ExampleTagTest, and testH from
ExampleTagClassTest.
Create a suite of tests from the ExampleTagTest class that are tagged with 'FeatureA'.
import matlab.unittest.TestSuite
sA = TestSuite.fromClass(?ExampleTagTest,'Tag','FeatureA');
Create a suite of tests from the ExampleTagClassTest class that are tagged with 'FeatureC'.
sB = TestSuite.fromFile('ExampleTagClassTest.m','Tag','FeatureC');
ans =
'ExampleTagTest/testE'
'ExampleTagTest/testD'
'ExampleTagClassTest/testG'
Create a suite of all the tests from the ExampleTagTest and ExampleTagClassTest classes.
import matlab.unittest.selectors.HasTag
sA = TestSuite.fromClass(?ExampleTagTest);
sB = TestSuite.fromFile('ExampleTagClassTest.m');
suite = [sA sB];
s1 =
Name: 'ExampleTagTest/testA'
ProcedureName: 'testA'
TestClass: "ExampleTagTest"
BaseFolder: 'C:\work'
Parameterization: [0×0 matlab.unittest.parameters.EmptyParameter]
SharedTestFixtures: [0×0 matlab.unittest.fixtures.EmptyFixture]
Tags: {1×0 cell}
Tests Include:
0 Parameterizations, 0 Shared Test Fixture Classes, 0 Tags.
Select all the tests with the 'Unit' tag and display their names.
36-64
Tag Unit Tests
s2 = suite.selectIf(HasTag('Unit'));
{s2.Name}'
ans =
'ExampleTagTest/testD'
'ExampleTagTest/testB'
'ExampleTagTest/testC'
Select all the tests with the 'FeatureB' or 'System' tag using a constraint.
import matlab.unittest.constraints.IsEqualTo
constraint = IsEqualTo('FeatureB') | IsEqualTo('System');
s3 = suite.selectIf(HasTag(constraint));
{s3.Name}'
ans =
'ExampleTagTest/testE'
'ExampleTagClassTest/testH'
'ExampleTagClassTest/testG'
'ExampleTagClassTest/testF'
See Also
matlab.unittest.constraints | matlab.unittest.selectors.HasTag |
matlab.unittest.TestSuite | runtests | matlab.unittest.TestCase
36-65
36 Unit Testing
You can share test fixtures across test classes using the SharedTestFixtures attribute of the
matlab.unittest.TestCase class. When you share a fixture across test classes that run together,
the testing framework sets up the fixture once for all the test classes and tears it down after all the
test classes run. If you specify the fixture using the TestClassSetup methods block of each class
instead, the testing framework sets up the fixture before and tears it down after running each test
class.
This example shows how to use shared fixtures when creating tests. It shows how to share a fixture
for adding a folder containing source code to the path across two test classes. The test classes use
this fixture to access the source code required by the tests.
Open the example to make the source and test code available in your current folder.
openExample("matlab/WriteTestsUsingSharedTestFixturesExample")
This code shows the contents of the DocPolynomTest class definition file, which uses a shared
fixture to access the folder defining the DocPolynom class. For more information about the
DocPolynom class and to view the class code, see “Representing Polynomials with Classes”.
properties
TextToDisplay = "Equation under test: "
end
methods (Test)
function testConstructor(testCase)
p = DocPolynom([1 0 1]);
testCase.verifyClass(p,?DocPolynom)
end
function testAddition(testCase)
p1 = DocPolynom([1 0 1]);
p2 = DocPolynom([5 2]);
actual = p1 + p2;
expected = DocPolynom([1 5 3]);
diagnostic = [testCase.TextToDisplay ...
"(x^2 + 1) + (5*x + 2) = x^2 + 5*x + 3"];
testCase.verifyEqual(actual,expected,diagnostic)
end
function testMultiplication(testCase)
p1 = DocPolynom([1 0 3]);
p2 = DocPolynom([5 2]);
actual = p1 * p2;
expected = DocPolynom([5 2 15 6]);
diagnostic = [testCase.TextToDisplay ...
36-66
Write Tests Using Shared Fixtures
This code shows the contents of the BankAccountTest class definition file, which uses a shared
fixture to access the folder defining the BankAccount class. For more information about the
BankAccount class and to view the class code, see “Developing Classes That Work Together”.
methods (Test)
function testConstructor(testCase)
b = BankAccount(1234,100);
testCase.verifyEqual(b.AccountNumber,1234, ...
"Constructor must correctly set account number.")
testCase.verifyEqual(b.AccountBalance,100, ...
"Constructor must correctly set account balance.")
end
function testConstructorNotEnoughInputs(testCase)
import matlab.unittest.constraints.Throws
testCase.verifyThat(@()BankAccount,Throws("MATLAB:minrhs"))
end
function testDeposit(testCase)
b = BankAccount(1234,100);
b.deposit(25)
testCase.verifyEqual(b.AccountBalance,125)
end
function testWithdraw(testCase)
b = BankAccount(1234,100);
b.withdraw(25)
testCase.verifyEqual(b.AccountBalance,75)
end
function testNotifyInsufficientFunds(testCase)
callbackExecuted = false;
function testCallback(~,~)
callbackExecuted = true;
end
b = BankAccount(1234, 100);
b.addlistener("InsufficientFunds",@testCallback);
b.withdraw(50)
testCase.assertFalse(callbackExecuted, ...
"The callback should not have executed yet.")
b.withdraw(60)
36-67
36 Unit Testing
testCase.verifyTrue(callbackExecuted, ...
"The listener callback should have fired.")
end
end
end
Run the tests in your current folder and its subfolders. The testing framework sets up the shared test
fixture, runs the tests in the BankAccountTest and DocPolynomTest classes, and tears down the
fixture after running the tests. In this example, all of the tests pass.
runtests("IncludeSubfolders",true);
Setting up PathFixture
Done setting up PathFixture: Added 'C:\work\WriteTestsUsingSharedTestFixturesExample\fixture_exam
__________
Running BankAccountTest
.....
Done BankAccountTest
__________
Running DocPolynomTest
...
Done DocPolynomTest
__________
See Also
matlab.unittest.TestCase | matlab.unittest.fixtures.Fixture |
matlab.unittest.fixtures.PathFixture
Related Examples
• “Create Basic Custom Fixture” on page 36-69
• “Create Advanced Custom Fixture” on page 36-71
36-68
Create Basic Custom Fixture
In a file in your working folder, create a new class, FormatHexFixture that inherits from the
matlab.unittest.fixtures.Fixture class. Since we want the fixture to restore the pretest state
of the MATLAB display format, create an OriginalFormat property to keep track of the original
display format.
classdef FormatHexFixture < matlab.unittest.fixtures.Fixture
properties (Access = private)
OriginalFormat
end
end
Subclasses of the Fixture class must implement the setup method. Use this method to record the
pretest display format, and set the format to 'hex'. Use the teardown method to restore the
original display format. Define the setup and teardown methods in the methods block of the
FormatHexFixture class.
classdef FormatHexFixture < matlab.unittest.fixtures.Fixture
properties (Access = private)
OriginalFormat
end
methods
function setup(fixture)
fixture.OriginalFormat = format;
format hex
end
function teardown(fixture)
format(fixture.OriginalFormat)
end
end
end
In a file in your working folder, create the following test class, SampleTest.m.
classdef SampleTest < matlab.unittest.TestCase
methods (Test)
function test1(testCase)
testCase.applyFixture(FormatHexFixture)
actStr = getColumnForDisplay([1;2;3],'Small Integers');
expStr = ['Small Integers '
'3ff0000000000000'
'4000000000000000'
'4008000000000000'];
testCase.verifyEqual(actStr,expStr)
end
36-69
36 Unit Testing
end
end
This test applies the custom fixture and verifies that the displayed column of hexadecimal
representation is as expected.
run(SampleTest);
Running SampleTest
.
Done SampleTest
__________
See Also
matlab.unittest.fixtures.Fixture
Related Examples
• “Create Advanced Custom Fixture” on page 36-71
• “Write Tests Using Shared Fixtures” on page 36-66
36-70
Create Advanced Custom Fixture
In a methods block in your class, define a constructor that sets the Format property.
methods
function fixture = NumericFormatFixture(fmt)
fixture.Format = fmt;
end
end
Subclasses of the Fixture interface must implement the setup method, which makes changes to the
environment when the testing framework sets up the fixture. To restore the environment when the
framework tears down the fixture, you can call the addTeardown method within the setup method.
In a methods block, implement the setup method to change the numeric format to the format
specified during fixture construction and to restore the format to its original state after testing. To
provide descriptive information when the framework sets up and tear downs the fixture, set the
SetupDescription and TeardownDescription properties within the method.
methods
function setup(fixture)
originalFormat = format;
fixture.addTeardown(@format,originalFormat)
format(fixture.Format)
fixture.SetupDescription = "Set the numeric format to " + ...
fixture.Format + ".";
fixture.TeardownDescription = ...
"Restored the numeric format to " + ...
originalFormat.NumericFormat + ".";
end
end
Implement the isCompatible method in your Fixture subclass if the fixture is configurable (for
instance, if its class constructor accepts input arguments). In this example, because you set the
Format property using the class constructor, you must implement isCompatible.
The testing framework calls isCompatible to determine whether instances of the same Fixture
subclass correspond to the same shared test fixture state. The information about fixture compatibility
helps the framework decide when to perform teardown and setup actions. Two
NumericFormatFixture instances make the same change to the environment when their Format
36-71
36 Unit Testing
properties are equal. Specify this compatibility definition by implementing the isCompatible
method in a methods block with protected access.
methods (Access=protected)
function tf = isCompatible(fixture1,fixture2)
tf = fixture1.Format == fixture2.Format;
end
end
methods
function fixture = NumericFormatFixture(fmt)
fixture.Format = fmt;
end
function setup(fixture)
originalFormat = format;
fixture.addTeardown(@format,originalFormat)
format(fixture.Format)
fixture.SetupDescription = "Set the numeric format to " + ...
fixture.Format + ".";
fixture.TeardownDescription = ...
"Restored the numeric format to " + ...
originalFormat.NumericFormat + ".";
end
end
methods (Access=protected)
function tf = isCompatible(fixture1,fixture2)
tf = fixture1.Format == fixture2.Format;
end
end
end
In a file named ExampleTest.m in your current folder, create the ExampleTest class that applies
the custom fixture and verifies that a numeric value is displayed in the expected format. To simplify
this example, the actual value is produced by a call to the formattedDisplayText function. In
practice, you test user-defined code.
classdef ExampleTest < matlab.unittest.TestCase
methods (Test)
function formatTest(testCase)
testCase.applyFixture(NumericFormatFixture("bank"))
actual = strtrim(formattedDisplayText(pi));
expected = "3.14";
testCase.verifyEqual(actual,expected)
end
end
end
Run the ExampleTest class. The testing framework sets up the fixture, which changes the display
format to the currency format. Once the test run is complete, the framework tears down the fixture,
which restores the original display format. In this example, the test passes.
runtests("ExampleTest");
36-72
Create Advanced Custom Fixture
Running ExampleTest
.
Done ExampleTest
__________
In your current folder, create three test classes that each use an instance of
NumericFormatFixture as a shared test fixture.
The TestA and TestB classes are assigned shared fixtures that make the same change to the
environment. On the other hand, the TestC class is assigned a fixture that enforces a different
numeric format. According to the implementation of the isCompatible method in this example, the
testing framework finds the fixtures on TestA and TestB compatible. However, it finds the fixture on
TestC incompatible with the other fixtures.
The information about fixture compatibility helps the framework decide when to perform teardown
and setup actions. If you run TestA, TestB, and TestC as part of the same test suite, the framework
does not tear down the fixture when switching from TestA to TestB because both classes require the
36-73
36 Unit Testing
same environment. However, when switching from TestB to TestC, the framework tears down the
existing fixture and sets up a fresh fixture required by TestC. In this example, all the tests pass.
runtests(["TestA" "TestB" "TestC"]);
Setting up NumericFormatFixture
Done setting up NumericFormatFixture: Set the numeric format to bank.
__________
Running TestA
.
Done TestA
__________
Running TestB
.
Done TestB
__________
Setting up NumericFormatFixture
Done setting up NumericFormatFixture: Set the numeric format to hex.
__________
Running TestC
.
Done TestC
__________
An alternative approach to calling the addTeardown method within the setup method is to
implement a separate teardown method. This code shows how to recreate the
NumericFormatFixture class by implementing both the setup and teardown methods. Note that
the alternative class definition contains an additional property, OriginalFormat, to pass information
about the original format to the teardown method.
classdef NumericFormatFixture < matlab.unittest.fixtures.Fixture
properties (SetAccess=immutable)
Format (1,1) string
end
properties (Access=private)
OriginalFormat
end
methods
function fixture = NumericFormatFixture(fmt)
fixture.Format = fmt;
end
function setup(fixture)
fixture.OriginalFormat = format().NumericFormat;
format(fixture.Format)
fixture.SetupDescription = "Set the numeric format to " + ...
36-74
Create Advanced Custom Fixture
fixture.Format + ".";
end
function teardown(fixture)
format(fixture.OriginalFormat)
fixture.TeardownDescription = ...
"Restored the numeric format to " + ...
fixture.OriginalFormat + ".";
end
end
methods (Access=protected)
function tf = isCompatible(fixture1,fixture2)
tf = fixture1.Format == fixture2.Format;
end
end
end
See Also
matlab.unittest.fixtures.Fixture | matlab.unittest.TestCase | format
Related Examples
• “Create Basic Custom Fixture” on page 36-69
• “Write Tests Using Shared Fixtures” on page 36-66
36-75
36 Unit Testing
The testing framework enables you to parameterize your test class at different levels. Additionally,
when you call a test class method with multiple parameters, you can specify how the method should
be invoked for different combinations of the parameters.
For example, consider the SampleTest class. The class defines a parameterized test because it
specifies properties within a properties block with the TestParameter attribute. The properties
are passed to Test methods and are used to perform qualifications.
The test class results in a parameterized test suite with five elements.
suite = testsuite("SampleTest");
{suite.Name}'
ans =
{'SampleTest/test1(numericArray=int16_1)' }
{'SampleTest/test1(numericArray=1x4_single)' }
{'SampleTest/test1(numericArray=3x3_double)' }
{'SampleTest/test2(functionHandle=@false)' }
{'SampleTest/test2(functionHandle=function_handle)'}
36-76
Use Parameters in Class-Based Tests
Specify the value of a parameterization property as a nonempty cell array or scalar structure with at
least one field. The testing framework uses the property value to specify parameter names and values
in the test suite:
• If the property value is a cell array, the framework generates descriptive parameter names from
the elements of the cell array by taking into account their values, types, and dimensions.
• If the property value is a structure, the structure fields represent the parameter names and the
structure values represent the parameter values. To have full control over parameter names in the
suite, define the parameters using a structure instead of a cell array.
Note If you have a MATLAB Test™ license, you can set a parameterization property to a
matlabtest.parameters.BaselineParameter object for baseline testing. For more information,
see “Create Baseline Tests for MATLAB Code” (MATLAB Test).
• Class load time: If the property value can be determined at the time MATLAB loads the test class
definition, initialize the property using a default value. You can specify the default value in the
properties block or using a local function in the classdef file. For more information about
assigning values in a class definition, see “Evaluation of Expressions in Class Definitions”.
When you initialize a parameterization property at class load time, the parameters associated with
the property remain fixed for different test runs. Each time you create a suite from the
parameterized test class, the framework uses the same parameter names and values to run the
tests. See “Create Basic Parameterized Test” on page 36-83 for an example that uses
parameterization properties with default values.
• Suite creation time: If you cannot or do not want to determine the parameters at class load
time, initialize the property at suite creation time using a static method with the
TestParameterDefinition attribute. When you initialize a parameterization property with a
TestParameterDefinition method, the parameters associated with the property can vary for
different test runs. Each time you create a suite from the parameterized test class, the framework
generates fresh parameter names and values to run the tests. For more information, see “Define
Parameters at Suite Creation Time” on page 36-99.
Note Once you assign a value to a parameterization property, do not modify it. For example, when
you initialize a parameterization property using a default value, you cannot use a
TestParameterDefinition method to overwrite the default value.
A parameter might be used by several unit tests. Tests using the same parameter must run
independently, without accidentally affecting one another. In addition, a running test must not affect
subsequent reruns of the same test. To ensure test run independence, initialize your parameterization
properties with value objects. Using handle objects (such as MATLAB graphics objects) as parameter
values is not recommended. For more information about the behavior of value and handle objects, see
“Comparison of Handle and Value Classes”.
36-77
36 Unit Testing
If you need to test handle objects in your parameterized test, consider constructing them indirectly
by using function handles as parameter values and invoking those function handles in tests. For
example, write a parameterized test to test the default current point of figures created with the
figure and uifigure functions.
classdef FigureTest < matlab.unittest.TestCase
properties (TestParameter)
figureType = {@figure,@uifigure};
end
methods (Test)
function defaultCurrentPoint(testCase,figureType)
fig = figureType();
testCase.addTeardown(@close,fig)
cp = fig.CurrentPoint;
testCase.verifyEqual(cp,[0 0])
end
end
end
This table shows different parameterization levels and the required method and property attributes
for each level.
A parameterized method can access parameterization properties depending on the level at which the
method is defined:
• A parameterized TestClassSetup method can access parameterization properties only with the
ClassSetupParameter attribute.
• A parameterized TestMethodSetup method can access parameterization properties only with the
MethodSetupParameter or ClassSetupParameter attributes.
36-78
Use Parameters in Class-Based Tests
For an example of how to parameterize a test class at different levels, see “Create Advanced
Parameterized Test” on page 36-88.
36-79
36 Unit Testing
For example, this test uses the pairwise combination to test the size of
different matrices.
Create a test suite from the class. One possible outcome contains the
ten elements listed below.
suite = testsuite("ZerosTest");
{suite.Name}'
ans =
{'ZerosTest/testSize(rowCount=r1,columnCount=c1,type=single)'}
{'ZerosTest/testSize(rowCount=r1,columnCount=c2,type=double)'}
{'ZerosTest/testSize(rowCount=r1,columnCount=c3,type=uint16)'}
{'ZerosTest/testSize(rowCount=r2,columnCount=c1,type=double)'}
{'ZerosTest/testSize(rowCount=r2,columnCount=c2,type=single)'}
{'ZerosTest/testSize(rowCount=r2,columnCount=c3,type=single)'}
{'ZerosTest/testSize(rowCount=r3,columnCount=c1,type=uint16)'}
{'ZerosTest/testSize(rowCount=r3,columnCount=c2,type=single)'}
{'ZerosTest/testSize(rowCount=r3,columnCount=c3,type=double)'}
{'ZerosTest/testSize(rowCount=r2,columnCount=c2,type=uint16)'}
— columnCount Property
c1 c2 c3
rowCount r1 1 2 3
Property
36-80
Use Parameters in Class-Based Tests
While the framework guarantees that tests are created for every pair
of values at least once, you should not rely on the suite size, ordering,
or specific set of test suite elements.
"n-wise" Methods are invoked for every n-tuple of parameter values at least
once (requires MATLAB Test). You can specify n as an integer between
2 and 10. For example, specify the attribute as "4-wise" to invoke a
method for every quadruple of parameter values at least once.
You can combine parameters at the class-setup, method-setup, and test levels. For example, use the
two method attributes TestMethodSetup,ParameterCombination="sequential" to specify
sequential combination of the method-setup-level parameters defined in the properties block with
the MethodSetupParameter attribute.
For examples of how to combine test parameters, see “Create Basic Parameterized Test” on page 36-
83 and “Create Advanced Parameterized Test” on page 36-88.
See Also
Classes
matlab.unittest.parameters.Parameter | matlab.unittest.TestCase
Namespaces
matlab.unittest.parameters
More About
• “Create Basic Parameterized Test” on page 36-83
• “Create Advanced Parameterized Test” on page 36-88
• “Define Parameters at Suite Creation Time” on page 36-99
36-81
36 Unit Testing
36-82
Create Basic Parameterized Test
In your current folder, create a function in the file sierpinski.m. This function returns a matrix
representing an image of a Sierpinski carpet fractal. It takes as input the fractal level and an optional
data type.
msize = 3^levels;
carpet = ones(msize,classname);
function cutCarpet(x,y,s,cl)
if cl
ss = s/3; % Define subsize
for lx = 0:2
for ly = 0:2
if lx == 1 && ly == 1
% Remove center square
carpet(x+ss:x+2*ss-1,y+ss:y+2*ss-1) = 0;
else
% Recurse
cutCarpet(x+lx*ss,y+ly*ss,ss,cl-1)
end
end
end
end
end
end
In a file in your current folder, create the TestCarpet class to test the sierpinski function. Define
the properties used for parameterized testing in a properties block with the TestParameter
attribute.
The type property contains the different data types you want to test. The level property contains
the different fractal levels you want to test. The side property contains the number of rows and
columns in the Sierpinski carpet matrix and corresponds to the level property.
36-83
36 Unit Testing
In a methods block with the Test attribute, define three test methods:
• The testRemainPixels method tests the output of the sierpinski function by verifying that
the number of nonzero pixels is the same as expected for a particular level. This method uses the
level property and, therefore, results in three test elements—one for each value in level.
• The testClass method tests the class of the output from the sierpinski function with each
combination of the type and level parameter values (that is, exhaustive parameter
combination). The method results in nine test elements.
• The testDefaultL1Output method does not use a TestParameter property and, therefore, is
not parameterized. The method verifies that the level 1 matrix contains the expected values.
Because the test method is not parameterized, it results in one test element.
methods (Test)
function testRemainPixels(testCase,level)
expPixelCount = 8^level;
actPixels = find(sierpinski(level));
testCase.verifyNumElements(actPixels,expPixelCount)
end
function testClass(testCase,type,level)
testCase.verifyClass( ...
sierpinski(level,type),type)
end
function testDefaultL1Output(testCase)
exp = single([1 1 1; 1 0 1; 1 1 1]);
testCase.verifyEqual(sierpinski(1),exp)
end
end
end
Define the testNumel method to ensure that the matrix returned by the sierpinski function has
the correct number of elements. Set the ParameterCombination attribute for the method to
'sequential'. Because the level and side properties each specify three parameter values, the
testNumel method is invoked three times — one time for each of the 'small', 'medium', and
'large' values.
methods (Test)
36-84
Create Basic Parameterized Test
function testRemainPixels(testCase,level)
expPixelCount = 8^level;
actPixels = find(sierpinski(level));
testCase.verifyNumElements(actPixels,expPixelCount)
end
function testClass(testCase,type,level)
testCase.verifyClass( ...
sierpinski(level,type),type)
end
function testDefaultL1Output(testCase)
exp = single([1 1 1; 1 0 1; 1 1 1]);
testCase.verifyEqual(sierpinski(1),exp)
end
end
At the command prompt, create a suite from TestCarpet.m. The suite has 16 test elements.
MATLAB includes parameterization information in the names of the suite elements.
suite = matlab.unittest.TestSuite.fromFile('TestCarpet.m');
{suite.Name}'
ans =
{'TestCarpet/testNumel(level=small,side=small)' }
{'TestCarpet/testNumel(level=medium,side=medium)'}
{'TestCarpet/testNumel(level=large,side=large)' }
{'TestCarpet/testRemainPixels(level=small)' }
{'TestCarpet/testRemainPixels(level=medium)' }
{'TestCarpet/testRemainPixels(level=large)' }
{'TestCarpet/testClass(type=single,level=small)' }
{'TestCarpet/testClass(type=single,level=medium)'}
{'TestCarpet/testClass(type=single,level=large)' }
{'TestCarpet/testClass(type=double,level=small)' }
{'TestCarpet/testClass(type=double,level=medium)'}
{'TestCarpet/testClass(type=double,level=large)' }
{'TestCarpet/testClass(type=uint16,level=small)' }
{'TestCarpet/testClass(type=uint16,level=medium)'}
{'TestCarpet/testClass(type=uint16,level=large)' }
{'TestCarpet/testDefaultL1Output' }
suite.run
36-85
36 Unit Testing
Running TestCarpet
.......... ......
Done TestCarpet
__________
ans =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
16 Passed, 0 Failed, 0 Incomplete.
2.459 seconds testing time.
Use the selectIf method of TestSuite to select test elements that use a particular
parameterization. Select all test elements that use the parameter name 'small' in the level
parameterization property list. The filtered suite has five elements.
s1 = suite.selectIf('ParameterName','small');
{s1.Name}'
ans =
{'TestCarpet/testNumel(level=small,side=small)' }
{'TestCarpet/testRemainPixels(level=small)' }
{'TestCarpet/testClass(type=single,level=small)'}
{'TestCarpet/testClass(type=double,level=small)'}
{'TestCarpet/testClass(type=uint16,level=small)'}
Running TestCarpet
.....
Done TestCarpet
__________
Alternatively, you can create the same test suite directly using the fromFile method of TestSuite.
import matlab.unittest.selectors.HasParameter
s1 = matlab.unittest.TestSuite.fromFile('TestCarpet.m', ...
HasParameter('Name','small'));
See Also
matlab.unittest.TestCase | matlab.unittest.selectors.HasParameter |
matlab.unittest.TestSuite
36-86
Create Basic Parameterized Test
Related Examples
• “Use Parameters in Class-Based Tests” on page 36-76
• “Create Advanced Parameterized Test” on page 36-88
• “Define Parameters at Suite Creation Time” on page 36-99
• “Use External Parameters in Parameterized Test” on page 36-95
36-87
36 Unit Testing
In a file in your current folder, create the TestRand class to test various aspects of random number
generation. Define the properties used for parameterized testing.
classdef TestRand < matlab.unittest.TestCase
properties (ClassSetupParameter)
generator = {'twister','combRecursive','multFibonacci'};
end
properties (MethodSetupParameter)
seed = {0,123,4294967295};
end
properties (TestParameter)
dim1 = struct('small',1,'medium',2,'large',3);
dim2 = struct('small',2,'medium',3,'large',4);
dim3 = struct('small',3,'medium',4,'large',5);
type = {'single','double'};
end
end
Define the setup methods at the test class and test method levels. These methods register the initial
random number generator state. After the framework runs the tests, the methods restore the original
state. The classSetup method defines the type of random number generator, and the methodSetup
method seeds the generator.
classdef TestRand < matlab.unittest.TestCase
properties (ClassSetupParameter)
generator = {'twister','combRecursive','multFibonacci'};
end
properties (MethodSetupParameter)
seed = {0,123,4294967295};
end
properties (TestParameter)
dim1 = struct('small',1,'medium',2,'large',3);
dim2 = struct('small',2,'medium',3,'large',4);
dim3 = struct('small',3,'medium',4,'large',5);
type = {'single','double'};
end
methods (TestClassSetup)
36-88
Create Advanced Parameterized Test
function classSetup(testCase,generator)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(0,generator)
end
end
methods (TestMethodSetup)
function methodSetup(testCase,seed)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(seed)
end
end
end
Define the testSize method in a methods block with the Test and ParameterCombination =
'sequential' attributes.
properties (MethodSetupParameter)
seed = {0,123,4294967295};
end
properties (TestParameter)
dim1 = struct('small',1,'medium',2,'large',3);
dim2 = struct('small',2,'medium',3,'large',4);
dim3 = struct('small',3,'medium',4,'large',5);
type = {'single','double'};
end
methods (TestClassSetup)
function classSetup(testCase,generator)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(0,generator)
end
end
methods (TestMethodSetup)
function methodSetup(testCase,seed)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(seed)
end
end
36-89
36 Unit Testing
end
end
The method tests the size of the output for each corresponding parameter value in dim1, dim2, and
dim3. For a given TestClassSetup and TestMethodSetup parameterization, the framework calls
the testSize method three times — one time for each of the 'small', 'medium', and 'large'
values. For example, to test with all of the 'medium' values, the framework uses
testCase.verifySize(rand(2,3,4),[2 3 4]).
Define the testRepeatable method in a methods block with the Test and
ParameterCombination = 'pairwise' attributes.
classdef TestRand < matlab.unittest.TestCase
properties (ClassSetupParameter)
generator = {'twister','combRecursive','multFibonacci'};
end
properties (MethodSetupParameter)
seed = {0,123,4294967295};
end
properties (TestParameter)
dim1 = struct('small',1,'medium',2,'large',3);
dim2 = struct('small',2,'medium',3,'large',4);
dim3 = struct('small',3,'medium',4,'large',5);
type = {'single','double'};
end
methods (TestClassSetup)
function classSetup(testCase,generator)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(0,generator)
end
end
methods (TestMethodSetup)
function methodSetup(testCase,seed)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(seed)
end
end
36-90
Create Advanced Parameterized Test
testCase.verifyEqual(firstRun,secondRun)
end
end
end
The method verifies that the random number generator results are repeatable. For a given
TestClassSetup and TestMethodSetup parameterization, the framework calls the
testRepeatable method 10 times to ensure testing with each pair of parameter values specified by
dim1, dim2, and dim3. If the parameter combination were exhaustive, the framework would call the
method 3³ = 27 times.
Define the testClass method in a methods block with the Test attribute. Because the
ParameterCombination attribute is not specified, the parameter combination is exhaustive by
default.
properties (MethodSetupParameter)
seed = {0,123,4294967295};
end
properties (TestParameter)
dim1 = struct('small',1,'medium',2,'large',3);
dim2 = struct('small',2,'medium',3,'large',4);
dim3 = struct('small',3,'medium',4,'large',5);
type = {'single','double'};
end
methods (TestClassSetup)
function classSetup(testCase,generator)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(0,generator)
end
end
methods (TestMethodSetup)
function methodSetup(testCase,seed)
orig = rng;
testCase.addTeardown(@rng,orig)
rng(seed)
end
end
36-91
36 Unit Testing
state = rng;
firstRun = rand(dim1,dim2,dim3);
rng(state)
secondRun = rand(dim1,dim2,dim3);
testCase.verifyEqual(firstRun,secondRun)
end
end
methods (Test)
function testClass(testCase,dim1,dim2,type)
testCase.verifyClass(rand(dim1,dim2,type),type)
end
end
end
The method verifies that the class of the output from rand is the same as the expected class. For a
given TestClassSetup and TestMethodSetup parameterization, the framework calls the
testClass method 3×3×2 = 18 times to ensure testing with each combination of dim1, dim2, and
type parameter values.
suite = matlab.unittest.TestSuite.fromClass(?TestRand)
suite =
Name
ProcedureName
TestClass
BaseFolder
Parameterization
SharedTestFixtures
Tags
Tests Include:
17 Unique Parameterizations, 0 Shared Test Fixture Classes, 0 Tags.
suite(1).Name
ans =
'TestRand[generator=twister]/[seed=0]testClass(dim1=small,dim2=small,type=single)'
36-92
Create Advanced Parameterized Test
At the command prompt, create a selector to select test elements that test the 'twister' generator
for 'single' precision. Create a suite by omitting test elements that use properties with the
'large' parameter name.
import matlab.unittest.selectors.HasParameter
s = HasParameter('Property','generator','Name','twister') & ...
HasParameter('Property','type','Name','single') & ...
~HasParameter('Name','large');
suite2 = matlab.unittest.TestSuite.fromClass(?TestRand,s)
suite2 =
Name
ProcedureName
TestClass
BaseFolder
Parameterization
SharedTestFixtures
Tags
Tests Include:
9 Unique Parameterizations, 0 Shared Test Fixture Classes, 0 Tags.
If you first generate the full suite from the TestRand class, you can construct the same filtered suite
using the selectIf method.
suite = matlab.unittest.TestSuite.fromClass(?TestRand);
suite2 = selectIf(suite,s);
suite2.run;
Running TestRand
.......... ..
Done TestRand
__________
Create a selector that omits test elements that use properties with the 'large' or 'medium'
parameter names. Limit results to test elements from the testRepeatable method.
import matlab.unittest.selectors.HasParameter
s = ~(HasParameter('Name','large') | HasParameter('Name','medium'));
suite3 = matlab.unittest.TestSuite.fromMethod(?TestRand,'testRepeatable',s);
{suite3.Name}'
36-93
36 Unit Testing
ans =
{'TestRand[generator=twister]/[seed=0]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=twister]/[seed=123]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=twister]/[seed=4294967295]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=combRecursive]/[seed=0]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=combRecursive]/[seed=123]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=combRecursive]/[seed=4294967295]testRepeatable(dim1=small,dim2=small,dim3=small)'}
{'TestRand[generator=multFibonacci]/[seed=0]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=multFibonacci]/[seed=123]testRepeatable(dim1=small,dim2=small,dim3=small)' }
{'TestRand[generator=multFibonacci]/[seed=4294967295]testRepeatable(dim1=small,dim2=small,dim3=small)'}
suite3.run;
Running TestRand
.........
Done TestRand
__________
At the command prompt, run all of the test elements from the TestRand class that use the 'double'
parameter name.
runtests('TestRand','ParameterName','double');
Running TestRand
.......... .......... .......... .......... ..........
.......... .......... .......... .
Done TestRand
__________
See Also
matlab.unittest.TestSuite | matlab.unittest.TestCase |
matlab.unittest.selectors.HasParameter
Related Examples
• “Use Parameters in Class-Based Tests” on page 36-76
• “Create Basic Parameterized Test” on page 36-83
• “Define Parameters at Suite Creation Time” on page 36-99
• “Use External Parameters in Parameterized Test” on page 36-95
36-94
Use External Parameters in Parameterized Test
You can inject variable inputs into your existing class-based test. To provide test data that is defined
outside the test file and that should be used iteratively by the test (via parameterized testing), create
an array of Parameter instances, and then use the ExternalParameters name-value argument
with TestSuite creation methods such as fromClass.
Create the cleanData function. The function accepts an array, vectorizes the array, removes 0, NaN,
and Inf, and then sorts the array.
function Y = cleanData(X)
Y = X(:); % Vectorize array
Y = rmmissing(Y); % Remove NaN
% Remove 0 and Inf
idx = (Y==0 | Y==Inf);
Y = Y(~idx);
% If array is empty, set to eps
if isempty(Y)
Y = eps;
end
Y = sort(Y); % Sort vector
end
Create a parameterized test to test the cleanData function. The test repeats each of the four Test
methods for the two data sets that are defined in the properties block.
36-95
36 Unit Testing
end
Run the tests. The framework runs the eight parameterized tests using the data defined in the test
file.
import matlab.unittest.TestSuite
suite1 = TestSuite.fromClass(?TestClean);
results = suite1.run;
table(results)
Running TestClean
........
Done TestClean
__________
ans =
8×6 table
Create an array of Parameter instances from the external data set. The fromData method accepts
the name of the parameterization property from the properties block in TestClean and the new
data as a cell array (or structure).
import matlab.unittest.parameters.Parameter
newData = {A};
param = Parameter.fromData("Data",newData);
Create a new test suite using the external parameters. The framework appends the characters #ext
to the end of the parameter names, indicating that the parameters are defined externally.
suite2 = TestSuite.fromClass(?TestClean,"ExternalParameters",param);
{suite2.Name}'
ans =
{'TestClean/classCheck(Data=2x3_double#ext)' }
36-96
Use External Parameters in Parameterized Test
{'TestClean/sortCheck(Data=2x3_double#ext)' }
{'TestClean/finiteCheck(Data=2x3_double#ext)'}
{'TestClean/noZeroCheck(Data=2x3_double#ext)'}
To have full control over parameter names in the suite, define the parameters using a structure. Then,
run the tests.
newData = struct("commandLineData",A);
param = Parameter.fromData("Data",newData);
suite2 = TestSuite.fromClass(?TestClean,"ExternalParameters",param);
{suite2.Name}'
results = suite2.run;
ans =
{'TestClean/classCheck(Data=commandLineData#ext)' }
{'TestClean/sortCheck(Data=commandLineData#ext)' }
{'TestClean/finiteCheck(Data=commandLineData#ext)'}
{'TestClean/noZeroCheck(Data=commandLineData#ext)'}
Running TestClean
....
Done TestClean
__________
Create parameters from the stored data set and A, and then create a test suite.
newData = struct("commandLineData",A,"storedData",readmatrix("myFile.dat"));
param2 = Parameter.fromData("Data",newData);
suite3 = TestSuite.fromClass(?TestClean,"ExternalParameters",param2);
To run the tests using parameters defined in the test file and externally, concatenate the test suites.
View the suite element names and run the tests.
suite = [suite1 suite3];
{suite.Name}'
results = suite.run;
ans =
{'TestClean/classCheck(Data=clean)' }
{'TestClean/classCheck(Data=needsCleaning)' }
{'TestClean/sortCheck(Data=clean)' }
{'TestClean/sortCheck(Data=needsCleaning)' }
36-97
36 Unit Testing
{'TestClean/finiteCheck(Data=clean)' }
{'TestClean/finiteCheck(Data=needsCleaning)' }
{'TestClean/noZeroCheck(Data=clean)' }
{'TestClean/noZeroCheck(Data=needsCleaning)' }
{'TestClean/classCheck(Data=commandLineData#ext)' }
{'TestClean/classCheck(Data=storedData#ext)' }
{'TestClean/sortCheck(Data=commandLineData#ext)' }
{'TestClean/sortCheck(Data=storedData#ext)' }
{'TestClean/finiteCheck(Data=commandLineData#ext)'}
{'TestClean/finiteCheck(Data=storedData#ext)' }
{'TestClean/noZeroCheck(Data=commandLineData#ext)'}
{'TestClean/noZeroCheck(Data=storedData#ext)' }
Running TestClean
........
Done TestClean
__________
Running TestClean
........
Done TestClean
__________
See Also
matlab.unittest.TestSuite | matlab.unittest.parameters.Parameter.fromData
Related Examples
• “Use Parameters in Class-Based Tests” on page 36-76
• “Create Basic Parameterized Test” on page 36-83
• “Create Advanced Parameterized Test” on page 36-88
• “Define Parameters at Suite Creation Time” on page 36-99
36-98
Define Parameters at Suite Creation Time
Parameterized tests let you run the same test procedure repeatedly, using different data values each
time. In a parameterized test, these data values are called parameters and are represented by
parameterization properties of the test class. MATLAB® uses parameterization properties to
generate the parameter names and values for each test run.
In most cases, MATLAB can determine the value of a parameterization property when it loads the test
class definition. Therefore, you can initialize the property using a default value. When you initialize a
parameterization property with a default value, the parameters associated with the property remain
fixed for different test runs. Each time you create a suite from the parameterized test class, the
testing framework uses the same parameter names and values to run the tests.
In some cases, MATLAB cannot determine the value of a parameterization property when it loads the
test class definition. For example, sometimes a parameterization property depends on another
property defined at a higher parameterization level. Or you might not want the parameters to be
determined at class load time. For instance, if parameters represent files in a folder, you might want
to refresh the parameters each time you create a suite to test the files. When you cannot or do not
want to initialize a parameterization property at class load time, initialize it at suite creation time
using a static method with the TestParameterDefinition attribute. When you initialize a
parameterization property using a TestParameterDefinition method, the parameters associated
with the property can vary for different test runs. In other words, each time you create a test suite
from the parameterized test class, the framework generates fresh parameter names and values to run
the tests.
This example shows how to use parameterization properties with default and nondefault values to
verify that the public properties of a group of classes in your current folder are nonempty. In it, you
define a parameterized test class named PropertiesTest in the test subfolder of your current
folder. You define three classes to test, named ClassA, ClassB, and ClassC, in the source
subfolder of your current folder. For a summary of these three classes, see Classes in source
Subfolder on page 36-104.
To test the public properties of classes defined in the source subfolder, create the PropertiesTest
class in the test subfolder. This class takes three specified classes, retrieves all properties of each
class, and verifies that they are nonempty. To iterate over the classes to test, parameterize
PropertiesTest at the class-setup level. To iterate over the properties of each class specified by a
given class-setup-level parameterization, parameterize PropertiesTest at the test level.
• List the classes for the framework to iterate over in a property named classToTest. Because this
example assumes that the classes in the source subfolder are fixed and known at the time
MATLAB loads the test class definition, initialize the property using a default value. In order to
specify the class to test before running any Test methods, make classToTest a
ClassSetupParameter property.
• Define a TestParameter property named propertyToTest that you can use to iterate over the
properties of whatever class the framework is currently testing. Because its value depends on the
class being tested, do not assign it a default value. Instead, initialize it at suite creation time using
a TestParameterDefinition method.
36-99
36 Unit Testing
• To store the value of different properties on an instance of the class being tested, define a
property named ObjectToTest.
classdef PropertiesTest < matlab.unittest.TestCase
properties (ClassSetupParameter)
classToTest = {'ClassA','ClassB','ClassC'};
end
properties (TestParameter)
propertyToTest
end
properties
ObjectToTest
end
end
In the PropertiesTest class, propertyToTest has a different value for each class being tested.
Therefore, you cannot assign a default value to it. Instead, you must initialize it at suite creation time.
To implement this requirement, add a TestParameterDefinition method named
initializeProperty. Because a TestParameterDefinition method must be static, use the
combined method attributes TestParameterDefinition,Static to define the method.
properties (TestParameter)
propertyToTest
end
properties
ObjectToTest
end
methods (TestParameterDefinition,Static)
function propertyToTest = initializeProperty(classToTest)
propertyToTest = properties(classToTest);
end
end
end
In the initializeProperty method, both the input argument classToTest and the output
argument propertyToTest are parameterization properties defined in the PropertiesTest class.
Any time you define a TestParameterDefinition method, all inputs to the method must match
parameterization properties defined in the same class or one of its superclasses. Also, all outputs of
the method must match parameterization properties defined in the same class.
In the initializeProperty method, the input argument classToTest is defined at the highest
parameterization level. This puts it higher than the output argument propertyToTest, which is
36-100
Define Parameters at Suite Creation Time
defined at the lowest parameterization level. Any time you define a TestParameterDefinition
method that accepts inputs, the inputs must be at a higher parameterization level relative to the
outputs of the method. For more information about parameterization levels, see “Use Parameters in
Class-Based Tests” on page 36-76.
To test for nonempty property values, you must first create an object of the class being tested so that
you can retrieve the property values. To implement this requirement, add the parameterized
classSetup method to the PropertiesTest class. In order to have the object ready before running
any Test methods, make classSetup a TestClassSetup method.
The classSetup method creates an instance of the class being tested and stores it in the
ObjectToTest property. Tests can later retrieve the property values from ObjectToTest. In this
example, the framework runs the tests by calling the classSetup method three times—one time for
each of ClassA, ClassB, and ClassC.
classdef PropertiesTest < matlab.unittest.TestCase
properties (ClassSetupParameter)
classToTest = {'ClassA','ClassB','ClassC'};
end
properties (TestParameter)
propertyToTest
end
properties
ObjectToTest
end
methods (TestParameterDefinition,Static)
function propertyToTest = initializeProperty(classToTest)
propertyToTest = properties(classToTest);
end
end
methods (TestClassSetup)
function classSetup(testCase,classToTest)
constructor = str2func(classToTest);
testCase.ObjectToTest = constructor();
end
end
end
To test that the properties on ObjectToTest are nonempty, add a Test method named
testProperty. In order for the method to iterate over the properties of ObjectToTest, make the
method parameterized, and pass it propertyToTest.
During each test, the testProperty method retrieves the value of a property on ObjectToTest.
Then, it uses a call to the verifyNotEmpty qualification method to verify that the value is not empty.
For a given class-setup-level parameterization, the framework calls testProperty once for each
property on the class being tested.
classdef PropertiesTest < matlab.unittest.TestCase
properties (ClassSetupParameter)
36-101
36 Unit Testing
classToTest = {'ClassA','ClassB','ClassC'};
end
properties (TestParameter)
propertyToTest
end
properties
ObjectToTest
end
methods (TestParameterDefinition,Static)
function propertyToTest = initializeProperty(classToTest)
propertyToTest = properties(classToTest);
end
end
methods (TestClassSetup)
function classSetup(testCase,classToTest)
constructor = str2func(classToTest);
testCase.ObjectToTest = constructor();
end
end
methods (Test)
function testProperty(testCase,propertyToTest)
value = testCase.ObjectToTest.(propertyToTest);
testCase.verifyNotEmpty(value)
end
end
end
Now that the PropertiesTest class definition is complete, you can create a parameterized test
suite and run the tests. To do this, make sure that the source and test subfolders are on the path.
addpath("source","test")
suite = testsuite("PropertiesTest");
The test suite includes eight elements. Each element corresponds to a property defined within the
source subfolder. Return the name of the first suite element.
suite(1).Name
ans =
'PropertiesTest[classToTest=ClassA]/testProperty(propertyToTest=PropA1)'
36-102
Define Parameters at Suite Creation Time
Run the tests. Because two properties in the source subfolder are empty, two of the tests fail.
suite.run
Running PropertiesTest
..
================================================================================
Verification failed in PropertiesTest[classToTest=ClassA]/testProperty(propertyToTest=PropA3).
---------------------
Framework Diagnostic:
---------------------
verifyNotEmpty failed.
--> The value must not be empty.
--> The value has a size of [0 0].
Actual Value:
[]
------------------
Stack Information:
------------------
In C:\TEMP\Examples\matlab-ex41465327\test\PropertiesTest.m (PropertiesTest.testProperty) at
================================================================================
....
================================================================================
Verification failed in PropertiesTest[classToTest=ClassC]/testProperty(propertyToTest=PropC1).
---------------------
Framework Diagnostic:
---------------------
verifyNotEmpty failed.
--> The value must not be empty.
--> The value has a size of [0 0].
Actual Value:
[]
------------------
Stack Information:
------------------
In C:\TEMP\Examples\matlab-ex41465327\test\PropertiesTest.m (PropertiesTest.testProperty) at
================================================================================
..
Done PropertiesTest
__________
Failure Summary:
ans =
1×8 TestResult array with properties:
Name
Passed
36-103
36 Unit Testing
Failed
Incomplete
Duration
Details
Totals:
6 Passed, 2 Failed (rerun), 0 Incomplete.
0.2348 seconds testing time.
Run only the tests for ClassB. To do this, use the selectIf method of the
matlab.unittest.TestSuite class to select test suite elements that use a particular
parameterization. The resulting test suite is a filtered suite and has only three elements.
suite2 = suite.selectIf("ParameterName","PropB*");
{suite2.Name}'
Running PropertiesTest
...
Done PropertiesTest
__________
Alternatively, you can run the same tests by creating a selector that filters the test suite by
parameterization.
import matlab.unittest.selectors.HasParameter
import matlab.unittest.constraints.StartsWithSubstring
suite3 = matlab.unittest.TestSuite.fromClass(?PropertiesTest, ...
HasParameter("Name",StartsWithSubstring("PropB")));
suite3.run;
Running PropertiesTest
...
Done PropertiesTest
__________
This section provides the contents of the classes in the source subfolder.
ClassA has three properties. Two of its properties have nonempty values.
classdef ClassA
properties
PropA1 = 1;
PropA2 = 2;
PropA3
36-104
Define Parameters at Suite Creation Time
end
end
ClassB has three properties. All of its properties have nonempty values.
classdef ClassB
properties
PropB1 = 1;
PropB2 = 2;
PropB3 = 'a';
end
end
ClassC has two properties. One of its properties has a nonempty value.
classdef ClassC
properties
PropC1
PropC2 = [1 2 3];
end
end
See Also
matlab.unittest.TestSuite | matlab.unittest.selectors.HasParameter |
matlab.unittest.TestCase
Related Examples
• “Use Parameters in Class-Based Tests” on page 36-76
• “Create Basic Parameterized Test” on page 36-83
• “Create Advanced Parameterized Test” on page 36-88
• “Use External Parameters in Parameterized Test” on page 36-95
36-105
36 Unit Testing
Create the following function that solves roots of the quadratic equation in a file,
quadraticSolver.m, in your working folder.
function r = quadraticSolver(a, b, c)
% quadraticSolver returns solutions to the
% quadratic equation a*x^2 + b*x + c = 0.
end
Create the following test class in a file, SolverTest.m, in your working folder.
methods (Test)
function testRealSolution(testCase)
actSolution = quadraticSolver(1,-3,2);
expSolution = [2,1];
testCase.verifyEqual(actSolution,expSolution);
end
function testImaginarySolution(testCase)
actSolution = quadraticSolver(1,2,10);
expSolution = [-1+3i, -1-3i];
testCase.verifyEqual(actSolution,expSolution);
end
end
end
At the command prompt, add the matlab.unittest.TestSuite class to the current import list.
import matlab.unittest.TestSuite
Make sure the SolverTest class definition file is on your MATLAB path.
36-106
Create Simple Test Suites
The fromClass method creates a suite from all Test methods in the SolverTest class.
suiteClass = TestSuite.fromClass(?SolverTest);
result = run(suiteClass);
The fromFile method creates a suite using the name of the file to identify the class.
suiteFile = TestSuite.fromFile('SolverTest.m');
result = run(suiteFile);
The fromFolder method creates a suite from all test case files in the specified folder. For example,
the following files are in the current folder:
• BankAccountTest.m
• DocPolynomTest.m
• FigurePropertiesTest.m
• IsSupportedTest.m
• SolverTest.m
suiteFolder = TestSuite.fromFolder(pwd);
result = run(suiteFolder);
suiteMethod = TestSuite.fromMethod(?SolverTest,'testRealSolution')'
result = run(suiteMethod);
See Also
matlab.unittest.TestSuite
Related Examples
• “Write Simple Test Case Using Functions” on page 36-32
• “Write Simple Test Case Using Classes” on page 36-53
36-107
36 Unit Testing
You can also assign the test file output to a variable and run the tests using the functional form or dot
notation.
% Create Test or TestCase objects
t1 = DocPolynomTest; % TestCase object from class-based test
t2 = axesPropertiesTest; % Test object from function-based test
Alternatively, you can run tests contained in a single file by using runtests or from the Editor.
36-108
Run Tests for Various Workflows
results1 = run(DocPolynomTest,'testMultiplication');
Function-based test files return an array of Test objects instead of a single TestCase object. You
can run a particular test by indexing into the array. However, you must examine the Name field in the
test array to ensure you run the correct test. For example, only run the test, surfaceColorTest,
from the axesPropertiesTest file.
ans =
axesPropertiesTest/testDefaultXLim
ans =
axesPropertiesTest/surfaceColorTest
suite = {'axesPropertiesTest','DocPolynomTest'};
runtests(suite);
Run all tests in the current folder using the pwd as input to the runtests function.
runtests(pwd);
Alternatively, you can explicitly create Test arrays and use the run method to run them.
import matlab.unittest.TestSuite
s1 = TestSuite.fromClass(?DocPolynomTest);
s2 = TestSuite.fromFile('axesPropertiesTest.m');
36-109
36 Unit Testing
Since the suite is explicitly defined, it is easy for you to perform further analysis on the suite, such as
rerunning failed tests.
failedTests = fullSuite([result.Failed]);
result2 = run(failedTests);
import matlab.unittest.TestRunner
import matlab.unittest.TestSuite
import matlab.unittest.plugins.TestRunProgressPlugin
% Generate TestSuite.
s1 = TestSuite.fromClass(?DocPolynomTest);
s2 = TestSuite.fromFile('axesPropertiesTest.m');
suite = [s1 s2];
See Also
runtests | run (TestCase) | run (TestSuite) | run (TestRunner)
More About
• “Run Tests in Editor” on page 36-17
36-110
Programmatically Access Test Diagnostics
After you run tests, you can access recorded diagnostics using the DiagnosticRecord field in the
Details property on the TestResult object. For example, if your test results are stored in the
variable results, then result(2).Details.DiagnosticRecord contains the recorded
diagnostics for the second test in the suite.
The recorded diagnostics are DiagnosticRecord objects. To access particular types of test
diagnostics for a test, use the selectFailed, selectPassed, selectIncomplete, and
selectLogged methods of the DiagnosticRecord class.
See Also
matlab.unittest.plugins.DiagnosticsRecordingPlugin |
matlab.unittest.plugins.diagnosticrecord.DiagnosticRecord |
matlab.unittest.TestResult
Related Examples
• “Add Plugin to Test Runner” on page 36-112
36-111
36 Unit Testing
This example shows how to add a plugin to the test runner. The example adds a plugin created using
the matlab.unittest.plugins.TestRunProgressPlugin class, which reports on test run
progress.
In a file named BankAccount.m in your current folder, create the BankAccount class.
36-112
Add Plugin to Test Runner
end
end
methods (Static)
function obj = loadobj(s)
if isstruct(s)
accNum = s.AccountNumber;
initBal = s.AccountBalance;
obj = BankAccount(accNum,initBal);
else
obj.AccountListener = AccountManager.addAccount(s);
end
end
end
end
In another file named BankAccountTest.m in your current folder, create a test class to test the
BankAccount class.
function testConstructorNotEnoughInputs(testCase)
import matlab.unittest.constraints.Throws
testCase.verifyThat(@()BankAccount,Throws("MATLAB:minrhs"))
end
function testDeposit(testCase)
b = BankAccount(1234,100);
b.deposit(25)
testCase.verifyEqual(b.AccountBalance,125)
end
function testWithdraw(testCase)
b = BankAccount(1234,100);
b.withdraw(25)
testCase.verifyEqual(b.AccountBalance,75)
end
function testNotifyInsufficientFunds(testCase)
callbackExecuted = false;
function testCallback(~,~)
callbackExecuted = true;
end
b = BankAccount(1234,100);
b.addlistener("InsufficientFunds",@testCallback);
b.withdraw(50)
testCase.assertFalse(callbackExecuted, ...
"The callback should not have executed yet.")
b.withdraw(60)
36-113
36 Unit Testing
testCase.verifyTrue(callbackExecuted, ...
"The listener callback should have fired.")
end
end
end
suite = matlab.unittest.TestSuite.fromClass(?BankAccountTest);
Create a test runner with no plugins, and use it to run the tests. The test runner runs the tests
silently and does not display any messages.
runner = matlab.unittest.TestRunner.withNoPlugins;
runner.run(suite);
Add a TestRunProgressPlugin instance to the test runner, and run the tests again. The test runner
now displays test run progress about BankAccountTest. (Default test runners already include this
plugin.)
import matlab.unittest.plugins.TestRunProgressPlugin
runner.addPlugin(TestRunProgressPlugin.withVerbosity(2))
runner.run(suite);
Running BankAccountTest
.....
Done BankAccountTest
__________
See Also
matlab.unittest.plugins
36-114
Write Plugins to Extend TestRunner
At the test suite, test class, and test levels, the reportFinalizedResult method enables the test
runner to report finalized test results. A test result is finalized when no remaining test content can
modify it. The test runner determines if it invokes the reportFinalizedResult method at each
level. At the test session level, the reportFinalizedSuite method enables the test runner to
report test results once the test suite is finalized.
The creation methods are the only set of TestRunnerPlugin methods with an output argument.
Typically, you extend the creation methods to listen for various events originating from the test
content at the corresponding level. Since both TestCase and Fixture instances inherit from the
handle class, you add listeners using the addlistener method. The methods that set up, run, and
tear down test content extend the way the test runner evaluates the test content.
The run method at this level, runTestSuite, extends the running of a portion of the entire
TestSuite array that the testing framework passes to the test runner. The
36-115
36 Unit Testing
reportFinalizedSuite method extends the reporting of a test suite that has been finalized by
runTestSuite.
At this level, the createSharedTestFixture method is the only plugin method with an output
argument. It returns the Fixture instances for each shared fixture required by a test class. These
Fixture instances are available to the test through the getSharedTestFixtures method of
TestCase.
The run method at this level, runTestClass, extends the running of tests that belong to the same
test class or the same function-based test, and incorporates the functionality described for the test
class level plugin methods.
At this level, the createTestClassInstance method is the only plugin method with an output
argument. It returns the TestCase instances created at the class level. For each class, the testing
framework passes the instance into any methods with the TestClassSetup or
TestClassTeardown attribute.
The run method at this level, runTest, extends the running of a single TestSuite element, and
incorporates the functionality described for the test level plugin methods.
The testing framework evaluates methods at the test class level within the scope of the
runTestClass method. If the TestClassSetup code completes successfully, it invokes the
36-116
Write Plugins to Extend TestRunner
runTest method one time for each element in the TestSuite array. Each TestClassSetup
parameterization invokes the creation, setup, and teardown methods a single time.
At this level, the createTestMethodInstance method is the only plugin method with an output
argument. It returns the TestCase instances created for each Test element. The testing framework
passes each of these instances into the corresponding Test methods, and into any methods with the
TestMethodSetup or TestMethodTeardown attribute.
The testing framework evaluates methods at the test level within the scope of the runTest method.
Provided the framework completes all TestMethodSetup work, it invokes the plugin methods at this
level a single time per Test element.
See Also
Functions
addlistener
Classes
matlab.unittest.plugins.TestRunnerPlugin | matlab.unittest.TestRunner |
matlab.unittest.TestCase | matlab.unittest.fixtures.Fixture |
matlab.unittest.TestSuite | matlab.unittest.plugins.Parallelizable |
matlab.automation.streams.OutputStream
Related Examples
• “Create Custom Plugin” on page 36-118
• “Run Tests in Parallel with Custom Plugin” on page 36-123
• “Plugin to Generate Custom Test Output Format” on page 36-140
• “Write Plugin to Save Diagnostic Details” on page 36-136
36-117
36 Unit Testing
In a file in your current folder, create the custom plugin class AssertionCountingPlugin, which
inherits from the TestRunnerPlugin class. For the complete code for
AssertionCountingPlugin, see AssertionCountingPlugin Class Definition Summary on page 36-
0 .
To keep track of the number of passing and failing assertions, define two read-only properties,
NumPassingAssertions and NumFailingAssertions, within a properties block.
plugin.NumPassingAssertions = 0;
plugin.NumFailingAssertions = 0;
runTestSuite@matlab.unittest.plugins.TestRunnerPlugin(...
plugin, pluginData);
The testing framework evaluates this method one time. It displays information about the total number
of tests, initializes the properties used by the plugin to generate text output, and invokes the
superclass method. After the framework completes evaluating the superclass method, the
runTestSuite method displays the assertion count summary by calling the helper method
printAssertionSummary (see Define Helper Methods on page 36-0 ).
Add listeners to AssertionPassed and AssertionFailed events to count the assertions. To add
these listeners, extend the methods used by the testing framework to create the test content. The test
content includes TestCase instances for each Test element, class-level TestCase instances for the
TestClassSetup and TestClassTeardown methods, and Fixture instances used when a
TestCase class has the SharedTestFixtures attribute.
36-118
Create Custom Plugin
Invoke the corresponding superclass method when you override the creation methods. The creation
methods return the content that the testing framework creates for each of their respective contexts.
When implementing one of these methods using the incrementPassingAssertionsCount and
incrementFailingAssertionsCount helper methods on page 36-0 , add the listeners required
by the plugin to the returned Fixture or TestCase instance.
fixture.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
fixture.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
end
Extend runTest to display the name of each test at run time. Include this method in a methods
block with protected access. Like all plugin methods, the runTest method requires you to invoke
the corresponding superclass method.
runTest@matlab.unittest.plugins.TestRunnerPlugin(...
plugin, pluginData);
end
end
36-119
36 Unit Testing
In a methods block with private access, define three helper methods. These methods increment the
number of passing or failing assertions, and print the assertion count summary.
function incrementFailingAssertionsCount(plugin)
plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
end
function printAssertionSummary(plugin)
fprintf('%s\n', repmat('_', 1, 30))
fprintf('Total Assertions: %d\n', ...
plugin.NumPassingAssertions + plugin.NumFailingAssertions)
fprintf('\t%d Passed, %d Failed\n', ...
plugin.NumPassingAssertions, plugin.NumFailingAssertions)
end
end
plugin.NumPassingAssertions = 0;
plugin.NumFailingAssertions = 0;
runTestSuite@matlab.unittest.plugins.TestRunnerPlugin(...
plugin, pluginData);
fixture.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
fixture.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
36-120
Create Custom Plugin
testCase.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener('AssertionPassed', ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener('AssertionFailed', ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
runTest@matlab.unittest.plugins.TestRunnerPlugin(...
plugin, pluginData);
end
end
function incrementFailingAssertionsCount(plugin)
plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
end
function printAssertionSummary(plugin)
fprintf('%s\n', repmat('_', 1, 30))
fprintf('Total Assertions: %d\n', ...
plugin.NumPassingAssertions + plugin.NumFailingAssertions)
fprintf('\t%d Passed, %d Failed\n', ...
plugin.NumPassingAssertions, plugin.NumFailingAssertions)
end
end
end
In your current folder, create a file named ExampleTest.m containing the following test class.
classdef ExampleTest < matlab.unittest.TestCase
methods(Test)
function testOne(testCase) % Test fails
testCase.assertEqual(5, 4)
end
function testTwo(testCase) % Test passes
testCase.verifyEqual(5, 5)
end
function testThree(testCase) % Test passes
testCase.assertEqual(7*2, 14)
end
end
end
At the command prompt, create a test suite from the ExampleTest class.
import matlab.unittest.TestSuite
import matlab.unittest.TestRunner
suite = TestSuite.fromClass(?ExampleTest);
36-121
36 Unit Testing
Create a TestRunner instance with no plugins. This code creates a silent runner and gives you
control over the installed plugins.
runner = TestRunner.withNoPlugins;
result = runner.run(suite);
runner.addPlugin(AssertionCountingPlugin)
result = runner.run(suite);
See Also
matlab.unittest.plugins.TestRunnerPlugin |
matlab.automation.streams.OutputStream | matlab.unittest.TestCase |
matlab.unittest.TestRunner | matlab.unittest.fixtures.Fixture | addlistener
Related Examples
• “Write Plugins to Extend TestRunner” on page 36-115
• “Run Tests in Parallel with Custom Plugin” on page 36-123
• “Write Plugin to Save Diagnostic Details” on page 36-136
36-122
Run Tests in Parallel with Custom Plugin
To keep track of the number of passing and failing assertions, define four read-only properties within
a properties block. Each MATLAB worker on the current parallel pool uses
NumPassingAssertions and NumFailingAssertions to track the number of passing and failing
assertions when running a portion of the TestSuite array. The MATLAB client uses
FinalizedNumPassingAssertions and FinalizedNumFailingAssertions to aggregate the
results from different workers and to report the total number of passing and failing assertions at the
end of the test session.
runSession@ ...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
36-123
36 Unit Testing
end
end
Invoke the corresponding superclass method when you override the creation methods. The creation
methods return the content that the testing framework creates for each of their respective contexts.
When implementing each of these methods using the incrementPassingAssertionsCount and
incrementFailingAssertionsCount helper methods on page 36-126, add the listeners required
by the plugin to the returned Fixture or TestCase instance.
fixture.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
fixture.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
end
36-124
Run Tests in Parallel with Custom Plugin
Extend the test runner to display the identifier of each test group that a worker runs along with the
number of Test elements within the group. Additionally, store the number of passing and failing
assertions in a communication buffer so that the client can retrieve these values to produce the
finalized results. Like all plugin methods, the runTestSuite method requires you to invoke the
corresponding superclass method at an appropriate point. In this case, invoke the superclass method
after initializing the properties and before storing the worker data. The testing framework evaluates
runTestSuite on the workers as many times as the number of test suite portions.
runTestSuite@ ...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
To store test-specific data, the implementation of runTestSuite contains a call to the storeIn
method of the Parallelizable interface. Use storeIn along with retrieveFrom when workers
must report to the client. In this example, after returning from the superclass method,
NumPassingAssertions and NumFailingAssertions contain the number of passing and failing
assertions corresponding to a group of tests. Because storeIn accepts the worker data as only one
input argument, the structure assertionStruct groups the assertion counts using two fields.
reportFinalizedSuite@ ...
36-125
36 Unit Testing
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
end
end
function incrementFailingAssertionsCount(plugin)
plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
end
function printAssertionSummary(plugin)
fprintf("%s\n",repmat('_',1,30))
fprintf("Total Assertions: %d\n", ...
plugin.FinalizedNumPassingAssertions + ...
plugin.FinalizedNumFailingAssertions)
fprintf("\t%d Passed, %d Failed\n", ...
plugin.FinalizedNumPassingAssertions, ...
plugin.FinalizedNumFailingAssertions)
end
end
runSession@ ...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
36-126
Run Tests in Parallel with Custom Plugin
fixture.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
fixture.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
testCase.addlistener("AssertionPassed", ...
@(~,~)plugin.incrementPassingAssertionsCount);
testCase.addlistener("AssertionFailed", ...
@(~,~)plugin.incrementFailingAssertionsCount);
end
function runTestSuite(plugin,pluginData)
suiteSize = numel(pluginData.TestSuite);
groupNumber = pluginData.Group;
fprintf("### Running a total of %d tests in group %d\n", ...
suiteSize,groupNumber)
plugin.NumPassingAssertions = 0;
plugin.NumFailingAssertions = 0;
runTestSuite@ ...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
function reportFinalizedSuite(plugin,pluginData)
assertionStruct = plugin.retrieveFrom( ...
pluginData.CommunicationBuffer, ...
DefaultData=struct("Passing",0,"Failing",0));
plugin.FinalizedNumPassingAssertions = ...
plugin.FinalizedNumPassingAssertions + assertionStruct.Passing;
plugin.FinalizedNumFailingAssertions = ...
plugin.FinalizedNumFailingAssertions + assertionStruct.Failing;
reportFinalizedSuite@ ...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
end
end
function incrementFailingAssertionsCount(plugin)
plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
end
function printAssertionSummary(plugin)
fprintf("%s\n",repmat('_',1,30))
fprintf("Total Assertions: %d\n", ...
plugin.FinalizedNumPassingAssertions + ...
plugin.FinalizedNumFailingAssertions)
36-127
36 Unit Testing
methods (Test)
function testAssert(testCase,num1,num2)
testCase.assertNotEqual(num1(),num2())
end
function testVerify(testCase,num1,num2)
testCase.verifyNotEqual(num1(),num2())
end
function testAssume(testCase,num1,num2)
testCase.assumeNotEqual(num1(),num2())
end
end
end
Create a test runner with no plugins. This code creates a silent runner that produces no output.
runner = testrunner("minimal");
You can now add any plugins you choose. Add an instance of the AssertionCountingPlugin class
to the runner, and run the tests in parallel. (You can also run the same tests in serial mode if you
invoke the run method on the runner.)
runner.addPlugin(AssertionCountingPlugin)
runner.runInParallel(suite);
----------------
36-128
Run Tests in Parallel with Custom Plugin
Finished Group 2
----------------
### Running a total of 20 tests in group 2
----------------
Finished Group 3
----------------
### Running a total of 19 tests in group 3
----------------
Finished Group 4
----------------
### Running a total of 19 tests in group 4
----------------
Finished Group 5
----------------
### Running a total of 18 tests in group 5
----------------
Finished Group 6
----------------
### Running a total of 18 tests in group 6
----------------
Finished Group 7
----------------
### Running a total of 18 tests in group 7
----------------
Finished Group 8
----------------
### Running a total of 17 tests in group 8
----------------
Finished Group 9
----------------
### Running a total of 17 tests in group 9
-----------------
Finished Group 10
-----------------
### Running a total of 17 tests in group 10
-----------------
Finished Group 11
-----------------
### Running a total of 16 tests in group 11
-----------------
Finished Group 12
-----------------
### Running a total of 16 tests in group 12
-----------------
Finished Group 13
-----------------
### Running a total of 15 tests in group 13
36-129
36 Unit Testing
-----------------
Finished Group 14
-----------------
### Running a total of 15 tests in group 14
-----------------
Finished Group 16
-----------------
### Running a total of 14 tests in group 16
-----------------
Finished Group 15
-----------------
### Running a total of 15 tests in group 15
-----------------
Finished Group 17
-----------------
### Running a total of 14 tests in group 17
-----------------
Finished Group 18
-----------------
### Running a total of 12 tests in group 18
See Also
Functions
testrunner | runInParallel | addlistener
Classes
matlab.unittest.plugins.TestRunnerPlugin |
matlab.unittest.plugins.Parallelizable | matlab.unittest.TestRunner |
matlab.unittest.TestSuite | matlab.unittest.TestCase |
matlab.unittest.fixtures.Fixture
Related Examples
• “Write Plugins to Extend TestRunner” on page 36-115
• “Create Custom Plugin” on page 36-118
36-130
Write Plugin to Add Data to Test Results
In a file in your current folder, create the custom plugin class DetailsRecordingPlugin, which
inherits from the TestRunnerPlugin class. For the complete code for DetailsRecordingPlugin,
see DetailsRecordingPlugin Class Definition Summary on page 36-0 .
To store the actual and expected values in TestResult objects, define two constant properties,
ActField and ExpField, within a properties block. Set the value of ActField to the name of the
field of the Details structure that contains the actual value. Set the value of ExpField to the name
of the field that contains the expected value.
properties (Constant, Access = private)
ActField = 'ActualValue';
ExpField = 'ExpectedValue';
end
To add new fields to the Details property of all TestResult objects belonging to the test session,
override the runSession method of TestRunnerPlugin in a methods block with protected
access. runSession adds two empty fields to the Details structure of TestResult objects and
invokes the superclass method to trigger the entire test run.
methods (Access = protected)
function runSession(plugin,pluginData)
resultDetails = pluginData.ResultDetails;
resultDetails.append(plugin.ActField,{})
resultDetails.append(plugin.ExpField,{})
runSession@matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData);
end
end
To add the fields, the implementation of runSession contains calls to the append method of the
matlab.unittest.plugins.plugindata.ResultDetails class. Each call adds an empty field to
the Details structure.
Add listeners for the AssertionPassed and AssertionFailed events by extending the methods
used by the testing framework to create the test content. The test content includes TestCase
instances for each Test element, class-level TestCase instances for the TestClassSetup and
TestClassTeardown method blocks, and Fixture instances used when a TestCase class has the
SharedTestFixtures attribute.
Invoke the corresponding superclass method when you override the creation methods. The listeners
that you add to the returned Fixture or TestCase instances cause the reactToAssertion helper
method on page 36-0 to execute whenever an assertion is performed. To add assertion data to test
results, pass the result modifier instance along with the assertion event listener data to the helper
method.
36-131
36 Unit Testing
In a methods block with private access, define the helper method reactToAssertion. This
method uses the QualificationEventData instance to extract the actual and expected values in
assertions based on the IsEqualTo constraint, converts the extracted values to cell arrays, and
appends the cell arrays to the fields of the corresponding TestResult object.
36-132
Write Plugin to Add Data to Test Results
end
In your current folder, create a file named ExampleTest.m containing the following parameterized
test class. The class results in a test suite with 25 elements, each corresponding to an experiment
performed using a different seed for the random number generator. In each experiment, the testing
framework creates a 1-by-100 vector of normally distributed random numbers and asserts that the
magnitude of the difference between the actual and expected sample means is within 0.1.
classdef ExampleTest < matlab.unittest.TestCase
properties
SampleSize = 100;
end
properties (TestParameter)
seed = num2cell(randi(10^6,1,25));
end
36-133
36 Unit Testing
methods(Test)
function testMean(testCase,seed)
import matlab.unittest.constraints.IsEqualTo
import matlab.unittest.constraints.AbsoluteTolerance
rng(seed)
testCase.assertThat(mean(randn(1,testCase.SampleSize)),...
IsEqualTo(0,'Within',AbsoluteTolerance(0.1)));
end
end
end
At the command prompt, create a test suite from the ExampleTest class.
import matlab.unittest.TestSuite
import matlab.unittest.TestRunner
suite = TestSuite.fromClass(?ExampleTest);
Create a TestRunner instance with no plugins. This code creates a silent runner and gives you
control over the installed plugins.
runner = TestRunner.withNoPlugins;
runner.addPlugin(DetailsRecordingPlugin)
result = runner.run(suite)
result =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
18 Passed, 7 Failed (rerun), 7 Incomplete.
0.12529 seconds testing time.
To retrieve more information about the behavior of random number generation, create a structure
array from the Details structures of the test results.
details = [result.Details]
details =
ActualValue
ExpectedValue
36-134
Write Plugin to Add Data to Test Results
Create an array containing the difference between the actual and expected values in each test and
then display the error values in a bar graph. The seven bars with a length greater than 0.1
correspond to the failed tests.
errorInMean = cell2mat([details.ExpectedValue]) - cell2mat([details.ActualValue]);
bar(errorInMean)
xlabel('Experiment')
ylabel('Error')
See Also
matlab.unittest.plugins.TestRunnerPlugin | matlab.unittest.TestRunner |
matlab.unittest.fixtures.Fixture | matlab.unittest.TestSuite | addlistener |
matlab.unittest.TestResult | matlab.unittest.plugins.plugindata.ResultDetails
Related Examples
• “Write Plugins to Extend TestRunner” on page 36-115
• “Create Custom Plugin” on page 36-118
36-135
36 Unit Testing
Create Plugin
In a file in your working folder, create a class, myPlugin, that inherits from the
matlab.unittest.plugins.TestRunnerPlugin class. In the plugin class:
• Define a FailedTestData property on the plugin that stores information from failed tests.
• Override the default createTestMethodInstance method of TestRunnerPlugin to listen for
assertion, fatal assertion, and verification failures, and to record relevant information.
• Override the default runTestSuite method of TestRunnerPlugin to initialize the
FailedTestData property value. If you do not initialize value of the property, each time you run
the tests using the same test runner, failed test information is appended to the FailedTestData
property.
• Define a helper function, recordData, to save information about the test failure as a table.
The plugin saves information contained in the PluginData and QualificationEventData objects.
It also saves the type of failure and timestamp.
properties
FailedTestData
end
testName = pluginData.Name;
testCase.addlistener('AssertionFailed', ...
@(~,event)plugin.recordData(event,testName, 'Assertion'));
testCase.addlistener('FatalAssertionFailed', ...
@(~,event)plugin.recordData(event,testName, 'Fatal Assertion'));
testCase.addlistener('VerificationFailed', ...
@(~,event)plugin.recordData(event,testName, 'Verification'));
end
end
36-136
Write Plugin to Save Diagnostic Details
In your working folder, create the file ExampleTest.m containing the following test class.
classdef ExampleTest < matlab.unittest.TestCase
methods(Test)
function testOne(testCase)
testCase.assertGreaterThan(5,10)
end
function testTwo(testCase)
wrongAnswer = 'wrong';
testCase.verifyEmpty(wrongAnswer,'Not Empty')
testCase.verifyClass(wrongAnswer,'double','Not double')
end
function testThree(testCase)
testCase.assertEqual(7*2,13,'Values not equal')
end
function testFour(testCase)
testCase.fatalAssertEqual(3+2,6);
end
end
end
The fatal assertion failure in testFour causes the framework to halt and throw an error. In this
example, there are no subsequent tests. If there was a subsequent test, the framework would not run
it.
At the command prompt, create a test suite from the ExampleTest class, and create a test runner.
import matlab.unittest.TestSuite
import matlab.unittest.TestRunner
suite = TestSuite.fromClass(?ExampleTest);
runner = TestRunner.withNoPlugins;
Create an instance of myPlugin and add it to the test runner. Run the tests.
p = DiagnosticRecorderPlugin;
runner.addPlugin(p)
result = runner.run(suite);
36-137
36 Unit Testing
With the failed fatal assertion, the framework throws an error, and the test runner does not return a
TestResult object. However, the DiagnosticRecorderPlugin stores information about the tests
preceding and including the test with the failed assertion.
At the command prompt, view information about the failed tests. The information is saved in the
FailedTestData property of the plugin.
T = p.FailedTestData
T =
5×6 table
There are many options to archive or post-process this information. For example, you can save the
variable as a MAT-file or use writetable to write the table to various file types, such as .txt, .csv,
or .xls.
T.Stack(3)
ans =
file: 'C:\Work\ExampleTest.m'
name: 'ExampleTest.testTwo'
line: 9
Display the diagnostics that the framework displayed for the fifth test failure.
celldisp(T.FrameworkDiagnostics(5))
ans{1} =
fatalAssertEqual failed.
--> The values are not equal using "isequaln".
--> Failure table:
Actual Expected Error RelativeError
______ ________ _____ __________________
5 6 -1 -0.166666666666667
Actual Value:
5
36-138
Write Plugin to Save Diagnostic Details
Expected Value:
6
See Also
matlab.unittest.plugins.TestRunnerPlugin | matlab.unittest.TestCase |
matlab.unittest.TestRunner | addlistener
Related Examples
• “Write Plugins to Extend TestRunner” on page 36-115
• “Create Custom Plugin” on page 36-118
• “Plugin to Generate Custom Test Output Format” on page 36-140
36-139
36 Unit Testing
Create Plugin
In a file in your working folder, create a class, ExampleCustomPlugin, that inherits from the
matlab.unittest.plugins.TestRunnerPlugin class. In the plugin class:
• Define a Stream property on the plugin that stores the OutputStream instance. By default, the
plugin writes to standard output.
• Override the default runTestSuite method of TestRunnerPlugin to output text that indicates
the test runner is running a new test session. This information is especially useful if you are
writing to a single log file, as it allows you to differentiate the test runs.
• Override the default reportFinalizedResult method of TestRunnerPlugin to write finalized
test results to the output stream. You can modify the print method to output the test results in a
format that works for your test logs or continuous integration system.
classdef ExampleCustomPlugin < matlab.unittest.plugins.TestRunnerPlugin
properties (Access=private)
Stream
end
methods
function p = ExampleCustomPlugin(stream)
if ~nargin
stream = matlab.automation.streams.ToStandardOutput;
end
validateattributes(stream, ...
{'matlab.automation.streams.OutputStream'},{})
p.Stream = stream;
end
end
methods (Access=protected)
function runTestSuite(plugin,pluginData)
plugin.Stream.print('\n--- NEW TEST SESSION at %s ---\n',...
char(datetime))
runTestSuite@...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData);
end
function reportFinalizedResult(plugin,pluginData)
thisResult = pluginData.TestResult;
if thisResult.Passed
status = 'PASSED';
elseif thisResult.Failed
status = 'FAILED';
elseif thisResult.Incomplete
status = 'SKIPPED';
end
plugin.Stream.print(...
'### YPS Company - Test %s ### - %s in %f seconds.\n',...
status,thisResult.Name,thisResult.Duration)
36-140
Plugin to Generate Custom Test Output Format
reportFinalizedResult@...
matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData)
end
end
end
In your working folder, create the file ExampleTest.m containing the following test class. In this test
class, two of the tests pass and the others result in a verification or assumption failure.
At the command prompt, create a test suite from the ExampleTest class, and create a test runner.
import matlab.unittest.TestSuite
import matlab.unittest.TestRunner
suite = TestSuite.fromClass(?ExampleTest);
runner = TestRunner.withNoPlugins;
Create an instance of ExampleCustomPlugin and add it to the test runner. Run the tests.
import matlab.automation.streams.ToFile
fname = 'YPS_test_results.txt';
p = ExampleCustomPlugin(ToFile(fname));
runner.addPlugin(p)
result = runner.run(suite);
type(fname)
36-141
36 Unit Testing
Rerun the Incomplete tests using the same test runner. View the contents of the output file.
suiteFiltered = suite([result.Incomplete]);
result2 = runner.run(suiteFiltered);
type(fname)
See Also
matlab.unittest.plugins.TestRunnerPlugin |
matlab.automation.streams.OutputStream | matlab.automation.streams.ToFile |
matlab.automation.streams.ToStandardOutput
Related Examples
• “Write Plugins to Extend TestRunner” on page 36-115
• “Write Plugin to Save Diagnostic Details” on page 36-136
36-142
Analyze Test Case Results
This example shows how to analyze the information returned by a test runner created from the
SolverTest test case.
Create the following function that solves roots of the quadratic equation in a file,
quadraticSolver.m, in your working folder.
type quadraticSolver.m
function r = quadraticSolver(a,b,c)
% quadraticSolver returns solutions to the
% quadratic equation a*x^2 + b*x + c = 0.
end
Create the following test class in a file, SolverTest.m, in your working folder.
type SolverTest.m
36-143
36 Unit Testing
Running SolverTest
...
Done SolverTest
__________
ans =
TestResult with properties:
Name: 'SolverTest/realSolution'
Passed: 1
Failed: 0
Incomplete: 0
Duration: 0.0066
Details: [1×1 struct]
Totals:
1 Passed, 0 Failed, 0 Incomplete.
0.0066456 seconds testing time.
To access functionality available to tables, create one from the TestResult object.
rt = table(result)
rt=3×6 table
Name Passed Failed Incomplete Duration Details
________________________________ ______ ______ __________ _________ __________
ans=3×6 table
Name Passed Failed Incomplete Duration Details
36-144
Analyze Test Case Results
writetable(rt,'myTestResults.csv','QuoteStrings',true)
See Also
Related Examples
• “Write Simple Test Case Using Classes” on page 36-53
36-145
36 Unit Testing
Using the SolverTest test case, add a method, testBadRealSolution. This test, based on
testRealSolution, calls the quadraticSolver function with inputs 1,3,2, but tests the results
against an incorrect solution, [2,1].
function testBadRealSolution(testCase)
actSolution = quadraticSolver(1,3,2);
expSolution = [2,1];
testCase.verifyEqual(actSolution,expSolution)
end
Save the updated SolverTest class definition and rerun the tests.
quadTests = matlab.unittest.TestSuite.fromClass(?SolverTest);
result1 = run(quadTests);
Running SolverTest
..
================================================================================
Verification failed in SolverTest/testBadRealSolution.
---------------------
Framework Diagnostic:
---------------------
verifyEqual failed.
--> The values are not equal using "isequaln".
--> Failure table:
Index Actual Expected Error RelativeError
_____ ______ ________ _____ _____________
1 -1 2 -3 -1.5
2 -2 1 -3 -3
Actual Value:
-1 -2
Expected Value:
2 1
------------------
Stack Information:
------------------
In C:\work\SolverTest.m (SolverTest.testBadRealSolution) at 19
================================================================================
.
Done SolverTest
__________
Failure Summary:
Analyze Results
Actual Value:
-1 -2
36-146
Analyze Failed Test Results
Expected Value:
2 1
At this point, you must decide if the error is in quadraticSolver or in your value for expSolution.
Correct Error
Rerun Tests
failedTests = quadTests([result1.Failed]);
result2 = run(failedTests)
Running SolverTest
.
Done SolverTest
__________
result2 =
Name: 'SolverTest/testBadRealSolution'
Passed: 1
Failed: 0
Incomplete: 0
Duration: 0.0108
Details: [1x1 struct]
Totals:
1 Passed, 0 Failed, 0 Incomplete.
0.010813 seconds testing time.
Alternatively, you can rerun failed tests using the (rerun) link in the test results.
See Also
More About
• “Rerun Failed Tests” on page 36-148
36-147
36 Unit Testing
This link allows you to modify your test code or your code under test and quickly rerun failed tests.
However, if you make structural changes to your test class, using the rerun link does not pick up the
changes. Structural changes include adding, deleting, or renaming a test method, and modifying a
test parameter property and its value. In this case, recreate the entire test suite to pick up the
changes.
Create the following function in your current working folder. The function is meant to compute the
square and square root. However, in this example, the function computes the cube of the value
instead of the square.
function [x,y] = exampleFunction(n)
validateattributes(n,{'numeric'},{'scalar'})
function testSquare(testCase)
[sqrVal,sqrRootVal] = exampleFunction(3);
verifyEqual(testCase,sqrVal,9);
end
function testSquareRoot(testCase)
[sqrVal,sqrRootVal] = exampleFunction(100);
verifyEqual(testCase,sqrRootVal,10);
end
Create a test suite and run the tests. The testSquare test fails because the implementation of
exampleFunction is incorrect.
suite = testsuite('ExampleTest.m');
results = run(suite)
Running exampleTest
================================================================================
Verification failed in exampleTest/testSquare.
---------------------
Framework Diagnostic:
---------------------
verifyEqual failed.
--> The values are not equal using "isequaln".
36-148
Rerun Failed Tests
27 9 18 2
Actual Value:
27
Expected Value:
9
------------------
Stack Information:
------------------
In C:\Work\exampleTest.m (testSquare) at 7
================================================================================
..
Done exampleTest
__________
Failure Summary:
results =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
1 Passed, 1 Failed (rerun), 0 Incomplete.
0.24851 seconds testing time.
x = n^2; % square
y = sqrt(n); % square root
end
Click the (rerun) link in the command window to rerun the failed test. You cannot rerun failed tests
if the variable that stores the test results is overwritten. If the link is no longer in the Command
Window, you can type results at the prompt to view it.
Running exampleTest
.
Done exampleTest
__________
ans =
Name: 'exampleTest/testSquare'
Passed: 1
Failed: 0
Incomplete: 0
Duration: 0.0034
36-149
36 Unit Testing
Totals:
1 Passed, 0 Failed, 0 Incomplete.
0.0033903 seconds testing time.
MATLAB stores the TestResult array associated with tests that you rerun in the ans variable.
results is a 1x2 array that contains all the tests in exampleTest.m, and ans is a 1x1 array that
contains the rerun results from the one failed test.
whos
Name Size Bytes Class Attributes
To programmatically rerun failed tests, use the Failed property on the TestResult object to create
and run a filtered test suite.
failedTests = suite([results.Failed]);
result2 = run(failedTests);
Running exampleTest
.
Done exampleTest
__________
To ensure that all passing tests continue to pass, rerun the full test suite.
See Also
More About
• “Analyze Failed Test Results” on page 36-146
36-150
Dynamically Filtered Tests
Assumption failures produce filtered tests. In the matlab.unittest.TestResult class, such a test
is marked Incomplete.
Since filtering test content through the use of assumptions does not produce test failures, it has the
possibility of creating dead test code. Avoiding this requires monitoring of filtered tests.
Test Methods
If an assumption failure is encountered inside of a TestCase method with the Test attribute, the
entire method is marked as filtered, but MATLAB runs the subsequent Test methods.
The following class contains an assumption failure in one of the methods in the Test block.
Since the testB method contains an assumption failure, when you run the test, the testing
framework filters that test and marks it as incomplete. After the assumption failure in testB, the
testing framework proceeds and executes testC, which contains a verification failure.
ts = matlab.unittest.TestSuite.fromClass(?ExampleTest);
res = ts.run;
Running ExampleTest
.
================================================================================
ExampleTest/testB was filtered.
Details
================================================================================
.
================================================================================
Verification failed in ExampleTest/testC.
---------------------
Framework Diagnostic:
---------------------
verifyFalse failed.
--> The value must evaluate to "false".
36-151
36 Unit Testing
Actual logical:
1
------------------
Stack Information:
------------------
In C:\work\ExampleTest.m (ExampleTest.testC) at 11
================================================================================
.
Done ExampleTest
__________
Failure Summary:
If you examine the TestResult, you notice that there is a passed test, a failed test, and a test that
did not complete due to an assumption failure.
res
res =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
1 Passed, 1 Failed, 1 Incomplete.
2.4807 seconds testing time.
The testing framework keeps track of incomplete tests so that you can monitor filtered tests for
nonexercised test code. You can see information about these tests within the TestResult object.
res([res.Incomplete])
ans =
Name: 'ExampleTest/testB'
Passed: 0
Failed: 0
Incomplete: 1
Duration: 2.2578
Details: [1×1 struct]
Totals:
0 Passed, 0 Failed, 1 Incomplete.
2.2578 seconds testing time.
To create a modified test suite from only the filtered tests, select incomplete tests from the original
test suite.
36-152
Dynamically Filtered Tests
tsFiltered = ts([res.Incomplete])
tsFiltered =
Tests Include:
0 Parameterizations, 0 Shared Test Fixture Classes, 0 Tags.
One of the methods in the following TestMethodSetup block within ExampleTest.m contains an
assumption failure.
methods(TestMethodSetup)
function setupMethod1(testCase)
testCase.assumeEqual(1,0)
% remaining test code is not exercised
end
function setupMethod2(testCase)
disp('* Running setupMethod2 *')
testCase.assertEqual(1,1)
end
end
methods(Test)
function testA(testCase)
testCase.verifyTrue(true)
end
function testB(testCase)
36-153
36 Unit Testing
testCase.assumeEqual(0,1)
% remaining test code is not exercised
end
function testC(testCase)
testCase.verifyFalse(true)
end
end
end
When you run the test, you see that the framework completes executes all the methods in the
TestMethodSetup block that do not contain the assumption failure, and it marks as incomplete all
methods in the Test block.
ts = matlab.unittest.TestSuite.fromClass(?ExampleTest);
res = ts.run;
Running ExampleTest
================================================================================
ExampleTest/testA was filtered.
Details
================================================================================
* Running setupMethod2 *
.
================================================================================
ExampleTest/testB was filtered.
Details
================================================================================
* Running setupMethod2 *
.
================================================================================
ExampleTest/testC was filtered.
Details
================================================================================
* Running setupMethod2 *
.
Done ExampleTest
__________
Failure Summary:
The Test methods did not change but all 3 are filtered due to an assumption failure in the
TestMethodSetup block. The testing framework executes methods in the TestMethodSetup block
without assumption failures, such as setupMethod2. As expected, the testing framework executes
setupMethod2 3 times, once before each Test method.
methods(TestClassSetup)
function setupClass(testCase)
testCase.assumeEqual(1,0)
% remaining test code is not exercised
36-154
Dynamically Filtered Tests
end
end
methods(TestMethodSetup)
function setupMethod1(testCase)
testCase.assumeEqual(1,0)
% remaining test code is not exercised
end
function setupMethod2(testCase)
disp('* Running setupMethod2 *')
testCase.assertEqual(1,1)
end
end
methods(Test)
function testA(testCase)
testCase.verifyTrue(true)
end
function testB(testCase)
testCase.assumeEqual(0,1)
% remaining test code is not exercised
end
function testC(testCase)
testCase.verifyFalse(true)
end
end
end
When you run the test, you see that the framework does not execute any of the methods in the
TestMethodSetup or Test.
ts = matlab.unittest.TestSuite.fromClass(?ExampleTest);
res = ts.run;
Running ExampleTest
================================================================================
All tests in ExampleTest were filtered.
Details
================================================================================
Done ExampleTest
__________
Failure Summary:
36-155
36 Unit Testing
----------------------------------------------------------------
ExampleTest/testC X Filtered by assumption.
The Test and TestMethodSetup methods did not change but everything is filtered due to an
assumption failure in the TestClassSetup block.
See Also
matlab.unittest.qualifications.Assumable | matlab.unittest.TestCase |
matlab.unittest.TestResult
36-156
Create Custom Constraint
In a file in your current folder, create a class named IsSameSizeAs that derives from the
matlab.unittest.constraints.Constraint class. The class constructor accepts an expected
value whose size is compared to the size of an actual value. The expected value is stored in the
ValueWithExpectedSize property. The recommended practice is to make Constraint
implementations immutable, so set the property SetAccess attribute to immutable.
methods
function constraint = IsSameSizeAs(value)
constraint.ValueWithExpectedSize = value;
end
end
end
In a methods block with private access, define a helper method sizeMatchesExpected that
determines if the actual and expected values are the same size. This method is invoked by other
constraint methods.
methods (Access=private)
function tf = sizeMatchesExpected(constraint,actual)
tf = isequal(size(actual), ...
size(constraint.ValueWithExpectedSize));
end
end
methods
function tf = satisfiedBy(constraint,actual)
tf = constraint.sizeMatchesExpected(actual);
end
end
methods
function diagnostic = getDiagnosticFor(constraint,actual)
import matlab.automation.diagnostics.StringDiagnostic
if constraint.sizeMatchesExpected(actual)
diagnostic = StringDiagnostic("IsSameSizeAs passed.");
else
36-157
36 Unit Testing
methods
function constraint = IsSameSizeAs(value)
constraint.ValueWithExpectedSize = value;
end
function tf = satisfiedBy(constraint,actual)
tf = constraint.sizeMatchesExpected(actual);
end
methods (Access=private)
function tf = sizeMatchesExpected(constraint,actual)
tf = isequal(size(actual), ...
size(constraint.ValueWithExpectedSize));
end
end
end
Verification passed.
36-158
Create Custom Constraint
Verification failed.
---------------------
Framework Diagnostic:
---------------------
IsSameSizeAs failed.
Actual Size: [5 5]
ExpectedSize: [1 5]
See Also
Classes
matlab.unittest.constraints.Constraint |
matlab.unittest.constraints.BooleanConstraint |
matlab.automation.diagnostics.StringDiagnostic |
matlab.automation.diagnostics.Diagnostic
Related Examples
• “Create Custom Boolean Constraint” on page 36-160
36-159
36 Unit Testing
In a file in your current folder, create a class named IsSameSizeAs that derives from the
matlab.unittest.constraints.BooleanConstraint class. The class constructor accepts an
expected value whose size is compared to the size of an actual value. The expected value is stored in
the ValueWithExpectedSize property. The recommended practice is to make
BooleanConstraint implementations immutable, so set the property SetAccess attribute to
immutable.
classdef IsSameSizeAs < matlab.unittest.constraints.BooleanConstraint
properties (SetAccess=immutable)
ValueWithExpectedSize
end
methods
function constraint = IsSameSizeAs(value)
constraint.ValueWithExpectedSize = value;
end
end
end
In a methods block with private access, define a helper method sizeMatchesExpected that
determines if the actual and expected values are the same size. This method is invoked by other
constraint methods.
methods (Access=private)
function tf = sizeMatchesExpected(constraint,actual)
tf = isequal(size(actual), ...
size(constraint.ValueWithExpectedSize));
end
end
methods
function tf = satisfiedBy(constraint,actual)
tf = constraint.sizeMatchesExpected(actual);
end
36-160
Create Custom Boolean Constraint
+ "]");
end
end
end
In exchange for implementing the required methods, the constraint inherits the appropriate and, or,
and not overloads, so it can be combined with other BooleanConstraint objects or negated.
methods
function constraint = IsSameSizeAs(value)
constraint.ValueWithExpectedSize = value;
end
function tf = satisfiedBy(constraint,actual)
tf = constraint.sizeMatchesExpected(actual);
end
methods (Access=protected)
function diagnostic = getNegativeDiagnosticFor(constraint,actual)
import matlab.automation.diagnostics.StringDiagnostic
if constraint.sizeMatchesExpected(actual)
diagnostic = StringDiagnostic( ...
"Negated IsSameSizeAs failed." + newline + ...
"Actual and expected sizes were the same ([" ...
+ int2str(size(actual)) + ...
"]) but should not have been.");
36-161
36 Unit Testing
else
diagnostic = StringDiagnostic( ...
"Negated IsSameSizeAs passed.");
end
end
end
methods (Access=private)
function tf = sizeMatchesExpected(constraint,actual)
tf = isequal(size(actual), ...
size(constraint.ValueWithExpectedSize));
end
end
end
Test a passing case. The test passes because one of the or conditions, HasLength(5), is true.
testCase.verifyThat(zeros(5),HasLength(5) | ~IsSameSizeAs(repmat(1,5)))
Verification passed.
Test a failing case. The test fails because one of the and conditions,
~IsSameSizeAs(repmat(1,5)), is false.
testCase.verifyThat(zeros(5),HasLength(5) & ~IsSameSizeAs(repmat(1,5)))
Verification failed.
---------------------
Framework Diagnostic:
---------------------
AndConstraint failed.
--> + [First Condition]:
| HasLength passed.
|
| Actual Value:
| 0 0 0 0 0
| 0 0 0 0 0
| 0 0 0 0 0
| 0 0 0 0 0
| 0 0 0 0 0
| Expected Length:
| 5
--> AND
+ [Second Condition]:
| Negated ISameSizeAs failed.
| Actual and expected sizes were the same ([5 5]) but should not have been.
-+---------------------
See Also
Classes
matlab.unittest.constraints.BooleanConstraint |
matlab.unittest.constraints.Constraint |
36-162
Create Custom Boolean Constraint
matlab.automation.diagnostics.StringDiagnostic |
matlab.automation.diagnostics.Diagnostic
Related Examples
• “Create Custom Constraint” on page 36-157
36-163
36 Unit Testing
App Testing
Test Creation – Class-based tests can use the app testing framework by subclassing
matlab.uitest.TestCase. Because matlab.uitest.TestCase is a subclass of
matlab.unittest.TestCase, your test has access to the features of the unit testing framework,
such as qualifications, fixtures, and plugins. To experiment with the app testing framework at the
command prompt, create a test case instance using
matlab.uitest.TestCase.forInteractiveUse.
Test Content – Typically, a test of an app programmatically interacts with app components using a
gesture method of matlab.uitest.TestCase, such as press or type, and then performs a
qualification on the result. For example, a test might press one check box and verify that the other
check boxes are disabled. Or it might type a number into a text box and verify that the app computes
the expected result. These types of tests require understanding of the properties of the app being
tested. To verify a button press, you must know where in the app object MATLAB stores the status of
a button. To verify the result of a computation, you must know how to access the result within the
app.
Test Cleanup – It is a best practice to include a teardown action to delete the app after the test.
Typically, the test method adds this action using the addTeardown method of
matlab.unittest.TestCase.
App Locking – When an app test creates a figure, the framework locks the figure immediately to
prevent external interactions with the components. The app testing framework does not lock UI
components if you create an instance of matlab.uitest.TestCase.forInteractiveUse for
experimentation at the command prompt.
Dialog Box Interaction – Some apps display modal dialog boxes, preventing interaction with other
app components. To access the figure behind a modal dialog box, you must first select an option in
the dialog box or dismiss the dialog box. To programmatically interact with a dialog box in the figure
window, use the chooseDialog or dismissDialog method.
36-164
Overview of App Testing Framework
Button uibutto ✔ ✔
n
Button uibutto ✔
Group ngroup
Check uicheck ✔ ✔ ✔
Box box
Date uidatep ✔ ✔
Picker icker
Discrete uiknob ✔ ✔
Knob
Drop uidropd ✔ ✔ ✔
Down own
Edit Field uieditf ✔ ✔
(Numeric, ield
Text)
Hyperlink uihyper ✔ ✔
link
Image uiimage ✔ ✔
Knob uiknob ✔ ✔ ✔
Label uilabel ✔
List Box uilistb ✔ ✔
ox
Menu uimenu ✔
Panel uipanel ✔ ✔ ✔
Polar polarax ✔ ✔ ✔
Axes es
Push Tool uipusht ✔
ool
Radio uiradio ✔ ✔ ✔
Button button
Slider uislide ✔ ✔ ✔
r
Spinner uispinn ✔ ✔ ✔
er
State uibutto ✔ ✔ ✔
Button n
Switch uiswitc ✔ ✔ ✔
(Rocker, h
Slider,
Toggle)
Tab uitab ✔
Tab uitabgr ✔
Group oup
36-165
36 Unit Testing
Table uitable ✔ ✔ ✔
Text Area uitexta ✔ ✔
rea
Toggle uitoggl ✔ ✔ ✔
Button ebutton
Toggle uitoggl ✔ ✔
Tool etool
Tree uitreen ✔ ✔
Node ode
UI Axes uiaxes ✔ ✔ ✔ ✔ ✔
UI Figure uifigur ✔ ✔ ✔ ✔
e
This example shows how to write a test for an app in your current folder. The app provides options to
change the sample size and colormap of a plot. To programmatically interact with the app and qualify
the results, use the app testing framework and the unit testing framework.
To explore the properties of the app prior to testing, create an instance of the app. This step is not
necessary for the tests, but it is helpful to explore the properties used by the tests. For example, use
app.UpdatePlotButton to access the Update Plot button within the app.
app = ConfigurePlotAppExample;
36-166
Overview of App Testing Framework
In a file named ConfigurePlotAppExampleTest.m in your current folder, create a test class that
derives from matlab.uitest.TestCase. Add two Test methods to the
ConfigurePlotAppExampleTest class. In each method, create an instance of the app before
testing and delete it after the test is complete:
• testSampleSize method — Modify the sample size, update the plot, and verify that the plot uses
the specified sample size.
• testColormap method — Select a colormap, update the plot, and verify that the plot uses the
specified colormap.
testCase.type(app.SampleSizeEditField,12)
testCase.press(app.UpdatePlotButton)
ax = app.UIAxes;
surfaceObj = ax.Children;
testCase.verifySize(surfaceObj.ZData,[12 12])
end
function testColormap(testCase)
app = ConfigurePlotAppExample;
testCase.addTeardown(@delete,app)
testCase.choose(app.ColormapDropDown,"Winter")
testCase.press(app.UpdatePlotButton)
expectedMap = winter;
ax = app.UIAxes;
testCase.verifyEqual(ax.Colormap,expectedMap)
end
end
end
Running ConfigurePlotAppExampleTest
.
Done ConfigurePlotAppExampleTest
__________
results =
1×2 TestResult array with properties:
Name
Passed
Failed
Incomplete
Duration
36-167
36 Unit Testing
Details
Totals:
2 Passed, 0 Failed, 0 Incomplete.
11.9555 seconds testing time.
See Also
matlab.uitest.TestCase
More About
• “Write Tests for an App” on page 36-169
• “Write Tests That Use App Testing and Mocking Frameworks” on page 36-173
• “App Building Components”
36-168
Write Tests for an App
This example shows how to write tests for an App Designer app in your current folder. To interact
with the app programmatically and qualify the results, use the app testing framework and the unit
testing framework.
To explore the properties of the app prior to testing, create an instance of the app. This step is not
necessary for the tests, but it is helpful to explore the properties used by the tests. For example, use
app.BloodPressureSwitch to access the Blood Pressure switch within the app.
app = PatientsDisplay;
In a file named PatientsDisplayTest.m in your current folder, create a test class that derives
from matlab.uitest.TestCase. To create an app for each test and delete it after the test, add a
TestMethodSetup method to the class. Then, add four Test methods to the class:
• testTab method — Test the tab-switching functionality. Choose the Data tab and then verify that
the chosen tab has the expected title.
• testPlottingOptions method — Test various plotting options. First, press the Histogram
radio button and verify that the x-axis label changes. Then, change the Bin Width slider and
verify the number of bins.
• testBloodPressure method — Test the blood pressure data and display. First, extract the blood
pressure data from the app, and verify the y-axis label and the values of the scatter points. Then,
switch to Diastolic readings, and verify the label and the displayed values again.
• testGender method — Test the gender data and display. First, verify the number of scatter points
for data about males. Then, include the data about females, and verify that two data sets are
36-169
36 Unit Testing
plotted and that the color of the scatter points for data about females is red. Finally, exclude the
data about males, and test the number of plotted data sets and scatter points.
methods (TestMethodSetup)
function launchApp(testCase)
testCase.App = PatientsDisplay;
testCase.addTeardown(@delete,testCase.App)
end
end
methods (Test)
function testTab(testCase)
% Choose the Data tab
dataTab = testCase.App.DataTab;
testCase.choose(dataTab)
function testPlottingOptions(testCase)
% Press the Histogram radio button
testCase.press(testCase.App.HistogramButton)
function testBloodPressure(testCase)
% Extract the blood pressure data from the app
t = testCase.App.DataTab.Children.Data;
t.Gender = categorical(t.Gender);
allMales = t(t.Gender == "Male",:);
maleDiastolicData = allMales.Diastolic';
maleSystolicData = allMales.Systolic';
% Verify the y-axis label and that the male Systolic data is
% displayed
ax = testCase.App.UIAxes;
testCase.verifyEqual(ax.YLabel.String,'Systolic')
testCase.verifyEqual(ax.Children.YData,maleSystolicData)
36-170
Write Tests for an App
% Verify the y-axis label and that the male Diastolic data
% is displayed
testCase.verifyEqual(ax.YLabel.String,'Diastolic')
testCase.verifyEqual(ax.Children.YData,maleDiastolicData)
end
function testGender(testCase)
% Take a screenshot if the test fails
import matlab.unittest.diagnostics.ScreenshotDiagnostic
testCase.onFailure(ScreenshotDiagnostic)
Run the tests. In this example, three tests pass and one test fails.
results = runtests("PatientsDisplayTest");
Running PatientsDisplayTest
...
================================================================================
Verification failed in PatientsDisplayTest/testGender.
---------------------
Framework Diagnostic:
---------------------
verifyNumElements failed.
--> The value did not have the correct number of elements.
Actual Value:
Columns 1 through 13
36-171
36 Unit Testing
131 133 119 142 142 132 128 137 129 131 133 117 137
Columns 14 through 26
146 123 143 114 126 137 138 137 118 128 135 121 136
Columns 27 through 39
135 147 124 134 130 130 127 141 111 134 137 136 130
Columns 40 through 52
137 127 127 115 131 126 120 132 120 123 141 129 124
Column 53
134
----------------------
Additional Diagnostic:
----------------------
Screenshot captured to:
--> C:\Temp\b5238869-2e26-4f74-838f-83b1929c4eb1\Screenshot_ad84e34f-7587-41ca-8a97-25c484bbc
------------------
Stack Information:
------------------
In C:\work\PatientsDisplayTest.m (PatientsDisplayTest.testGender) at 85
================================================================================
.
Done PatientsDisplayTest
__________
Failure Summary:
See Also
matlab.uitest.TestCase | matlab.unittest.diagnostics.ScreenshotDiagnostic
More About
• “Overview of App Testing Framework” on page 36-164
• “Write Tests for Custom UI Component”
• “Write Tests That Use App Testing and Mocking Frameworks” on page 36-173
36-172
Write Tests That Use App Testing and Mocking Frameworks
Create App
Create the launchApp app in your current folder. The app allows a user to select an input file and
displays the name of the file in the app. The file selection dialog box is a blocking modal dialog box
that waits for user input.
To explore the properties of the app prior to testing, call the launchApp function at the command
prompt. This step is not necessary for the tests, but it is helpful to explore the properties used by the
app tests. For example, use app.Button to access the Input file button within the app.
app = launchApp;
app.Button
ans =
36-173
36 Unit Testing
testCase.press(app.Button)
36-174
Write Tests That Use App Testing and Mocking Frameworks
testCase.verifyEqual(app.Label.Text,testCase.Filename)
end
end
end
Run the test. When the file selection dialog box appears, select input.txt to allow MATLAB to
proceed with the test. Selecting any other file results in a test failure.
runtests("LaunchAppTest");
Running LaunchAppTest
.
Done LaunchAppTest
__________
Create a FileChooser service with an Abstract method that implements the file selection
functionality.
classdef FileChooser
% Interface to choose a file
methods (Abstract)
[file,folder,status] = chooseFile(chooser,varargin)
end
end
Create a default FileChooser service that uses the uigetfile function for file selection.
Change the app to accept an optional FileChooser object. When called with no inputs, the app uses
an instance of DefaultFileChooser.
f = uifigure;
button = uibutton(f,"Text","Input file");
button.ButtonPushedFcn = @(src,event) pickFile(fileChooser);
label = uilabel(f,"Text","No file selected");
label.Position(1) = button.Position(1) + button.Position(3) + 25;
label.Position(3) = 200;
36-175
36 Unit Testing
app.Button = button;
app.Label = label;
[mockChooser,behavior] = testCase.createMock(?FileChooser);
when(behavior.chooseFile("*.*"),AssignOutputs(filename,pwd,1))
app = launchApp(mockChooser);
testCase.addTeardown(@close,app.UIFigure)
testCase.press(app.Button)
testCase.verifyEqual(app.Label.Text,filename)
end
function testCancel(testCase)
import matlab.mock.actions.AssignOutputs
[mockChooser,behavior] = testCase.createMock(?FileChooser);
36-176
Write Tests That Use App Testing and Mocking Frameworks
when(behavior.chooseFile("*.*"),AssignOutputs('input.txt',pwd,0))
app = launchApp(mockChooser);
testCase.addTeardown(@close,app.UIFigure)
testCase.press(app.Button)
testCase.verifyCalled(behavior.chooseFile("*.*"))
testCase.verifyEqual(app.Label.Text,'No file selected')
end
end
end
Run the tests. The tests run to completion without manual file selection.
runtests("LaunchAppTest");
Running LaunchAppTest
..
Done LaunchAppTest
__________
See Also
Classes
matlab.mock.TestCase | matlab.uitest.TestCase
More About
• “Overview of App Testing Framework” on page 36-164
• “Write Tests for an App” on page 36-169
• “Create Mock Object” on page 36-194
36-177
36 Unit Testing
In this section...
“Determine Bounds of Measured Code” on page 36-178
“Types of Time Experiments” on page 36-179
“Write Performance Tests with Measurement Boundaries” on page 36-179
“Run Performance Tests” on page 36-180
“Understand Invalid Test Results” on page 36-180
The performance test interface leverages the script, function, and class-based unit testing interfaces.
You can perform qualifications within your performance tests to ensure correct functional behavior
while measuring code performance. Also, you can run your performance tests as standard regression
tests to ensure that code changes do not break performance tests.
36-178
Overview of Performance Testing Framework
This table summarizes the differences between the frequentist and fixed time experiments.
36-179
36 Unit Testing
The performance testing framework does not support nested measurement boundaries. If you use
these methods incorrectly in a Test method and run the test as a TimeExperiment, then the
framework marks the measurement as invalid. Also, you still can run these performance tests as unit
tests. For more information, see “Test Performance Using Classes” on page 36-186.
• Use the runperf function to run the tests. This function uses a variable number of measurements
to reach a sample mean with a 0.05 relative margin of error within a 0.95 confidence level. It runs
the tests 5 times to warm up the code and between 4 and 256 times to collect measurements that
meet the statistical objectives.
• Generate an explicit test suite using the testsuite function or the methods in the TestSuite
class, and then create and run a time experiment.
You can run your performance tests as regression tests. For more information, see “Test Performance
Using Classes” on page 36-186.
When the performance testing framework encounters an invalid test result, it behaves differently
depending on the type of time experiment:
• If you create a frequentist time experiment, then the framework stops measuring for that test and
moves to the next test.
• If you create a fixed time experiment, then the framework continues collecting the specified
number of samples.
See Also
runperf | testsuite | matlab.perftest.TimeExperiment | matlab.perftest.TimeResult |
matlab.unittest.measurement.MeasurementResult
Related Examples
• “Test Performance Using Scripts or Functions” on page 36-182
36-180
Overview of Performance Testing Framework
36-181
36 Unit Testing
Create a performance test in a file named preallocationTest.m in your current folder. In this
example, you can choose to use either the following script-based test or the function-based test. The
output in this example is for the function-based test. If you use the script-based test, then your test
names will be different.
function testForLoop(testCase)
vectorSize = getSize();
for i=1:vectorSize
x(i) = 1;
end
end
results = runperf("preallocationTest.m")
Running preallocationTest
.......... .......... .......... .......... .......
Done preallocationTest
__________
36-182
Test Performance Using Scripts or Functions
results =
Name
Valid
Samples
TestActivity
Totals:
4 Valid, 0 Invalid.
8.7168 seconds testing time.
The results variable is a 1-by-4 TimeResult array. Each element in the array corresponds to one of
the tests defined in preallocationTest.m.
Display the measurement results for the second test. Your results might vary.
results(2)
ans =
Name: 'preallocationTest/testIndexingWithVariable'
Valid: 1
Samples: [4×7 table]
TestActivity: [9×12 table]
Totals:
1 Valid, 0 Invalid.
0.87973 seconds testing time.
As indicated by the size of the TestActivity property, the performance testing framework collected
nine measurements. This number of measurements includes five measurements to warm up the code.
The Samples property excludes warm-up measurements.
ans =
4×7 table
Display the mean measured time for the second test. To exclude data collected in the warm-up runs,
use the values in the Samples property.
36-183
36 Unit Testing
sampleTimes = results(2).Samples.MeasuredTime;
meanTest2 = mean(sampleTimes)
meanTest2 =
0.0969
To compare the different preallocation methods, create a table of summary statistics from results.
In this example, the ones function was the fastest way to initialize the vector to ones. The
performance testing framework made four measurement runs for this test.
T = sampleSummary(results)
T =
4×7 table
Change the statistical objectives defined by the runperf function by constructing and running a time
experiment. Construct a time experiment that collects two warm-up measurements and runs the test
a variable number of times to reach a sample mean with a 4% relative margin of error within a 98%
confidence level.
Construct a time experiment with the specified requirements, and run the test suite.
import matlab.perftest.TimeExperiment
experiment = TimeExperiment.limitingSamplingError("NumWarmups",2, ...
"RelativeMarginOfError",0.04,"ConfidenceLevel",0.98);
resultsTE = run(experiment,suite);
Running preallocationTest
.......... .......... .......... ..........
Done preallocationTest
__________
T1 =
4×7 table
36-184
Test Performance Using Scripts or Functions
See Also
runperf | testsuite | matlab.perftest.TimeExperiment | matlab.perftest.TimeResult
Related Examples
• “Overview of Performance Testing Framework” on page 36-178
• “Test Performance Using Classes” on page 36-186
36-185
36 Unit Testing
Consider the following unit (regression) test. You can run this test as a performance test using
runperf("fprintfTest") instead of runtests("fprintfTest").
testCase.addTeardown(@delete,testCase.file);
testCase.addTeardown(@fclose,testCase.fid);
end
end
methods(Test)
function testPrintingToFile(testCase)
textToWrite = repmat('abcdef',1,5000000);
fprintf(testCase.fid,'%s',textToWrite);
testCase.verifyEqual(fileread(testCase.file),textToWrite)
end
function testBytesToFile(testCase)
textToWrite = repmat('tests_',1,5000000);
nbytes = fprintf(testCase.fid,'%s',textToWrite);
testCase.verifyEqual(nbytes,length(textToWrite))
end
end
end
The measured time does not include the time to open and close the file or the assertion because these
activities take place inside a TestMethodSetup block, and not inside a Test block. However, the
measured time includes the time to perform the verifications. Best practice is to measure a more
accurate performance boundary.
Create a performance test in a file named fprintfTest.m in your current folder. This test is similar
to the regression test with the following modifications:
36-186
Test Performance Using Classes
fid
end
methods(TestMethodSetup)
function openFile(testCase)
testCase.file = tempname;
testCase.fid = fopen(testCase.file,'w');
testCase.assertNotEqual(testCase.fid,-1,'IO Problem')
testCase.addTeardown(@delete,testCase.file);
testCase.addTeardown(@fclose,testCase.fid);
end
end
methods(Test)
function testPrintingToFile(testCase)
textToWrite = repmat('abcdef',1,5000000);
testCase.startMeasuring();
fprintf(testCase.fid,'%s',textToWrite);
testCase.stopMeasuring();
testCase.verifyEqual(fileread(testCase.file),textToWrite)
end
function testBytesToFile(testCase)
textToWrite = repmat('tests_',1,5000000);
testCase.startMeasuring();
nbytes = fprintf(testCase.fid,'%s',textToWrite);
testCase.stopMeasuring();
testCase.verifyEqual(nbytes,length(textToWrite))
end
end
end
The measured time for this performance test includes only the call to fprintf, and the testing
framework still evaluates the qualifications.
Run the performance test. Depending on your system, you might see warnings that the performance
testing framework ran the test the maximum number of times but did not achieve a 0.05 relative
margin of error within a 0.95 confidence level.
results = runperf("fprintfTest")
Running fprintfTest
.......... .......... ...
Done fprintfTest
__________
results =
Name
36-187
36 Unit Testing
Valid
Samples
TestActivity
Totals:
2 Valid, 0 Invalid.
3.6789 seconds testing time.
The results variable is a 1-by-2 TimeResult array. Each element in the array corresponds to one of
the tests defined in the test file.
Display the measurement results for the first test. Your results might vary.
results(1)
ans =
Name: 'fprintfTest/testPrintingToFile'
Valid: 1
Samples: [4×7 table]
TestActivity: [9×12 table]
Totals:
1 Valid, 0 Invalid.
2.7009 seconds testing time.
As indicated by the size of the TestActivity property, the performance testing framework collected
nine measurements. This number includes five measurements to warm up the code. The Samples
property excludes warm-up measurements.
results(1).Samples
ans =
4×7 table
Display the mean measured time for the first test. To exclude data collected in the warm-up runs, use
the values in the Samples property.
sampleTimes = results(1).Samples.MeasuredTime;
meanTest = mean(sampleTimes)
36-188
Test Performance Using Classes
meanTest =
0.0418
To compare the different calls to fprintf, create a table of summary statistics from results. In this
example, both test methods write the same amount of data to a file. Therefore, some of the difference
between the statistical values is attributed to calling the fprintf function with an output argument.
T = sampleSummary(results)
T =
2×7 table
Change the statistical objectives defined by the runperf function by constructing and running a time
experiment. Construct a time experiment with measurements that reach a sample mean with a 2%
relative margin of error within a 98% confidence level. Collect 4 warm-up measurements and up to 16
sample measurements.
suite = testsuite("fprintfTest");
Construct a time experiment with the specified requirements, and run the tests. In this example, the
performance testing framework is not able to meet the stricter statistical objectives with the specified
number of maximum samples. Your results might vary.
import matlab.perftest.TimeExperiment
experiment = TimeExperiment.limitingSamplingError("NumWarmups",4, ...
"MaxSamples",16,"RelativeMarginOfError",0.02,"ConfidenceLevel",0.98);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... .......... ........Warning: Target Relative Margin of Error not met after running the
Done fprintfTest
__________
Increase the maximum number of samples to 32 and rerun the time experiment.
experiment = TimeExperiment.limitingSamplingError("NumWarmups",4, ...
"MaxSamples",32,"RelativeMarginOfError",0.02,"ConfidenceLevel",0.98);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... .......... .......... .
Done fprintfTest
__________
36-189
36 Unit Testing
T1 = sampleSummary(resultsTE)
T1 =
2×7 table
Start a new MATLAB session. A new session ensures that MATLAB has not run the code contained in
your tests.
Measure the first-time cost of your code by creating and running a fixed time experiment with zero
warm-up measurements and one sample measurement.
Create a test suite. Because you are measuring the first-time cost of a function, run a single test. To
run multiple tests, save the results and start a new MATLAB session between tests.
suite = testsuite("fprintfTest/testPrintingToFile");
import matlab.perftest.TimeExperiment
experiment = TimeExperiment.withFixedSampleSize(1);
results = run(experiment,suite);
Running fprintfTest
.
Done fprintfTest
__________
Display the results. The TestActivity table shows that there were no warm-up measurements.
fullTable = results.TestActivity
fullTable =
1×12 table
See Also
runperf | testsuite | matlab.perftest.TimeExperiment | matlab.perftest.TestCase |
matlab.perftest.TimeResult
Related Examples
• “Overview of Performance Testing Framework” on page 36-178
• “Test Performance Using Scripts or Functions” on page 36-182
36-190
Measure Fast Executing Test Code
In your current working folder, create a class-based test, PreallocationTest.m, that compares
different methods of preallocation. Since the test methods include qualifications, use the
startMeasuring and stopMeasuring methods to define boundaries for the code you want to
measure.
classdef PreallocationTest < matlab.perftest.TestCase
methods(Test)
function testOnes(testCase)
testCase.startMeasuring
x = ones(1,1e5);
testCase.stopMeasuring
testCase.verifyEqual(size(x),[1 1e5])
end
function testIndexingWithVariable(testCase)
import matlab.unittest.constraints.IsSameSetAs
testCase.startMeasuring
id = 1:1e5;
x(id) = 1;
testCase.stopMeasuring
testCase.verifyThat(x,IsSameSetAs(1))
end
function testIndexingOnLHS(testCase)
import matlab.unittest.constraints.EveryElementOf
import matlab.unittest.constraints.IsEqualTo
testCase.startMeasuring
x(1:1e5) = 1;
testCase.stopMeasuring
testCase.verifyThat(EveryElementOf(x),IsEqualTo(1))
end
function testForLoop(testCase)
testCase.startMeasuring
for i=1:1e5
x(i) = 1;
end
testCase.stopMeasuring
testCase.verifyNumElements(x,1e5)
end
end
end
Run PreallocationTest as a performance test. Two tests are filtered because the measurements
are too close to the precision of the framework.
results = runperf('PreallocationTest');
Running PreallocationTest
........
================================================================================
36-191
36 Unit Testing
Failure Summary:
To instruct the framework to automatically loop through the measured code and average the
measurement results, modify PreallocationTest to use a keepMeasuring-while loop instead of
startMeasuring and stopMeasuring.
function testIndexingWithVariable(testCase)
import matlab.unittest.constraints.IsSameSetAs
while(testCase.keepMeasuring)
id = 1:1e5;
x(id) = 1;
end
testCase.verifyThat(x,IsSameSetAs(1))
end
function testIndexingOnLHS(testCase)
import matlab.unittest.constraints.EveryElementOf
import matlab.unittest.constraints.IsEqualTo
while(testCase.keepMeasuring)
x(1:1e5) = 1;
end
testCase.verifyThat(EveryElementOf(x),IsEqualTo(1))
end
function testForLoop(testCase)
while(testCase.keepMeasuring)
for i=1:1e5
x(i) = 1;
end
end
testCase.verifyNumElements(x,1e5)
end
end
end
36-192
Measure Fast Executing Test Code
results = runperf('PreallocationTest');
Running PreallocationTest
.......... .......... .......... ..
Done PreallocationTest
__________
sampleSummary(results)
ans =
4×7 table
See Also
runperf | keepMeasuring
Related Examples
• “Overview of Performance Testing Framework” on page 36-178
• “Test Performance Using Classes” on page 36-186
36-193
36 Unit Testing
For example, suppose you want to test an algorithm for buying stock, but you do not want to test the
entire system. You could use a mock object to replace the functionality of looking up the stock price,
and another mock object to verify that the trader purchased the stock. The algorithm you are testing
does not know that it is operating on mock objects, and you can test the algorithm isolated from the
rest of the system.
Using a mock object, you can define behavior (a process known as stubbing). For example, you can
specify that an object produces predefined responses to queries. You can also intercept and
remember messages sent from the component under test to the mock object (a process known as
spying). For example, you can verify that a particular method was called or a property was set.
36-194
Create Mock Object
4 Qualify interactions between the component of interest and the mocked components. For
example, verify that a mocked method was called with particular inputs, or that a property was
set.
Depended on Components
In this example, the component under test is a simple day-trading algorithm. It is the part of the
system you want to test independent of other components. The day-trading algorithm has two
dependencies: a data service to retrieve the stock price data and a broker to purchase the stock.
In a file DataService.m in your current working folder, create an abstract class that includes a
lookupPrice method.
classdef DataService
methods (Abstract,Static)
price = lookupPrice(ticker,date)
end
end
In production code, there could be several concrete implementations of the DataService class, such
as a BloombergDataService class. This class uses the Datafeed Toolbox™. However, since we
create a mock of the DataService class, you do not need to have the toolbox installed to run the
tests for the trading algorithm.
classdef BloombergDataService < DataService
methods (Static)
function price = lookupPrice(ticker,date)
% This method assumes you have installed and configured the
% Bloomberg software.
conn = blp;
data = history(conn,ticker,'LAST_PRICE',date-1,date);
price = data(end);
close(conn)
end
end
end
In this example, assume that the broker component has not been developed yet. Once it is
implemented, it will have a buy method that accepts a ticker symbol and a specified number of shares
to buy, and returns a status code. The mock for the broker component uses an implicit interface, and
does not derive from a superclass.
In a file trader.m in your current working folder, create a simple day trading algorithm. The trader
function accepts as inputs a data service object that looks up the price of the stock, a broker object
that defines how the stock is bought, a ticker symbol, and a number of shares to purchase. If the
price from yesterday is less than the price two days ago, instruct the broker to buy the specified
number of shares.
function trader(dataService,broker,ticker,numShares)
yesterday = datetime('yesterday');
priceYesterday = dataService.lookupPrice(ticker,yesterday);
price2DaysAgo = dataService.lookupPrice(ticker,yesterday-days(1));
36-195
36 Unit Testing
end
end
The mock object is an implementation of the abstract methods and properties of the interface
specified by a superclass. You can also construct a mock without a superclass, in which case the mock
has an implicit interface. The component under test interacts with the mock object, for example, by
calling a mock object method or accessing a mock object property. The mock object carries out
predefined actions in response to these interactions.
When you create a mock, you also create an associated behavior object. The behavior object defines
the same methods as the mock object and controls mock behavior. Use the behavior object to define
mock actions and qualify interactions. For example, use it to define values a mocked method returns,
or verify that a property was accessed.
At the command prompt, create a mock test case for interactive use. Using the mock in a test class
instead of at the command prompt is presented later in this example.
import matlab.mock.TestCase
testCase = TestCase.forInteractiveUse;
Create a mock for the data service dependency and examine the methods on it. The data service
mock returns predefined values, replacing the implementation of the service that provides actual
stock prices. Therefore, it exhibits stubbing behavior.
[stubDataService,dataServiceBehavior] = createMock(testCase,?DataService);
methods(stubDataService)
Static methods:
lookupPrice
In the DataService class, the lookupPrice method is abstract and static. The mocking framework
implements this method as concrete and static.
Define behavior for the data service mock. For ticker symbol "FOO", it returns the price yesterday as
$123 and anything before yesterday is $234. Therefore, according to the trader function, the broker
always buys stock "FOO". For the ticker symbol "BAR", it returns the price yesterday as $765 and
anything before yesterday is $543. Therefore, the broker never buys stock "BAR".
import matlab.unittest.constraints.IsLessThan
yesterday = datetime('yesterday');
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"FOO",yesterday),123);
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"FOO",IsLessThan(yesterday)),234);
36-196
Create Mock Object
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"BAR",yesterday),765);
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"BAR",IsLessThan(yesterday)),543);
p1 = stubDataService.lookupPrice("FOO",yesterday)
p2 = stubDataService.lookupPrice("BAR",yesterday-days(5))
p1 =
123
p2 =
543
Create a mock for the broker dependency and examine the methods on it. Since the broker mock is
used to verify interactions with the component under test (the trader function), it exhibits spying
behavior. The broker mock has an implicit interface. While the buy method is not currently
implemented, you can create a mock with it.
[spyBroker,brokerBehavior] = createMock(testCase,'AddedMethods',{'buy'});
methods(spyBroker)
buy
s1 = spyBroker.buy
s2 = spyBroker.buy("inputs",[13 42])
s1 =
[]
s2 =
[]
36-197
36 Unit Testing
Since the trader function does not use the status return code, the default mock behavior of
returning empty is acceptable. The broker mock is a pure spy, and does not need to implement any
stubbing behavior.
Call the trader function. In addition to the ticker symbol and the number of shares to buy, the
trader function takes as inputs the data service and the broker. Instead of passing in actual data
service and broker objects, pass in the spyBroker and stubDataService mocks.
trader(stubDataService,spyBroker,"FOO",100)
trader(stubDataService,spyBroker,"FOO",75)
trader(stubDataService,spyBroker,"BAR",100)
Use the broker behavior object (the spy) to verify that the trader function calls the buy method, as
expected.
Use the TestCase.verifyCalled method to verify that the trader function instructed the buy
method to buy 100 shares of the FOO stock.
import matlab.mock.constraints.WasCalled;
testCase.verifyCalled(brokerBehavior.buy("FOO",100))
Verification passed.
Verify that FOO stock was purchased two times, regardless of the specified number of shares. While
the verifyCalled method is convenient to specify behavior, there is more functionality if you use
the WasCalled constraint. For example, you can verify that a mocked method was called a specified
number of times.
import matlab.unittest.constraints.IsAnything
testCase.verifyThat(brokerBehavior.buy("FOO",IsAnything), ...
WasCalled('WithCount',2))
Verification passed.
Verify that the buy method was not called requesting 100 shares of the BAR stock.
testCase.verifyNotCalled(brokerBehavior.buy("BAR",100))
Verification passed.
Although the trader function was called requesting 100 shares of BAR stock, the stub defined
yesterday's price for BAR to return a higher value than all days prior to yesterday. Therefore, the
broker never buys stock "BAR".
The interactive test case is convenient to experiment with at the command prompt. However, it is
typical to create and use mocks within a test class. In a file in your current working folder, create the
following test class that incorporates the interactive testing from this example.
classdef TraderTest < matlab.mock.TestCase
methods(Test)
function buysStockWhenDrops(testCase)
import matlab.unittest.constraints.IsLessThan
36-198
Create Mock Object
import matlab.unittest.constraints.IsAnything
import matlab.mock.constraints.WasCalled
yesterday = datetime('yesterday');
% Create mocks
[stubDataService,dataServiceBehavior] = createMock(testCase,...
?DataService);
[spyBroker,brokerBehavior] = createMock(testCase,...
'AddedMethods',{'buy'});
% Set up behavior
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"FOO",yesterday),123);
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"FOO",IsLessThan(yesterday)),234);
% Verify interactions
testCase.verifyCalled(brokerBehavior.buy("FOO",100))
testCase.verifyThat(brokerBehavior.buy("FOO",IsAnything),...
WasCalled('WithCount',2))
end
function doesNotBuyStockWhenIncreases(testCase)
import matlab.unittest.constraints.IsLessThan
yesterday = datetime('yesterday');
% Create mocks
[stubDataService,dataServiceBehavior] = createMock(testCase,...
?DataService);
[spyBroker,brokerBehavior] = createMock(testCase, ...
'AddedMethods',{'buy'});
% Set up behavior
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"BAR",yesterday),765);
testCase.assignOutputsWhen(dataServiceBehavior.lookupPrice(...
"BAR",IsLessThan(yesterday)),543);
% Verify interactions
testCase.verifyNotCalled(brokerBehavior.buy("BAR",100))
end
end
end
results = runtests('TraderTest');
table(results)
Running TraderTest
..
Done TraderTest
36-199
36 Unit Testing
__________
ans =
2×6 table
See Also
Classes
matlab.mock.TestCase
Related Examples
• “Specify Mock Object Behavior” on page 36-201
• “Qualify Mock Object Interaction” on page 36-206
• “Write Tests That Use App Testing and Mocking Frameworks” on page 36-173
36-200
Specify Mock Object Behavior
When you create a mock, you create an associated behavior object that controls mock behavior. Use
this object to define mock method and property behavior (stub). For more information on creating a
mock, see “Create Mock Object” on page 36-194.
The mock object is an implementation of the abstract methods and properties of the interface
specified by a superclass. You can also construct a mock without a superclass, in which case the mock
has an implicit interface.
Create a mock with an implicit interface. The interface includes Name and ID properties and a
findUser method that accepts an identifier and returns a name. While the interface is not currently
implemented, you can create a mock with it.
testCase = matlab.mock.TestCase.forInteractiveUse;
[mock,behaviorObj] = testCase.createMock('AddedProperties', ...
{'Name','ID'},'AddedMethods',{'findUser'});
Specify that when the findUser method is called with any inputs, it returns "Unknown". By default,
MATLAB returns an empty array when you call the findUser method.
• The assignOutputsWhen method defines return values for the method call.
• The mocked method call (behaviorObj.findUser) implicitly creates a MethodCallBehavior
object.
• The withAnyInputs method of the MethodCallBehavior object specifies that the behavior
applies to a method call with any number of inputs with any value.
testCase.assignOutputsWhen(withAnyInputs(behaviorObj.findUser),"Unknown")
n = mock.findUser(1)
n =
"Unknown"
Specify that when the input value is 1701, the mock method returns "Jim". This behavior supersedes
the return of "Unknown" for the input value of 1701 only because it was defined after that
specification.
testCase.assignOutputsWhen(behaviorObj.findUser(1701),"Jim")
n = mock.findUser(1701)
36-201
36 Unit Testing
n =
"Jim"
Specify that when the findUser method is called with only the object as input, the mock method
returns "Unspecified ID". The withExactInputs method of the MethodCallBehavior object
specifies that the behavior applies to a method call with the object as the only input value.
testCase.assignOutputsWhen(withExactInputs(behaviorObj.findUser), ...
"Unspecified ID")
n = mock.findUser % equivalent to n = findUser(mock)
n =
"Unspecified ID"
You can use classes in the matlab.unittest.constraints namespace to help define behavior.
Specify that findUser throws an exception when it is called with an ID greater than 5000.
import matlab.unittest.constraints.IsGreaterThan
testCase.throwExceptionWhen(behaviorObj.findUser(IsGreaterThan(5000)));
n = mock.findUser(5001)
Error using
matlab.mock.internal.MockContext/createMockObject/mockMethodCallback (line 323)
The following method call was specified to throw an exception:
findUser([1×1 matlab.mock.classes.Mock], 5001)
You can define behavior based on the number of outputs requested in a method call. If the method
call requests two output values, return "??" for the name and -1 for the ID.
testCase.assignOutputsWhen(withNargout(2, ...
withAnyInputs(behaviorObj.findUser)),"??",-1)
[n,id] = mock.findUser(13)
n =
"??"
id =
-1
When defining mock property behavior, keep in mind that displaying a property value in the command
window is a property access (get) operation.
Similar to defining mock method behavior, defining mock property behavior requires an instance of
the PropertyBehavior class. The framework returns an instance of this class when you access a
mock property. To define access behavior, use an instance of PropertyGetBehavior by calling the
get method of the PropertyBehavior class. To define set behavior, use an instance of the
36-202
Specify Mock Object Behavior
Specify that when the Name property is set to any value, the testing framework throws an exception.
• The throwExceptionWhen method instructs the framework to throw an exception for a specified
behavior.
• Accessing a property on the behavior object PropertyBehavior class (behaviorObj.Name)
creates a PropertyBehavior class instance.
• The call to the set method of the PropertyBehavior class creates a PropertySetBehavior.
testCase.throwExceptionWhen(set(behaviorObj.Name))
mock.Name = "Sue";
Allow the mock to store the value when the property is set to "David".
testCase.storeValueWhen(setToValue(behaviorObj.Name,"David"));
mock.Name = "David"
mock =
Name: "David"
ID: []
Assign the value of 1138 to the ID property and then throw an exception for property access.
import matlab.mock.actions.AssignOutputs
import matlab.mock.actions.ThrowException
when(get(behaviorObj.ID),then(AssignOutputs(1138),ThrowException))
id = mock.ID
id = mock.ID
id =
1138
Assign the value of 1138 and then 237 to the ID property. Then, throw an exception for property
access. Each call to the then method accepts up to two actions. To specify more subsequent actions,
use multiple calls to then.
36-203
36 Unit Testing
when(get(behaviorObj.ID),then(AssignOutputs(1138), ...
then(AssignOutputs(237),ThrowException)))
id = mock.ID
id = mock.ID
id = mock.ID
id =
1138
id =
237
If the object is the only input value, specify the findUser function return the value of "Phil" twice.
when(withExactInputs(behaviorObj.findUser),repeat(2,AssignOutputs("Phil")))
n = mock.findUser
n = mock.findUser
n =
"Phil"
n =
"Phil"
Call the function a third time. If you repeat an action, and do not follow it with a call to the then
method, the mock continues to return the repeated value.
n = mock.findUser
n =
"Phil"
Define behavior for setting the value of Name. Throw an exception the first two times and then store
the value.
import matlab.mock.actions.StoreValue
when(set(behaviorObj.Name),then(repeat(2,ThrowException),StoreValue))
mock.Name = "John"
mock.Name = "Penny"
36-204
Specify Mock Object Behavior
mock.Name = "Tommy"
mock =
Name: "Tommy"
Summary of Behaviors
Behavior TestCase Method matlab.mock.Actions Class
(Allows for Definition of
Repeat and Subsequent
Behavior)
Return specified values for assignOutputsWhen AssignOutputs
method call and property
access.
Return stored value when returnStoredValueWhen ReturnStoredValue
property is accessed.
Store value when property is storeValueWhen StoreValue
set.
Throw exception when method throwExceptionWhen ThrowException
is called or when property is set
or accessed.
See Also
Classes
matlab.mock.TestCase | matlab.mock.actions.AssignOutputs |
matlab.mock.actions.DoNothing | matlab.mock.actions.Invoke |
matlab.mock.actions.ReturnStoredValue | matlab.mock.actions.StoreValue |
matlab.mock.actions.ThrowException
Related Examples
• “Create Mock Object” on page 36-194
• “Qualify Mock Object Interaction” on page 36-206
• “Write Tests That Use App Testing and Mocking Frameworks” on page 36-173
36-205
36 Unit Testing
In the mocking framework, qualifications are functions used to test interactions with the object.
There are four types of qualifications:
• Verifications — Produce and record failures without throwing an exception. Since verifications do
not throw exceptions, all test content runs to completion even when verification failures occur.
Typically verifications are the primary qualifications for a unit test since they typically do not
require an early exit from the test. Use other qualification types to test for violation of
preconditions or incorrect test setup.
• Assumptions — Ensure that the test environment meets preconditions that otherwise do not result
in a test failure. Assumption failures result in filtered tests, and the testing framework marks the
tests as Incomplete.
• Assertions — Ensure that a failure condition invalidates the remainder of the current test content,
but does not prevent proper execution of subsequent test methods. A failure at the assertion point
marks the current test method as failed and incomplete.
• Fatal Assertions — Abort the test session upon failure. These qualifications are useful when the
failure mode is so fundamental that there is no point in continuing testing. These qualifications are
also useful when fixture teardown does not restore the MATLAB state correctly and it is preferable
to abort testing and start a fresh session.
The mock object is an implementation of the abstract methods and properties of the interface
specified by a superclass. You can also construct a mock without a superclass, in which case the mock
has an implicit interface. Create a mock with an implicit interface for a dice class. The interface
includes Color and NumSides properties and a roll method that accepts a number of dice and
returns a value. While the interface is not currently implemented, you can create a mock with it.
testCase = matlab.mock.TestCase.forInteractiveUse;
[mock,behaviorObj] = testCase.createMock('AddedProperties', ...
{'NumSides','Color'},'AddedMethods',{'roll'});
val = mock.roll(1);
testCase.verifyCalled(behaviorObj.roll(1))
Verify that the roll method was called with 3 dice. This test fails.
testCase.verifyCalled(behaviorObj.roll(3), ...
'roll method should have been called with input 3.')
36-206
Qualify Mock Object Interaction
----------------
Test Diagnostic:
----------------
roll method should have been called with input 3.
---------------------
Framework Diagnostic:
---------------------
verifyCalled failed.
--> Method 'roll' was not called with the specified signature.
--> Observed method call(s) with any signature:
out = roll([1×1 matlab.mock.classes.Mock], 1)
Verify that the roll method was not called with 2 dice.
testCase.verifyNotCalled(behaviorObj.roll(2))
testCase.verifyCalled(withAnyInputs(behaviorObj.roll))
Verify that the roll method was not called with 2 outputs and any inputs.
testCase.verifyNotCalled(withNargout(2,withAnyInputs(behaviorObj.roll)))
mock.Color = "red"
mock =
NumSides: []
Color: "red"
testCase.verifySet(behaviorObj.Color)
36-207
36 Unit Testing
Verify the color was accessed. This test passes because there is an implicit property access when
MATLAB displays the object.
testCase.verifyAccessed(behaviorObj.Color)
testCase.assertNotSet(behaviorObj.NumSides)
testCase = matlab.mock.TestCase.forInteractiveUse;
[mock,behaviorObj] = testCase.createMock('AddedProperties', ...
{'NumSides','Color'},'AddedMethods',{'roll'});
Roll 2 dice. Then use a constraint to verify that the roll method was called at least once with two
dice.
val = mock.roll(2);
import matlab.mock.constraints.WasCalled
testCase.verifyThat(behaviorObj.roll(2),WasCalled)
Roll one die. Then verify that the roll method was called at least twice with any inputs.
val = mock.roll(1);
testCase.verifyThat(withAnyInputs(behaviorObj.roll), ...
WasCalled('WithCount',2))
import matlab.mock.constraints.WasAccessed
testCase.verifyThat(behaviorObj.NumSides,~WasAccessed)
Set the color of the dice. Then verify the property was set once.
mock.Color = "blue";
import matlab.mock.constraints.WasSet
testCase.verifyThat(behaviorObj.Color,WasSet('WithCount',1))
36-208
Qualify Mock Object Interaction
Access the Color property. Then verify that it was not accessed exactly once. This test fails.
c = mock.Color
testCase.verifyThat(behaviorObj.Color,~WasAccessed('WithCount',1))
c =
"blue"
---------------------
Framework Diagnostic:
---------------------
Negated WasAccessed failed.
--> Property 'Color' was accessed the prohibited number of times.
Set the number of sides. Then, verify that the number of sides was set to 22.
mock.NumSides = 22;
testCase.verifyThat(behaviorObj.NumSides,WasSet('ToValue',22))
Use a constraint from the matlab.unittest.constraints namespace to assert that the number of
dice sides isn't set to more than 20. This test fails.
import matlab.unittest.constraints.IsLessThanOrEqualTo
testCase.verifyThat(behaviorObj.NumSides, ...
WasSet('ToValue',IsLessThanOrEqualTo(20)))
---------------------
Framework Diagnostic:
---------------------
WasSet failed.
--> Property 'NumSides' was not set to the specified value.
--> Observed property set(s) to any value:
<Mock>.NumSides = 22
36-209
36 Unit Testing
PropertySetBehavior
<Mock>.NumSides = <IsLessThanOrEqualTo constraint>
Summary of Qualifications
Type of TestCase Method matlab.mock.constraints Class
Qualification Use With
matlab.unittest.TestCas matlab.mock.constra
e Method ints Class
Method was verifyCalled or verifyThat WasCalled or
called verifyNotCalled Occurred
assumeCalled or assumeThat
assumeNotCalled
assertCalled or assertThat
assertNotCalled
fatalAssertCalled fatalAssertThat
or
fatalAssertNotCal
led
Method was Not applicable verifyThat, assumeThat, WasCalled
called a certain assertThat, or
number of times fatalAssertThat
Property was verifyAccessed or verifyThat WasAccessed or
accessed verifyNotAccessed Occurred
assumeAccessed or assumeThat
assumeNotAccessed
assertAccessed or assertThat
assertNotAccessed
fatalAssertAccess fatalAssertThat
ed or
fatalAssertNotAcc
essed
Property was Not applicable verifyThat, assumeThat, WasAccessed
accessed a assertThat, or
certain number fatalAssertThat
of times
Property was set verifySet or verifyThat WasSet or Occurred
verifyNotSet
assumeSet or assumeThat
assumeNotSet
assertSet or assertThat
assertNotSet
fatalAssertSet or fatalAssertThat
fatalAssertNotSet
36-210
Qualify Mock Object Interaction
See Also
Classes
matlab.mock.TestCase
Related Examples
• “Create Mock Object” on page 36-194
• “Specify Mock Object Behavior” on page 36-201
• “Write Tests That Use App Testing and Mocking Frameworks” on page 36-173
36-211
36 Unit Testing
• Script-based unit tests: Write each unit test as a separate section of a test script file. You can
perform basic qualifications, access the diagnostics that the framework records on test results,
refine the test suite by selecting the tests you want to run, and customize the test run by creating
and configuring a TestRunner object.
• Function-based unit tests: Write each unit test as a local function within a test function file.
Function-based tests subscribe to the xUnit testing philosophy. In addition to supporting the
functionality provided by script-based tests, function-based tests give you access to a rich set of
test authoring features. For example, you can use advanced qualification features, including
constraints, tolerances, and test diagnostics.
• Class-based unit tests: Write each unit test as a Test method within a class definition file. In
addition to supporting the functionality provided by script-based and function-based tests, class-
based tests provide you with several advanced test authoring features and give you access to the
full framework functionality. For example, you can use shared test fixtures, parameterize tests,
and reuse test content.
Typically, with script-based tests, you create a test file, and pass the file name to the runtests
function without explicitly creating a suite of Test elements. If you create an explicit test suite (using
the testsuite function or a method of the matlab.unittest.TestSuite class), there are
additional features available in script-based testing. With an explicit test suite, you can:
36-212
Ways to Write Unit Tests
• Refine your suite, for example, using the classes in the matlab.unittest.selectors
namespace. (Several of the selectors are applicable only for class-based tests.)
• Create a TestRunner object and customize it to run your tests. You can add the plugin classes in
the matlab.unittest.plugins namespace to the test runner.
For more information about script-based tests, see “Write Script-Based Unit Tests” on page 36-6 and
“Extend Script-Based Tests” on page 36-14.
• Set up the pretest state of the system and return it to the original state after running the test. You
can perform these tasks once per test file or once per unit test. For more information, see “Write
Test Using Setup and Teardown Functions” on page 36-35.
• Use the fixture classes in the matlab.unittest.fixtures namespace (with the applyFixture
method) to handle the setup and teardown of frequently used testing actions.
• Record diagnostic information at a certain verbosity level by using the log method.
• Use the full library of qualifications in the matlab.unittest.qualifications namespace. To
determine which qualification to use, see “Table of Verifications, Assertions, and Other
Qualifications” on page 36-59.
• Use advanced qualification features, including constraints, actual value proxies, tolerances, and
test diagnostics. You can use the classes in the matlab.unittest.constraints namespace and
classes deriving from the matlab.automation.diagnostics.Diagnostic interface in your
qualifications.
For more information about function-based tests, see “Function-Based Unit Tests” on page 36-28 and
“Extend Function-Based Tests” on page 36-40.
• Use setup and teardown method blocks to implicitly set up the pretest environment state and
return it to the original state after running the tests. For more information, see “Write Setup and
Teardown Code Using Classes” on page 36-56.
• Share fixtures among classes. For more information, see “Write Tests Using Shared Fixtures” on
page 36-66.
• Group tests into categories and then run the tests with specified tags. For more information, see
“Tag Unit Tests” on page 36-62.
• Write parameterized tests to combine and execute tests on specified lists of parameters. For more
information, see “Use Parameters in Class-Based Tests” on page 36-76.
• Use subclassing and inheritance to share and reuse test content. For example, you can reuse the
parameters and methods defined in a test class by deriving subclasses. For more information, see
“Hierarchies of Classes — Concepts”.
For more information about class-based tests, see “Class-Based Unit Tests” on page 36-44.
36-213
36 Unit Testing
See Also
More About
• “Write Script-Based Unit Tests” on page 36-6
• “Function-Based Unit Tests” on page 36-28
• “Class-Based Unit Tests” on page 36-44
External Websites
• Get Started with MATLAB Unit Testing Framework
• xUnit
• xUnit Patterns: Four-Phase Test
36-214
Compile MATLAB Unit Tests
MATLAB Compiler supports only class-based unit tests. (You cannot compile script-based or function-
based unit tests.) In addition, MATLAB Compiler currently does not support tests authored using the
performance testing framework.
In a file named TestRand.m in your current folder, create a parameterized test class that tests the
MATLAB random number generator (see “TestRand Class Definition Summary” on page 36-216).
In your current folder, create the runMyTests function. This function creates a test suite from the
TestRand class, runs the tests, and displays the test results.
function runMyTests
suite = matlab.unittest.TestSuite.fromClass(?TestRand);
runner = matlab.unittest.TestRunner.withNoPlugins;
results = runner.run(suite);
disp(results)
end
Compile the runMyTests function into a standalone application by running the mcc command in the
Command Window. MATLAB Compiler generates an application in your current folder.
mcc -m runMyTests
Open a terminal window, navigate to the folder into which you packaged your standalone application,
and run the application.
C:\work>runMyTests
1x1200 TestResult array with properties:
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
36-215
36 Unit Testing
For more information on how to create and run standalone applications, see “Create Standalone
Application from MATLAB Function” (MATLAB Compiler).
For example, consider the tests in the file TestRand.m. You can create a standalone application to
run these tests in parallel by compiling this function.
function runMyTestsInParallel
%#function parallel.Pool
results = runtests('TestRand.m','UseParallel',true);
disp(results)
end
Compile the function into a standalone application using the mcc command. To instruct MATLAB
Compiler to include the test file in the application, specify the file name using the -a option.
mcc -m runMyTestsInParallel -a TestRand.m
methods (Test)
function testRepeatable(testCase,dim1,dim2,dim3)
state = rng;
firstRun = rand(dim1,dim2,dim3);
rng(state)
secondRun = rand(dim1,dim2,dim3);
testCase.verifyEqual(firstRun,secondRun);
end
function testClass(testCase,dim1,dim2,type)
testCase.verifyClass(rand(dim1,dim2,type),type)
end
end
end
36-216
Compile MATLAB Unit Tests
sizes = num2cell(round(logspace(0,2,10)));
end
See Also
mcc | run (TestRunner) | run (TestSuite) | runtests | runInParallel |
compiler.build.standaloneApplication
More About
• “Ways to Write Unit Tests” on page 36-212
• “Create Standalone Application from MATLAB Function” (MATLAB Compiler)
36-217
36 Unit Testing
Statement Coverage
Statement coverage identifies the source code statements that execute when the tests run. Use this
type of coverage to determine whether every statement in your source code is executed at least once.
To report statement coverage, MATLAB divides the source code into statements that are separated by
a comma, semicolon, or newline character. For example, this code has three statements.
b = 1, a = 2 * (b + 10);
x = (b ~= 0) && (a/b > 18.5)
MATLAB divides control flow statements into smaller units for code coverage reporting. For example,
in the following control flow statement code, MATLAB reports coverage for these five units: if x >
0, elseif x < 0, and three calls to the disp function. To achieve 100% statement coverage, you
need tests that execute each of these units.
if x > 0
disp("x is positive.")
elseif x < 0
disp("x is negative.")
else
disp("x is either zero or NaN.")
end
A keyword followed by an expression forms a unit for which MATLAB reports statement coverage.
Among keywords that do not require an expression, MATLAB reports coverage for break, catch,
continue, return, and try. It ignores keywords such as else, end, and otherwise.
In general, MATLAB reports coverage for statements that perform some action on program data or
affect the flow of the program. It ignores code that defines functions, classes, or class members, such
as function [y1,...,yN] = myfun(x1,...,xM) or classdef MyClass.
Function Coverage
Function coverage identifies the functions defined in the source code that execute when the tests run.
Use this type of coverage to determine whether every function in your source code was called at least
once.
For example, this code contains three defined functions: f, root, and square. To achieve 100%
function coverage, you need tests that result in each of these functions being called.
function f(x)
if x >= 0
36-218
Types of Code Coverage for MATLAB Source Code
root
else
square
end
disp(x)
function root
x = sqrt(x);
end
function square
x = x.^2;
end
end
See Also
Classes
matlab.unittest.plugins.CodeCoveragePlugin | matlab.coverage.Result |
matlab.unittest.plugins.codecoverage.CoverageResult |
matlab.unittest.plugins.codecoverage.CoverageReport |
matlab.unittest.plugins.codecoverage.CoberturaFormat
Related Examples
• “Collect Statement and Function Coverage Metrics for MATLAB Source Code” on page 36-220
36-219
36 Unit Testing
When you run tests, you can collect and access code coverage information for your MATLAB® source
code by adding an instance of the matlab.unittest.plugins.CodeCoveragePlugin class to the
test runner. In MATLAB, a plugin created using a
matlab.unittest.plugins.codecoverage.CoverageResult or
matlab.unittest.plugins.codecoverage.CoverageReport format object provides
information about statement and function coverage. For more information about statement and
function coverage, see “Types of Code Coverage for MATLAB Source Code” on page 36-218.
This example shows how to collect code coverage metrics and generate reports including statement
and function coverage information for source code in a file. The file defines the
QuadraticPolynomial class, which represents quadratic polynomials. The class constructor first
validates that the coefficients of the polynomial are numeric values and then uses these values to
initialize the class properties. The class includes the solve method to return the roots of the
specified quadratic polynomial and the plot method to plot the polynomial around its axis of
symmetry. To view the complete code for QuadraticPolynomial, see QuadraticPolynomial
Class Definition on page 36-223.
In your current folder, save the QuadraticPolynomial class definition in a file named
QuadraticPolynomial.m. Then, create the QuadraticPolynomialTest1 test class in your
current folder. The two Test methods in the class test the solve method against real and imaginary
solutions.
To run tests and perform a code coverage analysis, first create a test runner with a plugin that
provides programmatic access to the statement and function coverage information for source code in
the file QuadraticPolynomial.m.
import matlab.unittest.plugins.CodeCoveragePlugin
import matlab.unittest.plugins.codecoverage.CoverageResult
runner = testrunner("textoutput");
format = CoverageResult;
36-220
Collect Statement and Function Coverage Metrics for MATLAB Source Code
plugin = CodeCoveragePlugin.forFile("QuadraticPolynomial.m",Producing=format);
addPlugin(runner,plugin)
Create a test suite from the QuadraticPolynomialTest1 class and run the tests. The tests pass.
suite1 = testsuite("QuadraticPolynomialTest1");
run(runner,suite1);
Running QuadraticPolynomialTest1
..
Done QuadraticPolynomialTest1
__________
After the test run, the Result property of the CoverageResult object holds the coverage result.
Access the statement coverage summary from the coverage result. The returned vector indicates that
the tests executed 8 out of the 17 statements in the file, resulting in 47% statement coverage. The
statement coverage is low because the tests did not execute the code that throws an error and the
code within the plot method.
result1 = format.Result;
statementSummary = coverageSummary(result1,"statement")
statementSummary = 1×2
8 17
Access the function coverage summary. The summary indicates that the function coverage is 75%
because the tests missed one of the four methods in the QuadraticPolynomial class (plot).
functionSummary = coverageSummary(result1,"function")
functionSummary = 1×2
3 4
Use the additional output argument of the coverageSummary method to retrieve the execution count
for each method.
[~,functionDescription] = coverageSummary(result1,"function")
disp([functionDescription.function.ExecutionCount])
2 2 0 2
Now, generate an interactive HTML code coverage report from the coverage result. The report
displays information about statement and function coverage and uses different colors to highlight the
executed or missed statements and functions.
generateHTMLReport(result1)
36-221
36 Unit Testing
You can interact with the HTML code coverage report. For example, you can select a coverage type
from the Currently viewing list to view detailed information about that coverage type, and you can
control the highlighting for covered or missed executables. This figure shows the Source Details
section for statement coverage, which displays all the statements that were covered or missed.
Create tests to execute the parts of the source code that were not executed by suite1. In your
current folder, create another test class named QuadraticPolynomialTest2. One Test method in
the class tests against nonnumeric inputs, and the other Test method tests properties of a plotted
polynomial.
36-222
Collect Statement and Function Coverage Metrics for MATLAB Source Code
end
end
end
Create a test suite from the QuadraticPolynomialTest2 class and run the tests. The tests pass.
suite2 = testsuite("QuadraticPolynomialTest2");
run(runner,suite2);
Running QuadraticPolynomialTest2
.
.
Done QuadraticPolynomialTest2
__________
In this example, you ran different test suites to qualify the same source code. To report on the total
aggregated coverage for these test runs, generate an interactive HTML report from the union of the
coverage results corresponding to the test runs. The report shows that the two test suites combined
fully exercised the statements and functions in the source code.
result2 = format.Result;
generateHTMLReport(result1 + result2)
classdef QuadraticPolynomial
properties
A,B,C % Coefficients of a*x^2 + b*x + c
end
methods
function obj = QuadraticPolynomial(a,b,c)
if ~isa(a,"numeric") || ~isa(b,"numeric") || ~isa(c,"numeric")
error("QuadraticPolynomial:InputMustBeNumeric", ...
"Coefficients must be numeric.")
else
obj.A = a; obj.B = b; obj.C = c;
end
end
function r = solve(obj)
% Return solutions to a*x^2 + b*x + c = 0
delta = calculateDelta(obj);
r(1) = (-obj.B - sqrt(delta)) / (2*obj.A);
r(2) = (-obj.B + sqrt(delta)) / (2*obj.A);
end
function plot(obj,ax)
% Plot a*x^2 + b*x + c around its axis of symmetry
delta = calculateDelta(obj);
x0 = -obj.B/(2*obj.A);
x1 = abs(sqrt(delta))/obj.A;
x = x0 + linspace(-x1,x1);
y = obj.A*x.^2 + obj.B*x + obj.C;
plot(ax,x,y)
36-223
36 Unit Testing
xlabel("x")
ylabel(sprintf("%.2fx^2%+.2fx%+.2f",obj.A,obj.B,obj.C))
end
end
methods (Access=private)
function delta = calculateDelta(obj)
delta = obj.B^2 - 4*obj.A*obj.C;
end
end
end
See Also
Classes
matlab.unittest.plugins.CodeCoveragePlugin | matlab.coverage.Result |
matlab.unittest.plugins.codecoverage.CoverageResult |
matlab.unittest.plugins.codecoverage.CoverageReport |
matlab.unittest.plugins.codecoverage.CoberturaFormat
Related Examples
• “Types of Code Coverage for MATLAB Source Code” on page 36-218
• “Profile Your Code to Improve Performance” on page 29-4
36-224
Insert Test Code Using Editor
This example shows how to use the MATLAB Editor to write and run a simple parameterized test for a
function. To set up the example, define the cleanData function in a file named cleanData.m in your
current folder. The function accepts a numeric array and returns a cleaned and sorted version of the
array. It vectorizes the array, removes the NaN, 0, and Inf entries, and finally sorts the vector.
function y = cleanData(X)
y = X(:); % Vectorize the array
y = rmmissing(y); % Remove NaN entries
% Remove 0 and Inf entries
idx = (y == 0 | y == Inf);
y = y(~idx);
% If the vector is empty, set it to eps
if isempty(y)
y = eps;
end
y = sort(y); % Sort the vector
end
methods (Test)
% Test methods
function unimplementedTest(testCase)
testCase.verifyFail("Unimplemented test");
end
end
end
36-225
36 Unit Testing
• To insert code that defines a Test method, click . To access the full list of options, click Insert
Method. These options let you add a method at the test level, method-setup level, or class-setup
level. You can change the name of the method and implement it after it is inserted.
• To insert code that defines a test-level parameterization property, click . To access the full list of
options, click Insert Parameters. These options let you add a property at the test level, method-
setup level, or class-setup level. You can change the name and value of the property after it is
inserted.
When you insert code for a method or property at the test level, method-setup level, or class-setup
level, the code is added to the methods or properties block with the corresponding attribute. If the
block does not exist, MATLAB creates it.
To test the cleanData function with different inputs, add a test-level parameterization property to
the CleanDataTest class. With the test class code visible in the Editor, go to the Editor tab and in
the Test section, click . MATLAB adds a property in a properties block with the
TestParameter attribute. Rename the property as data and initialize it using a structure with four
fields. The testing framework generates parameter names and values from the property value. For
more information about parameterized tests, see “Use Parameters in Class-Based Tests” on page 36-
76.
classdef CleanDataTest < matlab.unittest.TestCase
properties (TestParameter)
data = struct("empty",[],"scalar",0, ...
"vector",[13 NaN 0],"matrix",[NaN 2 0; 1 Inf 3]);
end
methods (Test)
% Test methods
function unimplementedTest(testCase)
testCase.verifyFail("Unimplemented test");
end
end
end
The test class template includes a simple Test method named unimplementedTest. Modify this
method to test an aspect of the cleanData function:
1 Rename the method as sortTest.
2 Parameterize the method by passing the data property as the second input argument to the
method.
36-226
Insert Test Code Using Editor
3 Add code to the method to verify that the cleanData function correctly sorts the array passed to
it.
properties (TestParameter)
data = struct("empty",[],"scalar",0, ...
"vector",[13 NaN 0],"matrix",[NaN 2 0; 1 Inf 3]);
end
methods (Test)
% Test methods
function sortTest(testCase,data)
actual = cleanData(data);
testCase.verifyTrue(issorted(actual))
end
end
end
To test if the cleanData function returns a nonempty value, add another Test method to the class
by clicking in the Test section. Implement the method by following these steps:
Save the file. This code provides the complete contents of the CleanDataTest class.
properties (TestParameter)
data = struct("empty",[],"scalar",0, ...
"vector",[13 NaN 0],"matrix",[NaN 2 0; 1 Inf 3]);
end
methods (Test)
% Test methods
function sortTest(testCase,data)
actual = cleanData(data);
testCase.verifyTrue(issorted(actual))
end
function nonemptyTest(testCase,data)
actual = cleanData(data);
testCase.verifyNotEmpty(actual)
end
end
end
36-227
36 Unit Testing
For more information on how to run tests and customize your test run interactively, see “Run Tests in
Editor” on page 36-17 and “Run Tests Using Test Browser” on page 36-20.
See Also
matlab.unittest.TestCase
Related Examples
• “Class-Based Unit Tests” on page 36-44
• “Use Parameters in Class-Based Tests” on page 36-76
• “Run Tests in Editor” on page 36-17
• “Run Tests Using Test Browser” on page 36-20
36-228
Develop and Integrate Software with Continuous Integration
• Finding problems in software and fixing them soon after they are introduced.
• Adding more features while reducing the resources required for debugging code.
• Minimizing integration and deployment overheads by performing integration on a continuous
basis.
• Clearly communicating the state of software and the changes that have been made to it.
This figure shows an example of the development cycle using the Jenkins CI server and open-source
source code management tools such as Git and GitHub. For information on how to interface MATLAB
with Jenkins, see Run MATLAB Tests on Jenkins Server.
36-229
36 Unit Testing
Run an automated pipeline of tasks (including testing) when you push your changes to the remote
repository or when you make a pull request:
1 Trigger an automated pipeline of tasks on Jenkins by pushing the committed changes to GitHub
or by making a pull request to merge the remote feature branch into the main branch.
2 Jenkins runs the automated pipeline, including MATLAB and Simulink tests, and generates
artifacts as specified in the project configuration.
36-230
Develop and Integrate Software with Continuous Integration
If you do not succeed in pushing your changes or making a pull request, follow these steps:
1 Inspect the automated pipeline results and the generated artifacts. Make appropriate changes to
your code.
2 Trigger a new pipeline on Jenkins by pushing your changes to GitHub or by making a pull
request.
Integration engineers can use Jenkins artifacts to decide when to merge the feature branch into the
main branch.
In addition to MATLAB, different toolboxes support continuous integration workflows. This table lists
common continuous integration use cases for models and code.
36-231
36 Unit Testing
See Also
Functions
buildtool | matlab (Linux)
Namespaces
matlab.unittest.plugins
More About
• “Set Up Git Source Control” on page 35-13
• “Use Source Control with Projects” on page 33-60
• “Explore an Example Project” on page 33-77
• “Continuous Integration with MATLAB on CI Platforms” on page 36-237
External Websites
• MathWorks Blogs: Developer Zone – Continuous Integration
36-232
Generate Artifacts Using MATLAB Unit Test Plugins
The MATLAB® unit testing framework enables you to customize your test runner using the plugin
classes in the matlab.unittest.plugins namespace. You can use some of these plugin classes to
generate test reports and artifacts compatible with continuous integration (CI) platforms:
You also can generate CI-compatible artifacts when you run Simulink® Test™ test cases. For more
information, see “Output Results for Continuous Integration Systems” (Simulink Test).
This example shows how to create a test suite and customize the test runner to report on test run
progress and produce CI-compatible artifacts.
In a file in your current folder, create the function quadraticSolver, which returns the roots of
quadratic polynomials.
function r = quadraticSolver(a,b,c)
% quadraticSolver returns solutions to the
% quadratic equation a*x^2 + b*x + c = 0.
end
To test quadraticSolver, create the test class SolverTest in your current folder.
36-233
36 Unit Testing
At the command prompt, create a test suite from the SolverTest class.
suite = testsuite("SolverTest");
import matlab.unittest.TestRunner
runner = TestRunner.withTextOutput("OutputDetail",3);
Create a TestReportPlugin instance that sends output to the file testreport.pdf and add the
plugin to the test runner.
import matlab.unittest.plugins.TestReportPlugin
pdfFile = "testreport.pdf";
p1 = TestReportPlugin.producingPDF(pdfFile);
runner.addPlugin(p1)
Create an XMLPlugin instance that writes JUnit-style XML output to the file
junittestresults.xml. Then, add the plugin to the test runner.
import matlab.unittest.plugins.XMLPlugin
xmlFile = "junittestresults.xml";
p2 = XMLPlugin.producingJUnitFormat(xmlFile);
runner.addPlugin(p2)
Create a plugin that outputs a Cobertura code coverage report for the source code in the file
quadraticSolver.m. Instruct the plugin to write its output to the file cobertura.xml and add the
plugin to the test runner.
import matlab.unittest.plugins.CodeCoveragePlugin
import matlab.unittest.plugins.codecoverage.CoberturaFormat
sourceCodeFile = "quadraticSolver.m";
reportFile = "cobertura.xml";
reportFormat = CoberturaFormat(reportFile);
p3 = CodeCoveragePlugin.forFile(sourceCodeFile,"Producing",reportFormat);
runner.addPlugin(p3)
results = runner.run(suite)
Running SolverTest
Setting up SolverTest
36-234
Generate Artifacts Using MATLAB Unit Test Plugins
results =
Name
Passed
Failed
Incomplete
Duration
Details
Totals:
3 Passed, 0 Failed, 0 Incomplete.
0.029822 seconds testing time.
List the files in your current folder. The three specified artifacts are stored in your current folder.
dir
.
..
GenerateArtifactsUsingMATLABUnitTestPluginsExample.m
SolverTest.m
cobertura.xml
html
junittestresults.xml
metadata
quadraticSolver.m
testreport.pdf
You can process the generated artifacts on CI platforms. You also can view the contents of the
generated artifacts. For example, open the PDF test report.
36-235
36 Unit Testing
open("testreport.pdf")
See Also
Classes
matlab.unittest.TestRunner | matlab.unittest.plugins.XMLPlugin |
matlab.unittest.plugins.TAPPlugin | matlab.unittest.plugins.CodeCoveragePlugin |
matlab.unittest.plugins.TestReportPlugin
Namespaces
matlab.unittest.plugins
More About
• “Develop and Integrate Software with Continuous Integration” on page 36-229
• “Continuous Integration with MATLAB on CI Platforms” on page 36-237
• “Output Results for Continuous Integration Systems” (Simulink Test)
36-236
Continuous Integration with MATLAB on CI Platforms
Azure DevOps
To perform continuous integration with MATLAB on Azure DevOps, install an extension to your Azure
DevOps organization. To run MATLAB in your pipeline, use the extension to author your pipeline in a
file named azure-pipelines.yml in the root of your repository. You can run your pipeline using a
Microsoft-hosted or self-hosted agent. For more information, see the extension on Visual Studio
Marketplace.
Bamboo
To perform continuous integration with MATLAB on Bamboo, install a plugin on your Bamboo CI
server. The plugin provides you with tasks to run a MATLAB build, as well as MATLAB tests, scripts,
functions, and statements as part of your build. For more information, see Continuous Integration
with MATLAB on Bamboo.
CircleCI
To perform continuous integration with MATLAB on CircleCI, opt-in to using third-party orbs in your
organization security settings. To run MATLAB in your pipeline, import the appropriate orb to author
your pipeline in a file named .circleci/config.yml in the root of your repository. For more
information, see the orb on CircleCI Orb Registry.
GitHub Actions
To perform continuous integration with MATLAB on GitHub Actions, make sure GitHub Actions is
enabled for your repository. To run MATLAB in your workflow, use the appropriate actions when you
define your workflow in the .github/workflows directory of your repository. You can run your
workflow using a GitHub-hosted or self-hosted runner. For more information, see Use MATLAB with
GitHub Actions.
GitLab CI/CD
To perform continuous integration with MATLAB on GitLab CI/CD, use a template to author your
pipeline in a file named .gitlab-ci.yml in the root of your repository. The template provides you
36-237
36 Unit Testing
with jobs to run a MATLAB build, as well as MATLAB tests, scripts, functions, and statements as part
of your build. For more information, see Use MATLAB with GitLab CI/CD.
Jenkins
To perform continuous integration with MATLAB on Jenkins, install a plugin on your Jenkins agent.
Then, you can use an interface to run MATLAB in freestyle and multi-configuration (matrix) projects.
You also can configure your pipeline as code checked into source control. For more information, see
the plugin on Jenkins Plugins Index.
TeamCity
To perform continuous integration with MATLAB on TeamCity®, install a plugin on your TeamCity
server. The plugin provides you with build steps to run a MATLAB build, as well as MATLAB tests,
scripts, functions, and statements as part of your build. For more information, see Continuous
Integration with MATLAB on TeamCity.
Other Platforms
To perform continuous integration with MATLAB on other CI platforms, use the matlab command
with the -batch option in your pipeline. You can use matlab -batch to run MATLAB scripts,
functions, and statements noninteractively. For example, matlab -batch "myscript" starts
MATLAB noninteractively and runs the commands in a file named myscript.m. MATLAB terminates
automatically with exit code 0 if the specified script, function, or statement executes successfully
without error. Otherwise, MATLAB terminates with a nonzero exit code.
See Also
Functions
buildtool | matlab (Linux)
Namespaces
matlab.unittest.plugins
More About
• “Develop and Integrate Software with Continuous Integration” on page 36-229
• “Generate Artifacts Using MATLAB Unit Test Plugins” on page 36-233
External Websites
• Continuous Integration Examples for MATLAB
36-238
37
Build Automation
• Name — The name of a task uniquely identifies the task in the plan.
• Dependencies — The dependencies of a task are other tasks in the plan that must run before the
task runs.
• Actions — The actions of a task define functions that execute when the task runs.
To create a plan, include the function call buildplan(localfunctions) in the main function of the
build file. Then, add tasks to the plan using built-in task classes or local task functions:
• Built-in task classes — In the main function, create tasks from the classes in the
matlab.buildtool.tasks namespace and add them to the plan. The classes provide the
flexibility to create common tasks tailored to your build requirements.
• Local task functions — In local task functions, specify the name, optional description, and action of
tasks that are not available through built-in task classes. Task functions are local functions in the
build file whose names end with the word "Task", which is case insensitive.
For example, in your current folder, create a build file named buildfile.m with three tasks. Create
the "check" and "test" tasks using built-in task classes, and create the "archive" task using a
local task function.
function plan = buildfile
import matlab.buildtool.tasks.CodeIssuesTask
import matlab.buildtool.tasks.TestTask
% Make the "archive" task dependent on the "check" and "test" tasks
plan("archive").Dependencies = ["check" "test"];
end
function archiveTask(~)
% Create ZIP file
37-2
Overview of MATLAB Build Tool
For more information on how to create a build file, see “Create and Run Tasks Using Build Tool” on
page 37-5.
• buildtool command — Use this command to run the tasks defined in the build file for your
project. Do not use buildtool if you create or modify your plan outside of the build file or if you
want to programmatically access the result of the build.
• run method — Use this method if you create or modify your plan outside of the build file for your
project or if you want to programmatically access the result of the build. The method returns a
matlab.buildtool.BuildResult object, which includes information about the build as well as
each task that was part of the build.
To run a task, the build runner first runs all its dependencies and then performs actions of the task in
the order they appear in the Actions property of the corresponding Task object.
For example, run the default task in the plan created by the file buildfile.m in your current folder.
The build tool first runs the "check" and "test" tasks because the "archive" task depends on
them. Your results might vary, depending on the files in your current folder and its subfolders.
buildtool
** Starting check
Analysis Summary:
Total Files: 3
Errors: 0 (Threshold: 0)
Warnings: 0 (Threshold: Inf)
** Finished check
** Starting test
...
Test Summary:
Total Tests: 3
Passed: 3
Failed: 0
Incomplete: 0
Duration: 0.13274 seconds testing time.
** Finished test
** Starting archive
** Finished archive
37-3
37 Build Automation
See Also
Functions
buildplan | buildtool
Namespaces
matlab.buildtool.tasks
More About
• “Create and Run Tasks Using Build Tool” on page 37-5
• “Create Tasks That Accept Arguments” on page 37-11
• “Create Groups of Similar Tasks” on page 37-16
• “Improve Performance with Incremental Builds” on page 37-22
37-4
Create and Run Tasks Using Build Tool
In the build file, define a main function that creates a plan using the buildplan function. Call the
buildplan function with localfunctions as the input so that the build tool automatically adds the
tasks corresponding to any local task functions to the plan.
The classes in the matlab.buildtool.tasks namespace provide the flexibility to create common
tasks tailored to your build requirements. Create tasks from these classes and add them to the plan:
• Use the CodeIssuesTask class to add a task that identifies code issues in the current folder and
its subfolders and fails the build if any errors are found.
• Use the TestTask class to add a task that runs the tests in the current folder and its subfolders
and fails the build if any of the tests fail.
The main function of the build file returns a Plan object that contains the Task objects
corresponding to the tasks in the plan.
37-5
37 Build Automation
If a task is not available through built-in task classes, specify it by adding a task function to the build
file. Task functions are local functions in the build file whose names end with the word "Task", which
is case insensitive. Make sure the first input to the task function is a TaskContext object, which the
task can ignore if its action does not require it. The build tool automatically creates this object, which
includes information about the plan as well as the task being run.
For instance, add a task function to create an archive of the current folder. The name of the task is
the name of the task function without the "Task" suffix. In this example, the task
function archiveTask results in a task named "archive". Additionally, the build tool treats the first
help text line, often called the H1 line, of the task function as the task description.
function archiveTask(~)
% Create ZIP file
filename = "source_" + ...
string(datetime("now",Format="yyyyMMdd'T'HHmmss"));
zip(filename,"*")
end
After adding the tasks, specify the default task and task dependencies in the main function. Make the
"archive" task the default task in the plan. Also, make the "archive" task dependent on the
"check" and "test" tasks. The order of task names does not matter. Before the build tool runs a
task, it first runs its depended-on tasks.
% Make the "archive" task dependent on the "check" and "test" tasks
plan("archive").Dependencies = ["check" "test"];
end
37-6
Create and Run Tasks Using Build Tool
plan = buildplan(localfunctions);
% Make the "archive" task dependent on the "check" and "test" tasks
plan("archive").Dependencies = ["check" "test"];
end
function archiveTask(~)
% Create ZIP file
filename = "source_" + ...
string(datetime("now",Format="yyyyMMdd'T'HHmmss"));
zip(filename,"*")
end
plan = buildfile;
plot(plan)
37-7
37 Build Automation
When calling the main function of the build file directly, make sure your current folder is the folder
containing the build file so that any relative paths used by the main function resolve correctly.
Alternatively, use the load static method to load a plan from the build file.
First, list the tasks in the file buildfile.m in your current folder. The list includes task names and
descriptions.
buildtool -tasks
Run the "test" task. In this example, all the tests pass, and the task runs successfully. Your results
might vary, depending on the tests in your current folder and its subfolders.
buildtool test
** Starting test
...
Test Summary:
Total Tests: 3
37-8
Create and Run Tasks Using Build Tool
Passed: 3
Failed: 0
Incomplete: 0
Duration: 0.016606 seconds testing time.
** Finished test
Now, run the default task in the plan. When you invoke the build tool without specifying a task, the
build tool runs the default tasks. In this example, the build tool first runs both dependencies of the
"archive" task and then performs the action specified by the archiveTask task function.
buildtool
** Starting check
Analysis Summary:
Total Files: 3
Errors: 0 (Threshold: 0)
Warnings: 0 (Threshold: Inf)
** Finished check
** Starting test
...
Test Summary:
Total Tests: 3
Passed: 3
Failed: 0
Incomplete: 0
Duration: 0.02066 seconds testing time.
** Finished test
** Starting archive
** Finished archive
Alternatively, if you want to programmatically access the result of the build, use the run method to
run the plan.
result = run(plan);
See Also
Functions
buildplan | buildtool
Classes
matlab.buildtool.Plan | matlab.buildtool.Task
Namespaces
matlab.buildtool.tasks
More About
• “Overview of MATLAB Build Tool” on page 37-2
• “Create Tasks That Accept Arguments” on page 37-11
37-9
37 Build Automation
37-10
Create Tasks That Accept Arguments
% Make the "archive" task dependent on the "check" and "test" tasks
plan("archive").Dependencies = ["check" "test"];
end
If you cannot use the built-in task classes in the matlab.buildtool.tasks namespace to achieve
your goals, specify tasks by adding local task functions to the build file. Make sure the first input to a
task function is a TaskContext object, which the task can ignore if its action does not require it.
Specify additional inputs if you want to pass arguments to the task actions. Use argument validation
to constrain the size, class, and other aspects of the arguments. For information on how to declare
specific restrictions on arguments, see “Function Argument Validation” on page 26-2.
37-11
37 Build Automation
Add the testTask task function to run the specified tests and fail the build if any of the tests fail.
Even though the TestTask class provides a built-in task for running tests, you cannot configure the
task at run time. To customize the task action at run time, use an optional argument, tests, as well
as a name-value argument, OutputDetail, in the task function. Declare the size and class
restrictions as well as the default values using an arguments block.
function testTask(~,tests,options)
% Run unit tests
arguments
~
tests string = pwd
options.OutputDetail (1,1) string = "terse"
end
results = runtests(tests, ...
IncludeSubfolders=true, ...
OutputDetail=options.OutputDetail);
assertSuccess(results);
end
Add the archiveTask task function to create an archive of the current folder. To have control over
the name of the ZIP file, use an optional argument, filename.
function archiveTask(~,filename)
% Create ZIP file
arguments
~
filename (1,1) string = "source_" + ...
string(datetime("now",Format="yyyyMMdd'T'HHmmss"))
end
zip(filename,"*")
end
% Make the "archive" task dependent on the "check" and "test" tasks
plan("archive").Dependencies = ["check" "test"];
end
function testTask(~,tests,options)
% Run unit tests
arguments
~
tests string = pwd
37-12
Create Tasks That Accept Arguments
function archiveTask(~,filename)
% Create ZIP file
arguments
~
filename (1,1) string = "source_" + ...
string(datetime("now",Format="yyyyMMdd'T'HHmmss"))
end
zip(filename,"*")
end
Run the default task in the plan. The build tool runs the "archive" task after running its
dependencies. Because you invoke the build tool without specifying any task arguments, the tasks
perform their basic actions.
buildtool
** Starting check
Analysis Summary:
Total Files: 3
Errors: 0 (Threshold: 0)
Warnings: 0 (Threshold: Inf)
** Finished check
** Starting test
...
** Finished test
** Starting archive
** Finished archive
Customize the action performed by the "archive" task by specifying a name for the ZIP file. In the
buildtool command, enclose the task argument in parentheses after the task name.
buildtool archive("source.zip")
** Starting check
Analysis Summary:
Total Files: 3
Errors: 0 (Threshold: 0)
Warnings: 0 (Threshold: Inf)
37-13
37 Build Automation
** Finished check
** Starting test
...
** Finished test
** Starting archive
** Finished archive
Run all the tasks again, but override the default behavior of the configurable tasks:
• Configure the "test" task to run the tests in a subfolder named myTests in your current folder
and display test run progress at the "concise" level.
• Configure the "archive" task to generate a ZIP file with a specific name.
** Starting check
Analysis Summary:
Total Files: 3
Errors: 0 (Threshold: 0)
Warnings: 0 (Threshold: Inf)
** Finished check
** Starting test
Running MyTestClass
...
Done MyTestClass
__________
** Finished test
** Starting archive
** Finished archive
Alternatively, you can run tasks by using the run method. For example, run the default task in the
plan.
plan = buildfile;
run(plan);
Customize the action performed by the "archive" task by specifying a name for the ZIP file. To
specify the task argument in the run method call, use a cell vector.
run(plan,"archive",{"source2.zip"});
Configure the "test" and "archive" tasks, and run them and the nonconfigurable "check" task.
Because you must specify the same number of task names and task argument groups in the run
method call, use an empty cell array for the "check" task arguments.
37-14
Create Tasks That Accept Arguments
See Also
Functions
buildplan | buildtool
Classes
matlab.buildtool.Plan | matlab.buildtool.Task
Namespaces
matlab.buildtool.tasks
More About
• “Overview of MATLAB Build Tool” on page 37-2
• “Create and Run Tasks Using Build Tool” on page 37-5
• “Function Argument Validation” on page 26-2
37-15
37 Build Automation
This example shows how to create a group of tasks that build MEX files in a build file and then run
the group and test the resulting MEX files. To run the example, you must have a supported C
compiler installed on your system and follow the steps in “Source and Test Code” on page 37-20 to
set up your current folder. The build file that you create in this example assumes that your current
folder has a source folder that contains the arrayProduct.c and yprime.c source files as well as
a tests folder that contains the MEXFileTest.m test file.
In the build file, define a function named buildfile that returns a plan with tasks created using
built-in task classes. Before adding the tasks, import the required classes and create a plan with no
tasks.
In the buildfile function, add a task named "clean" to the plan that deletes outputs and traces of
the other tasks in the build file. To create the task, use the matlab.buildtool.tasks.CleanTask
class.
The source folder in this example contains the arrayProduct.c and yprime.c source files. To
compile each C source file into a binary MEX file, use a matlab.buildtool.tasks.MexTask
instance. Because MexTask instances perform similar actions, organize them into a task group.
You can create a task group by adding a task whose name contains a colon to the plan. Start the task
name with the task group name followed by a colon. For instance, add the "mex" task group that
contains two tasks named "mex:arrayProduct" and "mex:yprime" to the plan. Each of these
37-16
Create Groups of Similar Tasks
tasks compiles a source file into a MEX file and saves the result to a folder named output in your
current folder.
% Add a task group to build MEX files
plan("mex:arrayProduct") = MexTask(fullfile("source","arrayProduct.c"),"output");
plan("mex:yprime") = MexTask(fullfile("source","yprime.c"),"output");
Using the matlab.buildtool.tasks.TestTask class, add a task named "test" to the plan that
runs the tests in the MEXFileTest test class and fails the build if any of the tests fail. Because the
tests must exercise the MEX files, make the "test" task dependent on the "mex" task group.
% Add a task to run tests
plan("test") = TestTask(fullfile("tests","MEXFileTest.m"));
37-17
37 Build Automation
the "mex" task group, the edges in the graph indicate that the "mex:arrayProduct" and
"mex:yprime" tasks must run before the "test" task runs.
plan = buildfile;
plot(plan,ShowAllTasks=true)
List the tasks in the build file including the tasks in any task groups.
Run the "mex" task group. The "mex:arrayProduct" and "mex:yprime" tasks in the task group
build binary MEX files and save them to the output folder. The build run progress includes
information specific to your compiler.
37-18
Create Groups of Similar Tasks
buildtool mex
** Starting mex:arrayProduct
mex source\arrayProduct.c -output output\arrayProduct.mexw64
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
** Finished mex:arrayProduct
** Starting mex:yprime
mex source\yprime.c -output output\yprime.mexw64
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
** Finished mex:yprime
** Done mex
Run the "test" task. Even though the "test" task depends on the "mex" task group, the build tool
skips the tasks in the task group because neither their inputs nor outputs have changed. In this
example, both the tests in the tests folder pass and the "test" task runs successfully.
buildtool test
** Done mex
** Starting test
..
Test Summary:
Total Tests: 2
Passed: 2
Failed: 0
Incomplete: 0
Duration: 0.50099 seconds testing time.
** Finished test
Run the "clean" task to delete outputs and traces of the other tasks in the plan. When you delete
the outputs or the trace of a task, the build tool no longer considers the task as up to date.
buildtool clean
** Starting clean
Deleted 'C:\work\output\arrayProduct.mexw64' successfully
Deleted 'C:\work\output\yprime.mexw64' successfully
** Finished clean
** Starting mex:arrayProduct
mex source\arrayProduct.c -output output\arrayProduct.mexw64
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
** Finished mex:arrayProduct
37-19
37 Build Automation
Now, run the "test" task again. The build tool runs only the "mex:yprime" task in the task group.
It skips the "mex:arrayProduct" task because the task is up to date.
buildtool test
** Starting mex:yprime
mex source\yprime.c -output output\yprime.mexw64
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
** Finished mex:yprime
** Done mex
** Starting test
..
Test Summary:
Total Tests: 2
Passed: 2
Failed: 0
Incomplete: 0
Duration: 0.50383 seconds testing time.
** Finished test
In your current folder, create the source folder if it does not exist. Then, copy two C source files
named arrayProduct.c and yprime.c to the source folder. For more information about the
source files used in this example, see “Tables of MEX Function Source Code Examples”.
mkdir source
copyfile(fullfile(matlabroot,"extern","examples","mex", ...
"arrayProduct.c"),"source","f")
copyfile(fullfile(matlabroot,"extern","examples","mex", ...
"yprime.c"),"source","f")
Create Tests
In your current folder, create the tests folder if it does not exist.
mkdir tests
In a file named MEXFileTest.m in the tests folder, create the MEXFileTest test class to test the
MEX files corresponding to the C source files.
37-20
Create Groups of Similar Tasks
function test2(testCase)
import matlab.unittest.fixtures.PathFixture
testCase.applyFixture(PathFixture(fullfile("..","output")))
actual = yprime(1,1:4);
expected = [2.0000 8.9685 4.0000 -1.0947];
testCase.verifyEqual(actual,expected,RelTol=1e-4)
end
end
end
See Also
Functions
buildplan | buildtool | plot
Classes
matlab.buildtool.Plan | matlab.buildtool.TaskGroup |
matlab.buildtool.tasks.MexTask
Namespaces
matlab.buildtool.tasks
More About
• “Overview of MATLAB Build Tool” on page 37-2
• “Create and Run Tasks Using Build Tool” on page 37-5
• “Improve Performance with Incremental Builds” on page 37-22
37-21
37 Build Automation
This topic shows how to create tasks that have inputs and outputs and then run these tasks as part of
incremental builds. For an overview of incremental builds, see “MATLAB Incremental Builds” on page
37-25.
Note Tasks created from the built-in task classes in the matlab.buildtool.tasks namespace
define their own inputs and outputs. Therefore, you do not need to explicitly specify their inputs and
outputs to take advantage of incremental builds.
In your current folder, create a build file named buildfile.m that contains a main function and two
local task functions, named pcodeTask and archiveTask, corresponding to the "pcode" and
"archive" tasks. (For illustrative purposes, the "pcode" task in this example is created using a task
function. The recommended practice is to create the task using the
matlab.buildtool.tasks.PcodeTask class.) For the complete code in the build file used in this
example, see “Summary of Build File” on page 37-23.
Add Main Function
Specify the inputs and outputs of the tasks by setting their Inputs and Outputs properties:
• "pcode" task — Set the Inputs and Outputs properties, respectively, to FileCollection
objects that represent all the .m and .p files in the source folder and any of its subfolders. You
can create FileCollection objects by assigning strings to the properties. You can also use the
matlab.buildtool.io.FileCollection.fromPaths or files method to explicitly create
FileCollection objects (for instance, plan("pcode").Inputs =
files(plan,"source/**/*.m");).
• "archive" task — Set the Inputs property to the Outputs property of the "pcode" task. (This
assignment results in an inferred dependency by making the "archive" task dependent on the
"pcode" task.) Set the Outputs property to a FileCollection object that represents a file
named source.zip in your current folder.
37-22
Improve Performance with Incremental Builds
plan("pcode").Inputs = "source/**/*.m";
plan("pcode").Outputs = plan("pcode").Inputs.replace(".m",".p");
plan("archive").Inputs = plan("pcode").Outputs;
plan("archive").Outputs = "source.zip";
end
Specify the tasks in the plan by adding local task functions to the build file. Add the pcodeTask task
function to obfuscate the inputs of the "pcode" task and create the P-code files in the same folders
as the inputs. Because the Inputs property of the "pcode" task holds a FileCollection object,
use the paths method of the FileCollection class to return the paths of the file collection as a
string vector. Then, call the pcode function using a comma-separated list of the paths.
function pcodeTask(context)
% Create P-code files
filePaths = context.Task.Inputs.paths;
pcode(filePaths{:},"-inplace")
end
This code shows the complete contents of the file buildfile.m in your current folder.
function plan = buildfile
plan = buildplan(localfunctions);
plan("pcode").Inputs = "source/**/*.m";
plan("pcode").Outputs = plan("pcode").Inputs.replace(".m",".p");
plan("archive").Inputs = plan("pcode").Outputs;
plan("archive").Outputs = "source.zip";
end
function pcodeTask(context)
% Create P-code files
filePaths = context.Task.Inputs.paths;
pcode(filePaths{:},"-inplace")
end
function archiveTask(context)
% Create ZIP file
task = context.Task;
zip(task.Outputs.paths,task.Inputs.paths)
end
Create a dependency graph of the build plan using the plot method. Even though you did not specify
an explicit dependency in the build file, the graph displays a dependency. The "archive" task has an
37-23
37 Build Automation
inferred dependency on the "pcode" task because you specified the inputs of the "archive" task by
using the outputs of the "pcode" task. Like explicit dependencies that you specify by setting the
Dependencies property of a task, inferred dependencies of a task must run before the task runs.
plan = buildfile;
plot(plan)
Because the tasks in this example have specified inputs and outputs, the tasks can run as part of
incremental builds. If the inputs and outputs of a task to run have not changed since the last time it
ran, the build tool skips the task. Otherwise, the build tool runs it.
Trigger the initial build by running the "archive" task. Because the "archive" task depends on
the "pcode" task, the build tool runs the "pcode" task before running the "archive" task.
buildtool archive
** Starting pcode
** Finished pcode
** Starting archive
** Finished archive
Run the "archive" task again. The build tool skips both of the tasks because none of the inputs or
outputs of the tasks have changed since the last run.
buildtool archive
37-24
Improve Performance with Incremental Builds
Add a file to the source folder, and then rerun the "archive" task. The build tool first runs the
"pcode" task because its inputs have changed between consecutive builds. The build tool then runs
the "archive" task because its inputs are the outputs of the "pcode" task, which have changed.
fclose(fopen(fullfile("source","newFile.m"),"w"));
buildtool archive
** Starting pcode
** Finished pcode
** Starting archive
** Finished archive
Delete the ZIP file created by the "archive" task, and then run the task. The build tool skips the
"pcode" task because none of its inputs or outputs have changed. However, the build tool runs the
"archive" task because its output has changed since the last time it ran successfully.
delete("source.zip")
buildtool archive
** Starting archive
** Finished archive
To specify the inputs and outputs of a task, set its Inputs and Outputs properties. For example, you
can set the properties to a vector of matlab.buildtool.io.FileCollection objects.
The build tool validates that specified inputs of a task exist before running the task and that specified
outputs of a task exist after running the task. If validation of task inputs or outputs fails, the build tool
fails the task.
Cache Folder
When you run a build, the build tool creates a cache folder named .buildtool in the plan root
folder if it does not exist. The cache folder includes information, such as task traces, that enables
incremental builds. A task trace is a record of the inputs, outputs, actions, and arguments of a task
from its last successful run. If you create a task with the DisableIncremental property set to
true, then the build tool does not create a trace for it.
37-25
37 Build Automation
Do not put the cache folder under source control. To exclude the cache folder from source control,
add its name to your source control ignore list. For example, append the cache folder name to
the .gitignore file in the plan root folder.
writelines(".buildtool",".gitignore",WriteMode="append")
Up-To-Date Check
Before running a task that has inputs or outputs and that has a DisableIncremental property
value of false, the build tool references the cache folder to check whether the task is up to date. If
the check passes, the build tool skips the task. Otherwise, the build tool runs the task.
For the check to pass, the inputs, outputs, actions, and arguments of the task must be the same as the
last time the task ran successfully. To determine whether a file has changed, the build tool examines
the contents of the file (not its timestamp).
See Also
Functions
files | matlab.buildtool.io.FileCollection.fromPaths | paths | buildplan |
buildtool
Classes
matlab.buildtool.io.FileCollection | matlab.buildtool.TaskInputs |
matlab.buildtool.TaskOutputs | matlab.buildtool.Task
Namespaces
matlab.buildtool.tasks
More About
• “Overview of MATLAB Build Tool” on page 37-2
• “Create and Run Tasks Using Build Tool” on page 37-5
• “Create Groups of Similar Tasks” on page 37-16
37-26
38
A System object is a specialized MATLAB object. Many toolboxes include System objects. System
objects are designed specifically for implementing and simulating dynamic systems with inputs that
change over time. Many signal processing, communications, and controls systems are dynamic. In a
dynamic system, the values of the output signals depend on both the instantaneous values of the
input signals and on the past behavior of the system. System objects use internal states to store that
past behavior, which is used in the next computational step. As a result, System objects are optimized
for iterative computations that process large streams of data in segments, such as video and audio
processing systems. This ability to process streaming data provides the advantage of not having to
hold large amounts of data in memory. Use of streaming data also allows you to use simplified
programs that use loops efficiently.
For example, you could use System objects in a system that reads data from a file, filters that data
and then writes the filtered output to another file. Typically, a specified amount of data is passed to
the filter in each loop iteration. The file reader object uses a state to track where in the file to begin
the next data read. Likewise, the file writer object tracks where it last wrote data to the output file so
that data is not overwritten. The filter object maintains its own internal states to ensure that the
filtering is performed correctly. This diagram represents a single loop of the system.
These advantages make System objects well suited for processing streaming data.
Note Check the product documentation to confirm fixed-point, code generation, and MATLAB
Compiler support for the specific System objects you want to use.
This separation of creation from execution lets you create multiple, persistent, reusable objects, each
with different settings. Using this approach avoids repeated input validation and verification, allows
38-2
What Are System Objects?
for easy use within a programming loop, and improves overall performance. In contrast, MATLAB
functions must validate parameters every time you call the function.
In addition to the System objects provided with System Toolboxes, you can create your own System
objects. See “Create System Objects”.
dft = dsp.FFT('FFTLengthSource','Property','FFTLength',1024);
dft(x);
If you run a System object without any input arguments, you must include empty parentheses. For
example, asysobj().
When you run a System object, it also performs other important tasks related to data processing,
such as initialization and handling object states.
Note An alternative way to run a System object is to use the step function. For example, for an
object created using dft = dsp.FFT, you can run it using step(dft,x).
All System objects support the following object functions. In cases where a function is not applicable
to a particular object, calling that function has no effect on the object.
38-3
38 System object Usage and Authoring
Function Description
Run the object function, or Runs the object to process data using the algorithm defined by that
step object.
Example: For the object dft = dsp.FFT;, run the object via:
• y = dft(x)
• y = step(dft,x)
See Also
matlab.System
Related Examples
• “System Objects vs MATLAB Functions” on page 38-5
• “System Design in MATLAB Using System Objects” on page 38-7
• “System Design in Simulink Using System Objects” (Simulink)
38-4
System Objects vs MATLAB Functions
Building a dynamic system with different execution phases and internal states using only MATLAB
functions would require complex programming. You would need code to initialize the system, validate
data, manage internal states, and reset and terminate the system. System objects perform many of
these managerial operations automatically during execution. By combining System objects in a
program with other MATLAB functions, you can streamline your code and improve efficiency.
The code reads audio data from a file, filters it, and plays the filtered audio data. The audio data is
read in frames. This code produces the same result as the System objects code in the next example,
allowing you to compare approaches.
fname = 'speech_dft_8kHz.wav';
Obtain the total number of samples and the sampling rate from the source file.
audioInfo = audioinfo(fname);
maxSamples = audioInfo.TotalSamples;
fs = audioInfo.SampleRate;
b = fir1(160,.15);
z = zeros(1,numel(b)-1);
Define the amount of audio data to process at one time, and initialize the while loop index.
frameSize = 1024;
nIdx = 1;
38-5
38 System object Usage and Authoring
The loop uses explicit indexing and state management, which can be a tedious and error-prone
approach. You must have detailed knowledge of the states, such as, sizes and data types. Another
issue with this MATLAB-only code is that the sound function is not designed to run in real time. The
resulting audio is choppy and barely audible.
The code uses System objects from the DSP System Toolbox™ software to read audio data from a file,
filter it, and then play the filtered audio data. This code produces the same result as the MATLAB
code shown previously, allowing you to compare approaches.
fname = "speech_dft_8kHz.wav";
audioIn = dsp.AudioFileReader(fname,'OutputDataType','single');
filtLP = dsp.FIRFilter('Numerator',fir1(160,.15));
audioOut = audioDeviceWriter('SampleRate',audioIn.SampleRate);
while ~isDone(audioIn)
audio = audioIn(); % Read audio source file
y = filtLP(audio); % Filter the data
audioOut(y); % Play the filtered data
end
This System objects code avoids the issues present in the MATLAB-only code. Without requiring
explicit indexing, the file reader object manages the data frame sizes while the filter manages the
states. The audio device writer object plays each audio frame as it is processed.
38-6
System Design in MATLAB Using System Objects
1 “Create Individual Components” on page 38-7 — Create the System objects to use in your
system. In addition to the System objects provided with toolboxes, you can also create your own
System objects. See “Create System Objects”.
2 “Configure Components” on page 38-8 — If necessary, change the objects’ property values to
model your particular system. All System object properties have default values that you may be
able to use without changing them. See “Configure Components” on page 38-8.
3 “Assemble Components Into System” on page 38-9 — Write a MATLAB program that includes
those System objects, connecting them using MATLAB variables as inputs and outputs to
simulate your system. See “Connecting System Objects” on page 38-9.
4 “Run Your System” on page 38-9 — Run your program. You can change tunable properties
while your system is running. See “Run Your System” on page 38-9 and “Reconfiguring
Objects” on page 38-10.
This section shows how to set up your system using predefined components from DSP System Toolbox
and Audio Toolbox™:
38-7
38 System object Usage and Authoring
audioIn = dsp.AudioFileReader;
filtLP = dsp.FIRFilter;
audioOut = audioDeviceWriter;
Configure Components
When to Configure Components
If you did not set an object's properties when you created it and do not want to use default values,
you must explicitly set those properties. Some properties allow you to change their values while your
system is running. See “Reconfiguring Objects” on page 38-10 for information.
Most properties are independent of each other. However, some System object properties enable or
disable another property or limit the values of another property. To avoid errors or warnings, you
should set the controlling property before setting the dependent property.
To display the current property values for an object, type that object’s handle name at the command
line (such as audioIn). To display the value of a specific property, type
objecthandle.propertyname (such as audioIn.FileName).
This section shows how to configure the components for your system by setting the component
objects’ properties.
Use this procedure if you have created your components separately from configuring them. You can
also create and configure your components at the same time, as described in a later example.
For the file reader object, specify the file to read and set the output data type.
For the filter object, specify the filter numerator coefficients using the fir1 function, which specifies
the low pass filter order and the cutoff frequency.
For the audio device writer object, specify the sample rate. In this case, use the same sample rate as
the input data.
audioIn.Filename = "speech_dft_8kHz.wav";
audioIn.OutputDataType = "single";
filtLP.Numerator = fir1(160,.15);
audioOut.SampleRate = audioIn.SampleRate;
Create the file reader object, specify the file to read, and set the output data type.
38-8
System Design in MATLAB Using System Objects
audioIn = dsp.AudioFileReader("speech_dft_8kHz.wav",...
'OutputDataType',"single");
Create the filter object and specify the filter numerator using the fir1 function. Specify the low pass
filter order and the cutoff frequency of the fir1 function.
filtLP = dsp.FIRFilter('Numerator',fir1(160,.15));
Create the audio player object and set the sample rate to the same rate as the input data.
audioOut = audioDeviceWriter('SampleRate',audioIn.SampleRate);
After you have determined the components you need and have created and configured your System
objects, assemble your system. Use the System objects like other MATLAB functions and include
them in MATLAB code. You can pass MATLAB variables as input arguments into System objects.
The main difference between using System objects and using functions is that System objects use a
two-step process. First you create the object and set its parameters and then, you run the object.
Running the object initializes it and controls the data flow and state management of your system. You
typically call a System object within a code loop.
You use the output from an object as the input to another object. For some System objects, you can
use properties of those objects to change the inputs or outputs. To verify that the appropriate number
of inputs and outputs are being used, you can use nargin and nargout on any System object. For
information on all available System object functions, see “System Object Functions” on page 38-3.
This section shows how to connect the components together to read, filter, and play a file of audio
data. The while loop uses the isDone function to read through the entire file.
while ~isDone(audioIn)
audio = audioIn(); % Read audio source file
y = filtLP(audio); % Filter the data
audioOut(y); % Play the filtered data
end
The first call to a System object initializes and runs the object. When a System object has started
processing data, you cannot change nontunable properties.
38-9
38 System object Usage and Authoring
• Input size
• Input complexity
• Input data type
• Tunable property data types
• Discrete state data types
If the System object author has restricted these specifications, you get an error if you try to change
them while the System object is in use.
Reconfiguring Objects
Change Properties
When a System object has started processing data, you cannot change nontunable properties. You
can use isLocked on any System object to verify whether the object is processing data. When
processing is complete, you can use the release function to release resources and allow changes to
nontunable properties.
Some object properties are tunable, which enables you to change them even if the object is in use.
Most System object properties are nontunable. Refer to the object’s reference page to determine
whether an individual property is tunable.
During object usage, after you have called the algorithm, some System objects do not allow changes
in input complexity, size, or data type. If the System object restricts these specifications, you can call
release to change these specifications. Calling release also resets other aspects of the System
object, such as states and Discrete states.
This example shows how to change the filter type to a high-pass filter as the code is running by
modifying the Numerator property of the filter object. The change takes effect the next time the
object is called.
38-10
Define Basic System Objects
System objects are composed of a base class, matlab.System and may include one or more
mixin classes. You specify the base class and mixin classes on the first line of your class definition
file.
3 Save the file and name it AddOne.m.
Define Algorithm
The stepImpl method contains the algorithm to execute when you run your object. Define this
method so that it contains the actions you want the System object to perform.
1 In the basic System object you created, inspect the stepImpl method template.
methods (Access = protected)
function y = stepImpl(obj,u)
% Implement algorithm. Calculate y as a function of input u and
% discrete states.
y = u;
end
end
The stepImpl method access is always set to protected because it is an internal method that
users do not directly call or run.
All methods, except static methods, require the System object handle as the first input argument.
The default value, inserted by MATLAB Editor, is obj. You can use any name for your System
object handle.
By default, the number of inputs and outputs are both one. Inputs and outputs can be added
using Inputs/Outputs. You can also use a variable number of inputs or outputs, see “Change the
Number of Inputs” on page 38-13.
Alternatively, if you create your System object by editing a MAT-file, you can add the stepImpl
method using Insert Method > Implement algorithm.
2 Change the computation in the stepImpl method to add 1 to the value of u.
methods (Access = protected)
38-11
38 System object Usage and Authoring
function y = stepImpl(~,u)
y = u + 1;
end
Tip Instead of passing in the object handle, you can use the tilde (~) to indicate that the object
handle is not used in the function. Using the tilde instead of an object handle prevents warnings
about unused variables.
3 Remove unused methods that are included by default in the basic template.
You can modify these methods to add more System object actions and properties. You can also
make no changes, and the System object still operates as intended.
The class definition file now has all the code necessary for this System object.
function y = stepImpl(~,u)
y = u + 1;
end
end
end
See Also
stepImpl | getNumInputsImpl | getNumOutputsImpl | matlab.System
Related Examples
• “Change the Number of Inputs” on page 38-13
• “System Design and Simulation in MATLAB” on page 38-7
38-12
Change the Number of Inputs
This example shows how to set the number of inputs for a System object™ with and without using
getNumInputsImpl.
If you have a variable number of inputs or outputs and you intend to use the System object in
Simulink®, you must include the getNumInputsImpl or getNumOutputsImpl method in your class
definition.
These examples show modifications for the number of inputs. If you want to change the number of
outputs, the same principles apply.
As with all System object Impl methods, you always set the getNumInputsImpl and
getNumOutputsImpl method's access to protected because they are internal methods that are
never called directly.
This example shows how to write a System object that allows the number of inputs to vary.
Update the stepImpl method to accept up to three inputs by adding code to handle one, two, or
three inputs. If you are only using this System object in MATLAB, getNumInputsImpl and
getNumOutputsImpl are not required.
Run this System object with one, two, and three inputs.
addObj = AddTogether;
addObj(2)
ans =
38-13
38 System object Usage and Authoring
addObj(2,3)
ans =
addObj(2,3,4)
ans =
This example shows how to write a System object that allows changes to the number of inputs and
outputs before running the object. Use this method when your System object will be included in
Simulink:
properties (Nontunable)
NumInputs = 3; % Default value
end
methods (Access = protected)
function y = stepImpl(obj,x1,x2,x3)
switch obj.NumInputs
case 1
y = x1;
case 2
y = x1 + x2;
case 3
y = x1 + x2 + x3;
otherwise
y = [];
end
end
function validatePropertiesImpl(obj)
if ((obj.NumInputs < 1) ||...
(obj.NumInputs > 3))
error("Only 1, 2, or 3 inputs allowed.");
end
end
38-14
Change the Number of Inputs
Run this System object with one, two, and three inputs.
addObj = AddTogether2;
addObj.NumInputs = 1;
addObj(2)
ans =
release(addObj);
addObj.NumInputs = 2;
addObj(2,3)
ans =
release(addObj);
addObj.NumInputs = 3;
addObj(2,3,4)
ans =
See Also
getNumInputsImpl | getNumOutputsImpl
Related Examples
• “Validate Property and Input Values” on page 38-16
• “Define Basic System Objects” on page 38-11
• “Using ~ as an Input Argument in Method Definitions” on page 38-51
38-15
38 System object Usage and Authoring
Validate Inputs
To validate input values, use the validateInputsImpl method. This example shows how to validate
that the first input is a numeric value.
38-16
Validate Property and Input Values
See Also
validateInputsImpl | validatePropertiesImpl
Related Examples
• “Define Basic System Objects” on page 38-11
• “Change Input Complexity, Dimensions, or Data Type” on page 38-10
• “Summary of Call Sequence” on page 38-46
• “Property Get and Set Methods”
• “Using ~ as an Input Argument in Method Definitions” on page 38-51
38-17
38 System object Usage and Authoring
In this example, you allocate file resources by opening the file so the System object can write to that
file. You do these initialization tasks one time during setup, rather than every time you run the object.
In this example, you define the public Filename property and specify the value of that property as
the nontunable character vector, default.bin. Users cannot change nontunable properties after the
setup method has been called.
properties (Nontunable)
Filename = "default.bin"
end
Users cannot access private properties directly, but only through methods of the System object. In
this example, you define the pFileID property as a private property. You also define this property as
hidden to indicate it is an internal property that never displays to the user.
Define Setup
You use the setupImpl method to perform setup and initialization tasks. You should include code in
the setupImpl method that you want to execute one time only. The setupImpl method is called
once the first time you run the object. In this example, you allocate file resources by opening the file
for writing binary data.
methods
function setupImpl(obj)
obj.pFileID = fopen(obj.Filename,"wb");
if obj.pFileID < 0
error("Opening the file failed");
end
end
end
Although not part of setup, you should close files when your code is done using them. You use the
releaseImpl method to release resources.
38-18
Initialize Properties and Setup One-Time Calculations
See Also
setupImpl | releaseImpl | stepImpl
Related Examples
• “Release System Object Resources” on page 38-22
• “Define Property Attributes” on page 38-24
• “Summary of Call Sequence” on page 38-46
38-19
38 System object Usage and Authoring
Define the System object constructor, which is a method that has the same name as the class (MyFile
in this example). Within that method, you use the setProperties method to make all public
properties available for input when the user constructs the object. nargin is a MATLAB function that
determines the number of input arguments. varargin indicates all of the object’s public properties.
methods
function obj = MyFile(varargin)
setProperties(obj,nargin,varargin{:});
end
end
methods
% You call setProperties in the constructor to let
% a user specify public properties of object as
% name-value pairs.
function obj = MyFile(varargin)
setProperties(obj,nargin,varargin{:});
end
end
38-20
Set Property Values at Construction Time
function stepImpl(obj,data)
fwrite(obj.pFileID,data);
end
See Also
nargin | setProperties
Related Examples
• “Define Property Attributes” on page 38-24
• “Release System Object Resources” on page 38-22
38-21
38 System object Usage and Authoring
In this section...
“Reset Algorithm State” on page 38-22
“Release System Object Resources” on page 38-22
This method allows you to clear the axes on the Whiteboard figure window while keeping the figure
open.
function releaseImpl(obj)
cla(Whiteboard.getWhiteboard());
hold on
end
For a complete definition of the Whiteboard System object, see “Create a Whiteboard System
Object” on page 38-30.
38-22
Reset Algorithm and Release Resources
See Also
resetImpl | releaseImpl
More About
• “Summary of Call Sequence” on page 38-46
• “Initialize Properties and Setup One-Time Calculations” on page 38-18
38-23
38 System object Usage and Authoring
Use the Nontunable attribute for a property when the algorithm depends on the value being
constant once data processing starts. Defining a property as nontunable may improve the efficiency
of your algorithm by removing the need to check for or react to values that change. For code
generation, defining a property as nontunable allows the memory associated with that property to be
optimized. You should define all properties that affect the number of input or output ports as
nontunable.
When you use the System object, you can only change nontunable properties before calling the object
or after calling the release function. For example, you define the InitialValue property as
nontunable and set its value to 0.
properties (Nontunable)
InitialValue = 0;
end
properties (DiscreteState)
Count;
end
38-24
Define Property Attributes
Property.... Use the dialog box to set the property access, System object attributes, and MATLAB
property attributes for your custom properties.
Access
Access Setting Description
SetAccess and public Property can be accessed by any other code in the same
GetAccess System object or another System object that references it.
protected Property can be used only by code in the same System object
or in a subclass.
private Property can be accessed only by code in the same System
object.
immutable You can set this property value only when you create the
System object. You cannot change the property value. This
setting applies only to SetAccess.
To create the property with the selected attributes, click Insert. MATLAB Editor inserts the property
into your code.
38-25
38 System object Usage and Authoring
properties
% Whether to increment the counter, must be a logical scalar
Increment (1, 1) logical = true
end
properties (DiscreteState)
% Count state variable
Count
end
function c = stepImpl(obj)
if obj.Increment && (obj.Count < obj.MaxValue)
obj.Count = obj.Count + 1;
else
disp(['Max count, ' num2str(obj.MaxValue) ' ,reached'])
end
c = obj.Count;
end
See Also
More About
• “Class Attributes”
• “Property Attributes”
• “What You Cannot Change While Your System Is Running” on page 38-9
• “Summary of Call Sequence” on page 38-46
38-26
Hide Inactive Properties
38-27
38 System object Usage and Authoring
if obj.UseRandomInitialValue
obj.pCount = rand();
else
obj.pCount = obj.InitialValue;
end
end
See Also
isInactivePropertyImpl
38-28
Limit Property Values to Finite List
For a System object that is used in a MATLAB System block in Simulink you can use enumerations or
property validation. If you use enumerations, enumerations can also derive from
Simulink.IntEnumType. You use this type of enumeration to add attributes (such as custom
headers) to the input or output of the MATLAB System block. See “Use Enumerated Data in Simulink
Models” (Simulink).
This example defines a Style property that can have the values solid, dash, or dot. The default
value is solid and the (1,1) defines the property as a scalar.
properties
Style (1,1) string {mustBeMember(Style, ["solid","dash","dot"])} = "solid";
end
Enumeration Property
To use enumerated data in a System object, you refer to the enumerations as properties in your
System object class definition and define your enumerated class in a separate class definition file.
This example defines a color enumeration property for a System object. The definition of the
enumeration class ColorValues is:
The ColorValues class inherits from int32 for code generation compatibility. Enumeration values
must be valid MATLAB identifiers on page 1-5.
In the System object, the Color property is defined as a ColorValues object with blue as the
default. The (1,1) defines the Color property as a scalar:
38-29
38 System object Usage and Authoring
properties
Color (1, 1) ColorValues = ColorValues.blue
end
This example shows the class definition of a Whiteboard System object™, two types of finite list
properties, and how to use the object. Each time you run the whiteboard object, it draws a line on a
whiteboard.
type Whiteboard.m
properties(Nontunable)
Color (1, 1) ColorValues = ColorValues.blue
Style (1,1) string {mustBeMember(Style, ["solid","dash","dot"])} = "solid";
end
function releaseImpl(~)
cla(Whiteboard.getWhiteboard());
hold on
end
end
methods (Static)
function a = getWhiteboard()
h = findobj('tag','whiteboard');
if isempty(h)
h = figure('tag','whiteboard');
hold on
end
a = gca;
end
end
end
38-30
Limit Property Values to Finite List
greenInk = Whiteboard;
blueInk = Whiteboard;
greenInk.Color = "green";
blueInk.Color = "blue";
blueInk.Style = "dot";
for i=1:3
greenInk();
blueInk();
end
release(greenInk);
release(blueInk);
38-31
38 System object Usage and Authoring
See Also
Related Examples
• “Validate Property Values”
• “Enumerations”
• “Code Generation for Enumerations” (MATLAB Coder)
38-32
Process Tuned Properties
properties
MiddleC = 440
NumNotes = 12
end
function hz = stepImpl(obj,noteShift)
% A noteShift value of 1 corresponds to obj.MiddleC
hz = obj.pLookupTable(noteShift);
end
function processTunedPropertiesImpl(obj)
propChange = isChangedProperty(obj,'NumNotes')||...
isChangedProperty(obj,'MiddleC')
if propChange
38-33
38 System object Usage and Authoring
See Also
processTunedPropertiesImpl
38-34
Define Composite System Objects
To define a System object from other System objects, store those other objects in your class definition
file as properties. In this example, the highpass and lowpass filters are the separate System objects
defined in their own class-definition files.
function resetImpl(obj)
reset(obj.pLowpass);
reset(obj.pHighpass);
end
end
end
properties (Nontunable)
% Filter coefficients
Numerator = [0.006,-0.0133,-0.05,0.26,0.6,0.26,-0.05,-0.0133,0.006];
end
38-35
38 System object Usage and Authoring
properties (DiscreteState)
State
end
function y = stepImpl(obj,u)
[y,obj.State] = filter(obj.Numerator,1,u,obj.State);
end
function resetImpl(obj)
obj.State = zeros(length(obj.Numerator)-1,1);
end
end
end
properties (Nontunable)
% Filter coefficients
Numerator = [0.006,0.0133,-0.05,-0.26,0.6,-0.26,-0.05,0.0133,0.006];
end
properties (DiscreteState)
State
end
function y = stepImpl(obj,u)
[y,obj.State] = filter(obj.Numerator,1,u,obj.State);
end
function resetImpl(obj)
obj.State = zeros(length(obj.Numerator)-1,1);
end
end
end
See Also
nargin
38-36
Define Finite Source Objects
In this section...
“Use the FiniteSource Class and Specify End of the Source” on page 38-37
“Complete Class Definition File with Finite Source” on page 38-37
function y = stepImpl(obj)
if ~obj.isDone()
obj.NumSteps = obj.NumSteps + 1;
y = obj.NumSteps;
else
y = 0;
end
end
38-37
38 System object Usage and Authoring
See Also
matlab.system.mixin.FiniteSource
More About
• “Subclassing Multiple Classes”
• “Using ~ as an Input Argument in Method Definitions” on page 38-51
38-38
Save and Load System Object
obj.protectedprop = s.protectedprop;
obj.pdependentprop = s.pdependentprop;
if isInUse
obj.state = s.state;
end
loadObjectImpl@matlab.System(obj,s,isInUse);
end
end
38-39
38 System object Usage and Authoring
end
methods (Access=protected)
function setupImpl(obj, ~)
obj.Count = 0;
end
function y = stepImpl(obj, u)
if u > 0
obj.Count = obj.Count + 1;
end
y = obj.Count;
end
end
end
properties (Dependent)
dependentprop
end
methods
function obj = MySaveLoader(varargin)
obj@matlab.System();
setProperties(obj,nargin,varargin{:});
end
38-40
Save and Load System Object
end
% Serialization
methods (Access = protected)
function s = saveObjectImpl(obj)
% Call the base class method
s = saveObjectImpl@matlab.System(obj);
function loadObjectImpl(obj,s,isInUse)
% Load child System objects
obj.child = matlab.System.loadObject(s.child);
See Also
saveObjectImpl | loadObjectImpl
38-41
38 System object Usage and Authoring
You can define your own info method to display specific information for your System object. The
default infoImpl method returns an empty struct. This infoImpl method returns detailed
information when info is called using info(x,'details') or only count information if it is called
using info(x).
properties
Threshold = 1
end
properties (DiscreteState)
Count
end
function resetImpl(obj)
obj.Count = 0;
end
function y = stepImpl(obj,u)
if (u > obj.Threshold)
obj.Count = obj.Count + 1;
end
y = obj.Count;
end
function s = infoImpl(obj,varargin)
if nargin>1 && strcmp('details',varargin(1))
s = struct('Name','Counter',...
'Properties', struct('CurrentCount', ...
obj.Count,'Threshold',obj.Threshold));
38-42
Define System Object Information
else
s = struct('Count',obj.Count);
end
end
end
end
See Also
infoImpl
38-43
38 System object Usage and Authoring
You can also restrict whether the input complexity, data type, or size can change while the object is in
use. Whichever aspects you restrict cannot change until after the user calls release.
This Counter System object restricts all three aspects of the input specification.
classdef Counter < matlab.System
%Counter Count values above a threshold
38-44
Handle Input Specification Changes
properties
Threshold = 1
end
properties (DiscreteState)
Count
end
methods
function obj = Counter(varargin)
setProperties(obj,nargin,varargin{:});
end
end
methods (Access=protected)
function resetImpl(obj)
obj.Count = 0;
end
See Also
isInputSizeMutableImpl
Related Examples
• “What You Cannot Change While Your System Is Running” on page 38-9
38-45
38 System object Usage and Authoring
The diagrams show an abstract view of which actions are performed when you call a System object.
The background color or each action indicates the type of call.
If you want a more detailed call sequence, see “Detailed Call Sequence” on page 38-49.
38-46
Summary of Call Sequence
38-47
38 System object Usage and Authoring
See Also
setupImpl | stepImpl | releaseImpl | resetImpl
Related Examples
• “Release System Object Resources” on page 38-22
• “Reset Algorithm State” on page 38-22
• “Set Property Values at Construction Time” on page 38-20
• “Define Basic System Objects” on page 38-11
38-48
Detailed Call Sequence
The call sequence diagrams show the order in which internal methods are called when you run the
specified method. If your System object does not overwrite a specified method, the default
implementation of that method is used.
If you want a more abstract view of the method calls, see “Summary of Call Sequence” on page 38-46.
1 If the System object is not in use (object was just created or was released),
Else, if the object is in use (object was called and release was not called)
i validatePropertiesImpl
38-49
38 System object Usage and Authoring
ii processTunedPropertiesImpl
b If the input size, data type, or complexity has changed
i validateInputsImpl
ii processInputSpecificationChangeImpl
1 If the object is in use (object was called and not released), call resetImpl
1 If the object is in use (object was called and not released), call releaseImpl
See Also
setupImpl | stepImpl | releaseImpl | resetImpl
Related Examples
• “Release System Object Resources” on page 38-22
• “Reset Algorithm State” on page 38-22
• “Set Property Values at Construction Time” on page 38-20
• “Define Basic System Objects” on page 38-11
38-50
Tips for Defining System Objects
General
• Define all one-time calculations in the setupImpl method and cache the results in a private
property. Use the stepImpl method for repeated calculations.
• Specify Boolean values using true or false instead of 1 or 0, respectively.
• If the variables in a method do not need to retain their values between calls, use local scope for
those variables in that method.
In many examples, instead of passing in the object handle, ~ is used to indicate that the object handle
is not used in the function. Using ~ instead of an object handle prevents warnings about unused
variables.
Properties
• For properties that do not change, define them in as Nontunable properties. Tunable properties
have slower access times than Nontunable properties
• Whenever possible, use the protected or private attribute instead of the public attribute for
a property. Some public properties have slower access times than protected and private
properties.
• If properties are accessed more than once in the stepImpl method, cache those properties as
local variables inside the method. A typical example of multiple property access is a loop. Iterative
calculations using cached local variables run faster than calculations that must access the
properties of an object. When the calculations for the method complete, you can save the local
cached results back to the properties of that System object. Copy frequently used tunable
properties into private properties. This best practice also applies to the updateImpl and
outputImpl methods.
38-51
38 System object Usage and Authoring
For example, in this code k is accessed multiple times in each loop iteration, but is saved to the
object property only once.
function y = stepImpl(obj,x)
k = obj.MyProp;
for p=1:100
y = k * x;
k = k + 0.1;
end
obj.MyProp = k;
end
• Default values of properties are shared across all instances of an object. Two instances of a class
can access the same default value if that property has not been overwritten by either instance.
Text Comparisons
Do not use character vector comparisons or character vector-based switch statements in the
stepImpl method. Instead, create a method handle in setupImpl. This handle points to a method in
the same class definition file. Use that handle in a loop in stepImpl.
This example shows how to use method handles and cached local variables in a loop to implement an
efficient object. In setupImpl, choose myMethod1 or myMethod2 based on a character vector
comparison and assign the method handle to the pMethodHandle property. Because there is a loop
in stepImpl, assign the pMethodHandle property to a local method handle, myFun, and then use
myFun inside the loop.
Simulink
For System objects being included in Simulink, add the StrictDefaults attribute. This attribute
sets all the MutableImpl methods to return false by default.
38-52
Tips for Defining System Objects
Code Generation
For information about System objects and code generation, see “System Objects in MATLAB Code
Generation” (MATLAB Coder).
38-53
38 System object Usage and Authoring
To access the System object editing options, create a new System object, or open an existing one.
To add predefined code to your System object, select the code from the appropriate menu. For
example, when you click Insert Property > Numeric, the MATLAB Editor adds the following code:
properties(Nontunable)
Property
end
The MATLAB Editor inserts the new property with the default name Property, which you can
rename. If you have an existing properties group with the Nontunable attribute, the MATLAB Editor
inserts the new property into that group. If you do not have a property group, the MATLAB Editor
creates one with the correct attribute.
38-54
Insert System Object Code Using MATLAB Editor
Insert Options
Properties Properties of the System object: Numeric, Logical, Enumeration, Positive Integer, Tunable
Numeric, Private, Protected, and Custom. When you select Enumeration or Custom Properties, a
separate dialog box opens to guide you in creating these properties.
Methods Methods commonly used in System object definitions. The MATLAB Editor creates only the
method structure. You specify the actions of that method.
The Insert Method menu organizes methods by categories, such as Algorithm, Inputs and
Outputs, and Properties and States. When you select a method from the menu, the MATLAB
Editor inserts the method template in your System object code. In this example, selecting Insert
Method > Release resources inserts the following code:
function releaseImpl(obj)
% Release resources, such as file handles
end
If a method from the Insert Method menu is present in the System object code, that method is
shown shaded on the Insert Method menu:
38-55
38 System object Usage and Authoring
Inputs / Inputs, outputs, and related methods, such as Validate inputs and Disallow input size
Outputs changes.
When you select an input or output, the MATLAB Editor inserts the specified code in the
stepImpl method. In this example, selecting Insert > Input causes the MATLAB Editor to
insert the required input variable u2. The MATLAB Editor determines the variable name, but
you can change it after it is inserted.
function y = stepImpl(obj,u,u2)
% Implement algorithm. Calculate y as a function of
% input u and discrete states.
y = u;
end
• Fahrenheit
• Celsius
• Kelvin
7 Select Fahrenheit as the default value by clicking Default.
38-56
Insert System Object Code Using MATLAB Editor
In the System object class definition, the following code was added:
properties(Nontunable)
TemperatureUnit (1, 1) TemperatureUnitValues = TemperatureUnitValues.Fahrenheit
end
For more information on enumerations, see “Limit Property Values to Finite List” on page 38-29.
38-57
38 System object Usage and Authoring
4 Click Insert and the following code is inserted into the System object definition:
properties(Nontunable, Constant)
Property
end
5 Replace Property with your property.
properties(Nontunable, Constant)
FreezingPointFahrenheit = 32;
end
The MATLAB Editor inserts this code into the System object:
function validateInputsImpl(obj,u)
% Validate inputs to the step method at initialization
end
See Also
Related Examples
• “Inspect System Object Code” on page 38-59
38-58
Inspect System Object Code
The Inspector displays an outline of all elements in the System object code.
• Navigate to a specific input, output, property, state, or method by clicking the name of that
element.
• Expand or collapse element sections with the arrow buttons.
• Identify access levels for properties and custom methods with the + (public), # (protected), and –
(private) symbols.
For example:
The cursor in the MATLAB Editor window goes to the resetImpl method.
38-59
38 System object Usage and Authoring
The Inspector provides warnings for legacy base classes, properties with legacy attributes, and
redundant methods. When a System object contains legacy code, the Inspector displays an Update
button that helps you replace or remove the legacy code.
The warnings and Update button are not available in MATLAB Online.
38-60
Inspect System Object Code
isDiscreteStateSpecificationMutableImpl, and
isTunablePropertyDataTypeMutableImpl when both of these conditions are met:
When the update modifies the System object code, a prompt lets you compare the updated code with
the previous version.
See Also
sysobjupdate
Related Examples
• “Insert System Object Code Using MATLAB Editor” on page 38-54
38-61
38 System object Usage and Authoring
You set up and use global variables for the MATLAB System block in the same way as you do for the
MATLAB Function block (see “Data Stores” (Simulink) and “Access Data Store Data in MATLAB
Function Blocks” (Simulink)). Like the MATLAB Function block, you must also use variable name
matching with a Data Store Memory block to use global variables in Simulink.
For example, this class definition file defines a System object that increments the first row of a matrix
by 1 at each time step. You must include getGlobalNamesImpl if the class file is P-coded.
This model includes the GlobalSysObjMatrix object in a MATLAB System block and the associated
Data Store Memory block.
38-62
Use Global Variables in System Objects
38-63
38 System object Usage and Authoring
38-64
Use Global Variables in System Objects
38-65
38 System object Usage and Authoring
This example shows how to create a System object™ that implements a moving average filter.
Introduction
System objects are MATLAB® classes that derive from matlab.System. As a result, System objects
all inherit a common public interface, which includes standard methods:
When you create new kinds of System objects, you provide specific implementations for all the
preceding methods to determine its behavior.
In this example, you create and use the movingAverageFilter System object.
movingAverageFilter is a System object that computes the unweighted mean of the previous
WindowLength input samples. WindowLength is the length of the moving average window.
movingAverageFilter accepts single-precision and double-precision 2-D input matrices. Each
column of the input matrix is treated as an independent (1-D) channel. The first dimension of the
input defines the length of the channel (or the input frame size). movingAverageFilter
independently computes the moving average of each input channel over time.
In the MATLAB Home tab, create a new System object class by selecting New > System Object >
Basic. The basic template for a System object opens in the MATLAB editor to guide you as you create
the movingAverageFilter System object.
Rename the class movingAverageFilter and save the file as movingAverageFilter.m. To ensure
you can use the System object, make sure you save the System object in a folder that is on the
MATLAB path.
For your convenience, a complete movingAverageFilter System object file is available with this
example. To open the completed class, enter:
edit movingAverageFilter.m
Add Properties
This System object needs four properties. First, add a public property WindowLength to control the
length of the moving average window. Because the algorithm depends on this value being constant
once data processing begins, the property is defined as nontunable. Additionally, the property only
accepts real, positive integers. To ensure input satisfies these conditions, add property validators (see
“Validate Property Values”). Set the default value of this property to 5.
properties(Nontunable)
WindowLength (1,1){mustBeInteger,mustBePositive} = 5
end
38-66
Create Moving Average System Object
Second, add two properties called State and pNumChannels. Users should not access either
property, so use the Access = private attribute. State saves the state of the moving average
filter. pNumChannels stores the number of channels in your input. The value of this property is
determined from the number of columns in the input.
properties(Access = private)
State;
pNumChannels = -1;
end
Finally, you need a property to store the FIR numerator coefficients. Add a property called
pCoefficients. Because the coefficients do not change during data processing and you do not want
users of the System object to access the coefficients, set the property attributes as Nontunable,
Access = private.
The System object constructor is a method that has the same name as the class
(movingAverageFilter in this example). You implement a System object constructor to allow
name-value pair inputs to the System object with the setProperties method. For example, with the
constructor, users can use this syntax to create an instance of the System object: filter =
movingAverageFilter('WindowLength',10). Do not use the constructor for anything else. All
other setup tasks should be written in the setupImpl method.
methods
function obj = movingAverageFilter(varargin)
% Support name-value pair arguments when constructing object
setProperties(obj,nargin,varargin{:})
end
end
The setupImpl method sets up the object and implements one-time initialization tasks. For this
System object, modify the default setupImpl method to calculate the filter coefficients, the state,
and the number of channels. The filter coefficients are computed based on the specified
WindowLength. The filter state is initialized to zero. (Note that there are WindowLength-1 states
per input channel.) Finally, the number of channels is determined from the number of columns in the
input.
For setupImpl and all Impl methods, you must set the method attribute Access = protected
because users of the System object do not call these methods directly. Instead the back-end of the
System object calls these methods through other user-facing functions.
function setupImpl(obj,x)
% Perform one-time calculations, such as computing constants
obj.pNumChannels = size(x,2);
obj.pCoefficients = ones(1,obj.WindowLength)/obj.WindowLength;
obj.State = zeros(obj.WindowLength-1,obj.pNumChannels,'like',x);
end
38-67
38 System object Usage and Authoring
The object's algorithm is defined in the stepImpl method. The algorithm in stepImpl is executed
when the user of the System object calls the object at the command line. In this example, modify
stepImpl to calculate the output and update the object's state values using the filter function.
function y = stepImpl(obj,u)
[y,obj.State] = filter(obj.pCoefficients,1,u,obj.State);
end
The state reset equations are defined in the resetImpl method. In this example, reset states to zero.
Additionally, you need to add a releaseImpl method. From the Editor toolstrip, select Insert
Method > Release resources. The releaseImpl method is added to your System object. Modify
releaseImpl to set the number of channels to -1, which allows new input to be used with the filter.
function resetImpl(obj)
% Initialize / reset discrete-state properties
obj.State(:) = 0;
end
function releaseImpl(obj)
obj.pNumChannels = -1;
end
Validate Input
To validate inputs to your System object, you must implement a validateInputsImpl method. This
method validates inputs at initialization and at each subsequent call where the input attributes (such
as dimensions, data type, or complexity) change. From the toolstrip, select Insert Method >
Validate inputs. In the newly inserted validateInputsImpl method, call validateattributes
to ensure that the input is a 2-D matrix with floating-point data.
function validateInputsImpl(~, u)
validateattributes(u,{'double','single'}, {'2d',...
'nonsparse'},'','input');
end
When you save an instance of a System object, saveObjectImpl defines what property and state
values are saved in a MAT-file. If you do not define a saveObjectImpl method for your System
object class, only public properties and properties with the DiscreteState attribute are saved.
Select Insert Method > Save in MAT-file. Modify saveObjectImpl so that if the object is locked,
the coefficients and number of channels is saved.
function s = saveObjectImpl(obj)
s = saveObjectImpl@matlab.System(obj);
if isLocked(obj)
s.pCoefficients = obj.pCoefficients;
s.pNumChannels = obj.pNumChannels;
end
end
38-68
Create Moving Average System Object
Method > Load from MAT-file. Modify loadObjectImpl so that if the object is locked, the
coefficients and number of channels are loaded.
function loadObjectImpl(obj,s,wasLocked)
if wasLocked
obj.pCoefficients = s.pCoefficients;
obj.pNumChannels = s.pNumChannels;
end
loadObjectImpl@matlab.System(obj,s,wasLocked);
end
Now that you have defined the System object, you can use the object in MATLAB. For example, use
movingAverageFilter to remove noise from a noisy pulse sequence.
movingAverageFilter = movingAverageFilter('WindowLength',10);
t = (1:250)';
signal = randn(250,1);
smoothedSignal = movingAverageFilter(signal);
plot(t,signal,t,smoothedSignal);
legend(["Input","Smoothed Signal"])
38-69
38 System object Usage and Authoring
To use your System object in Simulink®, see “Create Moving Average Filter Block with System
Object” (Simulink).
38-70
Create New System Objects for File Input and Output
This example shows how to create and use two different System objects to facilitate the streaming of
data in and out of MATLAB®: TextFileReader and TextFileWriter.
The objects discussed in this example address a number of realistic use cases, and they can be
customized to achieve more advanced and specialized tasks.
Introduction
System objects are MATLAB classes that derive from matlab.System. As a result, System objects all
inherit a common public interface, which includes standard methods:
When you create new kinds of System objects, you provide specific implementations for all the
preceding methods to determine its behavior.
In this example we discuss the internal structure and the use of the following two System objects:
• TextFileReader
• TextFileWriter
To create these System objects for streaming data in and out of MATLAB, this example uses standard
low-level file I/O functions available in MATLAB (like fscanf, fread, fprintf, and fwrite). By
abstracting away most usage details of those functions, they aim to make the task of reading and
writing streamed data simpler and more efficient.
This example includes the use of a number of advanced constructs to author System objects. For a
more basic introduction to authoring System objects, see “Create System Objects”.
The TextFileReader class includes a class definition, public and private properties, a constructor,
protected methods overridden from the matlab.System base class, and private methods. The
TextFileWriter class is similarly structured.
Class Definition
The class definition states that the TextFileReader class is derived from both matlab.System and
matlab.system.mixin.FiniteSource.
classdef (StrictDefaults)TextFileReader < matlab.System & matlab.system.mixin.FiniteSource
• matlab.System is required and is the base class for all System objects
• matlab.system.mixin.FiniteSource indicates this class is a signal source with a finite
number of data samples. For this type of class, in addition to the usual interface, the System
object™ will also expose the isDone function. When isDone returns true, the object reached the
end of the available data.
38-71
38 System object Usage and Authoring
Public Properties
Public properties can be changed by the user to adjust the behavior of the object to his or her
particular application. TextFileReader has two nontunable public properties (they can only be
changed before the first call to the object) and four tunable public properties. All the public
properties have a default value. Default values are assigned to the corresponding properties when
nothing else is specified by the user.
properties (Nontunable)
Filename = 'tempfile.txt'
HeaderLines = 4
end
properties
DataFormat = '%g'
Delimiter = ','
SamplesPerFrame = 1024
PlayCount = 1
end
Private Properties
Private properties are not visible to the user and can serve a number of purposes, including
• To hold values computed only occasionally, then used with subsequent calls to the algorithm. For
example, values used at initialization time, when setup is called or the object is called for the first
time. This can save recomputing them at runtime and improve the performance of the core
functionality
• To define the internal state of the object. For example, pNumEofReached stores the number of
times that the end-of-file indicator was reached:
properties(Access = private)
pFID = -1
pNumChannels
pLineFormat
pNumEofReached = 0
end
Constructor
The constructor is defined so that you can construct a TextFileReader object using name-value
pairs. The constructor is called when a new instance of TextDataReader is created. The call to
setProperties within the constructor allows setting properties with name-value pairs at
construction. No other initialization tasks should be specified in the constructor. Instead, use the
setupImpl method.
methods
function obj = TextFileReader(varargin)
setProperties(obj, nargin, varargin{:});
end
end
The public methods common to all System objects each have corresponding protected methods that
they call internally. The names of these protected methods all include an Impl postfix. They can be
implemented when defining the class to program the behavior of your System object.
38-72
Create New System Objects for File Input and Output
For more information on the correspondence between the standard public methods and their internal
implementations, please refer to “Summary of Call Sequence” on page 38-46.
• setupImpl
• resetImpl
• stepImpl
• releaseImpl
• isDoneImpl
• processTunedPropertiesImpl
• loadObjectImpl
• saveObjectImpl
Private Methods
Private methods are only accessible from within other methods of the same class. They can be used to
make the rest of the code more readable. They can also improve code reusability, by grouping under
separate routines code that is used multiple times in different parts of the class. For
TextFileReader, private methods are created for:
• getWorkingFID
• goToStartOfData
• peekCurrentLine
• lockNumberOfChannelsUsingCurrentLine
• readNDataRows
This example shows how you can use TextFileReader and TextFileWriter by:
• Creating a text file containing the samples of two different sinusoidal signals using
TextFileWriter
• Read from the text file using TextFileReader.
Create a new file to store two sinusoidal signals with frequencies of 50 Hz and 60 Hz. For each signal,
the data stored is composed of 800 samples at a sampling rate of 8 kHz.
fs = 8000;
tmax = 0.1;
t = (0:1/fs:tmax-1/fs)';
N = length(t);
f = [50,60];
data = sin(2*pi*t*f);
Form a header string to describe the data in a readable way for future use (optional step):
38-73
38 System object Usage and Authoring
To store the signal to a text file, create a TextFileWriter object. The constructor of
TextFileWriter needs the name of the target file and some optional parameters, which can be
passed in as name-value pairs.
TxtWriter = TextFileWriter('Filename','sinewaves.txt','Header',fileheader)
TxtWriter =
TextFileWriter with properties:
Filename: 'sinewaves.txt'
Header: 'The following contains 800 samples of two sinusoids,...'
DataFormat: '%.18g'
Delimiter: ','
TextFileWriter writes data to delimiter-separated ASCII files. Its public properties include:
• Filename — Name of the file to be written. If a file with this name already exists, it is
overwritten. When operations start, the object begins writing to the file immediately following the
header. The object then appends new data at each subsequent call to the object, until it is
released. Calling reset resumes writing from the beginning of the file.
• Header — Character string, often composed of multiple lines and terminated by a newline
character (\n). This is specified by the user and can be modified to embed human-readable
information that describes the actual data.
• DataFormat — Format used to store each data sample. This can take any value assignable as
Conversion Specifier within the formatSpec string used by the built-in MATLAB function
fprintf. DataFormat applies to all channels written to the file. The default value for this
property is '%.18g', which allows saving double precision floating point data in full precision.
• Delimiter — Character used to separate samples from different channels at the same time
instant. Every line of the written file maps to a time instant, and it includes as many samples as
the number of channels provided as input (in other words, the number of columns in the matrix
input passed to the object).
To write all the available data to the file, a single call to can be used.
TxtWriter(data)
The data is now stored in the new file. To visually inspect the file, type:
edit('sinewaves.txt')
Because the header takes up three lines, the data starts on line 4.
In this simple case, the length of the whole signal is small, and it fits comfortably on system memory.
Therefore, the data can be created all at once and written to a file in a single step.
There are cases when this approach is not possible or practical. For example, the data might be too
large to fit into a single MATLAB variable (too large to fit on system memory). Alternatively, the data
38-74
Create New System Objects for File Input and Output
might be created cyclically in a loop or streamed into MATLAB from an external source. In all these
cases, streaming the data into the file can be done with an approach similar to the following example.
Use a streamed sine wave generator to create a frame of data per loop. Run the desired number of
iterations to create the data and store it into the file:
frameLength = 32;
tmax = 10;
t = (0:1/fs:tmax-1/fs)';
N = length(t);
data = sin(2*pi*t*f);
numCycles = N/frameLength;
for k = 1:10 % Long running loop when you replace 10 with numCycles.
dataFrame = sin(2*pi*t*f);
TxtWriter(dataFrame)
end
release(TxtWriter)
TxtReader =
TextFileReader with properties:
Filename: 'sinewaves.txt'
HeaderLines: 3
DataFormat: '%g'
Delimiter: ','
SamplesPerFrame: 32
PlayCount: 1
TextFileReader reads numeric data from delimiter-separated ASCII files. Its properties are similar
to those of TextFileWriter. Some differences follow
• HeaderLines — Number of lines used by the header within the file specified in Filename. The
first call to the object starts reading from line number HeaderLines+1. Subsequent calls to the
object keep reading from the line immediately following the previously read line. Calling reset
will resume reading from line HeaderLines+1.
• Delimiter — Character used to separate samples from different channels at the same time
instant. In this case, the delimiter is also used to determine the number of data channels stored in
the file. When the object is first run, the object counts the number of Delimiter characters at
line HeaderLines+1, say numDel. Then for every time instant, the object reads numChan =
numDel+1 numeric values with format DataFormat. The matrix returned by the algorithm has
size SamplesPerFrame-by-numChan.
• SamplesPerFrame — Number of lines read by each call to the object. This value is also the
number of rows of the matrix returned as output. When the last available data rows are reached,
there might be fewer than the required SamplesPerFrame. In that case, the available data are
padded with zeros to obtain a matrix of size SamplesPerFrame-by-numChan. Once all the data
are read, the algorithm simply returns zeros(SamplesPerFrame,numChan) until reset or
release is called.
38-75
38 System object Usage and Authoring
• PlayCount — Number of times the data in the file is read cyclically. If the object reaches the end
of the file, and the file has not yet been read a number of times equal to PlayCount, reading
resumes from the beginning of the data (line HeaderLines+1). If the last lines of the file do not
provide enough samples to form a complete output matrix of size SamplesPerFrame-by-numChan,
then the frame is completed using the initial data. Once the file is read PlayCount times, the
output matrix returned by the algorithm is filled with zeros, and all calls to isDone return true
unless reset or release is called. To loop through the available data indefinitely, PlayCount
can be set to Inf.
To read the data from the text file, the more general streamed approach is used. This method of
reading data is also relevant to dealing with very large data files. Preallocate a data frame with
frameLength rows and 2 columns.
dataFrame = zeros(frameLength,2,'single');
Read from the text file and write to the binary file while data is present in the source text file. Notice
how the method isDone is used to control the execution of the while loop.
while(~isDone(TxtReader))
dataFrame(:) = TxtReader();
end
release(TxtReader)
Summary
This example illustrated how to author and use System objects to read from and write to numeric
data files. TextFileReader and TextFileWriter can be edited to perform special-purpose file
reading and writing operations. You can also combine these custom System objects with built-in
System objects such as dsp.BinaryFileWriter and dsp.BinaryFileReader.
For more information on authoring System objects for custom algorithms, see “Create System
Objects”.
See Also
More About
• “Create Moving Average System Object” on page 38-66
• “Tips for Defining System Objects” on page 38-51
• “Define Basic System Objects” on page 38-11
38-76
Create Composite System Object
This example shows how to create a System object™ composed of other System objects. This System
object uses two moving average System objects to find the cross-correlation of two independent
samples. The “Create Moving Average System Object” on page 38-66 example explains in detail how
to create a System object. This example focuses on how to use a System object within another System
object.
The ability to create more than one instance of a System object and having each instance manage its
own state is one of the biggest advantages of using System objects over functions. The private
properties MovingAverageFilter1 and MovingAverageFilter2 are used to store the two moving
average filter objects.
properties (Access=private)
% This example class contains two moving average filters (more can be added
% in the same way)
MovingAverageFilter1
MovingAverageFilter2
end
In the setupImpl method, create the two moving average System objects and initialize their public
properties.
function setupImpl(obj,~)
% Set up moving average objects with default values
obj.MovingAverageFilter1 = movingAverageFilter('WindowLength',obj.WindowLength1);
obj.MovingAverageFilter2 = movingAverageFilter('WindowLength',obj.WindowLength2);
end
The WindowLength public property from the movingAverageFilter System object is implemented
as a dependent property in this example.
properties(Nontunable,Dependent)
% WindowLength Moving window length
WindowLength1;
WindowLength2;
end
Whenever you assign a value to one of the dependent properties, the value is set in the corresponding
moving average filter. When you read one of the dependent properties, the value is read from the
corresponding moving average filter.
function set.WindowLength1(obj,WindowLength1)
% Set the window length of one moving average filter
obj.MovingAverageFilter1.WindowLength = WindowLength1;
end
function WindowLength = get.WindowLength1(obj)
% Read window length from one of the moving average filters
WindowLength = obj.MovingAverageFilter1.WindowLength;
end
38-77
38 System object Usage and Authoring
function set.WindowLength2(obj,WindowLength2)
% Set the window length of one moving average filter
obj.MovingAverageFilter2.WindowLength = WindowLength2;
end
function WindowLength = get.WindowLength2(obj)
% Read window length from one of the moving average filters
WindowLength = obj.MovingAverageFilter2.WindowLength;
end
Create random variables to calculate the cross-correlation of their moving averages, then view the
results in a stem plot.
x = rand(20,1);
y = rand(20,1);
crossCorr = crossCorrelationMovingAverages('WindowLength1',1,'WindowLength2',5);
38-78
Create Composite System Object
See Also
More About
• “Create Moving Average System Object” on page 38-66
• “Tips for Defining System Objects” on page 38-51
38-79