def spikes(spikes, axes_style, strong=None, anti_alias=False, fade=1.0, subplot_layout=0, time_unit=pq.ms, progress=None): """ Create a plot dialog with spike waveforms. Assumes that all spikes have waveforms with the same number of channels. :param dict spikes: A dictionary of :class:`neo.core.Spike` lists. :param int axes_style: Plotting mode. The following values are possible: - 1: Show each channel in a seperate plot, split vertically. - 2: Show each channel in a separate plot, split horizontally. - 3: Show each key of ``spikes`` in a separate plot, channels are split vertically. - 4: Show each key of ``spikes`` in a separate plot, channels are split horizontally. - 5: Show all channels in the same plot, split vertically. - 6: Show all channels in the same plot, split horizontally. :param dict strong: A dictionary of :class:`neo.core.Spike` lists. When given, these spikes are shown as thick lines on top of the regular spikes in the respective plots. :param bool anti_alias: Determines whether an antialiased plot is created. :param float fade: Vary transparency by segment. For values > 0, the first spike for each unit is displayed with the corresponding alpha value and alpha is linearly interpolated until it is 1 for the last spike. For values < 0, alpha is 1 for the first spike and ``fade`` for the last spike. Does not affect spikes from ``strong``. :param bool subplot_layout: The way subplots are arranged on the window: - 0: Linear - horizontally or vertically, depending on ``axis_style``. - 1: Square - this layout tries to have the same number of plots per row and per column. :param Quantity time_unit: Unit of X-Axis. :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if (not spikes or sum((len(l) for l in spikes.itervalues())) < 1) and \ (not strong or sum((len(l) for l in strong.itervalues())) < 1): raise SpykeException('No spikes for spike waveform plot!') if not progress: progress = ProgressIndicator() if strong is None: strong = {} progress.begin('Creating waveform plot') progress.set_ticks( sum((len(l) for l in spikes.itervalues())) + sum((len(l) for l in strong.itervalues()))) win_title = 'Spike waveforms' win = PlotDialog(toolbar=True, wintitle=win_title) try: ref_spike = spikes[spikes.keys()[0]][0] except IndexError: ref_spike = strong[strong.keys()[0]][0] if ref_spike.waveform is None: raise SpykeException('Cannot create waveform plot: At least one spike ' 'has no waveform or sampling rate!') ref_units = ref_spike.waveform.units channels = range(ref_spike.waveform.shape[1]) # Keys from spikes and strong without duplicates in original order seen = set() indices = [ k for k in spikes.keys() + strong.keys() if k not in seen and not seen.add(k) ] if axes_style <= 2: # Separate channel plots for c in channels: pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) for u in spikes: color = helper.get_object_color(u) qcol = Qt.QColor(color) alpha = fade if fade > 0.0 else 1.0 alpha_step = 1.0 - fade if fade > 0.0 else -1.0 - fade alpha_step /= len(spikes[u]) if len(spikes[u]) == 1: alpha = 1.0 for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException('Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve(x, s.waveform[:, c].rescale(ref_units), title=u.name, color=color) qcol.setAlphaF(alpha) curve.setPen(Qt.QPen(qcol)) alpha += alpha_step plot.add_item(curve) progress.step() for u in strong: color = helper.get_object_color(u) for s in strong[u]: x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) outline = make.curve(x, s.waveform[:, c].rescale(ref_units), color='#000000', linewidth=4) curve = make.curve(x, s.waveform[:, c].rescale(ref_units), color=color, linewidth=2) plot.add_item(outline) plot.add_item(curve) progress.step() _add_plot(plot, pw, win, c, len(channels), subplot_layout, axes_style, time_unit, ref_units) helper.make_window_legend(win, indices, True) elif axes_style > 4: # Only one plot needed pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) if axes_style == 6: # Horizontal split l = _split_plot_hor(channels, spikes, strong, fade, ref_units, time_unit, progress, plot) plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, time_unit.dimensionality.string) else: # Vertical split channels.reverse() max_offset = _find_y_offset(channels, spikes, strong, ref_units) l = _split_plot_ver(channels, spikes, strong, fade, ref_units, time_unit, progress, max_offset, plot) plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit(BasePlot.Y_LEFT, ref_units.dimensionality.string) win.add_plot_widget(pw, 0) win.add_legend_option([l], True) else: # One plot per unit if axes_style == 3: channels.reverse() max_offset = _find_y_offset(channels, spikes, strong, ref_units) for i, u in enumerate(indices): pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) spk = {} if u in spikes: spk[u] = spikes[u] st = {} if u in strong: st[u] = strong[u] if axes_style == 3: # Vertical split _split_plot_ver(channels, spk, st, fade, ref_units, time_unit, progress, max_offset, plot) else: # Horizontal split _split_plot_hor(channels, spk, st, fade, ref_units, time_unit, progress, plot) _add_plot(plot, pw, win, i, len(indices), subplot_layout, axes_style, time_unit, ref_units) win.add_custom_curve_tools() progress.done() win.show() if axes_style <= 2: if len(channels) > 1: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(True, channels) elif axes_style <= 4: if len(spikes) > 1: win.add_x_synchronization_option(True, range(len(spikes))) win.add_y_synchronization_option(True, range(len(spikes))) return win
def spikes(spikes, axes_style, strong=None, anti_alias=False, fade=1.0, subplot_layout=0, time_unit=pq.ms, progress=None): """ Create a plot dialog with spike waveforms. Assumes that all spikes have waveforms with the same number of channels. :param dict spikes: A dictionary of :class:`neo.core.Spike` lists. :param int axes_style: Plotting mode. The following values are possible: - 1: Show each channel in a seperate plot, split vertically. - 2: Show each channel in a separate plot, split horizontally. - 3: Show each key of ``spikes`` in a separate plot, channels are split vertically. - 4: Show each key of ``spikes`` in a separate plot, channels are split horizontally. - 5: Show all channels in the same plot, split vertically. - 6: Show all channels in the same plot, split horizontally. :param dict strong: A dictionary of :class:`neo.core.Spike` lists. When given, these spikes are shown as thick lines on top of the regular spikes in the respective plots. :param bool anti_alias: Determines whether an antialiased plot is created. :param float fade: Vary transparency by segment. For values > 0, the first spike for each unit is displayed with the corresponding alpha value and alpha is linearly interpolated until it is 1 for the last spike. For values < 0, alpha is 1 for the first spike and ``fade`` for the last spike. Does not affect spikes from ``strong``. :param bool subplot_layout: The way subplots are arranged on the window: - 0: Linear - horizontally or vertically, depending on ``axis_style``. - 1: Square - this layout tries to have the same number of plots per row and per column. :param Quantity time_unit: Unit of X-Axis. :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if (not spikes or sum((len(l) for l in spikes.itervalues())) < 1) and \ (not strong or sum((len(l) for l in strong.itervalues())) < 1): raise SpykeException('No spikes for spike waveform plot!') if not progress: progress = ProgressIndicator() if strong is None: strong = {} progress.begin('Creating waveform plot') progress.set_ticks( sum((len(l) for l in spikes.itervalues())) + sum((len(l) for l in strong.itervalues()))) win_title = 'Spike waveforms' win = PlotDialog(toolbar=True, wintitle=win_title) try: ref_spike = spikes[spikes.keys()[0]][0] except IndexError: ref_spike = strong[strong.keys()[0]][0] if ref_spike.waveform is None: raise SpykeException( 'Cannot create waveform plot: At least one spike ' 'has no waveform or sampling rate!') ref_units = ref_spike.waveform.units channels = range(ref_spike.waveform.shape[1]) # Keys from spikes and strong without duplicates in original order seen = set() indices = [k for k in spikes.keys() + strong.keys() if k not in seen and not seen.add(k)] if axes_style <= 2: # Separate channel plots for c in channels: pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) for u in spikes: color = helper.get_object_color(u) qcol = Qt.QColor(color) alpha = fade if fade > 0.0 else 1.0 alpha_step = 1.0 - fade if fade > 0.0 else -1.0 - fade alpha_step /= len(spikes[u]) if len(spikes[u]) == 1: alpha = 1.0 for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException( 'Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve( x, s.waveform[:, c].rescale(ref_units), title=u.name, color=color) qcol.setAlphaF(alpha) curve.setPen(Qt.QPen(qcol)) alpha += alpha_step plot.add_item(curve) progress.step() for u in strong: color = helper.get_object_color(u) for s in strong[u]: x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) outline = make.curve( x, s.waveform[:, c].rescale(ref_units), color='#000000', linewidth=4) curve = make.curve( x, s.waveform[:, c].rescale(ref_units), color=color, linewidth=2) plot.add_item(outline) plot.add_item(curve) progress.step() _add_plot(plot, pw, win, c, len(channels), subplot_layout, axes_style, time_unit, ref_units) helper.make_window_legend(win, indices, True) elif axes_style > 4: # Only one plot needed pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) if axes_style == 6: # Horizontal split l = _split_plot_hor(channels, spikes, strong, fade, ref_units, time_unit, progress, plot) plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit( BasePlot.X_BOTTOM, time_unit.dimensionality.string) else: # Vertical split channels.reverse() max_offset = _find_y_offset(channels, spikes, strong, ref_units) l = _split_plot_ver(channels, spikes, strong, fade, ref_units, time_unit, progress, max_offset, plot) plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit( BasePlot.Y_LEFT, ref_units.dimensionality.string) win.add_plot_widget(pw, 0) win.add_legend_option([l], True) else: # One plot per unit if axes_style == 3: channels.reverse() max_offset = _find_y_offset(channels, spikes, strong, ref_units) for i, u in enumerate(indices): pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) spk = {} if u in spikes: spk[u] = spikes[u] st = {} if u in strong: st[u] = strong[u] if axes_style == 3: # Vertical split _split_plot_ver(channels, spk, st, fade, ref_units, time_unit, progress, max_offset, plot) else: # Horizontal split _split_plot_hor(channels, spk, st, fade, ref_units, time_unit, progress, plot) _add_plot(plot, pw, win, i, len(indices), subplot_layout, axes_style, time_unit, ref_units) win.add_custom_curve_tools() progress.done() win.show() if axes_style <= 2: if len(channels) > 1: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(True, channels) elif axes_style <= 4: if len(spikes) > 1: win.add_x_synchronization_option(True, range(len(spikes))) win.add_y_synchronization_option(True, range(len(spikes))) return win
def signals(signals, events=None, epochs=None, spike_trains=None, spikes=None, show_waveforms=True, use_subplots=True, time_unit=pq.s, y_unit=None, progress=None): """ Create a plot from a list of analog signals. :param list signals: The list of :class:`neo.core.AnalogSignal` objects to plot. :param sequence events: A list of Event objects to be included in the plot. :param sequence epochs: A list of Epoch objects to be included in the plot. :param list spike_trains: A list of :class:`neo.core.SpikeTrain` objects to be included in the plot. The ``unit`` property (if it exists) is used for color and legend entries. :param list spikes: A list :class:`neo.core.Spike` objects to be included in the plot. The ``unit`` property (if it exists) is used for color and legend entries. :param bool show_waveforms: Determines if spikes from :class:`neo.core.Spike` and :class:`neo.core.SpikeTrain` objects are shown as waveforms (if available) or vertical lines. :param bool use_subplots: Determines if a separate subplot for is created each signal. :param Quantity time_unit: The unit of the x axis. :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if not signals: raise SpykeException( 'Cannot create signal plot: No signal data provided!') if not progress: progress = ProgressIndicator() # Plot title win_title = 'Analog Signal' if len(set((s.recordingchannel for s in signals))) == 1: if signals[0].recordingchannel and signals[0].recordingchannel.name: win_title += ' | Recording Channel: %s' %\ signals[0].recordingchannel.name if len(set((s.segment for s in signals))) == 1: if signals[0].segment and signals[0].segment.name: win_title += ' | Segment: %s' % signals[0].segment.name win = PlotDialog(toolbar=True, wintitle=win_title) if events is None: events = [] if epochs is None: epochs = [] if spike_trains is None: spike_trains = [] if spikes is None: spikes = [] if show_waveforms: for st in spike_trains: if st.waveforms is not None: spikes.extend(conversions.spike_train_to_spikes(st)) spike_trains = [] else: unit_spikes = {} for s in spikes: unit_spikes.setdefault(s.unit, []).append(s) for sps in unit_spikes.itervalues(): spike_trains.append(conversions.spikes_to_spike_train(sps, False)) spikes = [] channels = range(len(signals)) progress.set_ticks((len(spike_trains) + len(spikes) + 1) * len(channels)) offset = 0 * signals[0].units if use_subplots: plot = None for c in channels: pW = BaseCurveWidget(win) plot = pW.plot if signals[c].name: win.set_plot_title(plot, signals[c].name) elif signals[c].recordingchannel: if signals[c].recordingchannel.name: win.set_plot_title(plot, signals[c].recordingchannel.name) sample = (1 / signals[c].sampling_rate).simplified x = (sp.arange(signals[c].shape[0])) * sample + signals[c].t_start x.units = time_unit helper.add_epochs(plot, epochs, x.units) if y_unit is not None: plot.add_item(make.curve(x, signals[c].rescale(y_unit))) else: plot.add_item(make.curve(x, signals[c])) helper.add_events(plot, events, x.units) _add_spike_waveforms(plot, spikes, x.units, c, offset, progress) for train in spike_trains: color = helper.get_object_color(train.unit) helper.add_spikes(plot, train, color, units=x.units) progress.step() win.add_plot_widget(pW, c) plot.set_axis_unit(BasePlot.Y_LEFT, signals[c].dimensionality.string) progress.step() plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, x.dimensionality.string) else: channels.reverse() pW = BaseCurveWidget(win) plot = pW.plot helper.add_epochs(plot, epochs, time_unit) # Find plot y offset max_offset = 0 * signals[0].units for i, c in enumerate(channels[1:], 1): cur_offset = signals[channels[i - 1]].max() - signals[c].min() if cur_offset > max_offset: max_offset = cur_offset offset -= signals[channels[0]].min() for c in channels: sample = (1 / signals[c].sampling_rate).simplified x = (sp.arange(signals[c].shape[0])) * sample + signals[c].t_start x.units = time_unit if y_unit is not None: plot.add_item(make.curve(x, (signals[c] + offset).rescale(y_unit))) else: plot.add_item(make.curve(x, signals[c] + offset)) _add_spike_waveforms(plot, spikes, x.units, c, offset, progress) offset += max_offset progress.step() helper.add_events(plot, events, x.units) for train in spike_trains: color = helper.get_object_color(train.unit) helper.add_spikes(plot, train, color, units=x.units) progress.step() win.add_plot_widget(pW, 0) plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, x.dimensionality.string) plot.set_axis_unit(BasePlot.Y_LEFT, signals[0].dimensionality.string) win.add_custom_curve_tools(False) units = set([s.unit for s in spike_trains]) units = units.union([s.unit for s in spikes]) progress.done() helper.make_window_legend(win, units, False) win.show() if use_subplots: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(False, channels) return win
def signals(signals, events=None, epochs=None, spike_trains=None, spikes=None, show_waveforms=True, use_subplots=True, subplot_names=True, time_unit=pq.s, y_unit=None, progress=None): """ Create a plot from a list of analog signals. :param list signals: The list of :class:`neo.core.AnalogSignal` objects to plot. :param sequence events: A list of Event objects to be included in the plot. :param sequence epochs: A list of Epoch objects to be included in the plot. :param list spike_trains: A list of :class:`neo.core.SpikeTrain` objects to be included in the plot. The ``unit`` property (if it exists) is used for color and legend entries. :param list spikes: A list :class:`neo.core.Spike` objects to be included in the plot. The ``unit`` property (if it exists) is used for color and legend entries. :param bool show_waveforms: Determines if spikes from :class:`neo.core.Spike` and :class:`neo.core.SpikeTrain` objects are shown as waveforms (if available) or vertical lines. :param bool use_subplots: Determines if a separate subplot for is created each signal. :param bool subplot_names: Only valid if ``use_subplots`` is True. Determines if signal (or channel) names are shown for subplots. :param Quantity time_unit: The unit of the x axis. :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if not signals: raise SpykeException( 'Cannot create signal plot: No signal data provided!') if not progress: progress = ProgressIndicator() # Plot title win_title = 'Analog Signal' if len(set((s.recordingchannel for s in signals))) == 1: if signals[0].recordingchannel and signals[0].recordingchannel.name: win_title += ' | Recording Channel: %s' %\ signals[0].recordingchannel.name if len(set((s.segment for s in signals))) == 1: if signals[0].segment and signals[0].segment.name: win_title += ' | Segment: %s' % signals[0].segment.name win = PlotDialog(toolbar=True, wintitle=win_title) if events is None: events = [] if epochs is None: epochs = [] if spike_trains is None: spike_trains = [] if spikes is None: spikes = [] if show_waveforms: for st in spike_trains: if st.waveforms is not None: spikes.extend(conversions.spike_train_to_spikes(st)) spike_trains = [] else: unit_spikes = {} for s in spikes: unit_spikes.setdefault(s.unit, []).append(s) for sps in unit_spikes.itervalues(): spike_trains.append(conversions.spikes_to_spike_train(sps, False)) spikes = [] channels = range(len(signals)) channel_indices = [] for s in signals: if not s.recordingchannel: channel_indices.append(-1) else: channel_indices.append(s.recordingchannel.index) # Heuristic: If multiple channels have the same index, use channel order # as index for spike waveforms nonindices = max(0, channel_indices.count(-1) - 1) if len(set(channel_indices)) != len(channel_indices) - nonindices: channel_indices = range(len(signals)) progress.set_ticks((len(spike_trains) + len(spikes) + 1) * len(channels)) offset = 0 * signals[0].units if use_subplots: plot = None for c in channels: pW = BaseCurveWidget(win) plot = pW.plot if subplot_names: if signals[c].name: win.set_plot_title(plot, signals[c].name) elif signals[c].recordingchannel: if signals[c].recordingchannel.name: win.set_plot_title(plot, signals[c].recordingchannel.name) sample = (1 / signals[c].sampling_rate).simplified x = (sp.arange(signals[c].shape[0])) * sample + signals[c].t_start x.units = time_unit helper.add_epochs(plot, epochs, x.units) if y_unit is not None: plot.add_item(make.curve(x, signals[c].rescale(y_unit))) else: plot.add_item(make.curve(x, signals[c])) helper.add_events(plot, events, x.units) _add_spike_waveforms(plot, spikes, x.units, channel_indices[c], offset, progress) for train in spike_trains: color = helper.get_object_color(train.unit) helper.add_spikes(plot, train, color, units=x.units) progress.step() win.add_plot_widget(pW, c) plot.set_axis_unit(BasePlot.Y_LEFT, signals[c].dimensionality.string) progress.step() plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, x.dimensionality.string) else: channels.reverse() pW = BaseCurveWidget(win) plot = pW.plot helper.add_epochs(plot, epochs, time_unit) # Find plot y offset max_offset = 0 * signals[0].units for i, c in enumerate(channels[1:], 1): cur_offset = signals[channels[i - 1]].max() - signals[c].min() if cur_offset > max_offset: max_offset = cur_offset offset -= signals[channels[0]].min() for c in channels: sample = (1 / signals[c].sampling_rate).simplified x = (sp.arange(signals[c].shape[0])) * sample + signals[c].t_start x.units = time_unit if y_unit is not None: plot.add_item( make.curve(x, (signals[c] + offset).rescale(y_unit))) else: plot.add_item(make.curve(x, signals[c] + offset)) _add_spike_waveforms(plot, spikes, x.units, channel_indices[c], offset, progress) offset += max_offset progress.step() helper.add_events(plot, events, x.units) for train in spike_trains: color = helper.get_object_color(train.unit) helper.add_spikes(plot, train, color, units=x.units) progress.step() win.add_plot_widget(pW, 0) plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, x.dimensionality.string) plot.set_axis_unit(BasePlot.Y_LEFT, signals[0].dimensionality.string) win.add_custom_curve_tools() units = set([s.unit for s in spike_trains]) units = units.union([s.unit for s in spikes]) progress.done() helper.make_window_legend(win, units, False) win.show() if use_subplots: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(False, channels) return win
def spikes(spikes, axes_style, anti_alias=False, time_unit=pq.ms, progress=None): """ Create a plot dialog with spike waveforms. :param dict spikes: A dictionary of spike lists. :param int axes_style: Plotting mode. The following values are possible: 1 Show each channel in a seperate plot. 2 Show all channels in the same plot vertically. 3 Show all channels in the same plot horizontally. :param bool anti_alias: Determines whether an antialiased plot is created. :param Quantity time_unit: The (time) unit for the x axis :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if not spikes or sum((len(l) for l in spikes.itervalues())) < 1: raise SpykeException('No spikes for spike waveform plot!') if not progress: progress = ProgressIndicator() progress.begin('Creating waveform plot') progress.set_ticks(sum((len(l) for l in spikes.itervalues()))) win_title = 'Spike waveforms' win = PlotDialog(toolbar=True, wintitle=win_title) indices = spikes.keys() ref_spike = spikes[spikes.keys()[0]][0] if ref_spike.waveform is None: raise SpykeException('Cannot create waveform plot: At least one spike ' 'has no waveform or sampling rate!') ref_units = ref_spike.waveform.units channels = range(ref_spike.waveform.shape[1]) plot = None if axes_style == 1: # Separate channel plots for c in channels: pW = BaseCurveWidget(win) plot = pW.plot plot.set_antialiasing(anti_alias) for u in indices: color = helper.get_object_color(u) for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException('Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve(x, s.waveform[:, c].rescale(ref_units), title=u.name, color=color) plot.add_item(curve) progress.step() win.add_plot_widget(pW, c) helper.make_window_legend(win, indices, True) else: # Only one plot needed pW = BaseCurveWidget(win) plot = pW.plot plot.set_antialiasing(anti_alias) legend_items = [] if axes_style == 3: # Horizontal split offset = 0 * time_unit for c in channels: for u in indices: first_wave = True color = helper.get_object_color(u) for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException('Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve(x + offset, s.waveform[:, c].rescale(ref_units), u.name, color=color) if c == channels[0] and first_wave == True: legend_items.append(curve) first_wave = False plot.add_item(curve) progress.step() offset += x[-1] if c != channels[-1]: plot.add_item(make.marker((offset, 0), lambda x,y: '', movable=False, markerstyle='|', color='k', linestyle='-', linewidth=1)) else: # Vertical split channels.reverse() # Find plot y offset maxY = [] minY = [] for i, c in enumerate(channels): maxY.append(max(max(s.waveform[:, c].max() for s in d) for d in spikes.itervalues())) minY.append(min(min(s.waveform[:, c].min() for s in d) for d in spikes.itervalues())) maxOffset = 0 * ref_units for i in range(1, len(channels)): offset = maxY[i - 1] - minY[i] if offset > maxOffset: maxOffset = offset offset = 0 * ref_units for c in channels: for u in indices: first_wave = True color = helper.get_object_color(u) for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException('Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve(x, s.waveform[:, c].rescale(ref_units) + offset, u.name, color=color) if c == channels[0] and first_wave == True: legend_items.append(curve) first_wave = False plot.add_item(curve) progress.step() offset += maxOffset l = make.legend(restrict_items=legend_items) plot.add_item(l) win.add_plot_widget(pW, 0) win.add_legend_option([l], True) win.add_custom_curve_tools() progress.done() win.show() plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit(BasePlot.X_BOTTOM, x.dimensionality.string) if axes_style == 1: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(True, channels) if len(channels) == 1 or axes_style > 1: plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit(BasePlot.Y_LEFT, ref_units.dimensionality.string) return win
def spikes(spikes, axes_style, anti_alias=False, time_unit=pq.ms, progress=None): """ Create a plot dialog with spike waveforms. :param dict spikes: A dictionary of spike lists. :param int axes_style: Plotting mode. The following values are possible: - 1: Show each channel in a seperate plot, split vertically. - 2: Show each channel in a separate plot, split horizontally. - 3: Show each key of ``spikes`` in a separate plot, channels are split vertically. - 4: Show each key of ``spikes`` in a separate plot, channels are split horizontally. - 5: Show all channels in the same plot, split vertically. - 6: Show all channels in the same plot, split horizontally. :param bool anti_alias: Determines whether an antialiased plot is created. :param Quantity time_unit: Unit of X-Axis. :param progress: Set this parameter to report progress. :type progress: :class:`spykeutils.progress_indicator.ProgressIndicator` """ if not spikes or sum((len(l) for l in spikes.itervalues())) < 1: raise SpykeException('No spikes for spike waveform plot!') if not progress: progress = ProgressIndicator() progress.begin('Creating waveform plot') progress.set_ticks(sum((len(l) for l in spikes.itervalues()))) win_title = 'Spike waveforms' win = PlotDialog(toolbar=True, wintitle=win_title) ref_spike = spikes[spikes.keys()[0]][0] if ref_spike.waveform is None: raise SpykeException( 'Cannot create waveform plot: At least one spike ' 'has no waveform or sampling rate!') ref_units = ref_spike.waveform.units channels = range(ref_spike.waveform.shape[1]) if axes_style <= 2: # Separate channel plots indices = spikes.keys() for c in channels: pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) for u in indices: color = helper.get_object_color(u) for s in spikes[u]: if s.waveform is None or s.sampling_rate is None: raise SpykeException( 'Cannot create waveform plot: ' 'At least one spike has no ' 'waveform or sampling rate!') x = (sp.arange(s.waveform.shape[0]) / s.sampling_rate).rescale(time_unit) curve = make.curve( x, s.waveform[:, c].rescale(ref_units), title=u.name, color=color) plot.add_item(curve) if axes_style == 1 or c == channels[0]: plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit( BasePlot.Y_LEFT, ref_units.dimensionality.string) if axes_style == 2 or c == channels[-1]: plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit( BasePlot.X_BOTTOM, x.dimensionality.string) progress.step() if axes_style == 1: win.add_plot_widget(pw, c) else: win.add_plot_widget(pw, c, 0, c) helper.make_window_legend(win, indices, True) elif axes_style > 4: # Only one plot needed pw = BaseCurveWidget(win) plot = pw.plot plot.set_antialiasing(anti_alias) if axes_style == 6: # Horizontal split l = _split_plot_hor(channels, spikes, ref_units, time_unit, progress, plot) plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit( BasePlot.X_BOTTOM, time_unit.dimensionality.string) else: # Vertical split channels.reverse() max_offset = _find_y_offset(channels, spikes, ref_units) l = _split_plot_ver(channels, spikes, ref_units, time_unit, progress, max_offset, plot) plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit( BasePlot.Y_LEFT, ref_units.dimensionality.string) win.add_plot_widget(pw, 0) win.add_legend_option([l], True) else: # One plot per unit if axes_style == 3: # Vertical split channels.reverse() max_offset = _find_y_offset(channels, spikes, ref_units) plot_index = 0 for u, s in spikes.iteritems(): pW = BaseCurveWidget(win) plot = pW.plot plot.set_antialiasing(anti_alias) _split_plot_ver(channels, {u: s}, ref_units, time_unit, progress, max_offset, plot) if plot_index == 0: plot.set_axis_title(BasePlot.Y_LEFT, 'Voltage') plot.set_axis_unit( BasePlot.Y_LEFT, ref_units.dimensionality.string) win.add_plot_widget(pW, plot_index, 0, plot_index) plot_index += 1 else: plot_index = 0 for u, s in spikes.iteritems(): pW = BaseCurveWidget(win) plot = pW.plot plot.set_antialiasing(anti_alias) _split_plot_hor(channels, {u: s}, ref_units, time_unit, progress, plot) win.add_plot_widget(pW, plot_index, plot_index) plot_index += 1 plot.set_axis_title(BasePlot.X_BOTTOM, 'Time') plot.set_axis_unit( BasePlot.X_BOTTOM, time_unit.dimensionality.string) win.add_custom_curve_tools() progress.done() win.show() if axes_style <= 2: if len(channels) > 1: win.add_x_synchronization_option(True, channels) win.add_y_synchronization_option(True, channels) elif axes_style <= 4: if len(spikes) > 1: win.add_x_synchronization_option(True, range(len(spikes))) win.add_y_synchronization_option(True, range(len(spikes))) return win