fishbook/docs/getting_started.md

5.8 KiB

Getting started working with fishbook

Create a project folder and place the configuration file in it (see configuration for more information). If the configuration file contains the user credentials, you will not be prompted to enter them manually with every import.

Package contents

Fishbook has the following submodules:

  1. frontend - classes for standard usage
    • frontendclasses.py: classes reflect entries in the database such as Dataset, Subject, Cell, RePro, and Stimulus.
    • relacsclasses.py: classes that reflect Relacs repro classes such as BaselineRecording, FileStimulus, FIcurve.
    • util.py: util functions mainly for internal usage.
  2. backend - classes for direct database interaction
    • database.py: classes reflecting the database tables, These classes use the datajoint definitions to define the database tables and relations. Usually not needed for most users but helpful for advanced database interactions.

First steps

import fishbook as fb

# the following command will find and load all (!) dataset entries in the database
datasets, count = fb.Dataset.find()
print(count)

# or use 
print(fb.Dataset.datasetCount())

Finding what you might look for

For some classes, fetching and converting all matches to python objects of the Dataset class may take a while. You could then use a loop to iterate over the list of datasets and apply filters in python. This is fine, but has poor performance, better we use the underlying database for such restrictions. Again using the Dataset class restrictions can be done like this:

# to test your restrictions you may want to set the test==True flag
_, count = fb.Dataset.find(quality="good", min_date="2018-01-01", max_date="2018-12-31", test=True)
print(count)

# if you indeed want to fetch the results
datasets, count = fb.Dataset.find(quality="good", min_date="2018-01-01", max_date="2018-12-31")
print(len(datasets))

You can use the dataset class as an entry point to explore what is stored in the database about this dataset, e.g. wich cell(s) was recorded and the subject infromation.

d = datasets[0]
print(d)

cells = d.cells  # get the cells recorded in this dataset
cell = cells[0]
print(cell)

s = cell.subject
print(s)

# in a given subject we may record several cells
print(len(s.cells))

Which RePros were run in a given dataset?

In a dataset we may run several repros:

repros = d.repro_runs()
for r in repros:
    print(r)

in this example this leads to an output like, this. Two Research Protocols were run, this first the "BaselineActivity" repro and the second the "ReceptiveField" repro.

RePro: BaselineActivity  id: BaselineActivity_0
run: 0   on cell: 2018-01-10-ag
start time: 0.0  duration: 40.0796

RePro: ReceptiveField    id: ReceptiveField_0
run: 0   on cell: 2018-01-10-ag
start time: 40.0796      duration: 236.42

Getting information about the stimuli

The latter puts out a set of stimuli we may be interested in:

r = d.repro_runs()[-1]
stimuli = r.stimuli
print(len(stimuli))  # 90 in this example case
for stim in stimuli[:10]:  # let's print the first 10
    print(stim)

An entry in the Stimuli table (see ER-schema for details) is characterized by the stimulus id, the start time or start index (depends on the data source) and a stimulus duration. The stimulus also carries a textfield with the stimulus settings.

stim.settings

>> 'ReceptiveField-1:\n\tReceptiveField-1:\n\t\tModality: electric\n\t\tSamplingRate: 37.59398496240602+- -1.000\n\t\tdur: 0.0+- -1.000\n\t\tampl: 0.0+- -1.000\n\t\tdeltaf: 0.0+- -1.000\n\t\tfreq: 0.0+- -1.000\n\t\tx_pos: 0.0+- -1.000\n\t\ty_pos: 0.0+- -1.000\n\t\tz_pos: 0.0+- -1.000\n\tEOD Rate: 826.6917939137279 Hz\n\tEOD Amplitude: 0.4263797848004206 mV\n\tGlobalEField: 0.0 V\n\tGlobalEFieldAM: 0.0 V\n\tLocalEField: 0.0 V\n\tI: 0.0 V\n\ttime: 294.9933 s\n\tdelay: 0.0 s\n\tintensity: 0.039810717055349734 mV/cm\n\tdur: 1.0 \n\tampl: 0.04 \n\tdeltaf: 20.0 \n\tfreq: 854.7108299738921 \n\tx_pos: 142.5 \n\ty_pos: 2.0 \n\tz_pos: -15.0 \n'

# to convert it to yaml
import yaml
settings = yaml.safe_load(stim.settings.replace("\t", ""))
print(settings)

The output:

 {'ReceptiveField-1': None,
 'Modality': 'electric',
 'SamplingRate': '37.59398496240602+- -1.000',
 'dur': 1.0,
 'ampl': 0.04,
 'deltaf': 20.0,
 'freq': 854.7108299738921,
 'x_pos': 142.5,
 'y_pos': 2.0,
 'z_pos': -15.0,
 'EOD Rate': '826.6917939137279 Hz',
 'EOD Amplitude': '0.4263797848004206 mV',
 'GlobalEField': '0.0 V',
 'GlobalEFieldAM': '0.0 V',
 'LocalEField': '0.0 V',
 'I': '0.0 V',
 'time': '294.9933 s',
 'delay': '0.0 s',
 'intensity': '0.039810717055349734 mV/cm'}

Finding the data

The Stimulus in conjunction with the Dataset provides all infromation needed to get the data from the recorded traces.

The dataset can be located from the Dataset class:

print(d.data_source)  # the absolute path from which the data was imported
print(d.data_host)  # the fully qaulified host name

print(d.has_nix)  # informs whether data is stored in a nix file.

Let's assume you have access to the dataset and it uses a NIX file:

import os
import glob
import nixio as nix

path = d.data_source
assert(os.path.exists(path))
if (d.has_nix):
    nix_file = glob.glob(path + os.sep + "*nix")[0]  # there should only be one nix file
    mtag_id = stim.multi_tag_id
    position_index = stim.index

    nf = nix.File.open(nix_file, nix.FileMode.ReadOnly)
    block = nf.blocks[0]  # there is only a single block in relacs written files
    mt = block.multi_tags[mtag_id]
    data = mt.retrieve_data(position_index, "V-1")[:]  # we are interested in the membrane voltage
    nf.close()

    print(data.shape)