signature:
def values_above_sweep ( abf , dataI , dataY , ylabel = "" , useFigure = None ) :
    """To make plots like AP frequency over original trace .
 dataI = [ i ] # the i of the sweep
 dataY = [ 1.234 ] # something like inst freq"""

implementation:
xOffset = abf . currentSweep * abf . sweepInterval
if not useFigure : # just passing the figure makes it persistant !
    pylab . figure ( figsize = ( 8 , 6 ) )
ax = pylab . subplot ( 221 )
pylab . grid ( alpha = .5 )
if len ( dataI ) :
    pylab . plot ( abf . dataX [ dataI ] , dataY , '.' , ms = 10 , alpha = .5 , color = abf . colormap [ abf . currentSweep ] )
pylab . margins ( 0 , .1 )
pylab . ylabel ( ylabel )
pylab . subplot ( 223 , sharex = ax )
pylab . grid ( alpha = .5 )
pylab . plot ( abf . dataX , abf . dataY , color = abf . colormap [ abf . currentSweep ] , alpha = .5 )
pylab . ylabel ( "raw data (%s)" % abf . units )
ax2 = pylab . subplot ( 222 )
pylab . grid ( alpha = .5 )
if len ( dataI ) :
    pylab . plot ( abf . dataX [ dataI ] + xOffset , dataY , '.' , ms = 10 , alpha = .5 , color = abf . colormap [ abf . currentSweep ] )
pylab . margins ( 0 , .1 )
pylab . ylabel ( ylabel )
pylab . subplot ( 224 , sharex = ax2 )
pylab . grid ( alpha = .5 )
pylab . plot ( abf . dataX + xOffset , abf . dataY , color = abf . colormap [ abf . currentSweep ] )
pylab . ylabel ( "raw data (%s)" % abf . units )
pylab . tight_layout ( )


signature:
def gain ( abf ) :
    """easy way to plot a gain function ."""

implementation:
Ys = np . nan_to_num ( swhlab . ap . getAvgBySweep ( abf , 'freq' ) )
Xs = abf . clampValues ( abf . dataX [ int ( abf . protoSeqX [ 1 ] + .01 ) ] )
swhlab . plot . new ( abf , title = "gain function" , xlabel = "command current (pA)" , ylabel = "average inst. freq. (Hz)" )
pylab . plot ( Xs , Ys , '.-' , ms = 20 , alpha = .5 , color = 'b' )
pylab . axhline ( 0 , alpha = .5 , lw = 2 , color = 'r' , ls = "--" )
pylab . margins ( .1 , .1 )


signature:
def IV ( abf , T1 , T2 , plotToo = True , color = 'b' ) :
    """Given two time points ( seconds ) return IV data .
 Optionally plots a fancy graph ( with errorbars )
 Returns [ [ AV ] , [ SD ] ] for the given range ."""

implementation:
rangeData = abf . average_data ( [ [ T1 , T2 ] ] )
# get the average data per sweep
AV , SD = rangeData [ : , 0 , 0 ] , rangeData [ : , 0 , 1 ]
# separate by average and SD
Xs = abf . clampValues ( T1 )
# get clamp values at time point T1
if plotToo :
    new ( abf )
    # do this so it ' s the right shape and size
    # plot the original sweep
    pylab . subplot ( 221 )
    pylab . title ( "sweep data" )
    pylab . xlabel ( "time (s)" )
    pylab . ylabel ( "Measurement (%s)" % abf . units )
    sweep ( abf , 'all' , protocol = False )
    pylab . axis ( [ None , None , np . min ( rangeData ) - 50 , np . max ( rangeData ) + 50 ] )
    pylab . axvspan ( T1 , T2 , alpha = .1 , color = color )
    # share measurement region
    pylab . margins ( 0 , .1 )
    # plot the data zoomed in
    pylab . subplot ( 223 )
    pylab . title ( "measurement region" )
    pylab . xlabel ( "time (s)" )
    pylab . ylabel ( "Measurement (%s)" % abf . units )
    sweep ( abf , 'all' , protocol = False )
    pylab . axis ( [ T1 - .05 , T2 + .05 , np . min ( rangeData ) - 50 , np . max ( rangeData ) + 50 ] )
    pylab . axvspan ( T1 , T2 , alpha = .1 , color = color )
    # share measurement region
    pylab . margins ( 0 , .1 )
    # plot the protocol
    pylab . subplot ( 222 )
    pylab . title ( "protocol" )
    pylab . xlabel ( "time (s)" )
    pylab . ylabel ( "Command (%s)" % abf . unitsCommand )
    sweep ( abf , 'all' , protocol = True )
    pylab . axvspan ( T1 , T2 , alpha = .1 , color = color )
    # share measurement region
    pylab . margins ( 0 , .1 )
    # plot the I / V
    pylab . subplot ( 224 )
    pylab . grid ( alpha = .5 )
    pylab . title ( "command / measure relationship" )
    pylab . xlabel ( "Command (%s)" % abf . unitsCommand )
    pylab . ylabel ( "Measurement (%s)" % abf . units )
    pylab . errorbar ( Xs , AV , SD , capsize = 0 , marker = '.' , color = color )
    if abf . units == "pA" :
        pylab . axhline ( 0 , alpha = .5 , lw = 2 , color = 'r' , ls = "--" )
        pylab . axvline ( - 70 , alpha = .5 , lw = 2 , color = 'r' , ls = "--" )
    else :
        pylab . axhline ( - 70 , alpha = .5 , lw = 2 , color = 'r' , ls = "--" )
        pylab . axvline ( 0 , alpha = .5 , lw = 2 , color = 'r' , ls = "--" )
    pylab . margins ( .1 , .1 )
annotate ( abf )
return AV , SD


signature:
def comments ( abf , minutes = False ) :
    """draw vertical lines at comment points . Defaults to seconds ."""

implementation:
if not len ( abf . commentTimes ) :
    return
for i in range ( len ( abf . commentTimes ) ) :
    t , c = abf . commentTimes [ i ] , abf . commentTags [ i ]
    if minutes :
        t = t / 60
    pylab . axvline ( t , lw = 1 , color = 'r' , ls = "--" , alpha = .5 )
    X1 , X2 , Y1 , Y2 = pylab . axis ( )
    Y2 = Y2 - abs ( Y2 - Y1 ) * .02
    pylab . text ( t , Y2 , c , size = 8 , color = 'r' , rotation = 'vertical' , ha = 'right' , va = 'top' , weight = 'bold' , alpha = .5 )
    if minutes :
        pylab . xlabel ( "minutes" )
    else :
        pylab . xlabel ( "seconds" )


signature:
def dual ( ABF ) :
    """Plot two channels of current sweep ( top / bottom ) ."""

implementation:
new ( ABF )
pylab . subplot ( 211 )
pylab . title ( "Input A (channel 0)" )
ABF . channel = 0
sweep ( ABF )
pylab . subplot ( 212 )
pylab . title ( "Input B (channel 1)" )
ABF . channel = 1
sweep ( ABF )


signature:
def sweep ( ABF , sweep = None , rainbow = True , alpha = None , protocol = False , color = 'b' , continuous = False , offsetX = 0 , offsetY = 0 , minutes = False , decimate = None , newFigure = False ) :
    """Load a particular sweep then plot it .
 If sweep is None or False , just plot current dataX / dataY .
 If rainbow , it ' ll make it color coded prettily ."""

implementation:
if len ( pylab . get_fignums ( ) ) == 0 or newFigure :
    new ( ABF , True )
if offsetY > 0 :
    pylab . grid ( None )
# figure which sweeps to plot
if sweep is None :
    sweeps = [ ABF . currentSweep ]
    if not ABF . currentSweep :
        sweeps = [ 0 ]
elif sweep == "all" :
    sweeps = range ( 0 , ABF . sweeps )
elif type ( sweep ) in [ int , float ] :
    sweeps = [ int ( sweep ) ]
elif type ( sweep ) is list :
    sweeps = sweep
else :
    print ( "DONT KNOW WHAT TO DO WITH THIS SWEEPS!!!\n" , type ( sweep ) , sweep )
# figure out offsets :
if continuous :
    offsetX = ABF . sweepInterval
# determine the colors to use
colors = [ color ] * len ( sweeps )
# detault to blue
if rainbow and len ( sweeps ) > 1 :
    for i in range ( len ( sweeps ) ) :
        colors [ i ] = ABF . colormap [ i ]
if alpha is None and len ( sweeps ) == 1 :
    alpha = 1
if rainbow and alpha is None :
    alpha = .5
# correct for alpha
if alpha is None :
    alpha = 1
# conversion to minutes ?
if minutes == False :
    minutes = 1
else :
    minutes = 60
    pylab . xlabel ( "minutes" )
ABF . decimateMethod = decimate
# do the plotting of each sweep
for i in range ( len ( sweeps ) ) :
    ABF . setSweep ( sweeps [ i ] )
    if protocol :
        pylab . plot ( ( np . array ( ABF . protoX ) / ABF . rate + offsetX * i ) / minutes , ABF . protoY + offsetY * i , alpha = alpha , color = colors [ i ] )
    else :
        pylab . plot ( ( ABF . dataX + offsetX * i ) / minutes , ABF . dataY + offsetY * i , alpha = alpha , color = colors [ i ] )
ABF . decimateMethod = None
pylab . margins ( 0 , .02 )


signature:
def annotate ( abf ) :
    """stamp the bottom with file info ."""

implementation:
msg = "SWHLab %s " % str ( swhlab . VERSION )
msg += "ID:%s " % abf . ID
msg += "CH:%d " % abf . channel
msg += "PROTOCOL:%s " % abf . protoComment
msg += "COMMAND: %d%s " % ( abf . holding , abf . units )
msg += "GENERATED:%s " % '{0:%Y-%m-%d %H:%M:%S}' . format ( datetime . datetime . now ( ) )
pylab . annotate ( msg , ( .001 , .001 ) , xycoords = 'figure fraction' , ha = 'left' , va = 'bottom' , color = '#999999' , family = 'monospace' , size = 8 , weight = 'bold' )
if abf . nADC > 1 :
    msg = "Ch %d/%d" % ( abf . channel + 1 , abf . nADC )
    pylab . annotate ( msg , ( .01 , .99 ) , xycoords = 'figure fraction' , ha = 'left' , va = 'top' , color = '#FF0000' , family = 'monospace' , size = 12 , weight = 'bold' )


signature:
def new ( ABF , forceNewFigure = False , title = None , xlabel = None , ylabel = None ) :
    """makes a new matplotlib figure with default dims and DPI .
 Also labels it with pA or mV depending on ABF ."""

implementation:
if len ( pylab . get_fignums ( ) ) and forceNewFigure == False : # print ( " adding to existing figure " )
    return
pylab . figure ( figsize = ( 8 , 6 ) )
pylab . grid ( alpha = .5 )
pylab . title ( ABF . ID )
pylab . ylabel ( ABF . units )
pylab . xlabel ( "seconds" )
if xlabel :
    pylab . xlabel ( xlabel )
if ylabel :
    pylab . ylabel ( ylabel )
if title :
    pylab . title ( title )
annotate ( ABF )


signature:
def save ( abf , fname = None , tag = None , width = 700 , close = True , facecolor = 'w' , resize = True ) :
    """Save the pylab figure somewhere .
 If fname = = False , show it instead .
 Height force > dpi force
 if a tag is given instead of a filename , save it alongside the ABF"""

implementation:
if len ( pylab . gca ( ) . get_lines ( ) ) == 0 :
    print ( "can't save, no figure!" )
    return
if resize :
    pylab . tight_layout ( )
    pylab . subplots_adjust ( bottom = .1 )
annotate ( abf )
if tag :
    fname = abf . outpath + abf . ID + "_" + tag + ".png"
inchesX , inchesY = pylab . gcf ( ) . get_size_inches ( )
dpi = width / inchesX
if fname :
    if not os . path . exists ( abf . outpath ) :
        os . mkdir ( abf . outpath )
    print ( " <- saving [%s] at %d DPI (%dx%d)" % ( os . path . basename ( fname ) , dpi , inchesX * dpi , inchesY * dpi ) )
    pylab . savefig ( fname , dpi = dpi , facecolor = facecolor )
else :
    pylab . show ( )
if close :
    pylab . close ( )


signature:
def tryLoadingFrom ( tryPath , moduleName = 'swhlab' ) :
    """if the module is in this path , load it from the local folder ."""

implementation:
if not 'site-packages' in swhlab . __file__ :
    print ( "loaded custom swhlab module from" , os . path . dirname ( swhlab . __file__ ) )
    return
    # no need to warn if it ' s already outside .
while len ( tryPath ) > 5 :
    sp = tryPath + "/swhlab/"
    # imaginary swhlab module path
    if os . path . isdir ( sp ) and os . path . exists ( sp + "/__init__.py" ) :
        if not os . path . dirname ( tryPath ) in sys . path :
            sys . path . insert ( 0 , os . path . dirname ( tryPath ) )
        print ( "#" * 80 )
        print ( "# WARNING: using site-packages swhlab module" )
        print ( "#" * 80 )
    tryPath = os . path . dirname ( tryPath )
return


signature:
def update ( self , tids , info ) :
    """Called to update the state of the iterator . This methods
 receives the set of task ids from the previous set of tasks
 together with the launch information to allow the output
 values to be parsed using the output _ extractor . This data is then
 used to determine the next desired point in the parameter
 space by calling the _ update _ state method ."""

implementation:
outputs_dir = os . path . join ( info [ 'root_directory' ] , 'streams' )
pattern = '%s_*_tid_*{tid}.o.{tid}*' % info [ 'batch_name' ]
flist = os . listdir ( outputs_dir )
try :
    outputs = [ ]
    for tid in tids :
        matches = fnmatch . filter ( flist , pattern . format ( tid = tid ) )
        if len ( matches ) != 1 :
            self . warning ( "No unique output file for tid %d" % tid )
        contents = open ( os . path . join ( outputs_dir , matches [ 0 ] ) , 'r' ) . read ( )
        outputs . append ( self . output_extractor ( contents ) )
    self . _next_val = self . _update_state ( outputs )
    self . trace . append ( ( outputs , self . _next_val ) )
except :
    self . warning ( "Cannot load required output files. Cannot continue." )
    self . _next_val = StopIteration


signature:
def show ( self ) :
    """When dynamic , not all argument values may be available ."""

implementation:
copied = self . copy ( )
enumerated = [ el for el in enumerate ( copied ) ]
for ( group_ind , specs ) in enumerated :
    if len ( enumerated ) > 1 :
        print ( "Group %d" % group_ind )
    ordering = self . constant_keys + self . varying_keys
    # Ordered nicely by varying _ keys definition .
    spec_lines = [ ', ' . join ( [ '%s=%s' % ( k , s [ k ] ) for k in ordering ] ) for s in specs ]
    print ( '\n' . join ( [ '%d: %s' % ( i , l ) for ( i , l ) in enumerate ( spec_lines ) ] ) )
print ( 'Remaining arguments not available for %s' % self . __class__ . __name__ )


signature:
def _trace_summary ( self ) :
    """Summarizes the trace of values used to update the DynamicArgs
 and the arguments subsequently returned . May be used to
 implement the summary method ."""

implementation:
for ( i , ( val , args ) ) in enumerate ( self . trace ) :
    if args is StopIteration :
        info = "Terminated"
    else :
        pprint = ',' . join ( '{' + ',' . join ( '%s=%r' % ( k , v ) for ( k , v ) in arg . items ( ) ) + '}' for arg in args )
        info = ( "exploring arguments [%s]" % pprint )
    if i == 0 :
        print ( "Step %d: Initially %s." % ( i , info ) )
    else :
        print ( "Step %d: %s after receiving input(s) %s." % ( i , info . capitalize ( ) , val ) )


signature:
def _update_state ( self , vals ) :
    """Takes as input a list or tuple of two elements . First the
 value returned by incrementing by ' stepsize ' followed by the
 value returned after a ' stepsize ' decrement ."""

implementation:
self . _steps_complete += 1
if self . _steps_complete == self . max_steps :
    self . _termination_info = ( False , self . _best_val , self . _arg )
    return StopIteration
arg_inc , arg_dec = vals
best_val = min ( arg_inc , arg_dec , self . _best_val )
if best_val == self . _best_val :
    self . _termination_info = ( True , best_val , self . _arg )
    return StopIteration
self . _arg += self . stepsize if ( arg_dec > arg_inc ) else - self . stepsize
self . _best_val = best_val
return [ { self . key : self . _arg + self . stepsize } , { self . key : self . _arg - self . stepsize } ]


signature:
def proto_unknown ( theABF ) :
    """protocol : unknown ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as an unknown protocol" )
plot = ABFplot ( abf )
plot . rainbow = False
plot . title = None
plot . figure_height , plot . figure_width = SQUARESIZE , SQUARESIZE
plot . kwargs [ "lw" ] = .5
plot . figure_chronological ( )
plt . gca ( ) . set_axis_bgcolor ( '#AAAAAA' )
# different background if unknown protocol
frameAndSave ( abf , "UNKNOWN" )


signature:
def proto_0111 ( theABF ) :
    """protocol : IC ramp for AP shape analysis ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as an IC ramp" )
# AP detection
ap = AP ( abf )
ap . detect ( )
# also calculate derivative for each sweep
abf . derivative = True
# create the multi - plot figure
plt . figure ( figsize = ( SQUARESIZE , SQUARESIZE ) )
ax1 = plt . subplot ( 221 )
plt . ylabel ( abf . units2 )
ax2 = plt . subplot ( 222 , sharey = ax1 )
ax3 = plt . subplot ( 223 )
plt . ylabel ( abf . unitsD2 )
ax4 = plt . subplot ( 224 , sharey = ax3 )
# put data in each subplot
for sweep in range ( abf . sweeps ) :
    abf . setsweep ( sweep )
    ax1 . plot ( abf . sweepX , abf . sweepY , color = 'b' , lw = .25 )
    ax2 . plot ( abf . sweepX , abf . sweepY , color = 'b' )
    ax3 . plot ( abf . sweepX , abf . sweepD , color = 'r' , lw = .25 )
    ax4 . plot ( abf . sweepX , abf . sweepD , color = 'r' )
# modify axis
for ax in [ ax1 , ax2 , ax3 , ax4 ] : # everything
    ax . margins ( 0 , .1 )
    ax . grid ( alpha = .5 )
for ax in [ ax3 , ax4 ] : # only derivative APs
    ax . axhline ( - 100 , color = 'r' , alpha = .5 , ls = "--" , lw = 2 )
for ax in [ ax2 , ax4 ] : # only zoomed in APs
    ax . get_yaxis ( ) . set_visible ( False )
if len ( ap . APs ) :
    firstAP = ap . APs [ 0 ] [ "T" ]
    ax2 . axis ( [ firstAP - .25 , firstAP + .25 , None , None ] )
    ax4 . axis ( [ firstAP - .01 , firstAP + .01 , None , None ] )
# show message from first AP
if len ( ap . APs ) :
    firstAP = ap . APs [ 0 ]
    msg = "\n" . join ( [ "%s = %s" % ( x , str ( firstAP [ x ] ) ) for x in sorted ( firstAP . keys ( ) ) if not "I" in x [ - 2 : ] ] )
    plt . subplot ( 221 )
    plt . gca ( ) . text ( 0.02 , 0.98 , msg , transform = plt . gca ( ) . transAxes , fontsize = 10 , verticalalignment = 'top' , family = 'monospace' )
# save it
plt . tight_layout ( )
frameAndSave ( abf , "AP shape" )
plt . close ( 'all' )


signature:
def proto_gain ( theABF , stepSize = 25 , startAt = - 100 ) :
    """protocol : gain function of some sort . step size and start at are pA ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as an IC ramp" )
plot = ABFplot ( abf )
plot . kwargs [ "lw" ] = .5
plot . title = ""
currents = np . arange ( abf . sweeps ) * stepSize - startAt
# AP detection
ap = AP ( abf )
ap . detect_time1 = .1
ap . detect_time2 = .7
ap . detect ( )
# stacked plot
plt . figure ( figsize = ( SQUARESIZE , SQUARESIZE ) )
ax1 = plt . subplot ( 221 )
plot . figure_sweeps ( )
ax2 = plt . subplot ( 222 )
ax2 . get_yaxis ( ) . set_visible ( False )
plot . figure_sweeps ( offsetY = 150 )
# add vertical marks to graphs :
for ax in [ ax1 , ax2 ] :
    for limit in [ ap . detect_time1 , ap . detect_time2 ] :
        ax . axvline ( limit , color = 'r' , ls = '--' , alpha = .5 , lw = 2 )
# make stacked gain function
ax4 = plt . subplot ( 223 )
plt . ylabel ( "frequency (Hz)" )
plt . ylabel ( "seconds" )
plt . grid ( alpha = .5 )
freqs = ap . get_bySweep ( "freqs" )
times = ap . get_bySweep ( "times" )
for i in range ( abf . sweeps ) :
    if len ( freqs [ i ] ) :
        plt . plot ( times [ i ] [ : - 1 ] , freqs [ i ] , '-' , alpha = .5 , lw = 2 , color = plot . getColor ( i / abf . sweeps ) )
# make gain function graph
ax4 = plt . subplot ( 224 )
ax4 . grid ( alpha = .5 )
plt . plot ( currents , ap . get_bySweep ( "median" ) , 'b.-' , label = "median" )
plt . plot ( currents , ap . get_bySweep ( "firsts" ) , 'g.-' , label = "first" )
plt . xlabel ( "applied current (pA)" )
plt . legend ( loc = 2 , fontsize = 10 )
plt . axhline ( 40 , color = 'r' , alpha = .5 , ls = "--" , lw = 2 )
plt . margins ( .02 , .1 )
# save it
plt . tight_layout ( )
frameAndSave ( abf , "AP Gain %d_%d" % ( startAt , stepSize ) )
plt . close ( 'all' )
# make a second figure that just shows every sweep up to the first AP
plt . figure ( figsize = ( SQUARESIZE , SQUARESIZE ) )
plt . grid ( alpha = .5 )
plt . ylabel ( "Membrane Potential (mV)" )
plt . xlabel ( "Time (seconds)" )
for sweep in abf . setsweeps ( ) :
    plt . plot ( abf . sweepX2 , abf . sweepY , color = 'b' , alpha = .5 )
    if np . max ( abf . sweepY > 0 ) :
        break
plt . tight_layout ( )
plt . margins ( 0 , .1 )
plt . axis ( [ 0 , 1 , None , None ] )
plt . title ( "%d pA Steps from Rest" % stepSize )
frameAndSave ( abf , "voltage response fromRest" , closeWhenDone = False )
plt . axis ( [ 1.5 , 2.5 , None , None ] )
plt . title ( "%d pA Steps from %d pA" % ( stepSize , startAt ) )
frameAndSave ( abf , "voltage response hyperpol" , closeWhenDone = False )
plt . close ( 'all' )


signature:
def proto_0201 ( theABF ) :
    """protocol : membrane test ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as a membrane test" )
plot = ABFplot ( abf )
plot . figure_height , plot . figure_width = SQUARESIZE / 2 , SQUARESIZE / 2
plot . figure_sweeps ( )
# save it
plt . tight_layout ( )
frameAndSave ( abf , "membrane test" )
plt . close ( 'all' )


signature:
def proto_0202 ( theABF ) :
    """protocol : MTIV ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as MTIV" )
plot = ABFplot ( abf )
plot . figure_height , plot . figure_width = SQUARESIZE , SQUARESIZE
plot . title = ""
plot . kwargs [ "alpha" ] = .6
plot . figure_sweeps ( )
# frame to uppwer / lower bounds , ignoring peaks from capacitive transients
abf . setsweep ( 0 )
plt . axis ( [ None , None , abf . average ( .9 , 1 ) - 100 , None ] )
abf . setsweep ( - 1 )
plt . axis ( [ None , None , None , abf . average ( .9 , 1 ) + 100 ] )
# save it
plt . tight_layout ( )
frameAndSave ( abf , "MTIV" )
plt . close ( 'all' )


signature:
def proto_0203 ( theABF ) :
    """protocol : vast IV ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as a fast IV" )
plot = ABFplot ( abf )
plot . title = ""
m1 , m2 = .7 , 1
plt . figure ( figsize = ( SQUARESIZE , SQUARESIZE / 2 ) )
plt . subplot ( 121 )
plot . figure_sweeps ( )
plt . axvspan ( m1 , m2 , color = 'r' , ec = None , alpha = .1 )
plt . subplot ( 122 )
plt . grid ( alpha = .5 )
Xs = np . arange ( abf . sweeps ) * 5 - 110
Ys = [ ]
for sweep in range ( abf . sweeps ) :
    abf . setsweep ( sweep )
    Ys . append ( abf . average ( m1 , m2 ) )
plt . plot ( Xs , Ys , '.-' , ms = 10 )
plt . axvline ( - 70 , color = 'r' , ls = '--' , lw = 2 , alpha = .5 )
plt . axhline ( 0 , color = 'r' , ls = '--' , lw = 2 , alpha = .5 )
plt . margins ( .1 , .1 )
plt . xlabel ( "membrane potential (mV)" )
# save it
plt . tight_layout ( )
frameAndSave ( abf , "fast IV" )
plt . close ( 'all' )


signature:
def proto_0303 ( theABF ) :
    """protocol : repeated IC ramps ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as a halorhodopsin (2s pulse)" )
# show average voltage
proto_avgRange ( theABF , 0.2 , 1.2 )
plt . close ( 'all' )
# show stacked sweeps
plt . figure ( figsize = ( 8 , 8 ) )
for sweep in abf . setsweeps ( ) :
    color = 'b'
    if sweep in np . array ( abf . comment_sweeps , dtype = int ) :
        color = 'r'
    plt . plot ( abf . sweepX2 , abf . sweepY + 100 * sweep , color = color , alpha = .5 )
plt . margins ( 0 , .01 )
plt . tight_layout ( )
frameAndSave ( abf , "IC ramps" )
plt . close ( 'all' )
# do AP event detection
ap = AP ( abf )
ap . detect_time1 = 2.3
ap . detect_time2 = 8.3
ap . detect ( )
apCount = [ ]
apSweepTimes = [ ]
for sweepNumber , times in enumerate ( ap . get_bySweep ( "times" ) ) :
    apCount . append ( len ( times ) )
    if len ( times ) :
        apSweepTimes . append ( times [ 0 ] )
    else :
        apSweepTimes . append ( 0 )
# plot AP frequency vs time
plt . figure ( figsize = ( 8 , 8 ) )
ax1 = plt . subplot ( 211 )
plt . grid ( alpha = .4 , ls = '--' )
plt . plot ( np . arange ( len ( apCount ) ) * abf . sweepLength / 60 , apCount , '.-' , ms = 15 )
comment_lines ( abf )
plt . ylabel ( "AP Count" )
plt . subplot ( 212 , sharex = ax1 )
plt . grid ( alpha = .4 , ls = '--' )
plt . plot ( np . arange ( len ( apCount ) ) * abf . sweepLength / 60 , apSweepTimes , '.-' , ms = 15 )
comment_lines ( abf )
plt . ylabel ( "First AP Time (s)" )
plt . xlabel ( "Experiment Duration (minutes)" )
plt . tight_layout ( )
frameAndSave ( abf , "IC ramp freq" )
plt . close ( 'all' )


signature:
def proto_0304 ( theABF ) :
    """protocol : repeated IC steps ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as repeated current-clamp step" )
# prepare for AP analysis
ap = AP ( abf )
# calculate rest potential
avgVoltagePerSweep = [ ] ;
times = [ ]
for sweep in abf . setsweeps ( ) :
    avgVoltagePerSweep . append ( abf . average ( 0 , 3 ) )
    times . append ( abf . sweepStart / 60 )
# detect only step APs
M1 , M2 = 3.15 , 4.15
ap . detect_time1 , ap . detect_time2 = M1 , M2
ap . detect ( )
apsPerSweepCos = [ len ( x ) for x in ap . get_bySweep ( ) ]
# detect all APs
M1 , M2 = 0 , 10
ap . detect_time1 , ap . detect_time2 = M1 , M2
ap . detect ( )
apsPerSweepRamp = [ len ( x ) for x in ap . get_bySweep ( ) ]
# make the plot of APs and stuff
plt . figure ( figsize = ( 8 , 8 ) )
plt . subplot ( 311 )
plt . grid ( ls = '--' , alpha = .5 )
plt . plot ( times , avgVoltagePerSweep , '.-' )
plt . ylabel ( "Rest Potential (mV)" )
comment_lines ( abf )
plt . subplot ( 312 )
plt . grid ( ls = '--' , alpha = .5 )
plt . plot ( times , apsPerSweepCos , '.-' )
plt . ylabel ( "APs in Step (#)" )
comment_lines ( abf )
plt . subplot ( 313 )
plt . grid ( ls = '--' , alpha = .5 )
plt . plot ( times , apsPerSweepRamp , '.-' )
plt . ylabel ( "APs in Sweep (#)" )
comment_lines ( abf )
plt . tight_layout ( )
frameAndSave ( abf , "cos ramp" )
plt . close ( 'all' )


signature:
def proto_avgRange ( theABF , m1 = None , m2 = None ) :
    """experiment : generic VC time course experiment ."""

implementation:
abf = ABF ( theABF )
abf . log . info ( "analyzing as a fast IV" )
if m1 is None :
    m1 = abf . sweepLength
if m2 is None :
    m2 = abf . sweepLength
I1 = int ( abf . pointsPerSec * m1 )
I2 = int ( abf . pointsPerSec * m2 )
Ts = np . arange ( abf . sweeps ) * abf . sweepInterval
Yav = np . empty ( abf . sweeps ) * np . nan
# average
Ysd = np . empty ( abf . sweeps ) * np . nan
# standard deviation
# Yar = np . empty ( abf . sweeps ) * np . nan # area
for sweep in abf . setsweeps ( ) :
    Yav [ sweep ] = np . average ( abf . sweepY [ I1 : I2 ] )
    Ysd [ sweep ] = np . std ( abf . sweepY [ I1 : I2 ] )
    # Yar [ sweep ] = np . sum ( abf . sweepY [ I1 : I2 ] ) / ( I2 * I1 ) - Yav [ sweep ]
plot = ABFplot ( abf )
plt . figure ( figsize = ( SQUARESIZE * 2 , SQUARESIZE / 2 ) )
plt . subplot ( 131 )
plot . title = "first sweep"
plot . figure_sweep ( 0 )
plt . title ( "First Sweep\n(shaded measurement range)" )
plt . axvspan ( m1 , m2 , color = 'r' , ec = None , alpha = .1 )
plt . subplot ( 132 )
plt . grid ( alpha = .5 )
for i , t in enumerate ( abf . comment_times ) :
    plt . axvline ( t / 60 , color = 'r' , alpha = .5 , lw = 2 , ls = '--' )
plt . plot ( Ts / 60 , Yav , '.' , alpha = .75 )
plt . title ( "Range Average\nTAGS: %s" % ( ", " . join ( abf . comment_tags ) ) )
plt . ylabel ( abf . units2 )
plt . xlabel ( "minutes" )
plt . margins ( 0 , .1 )
plt . subplot ( 133 )
plt . grid ( alpha = .5 )
for i , t in enumerate ( abf . comment_times ) :
    plt . axvline ( t / 60 , color = 'r' , alpha = .5 , lw = 2 , ls = '--' )
plt . plot ( Ts / 60 , Ysd , '.' , alpha = .5 , color = 'g' , ms = 15 , mew = 0 )
# plt . fill _ between ( Ts / 60 , Ysd * 0 , Ysd , lw = 0 , alpha = . 5 , color = ' g ' )
plt . title ( "Range Standard Deviation\nTAGS: %s" % ( ", " . join ( abf . comment_tags ) ) )
plt . ylabel ( abf . units2 )
plt . xlabel ( "minutes" )
plt . margins ( 0 , .1 )
plt . axis ( [ None , None , 0 , np . percentile ( Ysd , 99 ) * 1.25 ] )
plt . tight_layout ( )
frameAndSave ( abf , "sweep vs average" , "experiment" )
plt . close ( 'all' )


signature:
def analyze ( fname = False , save = True , show = None ) :
    """given a filename or ABF object , try to analyze it ."""

implementation:
if fname and os . path . exists ( fname . replace ( ".abf" , ".rst" ) ) :
    print ( "SKIPPING DUE TO RST FILE" )
    return
swhlab . plotting . core . IMAGE_SAVE = save
if show is None :
    if cm . isIpython ( ) :
        swhlab . plotting . core . IMAGE_SHOW = True
    else :
        swhlab . plotting . core . IMAGE_SHOW = False
# swhlab . plotting . core . IMAGE _ SHOW = show
abf = ABF ( fname )
# ensure it ' s a class
print ( ">>>>> PROTOCOL >>>>>" , abf . protocomment )
runFunction = "proto_unknown"
if "proto_" + abf . protocomment in globals ( ) :
    runFunction = "proto_" + abf . protocomment
abf . log . debug ( "running %s()" % ( runFunction ) )
plt . close ( 'all' )
# get ready
globals ( ) [ runFunction ] ( abf )
# run that function
try :
    globals ( ) [ runFunction ] ( abf )
    # run that function
except :
    abf . log . error ( "EXCEPTION DURING PROTOCOL FUNCTION" )
    abf . log . error ( sys . exc_info ( ) [ 0 ] )
    return "ERROR"
plt . close ( 'all' )
# clean up
return "SUCCESS"


signature:
def processFolder ( abfFolder ) :
    """call processAbf ( ) for every ABF in a folder ."""

implementation:
if not type ( abfFolder ) is str or not len ( abfFolder ) > 3 :
    return
files = sorted ( glob . glob ( abfFolder + "/*.abf" ) )
for i , fname in enumerate ( files ) :
    print ( "\n\n\n### PROCESSING {} of {}:" . format ( i , len ( files ) ) , os . path . basename ( fname ) )
    processAbf ( fname , show = False )
plt . show ( )
return


signature:
def processAbf ( abfFname , saveAs = False , dpi = 100 , show = True ) :
    """automatically generate a single representative image for an ABF .
 If saveAs is given ( full path of a jpg of png file ) , the image will be saved .
 Otherwise , the image will pop up in a matplotlib window ."""

implementation:
if not type ( abfFname ) is str or not len ( abfFname ) > 3 :
    return
abf = swhlab . ABF ( abfFname )
plot = swhlab . plotting . ABFplot ( abf )
plot . figure_height = 6
plot . figure_width = 10
plot . subplot = False
plot . figure ( True )
if abf . get_protocol_sequence ( 0 ) == abf . get_protocol_sequence ( 1 ) or abf . sweeps < 2 : # same protocol every time
    if abf . lengthMinutes < 2 : # short ( probably a memtest or tau )
        ax1 = plt . subplot ( 211 )
        plot . figure_sweeps ( )
        plt . title ( "{} ({} sweeps)" . format ( abf . ID , abf . sweeps ) )
        plt . gca ( ) . get_xaxis ( ) . set_visible ( False )
        plt . subplot ( 212 , sharex = ax1 )
        plot . figure_protocol ( )
        plt . title ( "" )
    else : # long ( probably a drug experiment )
        plot . figure_chronological ( )
else : # protocol changes every sweep
    plots = [ 211 , 212 ]
    # assume we want 2 images
    if abf . units == 'mV' : # maybe it ' s something with APs ?
        ap = swhlab . AP ( abf )
        # go ahead and do AP detection
        ap . detect ( )
        # try to detect APs
        if len ( ap . APs ) : # if we found some
            plots = [ 221 , 223 , 222 , 224 ]
            # get ready for 4 images
    ax1 = plt . subplot ( plots [ 0 ] )
    plot . figure_sweeps ( )
    plt . title ( "{} ({} sweeps)" . format ( abf . ID , abf . sweeps ) )
    plt . gca ( ) . get_xaxis ( ) . set_visible ( False )
    plt . subplot ( plots [ 1 ] , sharex = ax1 )
    plot . figure_protocols ( )
    plt . title ( "protocol" )
    if len ( plots ) > 2 : # assume we want to look at the first AP
        ax2 = plt . subplot ( plots [ 2 ] )
        plot . rainbow = False
        plot . kwargs [ "color" ] = 'b'
        plot . figure_chronological ( )
        plt . gca ( ) . get_xaxis ( ) . set_visible ( False )
        plt . title ( "first AP magnitude" )
        # velocity plot
        plt . subplot ( plots [ 3 ] , sharex = ax2 )
        plot . abf . derivative = True
        plot . rainbow = False
        plot . traceColor = 'r'
        plot . figure_chronological ( )
        plt . axis ( [ ap . APs [ 0 ] [ "T" ] - .05 , ap . APs [ 0 ] [ "T" ] + .05 , None , None ] )
        plt . title ( "first AP velocity" )
if saveAs :
    print ( "saving" , os . path . abspath ( saveAs ) )
    plt . savefig ( os . path . abspath ( saveAs ) , dpi = dpi )
    return
if show :
    plot . show ( )


signature:
def frameAndSave ( abf , tag = "" , dataType = "plot" , saveAsFname = False , closeWhenDone = True ) :
    """frame the current matplotlib plot with ABF info , and optionally save it .
 Note that this is entirely independent of the ABFplot class object .
 if saveImage is False , show it instead .
 Datatype should be :
 * plot
 * experiment"""

implementation:
print ( "closeWhenDone" , closeWhenDone )
plt . tight_layout ( )
plt . subplots_adjust ( top = .93 , bottom = .07 )
plt . annotate ( tag , ( .01 , .99 ) , xycoords = 'figure fraction' , ha = 'left' , va = 'top' , family = 'monospace' , size = 10 , alpha = .5 )
msgBot = "%s [%s]" % ( abf . ID , abf . protocomment )
plt . annotate ( msgBot , ( .01 , .01 ) , xycoords = 'figure fraction' , ha = 'left' , va = 'bottom' , family = 'monospace' , size = 10 , alpha = .5 )
fname = tag . lower ( ) . replace ( " " , '_' ) + ".jpg"
fname = dataType + "_" + fname
plt . tight_layout ( )
if IMAGE_SAVE :
    abf . log . info ( "saving [%s]" , fname )
    try :
        if saveAsFname :
            saveAs = os . path . abspath ( saveAsFname )
        else :
            saveAs = os . path . abspath ( abf . outPre + fname )
        if not os . path . exists ( abf . outFolder ) :
            os . mkdir ( abf . outFolder )
        plt . savefig ( saveAs )
    except Exception as E :
        abf . log . error ( "saving [%s] failed! 'pip install pillow'?" , fname )
        print ( E )
if IMAGE_SHOW == True :
    if closeWhenDone == False :
        print ( "NOT SHOWING (because closeWhenDone==True and showing would mess things up)" )
    else :
        abf . log . info ( "showing [%s]" , fname )
        plt . show ( )
if closeWhenDone :
    print ( "closing figure" )
    plt . close ( 'all' )


signature:
def figure ( self , forceNew = False ) :
    """make sure a figure is ready ."""

implementation:
if plt . _pylab_helpers . Gcf . get_num_fig_managers ( ) > 0 and forceNew is False :
    self . log . debug ( "figure already seen, not creating one." )
    return
if self . subplot :
    self . log . debug ( "subplot mode enabled, not creating new figure" )
else :
    self . log . debug ( "creating new figure" )
    plt . figure ( figsize = ( self . figure_width , self . figure_height ) )


signature:
def save ( self , callit = "misc" , closeToo = True , fullpath = False ) :
    """save the existing figure . does not close it ."""

implementation:
if fullpath is False :
    fname = self . abf . outPre + "plot_" + callit + ".jpg"
else :
    fname = callit
if not os . path . exists ( os . path . dirname ( fname ) ) :
    os . mkdir ( os . path . dirname ( fname ) )
plt . savefig ( fname )
self . log . info ( "saved [%s]" , os . path . basename ( fname ) )
if closeToo :
    plt . close ( )


signature:
def comments ( self , minutes = False ) :
    """Add comment lines / text to an existing plot . Defaults to seconds .
 Call after a plot has been made , and after margins have been set ."""

implementation:
if self . comments == 0 :
    return
self . log . debug ( "adding comments to plot" )
for i , t in enumerate ( self . abf . comment_times ) :
    if minutes :
        t /= 60.0
    plt . axvline ( t , color = 'r' , ls = ':' )
    X1 , X2 , Y1 , Y2 = plt . axis ( )
    Y2 = Y2 - abs ( Y2 - Y1 ) * .02
    plt . text ( t , Y2 , self . abf . comment_tags [ i ] , color = 'r' , rotation = 'vertical' , ha = 'right' , va = 'top' , weight = 'bold' , alpha = .5 , size = 8 , )


signature:
def figure_chronological ( self ) :
    """plot every sweep of an ABF file ( with comments ) ."""

implementation:
self . log . debug ( "creating chronological plot" )
self . figure ( )
for sweep in range ( self . abf . sweeps ) :
    self . abf . setsweep ( sweep )
    self . setColorBySweep ( )
    if self . abf . derivative :
        plt . plot ( self . abf . sweepX , self . abf . sweepD , ** self . kwargs )
    else :
        plt . plot ( self . abf . sweepX , self . abf . sweepY , ** self . kwargs )
self . comments ( )
self . decorate ( )


signature:
def figure_sweeps ( self , offsetX = 0 , offsetY = 0 ) :
    """plot every sweep of an ABF file ."""

implementation:
self . log . debug ( "creating overlayed sweeps plot" )
self . figure ( )
for sweep in range ( self . abf . sweeps ) :
    self . abf . setsweep ( sweep )
    self . setColorBySweep ( )
    plt . plot ( self . abf . sweepX2 + sweep * offsetX , self . abf . sweepY + sweep * offsetY , ** self . kwargs )
if offsetX :
    self . marginX = .05
self . decorate ( )


signature:
def figure_protocol ( self ) :
    """plot the current sweep protocol ."""

implementation:
self . log . debug ( "creating overlayed protocols plot" )
self . figure ( )
plt . plot ( self . abf . protoX , self . abf . protoY , color = 'r' )
self . marginX = 0
self . decorate ( protocol = True )


signature:
def figure_protocols ( self ) :
    """plot the protocol of all sweeps ."""

implementation:
self . log . debug ( "creating overlayed protocols plot" )
self . figure ( )
for sweep in range ( self . abf . sweeps ) :
    self . abf . setsweep ( sweep )
    plt . plot ( self . abf . protoX , self . abf . protoY , color = 'r' )
self . marginX = 0
self . decorate ( protocol = True )


signature:
def fread ( f , byteLocation , structFormat = None , nBytes = 1 ) :
    """Given an already - open ( rb mode ) file object , return a certain number of bytes at a specific location .
 If a struct format is given , calculate the number of bytes required and return the object it represents ."""

implementation:
f . seek ( byteLocation )
if structFormat :
    val = struct . unpack ( structFormat , f . read ( struct . calcsize ( structFormat ) ) )
    val = val [ 0 ] if len ( val ) == 1 else list ( val )
    return val
else :
    return f . read ( nBytes )


signature:
def abf_read_header ( fname , saveHeader = True ) :
    """Practice pulling data straight out of an ABF ' s binary header . Support only ABF2 ( ClampEx an ClampFit 10 ) .
 Use only native python libraries . Strive for simplicity and readability ( to promote language portability ) .
 This was made by Scott Harden after a line - by - line analysis of axonrawio . py from the neo io library .
 Unlike NeoIO ' s format , I ' m going to try to prevent nested dictionaries to keep things simple ."""

implementation:
# # # THESE OBJETS WILL BE FULL WHEN THIS FUNCTION IS COMPLETE
header = { }
# information about the file format
sections = { }
# contains byte positions ( and block sizes ) for header information
strings = [ ]
# a list of strings stored in the ABF header ( protocol file , abf comment , and channel labels / units )
protocol = { }
# info about the ABF recording
tags = [ ]
# timed comments made during the abf as a list of lists [ pos , comment , tagtype , voice ]
adcs = [ ]
# ADC info as a list of dicts
dacs = [ ]
# DAC info as a list of dicts
digitalOutputs = [ ]
# one 0b00000 code per epoch
config = { }
# a concise collection of ABF info I think is useful . I intend only to return this object .
# # # READ THE FIRST PART OF THE FILE INTO MEMORY
# TODO : figure out the most memory - effecient way to do this
f = open ( fname , 'rb' )
config [ "abf_filename" ] = os . path . abspath ( fname )
# full path to the abf file on disk
config [ "abf_ID" ] = os . path . basename ( fname ) [ : - 4 ]
# abf filename without the " . abf "
# # # DECODE HEADER - this tells basic information about the file format
for key , byte_location , fmt in headerDescriptionV2 :
    header [ key ] = fread ( f , byte_location , fmt )
header [ 'fFileSignature' ] = header [ 'fFileSignature' ] . decode ( )
# # # DECODE SECTIONS - sections are where ( byte location ) in this file different data is stored
for sectionNumber , sectionName in enumerate ( sectionNames ) :
    uBlockIndex , uBytes , llNumEntries = fread ( f , 76 + sectionNumber * 16 , "IIl" )
    sections [ sectionName ] = [ uBlockIndex , uBytes , llNumEntries ]
config [ "abf_sweep_start_time" ] = header [ 'uFileStartTimeMS' ] / 1000 / 1000
# # # DECODE STRINGS - figure out where ( byte location ) strings are in this file
# There are 20 strings . Protocol path , ABF comment , then alternating channel name and units .
byte_location = sections [ 'StringsSection' ] [ 0 ] * BLOCKSIZE
string_size = sections [ 'StringsSection' ] [ 1 ]
strings_data = fread ( f , byte_location , structFormat = None , nBytes = string_size )
for key in [ b'AXENGN' , b'clampex' , b'Clampex' , b'CLAMPEX' , b'axoscope' ] :
    if key in strings_data :
        for line in strings_data . split ( key ) [ 1 ] . split ( b'\x00' ) [ 1 : - 1 ] :
            strings . append ( line . decode ( ) )
        config [ "abf_protocol_file" ] = strings [ 0 ]
        config [ "abf_comment" ] = strings [ 1 ]
        config [ "abf_channels" ] = strings [ 2 : : 2 ]
        config [ "abf_units" ] = strings [ 3 : : 2 ]
        break
# # # DECODE ADC INFO - a list of dictionaries , one per ADC employed
for ADCsection in range ( sections [ 'ADCSection' ] [ 2 ] ) :
    thisADC = { }
    byte_location = sections [ 'ADCSection' ] [ 0 ] * BLOCKSIZE + sections [ 'ADCSection' ] [ 1 ] * ADCsection
    for key , fmt in ADCInfoDescription :
        thisADC [ key ] = fread ( f , byte_location , fmt )
        byte_location += struct . calcsize ( fmt )
    adcs . append ( thisADC )
# # # PROTOCOL - info about the nature of the recording
byte_location = sections [ 'ProtocolSection' ] [ 0 ] * BLOCKSIZE
for key , fmt in protocolInfoDescription :
    protocol [ key ] = fread ( f , byte_location , fmt )
    byte_location += struct . calcsize ( fmt )
protocol . pop ( 'sUnused' , None )
# we don ' t need this
# # # TAGS ( COMMMENTS ) - those with a timestamp / comment ( not those embedded in the protocol )
# TODO : not sure what the tagtime units actually are . Byte positions ? Block number ?
byte_location = sections [ 'TagSection' ] [ 0 ] * BLOCKSIZE
for i in range ( sections [ 'TagSection' ] [ 2 ] ) :
    thisTag = [ ]
    for key , fmt in TagInfoDescription :
        val = fread ( f , byte_location , fmt )
        if type ( val ) is bytes :
            val = val . decode ( ) . strip ( )
        thisTag . append ( val )
        byte_location += struct . calcsize ( fmt )
    tags . append ( thisTag )
# # # DAC SECTIONS
for dacNumber in range ( sections [ 'DACSection' ] [ 2 ] ) :
    thisDAC = { }
    byte_location = sections [ 'DACSection' ] [ 0 ] * BLOCKSIZE + sections [ 'DACSection' ] [ 1 ] * dacNumber
    for key , fmt in DACInfoDescription :
        thisDAC [ key ] = fread ( f , byte_location , fmt )
        byte_location += struct . calcsize ( fmt )
    thisDAC . pop ( 'sUnused' , None )
    # we don ' t need this
    if thisDAC [ 'nWaveformEnable' ] == 0 :
        continue
        # don ' t record unused DACs
    dacs . append ( thisDAC )
# # # EPOCHS PER DAC - this is what appear on the waveform tab
epochs = [ ]
for epochNumber in range ( sections [ 'EpochPerDACSection' ] [ 2 ] ) :
    thisEpoch = { }
    byte_location = sections [ 'EpochPerDACSection' ] [ 0 ] * BLOCKSIZE + sections [ 'EpochPerDACSection' ] [ 1 ] * epochNumber
    for key , fmt in EpochInfoPerDACDescription :
        thisEpoch [ key ] = fread ( f , byte_location , fmt )
        byte_location += struct . calcsize ( fmt )
    thisEpoch . pop ( 'sUnused' , None )
    # we don ' t need this
    epochs . append ( thisEpoch )
# # # DIGITAL OUTPUTS - this is where digital outputs are stored . Returns binary string ( 7-0)
# this does not exist in Neo IO . It was hacked - in by Scott Harden ( github : swharden ) to capture digital outputs .
# let ' s just add the digital output string to the epochs array we already have started .
byte_location = sections [ 'EpochSection' ] [ 0 ] * BLOCKSIZE
for epochNumber in range ( sections [ 'EpochSection' ] [ 0 ] ) :
    if epochNumber >= len ( epochs ) :
        break
        # don ' t bother looking up unused epochs
    thisEpoch = epochs [ epochNumber ]
    for key , fmt in EpochSectionDescription :
        val = fread ( f , byte_location , fmt )
        if key == 'nEpochDigitalOutput' :
            val = format ( val , 'b' ) . rjust ( 8 , '0' )
            # convert to a binary string ( 7 - > 0)
        thisEpoch [ key ] = val
        byte_location += struct . calcsize ( fmt )
    thisEpoch . pop ( 'sUnused' , None )
    # we don ' t need this
    epochs [ epochNumber ] = thisEpoch
# # # WE ARE DONE READING THE FILE
f . close ( )
# # # EXTRA CONFIG - cherry - pick just what I find useful and arrange it in a simple dictionary
config [ "abfVersion" ] = float ( "" . join ( [ str ( x ) for x in header [ 'fFileVersionNumber' ] ] ) ) / 100
# now a float
config [ 'signalNames' ] = config [ 'abf_channels' ] [ : len ( adcs ) ]
# don ' t need more than the number of channels
config [ 'signalUnits' ] = config [ 'abf_units' ] [ : len ( adcs ) ]
# don ' t need more than the number of channels
config [ 'comments' ] = [ x [ : 2 ] for x in tags ]
config [ 'nSweeps' ] = sections [ 'SynchArraySection' ] [ 2 ]
# Determine the recording date from the header
YY = int ( header [ 'uFileStartDate' ] / 10000 )
MM = int ( ( header [ 'uFileStartDate' ] - YY * 10000 ) / 100 )
DD = int ( header [ 'uFileStartDate' ] - YY * 10000 - MM * 100 )
hh = int ( header [ 'uFileStartTimeMS' ] / 1000. / 3600. )
mm = int ( ( header [ 'uFileStartTimeMS' ] / 1000. - hh * 3600 ) / 60 )
ss = header [ 'uFileStartTimeMS' ] / 1000. - hh * 3600 - mm * 60
ms = int ( ( ss % 1 ) * 1e6 )
ss = int ( ss )
config [ 'abf_datetime' ] = datetime . datetime ( YY , MM , DD , hh , mm , ss , ms )


signature:
def frames ( fname = None , menuWidth = 200 , launch = False ) :
    """create and save a two column frames HTML file ."""

implementation:
html = """
    <frameset cols="%dpx,*%%">
    <frame name="menu" src="index_menu.html">
    <frame name="content" src="index_splash.html">
    </frameset>""" % ( menuWidth )
with open ( fname , 'w' ) as f :
    f . write ( html )
if launch :
    webbrowser . open ( fname )


signature:
def save ( html , fname = None , launch = False ) :
    """wrap HTML in a top and bottom ( with css ) and save to disk ."""

implementation:
html = html_top + html + html_bot
html = html . replace ( "~GENAT~" , swhlab . common . datetimeToString ( ) )
if fname is None :
    fname = tempfile . gettempdir ( ) + "/temp.html"
    launch = True
fname = os . path . abspath ( fname )
with open ( fname , 'w' ) as f :
    f . write ( html )
global stylesheetSaved
stylesheetPath = os . path . join ( os . path . dirname ( fname ) , "style.css" )
if not os . path . exists ( stylesheetPath ) or stylesheetSaved is False :
    with open ( stylesheetPath , 'w' ) as f :
        f . write ( stylesheet )
        stylesheetSaved = True
if launch :
    webbrowser . open ( fname )


signature:
def clampfit_rename ( path , char ) :
    """Given ABFs and TIFs formatted long style , rename each of them to prefix their number with a different number .
 Example : 2017_10_11_0011 . abf
 Becomes : 2017_10_11 _ ? 011 . abf
 where ? can be any character ."""

implementation:
assert len ( char ) == 1 and type ( char ) == str , "replacement character must be a single character"
assert os . path . exists ( path ) , "path doesn't exist"
files = sorted ( os . listdir ( path ) )
files = [ x for x in files if len ( x ) > 18 and x [ 4 ] + x [ 7 ] + x [ 10 ] == '___' ]
for fname in files :
    fname2 = list ( fname )
    fname2 [ 11 ] = char
    fname2 = "" . join ( fname2 )
    if fname == fname2 :
        print ( fname , "==" , fname2 )
    else :
        print ( fname , "->" , fname2 )
# fname = os . path . join ( path , fname )
# fname2 = os . path . join ( path , fname2)
# if not os . path . exists ( fname2 ) :
# os . rename ( fname , fname2)
return


signature:
def kernel_gaussian ( size = 100 , sigma = None , forwardOnly = False ) :
    """return a 1d gassuan array of a given size and sigma .
 If sigma isn ' t given , it will be 1/10 of the size , which is usually good ."""

implementation:
if sigma is None :
    sigma = size / 10
points = np . exp ( - np . power ( np . arange ( size ) - size / 2 , 2 ) / ( 2 * np . power ( sigma , 2 ) ) )
if forwardOnly :
    points [ : int ( len ( points ) / 2 ) ] = 0
return points / sum ( points )


signature:
def analyzeSweep ( abf , sweep , m1 = None , m2 = None , plotToo = False ) :
    """m1 and m2 , if given , are in seconds .
 returns [ # EPSCs , # IPSCs ]"""

implementation:
abf . setsweep ( sweep )
if m1 is None :
    m1 = 0
else :
    m1 = m1 * abf . pointsPerSec
if m2 is None :
    m2 = - 1
else :
    m2 = m2 * abf . pointsPerSec
# obtain X and Y
Yorig = abf . sweepY [ int ( m1 ) : int ( m2 ) ]
X = np . arange ( len ( Yorig ) ) / abf . pointsPerSec
# start by lowpass filtering ( 1 direction )
# Klpf = kernel _ gaussian ( size = abf . pointsPerMs * 10 , forwardOnly = True )
# Ylpf = np . convolve ( Yorig , Klpf , mode = ' same ' )
# Y = Ylpf # commit
Kmb = kernel_gaussian ( size = abf . pointsPerMs * 10 , forwardOnly = True )
Ymb = np . convolve ( Yorig , Kmb , mode = 'same' )
Y = Yorig - Ymb
# commit
# Y1 = np . copy ( Y )
# Y [ np . where ( Y > 0 ) [ 0 ] ] = np . power ( Y , 2)
# Y [ np . where ( Y < 0 ) [ 0 ] ] = - np . power ( Y , 2)
# event detection
thresh = 5
# threshold for an event
hitPos = np . where ( Y > thresh ) [ 0 ]
# area above the threshold
hitNeg = np . where ( Y < - thresh ) [ 0 ]
# area below the threshold
hitPos = np . concatenate ( ( hitPos , [ len ( Y ) - 1 ] ) )
# helps with the diff ( ) coming up
hitNeg = np . concatenate ( ( hitNeg , [ len ( Y ) - 1 ] ) )
# helps with the diff ( ) coming up
hitsPos = hitPos [ np . where ( np . abs ( np . diff ( hitPos ) ) > 10 ) [ 0 ] ]
# time point of EPSC
hitsNeg = hitNeg [ np . where ( np . abs ( np . diff ( hitNeg ) ) > 10 ) [ 0 ] ]
# time point of IPSC
hitsNeg = hitsNeg [ 1 : ]
# often the first one is in error
# print ( hitsNeg [ 0 ] )
if plotToo :
    plt . figure ( figsize = ( 10 , 5 ) )
    ax1 = plt . subplot ( 211 )
    plt . title ( "sweep %d: detected %d IPSCs (red) and %d EPSCs (blue)" % ( sweep , len ( hitsPos ) , len ( hitsNeg ) ) )
    plt . ylabel ( "delta pA" )
    plt . grid ( )
    plt . plot ( X , Yorig , color = 'k' , alpha = .5 )
    for hit in hitsPos :
        plt . plot ( X [ hit ] , Yorig [ hit ] + 20 , 'r.' , ms = 20 , alpha = .5 )
    for hit in hitsNeg :
        plt . plot ( X [ hit ] , Yorig [ hit ] - 20 , 'b.' , ms = 20 , alpha = .5 )
    plt . margins ( 0 , .1 )
    plt . subplot ( 212 , sharex = ax1 )
    plt . title ( "moving gaussian baseline subtraction used for threshold detection" )
    plt . ylabel ( "delta pA" )
    plt . grid ( )
    plt . axhline ( thresh , color = 'r' , ls = '--' , alpha = .5 , lw = 3 )
    plt . axhline ( - thresh , color = 'r' , ls = '--' , alpha = .5 , lw = 3 )
    plt . plot ( X , Y , color = 'b' , alpha = .5 )
    plt . axis ( [ X [ 0 ] , X [ - 1 ] , - thresh * 1.5 , thresh * 1.5 ] )
    plt . tight_layout ( )
    if type ( plotToo ) is str and os . path . isdir ( plotToo ) :
        print ( 'saving %s/%05d.jpg' % ( plotToo , sweep ) )
        plt . savefig ( plotToo + "/%05d.jpg" % sweep )
    else :
        plt . show ( )
    plt . close ( 'all' )
return [ len ( hitsPos ) , len ( hitsNeg ) ]


signature:
def filesByExtension ( fnames ) :
    """given a list of files , return a dict organized by extension ."""

implementation:
byExt = { "abf" : [ ] , "jpg" : [ ] , "tif" : [ ] }
# prime it with empties
for fname in fnames :
    ext = os . path . splitext ( fname ) [ 1 ] . replace ( "." , '' ) . lower ( )
    if not ext in byExt . keys ( ) :
        byExt [ ext ] = [ ]
    byExt [ ext ] = byExt [ ext ] + [ fname ]
return byExt


signature:
def findCells ( fnames ) :
    """given a list of files , return a list of cells by their ID .
 A cell is indicated when an ABF name matches the start of another file .
 Example :
 123456 . abf
 123456 - whatever . tif"""

implementation:
IDs = [ ]
filesByExt = filesByExtension ( fnames )
for abfFname in filesByExt [ 'abf' ] :
    ID = os . path . splitext ( abfFname ) [ 0 ]
    for picFname in filesByExt [ 'jpg' ] + filesByExt [ 'tif' ] :
        if picFname . startswith ( ID ) :
            IDs . append ( ID )
            break
return smartSort ( IDs )


signature:
def filesByCell ( fnames , cells ) :
    """given files and cells , return a dict of files grouped by cell ."""

implementation:
byCell = { }
fnames = smartSort ( fnames )
days = list ( set ( [ elem [ : 5 ] for elem in fnames if elem . endswith ( ".abf" ) ] ) )
# so pythonic !
for day in smartSort ( days ) :
    parent = None
    for i , fname in enumerate ( [ elem for elem in fnames if elem . startswith ( day ) and elem . endswith ( ".abf" ) ] ) :
        ID = os . path . splitext ( fname ) [ 0 ]
        if len ( [ x for x in fnames if x . startswith ( ID ) ] ) - 1 :
            parent = ID
        if not parent in byCell :
            byCell [ parent ] = [ ]
        byCell [ parent ] = byCell [ parent ] + [ fname ]
return byCell


signature:
def folderScan ( self , abfFolder = None ) :
    """populate class properties relating to files in the folder ."""

implementation:
if abfFolder is None and 'abfFolder' in dir ( self ) :
    abfFolder = self . abfFolder
else :
    self . abfFolder = abfFolder
self . abfFolder = os . path . abspath ( self . abfFolder )
self . log . info ( "scanning [%s]" , self . abfFolder )
if not os . path . exists ( self . abfFolder ) :
    self . log . error ( "path doesn't exist: [%s]" , abfFolder )
    return
self . abfFolder2 = os . path . abspath ( self . abfFolder + "/swhlab/" )
if not os . path . exists ( self . abfFolder2 ) :
    self . log . error ( "./swhlab/ doesn't exist. creating it..." )
    os . mkdir ( self . abfFolder2 )
self . fnames = os . listdir ( self . abfFolder )
self . fnames2 = os . listdir ( self . abfFolder2 )
self . log . debug ( "./ has %d files" , len ( self . fnames ) )
self . log . debug ( "./swhlab/ has %d files" , len ( self . fnames2 ) )
self . fnamesByExt = filesByExtension ( self . fnames )
if not "abf" in self . fnamesByExt . keys ( ) :
    self . log . error ( "no ABF files found" )
self . log . debug ( "found %d ABFs" , len ( self . fnamesByExt [ "abf" ] ) )
self . cells = findCells ( self . fnames )
# list of cells by their ID
self . log . debug ( "found %d cells" % len ( self . cells ) )
self . fnamesByCell = filesByCell ( self . fnames , self . cells )
# only ABFs
self . log . debug ( "grouped cells by number of source files: %s" % str ( [ len ( self . fnamesByCell [ elem ] ) for elem in self . fnamesByCell ] ) )


signature:
def html_index ( self , launch = False , showChildren = False ) :
    """generate list of cells with links . keep this simple .
 automatically generates splash page and regnerates frames ."""

implementation:
self . makePics ( )
# ensure all pics are converted
# generate menu
html = './%s/
' % os . path . basename ( self . abfFolder )
for ID in smartSort ( self . fnamesByCell . keys ( ) ) :
    link = ''
    if ID + ".html" in self . fnames2 :
        link = 'href="%s.html" target="content"' % ID
    html += ( '%s
' % ( link , ID ) )
    # show the parent ABF ( ID )
    if showChildren :
        for fname in self . fnamesByCell [ ID ] :
            thisID = os . path . splitext ( fname ) [ 0 ]
            files2 = [ x for x in self . fnames2 if x . startswith ( thisID ) and not x . endswith ( ".html" ) ]
            html += '%s' % thisID
            # show the child ABF
            if len ( files2 ) :
                html += ' (%s)' % len ( files2 )
                # show number of supporting files
            html += '
'
        html += "
"
style . save ( html , self . abfFolder2 + "/index_menu.html" )
self . html_index_splash ( )
# make splash page
style . frames ( self . abfFolder2 + "/index.html" , launch = launch )


signature:
def html_index_splash ( self ) :
    """generate landing page ."""

implementation:
html = """

        SWHLab %s<?span>

        """ % version . __version__
# html + = '  % s

 ' % self . abfFolder
# html + = '
 '
for parent in smartSort ( self . fnamesByCell . keys ( ) ) :
    html += '
%s
' % ( parent , parent )
    for child in self . fnamesByCell [ parent ] :
        fullpath = os . path . join ( self . abfFolder , child )
        protocol = swhlab . swh_abf . abfProtocol ( fullpath )
        html += '%s[%s]
' % ( fullpath , protocol )
style . save ( html , self . abfFolder2 + "/index_splash.html" )
return


signature:
def html_single_basic ( self , ID ) :
    """generate . / swhlab / xxyxxzzz . html for a single given abf .
 Input can be an ABF file path of ABF ID ."""

implementation:
if not ID in self . cells :
    self . log . error ( "ID [%s] not seen!" , ID )
    return
htmlFname = os . path . abspath ( self . abfFolder2 + "/" + ID + ".html" )
html = "
Data for ID %s
" % ID
npics = 0
for childID in [ os . path . splitext ( x ) [ 0 ] for x in self . fnamesByCell [ ID ] ] :
    pics = [ x for x in self . fnames2 if x . startswith ( childID ) and os . path . splitext ( x ) [ 1 ] . lower ( ) in [ ".png" , ".jpg" ] ]
    html += "%s
" % ( os . path . abspath ( self . abfFolder + '/' + childID + ".abf" ) )
    for i , pic in enumerate ( pics ) :
        html += '' % ( pic , pic )
        npics += 1
    html += "

"
style . save ( html , htmlFname )
self . log . info ( "created %s containing %d pictures" , htmlFname , npics )


signature:
def html_singleAll ( self , template = "basic" ) :
    """generate a data view for every ABF in the project folder ."""

implementation:
for fname in smartSort ( self . cells ) :
    if template == "fixed" :
        self . html_single_fixed ( fname )
    else :
        self . html_single_basic ( fname )


signature:
def makePics ( self ) :
    """convert every . image we find to a . / swhlab / image"""

implementation:
rescanNeeded = False
for fname in smartSort ( self . fnames ) :
    if fname in self . fnames2 :
        continue
    ext = os . path . splitext ( fname ) [ 1 ] . lower ( )
    if ext in [ ".jpg" , ".png" ] :
        if not fname in self . abfFolder2 :
            self . log . debug ( "copying %s" , fname )
            shutil . copy ( os . path . join ( self . abfFolder , fname ) , os . path . join ( self . abfFolder2 , fname ) )
            rescanNeeded = True
    if ext in [ ".tif" , ".tiff" ] :
        if not fname + ".jpg" in self . fnames2 :
            self . log . debug ( "converting %s" , fname )
            swhlab . swh_image . TIF_to_jpg ( os . path . join ( self . abfFolder , fname ) , saveAs = os . path . join ( self . abfFolder2 , fname + ".jpg" ) )
            rescanNeeded = True
if rescanNeeded :
    self . log . debug ( "new pics, so a rescan is needed..." )
    self . log . debug ( "REBUILDING ALL RECOMMENDED!!!!!!!!!!!" )
    self . folderScan ( )


signature:
def proto_01_01_HP010 ( abf = exampleABF ) :
    """hyperpolarization step . Use to calculate tau and stuff ."""

implementation:
swhlab . memtest . memtest ( abf )
# knows how to do IC memtest
swhlab . memtest . checkSweep ( abf )
# lets you eyeball check how it did
swhlab . plot . save ( abf , tag = "tau" )


signature:
def proto_01_11_rampStep ( abf = exampleABF ) :
    """each sweep is a ramp ( of set size ) which builds on the last sweep .
 Used for detection of AP properties from first few APs ."""

implementation:
standard_inspect ( abf )
swhlab . ap . detect ( abf )
swhlab . ap . check_sweep ( abf )
# eyeball how well event detection worked
swhlab . plot . save ( abf , tag = "check" )
swhlab . ap . check_AP_raw ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "raw" , resize = False )
swhlab . ap . check_AP_deriv ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "deriv" )
swhlab . ap . check_AP_phase ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "phase" )
for feature in [ 'downslope' , 'freq' ] :
    swhlab . ap . plot_values ( abf , feature , continuous = True )
    # plot AP info
    swhlab . plot . save ( abf , tag = feature )


signature:
def proto_01_12_steps025 ( abf = exampleABF ) :
    """IC steps . Use to determine gain function ."""

implementation:
swhlab . ap . detect ( abf )
standard_groupingForInj ( abf , 200 )
for feature in [ 'freq' , 'downslope' ] :
    swhlab . ap . plot_values ( abf , feature , continuous = False )
    # plot AP info
    swhlab . plot . save ( abf , tag = 'A_' + feature )
swhlab . plot . gain ( abf )
# easy way to do a gain function !
swhlab . plot . save ( abf , tag = '05-gain' )


signature:
def proto_01_13_steps025dual ( abf = exampleABF ) :
    """IC steps . See how hyperpol . step affects things ."""

implementation:
swhlab . ap . detect ( abf )
standard_groupingForInj ( abf , 200 )
for feature in [ 'freq' , 'downslope' ] :
    swhlab . ap . plot_values ( abf , feature , continuous = False )
    # plot AP info
    swhlab . plot . save ( abf , tag = 'A_' + feature )
f1 = swhlab . ap . getAvgBySweep ( abf , 'freq' , None , 1 )
f2 = swhlab . ap . getAvgBySweep ( abf , 'freq' , 1 , None )
f1 = np . nan_to_num ( f1 )
f2 = np . nan_to_num ( f2 )
Xs = abf . clampValues ( abf . dataX [ int ( abf . protoSeqX [ 1 ] + .01 ) ] )
swhlab . plot . new ( abf , title = "gain function" , xlabel = "command current (pA)" , ylabel = "average inst. freq. (Hz)" )
pylab . plot ( Xs , f1 , '.-' , ms = 20 , alpha = .5 , label = "step 1" , color = 'b' )
pylab . plot ( Xs , f2 , '.-' , ms = 20 , alpha = .5 , label = "step 2" , color = 'r' )
pylab . legend ( loc = 'upper left' )
pylab . axis ( [ Xs [ 0 ] , Xs [ - 1 ] , None , None ] )
swhlab . plot . save ( abf , tag = 'gain' )


signature:
def proto_02_01_MT70 ( abf = exampleABF ) :
    """repeated membrane tests ."""

implementation:
standard_overlayWithAverage ( abf )
swhlab . memtest . memtest ( abf )
swhlab . memtest . checkSweep ( abf )
swhlab . plot . save ( abf , tag = 'check' , resize = False )


signature:
def proto_02_02_IVdual ( abf = exampleABF ) :
    """dual I / V steps in VC mode , one from - 70 and one - 50."""

implementation:
av1 , sd1 = swhlab . plot . IV ( abf , .7 , 1 , True , 'b' )
swhlab . plot . save ( abf , tag = 'iv1' )
a2v , sd2 = swhlab . plot . IV ( abf , 2.2 , 2.5 , True , 'r' )
swhlab . plot . save ( abf , tag = 'iv2' )
swhlab . plot . sweep ( abf , 'all' )
pylab . axis ( [ None , None , min ( av1 ) - 50 , max ( av1 ) + 50 ] )
swhlab . plot . save ( abf , tag = 'overlay' )


signature:
def proto_02_03_IVfast ( abf = exampleABF ) :
    """fast sweeps , 1 step per sweep , for clean IV without fast currents ."""

implementation:
av1 , sd1 = swhlab . plot . IV ( abf , .6 , .9 , True )
swhlab . plot . save ( abf , tag = 'iv1' )
Xs = abf . clampValues ( .6 )
# generate IV clamp values
abf . saveThing ( [ Xs , av1 ] , 'iv' )


signature:
def proto_04_01_MTmon70s2 ( abf = exampleABF ) :
    """repeated membrane tests , likely with drug added . Maybe IPSCs ."""

implementation:
standard_inspect ( abf )
swhlab . memtest . memtest ( abf )
swhlab . memtest . checkSweep ( abf )
swhlab . plot . save ( abf , tag = 'check' , resize = False )
swhlab . memtest . plot_standard4 ( abf )
swhlab . plot . save ( abf , tag = 'memtests' )


signature:
def proto_VC_50_MT_IV ( abf = exampleABF ) :
    """combination of membrane test and IV steps ."""

implementation:
swhlab . memtest . memtest ( abf )
# do membrane test on every sweep
swhlab . memtest . checkSweep ( abf )
# see all MT values
swhlab . plot . save ( abf , tag = '02-check' , resize = False )
av1 , sd1 = swhlab . plot . IV ( abf , 1.2 , 1.4 , True , 'b' )
swhlab . plot . save ( abf , tag = 'iv' )
Xs = abf . clampValues ( 1.2 )
# generate IV clamp values
abf . saveThing ( [ Xs , av1 ] , '01_iv' )


signature:
def proto_IC_ramp_gain ( abf = exampleABF ) :
    """increasing ramps in ( ? ) pA steps ."""

implementation:
standard_inspect ( abf )
swhlab . ap . detect ( abf )
swhlab . ap . check_AP_raw ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "01-raw" , resize = False )
swhlab . ap . check_AP_deriv ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "02-deriv" )
swhlab . ap . check_AP_phase ( abf )
# show overlayed first few APs
swhlab . plot . save ( abf , tag = "03-phase" )
swhlab . ap . plot_values ( abf , 'freq' , continuous = True )
# plot AP info
pylab . subplot ( 211 )
pylab . axhline ( 40 , color = 'r' , lw = 2 , ls = "--" , alpha = .2 )
swhlab . plot . save ( abf , tag = '04-freq' )
swhlab . ap . plot_values ( abf , 'downslope' , continuous = True )
# plot AP info
pylab . subplot ( 211 )
pylab . axhline ( - 100 , color = 'r' , lw = 2 , ls = "--" , alpha = .2 )
swhlab . plot . save ( abf , tag = '04-downslope' )


signature:
def indexImages ( folder , fname = "index.html" ) :
    """OBSOLETE WAY TO INDEX A FOLDER ."""

implementation:
# TODO : REMOVE
html = ""
for item in glob . glob ( folder + "/*.*" ) :
    if item . split ( "." ) [ - 1 ] in [ 'jpg' , 'png' ] :
        html += "
%s
" % os . path . basename ( item )
        html += '' % os . path . basename ( item )
        html += '
' * 10
html += ""
f = open ( folder + "/" + fname , 'w' )
f . write ( html )
f . close
print ( "indexed:" )
print ( "  " , os . path . abspath ( folder + "/" + fname ) )
return


signature:
def save ( self , * args , ** kwargs ) :
    """A custom save method that handles figuring out when something is activated or deactivated ."""

implementation:
current_activable_value = getattr ( self , self . ACTIVATABLE_FIELD_NAME )
is_active_changed = self . id is None or self . __original_activatable_value != current_activable_value
self . __original_activatable_value = current_activable_value
ret_val = super ( BaseActivatableModel , self ) . save ( * args , ** kwargs )
# Emit the signals for when the is _ active flag is changed
if is_active_changed :
    model_activations_changed . send ( self . __class__ , instance_ids = [ self . id ] , is_active = current_activable_value )
if self . activatable_field_updated :
    model_activations_updated . send ( self . __class__ , instance_ids = [ self . id ] , is_active = current_activable_value )
return ret_val


signature:
def delete ( self , force = False , ** kwargs ) :
    """It is impossible to delete an activatable model unless force is True . This function instead sets it to inactive ."""

implementation:
if force :
    return super ( BaseActivatableModel , self ) . delete ( ** kwargs )
else :
    setattr ( self , self . ACTIVATABLE_FIELD_NAME , False )
    return self . save ( update_fields = [ self . ACTIVATABLE_FIELD_NAME ] )


signature:
def show ( self , args , file_handle = None , ** kwargs ) :
    "Write to file _ handle if supplied , othewise print output"

implementation:
full_string = ''
info = { 'root_directory' : '<root_directory>' , 'batch_name' : '<batch_name>' , 'batch_tag' : '<batch_tag>' , 'batch_description' : '<batch_description>' , 'launcher' : '<launcher>' , 'timestamp_format' : '<timestamp_format>' , 'timestamp' : tuple ( time . localtime ( ) ) , 'varying_keys' : args . varying_keys , 'constant_keys' : args . constant_keys , 'constant_items' : args . constant_items }
quoted_cmds = [ subprocess . list2cmdline ( [ el for el in self ( self . _formatter ( s ) , '<tid>' , info ) ] ) for s in args . specs ]
cmd_lines = [ '%d: %s\n' % ( i , qcmds ) for ( i , qcmds ) in enumerate ( quoted_cmds ) ]
full_string += '' . join ( cmd_lines )
if file_handle :
    file_handle . write ( full_string )
    file_handle . flush ( )
else :
    print ( full_string )


signature:
def update ( self ) :
    """Update the launch information - - use if additional launches were
 made ."""

implementation:
launches = [ ]
for path in os . listdir ( self . output_dir ) :
    full_path = os . path . join ( self . output_dir , path )
    if os . path . isdir ( full_path ) :
        launches . append ( self . _get_launch_info ( full_path ) )
self . launches = sorted ( launches )


signature:
def get_root_directory ( self , timestamp = None ) :
    """A helper method that supplies the root directory name given a
 timestamp ."""

implementation:
if timestamp is None :
    timestamp = self . timestamp
if self . timestamp_format is not None :
    root_name = ( time . strftime ( self . timestamp_format , timestamp ) + '-' + self . batch_name )
else :
    root_name = self . batch_name
path = os . path . join ( self . output_directory , * ( self . subdir + [ root_name ] ) )
return os . path . abspath ( path )


signature:
def _append_log ( self , specs ) :
    """The log contains the tids and corresponding specifications
 used during launch with the specifications in JSON format ."""

implementation:
self . _spec_log += specs
# This should be removed
log_path = os . path . join ( self . root_directory , ( "%s.log" % self . batch_name ) )
core . Log . write_log ( log_path , [ spec for ( _ , spec ) in specs ] , allow_append = True )


signature:
def _record_info ( self , setup_info = None ) :
    """All launchers should call this method to write the info file
 at the end of the launch . The . info file is saved given
 setup _ info supplied by _ setup _ launch into the
 root _ directory . When called without setup _ info , the existing
 info file is updated with the end - time ."""

implementation:
info_path = os . path . join ( self . root_directory , ( '%s.info' % self . batch_name ) )
if setup_info is None :
    try :
        with open ( info_path , 'r' ) as info_file :
            setup_info = json . load ( info_file )
    except :
        setup_info = { }
    setup_info . update ( { 'end_time' : tuple ( time . localtime ( ) ) } )
else :
    setup_info . update ( { 'end_time' : None , 'metadata' : self . metadata } )
with open ( info_path , 'w' ) as info_file :
    json . dump ( setup_info , info_file , sort_keys = True , indent = 4 )


signature:
def _setup_launch ( self ) :
    """Method to be used by all launchers that prepares the root
 directory and generate basic launch information for command
 templates to use ( including a registered timestamp ) ."""

implementation:
self . root_directory = self . get_root_directory ( )
if not os . path . isdir ( self . root_directory ) :
    os . makedirs ( self . root_directory )
platform_dict = { }
python_version = ( platform . python_implementation ( ) + platform . python_version ( ) )
platform_dict [ 'platform' ] = platform . platform ( )
platform_dict [ 'python_version' ] = python_version
platform_dict [ 'lancet_version' ] = str ( lancet_version )
return { 'root_directory' : self . root_directory , 'batch_name' : self . batch_name , 'batch_tag' : self . tag , 'batch_description' : self . description , 'launcher' : repr ( self ) , 'platform' : platform_dict , 'timestamp' : self . timestamp , 'timestamp_format' : self . timestamp_format , 'varying_keys' : self . args . varying_keys , 'constant_keys' : self . args . constant_keys , 'constant_items' : self . args . constant_items }


signature:
def summary ( self ) :
    """A succinct summary of the Launcher configuration . Unlike the
 repr , a summary does not have to be complete but must supply
 key information relevant to the user ."""

implementation:
print ( "Type: %s" % self . __class__ . __name__ )
print ( "Batch Name: %r" % self . batch_name )
if self . tag :
    print ( "Tag: %s" % self . tag )
print ( "Root directory: %r" % self . get_root_directory ( ) )
print ( "Maximum concurrency: %s" % self . max_concurrency )
if self . description :
    print ( "Description: %s" % self . description )


signature:
def _qsub_args ( self , override_options , cmd_args , append_options = [ ] ) :
    """Method to generate Popen style argument list for qsub using
 the qsub _ switches and qsub _ flag _ options parameters . Switches
 are returned first . The qsub _ flag _ options follow in keys ( )
 ordered if not a vanilla Python dictionary ( ie . a Python 2.7 +
 or param . external OrderedDict ) . Otherwise the keys are sorted
 alphanumerically . Note that override _ options is a list of
 key - value pairs ."""

implementation:
opt_dict = type ( self . qsub_flag_options ) ( )
opt_dict . update ( self . qsub_flag_options )
opt_dict . update ( override_options )
if type ( self . qsub_flag_options ) == dict : # Alphanumeric sort if vanilla Python dictionary
    ordered_options = [ ( k , opt_dict [ k ] ) for k in sorted ( opt_dict ) ]
else :
    ordered_options = list ( opt_dict . items ( ) )
ordered_options += append_options
unpacked_groups = [ [ ( k , v ) for v in val ] if type ( val ) == list else [ ( k , val ) ] for ( k , val ) in ordered_options ]
unpacked_kvs = [ el for group in unpacked_groups for el in group ]
# Adds ' - ' if missing ( eg , keywords in dict constructor ) and flattens lists .
ordered_pairs = [ ( k , v ) if ( k [ 0 ] == '-' ) else ( '-%s' % ( k ) , v ) for ( k , v ) in unpacked_kvs ]
ordered_options = [ [ k ] + ( [ v ] if type ( v ) == str else list ( v ) ) for ( k , v ) in ordered_pairs ]
flattened_options = [ el for kvs in ordered_options for el in kvs ]
return ( [ 'qsub' ] + self . qsub_switches + flattened_options + [ pipes . quote ( c ) for c in cmd_args ] )


signature:
def collate_and_launch ( self ) :
    """Method that collates the previous jobs and launches the next
 block of concurrent jobs when using DynamicArgs . This method
 is invoked on initial launch and then subsequently via a
 commandline call ( to Python via qsub ) to collate the
 previously run jobs and launch the next block of jobs ."""

implementation:
try :
    specs = next ( self . spec_iter )
except StopIteration :
    self . qdel_batch ( )
    if self . reduction_fn is not None :
        self . reduction_fn ( self . _spec_log , self . root_directory )
    self . _record_info ( )
    return
tid_specs = [ ( self . last_tid + i , spec ) for ( i , spec ) in enumerate ( specs ) ]
self . last_tid += len ( specs )
self . _append_log ( tid_specs )
# Updating the argument specifier
if self . dynamic :
    self . args . update ( self . last_tids , self . _launchinfo )
self . last_tids = [ tid for ( tid , _ ) in tid_specs ]
output_dir = self . qsub_flag_options [ '-o' ]
error_dir = self . qsub_flag_options [ '-e' ]
self . _qsub_block ( output_dir , error_dir , tid_specs )
# Pickle launcher before exit if necessary .
if self . dynamic or ( self . reduction_fn is not None ) :
    pickle_path = os . path . join ( self . root_directory , 'qlauncher.pkl' )
    pickle . dump ( self , open ( pickle_path , 'wb' ) , protocol = 2 )


signature:
def _qsub_collate_and_launch ( self , output_dir , error_dir , job_names ) :
    """The method that actually runs qsub to invoke the python
 process with the necessary commands to trigger the next
 collation step and next block of jobs ."""

implementation:
job_name = "%s_%s_collate_%d" % ( self . batch_name , self . job_timestamp , self . collate_count )
overrides = [ ( "-e" , error_dir ) , ( '-N' , job_name ) , ( "-o" , output_dir ) , ( '-hold_jid' , ',' . join ( job_names ) ) ]
resume_cmds = [ "import os, pickle, lancet" , ( "pickle_path = os.path.join(%r, 'qlauncher.pkl')" % self . root_directory ) , "launcher = pickle.load(open(pickle_path,'rb'))" , "launcher.collate_and_launch()" ]
cmd_args = [ self . command . executable , '-c' , ';' . join ( resume_cmds ) ]
popen_args = self . _qsub_args ( overrides , cmd_args )
p = subprocess . Popen ( popen_args , stdout = subprocess . PIPE )
( stdout , stderr ) = p . communicate ( )
self . debug ( stdout )
if p . poll ( ) != 0 :
    raise EnvironmentError ( "qsub command exit with code: %d" % p . poll ( ) )
self . collate_count += 1
self . message ( "Invoked qsub for next batch." )
return job_name


signature:
def _qsub_block ( self , output_dir , error_dir , tid_specs ) :
    """This method handles static argument specifiers and cases where
 the dynamic specifiers cannot be queued before the arguments
 are known ."""

implementation:
processes = [ ]
job_names = [ ]
for ( tid , spec ) in tid_specs :
    job_name = "%s_%s_tid_%d" % ( self . batch_name , self . job_timestamp , tid )
    job_names . append ( job_name )
    cmd_args = self . command ( self . command . _formatter ( spec ) , tid , self . _launchinfo )
    popen_args = self . _qsub_args ( [ ( "-e" , error_dir ) , ( '-N' , job_name ) , ( "-o" , output_dir ) ] , cmd_args )
    p = subprocess . Popen ( popen_args , stdout = subprocess . PIPE )
    ( stdout , stderr ) = p . communicate ( )
    self . debug ( stdout )
    if p . poll ( ) != 0 :
        raise EnvironmentError ( "qsub command exit with code: %d" % p . poll ( ) )
    processes . append ( p )
self . message ( "Invoked qsub for %d commands" % len ( processes ) )
if ( self . reduction_fn is not None ) or self . dynamic :
    self . _qsub_collate_and_launch ( output_dir , error_dir , job_names )


signature:
def qdel_batch ( self ) :
    """Runs qdel command to remove all remaining queued jobs using
 the < batch _ name > * pattern . Necessary when StopIteration is
 raised with scheduled jobs left on the queue .
 Returns exit - code of qdel ."""

implementation:
p = subprocess . Popen ( [ 'qdel' , '%s_%s*' % ( self . batch_name , self . job_timestamp ) ] , stdout = subprocess . PIPE )
( stdout , stderr ) = p . communicate ( )
return p . poll ( )


signature:
def _launch_process_group ( self , process_commands , streams_path ) :
    """Aggregates all process _ commands and the designated output files into a
 list , and outputs it as JSON , after which the wrapper script is called ."""

implementation:
processes = [ ]
for cmd , tid in process_commands :
    job_timestamp = time . strftime ( '%H%M%S' )
    basename = "%s_%s_tid_%d" % ( self . batch_name , job_timestamp , tid )
    stdout_path = os . path . join ( streams_path , "%s.o.%d" % ( basename , tid ) )
    stderr_path = os . path . join ( streams_path , "%s.e.%d" % ( basename , tid ) )
    process = { 'tid' : tid , 'cmd' : cmd , 'stdout' : stdout_path , 'stderr' : stderr_path }
    processes . append ( process )
# To make the JSON filename unique per group , we use the last tid in
# this group .
json_path = os . path . join ( self . root_directory , self . json_name % ( tid ) )
with open ( json_path , 'w' ) as json_file :
    json . dump ( processes , json_file , sort_keys = True , indent = 4 )
p = subprocess . Popen ( [ self . script_path , json_path , self . batch_name , str ( len ( processes ) ) , str ( self . max_concurrency ) ] )
if p . wait ( ) != 0 :
    raise EnvironmentError ( "Script command exit with code: %d" % p . poll ( ) )


signature:
def cross_check_launchers ( self , launchers ) :
    """Performs consistency checks across all the launchers ."""

implementation:
if len ( launchers ) == 0 :
    raise Exception ( 'Empty launcher list' )
timestamps = [ launcher . timestamp for launcher in launchers ]
if not all ( timestamps [ 0 ] == tstamp for tstamp in timestamps ) :
    raise Exception ( "Launcher timestamps not all equal. " "Consider setting timestamp explicitly." )
root_directories = [ ]
for launcher in launchers :
    command = launcher . command
    args = launcher . args
    command . verify ( args )
    root_directory = launcher . get_root_directory ( )
    if os . path . isdir ( root_directory ) :
        raise Exception ( "Root directory already exists: %r" % root_directory )
    if root_directory in root_directories :
        raise Exception ( "Each launcher requires a unique root directory" )
    root_directories . append ( root_directory )


signature:
def _launch_all ( self , launchers ) :
    """Launches all available launchers ."""

implementation:
for launcher in launchers :
    print ( "== Launching  %s ==" % launcher . batch_name )
    launcher ( )
return True


signature:
def _review_all ( self , launchers ) :
    """Runs the review process for all the launchers ."""

implementation:
# Run review of launch args if necessary
if self . launch_args is not None :
    proceed = self . review_args ( self . launch_args , show_repr = True , heading = 'Meta Arguments' )
    if not proceed :
        return False
reviewers = [ self . review_args , self . review_command , self . review_launcher ]
for ( count , launcher ) in enumerate ( launchers ) : # Run reviews for all launchers if desired . . .
    if not all ( reviewer ( launcher ) for reviewer in reviewers ) :
        print ( "\n == Aborting launch ==" )
        return False
    # But allow the user to skip these extra reviews
    if len ( launchers ) != 1 and count < len ( launchers ) - 1 :
        skip_remaining = self . input_options ( [ 'Y' , 'n' , 'quit' ] , '\nSkip remaining reviews?' , default = 'y' )
        if skip_remaining == 'y' :
            break
        elif skip_remaining == 'quit' :
            return False
if self . input_options ( [ 'y' , 'N' ] , 'Execute?' , default = 'n' ) != 'y' :
    return False
else :
    return self . _launch_all ( launchers )


signature:
def review_args ( self , obj , show_repr = False , heading = 'Arguments' ) :
    """Reviews the given argument specification . Can review the
 meta - arguments ( launch _ args ) or the arguments themselves ."""

implementation:
args = obj . args if isinstance ( obj , Launcher ) else obj
print ( '\n%s\n' % self . summary_heading ( heading ) )
args . summary ( )
if show_repr :
    print ( "\n%s\n" % args )
response = self . input_options ( [ 'y' , 'N' , 'quit' ] , '\nShow available argument specifier entries?' , default = 'n' )
if response == 'quit' :
    return False
if response == 'y' :
    args . show ( )
print ( '' )
return True


signature:
def input_options ( self , options , prompt = 'Select option' , default = None ) :
    """Helper to prompt the user for input on the commandline ."""

implementation:
check_options = [ x . lower ( ) for x in options ]
while True :
    response = input ( '%s [%s]: ' % ( prompt , ', ' . join ( options ) ) ) . lower ( )
    if response in check_options :
        return response . strip ( )
    elif response == '' and default is not None :
        return default . lower ( ) . strip ( )


signature:
def save ( self , filename , metadata = { } , ** data ) :
    """The implementation in the base class simply checks there is no
 clash between the metadata and data keys ."""

implementation:
intersection = set ( metadata . keys ( ) ) & set ( data . keys ( ) )
if intersection :
    msg = 'Key(s) overlap between data and metadata: %s'
    raise Exception ( msg % ',' . join ( intersection ) )


signature:
def _savepath ( self , filename ) :
    """Returns the full path for saving the file , adding an extension
 and making the filename unique as necessary ."""

implementation:
( basename , ext ) = os . path . splitext ( filename )
basename = basename if ( ext in self . extensions ) else filename
ext = ext if ( ext in self . extensions ) else self . extensions [ 0 ]
savepath = os . path . abspath ( os . path . join ( self . directory , '%s%s' % ( basename , ext ) ) )
return ( tempfile . mkstemp ( ext , basename + "_" , self . directory ) [ 1 ] if self . hash_suffix else savepath )


signature:
def file_supported ( cls , filename ) :
    """Returns a boolean indicating whether the filename has an
 appropriate extension for this class ."""

implementation:
if not isinstance ( filename , str ) :
    return False
( _ , ext ) = os . path . splitext ( filename )
if ext not in cls . extensions :
    return False
else :
    return True


signature:
def save ( self , filename , imdata , ** data ) :
    """Data may be either a PIL Image object or a Numpy array ."""

implementation:
if isinstance ( imdata , numpy . ndarray ) :
    imdata = Image . fromarray ( numpy . uint8 ( imdata ) )
elif isinstance ( imdata , Image . Image ) :
    imdata . save ( self . _savepath ( filename ) )


signature:
def fileModifiedTimestamp ( fname ) :
    """return " YYYY - MM - DD " when the file was modified ."""

implementation:
modifiedTime = os . path . getmtime ( fname )
stamp = time . strftime ( '%Y-%m-%d' , time . localtime ( modifiedTime ) )
return stamp


signature:
def loadResults ( resultsFile ) :
    """returns a dict of active folders with days as keys ."""

implementation:
with open ( resultsFile ) as f :
    raw = f . read ( ) . split ( "\n" )
foldersByDay = { }
for line in raw :
    folder = line . split ( '"' ) [ 1 ] + "\\"
    line = [ ] + line . split ( '"' ) [ 2 ] . split ( ", " )
    for day in line [ 1 : ] :
        if not day in foldersByDay :
            foldersByDay [ day ] = [ ]
        foldersByDay [ day ] = foldersByDay [ day ] + [ folder ]
nActiveDays = len ( foldersByDay )
dayFirst = sorted ( foldersByDay . keys ( ) ) [ 0 ]
dayLast = sorted ( foldersByDay . keys ( ) ) [ - 1 ]
dayFirst = datetime . datetime . strptime ( dayFirst , "%Y-%m-%d" )
dayLast = datetime . datetime . strptime ( dayLast , "%Y-%m-%d" )
nDays = ( dayLast - dayFirst ) . days + 1
emptyDays = 0
for deltaDays in range ( nDays ) :
    day = dayFirst + datetime . timedelta ( days = deltaDays )
    stamp = datetime . datetime . strftime ( day , "%Y-%m-%d" )
    if not stamp in foldersByDay :
        foldersByDay [ stamp ] = [ ]
        emptyDays += 1
percActive = nActiveDays / nDays * 100
print ( "%d of %d days were active (%.02f%%)" % ( nActiveDays , nDays , percActive ) )
return foldersByDay


signature:
def HTML_results ( resultsFile ) :
    """generates HTML report of active folders / days ."""

implementation:
foldersByDay = loadResults ( resultsFile )
# optionally skip dates before a certain date
# for day in sorted ( list ( foldersByDay . keys ( ) ) ) :
# if time . strptime ( day , " % Y - % m - % d " ) < time . strptime ( " 2016-05-01 " , " % Y - % m - % d " ) :
# del foldersByDay [ day ]
# Create a header
html = "
Active Folder Report (updated TIMESTAMP)
"
html += "
When a file is created (or modified) its parent folder is marked active for that day."
html += "
This page reports all folders which were active in the last several years. "
html += "
A single folder can be active for more than one date."
html = html . replace ( "TIMESTAMP" , ( time . strftime ( '%Y-%m-%d' , time . localtime ( ) ) ) )
html += "
" * 5
# create menu at the top of the page
html += "
Active Folder Dates
"
html += ""
lastMonth = ""
lastYear = ""
for day in sorted ( list ( foldersByDay . keys ( ) ) ) :
    month = day [ : 7 ]
    year = day [ : 4 ]
    if year != lastYear :
        html += "

%s " % year
        lastYear = year
    if month != lastMonth :
        html += "
%s: " % month
        lastMonth = month
    html += "%s, " % ( day , day [ 8 : ] )
html += "
" * 5
html = html . replace ( ",
" , "
" )
html += ""
# create the full list of folders organized by active date
html += "
Active Folders
"
for day in sorted ( list ( foldersByDay . keys ( ) ) ) :
    dt = datetime . datetime . strptime ( day , "%Y-%m-%d" )
    classPrefix = "weekday"
    if int ( dt . weekday ( ) ) > 4 :
        classPrefix = "weekend"
    html += "" % ( day , day )
    title = "%s (%s)" % ( day , DAYSOFWEEK [ dt . weekday ( ) ] )
    html += "
%s
" % ( classPrefix , title )
    html += "
" % ( classPrefix )
    # define folders to skip
    for folder in foldersByDay [ day ] :
        if "\\References\\" in folder :
            continue
        if "\\MIP\\" in folder :
            continue
        if "LineScan-" and "\\analysis\\" in folder :
            continue
        if "trakem2" in folder :
            continue
        if "SWHlab-" in folder :
            continue
        if "\\swhlab" in folder :
            continue
        html += "%s
" % folder
    html += "
"
fnameSave = resultsFile + ".html"
html = html . replace ( "D:\\X_Drive\\" , "X:\\" )
with open ( fnameSave , 'w' ) as f :
    f . write ( HTML_TEMPLATE . replace ( "" , "" + html ) )
print ( "saved" , fnameSave )


signature:
def quietParts ( data , percentile = 10 ) :
    """Given some data ( Y ) break it into chunks and return just the quiet ones .
 Returns data where the variance for its chunk size is below the given percentile .
 CHUNK _ POINTS should be adjusted so it ' s about 10ms of data ."""

implementation:
nChunks = int ( len ( Y ) / CHUNK_POINTS )
chunks = np . reshape ( Y [ : nChunks * CHUNK_POINTS ] , ( nChunks , CHUNK_POINTS ) )
variances = np . var ( chunks , axis = 1 )
percentiles = np . empty ( len ( variances ) )
for i , variance in enumerate ( variances ) :
    percentiles [ i ] = sorted ( variances ) . index ( variance ) / len ( variances ) * 100
selected = chunks [ np . where ( percentiles <= percentile ) [ 0 ] ] . flatten ( )
return selected


signature:
def ndist ( data , Xs ) :
    """given some data and a list of X posistions , return the normal
 distribution curve as a Y point at each of those Xs ."""

implementation:
sigma = np . sqrt ( np . var ( data ) )
center = np . average ( data )
curve = mlab . normpdf ( Xs , center , sigma )
curve *= len ( data ) * HIST_RESOLUTION
return curve


signature:
def abfinfo ( self , printToo = False , returnDict = False ) :
    """show basic info about ABF class variables ."""

implementation:
info = "\n### ABF INFO ###\n"
d = { }
for thingName in sorted ( dir ( self ) ) :
    if thingName in [ 'cm' , 'evIs' , 'colormap' , 'dataX' , 'dataY' , 'protoX' , 'protoY' ] :
        continue
    if "_" in thingName :
        continue
    thing = getattr ( self , thingName )
    if type ( thing ) is list and len ( thing ) > 5 :
        continue
    thingType = str ( type ( thing ) ) . split ( "'" ) [ 1 ]
    if "method" in thingType or "neo." in thingType :
        continue
    if thingName in [ "header" , "MT" ] :
        continue
    info += "%s <%s> %s\n" % ( thingName , thingType , thing )
    d [ thingName ] = thing
if printToo :
    print ( )
    for line in info . split ( "\n" ) :
        if len ( line ) < 3 :
            continue
        print ( "   " , line )
    print ( )
if returnDict :
    return d
return info


signature:
def headerHTML ( self , fname = None ) :
    """read the ABF header and save it HTML formatted ."""

implementation:
if fname is None :
    fname = self . fname . replace ( ".abf" , "_header.html" )
html = ""
html += "
abfinfo() for %s.abf
" % self . ID
html += self . abfinfo ( ) . replace ( "<" , "<" ) . replace ( ">" , ">" ) . replace ( "\n" , "
" )
html += "
Header for %s.abf
" % self . ID
html += pprint . pformat ( self . header , indent = 1 )
html = html . replace ( "\n" , '
' ) . replace ( " " , " " )
html = html . replace ( r"\x00" , "" )
html += ""
print ( "WRITING HEADER TO:" )
print ( fname )
f = open ( fname , 'w' )
f . write ( html )
f . close ( )


signature:
def generate_colormap ( self , colormap = None , reverse = False ) :
    """use 1 colormap for the whole abf . You can change it ! ."""

implementation:
if colormap is None :
    colormap = pylab . cm . Dark2
self . cm = colormap
self . colormap = [ ]
for i in range ( self . sweeps ) : # TODO : make this the only colormap
    self . colormap . append ( colormap ( i / self . sweeps ) )
if reverse :
    self . colormap . reverse ( )


signature:
def setSweep ( self , sweep = 0 , force = False ) :
    """Load X / Y data for a particular sweep .
 determines if forced reload is needed , updates currentSweep ,
 regenerates dataX ( if not None ) , decimates , returns X / Y .
 Note that setSweep ( ) takes 0.17ms to complete , so go for it !"""

implementation:
if sweep is None or sweep is False :
    sweep = 0
if sweep < 0 :
    sweep = self . sweeps - sweep
    # -1 means last sweep
    if sweep < 0 : # still !
        sweep = 0
        # first sweep
if sweep > ( self . sweeps - 1 ) :
    print ( " !! there aren't %d sweeps. Reverting to last (%d) sweep." % ( sweep , self . sweeps - 1 ) )
    sweep = self . sweeps - 1
sweep = int ( sweep )
try :
    if self . currentSweep == sweep and force == False :
        return
    self . currentSweep = sweep
    self . dataY = self . block . segments [ sweep ] . analogsignals [ self . channel ]
    self . dataY = np . array ( self . dataY )
    B1 , B2 = self . baseline
    if B1 == None :
        B1 = 0
    else :
        B1 = B1 * self . rate
    if B2 == None :
        B2 == self . sweepSize
    else :
        B2 = B2 * self . rate
        self . dataY -= np . average ( self . dataY [ self . baseline [ 0 ] * self . rate : self . baseline [ 1 ] * self . rate ] )
    self . sweep_genXs ( )
    self . sweep_decimate ( )
    self . generate_protocol ( sweep = sweep )
    self . dataStart = self . sweepInterval * self . currentSweep
except Exception :
    print ( "#" * 400 , "\n" , traceback . format_exc ( ) , '\n' , "#" * 400 )
return self . dataX , self . dataY


signature:
def sweep_genXs ( self ) :
    """generate sweepX ( in seconds ) to match sweepY"""

implementation:
if self . decimateMethod :
    self . dataX = np . arange ( len ( self . dataY ) ) / self . rate
    self . dataX *= self . decimateBy
    return
if self . dataX is None or len ( self . dataX ) != len ( self . dataY ) :
    self . dataX = np . arange ( len ( self . dataY ) ) / self . rate


signature:
def sweep_decimate ( self ) :
    """decimate data using one of the following methods :
 ' avg ' , ' max ' , ' min ' , ' fast '
 They ' re self explainatory . ' fast ' just plucks the n ' th data point ."""

implementation:
if len ( self . dataY ) < self . decimateBy :
    return
if self . decimateMethod :
    points = int ( len ( self . dataY ) / self . decimateBy )
    self . dataY = self . dataY [ : points * self . decimateBy ]
    self . dataY = np . reshape ( self . dataY , ( points , self . decimateBy ) )
    if self . decimateMethod == 'avg' :
        self . dataY = np . average ( self . dataY , 1 )
    elif self . decimateMethod == 'max' :
        self . dataY = np . max ( self . dataY , 1 )
    elif self . decimateMethod == 'min' :
        self . dataY = np . min ( self . dataY , 1 )
    elif self . decimateMethod == 'fast' :
        self . dataY = self . dataY [ : , 0 ]
    else :
        print ( "!!! METHOD NOT IMPLIMENTED YET!!!" , self . decimateMethod )
    self . dataX = np . arange ( len ( self . dataY ) ) / self . rate * self . decimateBy


signature:
def get_data_around ( self , timePoints , thisSweep = False , padding = 0.02 , msDeriv = 0 ) :
    """return self . dataY around a time point . All units are seconds .
 if thisSweep = = False , the time point is considered to be experiment time
 and an appropriate sweep may be selected . i . e . , with 10 second
 sweeps and timePint = 35 , will select the 5s mark of the third sweep"""

implementation:
if not np . array ( timePoints ) . shape :
    timePoints = [ float ( timePoints ) ]
data = None
for timePoint in timePoints :
    if thisSweep :
        sweep = self . currentSweep
    else :
        sweep = int ( timePoint / self . sweepInterval )
        timePoint = timePoint - sweep * self . sweepInterval
    self . setSweep ( sweep )
    if msDeriv :
        dx = int ( msDeriv * self . rate / 1000 )
        # points per ms
        newData = ( self . dataY [ dx : ] - self . dataY [ : - dx ] ) * self . rate / 1000 / dx
    else :
        newData = self . dataY
    padPoints = int ( padding * self . rate )
    pad = np . empty ( padPoints ) * np . nan
    Ic = timePoint * self . rate
    # center point ( I )
    newData = np . concatenate ( ( pad , pad , newData , pad , pad ) )
    Ic += padPoints * 2
    newData = newData [ Ic - padPoints : Ic + padPoints ]
    newData = newData [ : int ( padPoints * 2 ) ]
    # TODO : omg so much trouble with this !
    if data is None :
        data = [ newData ]
    else :
        data = np . vstack ( ( data , newData ) )
        # TODO : omg so much trouble with this !
return data


signature:
def generate_protocol ( self , sweep = None ) :
    """Create ( x , y ) points necessary to graph protocol for the current sweep ."""

implementation:
# TODO : make a line protocol that ' s plottable
if sweep is None :
    sweep = self . currentSweep
if sweep is None :
    sweep = 0
if not self . channel in self . header [ 'dictEpochInfoPerDAC' ] . keys ( ) :
    self . protoX = [ 0 , self . sweepSize ]
    self . protoY = [ self . holding , self . holding ]
    self . protoSeqX = self . protoX
    self . protoSeqY = self . protoY
    return
proto = self . header [ 'dictEpochInfoPerDAC' ] [ self . channel ]
self . protoX = [ ]
# plottable Xs
self . protoY = [ ]
# plottable Ys
self . protoX . append ( 0 )
self . protoY . append ( self . holding )
for step in proto :
    dX = proto [ step ] [ 'lEpochInitDuration' ]
    Y = proto [ step ] [ 'fEpochInitLevel' ] + proto [ step ] [ 'fEpochLevelInc' ] * sweep
    self . protoX . append ( self . protoX [ - 1 ] )
    self . protoY . append ( Y )
    # go to new Y
    self . protoX . append ( self . protoX [ - 1 ] + dX )
    # take it to the new X
    self . protoY . append ( Y )
# update the new Y # TODO : fix for ramps
if self . header [ 'listDACInfo' ] [ 0 ] [ 'nInterEpisodeLevel' ] : # nInterEpisodeLevel
    finalVal = self . protoY [ - 1 ]
    # last holding
else :
    finalVal = self . holding
    # regular holding
self . protoX . append ( self . protoX [ - 1 ] )
self . protoY . append ( finalVal )
self . protoX . append ( self . sweepSize )
self . protoY . append ( finalVal )
for i in range ( 1 , len ( self . protoX ) - 1 ) : # correct for weird ABF offset issue .
    self . protoX [ i ] = self . protoX [ i ] + self . offsetX
self . protoSeqY = [ self . protoY [ 0 ] ]
self . protoSeqX = [ self . protoX [ 0 ] ]
for i in range ( 1 , len ( self . protoY ) ) :
    if not self . protoY [ i ] == self . protoY [ i - 1 ] :
        self . protoSeqY . append ( self . protoY [ i ] )
        self . protoSeqX . append ( self . protoX [ i ] )
if self . protoY [ 0 ] != self . protoY [ 1 ] :
    self . protoY . insert ( 1 , self . protoY [ 0 ] )
    self . protoX . insert ( 1 , self . protoX [ 1 ] )
    self . protoY . insert ( 1 , self . protoY [ 0 ] )
    self . protoX . insert ( 1 , self . protoX [ 0 ] + self . offsetX / 2 )
self . protoSeqY . append ( finalVal )
self . protoSeqX . append ( self . sweepSize )
self . protoX = np . array ( self . protoX )
self . protoY = np . array ( self . protoY )


signature:
def clampValues ( self , timePoint = 0 ) :
    """return an array of command values at a time point ( in sec ) .
 Useful for things like generating I / V curves ."""

implementation:
Cs = np . zeros ( self . sweeps )
for i in range ( self . sweeps ) :
    self . setSweep ( i )
    # TODO : protocol only = True
    for j in range ( len ( self . protoSeqX ) ) :
        if self . protoSeqX [ j ] <= timePoint * self . rate :
            Cs [ i ] = self . protoSeqY [ j ]
return Cs


signature:
def guess_protocol ( self ) :
    """This just generates a string to define the nature of the ABF .
 The ultimate goal is to use info about the abf to guess what to do with it .
 [ vc / ic ] - [ steps / fixed ] - [ notag / drugs ] - [ 2ch / 1ch ]
 This represents 2 ^ 4 ( 18 ) combinations , but is easily expanded ."""

implementation:
clamp = "ic"
if self . units == "pA" :
    clamp = "vc"
command = "fixed"
if self . sweeps > 1 :
    self . setSweep ( 0 )
    P0 = str ( self . protoX ) + str ( self . protoY )
    self . setSweep ( 1 )
    P1 = str ( self . protoX ) + str ( self . protoY )
    if not P0 == P1 :
        command = "steps"
tags = "notag"
if len ( self . commentSweeps ) :
    tags = "drugs"
ch = "1ch"
if self . nADC > 1 :
    ch = "2ch"
guess = "-" . join ( [ clamp , command , tags , ch ] )
return guess


signature:
def average_sweep ( self , T1 = 0 , T2 = None , sweeps = None , stdErr = False ) :
    """given an array of sweeps , return X , Y , Err average .
 This returns * SWEEPS * of data , not just 1 data point ."""

implementation:
T1 = T1 * self . rate
if T2 is None :
    T2 = self . sweepSize - 1
else :
    T2 = T2 * self . rate
if sweeps is None :
    sweeps = range ( self . sweeps )
Ys = np . empty ( ( len ( sweeps ) , ( T2 - T1 ) ) )
for i in range ( len ( sweeps ) ) :
    self . setSweep ( sweeps [ i ] )
    Ys [ i ] = self . dataY [ T1 : T2 ]
Av = np . average ( Ys , 0 )
Es = np . std ( Ys , 0 )
Xs = self . dataX [ T1 : T2 ]
if stdErr : # otherwise return stdev
    Es = Es / np . sqrt ( len ( sweeps ) )
return Xs , Av , Es