Skip to content

Commit

Permalink
Merge pull request #56 from adamreeve/tdms-writing
Browse files Browse the repository at this point in the history
Implement writing TDMS files
  • Loading branch information
adamreeve committed Jan 29, 2017
2 parents 0dfbbd9 + 207ff59 commit 91069c2
Show file tree
Hide file tree
Showing 18 changed files with 1,243 additions and 264 deletions.
22 changes: 16 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@ npTDMS
:alt: wercker status
:target: https://app.wercker.com/project/bykey/446c67339f7d484188a35abc64dd3f51

Cross-platform module for reading TDMS files as produced by LabView.
Data is stored as a numpy array, and is loaded using numpy's fromfile routine
so is very fast.
npTDMS is a cross-platform Python package for reading and writing TDMS files as produced by LabVIEW,
and is built on top of the `numpy <http://www.numpy.org/>`__ package.
Data read from a TDMS file is stored in numpy arrays,
and numpy arrays are also used when writing TDMS file.

Typical usage might look like::

#!/usr/bin/env python
Typical usage when reading a TDMS file might look like::

from nptdms import TdmsFile

tdms_file = TdmsFile("path_to_file.tdms")
channel = tdms_file.object('Group', 'Channel1')
data = channel.data
time = channel.time_track()
# do stuff with data

And to write a file::

from nptdms import TdmsWriter, ChannelObject
import numpy

with TdmsWriter("path_to_file.tdms") as tdms_writer:
data_array = numpy.linspace(0, 1, 10)
channel = ChannelObject('Group', 'Channel1', data_array)
tdms_writer.write_segment([channel])

For more information, see the `npTDMS documentation <http://nptdms.readthedocs.io>`__.

Installation
Expand Down
76 changes: 76 additions & 0 deletions docs/apireference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
npTDMS API Reference
====================

Reading TDMS Files
------------------

.. module:: nptdms

.. autoclass:: TdmsFile
:members:

.. automethod:: __init__

.. autoclass:: TdmsObject
:members:

Writing TDMS Files
------------------

.. autoclass:: TdmsWriter
:members:

.. automethod:: __init__

.. autoclass:: RootObject
:members:

.. automethod:: __init__

.. autoclass:: GroupObject
:members:

.. automethod:: __init__

.. autoclass:: ChannelObject
:members:

.. automethod:: __init__

Data Types for Property Values
------------------------------

.. module:: nptdms.types

.. autoclass:: Int8

.. autoclass:: Int16

.. autoclass:: Int32

.. autoclass:: Int64

.. autoclass:: Uint8

.. autoclass:: Uint16

.. autoclass:: Uint32

.. autoclass:: Uint64

.. autoclass:: SingleFloat

.. autoclass:: DoubleFloat

.. autoclass:: String

.. autoclass:: Boolean

.. autoclass:: TimeStamp

Indices and Tables
------------------

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
87 changes: 15 additions & 72 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,75 +1,18 @@
Welcome to npTDMS's documentation
=================================

npTDMS is a Python module for reading binary TDMS files produced by LabView,
and is based on the
`file format documentation <http://zone.ni.com/devzone/cda/tut/p/id/5696>`_
released by NI.

Data is read from file directly into memory and is then interpreted as a
NumPy array, so reading files should be very fast.

Installation
============

npTDMS is available from the Python Package Index, so the easiest way to
install it is by running (as root)::

pip install npTDMS

Alternatively, after downloading the source code you can extract it and
change into the new directory, then run::

python setup.py install

Quick Start
===========

Typical usage might look like::

#!/usr/bin/env python

from nptdms import TdmsFile
tdms_file = TdmsFile("path_to_file.tdms")
channel = tdms_file.object('Group', 'Channel1')
data = channel.data
time = channel.time_track()
# do stuff with data

tdmsinfo Program
================

npTDMS comes with a command line program, ``tdmsinfo``, which
lists the contents of a TDMS file.
Usage looks like::

tdmsinfo [--properties] tdms_file

Passing the ``--properties`` or ``-p`` argument will include TDMS object
properties in the printed information.

What Doesn't Work
=================

Reading TDMS files with XML headers or files with
extended floating point data currently does not work.

Reference
=========

.. module:: nptdms.tdms

.. autoclass:: TdmsFile
:members:

.. automethod:: __init__

.. autoclass:: TdmsObject
:members:

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
npTDMS is a cross-platform Python package for reading and writing TDMS files as produced by LabVIEW,
and is built on top of the `numpy <http://www.numpy.org/>`__ package.
Data read from a TDMS file is stored in numpy arrays,
and numpy arrays are also used when writing TDMS file.

Contents
========

.. toctree::
quickstart
reading
writing
apireference
tdmsinfo
limitations
5 changes: 5 additions & 0 deletions docs/limitations.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Limitations
===========

npTDMS currently doesn't support reading TDMS files with XML headers,
or files with extended floating point data.
35 changes: 35 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Installation and Quick Start
============================

npTDMS is available from the Python Package Index, so the easiest way to
install it is by running (as root)::

pip install npTDMS

Or you can install npTDMS as a non-root user inside your home directory::

pip install --user npTDMS

Alternatively, after downloading the source code you can extract it and
change into the new directory, then run::

python setup.py install

Typical usage when reading a TDMS file might look like::

from nptdms import TdmsFile

tdms_file = TdmsFile("path_to_file.tdms")
channel = tdms_file.object('Group', 'Channel1')
data = channel.data
# do stuff with data

And to write a TDMS file::

from nptdms import TdmsWriter, ChannelObject
import numpy

with TdmsWriter("path_to_file.tdms") as tdms_writer:
data_array = numpy.linspace(0, 1, 10)
channel = ChannelObject('Group', 'Channel1', data_array)
tdms_writer.write_segment([channel])
37 changes: 37 additions & 0 deletions docs/reading.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Reading TDMS files
==================

To read a TDMS file, create an instance of the :py:class:`nptdms.TdmsFile`
class, passing the path to the file, or an already opened file to the ``__init__`` method::

tdms_file = TdmsFile("my_file.tdms")

This will read the contents of the TDMS file, then the various objects
in the file can be accessed using the
:py:meth:`nptdms.TdmsFile.object` method.
An object in a TDMS file is either the root object, a group object, or a channel
object.
Only channel objects contain data, but any object may have properties associated with it.

The object returned by the ``object`` method is an instance of :py:class:`nptdms.TdmsObject`.
If this is a channel containing data, you can access the data as a numpy array using its
``data`` attribute::

channel_object = tdms_file.object("group_name", "channel_name")
data = channel_object.data

If the array is waveform data and has the ``wf_start_offset`` and ``wf_increment``
properties, you can get an array of relative time values for the data using the
:py:meth:`nptdms.TdmsObject.time_track` method::

time = channel_object.time_track()

You can also access the properties of an object using the :py:meth:`nptdms.TdmsObject.property` method,
or the :py:attr:`nptdms.TdmsObject.properties` dictionary, for example::

# Iterate over all properties and print them
for name, value in channel_object.properties.items():
print("{0}: {1}".format(name, value))

# Get a single property value
property_value = channel_object.property("my_property_name")
29 changes: 29 additions & 0 deletions docs/tdmsinfo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
The tdmsinfo Command
====================

npTDMS comes with a command line program, ``tdmsinfo``, which
lists the contents of a TDMS file.
Usage looks like::

tdmsinfo [--properties] tdms_file

Passing the ``--properties`` or ``-p`` argument will include TDMS object
properties in the printed information.

The output of tdmsinfo including properties will look something like::

/
properties:
name: test_file
/'group_1'
properties:
group_property: property value
/'group_1'/'channel_a'
data type: tdsTypeU8
properties:
wf_start_time: 2016-12-3014:56:00+00:00
wf_increment: 0.0005
wf_samples: 2000

There is also a ``--debug`` or ``-d`` argument that will output debug information
to stderr, which can be useful when debugging a problem with a TDMS file.
80 changes: 80 additions & 0 deletions docs/writing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
Writing TDMS files
==================

npTDMS has rudimentary support for writing TDMS files.
The full set of optimisations supported by the TDMS file format for
speeding up the writing of files and minimising file size are not
implemented by npTDMS, but the basic functionality required to
write TDMS files is available.

To write a TDMS file, the :py:class:`nptdms.TdmsWriter` class is used, which
should be used as a context manager.
The ``__init__`` method accepts the path to the file to create, or a file
that has already been opened in binary write mode::

with TdmsWriter("my_file.tdms") as tdms_writer:
# write data

The :py:meth:`nptdms.TdmsWriter.write_segment` method is used to write
a segment of data to the TDMS file. Because the TDMS file format is designed
for streaming data applications, it supports writing data one segment at a time
as data becomes available.
If you don't require this functionality you can simple call ``write_segment`` once
with all of your data.

The ``write_segment`` method takes a list of objects, each of which must be an
instance of one of:

- :py:class:`nptdms.RootObject`. This is the TDMS root object, and there may only be one root object in a segment.
- :py:class:`nptdms.GroupObject`. This is used to group the channel objects.
- :py:class:`nptdms.ChannelObject`. An object that contains data.
- :py:class:`nptdms.TdmsObject`. A TDMS object that was read from a TDMS file using :py:class:`nptdms.TdmsFile`.

Each of ``RootObject``, ``GroupObject`` and ``ChannelObject``
may optionally have properties associated with them, which
are passed into the ``__init__`` method as a dictionary.
The data types supported as property values are:

- Integers
- Floating point values
- Strings
- datetime objects
- Boolean values

For more control over the data type used to represent a property value, for example
to use an unsigned integer type, you can pass an instance of one of the data types
from the :py:mod:`nptdms.types` module.

A complete example of writing a TDMS file with various object types and properties
is given below::

from nptdms import TdmsWriter, RootObject, GroupObject, ChannelObject

root_object = RootObject(properties={
"prop1": "foo",
"prop2": 3,
})
group_object = GroupObject("group_1", properties={
"prop1": 1.2345,
"prop2": False,
})
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
channel_object = ChannelObject("group_1", "channel_1", data, properties={})

with TdmsWriter("my_file.tdms") as tdms_writer:
tdms_writer.write_segment([
root_object,
group_object,
channel_object])

You could also read a TDMS file and then re-write it by passing :py:class:`nptdms.TdmsObject`
instances to the ``write_segment`` method. If you want
to only copy certain objects for example, you could do something like::

from nptdms import TdmsFile, TdmsWriter

original_file = TdmsFile("original_file.tdms")

with TdmsWriter("copied_file.tdms") as copied_file:
objects_to_copy = [obj for obj in original_file.objects.values() if include_object(obj)]
copied_file.write_segment(objects_to_copy)

0 comments on commit 91069c2

Please sign in to comment.