Source code for netpyne.analysis.tools

"""
Module for utilities to help analyze and plot results

"""

try:
    to_unicode = unicode
except NameError:
    to_unicode = str
try:
    basestring
except NameError:
    basestring = str

import functools
import sys
import pandas as pd
import pickle, json
import os


[docs] def exception(function): """ Wrapper function to catch exceptions in functions Parameters ---------- function : function A Python function **Required** """ @functools.wraps(function) def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except Exception as e: import traceback print(f"\nThere was an exception in {function.__name__}()") traceback.print_exc() return -1 return wrapper
[docs] def getInclude(include='allCells', sim=None): """ Function to return the cells indicated by the include list Parameters ---------- include : str, int, list Cells and/or NetStims to return information for **Default:** 'allCells' includes all cells **Options:** (1) 'all' includes all cells and all NetStims, (2) 'allNetStims' includes all NetStims but no cells, (3) a string which matches a pop name includes all cells in that pop, (4) a string which matches a NetStim name includes that NetStim, (5) an int includes the cell with that global identifier (GID), (6) a list of ints includes the cells with those GIDS, (7) a list with two items, the first of which is a string matching a pop name and the second of which is an int or a list of ints, includes the relative cell(s) from that population (e.g. ('popName', [0, 1]) includes the first two cells in popName, which are not likely to be the cells with GID 0 and 1) sim : NetPyNE sim object **Default:** ``None`` uses the current NetPyNE sim object Returns ------- cells, cellGids, netStimLabels : tuple ``cells`` is a list of dicts containing cell information, ``cellGids`` is a list of ints of the global identifier (GID) for each cell, ``netStimLabels`` is a list of strings of the included stimulations """ if not sim: from .. import sim allCells = sim.net.allCells allNetStimLabels = list(sim.net.params.stimSourceParams.keys()) cellGids = [] cells = [] netStimLabels = [] if type(include) == str: include = [include] for condition in include: if condition == 'all': # all cells and all Netstims cellGids = [c['gid'] for c in allCells] cells = list(allCells) netStimLabels = list(allNetStimLabels) return cells, cellGids, netStimLabels elif condition == 'allCells': # all cells but no NetStims cellGids = [c['gid'] for c in allCells] cells = list(allCells) elif condition == 'allNetStims': # all Netstims but no cells netStimLabels = list(allNetStimLabels) elif isinstance(condition, int): # cell gid cellGids.append(condition) elif isinstance(condition, basestring): # entire pop or single NetStim if condition in allNetStimLabels: netStimLabels.append(condition) else: cellGids.extend([c['gid'] for c in allCells if c['tags']['pop'] == condition]) elif ( isinstance(condition, (list, tuple)) and len(condition) == 2 and isinstance(condition[0], basestring) and isinstance(condition[1], (list, int)) ): # subset of a pop with relative indices cellsPop = [c['gid'] for c in allCells if c['tags']['pop'] == condition[0]] if isinstance(condition[1], list): cellGids.extend([gid for i, gid in enumerate(cellsPop) if i in condition[1]]) elif isinstance(condition[1], int): cellGids.extend([gid for i, gid in enumerate(cellsPop) if i == condition[1]]) elif isinstance(condition, (list, tuple)): # subset for subcond in condition: if isinstance(subcond, int): # cell gid cellGids.append(subcond) elif isinstance(subcond, basestring): # entire pop or single NetStim if subcond in allNetStimLabels: netStimLabels.append(subcond) else: cellGids.extend([c['gid'] for c in allCells if c['tags']['pop'] == subcond]) cellGids = sim.unique(cellGids) cells = [cell for cell in allCells if cell['gid'] in cellGids] cells = sorted(cells, key=lambda k: k['gid']) return cells, cellGids, netStimLabels
[docs] def getSpktSpkid(cellGids=[], timeRange=None, sim=None): """ Function to efficiently get a subset of spikes based on a timeRange and cellGids list Parameters ---------- cellGids : list A list of cells to include by global identifier (GID) **Default:** ``[]`` timeRange : [start, stop] A list of two floats specifying the time range of spikes to include **Default:** ``None`` includes the entire simulation time range sim : NetPyNE sim object **Default:** ``None`` uses the current NetPyNE sim object Returns ------- (selection, spkt, spkid) A tuple consisting of the subset in a Pandas dataframe, a list of spike times, and a list of spike GIDs """ if not sim: from .. import sim try: # Pandas 1.4.0 from pandas._libs import lib as pandaslib except: try: # Pandas 0.24 and later from pandas import _lib as pandaslib except: # Pandas 0.23 and earlier from pandas import lib as pandaslib df = pd.DataFrame( pandaslib.to_object_array([sim.allSimData['spkt'], sim.allSimData['spkid']]).transpose(), columns=['spkt', 'spkid'], ) if timeRange: # binary search is faster than query min, max = [int(df['spkt'].searchsorted(timeRange[i])) for i in range(2)] else: min, max = 0, len(df) if len(cellGids) == 0: sel = df[min:max] else: sel = df[min:max].query('spkid in @cellGids') spktList = sel['spkt'].tolist() spkidList = sel['spkid'].tolist() return sel, spktList, spkidList
[docs] def plotData(sim=None): """ Wrapper to run plotting functions specified in simConfig Parameters ---------- sim : NetPyNE sim object **Default:** ``None`` uses the current NetPyNE sim object """ if not sim: from .. import sim from netpyne import __gui__ # Only plot from the main node in parallel simulations if sim.rank == 0 and __gui__: sim.timing('start', 'plotTime') # Call analysis functions specified by user for funcName, kwargs in sim.cfg.analysis.items(): if kwargs == True: kwargs = {} elif kwargs == False: continue func = getattr(sim.plotting, funcName, None) if func is None: func = getattr(sim.analysis, funcName, None) if func: func(**kwargs) # call function with user arguments else: print(f'Unable to run {funcName} from sim.plotting and sim.analysis (no such function)') # Print timings if sim.cfg.timing: sim.timing('stop', 'plotTime') print((' Done; plotting time = %0.2f s' % sim.timingData['plotTime'])) sim.timing('stop', 'totalTime') sumTime = sum([t for k, t in sim.timingData.items() if k not in ['totalTime']]) if sim.timingData['totalTime'] <= 1.2 * sumTime: # Print total time (only if makes sense) print(('\nTotal time = %0.2f s' % sim.timingData['totalTime']))
# try: # print('\nEnd time: ', datetime.now()) # except: # pass
[docs] def saveData(data, fileName=None, fileDesc=None, fileType=None, fileDir=None, sim=None, **kwargs): """ Function to save data to a file Parameters ---------- data : data object **Required** fileName : str **Default:** ``None`` uses sim.cfg.fileName fileDesc : str **Default:** ``None`` If fileDesc is a string, it will be added to the file name after an underscore fileType : str **Default:** ``None`` saves the data as a Python Pickle file **Options:** ``'json'`` saves the data in a .json file fileDir : str **Default:** ``None`` saves to the current directory sim : NetPyNE sim object **Default:** ``None`` uses the current NetPyNE sim object Returns ------- fileName : str The complete name, with extension and path, of the file saved """ if not sim: from .. import sim if not fileType or fileType in ['pkl', 'pickle', '.pkl']: fileExt = '.pkl' elif fileType in ['json', '.json']: fileExt = '.json' else: raise Exception('fileType not recognized in saveData') if fileDesc is None: fileDesc = '_data' else: fileDesc = '_' + str(fileDesc) if not fileName or not isinstance(fileName, basestring): fileName = sim.cfg.filename + fileDesc + fileExt else: if fileName.endswith(fileExt): fileName = fileName.split(fileExt)[0] + fileDesc + fileExt else: fileName = fileName + fileDesc + fileExt if fileDir is not None: fileName = os.path.join(fileDir, fileName) if fileName.endswith('.pkl'): print(('Saving data as %s ... ' % (fileName))) with open(fileName, 'wb') as fileObj: pickle.dump(data, fileObj) elif fileName.endswith('.json'): print(('Saving data as %s ... ' % (fileName))) sim.saveJSON(fileName, data) else: print('File extension to save data not recognized') return fileName
[docs] def loadData(fileName, fileDir=None, sim=None): """ Function to load data from a file (JSON or Python Pickle) Parameters ---------- fileName : str **Required** fileDir : str The directory to load the data file from **Default:** ``None`` loads from the current directory sim : NetPyNE sim object **Default:** ``None`` uses the current NetPyNE sim object Returns ------- data : dict The data from the file """ if fileDir is not None: fileName = os.path.join(fileName, fileDir) if fileName.endswith('.pkl'): with open(fileName, 'rb') as input_file: data = pickle.load(input_file) elif fileName.endswith('.json'): with open(fileName) as input_file: data = json.load(input_file) else: raise Exception('loadData can only load JSON (.json) or Python Pickle (.pkl) files') return data
[docs] def checkAvailablePlots(requireCfg=False): """ Function to check which plots are available for the GUI Parameters ---------- requireCfg : bool Whether a plot configuration in sim.cfg.analysis is required to return True for each plot **Default:** False Returns ---------- output : dict Keys indicate the name of the analysis function and values whether they are available or not (Boolean) """ from .. import sim avail = { 'plotConn': False, 'plot2Dnet': False, 'plotTraces': False, 'plotRaster': False, 'plotSpikeHist': False, 'plotSpikeStats': False, 'plotLFP': False, 'granger': False, 'plotRxDConcentration': False, } # plot conn if hasattr(sim, 'net') and hasattr(sim.net, 'allCells') and len(sim.net.allCells) > 0: avail['plotConn'] = True avail['plot2Dnet'] = True # plot traces traces = list(sim.cfg.recordTraces.keys()) if len(traces) > 0 and hasattr(sim, 'allSimData'): for trace in traces: if trace in sim.allSimData and len(sim.allSimData.get(trace)): avail['plotTraces'] = True break # raster, spike hist, spike stats, rate psd and granger if ( hasattr(sim, 'allSimData') and 'spkid' in sim.allSimData and 'spkt' in sim.allSimData and len(sim.allSimData['spkid']) > 0 and len(sim.allSimData['spkt']) > 0 ): avail['plotRaster'] = True avail['plotSpikeHist'] = True avail['plotSpikeStats'] = True avail['plotRatePSD'] = True avail['granger'] = True # plot lfp if hasattr(sim, 'allSimData') and 'LFP' in sim.allSimData and len(sim.allSimData['LFP']) > 0: avail['plotLFP'] = True # rxd concentation if ( hasattr(sim, 'net') and hasattr(sim.net, 'rxd') and 'species' in sim.net.rxd and 'regions' in sim.net.rxd and len(sim.net.rxd['species']) > 0 and len(sim.net.rxd['regions']) > 0 ): avail['plotRxDConcentration'] = True # require config of plots in sim.cfg.analysis if requireCfg: for k in avail: if k not in sim.cfg.analysis: avail[k] = False return avail
# ------------------------------------------------------------------------------------------------------------------- ## Default NetPyNE Bokeh theme -- based on dark_minimal # ------------------------------------------------------------------------------------------------------------------- # Note: The Bokeh plotting APIs defaults override some theme properties. Namely: fill_alpha, # fill_color, line_alpha, line_color, text_alpha and text_color. Those properties should # therefore be set explicitly when using the plotting API. _guiTheme = { "attrs": { "Figure": { "background_fill_color": "#434343", # "#20262B", "border_fill_color": "#434343", # "#15191C", "outline_line_color": "#E0E0E0", "outline_line_alpha": 0.25, }, "Grid": {"grid_line_color": "#E0E0E0", "grid_line_alpha": 0.25}, "Axis": { "major_tick_line_alpha": 0, "major_tick_line_color": "#E0E0E0", "minor_tick_line_alpha": 0, "minor_tick_line_color": "#E0E0E0", "axis_line_alpha": 0, "axis_line_color": "#E0E0E0", "major_label_text_color": "#E0E0E0", "major_label_text_font": "Helvetica", "major_label_text_font_size": "1.025em", "axis_label_standoff": 10, "axis_label_text_color": "#E0E0E0", "axis_label_text_font": "Helvetica", "axis_label_text_font_size": "1.25em", "axis_label_text_font_style": "normal", }, "Legend": { "spacing": 8, "glyph_width": 15, "label_standoff": 8, "label_text_color": "#E0E0E0", "label_text_font": "Helvetica", "label_text_font_size": "1.025em", "border_line_alpha": 0, "background_fill_alpha": 0.5, # 0.25, "background_fill_color": "#434343", # "#20262B" }, "ColorBar": { "title_text_color": "#E0E0E0", "title_text_font": "Helvetica", "title_text_font_size": "1.025em", "title_text_font_style": "normal", "major_label_text_color": "#E0E0E0", "major_label_text_font": "Helvetica", "major_label_text_font_size": "1.025em", "background_fill_color": "#434343", # "#15191C", "major_tick_line_alpha": 0, "bar_line_alpha": 0, }, "Title": {"text_color": "#E0E0E0", "text_font": "Helvetica", "text_font_size": "1.15em"}, } }