# Matplotlib figures generated in external figure windows
# %matplotlib qt
# Matplotlib figures generated in the notebook inline with the rest of the script
%matplotlib inline

import numpy as np # Import NumPy for arrays and basic linear algebra
import matplotlib.pyplot as plt # Import PyPlot for basic plotting.
import matplotlib as mpl # Import Matplotlib for advanced plotting.
from mpl_toolkits.mplot3d import Axes3D # Import Matplotlib 3D Plots

Application Development

Software is a balance of code efficiency and performance, hence the developer of Python makes the following point:

“At some point, you end up with one little piece of your system, as a whole, where you end up spending all your time. If you write that just as a sort of simple-minded Python loop, at some point you will see that that is the bottleneck in your system. It is usually much more effective to take that one piece and replace that one function or module with a little bit of code you wrote in C or C++ rather than rewriting your entire system in a faster language, because for most of what you’re doing, the speed of the language is irrelevant.” - Guido van Rossum

Good software is not designed, fabricated and distrubted. It is grown over time using careful planning to maintain a healthy developement environment. Hene, code is continuously in a state of flux and must be tested regularly to ensure quality. The procedure for developing code is as follows:

  1. Make it work in the easiest, most readable way.

  2. Test it.

  3. If necessary, optimize the code.

  4. Test it, again.

Compiled languages catch many syntax errors early, whereas scripting languages only detect these errors at run-time. Compliers do not detect database errors, within large numerical arrays, and they do not detect logistical errors in an interactive application. Therefore, the only way to truely maximize software quality is to implement unit testing (steps 2. and 4. above), and integration testing.

Finally, there is no correct programming language for all applications. Good applications are written using multiple programming languages, each with complimentary attributes as shown below:

0. IPython Notebook Proof-of-Concept

Every idea starts out as a sketch. Start by sequentially proving the concept in a script that is broken down into cells.

0.1 Installation

IPython should be installed using the following steps.

  1. Install Qt
    • Verify installation by calling "qmake" in the terminal.
  2. Install Anaconda Python distribution.
    • Select "Install for me only" to install python devloper environment in the local user directory, that does not interfere with the distribution python installation in the global system directory.
    • Verify installation by calling "conda list" in the terminal. (Lists all installed python packages).
    • Verify installation by calling "python -version" in the terminal. (Should be a version in a local directory).

0.2 Getting Started

Launch the IPython Notebook by calling “ipython -notebook” in the terminal. It is recomended that the following code is run at the beginning of all IPython notebooks:

Let’s compare some plotting tools: ### Matplotlib

import skrf as rf
from skrf import plotting
warning: data module didnt load. dont worry about it.

WARNING: pyvisa not installed, virtual instruments will not be available
sweep = np.linspace(5/4*np.pi,7/4*np.pi, 10)
x,y = 0.7*np.cos(sweep), 0.7*np.sin(sweep)
ax = plt.subplot(1, 1, 1)
plotting.smith(smithR=1, chart_type='z', draw_labels=True, border=False, ax=ax)
ax.scatter(-0.5, 0.5, c='b', s=500)
ax.scatter(0.5, 0.5, c='b', s=500)
ax.plot(x,y)
[<matplotlib.lines.Line2D at 0x10a427cc0>]
../_images/output_6_1.png

Plot.ly

import plotly
plotly.plotly.sign_in("DylanBespalko", "q76nbogdwh")
x = np.arange(0.0, 20.0, 0.1)
y = 4/3*np.sin(x) + 1/3*np.sin(3*x)
trace0 = plotly.graph_objs.Scatter(x=x,y=y, name="Sin")
plotly.plotly.iplot([trace0])
import bokeh.plotting
bokeh.plotting.output_notebook()
BokehJS successfully loaded.
# create a new plot with a a datetime axis type
TOOLS = "hover,crosshair,pan,wheel_zoom,box_zoom,reset,save,box_select,lasso_select"
p = bokeh.plotting.figure(tools=TOOLS, width=800, height=350)

# add renderers
p.scatter(x, y)

# NEW: customize by setting attributes
p.title = "Fourier Series Square-Wave Approximation"
p.legend.orientation = "top_left"
p.grid.grid_line_alpha=0
p.xaxis.axis_label = 'Time [s]'
p.yaxis.axis_label = 'Amplitude'
p.ygrid.band_fill_color="olive"
p.ygrid.band_fill_alpha = 0.1

# show the results
bokeh.plotting.show(p)

1. Python Implementation

Now that idea is clear, it needs to be implemented in software using an interactive design environment (IDE). Copy the code from the IPyhhon notebook into a well-structured object-oriented software design.

1.1 Installation

  1. Install a Python IDE such as PyCharm.
  2. Install the Qt Designer (or Qt Creator) for GUI design.

1.2 Draw the GUI (The View)

  1. Draw the GUI of your application in Qt Designer save it (.ui)
    • Specify the signals (the actions) emitted by the GUI eg(button_pressed, close_request).
    • Specify the resizing behaviour of the GUI.
    • Specify the tab-order of the GUI.
      • Covert the Qt Designer GUI (.ui) to a python class (.py)
      • Create a Python sub-class of the previous class in a separate file (.py file in Step 2. can be overwritten).

1.3 Write the Model

Write the underlying logic of the software in a self-contained command-line program with an externally configurable API.

1.4 Write the Delegate

Write the Delegate to connect the View and the Model in both directions.

  1. Implement the slots (the callbacks/listeners) that repond to signals emitted by the View and update the Model.
  2. Implement the slots (the callbacks/listeners) that respond to signals emitted by the Model and update the View.

2. Test the Software

While a compiler or IDE may catch simple errors, they can not catch run-time errors which are more predominant in math and science applications that use data containers (arrays). Therefore testing is essential for catching most bugs in the software. Two types of testing are needed:

2.1 Installation

  1. The "unittest" package is built-in to python. It is used for simple unit testing.
  2. The "nose" package is provided with the Anaconda distribution. It is useful for automated unit-testing.

2.2 Unit-Testing

Unit-testing is useful for testing each component of the software in isolation. Unit-tests can be run interactively inside PyCharm.

2.3 Integration-Testing

Integration-testing is used to test cross-component interactions that are not covered in individual unit-tests. They are a final test certification that is performed under realistic operating conditions.

3. Optimize the Software

Do not optimize your software unless you need to. Only optimize a mature solution and only optimize where needed by profiling the software.

If additional performance is desired, there are multiple solutions for optimizing the performance of the software. The following table presents several methods organized left-to-right from easiest-to-hardest effort and slowest-to-fastest performance

Strategy Vectorization Multi-Processing Numba Cython Write C++
Methodology Use NumPy array operations to replace for loops. Use Multi-Processing to perform specific tasks in parallel. Just-In-Time (JIT) compile code during first function call using static data types. Generate C-Code and compile it using static data types. Re-write code in C++
Process
  1. Replace inner for-loops with vectorized NumPy (parallalized, compiled C-code)
  2. Improve memory consumption replace d = (a+b)*c with sum(a,b,out=d),c,out=d).
  1. Replace I/O bounded for loops with parallel loops.
  1. Add "@jit" for lazy function optimization.
  2. Add addtional function type information for better optimization.
  1. Save code to (.pyc) file and auto-generate C-code.
  2. Add ctype static-type for function input/output variables.
  3. Add ctype static-type for local variables.
  4. Disable limit-checking for function input variables.
  1. Re-write processor intensive modules in C++ and complile as shared object.
  2. Use the Boost.Python binding generator bind Python and C++ objects.

Generally speaking, there are two types of optimization.

  • (NumPy) Vectorization for optimization of "big data" mathematical operations.
  • (Cython) Static-type compilation for code with lots of loops.

Vectorization with NumPy uses statically-typed data arrays, hence it is unlikely that Cython compilation will optimize a process that is heavily implemented in NumPy. Cython is used to optimize loops that cannot be vectorized and can be combined with NumPy arrays. Hence, NumPy and Cython should cover most processing-bounded issues, while I/O bounded issues are solved using multi-processing.

3.1 Installation

  1. The "NumPy" package is provided with the Anaconda distribution.
  2. The "multiprocessing" package is built-in to python.
  3. The "Numba" package is provided with the Anaconda distribution.
  4. The "Cython" package is provided with the Anaconda distribution.
  5. Todo Add C++ instructions.

4. Test the Software, Again

Repeat Step 2. to enusre the optimized software has the same functionality as the origional code.