|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +This is an example for creating simple plots from various Neo structures. |
| 4 | +It includes a function that generates toy data. |
| 5 | +""" |
| 6 | +from __future__ import division # Use same division in Python 2 and 3 |
| 7 | + |
| 8 | +import numpy as np |
| 9 | +import quantities as pq |
| 10 | +from matplotlib import pyplot as plt |
| 11 | + |
| 12 | +import neo |
| 13 | + |
| 14 | + |
| 15 | +def generate_block(n_segments=3, n_channels=8, n_units=3, |
| 16 | + data_samples=1000, feature_samples=100): |
| 17 | + """ |
| 18 | + Generate a block with a single recording channel group and a number of |
| 19 | + segments, recording channels and units with associated analog signals |
| 20 | + and spike trains. |
| 21 | + """ |
| 22 | + feature_len = feature_samples / data_samples |
| 23 | + |
| 24 | + # Create container and grouping objects |
| 25 | + segments = [neo.Segment(index=i) for i in range(n_segments)] |
| 26 | + |
| 27 | + rcg = neo.RecordingChannelGroup(name='T0') |
| 28 | + for i in range(n_channels): |
| 29 | + rc = neo.RecordingChannel(name='C%d' % i, index=i) |
| 30 | + rc.recordingchannelgroups = [rcg] |
| 31 | + rcg.recordingchannels.append(rc) |
| 32 | + |
| 33 | + units = [neo.Unit('U%d' % i) for i in range(n_units)] |
| 34 | + rcg.units = units |
| 35 | + |
| 36 | + block = neo.Block() |
| 37 | + block.segments = segments |
| 38 | + block.recordingchannelgroups = [rcg] |
| 39 | + |
| 40 | + # Create synthetic data |
| 41 | + for seg in segments: |
| 42 | + feature_pos = np.random.randint(0, data_samples - feature_samples) |
| 43 | + |
| 44 | + # Analog signals: Noise with a single sinewave feature |
| 45 | + wave = 3 * np.sin(np.linspace(0, 2 * np.pi, feature_samples)) |
| 46 | + for rc in rcg.recordingchannels: |
| 47 | + sig = np.random.randn(data_samples) |
| 48 | + sig[feature_pos:feature_pos + feature_samples] += wave |
| 49 | + |
| 50 | + signal = neo.AnalogSignal(sig * pq.mV, sampling_rate=1 * pq.kHz) |
| 51 | + seg.analogsignals.append(signal) |
| 52 | + rc.analogsignals.append(signal) |
| 53 | + |
| 54 | + # Spike trains: Random spike times with elevated rate in short period |
| 55 | + feature_time = feature_pos / data_samples |
| 56 | + for u in units: |
| 57 | + random_spikes = np.random.rand(20) |
| 58 | + feature_spikes = np.random.rand(5) * feature_len + feature_time |
| 59 | + spikes = np.hstack([random_spikes, feature_spikes]) |
| 60 | + |
| 61 | + train = neo.SpikeTrain(spikes * pq.s, 1 * pq.s) |
| 62 | + seg.spiketrains.append(train) |
| 63 | + u.spiketrains.append(train) |
| 64 | + |
| 65 | + neo.io.tools.create_many_to_one_relationship(block) |
| 66 | + return block |
| 67 | + |
| 68 | +block = generate_block() |
| 69 | + |
| 70 | + |
| 71 | +# In this example, we treat each segment in turn, averaging over the channels |
| 72 | +# in each: |
| 73 | +for seg in block.segments: |
| 74 | + print("Analysing segment %d" % seg.index) |
| 75 | + |
| 76 | + siglist = seg.analogsignals |
| 77 | + time_points = siglist[0].times |
| 78 | + avg = np.mean(siglist, axis=0) # Average over signals of Segment |
| 79 | + |
| 80 | + plt.figure() |
| 81 | + plt.plot(time_points, avg) |
| 82 | + plt.title("Peak response in segment %d: %f" % (seg.index, avg.max())) |
| 83 | + |
| 84 | +# The second alternative is spatial traversal of the data (by channel), with |
| 85 | +# averaging over trials. For example, perhaps you wish to see which physical |
| 86 | +# location produces the strongest response, and each stimulus was the same: |
| 87 | + |
| 88 | +# We assume that our block has only 1 RecordingChannelGroup and each |
| 89 | +# RecordingChannel only has 1 AnalogSignal. |
| 90 | +rcg = block.recordingchannelgroups[0] |
| 91 | +for rc in rcg.recordingchannels: |
| 92 | + print("Analysing channel %d: %s" % (rc.index, rc.name)) |
| 93 | + |
| 94 | + siglist = rc.analogsignals |
| 95 | + time_points = siglist[0].times |
| 96 | + avg = np.mean(siglist, axis=0) # Average over signals of RecordingChannel |
| 97 | + |
| 98 | + plt.figure() |
| 99 | + plt.plot(time_points, avg) |
| 100 | + plt.title("Average response on channel %d" % rc.index) |
| 101 | + |
| 102 | +# There are three ways to access the spike train data: by Segment, |
| 103 | +# by RecordingChannel or by Unit. |
| 104 | + |
| 105 | +# By Segment. In this example, each Segment represents data from one trial, |
| 106 | +# and we want a peristimulus time histogram (PSTH) for each trial from all |
| 107 | +# Units combined: |
| 108 | +for seg in block.segments: |
| 109 | + print("Analysing segment %d" % seg.index) |
| 110 | + stlist = [st - st.t_start for st in seg.spiketrains] |
| 111 | + count, bins = np.histogram(np.hstack(stlist)) |
| 112 | + plt.figure() |
| 113 | + plt.bar(bins[:-1], count, width=bins[1] - bins[0]) |
| 114 | + plt.title("PSTH in segment %d" % seg.index) |
| 115 | + |
| 116 | +# By Unit. Now we can calculate the PSTH averaged over trials for each Unit: |
| 117 | +for unit in block.list_units: |
| 118 | + stlist = [st - st.t_start for st in unit.spiketrains] |
| 119 | + count, bins = np.histogram(np.hstack(stlist)) |
| 120 | + plt.figure() |
| 121 | + plt.bar(bins[:-1], count, width=bins[1] - bins[0]) |
| 122 | + plt.title("PSTH of unit %s" % unit.name) |
| 123 | + |
| 124 | +# By RecordingChannelGroup. Here we calculate a PSTH averaged over trials by |
| 125 | +# channel location, blending all Units: |
| 126 | +for rcg in block.recordingchannelgroups: |
| 127 | + stlist = [] |
| 128 | + for unit in rcg.units: |
| 129 | + stlist.extend([st - st.t_start for st in unit.spiketrains]) |
| 130 | + count, bins = np.histogram(np.hstack(stlist)) |
| 131 | + plt.figure() |
| 132 | + plt.bar(bins[:-1], count, width=bins[1] - bins[0]) |
| 133 | + plt.title("PSTH blend of recording channel group %s" % rcg.name) |
| 134 | + |
| 135 | +plt.show() |
0 commit comments