Python Programming

The Zurich Instruments LabOne Python API is distributed as the zhinst Python package via PyPi, the official third-party software repository for Python. The zhinst package contains the ziPython binary extension that is used to communicate with Zurich Instruments data servers and devices. It allows users to configure and stream data from their instrument directly into a Python programming environment using Python’s own native data structures and numpy arrays.

This chapter aims to help you get started using the Zurich Instruments LabOne Python API to control your instrument.

LabOne API documentation

For a full reference of the Python API visit the LabOne API documentation.

About Python

Python is open source software, freely available for download from Python’s official website. Python is a high-level programming language with an extensive standard library renowned for its "batteries included" approach. Combined with the numpy package for scientific computing, Python is a powerful computational tool for scientists that does not require an expensive software license.

This chapter and the provided examples are not intended to be a Python tutorial. For help getting started with Python itself, see either the Python Tutorial or one of the many online resources, for example, the learnpython.org. The Interactive Python Course is an interesting resource for those already familiar with Python basics.

Installing the LabOne Python API

This section lists detailed requirements. In most cases, installing the LabOne Python API should be as simple as searching for and installing the zhinst package in your Python distribution’s package manager or running the command-line command:

pip install zhinst

Requirements

The following requirements must be fulfilled in order to install and use the LabOne Python API:

  1. One of the following supported platforms and Python versions:

    1. 32 or 64-bit Windows with a Python 2.7, 3.5, 3.6 or 3.7 installation.

    2. 64-bit Linux with a Python 2.7, 3.5, 3.6 or 3.7 installation.

    3. 64-bit macOS and the system Python 2.7 (shipped pre-installed with macOS; other Python installations are not supported). The Data Server, which is unavailable on macOS, must run remotely on either an instrument or on a separate Windows or Linux PC.

  2. The pip Python package, Python’s most popular package management system.

  3. The numpy Python package (automatically installed by pip if zhinst is installed over the internet).

    Although the newest version of numpy is recommended, the zhinst package supports the following numpy versions:

    • Python 2.7 >= 1.6

    • Python 3.5 >= 1.10

    • Python 3.6 >= 1.12

    • Python 3.7 >= 1.14

  4. The correct version of the zhinst Python package for the target Python version and platform (automatically detected by pip if zhinst is installed over the internet).

    Note, it’s necessary to first uninstall/remove zhinst when down or upgrading to release 14.08 and it’s recommend to first uninstall zhinst when down or upgrading to release 18.12. See below for more details.

Upgrading to the LabOne Python API release 14.08

Important: If you your system already has an existing ziPython installation older than version 14.08, please be sure to either manually uninstall ziPython or manually remove the existing zhinst installation folder. This is due to improvements in the zhinst package structure in 14.08 (examples for different device classes are now organized in separate module/sub-directories) and the Python installer simply overwrites the existing installation, leading to a duplication of some files. For help locating [PYTHONROOT]\lib\site-packages\zhinst\ on your system, please see Locating the zhinst Installation Folder and Examples .

Packaging changes to the LabOne Python API in 18.12

The LabOne Python API prior to LabOne software release 18.12 was distributed as an MSI installer (Windows) or tarball (Linux, Mac), downloadable from the Zurich Instruments download page. From LabOne software release 18.12 onwards the LabOne Python API is distributed as a Python wheel which can be either downloaded via pip (or manually) from PyPi as the zhinst Python package. If installing zhinst from a wheel for the first time it is recommended to uninstall the ziPython installer first in Windows. On Linux, if zhinst was installed using pip, it’s recommended to first uninstall the old installation before installing the wheel:

pip uninstall ziPython

Note, in releases prior to 18.12, the Python API package was called ziPython. Since the top-level package is actually called zhinst and ziPython is the binary extension contained within it, the Python API package was renamed in 18.12 to zhinst for consistency.

Recommended Python Packages

The following Python packages can additionally be useful for programming with the LabOne Python API:

  1. matplotlib - recommended to plot the output from many of `zhinst’s examples.

  2. scipy - recommended to load data saved from the LabOne UI in binary Matlab format (.mat).

Installation (Windows, Linux, macOS)

The following installs the zhinst package from PyPi over the internet locally for the user performing the installation and does not require administrator rights. If the target PC for installation does not have access to the internet, please additionally see Offline Installation.

  1. Determine the path to the target Python installation. If the Python executable is not in your path, you can obtain the full path to your Python executable as follows:

    from __future__ import print_function
    import sys
    print(sys.executable)

    On Windows this will print something similar to:

    C:\Python27\python.exe
  2. Install the zhinst package. Using the full path to the Python executable, PATH_TO_PYTHON_EXE, as determined above in Step 1, open a command prompt and run Python with the pip module to install the zhinst package:

    PATH_TO_PYTHON_EXE -m pip install --user zhinst

    The --user flag tells pip to install the zhinst package locally for the user executing the command. Normally administrator rights are required in order to install the zhinst package for all users of the computer, for more information see below.

Global Installation as Administrator

In order to install the zhinst package for all users of the target Python installation, it must be installed using administrator rights and pip’s `--user command-line flag should be not be used. On Windows, Step 2 must be ran in a command prompt opened with administrator rights, this is normally achieved by doing a mouse right-click on the shortcut to cmd.exe and selecting "Run as administrator". On Linux, the package can be installed by preceding the installation step by “sudo”.

Offline Installation

To install zhinst package on a computer without access to the internet, please download the correct wheel file for your system and Python version from https://pypi.org/project/zhinst/ from another computer and copy it to the offline computer. If the target Python installation is Python 2.7 on a Linux 64-bit computer, please see Determining the correct Unicode version for Python 2.7 distributions below. If the numpy package is not yet installed, it can also be downloaded from either https://pypi.org/project/numpy/ or from Christoph Gohlke’s pythonlibs page. Then the wheels can be installed as described above using pip, except that the name of the wheel file must be provided as the last argument to pip instead of the name of the package, zhinst.

Determining the correct Unicode version for Python 2.7 distributions

In order to determine which version of Unicode your Python 2.7 distribution uses, please type the following commands in the interactive shell of your target Python distribution:

import sys
print sys.maxunicode

If the last command prints:

  • 65535, use the UCS2 version of zhinst:

    zhinst-xx.xx.xxxxx-cp27-cp27m-manylinux1_x86_64.whl

  • 1114111, use the UCS4 version of zhinst (note the additional "u"):

    zhinst-xx.xx.xxxxx-cp27-cp27mu-manylinux1_x86_64.whl

Getting Started with the LabOne Python API

This section introduces the user to the LabOne Python API.

Contents of the LabOne Python API

Alongside the binary extension ziPython for interfacing with Zurich Instruments Data Servers and devices, the LabOne Python API includes utility functions and examples.

See the LabOne API documentation for all available examples and which utility functions are available in zhinst.

Using the Built-in Documentation

ziPython’s built-in documentation can be accessed using the `help command in a python interactive shell:

  • On module level:

    >>> import zhinst.ziPython as ziPython
    >>> help(ziPython)
  • On class level, for example, for the Sweeper Module:

    >>> import zhinst.ziPython as ziPython
    >>> help(ziPython.SweeperModule)
  • On function level, for example, for the ziDAQServer poll method:

    >>> import zhinst.ziPython as ziPython
    >>> help(ziPython.ziDAQServer.poll)

See the LabOne API documentation for a full documentation.

Running the Examples

Prerequisites for running the Python examples:

  1. The zhinst package is installed as described above in Installing the LabOne Python API .

  2. The Data Server program is running and the instrument is discoverable, this is the case if the instrument can be seen in the User Interface.

  3. Signal Output 1 of the instrument is connected to Signal Input 1 via a BNC cable; many of the Python examples measure on this hardware channel.

It’s also recommended to install the matplotlib Python package in order to plot the data obtained in many of the examples, see Recommended Python Packages .

The API examples are available in the module zhinst.examples, which is organized into sub-modules according to the target Instrument class:

  • zhinst.examples.common: examples compatible with any class of instrument,

  • zhinst.examples.hdawg: examples only compatible with HDAWG Instruments,

  • zhinst.examples.hf2: examples only compatible with HF2 Series Instruments,

  • zhinst.examples.uhf: examples only compatible with the UHF Lock-in Amplifier.

All the examples follow the same structure and take one input argument: The device ID of the instrument to run the example with. The recommended way to run a zhinst example is to import the example’s module in an interactive shell and call the run_example() function. For example, to run the Data Acquisition Module FFT example:

import zhinst.examples.common.example_data_acquisition_edge_fft as example
example.run_example('dev123', do_plot=True);

which will produce some output in the Python shell, such as:

Discovered device `dev196`: HF2LI with options MFK, PLL, MOD, RTK, PID, WEB. Creating an API session for device `dev196` on `127.0.0.1`, `8005` with apilevel `1`. Setting trigger/0/level to 0.221.
Setting trigger/0/hysteresis 0.011.
Data Acquisition Module progress (acquiring 10 triggers): 100.00%.
Trigger is finished.
Data Acquisition's read() returned 10 signal segments.

Specify do_plot=False if matplotlib is unavailable. If matplotlib is installed, most examples will also plot the retrieved data, see Figure 1 for an example. If you encounter an error message please ensure that the above prerequisites are fulfilled.

example data acquisition edge fft
Figure 1. The plot produced by the LabOne Python API example demonstrating how to record the Fast Fourier Transform (FFT) applied to demodulator data using the Data Acquisition Module (example_data_acquisition_edge_fft.py)

Locating the zhinst Installation Folder and Examples

The examples distributed with the zhinst package can serve as a starting point to program your own measurement needs. The example python files, however, are generally not installed in user space. In order to ensure that you have sufficient permission to edit the examples and that your modifications are not overwritten by a later upgrade of the zhinst package, please copy them to your own user space before editing them.

The examples are contained in a subfolder of the zhinst package installation folder

[PYTHONROOT]\lib\site-packages\zhinst\

If you are unsure about the location of your PYTHONROOT, the path attribute of the zhinst module can be used in order to determine its location, for example,

from __future__ import print_function
import zhinst
print zhinst.__path__

will output something similar to:

C:\Python27\lib\site-packages\zhinst

Using ziCore Modules in the LabOne Python API

In the LabOne Python API ziCore Modules are configured and controlled via an instance of the Module’s class. This Module object is created using the relevant function from ziPython.ziDAQServer. For example, an instance of the Sweeper Module is created using ziPython.ziDAQServer’s `sweep() function. As such, an API session must be instantiated first using ziPython.ziDAQServer (see Specifying the Data Server Hostname and Port for more information about initializing API session) and then a sweeper object is created from instance of the API session as following:

>>> daq = ziPython.ziDAQServer('localhost', 8004, 6) # Create a connection to the Data Server ('localhost' means the Server is running on the same PC as the API client, use the device serial of the form 'mf-dev3000' if using an MF Instrument.
>>> sweeper = daq.sweep();

Note, that since creating a Module object without an API connection to the Data Server does not make sense, the Sweeper object is instantiated via the sweep method of the ziDAQServer class, not directly from the SweeperModule class.

The Module’s parameters are configured using the Module’s set method and specifying a path, value pair, for example:

>>> sweeper.set('sweep/start', 1.2e5);

The parameters can be read-back using the get method, which supports wildcards, for example:

>>> sweep_params = sweeper.get('sweep/*');

The variable sweep_params now contains a dictionary of all the Sweeper’s parameters. The other main Module commands are similarly used, e.g., sweeper.execute(), to start the sweeper. See ziCore Modules for more help with Modules and a description of their parameters.

Enabling Logging in the LabOne Python API

Logging from the API is not enabled by default upon initializing a server session with ziPython, it must be enabled (after using connect) with the setDebugLevel command. For example,

>>> daq.setDebugLevel(0)

sets the API’s logging level to 0, which provides the most verbose logging output. The other log levels are defined as following:

trace:0, debug:1, info:2, status:3, warning:4, error:5, fatal:6.

It is also possible for the user to write their own messages directly to ziPythonwith ’s log using the `writeDebugLog command. For example to write a log message of info severity level:

>>> daq.writeDebugLog(1, 'Hello log!')

On Windows the logs are located in the directory C:\Users\[USER]\AppData\Local\Temp\Zurich Instruments\LabOne Note that AppData is a hidden directory. The easiest way to find it is to open a File Explorer window and type the text %AppData%\.. in the address bar, and navigate from there. The directory contains folders containing log files from various LabOne components, in particular, the ziPythonLog folder contains logs from the LabOne Python API. On Linux, the logs can be found at "/tmp/ziPythonLog_USERNAME", where "USERNAME" is the same as the output of the "whoami" command.

LabOne Python API Tips and Tricks

In this section some tips and tricks for working with the LabOne Python API are provided.

Data Structures returned by ziPython.

The output arguments that ziPython returns are designed to use the native data structures that Python users are familiar with and that reflect the data’s location in the instruments node hierarchy. For example, when the poll command returns data from the instruments fourth demodulator (located in the node hierarchy as /dev123/demods/3/sample), the output argument contains a tree of nested dictionaries in which the data can be accessed by

data = daq.poll( poll_length, poll_timeout);
x = data['dev123']['demods']['4']['sample']['x'];
y = data['dev123']['demods']['4']['sample']['y'];
Tell poll to return a flat dictionary

By default, the data returned by poll is contained in a tree of nested dictionaries that closely mimics the tree structure of the instrument node hierarchy. By setting the optional fifth argument of poll to True, the data will be a flat dictionary. This can help avoid many nested if statements in order to check that the expected data was returned by poll. For example:

daq.subscribe('/dev123/demods/0/sample')
flat_dictionary_key = False
data = daq.poll(0.1, 200, 1, flat_dictionary_key)
if 'dev123' in data:
    if 'demods' in data['device']:
        if '0' in data['device']['demods']:
            # access the demodulator data:
            x = data['dev123']['demods']['0']['sample']['x']
            y = data['dev123']['demods']['0']['sample']['y']

Could be rewritten more concisely as:

daq.subscribe('/dev123/demods/0/sample')
flat_dictionary_key = True
data = daq.poll(0.1, 200, 1, flat_dictionary_key)
if '/dev123/demods/0/sample' in data:
    # access the demodulator data:
    x = data['/dev123/demods/0/sample']['x']
    y = data['/dev123/demods/0/sample']['y']
Use the Utility Routines to load Data saved from the LabOne UI and ziControl in Python.

The utilities package zhinst.utils contains several routines to help loading .csv or .mat files saved from either the LabOne User Interface or ziControl into Python. These functions are generally minimal wrappers around NumPy (genfromtxt()) or scipy (loadmat()) routines. However, the function load_labone_demod_csv() is optimized to load demodulator data saved in .csv format by the LabOne UI (since it specifies the .csv columns' dtypes explicitly) and the function load_zicontrol_zibin() can directly load data saved in binary format from ziControl. See the LabOne API documentation for reference documentation on these commands.