0% found this document useful (0 votes)
4 views

Python For Matlab Development Extend Matlab With 300000 Modules From The Python Package Index 1st Ed Danial download

The document is about the book 'Python for MATLAB Development' by Albert Danial, which focuses on extending MATLAB with over 300,000 modules from the Python Package Index. It includes various chapters covering installation, language basics, and data containers, aimed at helping users integrate Python with MATLAB effectively. Additionally, it provides links to related recommended products and resources for further exploration.

Uploaded by

shuseivoog
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Python For Matlab Development Extend Matlab With 300000 Modules From The Python Package Index 1st Ed Danial download

The document is about the book 'Python for MATLAB Development' by Albert Danial, which focuses on extending MATLAB with over 300,000 modules from the Python Package Index. It includes various chapters covering installation, language basics, and data containers, aimed at helping users integrate Python with MATLAB effectively. Additionally, it provides links to related recommended products and resources for further exploration.

Uploaded by

shuseivoog
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 86

Python For Matlab Development Extend Matlab With

300000 Modules From The Python Package Index 1st


Ed Danial download

https://ebookbell.com/product/python-for-matlab-development-
extend-matlab-with-300000-modules-from-the-python-package-
index-1st-ed-danial-38662504

Explore and download more ebooks at ebookbell.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

Dynamic System Modeling And Analysis With Matlab And Python For
Control Engineers Jongrae Kim

https://ebookbell.com/product/dynamic-system-modeling-and-analysis-
with-matlab-and-python-for-control-engineers-jongrae-kim-46431456

Computational Framework For The Finite Element Method In Matlab And


Python Pavel Sumets

https://ebookbell.com/product/computational-framework-for-the-finite-
element-method-in-matlab-and-python-pavel-sumets-43875848

Computational Framework For The Finite Element Method In Matlab And


Python Pavel Sumets

https://ebookbell.com/product/computational-framework-for-the-finite-
element-method-in-matlab-and-python-pavel-sumets-43892942

Python For Programmers Oswald Campesato

https://ebookbell.com/product/python-for-programmers-oswald-
campesato-45333572
Python For Data Analysis 3rd Wes Mckinney

https://ebookbell.com/product/python-for-data-analysis-3rd-wes-
mckinney-46540276

Python For Engineers And Scientists Rakesh Nayak Nishu Gupta

https://ebookbell.com/product/python-for-engineers-and-scientists-
rakesh-nayak-nishu-gupta-46814830

Python For Engineers And Scientists Concepts And Applications Rakesh


Nayak

https://ebookbell.com/product/python-for-engineers-and-scientists-
concepts-and-applications-rakesh-nayak-46844500

Python For Cybersecurity Using Python For Cyber Offense And Defense
Howard E Poston Iii

https://ebookbell.com/product/python-for-cybersecurity-using-python-
for-cyber-offense-and-defense-howard-e-poston-iii-46873132

Python For Probability Statistics And Machine Learning 3rd Edition 3rd
Edition Jos Unpingco

https://ebookbell.com/product/python-for-probability-statistics-and-
machine-learning-3rd-edition-3rd-edition-jos-unpingco-47165906
Python for
MATLAB
Development
Extend MATLAB with 300,000+
Modules from the Python Package Index

Albert Danial
Python for MATLAB
Development
Extend MATLAB with 300,000+
Modules from the Python
Package Index

Albert Danial
Python for MATLAB Development: Extend MATLAB with 300,000+ Modules from the
Python Package Index
Albert Danial
Redondo Beach, CA, USA

ISBN-13 (pbk): 978-1-4842-7222-0 ISBN-13 (electronic): 978-1-4842-7223-7


https://doi.org/10.1007/978-1-4842-7223-7

Copyright © 2022 by Albert Danial


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Steve Anglin
Development Editor: James Markham
Coordinating Editor: Mark Powers
Cover designed by eStudioCalamar
Cover image by Shutterstock (www.shutterstock.com)
Distributed to the book trade worldwide by Apress Media, LLC, 1 New York Plaza, New York, NY 10004,
U.S.A. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail [email protected], or visit www.
springeronline.com. Apress Media, LLC is a California LLC and the sole member (owner) is Springer Science
+ Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation.
For information on translations, please e-mail [email protected]; for reprint,
paperback, or audio rights, please e-mail [email protected].
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available to
readers on GitHub at https://github.com/Apress/python-­for-­matlab-­development. For more detailed
information, please visit http://www.apress.com/source-­code.
Printed on acid-free paper
To Ashley, Theodore, Mimi
Table of Contents
About the Author����������������������������������������������������������������������������������������������������xxi

About the Technical Reviewers����������������������������������������������������������������������������xxiii


Preface������������������������������������������������������������������������������������������������������������������xxv

Acknowledgments�����������������������������������������������������������������������������������������������xxvii

Chapter 1: Introduction�������������������������������������������������������������������������������������������� 1
1.1 Learn Python Through MATLAB Equivalents��������������������������������������������������������������������������� 2
1.2 Is Python Really Free?������������������������������������������������������������������������������������������������������������� 4
1.3 What About Toolboxes?����������������������������������������������������������������������������������������������������������� 5
1.4 Why Python Won’t Replace MATLAB��������������������������������������������������������������������������������������� 5
1.5 Contents at a Glance��������������������������������������������������������������������������������������������������������������� 6
1.6 I Already Know Python. How Do I Call Python Functions in MATLAB?������������������������������������� 8
1.7 The Recipes Don’t Work! MATLAB Crashes! (and What to Do About It)����������������������������������� 8

Chapter 2: Installation�������������������������������������������������������������������������������������������� 11
2.1 Downloads���������������������������������������������������������������������������������������������������������������������������� 11
2.1.1 Match Your Python and MATLAB Versions!������������������������������������������������������������������� 12
2.1.2 Verify That Python Runs������������������������������������������������������������������������������������������������ 12
2.2 Post-Install Configuration and Checkout������������������������������������������������������������������������������� 12
2.3 Creating and Running a Python Program������������������������������������������������������������������������������ 14
2.4 The Curse of Choice�������������������������������������������������������������������������������������������������������������� 15
2.5 V irtual Environments������������������������������������������������������������������������������������������������������������� 15
2.5.1 matpy, the Virtual Environment Used in This Book������������������������������������������������������� 16
2.5.2 Commands to Manage Virtual Environments���������������������������������������������������������������� 17
2.5.3 Keeping Your Virtual Environment Current������������������������������������������������������������������� 18

v
Table of Contents

2.6 ipython, IDEs������������������������������������������������������������������������������������������������������������������������� 20


2.6.1 Autoload Modules When ipython Starts������������������������������������������������������������������������ 20
2.7 Python and MATLAB Versions Used in This Book������������������������������������������������������������������ 21

Chapter 3: Language Basics����������������������������������������������������������������������������������� 23


3.1 Assignment��������������������������������������������������������������������������������������������������������������������������� 23
3.1.1 Assignment with =������������������������������������������������������������������������������������������������������� 23
3.1.2 In-Place Updates with +=, -=, and Others������������������������������������������������������������������� 25
3.1.3 Walrus Operator, =�������������������������������������������������������������������������������������������������������� 26
3.2 P rinting��������������������������������������������������������������������������������������������������������������������������������� 27
3.3 I ndentation���������������������������������������������������������������������������������������������������������������������������� 28
3.3.1 T abs������������������������������������������������������������������������������������������������������������������������������ 30
3.4 I ndexing�������������������������������������������������������������������������������������������������������������������������������� 30
3.4.1 Brackets vs. Parentheses��������������������������������������������������������������������������������������������� 30
3.4.2 Zero-Based Indexing and Index Ranges����������������������������������������������������������������������� 30
3.4.3 Start, End, and Negative Indices����������������������������������������������������������������������������������� 31
3.4.4 I ndex Strides����������������������������������������������������������������������������������������������������������������� 32
3.4.5 I ndex Chaining�������������������������������������������������������������������������������������������������������������� 32
3.5 f or loops�������������������������������������������������������������������������������������������������������������������������������� 33
3.5.1 Early Loop Exits������������������������������������������������������������������������������������������������������������ 36
3.5.2 Exit from Nested Loops������������������������������������������������������������������������������������������������ 36
3.6 w
 hile Loops��������������������������������������������������������������������������������������������������������������������������� 37
3.7 i f Statements������������������������������������������������������������������������������������������������������������������������� 38
3.7.1 Boolean Expressions and Operators����������������������������������������������������������������������������� 39
3.7.2 R
 ange Tests������������������������������������������������������������������������������������������������������������������ 39
3.8 F unctions������������������������������������������������������������������������������������������������������������������������������ 40
3.8.1 Pass by Value and Pass by Reference�������������������������������������������������������������������������� 41
3.8.2 V ariable Arguments������������������������������������������������������������������������������������������������������ 43
3.8.3 K
 eyword Arguments����������������������������������������������������������������������������������������������������� 44

vi
Table of Contents

3.8.4 Decorators�������������������������������������������������������������������������������������������������������������������� 46
3.8.5 Type Annotation and Argument Validation�������������������������������������������������������������������� 47
3.8.6 Left-Hand Side Argument Count����������������������������������������������������������������������������������� 49
3.9 Generators���������������������������������������������������������������������������������������������������������������������������� 50
3.9.1 y ield, next()������������������������������������������������������������������������������������������������������������������� 50
3.9.2 r ange()�������������������������������������������������������������������������������������������������������������������������� 51
3.10 Scoping Rules and Global Variables������������������������������������������������������������������������������������ 52
3.11 C
 omments��������������������������������������������������������������������������������������������������������������������������� 54
3.11.1 D
 ocstrings������������������������������������������������������������������������������������������������������������������ 54
3.12 L ine Continuation���������������������������������������������������������������������������������������������������������������� 56
3.13 E xceptions��������������������������������������������������������������������������������������������������������������������������� 56
3.14 Modules and Packages������������������������������������������������������������������������������������������������������� 58
3.14.1 N
 amespace����������������������������������������������������������������������������������������������������������������� 58
3.14.2 d ef main()������������������������������������������������������������������������������������������������������������������� 60
3.14.3 Module Search Path��������������������������������������������������������������������������������������������������� 61
3.14.4 Installing New Modules���������������������������������������������������������������������������������������������� 62
3.14.5 Module Dependency Conflicts and Virtual Environments������������������������������������������� 63

Chapter 4: Data Containers������������������������������������������������������������������������������������� 65


4.1 NumPy Arrays����������������������������������������������������������������������������������������������������������������������� 66
4.2 Strings����������������������������������������������������������������������������������������������������������������������������������� 68
4.2.1 Strings, Character Arrays, and Byte Arrays������������������������������������������������������������������� 68
4.2.2 String Operations���������������������������������������������������������������������������������������������������������� 70
4.2.3 Formatting�������������������������������������������������������������������������������������������������������������������� 74
4.2.4 Separate a String into Words���������������������������������������������������������������������������������������� 75
4.2.5 Tests on Strings������������������������������������������������������������������������������������������������������������ 76
4.2.6 String Searching, Replacing with Regular Expressions������������������������������������������������ 77
4.2.7 S
 tring Templates����������������������������������������������������������������������������������������������������������� 80
4.3 Python Lists and MATLAB Cell Arrays����������������������������������������������������������������������������������� 81
4.3.1 Initialize an Empty List������������������������������������������������������������������������������������������������� 82
4.3.2 Create a List with Given Values������������������������������������������������������������������������������������ 83

vii
Table of Contents

4.3.3 Get the Length of a List������������������������������������������������������������������������������������������������ 83


4.3.4 Index a List Item����������������������������������������������������������������������������������������������������������� 84
4.3.5 Extract a Range of Items���������������������������������������������������������������������������������������������� 85
4.3.6 Warning—Python Index Ranges Are Not Checked!������������������������������������������������������ 87
4.3.7 Append an Item������������������������������������������������������������������������������������������������������������ 90
4.3.8 A
 ppend Another List����������������������������������������������������������������������������������������������������� 91
4.3.9 Preallocate an Empty List��������������������������������������������������������������������������������������������� 92
4.3.10 Insert to the Beginning (or Any Other Position) of a List��������������������������������������������� 93
4.3.11 Indexing Nested Containers���������������������������������������������������������������������������������������� 93
4.3.12 Membership Test: Does an Item Exist in a List?��������������������������������������������������������� 94
4.3.13 Find the Index of an Item�������������������������������������������������������������������������������������������� 95
4.3.14 Apply an Operation to All Items (List Comprehension)������������������������������������������������ 97
4.3.15 Select a Subset of Items Based on a Condition���������������������������������������������������������� 98
4.3.16 How Many Times Does an Item Occur?���������������������������������������������������������������������� 99
4.3.17 Remove the First or Last (or Any Intermediate) List Item������������������������������������������� 99
4.3.18 Remove an Item by Value����������������������������������������������������������������������������������������� 100
4.3.19 Merging Multiple Lists���������������������������������������������������������������������������������������������� 101
4.3.20 Unmerging Combined Lists�������������������������������������������������������������������������������������� 103
4.3.21 Sort a List����������������������������������������������������������������������������������������������������������������� 105
4.3.22 Reverse a List����������������������������������������������������������������������������������������������������������� 106
4.4 P ython Tuples���������������������������������������������������������������������������������������������������������������������� 106
4.5 Python Sets and MATLAB Set Operations��������������������������������������������������������������������������� 109
4.6 Python Dictionaries and MATLAB Maps������������������������������������������������������������������������������ 111
4.6.1 Iterating over Keys������������������������������������������������������������������������������������������������������ 112
4.6.2 Testing for Key Existence�������������������������������������������������������������������������������������������� 113
4.6.3 Iterating over Keys, Sorting by Key����������������������������������������������������������������������������� 115
4.6.4 Iterating over Keys, Sorting by Value�������������������������������������������������������������������������� 117
4.6.5 T uples As Keys������������������������������������������������������������������������������������������������������������ 119
4.6.6 L ist Values������������������������������������������������������������������������������������������������������������������ 120

viii
Table of Contents

4.7 Structured Data������������������������������������������������������������������������������������������������������������������� 120


4.7.1 Method 1: namedtuple������������������������������������������������������������������������������������������������ 121
4.7.2 Method 2: SimpleNamespace������������������������������������������������������������������������������������� 121
4.7.3 Method 3: Classes������������������������������������������������������������������������������������������������������ 122
4.7.4 Method 4: Data Classes���������������������������������������������������������������������������������������������� 124
4.7.5 Enumerations������������������������������������������������������������������������������������������������������������� 132
4.8 Caveat: “=” Copies a Reference for Nonscalars!���������������������������������������������������������������� 134

Chapter 5: Dates and Times���������������������������������������������������������������������������������� 137


5.1 Time������������������������������������������������������������������������������������������������������������������������������������ 137
5.1.1 Current Time��������������������������������������������������������������������������������������������������������������� 137
5.1.2 Time String Formats��������������������������������������������������������������������������������������������������� 138
5.1.3 tic, toc; %timeit����������������������������������������������������������������������������������������������������������� 140
5.2 Dates����������������������������������������������������������������������������������������������������������������������������������� 141
5.2.1 datetime Objects to and from Strings������������������������������������������������������������������������ 141
5.2.2 Time Deltas����������������������������������������������������������������������������������������������������������������� 142
5.3 Timezones��������������������������������������������������������������������������������������������������������������������������� 144
5.3.1 UTC vs. Local Time����������������������������������������������������������������������������������������������������� 146
5.4 Time Conversions to and from datetime Objects���������������������������������������������������������������� 148
5.4.1 Unix Epoch Seconds��������������������������������������������������������������������������������������������������� 148
5.4.2 ISO 8601 Time String�������������������������������������������������������������������������������������������������� 149
5.4.3 Julian Date; Modified Julian Date; GPS Time������������������������������������������������������������� 150
5.5 zoneinfo in Python >= 3.9�������������������������������������������������������������������������������������������������� 151
5.5.1 L ist Available Timezones��������������������������������������������������������������������������������������������� 152
5.5.2 Date Increments Across Daylight Savings Transition������������������������������������������������� 152
5.6 R
 eferences�������������������������������������������������������������������������������������������������������������������������� 153

Chapter 6: Call Python Functions from MATLAB��������������������������������������������������� 155


6.1 Configure MATLAB to Recognize Python����������������������������������������������������������������������������� 155
6.2 Does It Work?���������������������������������������������������������������������������������������������������������������������� 157
6.3 Importing (and Reloading) Python Modules������������������������������������������������������������������������ 159
6.4 Configure startup.m for Python Work���������������������������������������������������������������������������������� 159
ix
Table of Contents

6.5 Create Python Variables and Call Python Functions in MATLAB������������������������������������������ 161
6.5.1 Scalars������������������������������������������������������������������������������������������������������������������������ 161
6.5.2 Lists and Cell Arrays��������������������������������������������������������������������������������������������������� 163
6.5.3 Tuples������������������������������������������������������������������������������������������������������������������������� 165
6.5.4 Numeric Arrays����������������������������������������������������������������������������������������������������������� 166
6.5.5 Dictionaries and Structs��������������������������������������������������������������������������������������������� 168
6.5.6 Keyword Arguments��������������������������������������������������������������������������������������������������� 171
6.5.7 Python-to-MATLAB and MATLAB-to-Python Variable Converters������������������������������� 172
6.5.8 Traversing Generators������������������������������������������������������������������������������������������������� 172
6.5.9 Traversing zip()����������������������������������������������������������������������������������������������������������� 174
6.6 Modifying the Python Search Path Within MATLAB������������������������������������������������������������� 174
6.6.1 Extending sys.path with an Alias�������������������������������������������������������������������������������� 175
6.6.2 Extending sys.path with insert()��������������������������������������������������������������������������������� 175
6.6.3 Extending sys.path with append()������������������������������������������������������������������������������ 176
6.7 Python Bridge Modules������������������������������������������������������������������������������������������������������� 177
6.8 Debugging Python Code Called by MATLAB������������������������������������������������������������������������ 178
6.9 Summary of Steps to Calling Python Code from MATLAB��������������������������������������������������� 181
6.10 Call MATLAB from Python������������������������������������������������������������������������������������������������� 182
6.10.1 I nstall matlab.engine������������������������������������������������������������������������������������������������ 182
6.10.2 Call Functions in a New MATLAB Session���������������������������������������������������������������� 183
6.10.3 Call Functions in an Existing MATLAB Session��������������������������������������������������������� 184
6.11 Other Mechanisms for MATLAB/Python Interaction���������������������������������������������������������� 186
6.11.1 System Calls and File I/O������������������������������������������������������������������������������������������ 186
6.11.2 T CP/IP Exchange������������������������������������������������������������������������������������������������������� 188

Chapter 7: Input and Output��������������������������������������������������������������������������������� 189


7.1 Text Files����������������������������������������������������������������������������������������������������������������������������� 189
7.1.1 Reading Corrupted Text Files with pathlib������������������������������������������������������������������ 191
7.1.2 Reading and Writing Numeric Data���������������������������������������������������������������������������� 192
7.1.3 I/O Exceptions������������������������������������������������������������������������������������������������������������� 192
7.1.4 Parsing Text���������������������������������������������������������������������������������������������������������������� 193

x
Table of Contents

7.1.5 csv������������������������������������������������������������������������������������������������������������������������������ 199


7.1.6 XML���������������������������������������������������������������������������������������������������������������������������� 203
7.1.7 YAML��������������������������������������������������������������������������������������������������������������������������� 212
7.1.8 JSON��������������������������������������������������������������������������������������������������������������������������� 213
7.1.9 ini�������������������������������������������������������������������������������������������������������������������������������� 214
7.2 Recipe 7-1: Read YAML Files���������������������������������������������������������������������������������������������� 216
7.3 Recipe 7-2: Write YAML Files���������������������������������������������������������������������������������������������� 217
7.4 Recipe 7-3: Read an ini File������������������������������������������������������������������������������������������������ 218
7.5 Recipe 7-4: Write an ini File������������������������������������������������������������������������������������������������ 220
7.6 B
 inary Files������������������������������������������������������������������������������������������������������������������������� 222
7.7 Excel .xls, .xlsx�������������������������������������������������������������������������������������������������������������������� 225
7.7.1 Reading .xls and .xlsx Files���������������������������������������������������������������������������������������� 226
7.7.2 W
 riting .xlsx Files������������������������������������������������������������������������������������������������������� 231
7.8 Recipe 7-5: Write an .xlsx File��������������������������������������������������������������������������������������������� 234
7.9 H
 DF5����������������������������������������������������������������������������������������������������������������������������������� 237
7.9.1 Reading an HDF5 File������������������������������������������������������������������������������������������������� 237
7.9.2 Writing an HDF5 File��������������������������������������������������������������������������������������������������� 239
7.9.3 Reading and Writing HDF5 Dataset Attributes������������������������������������������������������������ 243
7.9.4 Iterating over All HDF5 Datasets��������������������������������������������������������������������������������� 244
7.10 N
 etCDF4���������������������������������������������������������������������������������������������������������������������������� 246
7.10.1 Reading a NetCDF4 File�������������������������������������������������������������������������������������������� 246
7.11 S
 QLite�������������������������������������������������������������������������������������������������������������������������������� 249
7.12 Recipe 7-6: CRUD with an SQLite Database���������������������������������������������������������������������� 252
7.13 P ickle Files������������������������������������������������������������������������������������������������������������������������ 255
7.14 MATLAB .mat Files������������������������������������������������������������������������������������������������������������ 257
7.14.1 Inspecting the Contents of a .mat File���������������������������������������������������������������������� 258
7.14.2 Reading a .mat File��������������������������������������������������������������������������������������������������� 260
7.14.3 Writing a .mat File���������������������������������������������������������������������������������������������������� 262
7.14.4 m
 at Version 7.3��������������������������������������������������������������������������������������������������������� 267

xi
Table of Contents

7.15 Command-Line Input�������������������������������������������������������������������������������������������������������� 268


7.15.1 Python: sys.argv������������������������������������������������������������������������������������������������������� 269
7.15.2 MATLAB: Function Arguments; varargin������������������������������������������������������������������� 270
7.15.3 Python: argparse������������������������������������������������������������������������������������������������������ 271
7.16 Interactive Input���������������������������������������������������������������������������������������������������������������� 275
7.17 Receiving and Sending over a Network���������������������������������������������������������������������������� 276
7.17.1 HTTP, HTTPS�������������������������������������������������������������������������������������������������������������� 276
7.17.2 Python As a Web Server������������������������������������������������������������������������������������������� 278
7.17.3 TCP/IP����������������������������������������������������������������������������������������������������������������������� 280
7.18 Recipe 7-7: TCP Server����������������������������������������������������������������������������������������������������� 284
7.19 Interacting with Databases����������������������������������������������������������������������������������������������� 286
7.19.1 PostgreSQL��������������������������������������������������������������������������������������������������������������� 286
7.19.2 MongoDB������������������������������������������������������������������������������������������������������������������ 290
7.20 Recipe 7-8: CRUD with a PostgreSQL Database��������������������������������������������������������������� 293
7.21 Recipe
 7-9: CRUD with a MongoDB Database������������������������������������������������������������������ 296
7.21.1 Read������������������������������������������������������������������������������������������������������������������������� 298
7.21.2 Update���������������������������������������������������������������������������������������������������������������������� 300
7.21.3 Delete����������������������������������������������������������������������������������������������������������������������� 300
7.22 Recipe 7-10: Interact with Redis��������������������������������������������������������������������������������������� 300
7.23 Reference�������������������������������������������������������������������������������������������������������������������������� 305

Chapter 8: Interacting with the File System��������������������������������������������������������� 307


8.1 Reading Directory Contents������������������������������������������������������������������������������������������������ 308
8.2 Finding Files������������������������������������������������������������������������������������������������������������������������ 309
8.3 Deleting Files���������������������������������������������������������������������������������������������������������������������� 309
8.4 C
 reating Directories������������������������������������������������������������������������������������������������������������ 310
8.5 D
 eleting Directories������������������������������������������������������������������������������������������������������������ 310
8.6 W
 alking Directory Trees������������������������������������������������������������������������������������������������������ 311

xii
Table of Contents

Chapter 9: Interacting with the Operating System and External Executables������ 315
9.1 Reading, Setting Environment Variables����������������������������������������������������������������������������� 315
9.2 Calling External Executables���������������������������������������������������������������������������������������������� 317
9.2.1 Checking for Failures�������������������������������������������������������������������������������������������������� 319
9.2.2 A Bytes-Like Object Is Required��������������������������������������������������������������������������������� 321
9.3 Inspecting the Process Table and Process Resources�������������������������������������������������������� 322

Chapter 10: Object-Oriented Programming���������������������������������������������������������� 327


10.1 Classes������������������������������������������������������������������������������������������������������������������������������ 327
10.1.1 Private vs. Public������������������������������������������������������������������������������������������������������ 329
10.1.2 Custom Printers�������������������������������������������������������������������������������������������������������� 330
10.1.3 Custom Exceptions��������������������������������������������������������������������������������������������������� 331
10.2 Performance Implications������������������������������������������������������������������������������������������������� 333

Chapter 11: NumPy and SciPy������������������������������������������������������������������������������ 335


11.1 NumPy Arrays������������������������������������������������������������������������������������������������������������������� 335
11.1.1 Formatting NumPy Array Values������������������������������������������������������������������������������� 336
11.1.2 Differences Between NumPy Arrays and MATLAB Matrices������������������������������������� 338
11.1.3 NumPy Data Types���������������������������������������������������������������������������������������������������� 341
11.1.4 Typecasting Scalars and Arrays�������������������������������������������������������������������������������� 343
11.1.5 Hex, Binary, and Decimal Representations��������������������������������������������������������������� 344
11.1.6 Creating Arrays��������������������������������������������������������������������������������������������������������� 345
11.1.7 Complex Scalars and Arrays������������������������������������������������������������������������������������� 355
11.1.8 L inear Indexing��������������������������������������������������������������������������������������������������������� 357
11.1.9 Reading/Writing Arrays to/from Text Files���������������������������������������������������������������� 359
11.1.10 Reading/Writing Arrays to/from Binary Files���������������������������������������������������������� 360
11.1.11 P rimitive Array Operations�������������������������������������������������������������������������������������� 368
11.1.12 A
 dding Dimensions������������������������������������������������������������������������������������������������� 371
11.1.13 A
 rray Broadcasting������������������������������������������������������������������������������������������������� 373
11.1.14 I ndex Masks����������������������������������������������������������������������������������������������������������� 377
11.1.15 Extracting and Updating Submatrices�������������������������������������������������������������������� 380

xiii
Table of Contents

11.1.16 Finding Terms of Interest���������������������������������������������������������������������������������������� 383


11.1.17 Object-Oriented Programming and Computational Performance��������������������������� 388
11.2 Linear Algebra������������������������������������������������������������������������������������������������������������������� 394
11.2.1 Linear Equations������������������������������������������������������������������������������������������������������� 395
11.2.2 Singular Value Decomposition���������������������������������������������������������������������������������� 397
11.2.3 Eigenvalue Problems������������������������������������������������������������������������������������������������ 398
11.3 Sparse Matrices���������������������������������������������������������������������������������������������������������������� 401
11.3.1 Sparse Matrix Creation with COO, CSC, CSR������������������������������������������������������������� 401
11.3.2 Sparse Matrix Creation with LIL, DOK����������������������������������������������������������������������� 408
11.3.3 Sparse Matrix Creation with BSR, DIA���������������������������������������������������������������������� 411
11.3.4 Test Matrices������������������������������������������������������������������������������������������������������������ 413
11.3.5 Sparse Matrix I/O������������������������������������������������������������������������������������������������������ 415
11.3.6 Linear Algebra���������������������������������������������������������������������������������������������������������� 418
11.3.7 Summary of Sparse Formats and Capabilities; Recommendations������������������������� 424
11.4 Interpolation���������������������������������������������������������������������������������������������������������������������� 426
11.4.1 One-Dimensional Interpolation��������������������������������������������������������������������������������� 426
11.4.2 Two-Dimensional Interpolation��������������������������������������������������������������������������������� 429
11.4.3 Two-Dimensional Interpolation on a Grid����������������������������������������������������������������� 435
11.5 Curve Fitting���������������������������������������������������������������������������������������������������������������������� 437
11.5.1 Linear Regression����������������������������������������������������������������������������������������������������� 437
11.5.2 Fitting Higher-Order Polynomials����������������������������������������������������������������������������� 438
11.5.3 Fitting to Models������������������������������������������������������������������������������������������������������� 439
11.6 Recipe 11-1: Curve Fitting with differential_evolution()��������������������������������������������������� 447
11.7 Regression������������������������������������������������������������������������������������������������������������������������ 449
11.7.1 Ordinary Least Squares�������������������������������������������������������������������������������������������� 449
11.7.2 Weighted Least Squares������������������������������������������������������������������������������������������� 452
11.7.3 Confidence and Prediction Intervals������������������������������������������������������������������������� 453
11.8 Recipe 11-2: Weighted Least Squares in MATLAB������������������������������������������������������������ 457
11.9 Recipe 11-3: Confidence and Prediction Intervals in MATLAB������������������������������������������ 460

xiv
Table of Contents

11.10 Finding Roots������������������������������������������������������������������������������������������������������������������ 463


11.10.1 Univariate��������������������������������������������������������������������������������������������������������������� 463
11.10.2 Multivariate������������������������������������������������������������������������������������������������������������ 465
11.11 Recipe 11-4: Solving Simultaneous Nonlinear Equations����������������������������������������������� 466
11.12 Optimization�������������������������������������������������������������������������������������������������������������������� 467
11.12.1 Linear Programming����������������������������������������������������������������������������������������������� 468
11.12.2 Simulated Annealing����������������������������������������������������������������������������������������������� 474
11.13 Differential Equations������������������������������������������������������������������������������������������������������ 479
11.14 Symbolic Mathematics��������������������������������������������������������������������������������������������������� 481
11.14.1 Defining Symbolic Variables����������������������������������������������������������������������������������� 482
11.14.2 Derivatives�������������������������������������������������������������������������������������������������������������� 482
11.14.3 Integrals����������������������������������������������������������������������������������������������������������������� 483
11.14.4 Solving Equations��������������������������������������������������������������������������������������������������� 484
11.14.5 Linear Algebra�������������������������������������������������������������������������������������������������������� 484
11.14.6 Series��������������������������������������������������������������������������������������������������������������������� 486
11.15 Recipe 11-5: Using SymPy in MATLAB���������������������������������������������������������������������������� 486
11.16 Recipe 11-6: Compute Laplace Transforms�������������������������������������������������������������������� 487
11.17 Unit Systems������������������������������������������������������������������������������������������������������������������� 488
11.17.1 Defining Units in pint���������������������������������������������������������������������������������������������� 489
11.18 Recipe 11-7: Using pint in MATLAB��������������������������������������������������������������������������������� 491
11.19 References���������������������������������������������������������������������������������������������������������������������� 492

Chapter 12: Plotting���������������������������������������������������������������������������������������������� 493


12.1 Point and Line Plots���������������������������������������������������������������������������������������������������������� 493
12.1.1 Saving Plots to Files������������������������������������������������������������������������������������������������� 496
12.1.2 Multiple Plots per Figure������������������������������������������������������������������������������������������ 497
12.1.3 Date and Time on the X Axis������������������������������������������������������������������������������������� 499
12.1.4 Double Y Axes����������������������������������������������������������������������������������������������������������� 500
12.1.5 Histograms��������������������������������������������������������������������������������������������������������������� 502
12.1.6 Stack Plots���������������������������������������������������������������������������������������������������������������� 504

xv
Table of Contents

12.2 Area Plots�������������������������������������������������������������������������������������������������������������������������� 505


12.2.1 imshow()������������������������������������������������������������������������������������������������������������������� 505
12.3 Animations������������������������������������������������������������������������������������������������������������������������ 510
12.4 Plotting on Maps with Cartopy������������������������������������������������������������������������������������������ 514
12.4.1 Points������������������������������������������������������������������������������������������������������������������������ 514
12.4.2 Lines������������������������������������������������������������������������������������������������������������������������� 517
12.4.3 Area�������������������������������������������������������������������������������������������������������������������������� 519
12.4.4 MATLAB and Cartopy������������������������������������������������������������������������������������������������ 527
12.4.5 Avoid matplotlib’s Qt Backend in MATLAB!��������������������������������������������������������������� 529
12.5 Recipe 12-1: Drawing Lines on Maps with Cartopy���������������������������������������������������������� 529
12.6 Recipe 12-2: Overlay Contours on Globe with Cartopy����������������������������������������������������� 531
12.7 Recipe 12-3: Shade Map Regions by Value with Cartopy������������������������������������������������� 532
12.8 Plotting on Maps with GeoPandas������������������������������������������������������������������������������������ 535
12.9 Making
 Plots in Batch Mode��������������������������������������������������������������������������������������������� 535
12.10 Interactive
 Plot Editing���������������������������������������������������������������������������������������������������� 536

Chapter 13: Tables and Dataframes���������������������������������������������������������������������� 539


13.1 Loading Tables from Files������������������������������������������������������������������������������������������������� 540
13.2 Table Summaries�������������������������������������������������������������������������������������������������������������� 543
13.2.1 Table Size, Column Names, Column Types���������������������������������������������������������������� 543
13.2.2 summary() and .info()/.describe()����������������������������������������������������������������������������� 545
13.2.3 groupsummary() and .value_counts()����������������������������������������������������������������������� 546
13.2.4 head() and tail()�������������������������������������������������������������������������������������������������������� 546
13.3 Cleaning Data�������������������������������������������������������������������������������������������������������������������� 547
13.3.1 Renaming Columns�������������������������������������������������������������������������������������������������� 547
13.3.2 Changing Column Data Types����������������������������������������������������������������������������������� 548
13.3.3 Changing Column Data��������������������������������������������������������������������������������������������� 549
13.3.4 Making Timestamps from Strings���������������������������������������������������������������������������� 550
13.4 Creating Tables Programmatically������������������������������������������������������������������������������������ 550
13.5 Sorting Rows��������������������������������������������������������������������������������������������������������������������� 551

xvi
Table of Contents

13.6 Table Subsets�������������������������������������������������������������������������������������������������������������������� 552


13.6.1 All Rows, Selected Columns������������������������������������������������������������������������������������� 552
13.6.2 All Columns, Selected Rows������������������������������������������������������������������������������������� 553
13.6.3 Selected Rows, Selected Columns��������������������������������������������������������������������������� 553
13.6.4 Filter Rows by Conditional Operations���������������������������������������������������������������������� 555
13.7 Iterating over Rows����������������������������������������������������������������������������������������������������������� 555
13.8 Pivot Tables����������������������������������������������������������������������������������������������������������������������� 556
13.8.1 Single-Level Aggregation����������������������������������������������������������������������������������������� 556
13.8.2 Multilevel Aggregation���������������������������������������������������������������������������������������������� 558
13.9 Adding Columns���������������������������������������������������������������������������������������������������������������� 558
13.10 Deleting Columns������������������������������������������������������������������������������������������������������������ 560
13.11 Joins Across Tables��������������������������������������������������������������������������������������������������������� 561
13.12 GeoPandas���������������������������������������������������������������������������������������������������������������������� 564
13.13 Recipe 13-1: Maps with GeoPandas������������������������������������������������������������������������������� 569
13.14 References���������������������������������������������������������������������������������������������������������������������� 573

Chapter 14: High Performance Computing����������������������������������������������������������� 575


14.1 Paths to Faster Python Code��������������������������������������������������������������������������������������������� 576
14.2 Reference Problems���������������������������������������������������������������������������������������������������������� 577
14.2.1 The Mandelbrot Set�������������������������������������������������������������������������������������������������� 577
14.2.2 A 2D Finite Element Solver��������������������������������������������������������������������������������������� 579
14.3 Reference Hardware and OS��������������������������������������������������������������������������������������������� 581
14.4 Baseline Performance������������������������������������������������������������������������������������������������������� 582
14.4.1 Mandelbrot
 Set Performance����������������������������������������������������������������������������������� 582
14.4.2 FE
 Solver Performance��������������������������������������������������������������������������������������������� 582
14.5 Profiling
 Python Code�������������������������������������������������������������������������������������������������������� 583
14.5.1 Scalene��������������������������������������������������������������������������������������������������������������������� 584
14.5.2 Austin and FlameGraph�������������������������������������������������������������������������������������������� 586
14.6 Multicore
 Computation with multiprocessing������������������������������������������������������������������� 589
14.7 Vectorization��������������������������������������������������������������������������������������������������������������������� 591

xvii
Table of Contents

14.8 Cython������������������������������������������������������������������������������������������������������������������������������� 594


14.8.1 Python Compiled with Cython����������������������������������������������������������������������������������� 595
14.8.2 Parallel for Loops with Cython���������������������������������������������������������������������������������� 598
14.8.3 Cython Performance������������������������������������������������������������������������������������������������� 599
14.9 Pythran������������������������������������������������������������������������������������������������������������������������������ 599
14.9.1 Examples of Signature Comments��������������������������������������������������������������������������� 600
14.9.2 Python Compiled with Pythran; Parallel for Loops��������������������������������������������������� 601
14.9.3 Pythran Performance������������������������������������������������������������������������������������������������ 603
14.10 Numba���������������������������������������������������������������������������������������������������������������������������� 604
14.10.1 Parallel for Loops with Numba������������������������������������������������������������������������������� 606
14.10.2 Numba Keyword Arguments nopython, fastmath��������������������������������������������������� 607
14.10.3 Numba Performance���������������������������������������������������������������������������������������������� 607
14.10.4 Numba Limitations������������������������������������������������������������������������������������������������� 607
14.11 f2py��������������������������������������������������������������������������������������������������������������������������������� 608
14.12 Recipe 14-1: Accelerating MATLAB with Python on a Single Computer������������������������� 612
14.12.1 Compile Python Modules in a MATLAB-Friendly Virtual Environment�������������������� 612
14.12.2 MATLAB + Cython��������������������������������������������������������������������������������������������������� 612
14.12.3 MATLAB + Pythran�������������������������������������������������������������������������������������������������� 613
14.12.4 MATLAB + Numba�������������������������������������������������������������������������������������������������� 613
14.12.5 MATLAB + f2py������������������������������������������������������������������������������������������������������� 614
14.12.6 MATLAB + Python Performance Results���������������������������������������������������������������� 614
14.13 Distributed Memory Parallel Processing with Dask�������������������������������������������������������� 615
14.13.1 Parallel MATLAB����������������������������������������������������������������������������������������������������� 616
14.13.2 Dask Execution Paradigm and Performance Expectations������������������������������������� 617
14.13.3 Example 1: Sum of Prime Factors on One Computer���������������������������������������������� 618
14.13.4 Setting Up a Dask Cluster on Multiple Computers�������������������������������������������������� 625
14.13.5 Example 2: Sum of Prime Factors on Multiple Computers������������������������������������� 626
14.13.6 Example 3: A Gigapixel Mandelbrot Image������������������������������������������������������������� 628
14.13.7 Example 4: Finite Element Frequency Domain Response��������������������������������������� 634

xviii
Table of Contents

14.14 Recipe 14-2: Accelerating MATLAB with Python on Multiple Computers������������������������ 646
14.14.1 Parallel Prime Sums with MATLAB������������������������������������������������������������������������� 647
14.14.2 Parallel Gigapixel Mandelbrot with MATLAB����������������������������������������������������������� 648
14.14.3 Parallel Direct Frequency Response with MATLAB������������������������������������������������� 652
14.15 References���������������������������������������������������������������������������������������������������������������������� 654

Chapter 15: Language Pitfalls������������������������������������������������������������������������������ 655


15.1 Troublesome Language Features�������������������������������������������������������������������������������������� 655
15.2 MATLAB����������������������������������������������������������������������������������������������������������������������������� 655
15.3 Python������������������������������������������������������������������������������������������������������������������������������� 658

Appendix A: MATLAB/Python Recipe Index���������������������������������������������������������� 661

Appendix B: Generating Sample Data with Faker������������������������������������������������� 663

Appendix C: Finite Element Source Listing����������������������������������������������������������� 667

Appendix D: Python-to-MATLAB and MATLAB-­to-­Python Variable Converters����� 669

Appendix E: A Utility to Patch Cartopy to Use requests���������������������������������������� 681

Index��������������������������������������������������������������������������������������������������������������������� 687

xix
About the Author
Albert Danial is an aerospace engineer with 30 years of
experience, currently working for Northrop Grumman near
Los Angeles. Before Northrop Grumman, he was a member
of the NASTRAN Numerical Methods team at MSC Software
and a systems analyst at SPARTA. He has a Bachelor of
Aerospace Engineering degree from the Georgia Institute of
Technology and master’s and Ph.D. degrees in Aeronautics
and Astronautics from Purdue University. He is the author of
cloc, the open source code counter.
Al has used MATLAB since 1990 and Python since 2006
Logan Delancey Studio for algorithm prototyping, earth science data processing,
spacecraft mission planning, optimization, visualization,
and countless utilities that simplify daily engineering work.

xxi
About the Technical Reviewers
Darrell Yocom earned a master’s degree in Computer
Science from USC and has over 40 years of experience
programming in the aerospace industry. Through the
years, he’s seen programming change from the monolithic
spaghetti-Fortran programs of the 1970s to today’s object-
oriented approaches. Darrell is an avid sailor and sails the
Pacific weekly on his sailboat, Stargazer.

Dr. Phillip Feldman, after receiving a PhD in Electrical


Engineering from the University of Southern California in
1987, spent six years as a technology policy analyst with the
RAND Corporation in Santa Monica, CA. Since then, he’s
worked in the aerospace industry for over 20 years.
Much of this work involves communications satellites
and related technology. Outside of work, Dr. Feldman has a
broad range of interests, many of which are showcased on his
website at http://phillipmfeldman.org.

xxiii
Preface
In 2018, I was chatting with a young engineer who had recently earned an engineering
master’s degree. MATLAB came up and she spoke of her frustration with license
shortages when projects came due at school. I had the same frustrations—25 years
earlier. Had nothing changed?
Of course, a lot had changed.
By then, we had already found our separate ways to Python to do the kind of work we
used to do in MATLAB. Why were so few MATLAB users aware of the power and freedom
Python could bring them?
I began assembling notes comparing Python solutions to their MATLAB equivalents
and shortly afterward learned of MATLAB’s py module. A binary API to Python?! Too
good to be true. It was too good to be true, in a sense; early versions couldn’t use critical
modules such as NumPy.
The MathWorks improved py with each MATLAB release, though, and today
MATLAB can run code from NumPy, SciPy, Pandas, matplotlib, statsmodels, dask,
even modules compiled with Cython, Numba, Pythran, and f2py. The MATLAB +
Python combination offers astounding possibilities to both languages, yet few MATLAB
developers know of this capability or how to take advantage of it. Fertile ground for a
new book, I thought.

xxv
Acknowledgments
Rachel Rybarczyk’s comments about MATLAB and Python inspired me to start the
journey that led to this book.
Alain Sei, although bowing out as my coauthor after realizing the magnitude of the
work ahead, nonetheless stayed on as my first reader. At our weekly meetings in building
R2, Alain put thought-provoking spin on things to keep my perspective fresh.
Rocco Samuele helped elevate the literary quality of the text. While I don’t have
Rocco’s chops for the written word, his edit suggestions clarified my writing.
Ravi Narasimhan’s critique of an early draft felt more like a mugging than a
review. After the bruises faded, it was clear he’d given me a goldmine of improvement
suggestions. Implementing them led to a more balanced tone and more convincing
assertions. Ravi also provided the MATLAB examples for the point and line plots on
maps shown in Section 12.4.
When Curtis Webb first told me about Numba four years ago, I dismissed his claims
that it could make Python functions run 10 ×, even 30 × faster—without using a C/C++/
Fortran compiler. Impossible! Yet somehow, like a magical alien technology, Numba
does just that. Best tip ever, thanks, Curtis!
Parker Hudnut gave valuable “big picture” suggestions on the book’s overall
structure. Thanks! The beer’s on me the next time we’re at building H.
Thank you Steven Millett, Petra Poschmann, Drew Swalley, and Mark Vaughn for tips
on missing or incomplete topics.
Thanks to Professor John Hedengren for letting me copy his predband() function in
my section on prediction intervals (Section 11.7.3). His website1 has excellent videos on
statistical computations in Python.
Thanks to Professor James Doyle for advice on, and a technical review of, the
frequency response section, Section 14.13.7. His classic “red book” on structural wave
propagation [1] remains one of my favorite technical reads.

1
https://apmonitor.com/che263/index.php/Main/PythonRegressionStatistics

xxvii
Acknowledgments

Dale Williamson’s insights on structural dynamics were inspiring and educational,


and for that I’m grateful; thanks Dale. Errors with the formulation of equations and
procedures are entirely mine.
My technical reviewers, Phillip Feldman and Darrell Yocom, are the unsung heroes
behind the operational aspects of the code and examples. Both found numerous
code errors and saved me from embarrassingly wrong explanations. Phillip guided
me through the confidence and prediction intervals in the regression section, Section
Section 11.7.3. Darrell was the original “observant reader” mentioned at the end of the
TCP Recipe, Section 7.18, and first altered me to MATLAB’s type downcast behavior for
mixed-type math, Section 15.2.
To the Apress team, thank you: Steve Anglin for taking a chance on me; Mark Powers
for shepherding the book from early draft to production; Sherly Nandha for the extensive
copy editing and typesetting work needed to turn my draft into a book.
Finally, and most importantly, thanks to Ashley, Theodore, and Mimi for believing in
me and giving me time and space to write.
A.N.D.
November 2021

xxviii
CHAPTER 1

Introduction
MATLAB is amazing—but you already know this. With a few lines of code, you can load
data, manipulate it countless ways, view it, and extract its deeper meaning. MATLAB is
also a terrific sandbox for prototyping algorithms and exploring numerical experiments,
for simulating phenomena, for churning through test results, and for generating reports.
Additionally, MATLAB’s documentation and tutorials—either built-in, hosted at The
MathWorks’ website, or available on YouTube—are thorough and high quality.
The underdocumented and underappreciated MATLAB py module, however,
motivated the creation of this book. The py module provides a binary interface between
MATLAB and Python. That’s huge—it opens a door from MATLAB to hundreds of
thousands of open source Python packages for machine learning, artificial intelligence,
data mining, database access, astronometric computation, geographic information
services, web services, high performance computing, and countless others.
Better still, the power of Python via MATLAB’s py is available for free to individuals
and at low cost to corporations (see Section 1.2). There is a caveat though: to use py,
you must also know Python. This book aims to be your guide to learning Python and
taking full advantage of MATLAB’s ability to interact with it. When viewed as a MATLAB
extension, it can be said without exaggeration that

Python is the most powerful of all MATLAB toolboxes.

1
© Albert Danial 2022
A. Danial, Python for MATLAB Development, https://doi.org/10.1007/978-1-4842-7223-7_1
Chapter 1 Introduction

1.1 Learn Python Through MATLAB Equivalents


As a MATLAB developer, you have a head start on learning Python because the two
languages have much in common. This book takes a Rosetta Stone–like approach by
presenting MATLAB and Python code side by side. MATLAB appears on the left, and
Python, usually in the form of an ipython interactive session, is on the right:

MATLAB: Python:

>> format long e In : import numpy as np


>> x = [2.3 3.3]; In : x = np.array([2.3, 3.3])
>> y = [-4 5.0]; In : y = np.array([-4, 5.0])
>> x*y' In : x.dot(y)
   7.300000000000001e+00 Out: 7.300000000000001

>> whos In : whos


Name Size Bytes Class Var Type     Data/Info
x    1x2  16    double x   ndarray  2: float64, 16 bytes
y    1x2  16    double y   ndarray  2: float64, 16 bytes

To keep the examples tight, I’ve edited them for brevity; the actual result from both
whos commands has more columns than are shown. MATLAB’s ans = line is also stripped
throughout.
Helpful too are the many function names Python’s numeric and scientific modules
share with their MATLAB counterparts. Table 1-1 shows a small subset of these. The
Python function prefixes np, npr, plt, and sci are defined with Python statements
import numpy as np, import numpy.random as npr, import matplotlib.pyplot as
plt, and import scipy.interpolate as sci.

2
Chapter 1 Introduction

Table 1-1. Some function names common to MATLAB and Python


Category MATLAB Python Notes

Creation meshgrid() np.meshgrid() Create a pair of coordinate arrays


logspace() np.logspace() Exponentially distributed terms
linspace() np.linspace() Evenly distributed terms
ones() np.ones() Create a ones-filled array
zeros() np.zeros() Create a zero-filled array
rand() npr.rand() Create a random array
Operations all() np.all() True if all terms evaluate as true
angle() np.angle() Angle of complex terms
any() np.any() True if any term evaluates as true
ceil() np.ceil() Ceiling function
cross() np.cross() Cross product
cumprod() np.cumprod() Cumulative product
cumsum() np.cumsum() Cumulative sum
diag() np.diag() Create a diagonal matrix or extract
diagonal terms
tril() np.tril() Extract lower triangular terms
triu() np.triu() Extract upper triangular terms
floor() np.floor() Floor function
histogram() np.histogram() Create histogram matrices from
coordinate vectors
Interpolation polyfit() np.polyfit() Fit a polynomial to data
griddata() sci.griddata() 2D interpolation
Plotting plot() plt.plot() Create line plots
imshow() plt.imshow() Display an array graphically
contourf() plt.contourf() Display filled contours
spy() plt.spy() Display sparsity pattern

3
Chapter 1 Introduction

While the similarities are encouraging, the two languages have fundamental
differences that will be most noticeable in Chapter 4.

1.2 Is Python Really Free?


The source code for Python and its most important modules is freely available under
open source licenses. However, there’s a world of difference between millions of lines of
free source code and a robust Python installation with secure package management on
your organization’s Windows, Linux, and macOS computers.
At least two companies, Anaconda and ActiveState, offer licensed Python
distributions which solve complex installation, bundling, deployment, package
management, and security-vetting issues. Both companies permit free use of their
distributions for individuals, but charge for commercial deployments.
Large organizations can bypass licensed distributions from Anaconda or ActiveState
by building their own distributions—but this requires considerable expertise and
adds commensurate labor costs. In addition to the challenges of compiling Python
and the hundreds of library dependencies needed by popular modules on multiple
architectures, a skilled team would be needed to maintain the organization’s private
module repository and continuously update and scan modules for security.
In this sense, a Python deployment for anything beyond a small organization is
decidedly not free. This situation is not unique to Python. Any popular open source
software package deployed widely in an organization should be managed with
installation tracking, security vetting, version management, and so on. This applies to
node and its package manager, npm, Ruby and its Gems, Rust and crates, Perl and CPAN,
R and CRAN, and so on.
If Python has a substantial cost, why not just stick with MATLAB? There are four
main reasons: (1) Python is so popular that large organizations may have Anaconda
or ActiveState licenses anyway, independently of MATLAB and its users’ needs; (2)
Python licenses from Anaconda and ActiveState are far less expensive than MATLAB
licenses; (3) unlike MATLAB toolboxes, extra Python modules do not add costs; and (4)
Python instances are not bound to license servers or license files—once a corporation
purchases licenses from Anaconda or ActiveState, subsequent Python use by the covered
number of developers is unrestricted. This last point greatly reduces logistical hassles for
deployment on stand-alone networks and use at home or on the road.

4
Chapter 1 Introduction

1.3 What About Toolboxes?


MATLAB’s full power is realized through a large collection of domain-specific—and
separately sold—toolboxes. The examples in this book, however, use only the core
MATLAB product.
Nonetheless, many solutions that are otherwise only available from many toolboxes,
namely, Mapping, Curve Fitting, Database, Parallel Computing, Symbolic, Statistics,
Optimization, Controls, and Signal Processing, are available to MATLAB by calling
Python functions. As a simple example, a weighted least squares function exists in
MATLAB’s Curve Fitting Toolbox. If you don’t have the Curve Fitting Toolbox, though,
you can compute weighted least squares in MATLAB by calling Python’s WLS() function
in the statsmodels module (demonstrated in Section 11.7.1).

1.4 Why Python Won’t Replace MATLAB


I’m occasionally asked if Python will replace MATLAB. For certain tasks, yes, it absolutely
can. As problems become more specialized, however, you’ll find that MATLAB toolboxes
made to solve those problems have no credible competition. Controls engineers will
rightly insist on one or more of the Controls Toolboxes; engineers that work with
embedded hardware will need Coder and the Fixed-Point Designer; aircraft designers
will be able to explore large tradespaces with the Aerospace Blockset.
Even in cases where Python alternatives exist, it is much easier and cleaner to call
a toolbox function than maintain a hybrid Python/MATLAB code base, keep Python
installations synchronized with MATLAB updates, and write harder-to-read code with
awkward-looking function calls and type conversions. In the long run, it may even cost
less to use toolboxes by avoiding the complexity of adding Python to your MATLAB work
flow. The balance of benefits against drawbacks will vary between use cases, individuals,
projects, and organizations.
No further mention of Simulink will appear in this book because it stands in a league
of its own; there are no Python projects with remotely similar capabilites.1

1
Development on SimuPy at https://github.com/simupy/simupy, the closest Python project to
Simulink, has stagnated.

5
Chapter 1 Introduction

The MathWorks products are invaluable when you’re using them to solve the most
niche and technically specialized problems conveniently, thoroughly, and quickly.
Python can play a supporting role alongside MATLAB and Simulink but won’t be their
replacement.
Having said that, once you’re proficient with Python you’ll find you need MATLAB
less. That’s not so much an indictment against MATLAB as it is an endorsement of
Python. Python, being a general-purpose language, excels at many things MATLAB is
less suited for. Let Python take care of the “low-hanging fruit” tasks such as aggregating
data from a collection of NetCDF4 files, scanning a directory for Excel files having tabs
named “2017 inventory,” and reformatting plain text data into a set of JSON records.
Oddly, Python may also be the better choice at the other end of the spectrum for the
biggest and most computationally challenging jobs. Unlike MATLAB, Python’s parallel
processing modules such as Dask are not restricted by licenses, so you can run on as
many processors as you can access.
Knowing Python alongside MATLAB expands your problem-solving options.
Whether that means solving new problems with just Python or with MATLAB/Python
hybrids, you’ll have considerably more power at your command than you have with
MATLAB alone.

1.5 Contents at a Glance


This book aims to be several things: a Python tutorial; a collection of MATLAB/Python
equivalent expressions, functions, and programs; a reference manual for solving
computational problems in Python; and a cookbook of MATLAB-calling-Python
examples. Where should you start?
All readers, even Python experts, should begin with Chapter 2, “Installation.” It
describes how to create a MATLAB-friendly virtual environment needed to run the
examples in this book.
MATLAB developers unfamiliar with Python can get up to speed by reading—and
practicing examples in—Chapters 3 and 4, “Language Basics” and “Data Containers.”
Once you’re comfortable with the basics of Python, skip around to sections that
interest you.
Chapter 5, “Dates and Times,” covers the details of measuring, reading, writing, and
shifting date and time objects.

6
Chapter 1 Introduction

Chapter 6, “Call Python Functions from MATLAB,” begins the heart of this book. It
covers the basics of MATLAB’s py module, shows how to extend the Python search path
within MATLAB, describes the nuances of Python-native variables in MATLAB and how
to convert them to MATLAB-native variables, and shows other mechanisms for the two
languages to interact.
“Input and Output,” Chapter 7, covers reading and writing text and binary files
common to numeric work: plain text, JSON, YAML, XML, CSV, Excel, raw binary, HDF5,
netCDF. The section on network I/O shows how to write TCP/IP clients and servers
in both Python and MATLAB. The first simple MATLAB-calling-Python recipes (to let
MATLAB read YAML and .ini files) appear in this chapter.
In addition to reading and writing files, programs must sometimes read directory
contents, search for files, get file metadata like size and modification time, and remove
directories. These actions are covered in Chapter 8, “Interacting with the File System.”
Python and MATLAB occasionally need to run external executables, check
environment variables, and monitor the computer’s load. Chapter 9, “Interacting with
the Operating System and External Executables,” shows how this is done in the two
languages.
Chapter 10, “Object-Oriented Programming,” shows how classes are defined and
instantiated in MATLAB and Python.
Chapter 11, “NumPy and SciPy,” spans nearly a quarter of this book. It covers
NumPy’s ndarray, the Python object closest to MATLAB’s matrix, as well as the many
functions that perform array operations, linear algebra, and interpolation. SciPy, a
scientific computing package built on NumPy, brings additional capability such as
sparse matrices, optimization, curve fitting, and differential equation solvers.
Data visualization is covered in Chapter 12, “Plotting.” In addition to the basics of
point, line, and contour plots, overlaying data on maps is also described.
The Pandas module for Python appeared five years before The MathWorks added
tables to MATLAB. Chapter 13, “Tables and Dataframes,” shows the basics of Pandas
dataframes and how equivalent operations are done with MATLAB tables.
Chapter 14, “High Performance Computing,” explores ways to make Python run
faster—and faster Python can mean faster MATLAB programs if you’re willing to
implement slow MATLAB functions in Python. The chapter has examples of using
Cython, Pythran, f2py, and Numba to make Python run faster on a single computer, and
dask to run Python on clusters. You’ll see that wherever a Python program is accelerated,
the analogous MATLAB program can also be accelerated the same amount just by
having MATLAB call faster Python functions.
7
Chapter 1 Introduction

MATLAB and Python both have sharp edges that can bring grief to new developers.
Chapter 15, “Language Pitfalls,” covers aspects of the two languages to watch out for.
Appendix A lists all MATLAB-calling-Python recipes in this book while appendices
B-E contain source listings that are too long for the body of the book. All source code
from the book can be found at the book’s Github repository at https://github.com/
Apress/python-for-matlab-development.

1.6 I Already Know Python. How Do I Call Python


Functions in MATLAB?
First, create a MATLAB-friendly virtual environment, matpy, as described in Section 2.5.1.
Then jump straight to Chapter 6, “Call Python Functions from MATLAB.” Refer to
Appendix A for the list of MATLAB-calling-Python recipes; these examples can
help guide your own code development.

1.7 T he Recipes Don’t Work! MATLAB Crashes!


(and What to Do About It)
MATLAB and Python, specifically the Anaconda distribution, occupy a large footprint
on your computer. Among other files, each comes with more than a thousand shared
libraries. Some libraries are common to both (e.g., ARPACK, BLAS, HDF5, Intel Math
Kernel Library, JPEG, LAPACK, Qt, Xerces-C), but these common libraries are often at
different—and incompatible—versions.
This is a problem. If you’re in MATLAB and you use its py module to access a
Python function which loads a shared library common to both Python and MATLAB,
which version is loaded, MATLAB’s or Python’s? The answer depends on several factors
including your environment variables. If your environment is not set up properly, the
function call may invoke an incompatible library routine causing the function call to fail,
or MATLAB to crash.

8
Chapter 1 Introduction

The best MATLAB-friendly environment I’ve been able to devise is the matpy virtual
environment described in Section 2.5.1. matpy cannot prevent all MATLAB crashes.
An example is loading Python’s matplotlib module into MATLAB, then making a plot
using matplotlib's default Qt backend. MATLAB crashes as soon as the plot command
is called:
MATLAB 2020b:

>> plt = py.importlib.import_module('matplotlib.pyplot');


>> plt.plot()

The workaround is to configure a different matplotlib backend: TkAgg on Linux and


macOS and WXAgg on Windows; details are in Section 12.4.5.
Software on a computer is in constant flux. Operating system updates, security
patches, MATLAB version changes, and Python module updates can all affect how
hybrid MATLAB/Python programs work from a matpy environment.
If an example from this book doesn’t work or causes MATLAB to crash, describe your
setup in an issue at the book’s GitHub page, https://github.com/Apress/python-for-
matlab-development.
Ideally, I’ll be able to post a working solution. That won’t always be possible since
I might not be able to duplicate your problem or match your combination of OS and
MATLAB versions. If nothing else, the problem you hit will get wider exposure—and
possibly a crowd-sourced solution.

9
CHAPTER 2

Installation
Installing MATLAB is pretty straightforward: download the installation package
from the MathWorks’ website, run the installer, then either authenticate with your
MathWorks credentials or provide licensing information. Installing Python is equally
easy on Windows and Linux, but installing the recommended Anaconda distribution on
macOS is more involved because it requires one to also install the Xcode development
environment. Finally, configuring a Python installation that MATLAB can use
seamlessly is harder still. In this chapter, I’ll cover installation steps, explain why
Python configuration is more problematic than MATLAB, then show how to create an
installation that can run the examples in this book.

2.1 Downloads
Python installers for macOS and Windows are freely available from python.org. Linux
and macOS distributions generally come with Python preinstalled.
It is best to avoid using a Python installation that comes with your operating
system, however. If you install new modules or upgrade existing ones, you might
break functionality your OS relies on. You are best off leaving the OS-provided Python
version alone.
Regardless of your computer’s operating system, my recommendation is to
download and install the Anaconda Python distribution from anaconda.com. Unless you
are making one installation for multiple people, install it into a directory or folder that
you own. Unlike the “vanilla” Python installer from python.org, Anaconda comes with
NumPy, SciPy, matplotlib, Pandas, and many other modules of interest to scientists and
engineers. Anaconda also includes the Spyder IDE, which, while not as capable as the
MATLAB IDE, has useful editing, debugging, and profiling options. Spyder even includes
a MATLAB theme.

11
© Albert Danial 2022
A. Danial, Python for MATLAB Development, https://doi.org/10.1007/978-1-4842-7223-7_2
Chapter 2 Installation

2.1.1 Match Your Python and MATLAB Versions!


If you plan to call Python from MATLAB (explained in Chapter 6), you’ll need to take
care to install a version of Python supported by your version of MATLAB. Visit the
MathWorks’ website1 to see which Python versions your release of MATLAB supports.
You may need to go to Anaconda’s archive2 area to get an older distribution if the current
one is too new for your MATLAB version.
This book uses MATLAB 2020b and Python 3.8.8.

2.1.2 Verify That Python Runs


After you’ve installed Python, open a terminal window on Linux or macOS or an
Anaconda terminal on Windows and type

> python --version

The result should show Python 3.8.8—or higher, if your MATLAB version supports
newer releases.

2.2 Post-Install Configuration and Checkout


The following instructions assume you’re using the Anaconda Python distribution.
The first step after installing the downloaded bundle from anaconda.org is to update
the installation with the latest security updates and packages. The easiest way to do that
is to issue the command conda update in a terminal (pick an “Anaconda Terminal” on
Windows). The command will print an error message containing the command that will
actually work. It looks like this on Linux:

(base) > conda update

CondaValueError: no package names supplied


# If you want to update to a newer version of Anaconda, type:
#
# $ conda update --prefix /usr/local/anaconda3/2020.07 anaconda

1
www.mathworks.com/help/matlab/matlab_external/install-supported-python-
implementation.html
2
https://repo.anaconda.com/archive/

12
Chapter 2 Installation

and this on Windows:

(base) C:\>conda update

CondaValueError: no package names supplied


# If you want to update to a newer version of Anaconda, type:
#
# $ conda update --prefix C:\ProgramData\Anaconda3 anaconda

The correct update commands for these particular installations are therefore
Linux:

conda update --prefix /usr/local/anaconda3/2020.07 anaconda

and
Windows:

conda update --prefix C:\ProgramData\Anaconda3 anaconda

After the update, run ipython either from the command line on Linux and macOS or
an Anaconda Prompt terminal on Windows to start a read-evaluate-print-loop (REPL)
similar to MATLAB’s console-like interactive environment.
Our first step will be to make a simple variable assignment and then invoke the whos
command to see what’s in your environment:

MATLAB: Python:

>> a = 1; In : a = 1
>> whos In : whos
  Name Size Bytes Class Variable Type Data/Info
  a    1x1  8     double ----------------------------
a        int  1

Already we see a difference—the Python a is an integer scalar, while the MATLAB a is


a two-dimensional array, sized 1 x 1, with a type of double.
This highlights a conceptual difference between the two languages: MATLAB’s
default data container is a double-precision matrix, while Python’s is a scalar whose type
is inferred from the value on the right-hand side. Chapter 4 covers MATLAB and Python
data containers in depth.

13
Chapter 2 Installation

2.3 Creating and Running a Python Program


A Python program consists of Python source code in a text file. The file name does not
have to have a .py extension, but this is the most common practice. There are several
ways to run a Python program:

• On all operating systems, open a terminal which has the Python


executable on the path, then type python (or python3) followed by
the name of the source file.

• On Windows, create an association between the .py file extension


and the full path to the Python executable. (In general, this is not a
good idea since it will complicate your life when you try to switch
virtual environments which will be discussed later.)

• On Linux and macOS, add a pound-bang line pointing to your


preferred Python executable and then make the file itself executable
with the chmod command:

> chmod a+rx my_program.py

When they are invoked as commands, Unix-like operating systems examine the first
line of executable text files for the characters #!—the pound-bang, or shebang. If these
exist, the operating system invokes the rest of the first line to interpret the remaining
lines in the file. Examples are

#!/usr/bin/env python3
#!/usr/bin/python3
#!/apps/python/3.8.8/bin/python

The first of these runs the env command to select the first python3 executable in your
$PATH. Doing so is considered a best practice.
Pound-bang lines are ignored on Windows.
Interestingly, the path to the MATLAB executable can also be used on the pound-­
bang line to run MATLAB code as a stand-alone batch script:

#!/apps/matlab/2018a/bin/matlab -nojvm -nodisplay -nosplash -nodesktop


a = rand(3);
b = rand(3);
fprintf('Random eigenvalues:');
eig(a,b)
14
Chapter 2 Installation

2.4 The Curse of Choice


MATLAB enjoys a fundamental advantage over Python with its hegemony of toolboxes.
The fact that there is only one Optimization Toolbox means you don’t have to decide
which to use.
Freedom of choice is great, but in the world of open source software, choice adds
configuration and installation complexity often summarized as “dependency hell.” As
a trivial example, consider a software package M that depends on Z version 2.4. You
download M and Z 2.4 and install them. Later, you also need package N which depends
on an older version of Z, version 2.1. All is well if your software configuration system
allows multiple versions of the same package; you just need to install both versions of Z
and make sure M uses Z v2.4 while N uses Z v2.1. If you simply replace Z v2.4 with Z v2.1,
N will continue working, but you’ll break M.
Scale this small scenario by two or three orders of magnitude, include forced
package and operating system updates for security reasons, and you’ll have a sense of
the difficulty involved in maintaining large software packages.
MATLAB’s seamless updates and toolbox installations look especially appealing in
light of Python’s module installation and update challenges.

2.5 Virtual Environments


To simplify package and plug-in installation, many open source languages—Python,
Perl, Ruby, Node, R, and Rust, to name a few—come with package managers that
determine which dependencies are needed to install a requested package, then
recursively download and install those dependencies. The challenge for Python’s
package managers, pip, or conda if you’re using the recommended Anaconda
distribution, is that a Python installation permits only one version of a package or
module. This means Python modules with conflicting dependencies cannot coexist in
the same installation! Well, technically they can coexist on the file system, but modules
lacking compatible dependencies will fail, leading to a broken Python installation.
Python’s solution to the problem of module dependency conflicts is to support the
creation of, and easy switch between, multiple shared installations known as virtual
environments. A virtual environment looks and acts like an independent Python
installation even though under the hood common libraries and modules are shared with
other environments. Each virtual environment has its own copy of modules that could
conflict with those in other environments.
15
Chapter 2 Installation

2.5.1 matpy, the Virtual Environment Used in This Book


For the most part, MATLAB works well with any Python version supported for that
release. In my case, the successful pairing is MATLAB 2020b and Python 3.8. There
are two problematic cases though. First, the Python GeoPandas module depends on a
prodigious list of shared libraries which have MATLAB counterparts. On Linux, this can
be overcome by matching GLIBC libraries in the virtual environment with that used by
MATLAB. Success on Windows and macOS can be a hit-or-miss proposition. I was able
to use GeoPandas from MATLAB on a Windows laptop successfully for several months
until I applied security updates, after which importing GeoPandas failed with a DLL
load error.
The second case involves loading compiled Python modules into MATLAB, as
done in Section 14.12, to boost MATLAB’s performance. On Linux, MATLAB can only
import such modules if they are compiled in an environment with a compatible version
of GLIBC.
It is a credit to the conda developers that such a fundamental dependency challenge
can be overcome. I was able to create a virtual environment with an older version of
GLIBC to match MATLAB’s simply by “pinning” versions of the needed libraries. With
this change, MATLAB can use GeoPandas without issues. This command creates the
virtual environment matpy which allows one to run all Python and MATLAB+Python
examples in this book:
Linux (Ubuntu 20.04):

conda create --name matpy python=3.8.8 libgcc-devel_linux-64=8.4.0 \


   libgcc-ng=8.4.0 geopandas matplotlib pulp cartopy austin faker \
   pint poliastro psycopg2 pymongo pythran redis redis-py simanneal \
   netCDF4 descartes h5py statsmodels pyyaml psutil lxml dask \
   distributed paramiko sympy requests pyflakes uncertainties seaborn \
   cython pytest scikit-umfpack ipython -c conda-forge
conda activate matpy
pip3 install scalene

Windows 10:

conda create --name matpy python=3.8.8 geopandas matplotlib pulp ^


   cartopy faker pint poliastro psycopg2 pymongo pythran redis ^
   redis-py statsmodels simanneal netCDF4 descartes h5py pyyaml ^

16
Chapter 2 Installation

    psutil lxml dask distributed paramiko sympy requests pyflakes ^


    cython uncertainties seaborn pytest ipython -c conda-forge
conda activate matpy
pip3 install wxPython scalene

macOS (Catalina, Big Sur):

conda create --name matpy python=3.8.8 geopandas matplotlib pulp \


   cartopy austin faker intel-openmp=2021.2.0 llvm-openmp=10.0.0 \
   libllvm10=10.0.1 llvmlite=0.36.0 \
   pint poliastro psycopg2 pymongo pythran redis redis-py simanneal \
   netCDF4 descartes h5py statsmodels pyyaml psutil lxml dask \
   distributed paramiko sympy requests pyflakes uncertainties seaborn \
   cython pytest ipython -c conda-forge
conda activate matpy
pip3 install scalene

The MATLAB command must be started from a terminal session which has matpy
activated, for example:
console:

conda activate matpy


matlab

2.5.2 Commands to Manage Virtual Environments


The following conda commands3 use the matpy virtual environment as an example:
List existing virtual environments

conda env list

Create a virtual environment

conda create --name matpy

Create a virtual environment using a YAML file

conda env create -f environment.yml

3
https://conda.io/projects/conda/en/latest/user-guide/tasks/
manage-environments.html
17
Chapter 2 Installation

Create a virtual environment with pinned versions

conda create --name matpy python=3.8.8 libgcc-devel_linux-64=8.4.0


libgcc-ng=8.4.0

Create a virtual environment in a specified directory

conda create --prefix /path/to/env/name matplotlib=3.1 numpy=1.16

Show where virtual environments are installed

conda info --envs

Activate a virtual environment

conda activate matpy

Deactivate the current virtual environment

conda deactivate

Search for a package

conda search libgcc-devel_linux-64

List packages in a virtual environment

conda list -n matpy

Delete a virtual environment

conda remove --name matpy --all

2.5.3 Keeping Your Virtual Environment Current


Anaconda updates their packages frequently. To stay current with security updates and
bug fixes, run conda update periodically. The conventional way to do this is with
console:

(matpy) $ conda update --all

18
Chapter 2 Installation

However, don’t do this yet! Our matpy conda environment was created with pinned
versions of modules whose shared libraries need to be consistent with their MATLAB
counterparts. Without taking precautions, update --all may install newer versions of
shared libraries that cause MATLAB to fail when it runs Python code.
The necessary precaution requires adding a file called pinned in the relevant conda
environment’s conda-meta directory. Where is this directory? Output from conda info
will tell you the location. conda-meta is in the directory shown for active env location.
For example:
console:

(matpy) $ conda info

      active environment  :  matpy
     active env location  :  /usr/local/anaconda3/2020.07/envs/matpy
             shell level  :  2
        user config file  :  /home/al/.condarc
             ..lines deleted..

Therefore, for this particular environment, the necessary file is /usr/local/


anaconda3/2020.07/envs/matpy/conda-meta/pinned. Create this file with a text
editor and add lines to match pinned entries that were used when creating the matpy
environment (see Section 2.5.1). On macOS, pinned would contain
macOS:

python=3.8.*
intel-openmp=2021.2.*
llvm-openmp=10.0.*
libllvm10=10.0.*
llvmlite=0.36.*

The asterisks in the third numeric position means any value may be used. It’s safe to
run conda update --all after this file is in place.

Note conda environments like matpy are easy to create, modify, experiment
with, and destroy. Once you have an environment you want to keep for a while,
remember to add a pinned file before you update it.

19
Chapter 2 Installation

2.6 ipython, IDEs


MATLAB is more than a language; its IDE is an integral part of the overall MATLAB
experience. MATLAB developers learning Python may be disappointed that an equally
capable IDE does not exist for Python.While several powerful Python IDEs do exist--
PyCharm, Visual Studio Code with Microsoft’s excellent Python extension, and Spyder--
only Spyder provides an experience resembling MATLAB’s IDE. Rather than explaining
Spyder’s use in this book, please see the book’s Github repository, https://github.com/
Apress/python-for-matlab-development, for links to videos showing how MATLAB
IDE interactions such as editing, debugging, and plotting are done with Spyder. For
the text in this book, I will use the ipython REPL which comes with each of the three
distributions mentioned in the previous section. While the python command itself is a
REPL, its user interface is primitive compared to ipython’s.
After verifying that you have a suitably recent version of Python (Section 2.1.2),
start an ipython session either by typing ipython at the command line (Linux, macOS)
or selecting an iPython session through the application navigator (on Windows: Start/
Programs/).

> ipython
In : import numpy
In : import matplotlib.pyplot
In : import scipy.interpolate
In : import pandas
In : import statsmodels
In : import h5py
In : import dask

We’ll use many additional modules, but if these import without errors, your
installation will be sufficient for rigorous numerical analysis.

2.6.1 Autoload Modules When ipython Starts


MATLAB will automatically run commands in startup.m in the directory identified by
the command userpath. This is useful for adding directories to your MATLAB search
path, setting format to something other than the default and so on.

20
Chapter 2 Installation

ipython has a similar mechanism to run commands at the start of each session. This
is even more necessary in Python than MATLAB because most Python sessions begin
with module imports that should be done every time; importing these automatically is a
terrific convenience. First identify the ipython “profile” directory:

In : import IPython
In : IPython.paths.locate_profile()
Out: '/home/al/.ipython/profile_default'

ipython start-up commands can be added to any file ending with .py in the startup
directory below the profile directory. If multiple .py files exist there, they are executed in
alphabetical order. I’ve customized my ipython start-up with the file

/home/al/.ipython/profile_default/startup/00-start.py

which contains

import os
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import plot, show, scatter, imshow, figure, savefig

2.7 Python and MATLAB Versions Used in This Book


All Python code in this book used 3.8.8 from Anaconda 2020.07.
All MATLAB code used Release 2020b. This version of MATLAB predates Python 3.9
which was released in October 2020 and therefore does not support 3.9.

21
CHAPTER 3

Language Basics
The fundamental elements of the Python language—variable assignment, indentation,
array indexing, for and while loops, if statements, functions, comments, exceptions,
modules—are covered in this chapter. Although classes and object-oriented
programming are also fundamental aspects of Python, these will be covered in
Chapter 10.

3.1 Assignment
Python supports four forms of variable assignment: conventional, conditional, in-place,
and the recently added “walrus operator.”

3.1.1 Assignment with =


Variable assignment in both languages looks similar:

MATLAB: Python:

>> a = 1.2; In : a = 1.2


>> b = [1 2 .3]; In : b = [1, 2, .3]
>> c = "this is MATLAB"; In : c = "this is Python"

The semicolon at the end of each MATLAB line is optional. Without it, MATLAB
prints the contents of the variable to STDOUT—helpful for observing values during
development but distracting for working code.

23
© Albert Danial 2022
A. Danial, Python for MATLAB Development, https://doi.org/10.1007/978-1-4842-7223-7_3
Chapter 3 Language Basics

Both languages allow multiple expressions on the same line separated by


semicolons, but Python additionally supports assigning multiple values with a single =.
MATLAB can assign multiple left-hand side values only from function calls, not static
­assignments.

MATLAB: Python:

>> d = 4; e = 2.71 In : d = 4; e = 2.71


     # or
In : d, e = 4, 2.71

Python also supports chained assignment where all variables are set to the
same value:
Python:

In : f = g = 5.5
In : f
Out: 5.5

In : g
Out: 5.5

Unlike MATLAB, Python supports a conditional assignment statement that works


like the ternary operator (e.g., x = (y < z) ? y : z) in C, Perl, and Java, among others.
It allows assignment of either one or another value depending on a condition:
Python:

In : g = 7
In : h = 'bigger than 5' if g > 5 else 'smaller'
In : h
Out: 'bigger than 5'

In : g = -7
In : h = 'bigger than 5' if g > 5 else 'smaller'
In : h
Out: 'smaller'

24
Chapter 3 Language Basics

3.1.2 In-Place Updates with +=, -=, and Others


A clumsy aspect of MATLAB is its lack of increment and decrement operators. Python
does not have ++ or -- operators but supports in-place updates with +=, -=, and many
additional operators.

MATLAB: Python:

>> a = 0; In : a = 0
>> a = a + 1 In : a += 1
a = 1 In : a
Out: 1

MATLAB’s a = a + 1 looks harmless enough, but replace a with an element of a


nested class or structure, for example, catalog.volume(j).on_loan.count, and the text
duplication becomes unwieldy.
Table 3-1 summarizes Python’s in-place update operators.

Table 3-1. Python in-place update operators


Operator Effect on Left-Hand Side

+= x Increment by x
-= x Decrement by x
*= x Multiply by x
/= x Divide by x
**= x Raise to the x power
|= x Bitwise OR with x
&= x Bitwise AND with x
^= x Bitwise exclusive OR with x
<<= x Bit shift left x times
>>= x Bit shift right x times

Of course, MATLAB can perform these operations too, just not in-place.

25
Chapter 3 Language Basics

3.1.3 Walrus Operator, :=


The last of the four Python assignment expressions, the walrus operator, or :=, was
introduced in Python 3.8. It works like a conventional assignment statement with the
side effect that the entire expression, both left-hand side and right-hand side, has the
value of the right-hand side. The walrus operator has no MATLAB equivalent.
Here’s a simple example:
Python:

In : x := 100
In : x
Out: 100

Nothing surprising here; x was set to 100. What’s not obvious is that the entire
statement x := 100 also has the value of 100. We can see that if we capture the full
expression with another variable:
Python:

In : y = (x := 100)
In : x
Out: 100
In : y
Out: 100

One practical use of this behavior is inserting intermediate variables in the middle
of a computation for use later. Here’s the Pythagorean theorem equation with additional
variables inserted to store intermediate values of Δx and Δy:
Python:

In : from math import sqrt


In : x1, x2 = 1.73, 9.31
In : y1, y2 = 24.6, -6.77
In : d = sqrt( (dx := (x2-x1))**2 + (dy := (y2-y1))**2 )
In d
Out 32.272795044743184

26
Chapter 3 Language Basics

In : dx
Out: 7.58

In : dy
Out: -31.37

Inserting dx := and dy := lets us save these intermediate values without disrupting the
larger computation for d.
The walrus operator is also convenient when working with regular expressions (to be
covered in Section 4.2.6) as it allows one to populate a match object and test whether or
not it was successful in a single step:

Python, Without Walrus: Python, with Walrus:

import re import re
L = "n= Bob" L = "n= Bob"
m = re.search(r"n=\s*(\w+)", L) if m := re.search(r"n=\s*(\w+)", L):
if m is not None:     print('name is ',m.group(1))
    print('name is ',m.group(1))

3.2 Printing
In the MATLAB IDE and .m files, the results of an expression are printed immediately
unless the line ends with a semicolon. A Python REPL such as ipython will also print
expressions that have no assignment, that is, without an equals sign:

MATLAB: Python:

>> i = 1 In : i = 1
i = 1 In : i
>> i, length('abc') Out: 1
i = 1 In : i, len('abc')
ans = 3 Out: (1, 3)

27
Chapter 3 Language Basics

Similarly, within a MATLAB .m file, the result of every assignment is printed unless
the line ends with a semicolon. Python follows more typical programming conventions
and requires a call to its print() function to display output from a running .py file.
MATLAB’s fprintf() function is a close analog to Python’s print() and provides similar
capability to displaying formatted text. There are a few notable difference between the
two, though.
Python’s print():

• By default automatically appends a newline (this can be suppressed


by adding the optional argument end='')

• Supports an optional argument to flush its output stream


immediately (flush=True).

• Supports an optional argument to write to a given output stream,


including STDERR (file=sys.stderr). MATLAB does not support
writing to STDERR which complicates error handling.

String formatting in Python is covered in detail in Section 4.2.3; these few lines give a
quick preview of equivalent string and floating-point output formatting:

MATLAB: Python:

fprintf('abc\n ') print('abc')


x = 1.23; x = 1.23
e = 'easy'; e = 'easy'
fprintf('x = %8.3f\n', x) print(f'x = x:8.3f')
fprintf('e = %-10s\n', e) print(f'e = e:<10s')

3.3 Indentation
A Python hallmark is its use of indentation to define the scope of classes, functions,
loops, if statements, exception handlers, and so on. Interestingly, code written in other
computer languages that ignore leading whitespace generally end up with similar
indentation because this makes code easier to understand and is considered good
coding style.

28
Another Random Scribd Document
with Unrelated Content
"Only the morality of business," put in a coarse-looking fellow
who, having been betwixt and between the conversations, had been
drinking rather heavily. "There's no need for you to join the ladies as
yet, Mrs. Gissing."

Major Erlton, at her right hand, scowled, and the boy on her left
flushed up to the eyes. He was her latest admirer, and was still in
the stage when she seemed an angel incarnate. Only the day before
he had wanted to call out a cynical senior who had answered his
vehement wonder as to how a woman like she was could have
married a little beast like Gissing, with the irreverent suggestion that
it might be because the name rhymed with kissing.

In the present instance she heeded neither the scowl nor the
flush, and her voice came calmly. "I don't intend to, doctor. I mean
to send you into the drawing room instead. That will be quite as
effectual to the proprieties."

Amid the laugh, Major Erlton found opportunity for an admiring


whisper. She had got the brute well above the belt that time. But the
boy's flush deepened; he looked at his goddess with pained,
perplexed eyes.

"The morality of speculation or gambling," retorted the doctor,


speaking slowly and staring at the delighted Major angrily, "is the art
of winning as much money as you can--conveniently. That reminds
me, Erlton; you must have raked in a lot over that match."

A sudden dull red showed on the face whose admiration Alice was
answering by a smile.

"I won a lot, also," she interrupted hastily, "thanks to your tip,
Erlton. You never forget your friends."

"No one could forget you--there is no merit----" began the boy


hastily, then pausing before the publicity of his own words, and
bewildered by the smile now given to him. Herbert Erlton noted the
fact sullenly. He knew that for the time being all the little lady's
personal interest was his; but he also knew that was not nearly so
much as he gave her. And he wanted more, not understanding that
if she had had more to give she would probably have been less
generous than she was; being of that class of women who sin
because the sin has no appreciable effect on them. It leaves them
strangely, inconceivably unsoiled. This imperviousness, however,
being, as a rule, considered the man's privilege only, Major Erlton
failed to understand the position, and so, feeling aggrieved, turned
on the lad.

"I'll remember you the next time if you like, Mainwaring," he said,
"but someone has to lose in every game. I'd grasped that fact before
I was your age, and made up my mind it shouldn't be me."

"Sound commercial morality!" laughed another guest. "Try it,


Mainwaring, at the next Gymkhâna. By the way, I hear that
professional, Greyman, is off, so amateurs will have a chance now;
he was a devilish fine rider."

"Rode a devilish fine horse, too," put in the unappeased doctor.


"You bought it, Erlton, in spite----"

"Yes! for fifteen hundred," interrupted the Major, in unmistakable


defiance. "A long price, but there was hanky-panky in that match.
Greyman tried fussing to cover it. You never can trust professionals.
However, I and my friends won, and I shall win again with the horse.
Take you evens in gold mohurs for the next----"

There was always a sledge-hammer method in the Major's fence,


and the subject dropped.

The room was heavy with the odors of meats and drinks. Dark as
it was, the flood of sunshine streaming into the veranda outside,
where yellow hornets were buzzing and the servants washing up the
dishes, sent a glare even into the shadows. Neither the furniture nor
appointments of the room owed anything to the East--for Indian art
was, so to speak, not as yet invented for English folk--yet there was
a strange unkennedness about their would-be familiarity which
suddenly struck the latest exile, young Mainwaring.

"India is a beastly hole," he said, in an undertone--"things are so


different--I wish I were out of it." There was a note of appeal in his
young voice; his eyes, meeting Alice Gissing's, filled with tears to his
intense dismay. He hoped she might not see them; but she did, and
leaned over to lay one kindly be-ringed little hand on the table quite
close to his.

"You've got liver," she said confidentially. "India is quite a nice


place. Come to the assembly to-night, and I will give you two extras-
-whole ones. And don't drink any more madeira, there is a good boy.
Come and have coffee with me in the drawing room instead; that
will set you right."

Less has set many a boy hopelessly wrong. To do Alice Gissing


justice, however, she never recognized such facts; her own head
being quite steady. But Major Erlton understood the possible results
perfectly, and commented on them when, as a matter of course, his
long length remained lounging in an easy-chair after the other
guests had gone, and Mr. Gissing had retired to business. People,
from the Palais Royale playwrights, downward--or upward--always
poke fun at the husbands in such situations; but no one jibes at the
man who succeeds to the cut-and-dried necessity for devotion. Yet
there is surely something ridiculous in the spectacle of a man playing
a conjugal part without even a sense of duty to give him dignity in it,
and the curse of the commonplace comes as quickly to Abelard and
Heloise as it does to Darby and Joan. So Major Erlton, lounging and
commenting, might well have been Mrs. Gissing's legal owner.
"Going to make a fool of that lad now, I suppose, Allie. Why the
devil should you when you don't care for boys?"

She came to a stand in front of him like a child, her hands behind
her back, but her china-blue eyes had a world of shrewdness in
them. "Don't I? Do you think I care for men either? I don't. You just
amuse me, and I've got to be amused. By the way, did you
remember to order the cart at five sharp? I want to go round the
Fair before the Club."

If they had been married ten times over, their spending the
afternoon together could not have been more of a foregone
conclusion; there seemed, indeed, no choice in the matter. And they
were prosaically punctual, too; at "five sharp" they climbed into the
high dog-cart boldly, in face of a whole posse of servants dressed in
the nabob and pagoda-tree style, also with silver crests in their pith
turbans and huge monograms on their breastplates; old-fashioned
servants with the most antiquated notions as to the needs of the
sahib logue, and a fund of passive resentment for the least change
in the inherited routine of service. Changes which they referred to
the fact that the new-fangled sahibs were not real sahibs. But the
heavy, little and big breakfasts, the unlimited beer, the solid dinners,
the milk punch and brandy pâni, all had their appointed values in the
Gissings' house; so the servants watched their mistress with
approving smiles. And on Mondays there was always a larger posse
than usual to see the old Mai, who had been Alice Gissing's ayah for
years and years, hand up the bouquet which the gardener always
had ready, and say, "My salaams to the missy-baba." Mrs. Gissing
used to take the flowers just as she took her parasol or her gloves.
Then she would say, "All right," partly to the ayah, partly to her
cavalier, and the dog-cart, or buggy, or mail-phaeton, whichever it
happened to be, would go spinning away. For the old Mai had
handed the flowers into many different turn-outs and remained on
the steps ready with the authority of age and long service, to crush
any frivolous remarks newcomers might make. But the destination of
the bouquet was always the same; and that was to stand in a peg
tumbler at the foot of a tiny white marble cross in the cemetery. Mrs.
Gissing put a fresh offering in it every Monday, going through the
ceremony with a placid interest; for the date on the cross was far
back in the years. Still, she used to speak of the little life which had
come and gone from hers when she was yet a child herself, with a
certain self-possessed plaintiveness born of long habit.

"I was barely seventeen," she would say, "and it was a dear little
thing. Then Saumarez was transferred, and I never returned to
Lucknow till I married Gissing. It was odd, wasn't it, marrying twice
to the same station. But, of course, I can't ask him to come here, so
it is doubly kind of you; for I couldn't come alone, it is so sad."

Her blue eyes would be limpid with actual tears; yet as she waited
for the return of the tumbler, which the watchman always had to
wash out, she looked more like some dainty figure on a cracker than
a weeping Niobe. Nevertheless, the admirers whom she took in
succession into her confidence thought it sweet and womanly of her
never to have forgotten the dead baby, though they rather admired
her dislike to live ones. Some of them, when their part in the weekly
drama came upon them, as it always did in the first flush of their
fancy for the principal actress in it, began by being quite sentimental
over it. Herbert Erlton did. He went so far once as to bring an
additional bouquet of pansies from his wife's pet bed; but the little
lady had looked at it with plaintive distrust. "Pansies withered so
soon," she said, "and as the bouquet had to last a whole week,
something less fragile was better." Indeed, the gardener's bouquets,
compact, hard, with the blossoms all jammed into little spots of color
among the protruding sprigs of privet, were more suited to her calm
permanency of regret, than the passionate purple posy which had
looked so pathetically out of place in the big man's coarse hands.
She had taken it from him, however, and strewn the already
drooping flowers about the marble. They looked pretty, she had said,
though the others were best, as she liked everything to be tidy;
because she had been very, very fond of the poor little dear.
Saumarez had never been kind, and it had been so pretty; dark, like
its father, who had been a very handsome man. She had cried for
days, then, though she didn't like children now. But she would
always remember this one, always! The old Mai and she often talked
of it; especially when she was dressing for a ball, because the
gardener brought bouquets for them also.

Major Erlton, therefore, gave no more pansies, and his sentiment


died down into a sort of irritable wonder what the little woman
would be at. The unreality of it all struck him afresh on this
particular Monday: as he watched her daintily removing the few
fallen petals; so he left her to finish her task while he walked about.
The cemetery was a perfect garden of a place, with rectangular
paths bordered by shrubs which rose from a tangle of annual flowers
like that around the Gissings' house. This blossoming screen hid the
graves for the most part; but in the older portions great domed
erections--generally safeguarding an infant's body--rose above it
more like summer-houses than tombs. Herbert Erlton preferred this
part of the cemetery. It was less suggestive than the newer portion,
and he was one of those wholesome, hearty animals to whom the
very idea of death is horrible. So hither, after a time, she came,
stepping daintily over the graves, and pausing an instant on the way
to add a sprig of mignonette to the rosebud she had brought from a
bush beside the cross; it was a fine, healthy bush which yielded a
constant supply of buds suitable for buttonholes. She looked
charming, but he met her with a perplexed frown.

"I've been wondering, Allie," he said, "what you would have been
like if that baby had lived. Would you have cared for it?"

Her eyes grew startled. "But I do care for it! Why should I come if
I didn't? It isn't amusing, I'm sure; so I think it very unkind of you to
suggest----"

"I never suggested anything," he protested. "I know you did--that


you do care. But if it had lived----" he paused as if something
escaped his mental grasp. "Why, I expect you would have been
different somehow; and I was wondering----"
"Oh! don't wonder, please, it's a bad habit," she replied, suddenly
appeased. "You will be wondering next if I care for you. As if you
didn't know that I do."

She was pinning the buttonhole into his coat methodically, and he
could not refuse an answering smile; but the puzzled look remained.
"I suppose you do, or you wouldn't----" he began slowly. Then a
sudden emotion showed in face and voice. "You slip from me
somehow, Allie--slip like an eel. I never get a real hold---- Well! I
wonder if women understand themselves? They ought to, for
nobody else can, that's one comfort." Whether he meant he was no
denser than previous recipients of rosebuds, or that mankind
benefited by failing to grasp feminine standards, was not clear. And
Mrs. Gissing was more interested in the fact that the mare was
growing restive. So they climbed into the high dog-cart again, and
took her a quieting spin down the road. The fresh wind of their own
speed blew in their faces, the mare's feet scarcely seemed to touch
the ground, the trees slipped past quickly, the palm-squirrels fled
chirruping. He flicked his whip gayly at them in boyish fashion as he
sat well back, his big hand giving to the mare's mouth. Hers lay
equably in her lap, though the pace would have made most women
clutch at the rail.

"Jolly little beasts; aint they, Allie?"

"Jolly altogether; jolly as it can be," she replied with the frank
delight of a girl. They had forgotten themselves innocently enough;
but one of the men in a dog-cart, past which they had flashed, put
on an outraged expression.

"Erlton and Mrs. Gissing again!" he fussed. "I shall tell my wife to
cut her. Being in business ourselves we have tried to keep square.
But this is an open scandal. I wonder Mrs. Erlton puts up with it. I
wouldn't."
His companion shook his head. "Dangerous work, saying that.
Wait till you are a woman. I know more about them than most,
being a doctor, so I never venture on an opinion. But, honestly, I
believe most women--that little one ahead into the bargain--don't
care a button one way or the other. And, for all our talk, I don't
believe we do either, when all is said and done."

"What is said and done?" asked the other peevishly.

There was a pause. The lessening dog-cart with its flutter of


ribbons, its driver sitting square to his work, showed on the hard
white road which stretched like a narrowing ribbon over the empty
plain. Far ahead a little devil of wind swept the dust against the blue
sky like a cloud. Nearer at hand lay a cluster of mud hovels, and--
going toward it before the dog-cart--a woman was walking along the
dusty side of the road. She had a bundle of grass on her head, a
baby across her hip, a toddling child clinging to her skirts. The
afternoon sun sent the shadows conglomerately across the white
metal.

"Passion, Love, Lust, the attractions of sex for sex--what you will,"
said the doctor, breaking the silence. "Nothing is easier knocked out
of a man, if he is worth calling one--a bugle call, a tight corner----
God Almighty!--they're over that child! Drive on like the devil, man,
and let me see what I can do."

There is never much to do when all has been done in an instant.


There had been a sudden causeless leaving of the mother's side, a
toddling child among the shadows, a quick oath, a mad rear as the
mare, checked by hands like a vise for strength, snapped the shafts
as if they had been straws. No delay, no recklessness; but one of
these iron-shod hoofs as it flung out had caught the child full on the
temple, and there was no need to ask what that curved blue mark
meant, which had gone crashing into the skull.
Alice Gissing had leaped from the dog-cart and stood looking at
the pitiful sight with wide eyes.

"We couldn't do anything," she said in an odd hard voice, as the


others joined her. "There was nothing we could do. Tell the woman,
Herbert, that we couldn't help it."

But the Major, making the still plunging mare a momentary


excuse for not facing the ghastly truth, had, after one short, sharp
exclamation--almost of fear, turned to help the groom. So there was
no sound for a minute save the plunging of hoofs on the hard
ground, the groom's cheerful voice lavishing endearments on his
restless charge, and a low animal-like whimper from the mother,
who, after one wild shriek, had sunk down in the dust beside the
dead child, looking at the purple bruise dully, and clasping her living
baby tighter to her breast. For it, thank the gods! was the boy. That
one with the mark on its forehead only the girl.

Then the doctor, who had been busy with deft but helpless hands,
rose from his knees, saying a word or two in Hindustani which
provoked a whining reply from the woman.

"She admits it was no one's fault," he said. "So Erlton, if you will
take our dog-cart----"

But the Major had faced the position by this time. "I can't go. She
is a camp follower, I expect, and I shall have to find out--for
compensation and all that. If you would take Mrs. Gissing----" His
voice, steady till then, broke perceptibly over the name; its owner
looked up sharply, and going over to him laid her hand on his arm.

"It wasn't your fault," she said, still in that odd hard voice. "You
had the mare in hand; she didn't stir an inch. It is a dreadful thing to
happen, but"--she threw her head back a little, her wide eyes
narrowed as a frown puckered her smooth forehead--"it isn't as if we
could have prevented it. The thing had to be."
She might have been the incarnation of Fate itself as she glanced
down at the dead child in the dust, at the living one reaching from
its mother's arms to touch its sister curiously, at the slow tears of
the mother herself as she acquiesced in the eternal fitness of things;
for a girl more or less was not much in the mud hovel, where she
and her man lived hardly, and the Huzoors would doubtless give
rupees in exchange, for they were just. She wept louder, however,
when with conventional wailing the women from the clustering huts
joined her, while the men, frankly curious, listened to the groom's
spirited description of the incident.

"You had better go, Allie; you do no good here," said the Major
almost roughly. He was anxious to get through with it all; he was
absorbed in it.

So the man who had said he was going to tell his wife to cut Mrs.
Gissing had to help her into the dog-cart.

"It was horrible, wasn't it?" she said suddenly when, in silence,
they had left the little tragedy far behind them. "We were going an
awful pace, but you saw he had the mare in hand. He is awfully
strong, you know." She paused, and a reflectively complacent smile
stole to her face. "I suppose you will think it horrid," she went on;
"but it doesn't feel to me like killing a human being, you know. I'm
sorry, of course, but I should have been much sorrier if it had been a
white baby. Wouldn't you?"

She set aside his evasion remorselessly. "I know all that! People
say, of course, that it is wicked not to feel the same toward people
whether they're black or white. But we don't. And they don't either.
They feel just the same about us because we are white. Don't you
think they do?"

"The antagonism of race----" he began sententiously, but she cut


him short again. This time with an irrelevant remark.
"I wonder what your wife would say if she saw me driving in your
dog-cart?"

He stared at her helplessly. The one problem was as


unanswerable as the other.

"You had better drive round the back way to the Fair," she said
considerately. "Somebody there will take me off your hands.
Otherwise you will have to drive me to the Club; for I'm not going
home. It would be dreadful after that horrid business. Besides, the
Fair will cheer me up. One doesn't understand it, you know, and the
people crowd along like figures on a magic lantern slide. I mean that
you never know what's coming next, and that is always so jolly, isn't
it?"

It might be, but the man with the wife felt relieved when, five
minutes afterward, she transferred herself to young Mainwaring's
buggy. The boy, however, felt as if an angel had fluttered down from
the skies to the worn, broken-springed cushion beside him; an angel
to be guarded from humanity--even her own.

"How the beggars stare," he said after they had walked the horse
for a space through the surging crowds. "Let us get away from the
grinning apes." He would have liked to take her to paradise and put
flaming swords at the gate.

"They don't grin," she replied curtly, "they stare like Bank-holiday
people stare at the wild beasts in the Zoo. But let us get away from
the watered road, the policemen, and all that. That's no fun. See, go
down that turning into the middle of it; you can get out that way to
the river road afterward if you like."

The bribe was sufficient; it was not far across to peace and quiet,
so the turn was made. Nor was the staring worse in the irregular
lane of booths and stalls down which they drove. The unchecked
crowd was strangely silent despite the numberless children carried
shoulder high to see the show, and though the air was full of
throbbings of tomtoms, twanging of sutaras, intermittent poppings
and fizzings of squibs. But it was also strangely insistent; going on
its way regardless of the shouting groom.

"Take care," said Mrs. Gissing lightly, "don't run over another
child. By the way, I forgot to tell you--the Fair was so funny--but
Erlton ran over a black baby. It wasn't his fault a bit, and the mother,
luckily, didn't seem to mind; because it was a girl, I expect. Aren't
they an odd people? One really never knows what will make them
cry or laugh."

Something was apparently amusing them at that moment,


however, for a burst of boisterous merriment pealed from a dense
crowd near a booth pitched in an open space.

"What's that?" she cried sharply. "Let's go and see."

She was out of the dog-cart as she spoke despite his protest that
it was impossible--that she must not venture.

"Do you imagine they'll murder me?" she asked with an


insouciant, incredulous laugh. "What nonsense! Here, good people,
let me pass, please!"

She was by this time in the thick of the crowd, which gave way
instinctively, and he could do nothing but follow; his boyish face
stern with the mere thought her idle words had conjured up. Do her
any injury? Her dainty dress should not even be touched if he could
help it.

But the sightseers, most of them peasants beguiled from their


fields for this Festival of Spring, had never seen an English lady at
such close quarters before, if, indeed, they had ever seen one at all.
So, though they gave way they closed in again, silent but insistent in
their curiosity; while, as the center of attraction came nearer, the
crowd in front became denser, more absorbed in the bursts of
merriment. There was a ring of license in them which made young
Mainwaring plead hurriedly:

"Mrs. Gissing!--don't--please don't."

"But I want to see what they're laughing at," she replied. And
then in perfect mimicry of the groom's familiar cry, her high clear
voice echoed over the heads in front of her: "Hut! Hut! Ari bhaiyan!
Hut!"

They turned to see her gay face full of smiles, joyous, confident,
sympathetic, and the next minute the cry was echoed with
approving grins from a dozen responsive throats.

"Stand back, brothers! Stand back!"

There were quick hustlings to right and left, quick nods and
smiles, even broad laughs full of good fellowship; so that she found
herself at the innermost circle with clear view of the central space,
of the cause of the laughter. It made her give a faint gasp and stand
transfixed. Two white-masked figures, clasped waist to waist, were
waltzing about tipsily. One had a curled flaxen wig, a muslin dress
distended by an all too visible crinoline, giving full play to a pair of
prancing brown legs. The other wore an old staff uniform, cocked
hat and feather complete. The flaxen curls rested on the tarnished
epaulet, the unembracing arms flourished brandy bottles.

It was a vile travesty; and the Englishwoman turned instinctively


to the Englishman as if doubtful what to do, how to take it. But the
passion of his boyish face seemed to make things clear--to give her
the clew, and she gripped his hand hard.

"Don't be a fool!" she whispered fiercely. "Laugh. It's the only


thing to do." Her own voice rang out shrill above the uncertain stir in
the crowd, taken aback in its merriment.

But something else rose above it also. A single word:


"Bravo!"

She turned like lightning to the sound, her cheeks for the first
time aflame, but she could see no one in the circle of dark faces
whom she could credit with the exclamation. Yet she felt sure she
had heard it.

"Bravo!" Had it been said in jest or earnest, in mockery or----


Young Mainwaring interrupted the problem by suggesting that as the
maskers had run away into a booth, where he could not follow and
give them the licking they deserved because of her presence, it
might be as well for her to escape further insult by returning to the
buggy. His tone was as full of reproach as that of a lad in love could
be, but Mrs. Gissing was callous. She declared she was glad to have
seen it. Englishmen did drink and Englishwomen waltzed. Why, then,
shouldn't the natives poke fun at both habits if they chose? They
themselves could laugh at other things. And laugh she did,
recklessly, at everything and everybody for the remainder of the
drive. But underneath her gayety she was harping on that "Bravo!"
And suddenly as they drove by the river she broke in on the boy's
prattle to say excitedly: "I have it! It must have been the one in the
Afghan cap who said 'Bravo!' He was fairer than the rest. Perhaps he
was an Englishman disguised. Well! I should know him again if I saw
him."

"Him? who--what? Who said bravo?" asked the lad. He had been
too angry to notice the exclamation at the time.

She looked at him quizzically. "Not you--you abused me. But


someone did--or didn't"--here her little slack hands resting in her lap
clasped each other tightly. "I rather wish I knew. I'd rather like to
make him say it again. Bravo! Bravo!"

And then, as if at her own mimicry, she returned to her childish


unreasoning laugh.
CHAPTER VI.
THE GIFT OF MANY FACES.

Mrs. Gissing had guessed right. The man in the Afghan cap was
Jim Douglas, who found the disguise of a frontiersman the easiest to
assume, when, as now, he wanted to mix in a crowd. And he would
have said "Bravo" a dozen times over if he had thought the little lady
would like to hear it; for her quick denial of the possibility of insult
had roused his keenest admiration. Here had spoken a dignity he
had not expected to find in one whom he only knew as a woman
Major Erlton delighted to honor. A dignity lacking in the big brave
boy beside her; lacking, alas! in many a big brave Englishman of
greater importance. So he had risked detection by that sudden
"Bravo!" Not that he dreaded it much. To begin with, he was used to
it, even when he posed as an out-lander, for there was a trick in his
gait, not to be Orientalized, which made policemen salute gravely as
he passed disguised to the tent. Then there was ignorance of some
one or another of the million shibboleths which divide men from
each other in India; shibboleths too numerous for one lifetime's
learning, which require to be born in the blood, bred in the bone. In
this case, also, he had every intention of asserting his race by licking
one at least of the offenders when the show was over. For he
happened to know one of them; having indeed licked him a few days
before over a certain piece of bone. So, as the crowd, accepting the
finale of one amusement placidly, drifted away to see another, he
walked over to the tent in which the discomforted caricaturists had
found refuge. It was a tattered old military bell-tent, bought most
likely at some auction with the tattered old staff uniform. As he lifted
the flap the sound of escaping feet made him expect a stern chase;
but he was mistaken. Two figures rose with a start of studied
surprise and salaamed profoundly as he entered. They were both
stark naked save for a waistcloth, and Jim Douglas could not resist a
quick glance round for the discarded costumes. They were nowhere
to be seen; being hidden, probably, under the litter of properties
strewing the squalid green-room. Still of the identity of the man he
knew Jim Douglas had no doubt, and as this one was also the
nearest, he promptly seized him by the both shoulders and gave him
a sound Western kick, which would have been followed by others if
the recipient had not slipped from his hold like an eel. For Jhungi,
Bunjârah, and general vagrant, habitually oiled himself from head to
foot after the manner of his profession as a precaution against such
possible attempts at capture.

His assailant, grasping this fact, at any rate, did not risk dignity by
pursuit; though the man stood salaaming again within arm's length.

"You scoundrel!" said Jim Douglas with as much severity as he


could command before the mixture of deference and defiance,
innocence and iniquity, in the sharp, cunning face before him.
"Wasn't the licking I gave you before enough?"

Jhungi superadded perplexity to his other show of emotions. "The


Huzoor mistakes," he said, with sudden cheerful understanding. "It
was the miscreant Bhungi, my brother, whom the Huzoor licked. The
misbegotten idler who tells lies in the bazaar about bones and sacks.
So his skin smarts, but my body is whole. Is it not so, Father Tiddu?"

The appeal to his companion was made with curious eagerness,


and Jim Douglas, who had heard this tale of the ill-doing double
before, looked at the witness to it with interest. That this man was
or was not Jhungi's co-offender he could not say with certainty, for
there was a remarkable lack of individuality about both face and
figure when in repose. But the nickname of Tiddu, or cricket, was
immediately explained by the jerky angularity of his actions. Save for
the faint frostiness of sprouting gray hairs on a shaven cheek and
skull he might have been any age.

"Of a truth it was Bhungi," he said in a well-modulated but creaky


voice. "Time was when liars, such as he, fell dead. Now they don't
even catch fevers, and if they do, the Huzoors give them a bitter
powder and start them lying again. So, since one dead fish stinks a
whole tank, virtuous Jhungi, being like as two peas in a pod, suffers
an ill-name. But Bhungi will know what it means to tell lies when he
stands before his Creator. Nevertheless in this world the master
being enraged----"

"Not so, Father Tiddu," interrupted Jhungi glibly, "the Huzoor is


but enraged with Bhungi. And rightly. Did not we hide our very faces
with shame while he mimicked the noble people? Did we not try to
hold him when he fled from punishment--as the Huzoor no doubt
heard----"

Jim Douglas without a word slipped his hand down the man's
back. The wales of a sound hiding were palpable; so was his wince
as he dodged aside to salaam again.

"The Huzoor is a male judge," he said admiringly. "No black man


could deceive him. This slave has certainly been whipped. He fell
among liars who robbed him of his reputation. Will the Huzoor do
likewise? On the honor of a Bunjârah 'tis Bhungi whom the Huzoor
beats. He gives Jhungi bitter powders when he gets the fever. And
even Bhungi but tries to earn a stomachful as he can when the
Huzoors take his trade from him."

"The world grows hollow, to match a man's swallow," quoted


Tiddu affably.

The familiar by-word of poverty, the quiet mingling of truth and


falsehood, daring and humility in Jhungi's plea, roused both Jim
Douglas' sense of humor, and the sympathy--which with him was
always present--for the hardness and squalidness of so many of the
lives around him.

"But you can surely earn the stomachful honestly," he said, anger
passing into irritation. "What made you take to this trade?" He
kicked at a pile of properties, and in so doing disclosed the skeleton
of a crinoline. Jhungi with a shocked expression stooped down and
covered it up decorously.

"But it is my trade," he replied; "the Huzoor must surely have


heard of the Many-Faced tribe of Bunjârahs? I am of them.'

"Lie not, Jhungi!" interrupted Tiddu calmly, "he is but my


apprentice, Huzoor, but I----" he paused, caught up a cloth, gave it
one dexterous twirl round him, squatted down, and there he was, to
the life, a veiled woman watching the stranger with furtive, modest
eye. "But I," came a round feminine voice full of feminine inflections,
"am of the thousand-faced people who wander to a thousand places.
A new place, a new face. It makes a large world, Huzoor, a strange
world." There was a melancholy cadence in his voice, which added
interest to the sheer amaze which Jim Douglas was feeling. He had
heard the legend of the Many-Faced Tribe, had even seen clever
actors claiming to belong to it, and knew how the Stranglers
deceived their victims, but anything like this he had never credited,
much less seen. He himself, though he knew to the contrary, could
scarcely combat the conviction, which seemed to come to him from
that one furtive eye, that a woman sat within those folds.

"But how?" he begun in perplexity. "I thought the Baharupas [Lit.


many-faced] never went in caravans."

Tiddu resumed the cracked voice and let the smile become visible,
and, as if by magic, the illusion disappeared. "The Huzoor is right.
We are wanderers. But in my youth a woman tied me to one place,
one face; women have the trick, Huzoor, even if they are wanderers
themselves. This one was, but I loved her; so after we had burned
her and her fellow-wanderer together hand-in-hand, according to
the custom, so that they might wander elsewhere but not in the
tribe, I lingered on. He was the father of Jhungi, and the boy being
left destitute I taught him to play; for it needs two in the play as in
life. The man and the woman, or folks care not for it. So I taught
Jhungi----"

"And brother Bhungi?" suggested his hearer dryly.

A faint chuckle came from the veil. "And Bhungi. He plays well,
and hath beguiled an old rascal with thin legs and a fat face like
mine into playing with him. Some, even the Huzoor himself, might
be beguiled into mistaking Siddu for Tiddu. But it is a tom-cat to a
tiger. So being warned, the Huzoor will give no unearned blows. Yet
if he did, are not two kicks bearable from the mulch-cow?" As he
spoke he angled out a hand impudently for an alms with the
beggars' cry of "Alakh," to point his meaning.

It was echoed by Jhungi, who, envious of Tiddu's holding the


boards, as it were, had in sheer devilry and desire not to be
outdone, taken up the disguise of a mendicant. It was a most
creditable performance, but Tiddu dismissed it with a waive of the
hand.

"Bullah!" he said contemptuously, "'tis the refuge of fools. There is


not one true beggar in fifty, so the forty-and-nine false ones go free
of detention as the potter's donkey. Even the Huzoor could do
better--had I the teaching of him."

He leaned forward, dropping his voice slightly, and Jim Douglas


narrowed his eyes as men do when some unbidden idea claims
admittance to the brain.

"You?" he echoed; "what could you teach me?"

Tiddu rose, let fall the veil to decent dignified drapery, and fixed
his eyes full on the questioner. They were luminous eyes, differing
from Jhungi's beady ones as the fire-opal differs from the diamond.

"What could I teach?" he re-echoed, and his tone, monotonously


distinct to Jim Douglas, was inaudible to others, judging by Jhungi's
impassive face. "Many things. For one, that the Baharupas are not
mimics only. They have the Great Art. What is it? God knows. But
what they will folk to see, that is seen. That and no more."

Jim Douglas laughed derisively. Animal magnetism and


mesmerism were one thing: this was another.

"The Huzoor thinks I lie; but he must have heard of the doctor
sahib in Calcutta who made suffering forget to suffer."

"You mean Dr. Easdale. Did you know him? Was he a pupil of
yours?" came the cynical question.

Tiddu's face became expressionless. "Perhaps; but this slave


forgets names. Yet the Huzoors have the gift sometimes. The
Baharupas have it not always; though the father's hoard goes
oftenest to the son. Now, if, by chance, the Huzoor had the gift and
could use it, there would be no need for policemen to salute as he
passes; no need for the drug-smokers to cease babbling when he
enters. So the Huzoor could find out what he wants to find out; what
he is paid to find out."

His eyes met Jim Douglas' surprise boldly.

"How do you know I want to find out anything?" said the latter,
after a pause.

Tiddu laughed. "The Huzoor must find a turban heavy, and there
is no room for English toes in a native shoe; folk seek not such
discomfort for naught."

Jim Douglas paused again; the fellow was a charlatan, but he was
consummately clever; and if there was anything certain in this world
it was the wisdom of forgetting Western prejudices occasionally in
dealing with the East.

"Send that man away," he said curtly, "I want to talk to you
alone."

But the request seemed lost on Tiddu. He folded up the veil


impudently, and resumed the thread of the former topic. "Yet Jhungi
plays the beggar well, for which Fate be praised, since he must ask
alms elsewhere if the Huzoor refuses them. For the purse is empty"--
here he took a leathern bag from his waistband and turned it inside
out--"by reason of the Huzoor's dislike to good mimics. So thou must
to the temples, Jhungi, and if thou meetest Bhungi give him the
sahib's generous gift; for blows should not be taken on loan."

Jhungi, who all this time had been telling his beads like the best
of beggars, looked up with some perplexity; whether real or
assumed Jim Douglas felt it was impossible to say, in that hotbed of
deception.

"Bhungi?" echoed the former, rising to his feet. "Ay! that will I, if I
meet him. But God knows as to that. God knows of Bhungi----"

"The purse is empty," repeated Tiddu in a warning voice, and


Jhungi, with a laugh, pulled himself and his disguise together, as it
were, and passed out of the tent; his beggar's cry, "Alakh! Alakh!"
growing fainter and fainter while Tiddu and Jim Douglas looked at
each other.

"Jhungi-Bhungi--Bhungi-Jhungi," jeered the Baharupa, suddenly,


jingling the names together. "Which be which, as he said, God
knows, not man. That is the best of lies. They last a body's lifetime,
so the Huzoor may as well learn old Tiddu's----"

"Or Siddu's?"
"Or Siddu's," assented the mountebank calmly. "But the Huzoor
cannot learn to use his gift from that old rascal. He must come to
the many-faced one, who is ready to teach it."

"Why?"

Tiddu abandoned mystery at once.

"For fifty rupees, Huzoor; not a pice less. Now, in my hand."

Was it worth it? Jim Douglas decided instantly that it might be.
Not for the gift's sake; of that he was incredulous. But Tiddu was a
consummate actor and could teach many tricks worth knowing.
Then in this roving commission to report on anything he saw and
heard to the military magnate, it would suit him for the time to have
the service of an arrant scoundrel. Besides, the pay promised him
being but small, the wisdom of having a second string to the bow of
ambition had already decided him on combining inquiry with
judicious horse-dealing; since he could thus wander through villages
buying, through towns selling, without arousing suspicion; and this
life in a caravan would start him on these lines effectively. Finally,
this offer of Tiddu's was unsought, unexpected, and, ever since Kate
Erlton's appeal, Jim Douglas had felt a strange attraction toward
pure chance. So he took out a note from his pocket-book and laid it
in the Baharupa's hand.

"You asked fifty," he said, "I give a hundred; but with the branch
of the neem-tree between us two."

Tiddu gave him an admiring look. "With the sacred 'Lim ke dagla'
between us, and Mighty Murri-am herself to see it grow," he echoed.
"Is the Huzoor satisfied?"

The Englishman knew enough of Bunjârah oaths to be sure that


he had, at least, the cream of them; besides, a hundred rupees went
far in the purchase of good faith. So that matter was settled, and he
felt it to be a distinct relief; for during the last day or two he had
been casting about for a fair start rather aimlessly. In truth, he had
underrated the gap little Zora's death would make in his life, and had
been in a way bewildered to find himself haunting the empty nest on
the terraced roof in forlorn, sentimental fashion. The sooner,
therefore, that he left Lucknow the better. So, as the Bunjârah had
told him the caravan was starting the very next morning, he hastily
completed his few preparations, and having sent Tara word of his
intention, went, after the moon had risen, to lock the doors on the
past idyl and take the key of the garden-house back to its owner; for
he himself had always lodged, in European fashion, near the Palace.

The garden, as he entered it, lay peaceful as ever; so utterly


unchanged from what he remembered it on many balmy moonlit
nights, that he could not help looking up once more, as if expectant
of that tinsel flutter, that soft welcome, "Khush-âmud-und Huzrut."
Strange! So far as he was concerned the idyl might be beginning;
but for her? All unconsciously, as he paused, his thought found
answer in one spoken word--the Persian equivalent for "it is
finished," which has such a finality in its short syllables:

"Khutm."

"Khutm." The echo came from Tara's voice, but it had a ring in it
which made him turn, anticipating some surprise. She was standing
not far off, below the plinth, as he was, having stepped out from the
shadow of the trees at his approach, and she was swathed from
head to foot in the white veil of orthodox widowhood, which
encircled her face like a cere-cloth. Even in the moonlight he could
see the excitement in her face, the glitter in the large, wild eyes.

"Tara!" he exclaimed sharply, his experience warning him of


danger, "what does this mean?"

"That the end has come; the end at last!" she cried theatrically;
every fold of her drapery, though she stood stiff as a corpse,
seeming to be instinct with fierce vitality.

He changed his tone at once, perceiving that the danger might be


serious. "You mean that your service is at an end," he said quietly. "I
told you that some days ago. Also that your pay would be continued
because of your goodness to her--to the dead. I advised your
returning north, nearer your own people, but you are free to go or
stay. Do you want anything more? If you do, be quick, please, for I
am in a hurry."

His coolness, his failure to remark on the evident meaning of her


changed dress, calmed her somewhat.

"I want nothing," she replied sullenly. "A suttee wants nothing in
this world, and I am suttee. I have been the master's servant for
gratitude's sake--now I am the servant of God for righteousness'
sake." So far she had, spoken as if the dignified words had been
pre-arranged; now she paused in a sort of wistful anger at the
indifference on his face. The words meant so much to her, and, as
she ceased from them, their controlling power seemed to pass also,
and she flung out her arms wildly, then brought them down in
stinging blows upon her breasts.

"I am suttee. Yes! I am suttee! Reject me not again, ye Shining


Ones! reject me not again."

The cry was full of exalted resolve and despair. It made Jim
Douglas step up to her, and seizing both hands, hold them fast.

"Don't be a fool, Tara!" he said sternly. "Tell me, sensibly, what all
this means. Tell me what you are going to do."

His touch seemed to scorch her, for she tore herself away from it
vehemently; yet it seemed also to quiet her, and she watched him
with somber eyes for a minute ere replying: "I am going to Holy
Gunga. Where else should a suttee go? The Water will not reject me
as the Fire did, since, before God! I am suttee. As the master
knows,"--her voice held a passionate appeal,--"I have been suttee all
these long years. Yet now I have given up all--all!"

With a swift gesture, full of womanly grace, but with a sort of


protest against such grace in its utter abandonment and self-
forgetfulness, she flung out her arms once more. This time to raise
the shrouding veil from her head and shoulders. Against this
background of white gleaming in the moonlight, her new-shaven
skull showed death-like, ghastly. Jim Douglas recoiled a step, not
from the sight itself, but because he knew its true meaning; knew
that it meant self-immolation if she were left to follow her present
bent. She would simply go down to the Ganges and drown herself.
An inconceivable state of affairs, beyond all rational understanding;
but to be reckoned with, nevertheless, as real, inevitable.

"What a pity!" he said, after a moment's pause had told him that
it would be well to try and take the starch out of her resolution by
fair means or foul, leaving its cause for future inquiry. "You had such
nice hair. I used to admire it very much."

Her hands fell slowly, a vague terror and remorse came to her
eyes; and he pursued the advantage remorselessly. "Why did you
cut it off?" He knew, of course, but his affected ignorance took the
color, the intensity from the situation, by making her feel her coup
de theatre had failed.

"The Huzoor must know," she faltered, anger and disappointment


and vague doubt in her tone, while her right hand drew itself over
the shaven skull as if to make sure there was no mistake. "I am
suttee--" The familiar word seemed to bring certainty with it, and
she went on more confidentially. "So I cut it all off and it lies there,
ready, as I am, for purification."

She pointed to the upper step leading to the plinth, where, as on


an altar, lay all her worldly treasures, arranged carefully with a view
to effect. The crimson scarf she had always worn was folded--with
due regard to the display of its embroidered edge--as a cloth, and at
either end of it lay a pile of trumpery personal adornments, each
topped and redeemed from triviality by a gold wristlet and anklet. In
the center, set round by fallen orange-blossoms, rose a great heap
of black hair, snakelike in glistening coils. The simple pomposity of
the arrangement was provocative of smiles, the wistful eagerness of
the face watching its effect on the master was provocative of tears.
Jim Douglas, feeling inclined for both, chose the former deliberately;
he even managed a derisive laugh as he stepped up to the altar and
laid sacrilegious hands on the hair. Tara gave a cry of dismay, but he
was too quick for her, and dangled a long lock before her very eyes,
in jesting, but stern decision.

"That settles it, Tara. You can go to Gunga now if you like, and
bathe and be as holy as you like. But there will be no Fire or Water.
Do you understand?"

She looked at the hand holding the hair with the oddest
expression, though she said obstinately, "I shall drown if I choose."

"Why should you choose?" he asked. "You know as well as I that


it is too late for any good to you or others. The Fire and Water
should have come twelve years ago. The priests won't say so of
course. They want fools to help them in this fuss about the new law.
Ah! I thought so! They have been at you, have they? Well, be a fool
if you like, and bring them pennies at Benares as a show. You
cannot do anything else. You can't even sacrifice your hair really, so
long as I have this bit." He began to roll the lock round his finger,
neatly.

"What is the Huzoor going to do with it?" she asked, and the
oddness had invaded her voice.

"Keep it," he retorted. "And by all, these thirty thousand and odd
gods of yours, I'll say it was a love-token if I choose. And I will if you
are a fool." He drew out a small gold locket attached to the
Brahminical thread he always wore, and began methodically to fit
the curl into it, wondering if this cantrip of his--for it was nothing
more--would impress Tara. Possibly. He had found such suggestions
of ritual had an immense effect, especially with the womenkind who
were for ever inventing new shackles for themselves; but her next
remark startled him considerably.

"Is the bibi's hair in there too?" she asked. There was a real
anxiety in her tone, and he looked at her sharply, wondering what
she would be at.

"No," he answered. In truth it was empty; and had been empty


ever since he had taken a fair curl from it many years before; a curl
which had ruined his life. The memory making him impatient of all
feminine subtleties, he added roughly, "It will stay there for the
present; but if you try suttee nonsense I swear I'll tie it up in a
cowskin bag, and give it to a sweeper to make broth of."

The grotesque threat, which suggested itself to his sardonic


humor as one suitable to the occasion, and which in sober earnest
was terrible to one of her race, involving as it did eternal damnation,
seemed to pass her by. There was even, he fancied, a certain relief
in the face watching him complete his task; almost a smile quivering
about her lips. But when he closed the locket with a snap, and was
about to slip it back to its place, the full meaning of the threat, of
the loss--or of something beyond these--seemed to overtake her; an
unmistakable terror, horror, and despair swept through her. She flung
herself at his feet, clasping them with both hands.

"Give it me back, master," she pleaded wildly. "Hinder me not


again! Before God I am suttee! I am suttee!"

But this same Eastern clutch of appeal is disconcerting to the


average Englishman. It fetters the understanding in another sense,
and smothers sympathy in a desire to be left alone. Even Jim
Douglas stepped back from it with something like a bad word. She
remained crouching for a moment with empty hands, then rose in
scornful dignity.

"There was no need to thrust this slave away," she said proudly.
"Tara, the Rajputni, will go without that. She will go to Holy Gunga
and be purged of inmost sin. Then she will return and claim her right
of suttee at the master's hand. Till then he may keep what he stole."

"He means to keep it," retorted the master savagely, for he had
come to the end of his patience. "Though what this fuss about
suttee means I don't know. You used to be sensible enough. What
has come to you?"

Tara looked at him helplessly, then, wrapping her widow's veil


round her, prepared to go in silence. She could not answer that
question even to herself. She would not even admit the truth of the
old tradition, that the only method for a woman to preserve
constancy to the dead was to seek death itself. That would be to
admit too much. Yet that was the truth, to which her despair at
parting pointed even to herself. Truth? No! it was a lie! She would
disprove it even in life if she was prevented from doing so by death.
So, without a word, she gathered up the crimson drapery and what
lay on it. Then, with these pathetic sacrifices of all the womanhood
she knew tight clasped in her widow's veil, she paused for a last
salaam.

The incomprehensible tragedy of her face irritated him into


greater insistence.

"But what is it all about?" he reiterated. "Who has been putting


these ideas into your head? Who has been telling you to do this? Is
it Soma, or some devil of a priest?"

As he waited for an answer the floods of moonlight threw their


shadows together to join the perfumed darkness of the orange
trees. The city, half asleep already, sent no sound to invade the
silence.
"No! master. It was God."

Then the shadow left him and disappeared with her among the
trees. He did not try to call her back. That answer left him helpless.

But as, after climbing the stairs, he passed slowly from one to
another of the old familiar places in the pleasant pavilions, the
mystery of such womanhood as Tara Devi's and little Zora's
oppressed him. Their eternal cult of purely physical passion, their
eternal struggle for perfect purity and constancy, not of the soul, but
the body; their worship alike of sex and He who made it seemed
incomprehensible. And as he turned the key in the lock for the last
time, he felt glad to think that it was not likely the problem would
come into his life again; even though he carried a long lock of black
hair with him. It was an odd keepsake, but if he was any judge of
faces his cantrip had served his purpose; Tara would not commit
suicide while he held that hostage.

So, having scant leisure left, he hurried through the alleys to


return the key. They were almost deserted; the children at this hour
being asleep, the men away lounging in the bazaars. But every now
and again a formless white figure clung to a corner shadow to let
him pass. A white shadow itself, recalling the mystery he had been
glad to leave unsolved; for he knew them to be women taking this
only opportunity for a neighborly visit. Old or young, pretty or ugly?
What did it matter? They were women, born temptresses of virtuous
men; and they were proud of the fact, even the poor old things long
past their youth. There was a chink in a door he was about to pass.
A chink an inch wide with a white shadow behind it. A woman was
looking out. What sort of a woman, he wondered idly? Suddenly the
chink widened, a hand crept through it, beckoning. He could see it
clearly in the moonlight. An old wrinkled hand, delicately old,
delicately wrinkled, inconceivably thin, but with the pink henna stain
of the temptress still on palms and fingers. A hand with the whole
history of seclusion written on it. He crossed over to it, and heard a
hurried breathless whisper.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookbell.com

You might also like