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 zhinst.core 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.

LabOne API Examples

To see the Python API in action take a look at some of the examples that we published on our public GitHub repository.

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.

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. Windows 10, x86_64, with a Python 3.5-3.9 installation.

    2. GNU/Linux with glibc 2.17 or newer (CentOS/RHEL 7+, all recent versions of Debian and Ubuntu). x86_64 wheels are available for Python 3.5-3.9. aarch64 wheels are available for Python 3.7-3.9.

    3. macOS 10.11+ x86_64 and Python 3.5-3.9. macOS 11+ arm64 (Apple Silicon) wheels are provided for Python 3.9+.

  2. Installation on Linux requires pip 19.3+ for support of the manylinux2014 platform tag. In case of problems, please try to install the package in a virtual environment with latest pip:

    $ python3 -m venv venv
    $ . venv/bin/activate
    $ pip install --upgrade pip
    $ pip install zhinst
  3. The numpy Python package.

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 the provided 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:

    import sys
    print(sys.executable)

    On Windows this will print something similar to:

    C:\Python37\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 numpy package is not yet installed, it can be downloaded from https://pypi.org/project/numpy/. 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.

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 zhinst.core for interfacing with Zurich Instruments Data Servers and devices, the LabOne Python API includes utility functions.

See the LabOne API documentation for all available utility functions, in zhinst.

Using the Built-in Documentation

zhinst.core's built-in documentation can be accessed using the help command in a python interactive shell:

  • On module level:

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

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

    >>> import zhinst.core
    >>> help(zhinst.core.ziDAQServer.poll)

See the LabOne API documentation for a full documentation.

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 zhinst.core.ziDAQServer. For example, an instance of the Sweeper Module is created using zhinst.core.ziDAQServer’s `sweep() function. As such, an API session must be instantiated first using zhinst.core.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 = zhinst.core.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('start', 1.2e5);

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

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

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. 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 the LabOne Python API 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 the LabOne Python API.

The output arguments that the LabOne Python API 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.