Programming Style
|
|
Errors and Exceptions
|
Tracebacks can look intimidating, but they give us a lot of useful information about what went wrong in our program, including where the error occurred and what type of error it was.
An error having to do with the ‘grammar’ or syntax of the program is called a SyntaxError . If the issue has to do with how the code is indented, then it will be called an IndentationError .
A NameError will occur when trying to use a variable that does not exist. Possible causes are that a variable definition is missing, a variable reference differs from its definition in spelling or capitalization, or the code contains a string that is missing quotes around it.
Containers like lists and strings will generate errors if you try to access items in them that do not exist. This type of error is called an IndexError .
Trying to read a file that does not exist will give you an FileNotFoundError . Trying to read a file that is open for writing, or writing to a file that is open for reading, will give you an IOError .
|
Defensive Programming
|
Program defensively, i.e., assume that errors are going to arise, and write code to detect them when they do.
Put assertions in programs to check their state as they run, and to help readers understand how those programs are supposed to work.
Use preconditions to check that the inputs to a function are safe to use.
Use postconditions to check that the output from a function is safe to use.
Write tests before writing code in order to help determine exactly what that code is supposed to do.
|
Debugging
|
Know what code is supposed to do before trying to debug it.
Make it fail every time.
Make it fail fast.
Change one thing at a time, and for a reason.
Keep track of what you’ve done.
Be humble.
|
Timing and Speeding Up Your Programs
|
Use magic commands %time and %timeit to speed-test your code in Notebooks
Numpy arrays and functions (ufuncs) are much faster than using lists and loops.
You can make code more efficient for handling arrays (if not faster) using vectorization.
|
Working with Numpy Arrays
|
Numpy arrays can be created from lists using numpy.array or via other numpy functions.
Like lists, numpy arrays are indexed in row-major order, with the last index read out fastest.
Numpy arrays can be edited and selected from using indexing and slicing, or have elements appended, inserted or deleted using using numpy.append , numpy.insert or numpy.delete .
Numpy arrays must be copied using numpy.copy or by operating on the array so that it isn’t changed, not using = which simply assigns another label to the same array, as for lists.
Use numpy.reshape , numpy.transpose (or .T ) to reshape arrays, and numpy.ravel to flatten them to a single dimension. Various numpy stack functions can be used to combine arrays.
numpy.genfromtxt can read data into structured numpy arrays. Columns must be referred to using the field name given to that column when the data is read in.
Conditional statements can be used to select elements from arrays with the same shape, e.g. that correspond to the same data set.
|
Array Calculations with Numpy
|
Numpy ufuncs operate element-wise (item by item) on an array.
Common mathematical operators applied to numpy arrays act as wrappers for fast array calculations.
Binary ufuncs operate on two arrays: if the arrays have different shapes which are compatible, the operation uses broadcasting rules.
Many operations and numerical methods (such as random number generation) can be carried out with numpy functions.
Arrays can be masked to allow unwanted elements (e.g. with nan values) to be ignored in array calculations using special masked array ufuncs.
Define your own functions that carry out complex array operations by combining different numpy functions.
|
Numerical Methods with Scipy
|
Scipy sub-packages need to be individually loaded - import scipy and then referring to the package name is not sufficient. Instead use, e.g. from scipy import fft .
Specific functions can also be loaded separately such as from scipy.interpolate import interp1d .
For model fitting when errors are normally distributed you can use scipy.optimize.curve_fit . For more general function minimization use scipy.optimize.minimize
Be careful with how Scipy’s Fast Fourier Transform results are ordered in the output arrays.
Always be careful to read the documentation for any Scipy sub-packages and functions to see how they work and what is assumed.
|
Introduction to Astropy
|
Astropy includes the core packages plus coordinated sub-packages and affiliated sub-packages (which need to be installed separately).
The astropy.units sub-package enables calculations to be carried out using self-consistent physical units.
astropy.constants enables calculations using physical constants using a whole range of physical units when combined with the units sub-package.
astropy.cosmology allows calculations of fundamental cosmological quantities such as the cosmological age or luminosity distance, for a specified cosmological model.
astropy.coordinates and astropy.time , provide a number of functions that can be combined to determine when a given target object can best be observed from a given location.
|
Working with FITS Data
|
FITS files can be read in and explored using the astropy.io.fits sub-package. The open command is used to open a datafile.
FITS files consist of one or more Header Data Units (HDUs) which include a header and possibly data, in the form of a table or image. The structure can be accessed using the .info() method
Headers contain sets of keyword/value pairs (like a dictionary) and optional comments, which describe the metadata for the data set, accessible using the .header['KEYWORD'] method.
Tables and images can be accessed using the .data method, which assigns table data to a structured array, while image data is assigned to an n-dimensional array which may be plotted with e.g. matplotlib’s imshow function.
|