Skip to content

Commit f2c0cd6

Browse files
authored
Merge pull request #514 from jgrewe/docs
rewrite of the docs
2 parents 29e439a + 474d76a commit f2c0cd6

File tree

95 files changed

+2718
-1313
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2718
-1313
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ Makefile
4646
.cache
4747
.eggs
4848
.mypy_cache
49+
50+
# vscode
51+
.vscode

README.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ The simplest way to install *NIXPY* is from PyPI using pip. The name of the pack
2727

2828
pip install nixio
2929

30-
Bindings for C++ NIX
31-
--------------------
32-
33-
The setup script will automatically build the bindings for *NIX* if it is detected on the system, otherwise only the pure Python version will be installed.
34-
35-
For instructions on building *NIX*, see the `NIX README <https://github.com/G-Node/nix/blob/master/README.md>`_ file.
36-
3730

3831
To check if installed properly
3932
------------------------------

docs/source/annotations.rst

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
.. toctree::
2+
:maxdepth: 1
3+
4+
.. _metadata:
5+
6+
Annotations with arbitrary metadata
7+
===================================
8+
9+
The entities of the data model that were discussed so far carry just enough information to get a basic understanding of the stored data. Often much more information than that is required. Storing additional metadata is a central part of the NIX concept. We use a slightly modified version of the *odML* data model for metadata to store additional information. In brief: the model consists of *Sections* that contain *Properties* which in turn carry a list of values. Again, *Sections* can be nested to represent logical dependencies in the hierarchy of a tree. While all data entities discussed above are children of *Block* entities, the metadata lives parallel to the *Blocks*. The idea behind this is that several blocks may refer to the same metadata, or, the other way round the metadata applies to data entities in several blocks. The *types* used for the *Sections* in the following example are defined
10+
in the `odml terminologies <https://github.com/G-Node/odml-terminologies>`_
11+
12+
Most of the data entities can link to metadata sections.
13+
14+
.. literalinclude:: examples/annotations.py
15+
:lines: 5-21
16+
:caption: We can add arbitrary metadata in trees of *Sections* and *Properties* (:download:`example code <examples/annotations.py>`).
17+
18+
For a quick view of the metadata tree pretty-print it:
19+
20+
.. literalinclude:: examples/annotations.py
21+
:lines: 24
22+
23+
which leads to an output like this. The argument ``max_depth=-1`` notes that the full depth of the tree should be displayed. In the default case (``max_depth=1``) the display will be more compact and will not recursively traverse the whole tree.
24+
25+
.. code-block:: text
26+
27+
recording session [odml.recording]
28+
|- experimenter: ('John Doe',)
29+
|- recording date: ('2014-01-01',)
30+
subject [odml.subject]
31+
|- id: ('mouse xyz',)
32+
cell [odml.cell]
33+
|- resting potential: (-64.5,)mV
34+
35+
The *Sections* add much like dictionaries. To access e.g. the "resting potential" of the cell we may call:
36+
37+
.. literalinclude:: examples/annotations.py
38+
:lines: 26
39+
40+
Extending Properties
41+
--------------------
42+
43+
Properties can carry multiple values and additional information such as a definition.
44+
45+
.. literalinclude:: examples/annotations.py
46+
:lines: 33-35
47+
48+
Reading the values will return a tuple. This has the background that one cannot change a tuple. Changing the values stored in a *Property* can be done e.g. by the ``extend_values`` method
49+
50+
.. literalinclude:: examples/annotations.py
51+
:lines: 37-38
52+
53+
One can extend it by single values or by lists of values.
54+
55+
The data type of all values must, however, be the same. Adding a number to the list of strings will fail with a ``TypeError``:
56+
57+
.. literalinclude:: examples/annotations.py
58+
:lines: 40-43
59+
60+
.. code-block:: text
61+
62+
New data type '<class 'numpy.int64'>' is inconsistent with the Property's data type '<class 'numpy.str_'>'
63+
64+
**Note:** Once the property has been created, the data type can't be changed. One would need to create a replacement with the desired data type.
65+
66+
Finding annotations
67+
-------------------
68+
69+
If we do not know the exact path of the *Section* we are looking for, we need to search it by passing a function (in this case a lambda function) to the ``find_section`` method. The following code shows two examples in which we look first for a section with a given name or second a section which contains a property with a certain name.
70+
71+
.. literalinclude:: examples/annotations.py
72+
:lines: 28 - 31
73+
74+
The result of the ``find_sections`` will always be a list which may be empty if no match was found. Therefore, the call in the last line is to some extent risky and would lead to an ``OutOfBounds`` exception if the search failed.

docs/source/api/modules.rst

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs/source/api/nixio.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
nixio package
2-
=============
1+
Internal API
2+
============
33

44
Subpackages
55
-----------

docs/source/basic_idea.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Idea
2+
====
3+
4+
The basic idea of the *NIX* project is to come up with a **generic**
5+
data model that defines as few structures/entities as possible while
6+
being able to represent a multitude of different data structures, allows
7+
for in-depth annotation and supports standardization.
8+
9+
Designing a **generic** data model implies that the defined entities are
10+
named in a way that may seem uncommon but are more general than the
11+
*domain-specific* terms used in any given field or community.
12+
13+
14+
Please follow this link to the `C++ nix library documentation <https://nixio.readthedocs.io/en/master/data_model.html>`_ to lear more about the data model.
15+
16+
The idea of the *NIX* data model has been implemented using the
17+
`HDF5 <https://www.hdfgroup.org>`__ file format.

docs/source/conf.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright © 2014, German Neuroinformatics Node (G-Node)
1+
# Copyright © 2014-2021, German Neuroinformatics Node (G-Node)
22
#
33
# All rights reserved.
44
#
@@ -9,40 +9,31 @@
99
from nixio.info import RELEASE, COPYRIGHT, BRIEF
1010

1111
# general config
12-
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
13-
source_suffix = '.rst'
14-
master_doc = 'index'
15-
project = BRIEF
16-
copyright = COPYRIGHT
17-
release = RELEASE
18-
exclude_patterns = []
19-
pygments_style = 'sphinx'
12+
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.autosectionlabel']
13+
source_suffix = '.rst'
14+
master_doc = 'index'
15+
project = BRIEF
16+
copyright = COPYRIGHT
17+
release = RELEASE
18+
exclude_patterns = []
19+
pygments_style = 'sphinx'
2020

2121
# html options
22-
htmlhelp_basename = 'nixio'
22+
htmlhelp_basename = 'nixio'
2323
try:
24-
html_theme = 'sphinx_rtd_theme'
25-
html_sidebars = {
26-
'**': [
27-
'about.html', 'navigation.html', 'searchbox.html',
28-
]
29-
}
24+
html_theme = 'sphinx_rtd_theme'
25+
html_sidebars = {'**': ['about.html', 'navigation.html', 'searchbox.html']}
3026

31-
html_theme_options = {
32-
'logo' : 'logo.png',
33-
'github_user' : 'G-Node',
34-
'github_repo' : 'nixpy',
35-
'github_button' : True,
36-
'github_count' : False,
37-
'travis_button' : True,
38-
'link' : '#456BA8'
39-
}
27+
html_theme_options = {'logo_only': True,
28+
'display_version': True,
29+
'style_external_links': True,
30+
'prev_next_buttons_location': "both"}
31+
32+
html_logo = "nix_logo.png"
4033

4134
except ImportError:
42-
html_theme = 'default'
35+
html_theme = 'default'
4336

4437
# intersphinx configuration
45-
intersphinx_mapping = {
46-
'http://docs.python.org/' : None,
47-
'http://docs.scipy.org/doc/numpy': None
48-
}
38+
intersphinx_mapping = {'http://docs.python.org/': None,
39+
'http://docs.scipy.org/doc/numpy': None}

docs/source/contact.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.. :toctree::
2+
:maxdepth: 2
3+
4+
Getting support
5+
===============
6+
7+
If you experience problems using *NIX* feel free to join our IRC
8+
channel `#gnode at FreeNode <irc://irc.freenode.net/gnode>`__ or write
9+
an email to [email protected]. If you find a bug or have a feature
10+
request please report it using the `project issue tracker
11+
<https://github.com/G-Node/nixpy/issues>`__.
12+
13+
14+
Contact
15+
-------
16+
17+
The project is maintained by the `German Neuroinformatics Node,
18+
G-Node <http://www.g-node.org>`__. `G-Node at
19+
GitHub <https://github.com/g-node>`__,
20+
`email <mailto:[email protected]>`__.

docs/source/data_handling.rst

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
.. toctree::
2+
:maxdepth: 1
3+
4+
Working with data
5+
=================
6+
7+
Storing data is one thing, but we want to work with it. The following examples illustrate reading of data from *DataArray*, *Tag* and *MultiTag* entities. We will use the dummy dataset already used in the :doc:`tagging <./tagging>` example. The figure below shows what is stored in the dataset.
8+
9+
.. figure:: ./images/tag1.png
10+
:alt: a system's response to a stimulus
11+
12+
At some instance in time a system was exposed to a stimulus that leads to the system's response. The response has been recorded and stored in a *DataArray*, a *Tag* is used to highlight the "stimulus-on" segment of the data.
13+
14+
.. literalinclude:: examples/tagging_example.py
15+
:caption: :download:`example code <examples/tagging_example.py>`
16+
:lines: 78 - 90
17+
18+
In this example we know the interesting entities by name, i.e. the
19+
*DataArray* is called **response** and the *Tag* is called **stimulus**.
20+
In cases in which we have no clue about the names, we just have to
21+
browse the file or `search <./finding_things.md>`__ by name or type.
22+
23+
Reading data
24+
------------
25+
26+
The first and maybe most common problem is to read the data stored in a
27+
*DataArray*.
28+
29+
Reading all data
30+
~~~~~~~~~~~~~~~~
31+
32+
In *NIX* when you open a *DataArray* the stored data is **not** automatically read from file. This keeps the object lightweight and easy to create. To read the data you can simply access it in a numpy style:
33+
34+
.. literalinclude:: examples/tagging_example.py
35+
:caption: :download:`example code <examples/tagging_example.py>`
36+
:lines: 71 - 73
37+
38+
There are a few noteworthy things:
39+
40+
- We use some previous knowledge here. For one, we know the names of the entities. Further, we know that the data is 1-D and the single dimension is a ``SampledDimension``. If these things are not known, the NIX library offers the necessary functions to get this information.
41+
- ``DataArray.shape`` returns a tuple with the data shape.
42+
- ``DataArray.dtype`` returns the data type.
43+
- To find out the ``DimensionType``, we need to access the dimension:
44+
45+
.. code-block:: python
46+
47+
for dim in data_array.dimensions:
48+
print(dim.dimension_type)
49+
50+
51+
Reading partial data
52+
~~~~~~~~~~~~~~~~~~~~
53+
54+
In other instances it might be wanted to read only parts of the data.
55+
Reading slices of the data is straight forward using the numpy style.
56+
57+
.. literalinclude:: examples/tagging_example.py
58+
:caption: :download:`example code <examples/tagging_example.py>`
59+
:lines: 98-101
60+
61+
An alternative approach is to use the ``DataArray.get_slice`` method which by default works with indices but can also work in data coordinates. E.g. we know that the data is 1-D and covers a span of 3.5s and we want to have the data in the interval 0.5s through 1.75s. The method returns a ``nixio.DataView`` object. The actual reading is done by accessing the data.
62+
63+
.. literalinclude:: examples/tagging_example.py
64+
:caption: :download:`example code <examples/tagging_example.py>`
65+
:lines: 103-106
66+
:emphasize-lines: 3
67+
68+
The arguments ``positions`` and ``extents`` are passed as lists. There must be one entry for each dimension of the data. In this case, since the data is 1-D, positions and extents are 1-element lists.
69+
Note: the slice is defined by the starting point(s) and the *extent(s)*, not with start and end points.
70+
71+
Reading tagged data
72+
~~~~~~~~~~~~~~~~~~~
73+
74+
*Tag* and *MultiTag* tag single or multiple points or regions in data stored in the referenced *DataArrays* (see `tagging <./tagging.md>`__ for more information and the example data created in the `example <#mtag_regions>`__ will be used in the following code snippets).
75+
76+
.. figure:: ./images/multiple_regions.png
77+
:alt: tagging multiple segments
78+
79+
Plot of the data created by this :download:`example <examples/multiple_regions.py>` on tagging multiple regions in data.
80+
81+
In order to read the data that belongs to the highlighted region(s) *Tag* and *MultiTag* define the ``tagged_data`` methods which return ``nixio.DataView`` objects from which the data is read as shown above. The following code snippet shows how to use these function:
82+
83+
.. literalinclude:: examples/multiple_regions.py
84+
:lines: 86 - 97
85+
:emphasize-lines: 10
86+
:caption: Reading data segments tagged by the *Tag* or *MultiTag* can be done using the ``tagged_data`` method (:download:`example code <examples/multiple_regions.py>`).
87+
88+
The *MultiTag* version of the ``tagged_data`` method takes two arguments. The first is the index of the tagged region (0 for the first), the second argument is the name of the referenced *DataArray* (you can also use the index or the id). Since the *Tag* tags only a single region, it takes only one argument, i.e. the name (id, index) of the referenced *DataArray*.
89+
90+
.. figure:: ./images/reading_tagged_data.png
91+
:alt: reading tagged data
92+
93+
94+
Analogously, the feature data attached to the *Tag* or *MultiTag* can be
95+
obtained using the ``feature_data`` methods.
96+
97+
.. literalinclude:: examples/multiple_regions.py
98+
:lines: 69 - 76
99+
:emphasize-lines: 6, 7
100+
:caption: ``feature_data`` works analogously, the first argument is the index of the tagged region, the second the name (or id or index) of the feature. Here the feature stores a single number, i.e. the frequency of the stimulus for each tagged region which is plotted below the highlighted regions in the figure above (:download:`example code <examples/multiple_regions.py>`).
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import nixio
2+
3+
def main():
4+
5+
nixfile = nixio.File.open("annotations.nix", mode=nixio.FileMode.Overwrite)
6+
block = nixfile.create_block("recording 1", "nix.session")
7+
8+
session = nixfile.create_section('recording session', 'odml.recording')
9+
session['experimenter'] = 'John Doe'
10+
session['recording date'] = '2014-01-01'
11+
12+
subject = session.create_section('subject', 'odml.subject')
13+
subject['id'] = 'mouse xyz'
14+
15+
cell = subject.create_section('cell', 'odml.cell')
16+
p = cell.create_property('resting potential', -64.5)
17+
p.uncertainty = 2.25
18+
p.unit = 'mV'
19+
20+
# set the recording block metadata
21+
block.metadata = session
22+
23+
# query the metadata
24+
block.metadata.pprint(max_depth=-1)
25+
26+
print(block.metadata["subject"]["cell"]["resting potential"])
27+
28+
print(session.find_sections(lambda s: s.name.lower() == "cell"))
29+
30+
print(session.find_sections(lambda s: "resting potential" in s.props))
31+
print(session.find_sections(lambda s: "resting potential" in s.props)[0]["resting potential"])
32+
33+
observations = subject.create_property("observations", ["p10", "p12", "p14"])
34+
observations.definition = "Some behavioral observations I did on several days"
35+
print(observations.values)
36+
37+
observations.extend_values("p16")
38+
observations.extend_values(["p18", "p20"])
39+
40+
try:
41+
observations.extend_values(22)
42+
except TypeError as e:
43+
print(e)
44+
45+
nixfile.close()
46+
47+
if __name__ == "__main__":
48+
main()

0 commit comments

Comments
 (0)