2. Introduction to the GDA

For general background and detailed description of GDA, first read the ‘GDA Users’ Manual’ (in documentation/docs). This includes: an introduction to GDA, the GDA scripting environment, a description of scanning (data acquisition), advanced plotting techniques, and data analysis techniques.

A more detailed description of developing new components in GDA in Jython is provided in the ‘GDA Jython training course’ (in documentation/docs). This has practical examples of developing new components in Jython, scanning them, and plotting and analysing their output.

Here, we describe further examples of user-defined scannables in Jython, and scanning and manipulating them from the Jython terminal.

2.1. Example usage of the main Jython GDA commands

List all scannable objects:

>>> pos

Help:

>>> help

List all devices:

>>> ls

List all scannable devices (devices that implement the Scannable interface):

>>> ls Scannable

Import demo scannable definitions:

>>> import scannableClasses
>>> from scannableClasses import *

Make a new instance of SimpleScannable:

>>> simple = SimpleScannable('simple', 0.0)

Scan simple from 0 to 1 in steps of 0.01:

>>> scan simple 0.0 1.0 0.01

Get current position of simple:

>>>pos simple

Move simple to 0.5:

>>>pos simple 0.5

Delete an existing object:

>>> del simple

See the Jython training manual for more detailed descriptions and further examples.

2.2. Example devices

A Jython module containing several demonstration scannable objects is contained in the user scripts folder (‘documentation/users/scripts/scannableClasses.py’. This file can be opened, viewed and edited in the Jython Editor view in the GDA client. (If this view is not visible at startup, select the ‘JythonEditor’ view from the View menu in GDA.)

New users can gain familiarity with the Jython terminal by following the examples below. Users should type in the Jython commands below from the GDA Jython Scripting Terminal. Each command follows the Jython terminal prompt ‘>>>’. A short description precedes each command or set of commands.

To superimpose successive scans on previous scans, the ‘Create new graph’ and ‘Clear old graphs’ should be left unchecked.

Import all the classes from the demonstration ‘scannableClasses’ module (if not already done so above):

>>> import scannableClasses
>>> from scannableClasses import *

Help is available for most of these classes:

>>> help ScannableGaussian
>>> help ScannableSine

Make an instance of ScannableGaussian:

>>> sg = ScannableGaussian('sg', 0.0)

Scan it from -2 to 2 in steps of 0.02:

>>> scan sg -2.0 2.0 0.02
../_images/intro1.png

Change its centre to -1 and rescan:

>>> sg.centre = -1
>>> scan sg -2.0 2.0 0.02
../_images/intro2.png

Move again, add some noise, and rescan:

>>> sg.centre = 0.5
>>> sg.noise = 0.2
>>> scan sg -2.0 2.0 0.02
../_images/intro3.png

Make a new instance of ScannableGaussian, setting values for its additional optional properties, and scan it:

>>> sg2 = ScannableGaussian('sg2', 0.0, centre=0.75, width=1.54, height=2.0, noise=0.1)
>>> scan sg2 -2.0 2.0 0.02
../_images/intro4.png

Make an instance of a ScannableSine class and scan it:

>>> ss = ScannableSine('ss', 0.0)
>>> scan ss -2.0 2.0 0.02
../_images/intro5.png

Change the period and phase of ss and rescan:

>>> ss.period = 0.2
>>> ss.phase = 1.0
>>> scan ss -2.0 2.0 0.02
../_images/intro6.png

Change the magnitude, phase, and noise, of the sine, and rescan:

>>> ss.magnitude = 2.0
>>> ss.phase = 0.5
>>> ss.noise = 0.2
>>> scan ss -2.0 2.0 0.02
../_images/intro7.png

Multiple scans can also be nested to an arbitrary level. To illustrate a nested scan with two levels, i.e. an inner scan nested within an outer scan, we can define the outer scan to set the value of the inner scan. The example class ScannableGaussianWidth in the scannableClasses module (in directory documention/users/scripts) takes an existing ScannableGaussian instance, and sets the width of the scannableGaussian to its own current value. The enclosed scannableGaussian can be scanned at each width across a user-defined range.

Instantiate a new ScannableGaussianWidth object:

>>> sgw = ScannableGaussianWidth('sgw', 0.0, scannableGaussian0)

Perform the nested scan:

>>> scan sgw 1. 10. 1 scannableGaussian0 0. 100. 10

The results of this scan in the Terminal plot window are shown below:

../_images/intro8.png

2.3. Using the plotting functions in GDA

Apart from the basic plotting window in the Terminal view which displays the current scan, GDA also has some advanced plotting capabilities for previously-recorded scans. These are designed for post-scan analysis and visualisation. For a detailed description of advanced plotting, refer to ‘Chapter 6. Plotting’ in the GDA Users’ Manual, and Section 6 ‘Data analysis and visualisation’ in the GDA Jython training course.

Here, we show a few basic plotting examples using the example Scannable classes in the module ‘scannableClasses’.

Make new ScannableSine:

>>> del ss
>>> ss = ScannableSine('ss', 0.0, period=0.5)

Scan a scannable:

>>> scan ss -4.0 4.0 0.05

Make a new ScanFileHolder object (delete first, if already have ‘data’ object):

>>> del data
>>> data = ScanFileHolder()

Read the last scan into the ScanFileHolder:

>>> data.loadSRS()

Print information about the scan:

>>> data.info()

Plot column 1 against column 0:

>>>data.plot(0,1)

The plot and associated functions are available in the ‘Data Vector’ view in the GDA client.

../_images/intro9.png

Individual columns of the scan can be accessed from the complete scan:

>>> dataset1 = data[1]

... and plotted against other data columns:

>>> Plotter.plot('Data Vector', data[0], dataset1)</nowiki>

Characteristics of individual data columns can be accessed using different functions:

>>> dataset1.min()
-0.9999
>>> dataset1.max()
0.9999

Datasets can be transformed:

>>> dataset1 -= dataset1.min()
>>> dataset1.min()
0.0
>>> dataset1.max()
1.998
>>> dataset1 /= dataset1.max()
>>> dataset1.min()
0.0
>>> dataset1.max()
1.0

The two commands above result in the dataset being normalised to the range [0,1]. This is demonstrated by re-plotting the data:

>>> Plotter.plot('Data Vector', data[0], dataset1)
../_images/intro10.png

Generate double nested scan data:

Scan scannableGaussian1 within a scan of scannableGaussian0. Both scans range from -2.0 to +2.0, with a step of 0.2. Both scans therefore consist individually of 11 data points:

>>> scan scannableGaussian0 -2.0 2.0 0.2 scannableGaussian1 -2.0 2.0 0.2

Read the scan into a ScanFileHolder, and print its information:

>>> data.loadSRS()
>>> data.info()
0 x
1 y
2 x
3 y
4 .....

Plot each scan independently:

>>> data.plot(data[0], data[1])
>>> data.plot(data[2], data[3])

Extract the signal (‘y’, i.e. Gaussian) from the first scan:

>>> test1 = data[1]

Resize the data to a square grid:

>>> test1.resize([21,21])

Note: The dimension arguments must correspond to the dimensions of the nested scan. Both the inner and our scans are from -2.0 to 2.0 in steps of 0.2; therefore each dimension consists of 21 points.

Plot the outer scan data over the range of the combined scan. This consists of 441 (21x21) points. The value of the outer scan increments every 21 points:

>>> data.plot(DataSet.arange(441), data[1])
../_images/intro12.png

Plot the inner scan data over the range of the combined scan. This consists of 441 (21x21) points. The inner scan data consist of 21 adjacent Gaussians:

>>> data.plot(DataSet.arange(441), data[3])
../_images/intro13.png

Plot an image:

>>> Plotter.plotImage('Data Vector', test1)
../_images/intro14.png

Do the same for the second scan:

>>> test2 = data[3]
>>> Plotter.plot('Data Vector', DataSet.arange(121), test2)
>>> test2.resize([11, 11]) </nowiki>
>>> Plotter.plot('Data Vector', DataSet.arange(121), test1)
>>> Plotter.plotImage('Data Vector', test2)
../_images/intro15.png

Plot the individual data sets over the complete scan range:

>>> data.plot(DataSet.arange(121), data[0])
>>> data.plot(DataSet.arange(121), data[1])
>>> data.plot(DataSet.arange(121), data[2])
>>> data.plot(DataSet.arange(121), data[3])

Alternative plotting command using Plotter:

>>> Plotter.plot('Data Vector', DataSet.arange(121), data[0])
>>> Plotter.plot('Data Vector', DataSet.arange(441), data[1])
>>> Plotter.plot('Data Vector', DataSet.arange(121), data[0])
>>> Plotter.plot('Data Vector', DataSet.arange(441), data[3])

Make a new data set, the product of test1 and test2, and plot (resulting in a 2D Gaussian), both as flat image (heat map), and as (rotatable) 3D:

>>> test3 = test1 * test2
>>> Plotter.plotImage('Data Vector', test3)
../_images/intro16.png
>>> Plotter.plot3D('Data Vector', test3)
../_images/intro17.png

Make a different combination of data and plot:

>>> test4 = test1 + test2
>>> Plotter.plotImage('Data Vector', test4)
../_images/intro18.png
>>> Plotter.plot3D('Data Vector', test4)
../_images/intro19.png

Plot the expanded / resized data sets:

>>> Plotter.plot('Data Vector', DataSet.arange(121), data[1])
>>> Plotter.plot('Data Vector', DataSet.arange(121), data[3])

Do a nested scan of an outer Gaussian containing an inner sine:

>>> scan scannableGaussian0 -2.0 2.0 0.2 scannableSine -2.0 2.0 0.2
>>> data.loadSRS()
>>> test1 = data[1]
>>> test2 = data[3]
>>> test1.resize([21,21])
>>> test2.resize([21,21])
>>> test3 = test1 * test2
>>> test4 = test1 + test2
>>> Plotter.plotImage('Data Vector', test3)
../_images/intro20.png
>>> Plotter.plot3D("Data Vector", test3)
../_images/intro21.png
>>> Plotter.plotImage("Data Vector", test4)
../_images/intro22.png
>>> Plotter.plot3D("Data Vector", test4)
../_images/intro23.png