示例#1
0
def PlotTracesAsGrids(df, index, viewRange, saveDir=None, colorfy=False, dpi=300, 
                      fig_size=None, adjustFigH=True, adjustFigW=True, nullRange=None, 
                      annotation='Simple', setFont='default',gridSpec='Vertical', 
                      scalebarAt='all', fontSize=10, linewidth=1.0, monoStim=False,
                      stimReflectCurrent=True):
    "Export Multiple episodes arranged in a grid; default vertically""" 
    if not colorfy:
        colorfy = ['k']
        
    nchannels = len(viewRange.keys())
    nepisodes = len(index)
    if isinstance(gridSpec, str):
        nrows, ncols = {
        'ver': (nchannels*nepisodes, 1),
        'hor': (1, nchannels*nepisodes),
        'cha': (nchannels, nepisodes),
        'epi': (nepisodes, nchannels)
        }.get(gridSpec[:3].lower(), (None, None))
    
        if nrows is None:
            raise(ValueError('Unrecognized gridSpec: {}'.format(gridSpec)))
    else:
        raise(TypeError('Unrecognized type of argument: "gridSpec"'))
        
    fig, _ = plt.subplots(nrows=nrows, ncols=ncols, sharex=True)
    ax = fig.get_axes()
            
    # text annotation area
    textbox = []
    viewRange_dict = {}
    row, col = 0,0 # keep track of axis used
    first_last_mat = [[],[]]
    for n, i in enumerate(index):
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        
        for c, m in enumerate(viewRange.keys()):
            # Draw plots
            X = zData.Time
            Y = getattr(zData, m[0])[m[1]]
            # null the trace
            if nullRange is not None:
                if isinstance(nullRange, list):
                    Y = Y - np.mean(spk_window(Y, ts, nullRange))
                else: # a single number
                    Y = Y - Y[time2ind(nullRange, ts)]
            # window the plot
            X = spk_window(X, ts, viewRange[m][0])
            Y = spk_window(Y, ts, viewRange[m][0])
            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
            # do the plot
            ind = np.ravel_multi_index((row,col), (nrows, ncols), order='C')
            if n == 0:
                first_last_mat[0].append(ind)
            elif n == len(index)-1:
                first_last_mat[-1].append(ind)
            
            if m[0] in ['Voltage', 'Current'] or not monoStim:
                ax[ind].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth)
            else:
                ax[ind].plot(X, Y, color='k', lw=linewidth)
            # View range
            viewRange_dict[(row,col)] = list(m)+list(viewRange[m])
            # Draw initial value
            InitVal = "{0:0.0f}".format(Y[0])      
            if m[0] == 'Voltage':
                InitVal += 'mV'
            elif m[0] == 'Current':
                InitVal += 'pA'
            elif m[0] == 'Stimulus':
                if stimReflectCurrent:
                    InitVal += 'pA'
                else:
                    InitVal = ''
            
            ax[ind].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]),  Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])

            if m[1] not in channels:
                channels.append(m[1])
            
            # update axis
            row, col = {
                'ver': (row+1, col),
                'hor': (row, col+1),
                'cha': (row+1 if c<nrows-1 else 0, col+1 if c==nrows-1 else col),
                'epi': (row+1 if c==ncols-1 else row, col+1 if c<ncols-1 else 0)
                }.get(gridSpec[:3].lower())
            
        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw more annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))
            
        # Group all the episode annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left",pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []
    
    
    # set axis
    for c, vr in enumerate(viewRange_dict.items()):
        l, r = vr
        ind = np.ravel_multi_index(l, (nrows, ncols), order='C')
        ax[ind].set_xlim(r[2])
        ax[ind].set_ylim(r[3])
        # Add scalebar
        if scalebarAt.lower()=='all' or (scalebarAt.lower()=='first' and ind in first_last_mat[0]) or (scalebarAt.lower()=='last' and ind in first_last_mat[-1]):
            scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if r[0]=='Voltage' else 'pA', ax=ax[ind]))
        else: # including 'none'
            TurnOffAxis(ax=ax[ind])
            
        plt.subplots_adjust(hspace = .001)
        # temp = 510 + c
        temp = tic.MaxNLocator(3)
        ax[ind].yaxis.set_major_locator(temp)
                        
    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                    (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)

    # save the figure
    if adjustFigW:
        fig_size = (fig_size[0]*ncols, fig_size[1])
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nrows)
    fig.set_size_inches(fig_size)
    
    # plt.subplots_adjust(hspace=-0.8)
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi, transparent=True)
    # Close the figure after save
    plt.close(fig)
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))

    return(ax)
示例#2
0
def PlotTracesConcatenated(df, index, viewRange, saveDir, colorfy=False, dpi=300, 
                           fig_size=None, nullRange=None, hSpaceType='Fixed', hFixedSpace=0.10, 
                           adjustFigW=True, adjustFigH=True, trimH=(None,None), 
                           annotation='Simple', setFont='default', fontSize=10, 
                           linewidth=1.0, monoStim=False, stimReflectCurrent=True):
    """Export traces arranged horizontally.
    Good for an experiments acquired over multiple episodes.
    trimH: (t1, t2) trim off the beginning of first episode by t1 seconds, and the
        the end of the last episode by t2 seconds
    """
    nchannels = len(viewRange.keys())
    if not colorfy:
        colorfy=['k']
    fig, _= plt.subplots(nrows=nchannels, ncols=1, sharex=True)
    ax = fig.get_axes()
    # text annotation area
    textbox = []
    nullBase = dict()
    currentTime = 0
    maxWindow = max(df['Duration'])
    for n, i in enumerate(index): #iterate over episodes
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        for c, m in enumerate(viewRange.keys()): # iterate over channels/streams
            # Draw plots
            X = zData.Time + currentTime
            Y = getattr(zData, m[0])[m[1]]
            # null the trace
            if nullRange is not None:
                if n == 0: # calculate nullBase
                    if isinstance(nullRange, list):
                        nullBase[(m[0],m[1])] = np.mean(spk_window(Y, ts, nullRange))
                    else:
                        nullBase[(m[0],m[1])] = Y[time2ind(nullRange, ts)]
                Y = Y - nullBase[(m[0],m[1])]
            if n == 0 and trimH[0] is not None:
                X = spk_window(X, ts, (trimH[0], None))
                Y = spk_window(X, ts, (trimH[0], None))
            elif n + 1 == len(index) and trimH[1] is not None:
                X = spk_window(X, ts, (None, trimH[1]))
                Y = spk_window(X, ts, (None, trimH[1]))
            
            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
            # do the plot
            if m[0] in ['Voltage', 'Current'] or not monoStim: # temporary workaround
                ax[c].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth)
            else:
                ax[c].plot(X, Y, color='k', lw=linewidth)
            # Draw the initial value, only for the first plot
            if n == 0:
                InitVal = "{0:0.0f}".format(Y[0])      
                if m[0] == 'Voltage':
                    InitVal += 'mV'
                elif m[0] == 'Current':
                    InitVal += 'pA'
                elif m[0] == 'Stimulus':
                    if stimReflectCurrent:
                        InitVal += 'pA'
                    else:
                        InitVal = ''
                
                ax[c].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]), Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])
                    
            if m[1] not in channels:
                channels.append(m[1])
            
        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw some annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))
        
        # Set some spacing for the next episode
        if n+1 < len(index):
            if hSpaceType.lower() == 'fixed':
                currentTime = currentTime + (len(Y)-1)*ts + maxWindow * hFixedSpace / 100.0
            elif hSpaceType.lower() in ['real time', 'realtime', 'rt']:
                currentTime = currentTime + (df['Data'][index[n+1]].Protocol.WCtime - zData.Protocol.WCtime)*1000
                    
    # Group all the episodes annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left",pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []
    
    # set axis
    for c, vr in enumerate(viewRange.items()):
        ax[c].set_ylim(vr[1][1])
        # Add scalebar
        scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if vr[0][0]=='Voltage' else 'pA', ax=ax[c]))
        plt.subplots_adjust(hspace = .001)
        temp = tic.MaxNLocator(3)
        ax[c].yaxis.set_major_locator(temp)

    # Set font
    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)
            
    # figure out and set the figure size
    if adjustFigW:
        fig_size = (np.ptp(ax[0].get_xlim()) / maxWindow * fig_size[0], fig_size[1])
    
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nchannels)
        
    fig.set_size_inches(fig_size)
    
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi)
    # Close the figure after save
    plt.close(fig)
    # Convert svg file to eps
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))
    
    return(ax)
示例#3
0
def PlotTraces(df, index, viewRange, saveDir, colorfy=False, dpi=300, fig_size=None, 
               adjustFigH=True, adjustFigW=True, nullRange=None, annotation='Simple', 
               setFont='default', fontSize=10, linewidth=1.0, monoStim=False, stimReflectCurrent=True):
    """Export multiple traces overlapping each other"""    
    # np.savez('R:/tmp.npz', df=df, index=index, viewRange=[viewRange], saveDir=saveDir, colorfy=colorfy)
    # return
    # set_trace()
    # Start the figure
    # viewRange= {(channel, stream):[[xmin,xmax],[ymin),ymax]]}
    nchannels = len(viewRange.keys())
    if not fig_size: # if not specified size, set to (4, 4*nchannels)
        fig_size = (4, 4*nchannels)

    if not colorfy:
        colorfy=['k']
    fig, _= plt.subplots(nrows=nchannels, ncols=1, sharex=True)
    ax = fig.get_axes()
    # text annotation area
    textbox = []
    for n, i in enumerate(index):
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        
        for c, m in enumerate(viewRange.keys()):
            # Draw plots
            X = zData.Time
            Y = getattr(zData, m[0])[m[1]]
            # null the trace, but ignore arithmetic data since their data were already nulled
            if nullRange is not None and zData.Protocol.acquireComment != 'PySynapse Arithmetic Data':
                if isinstance(nullRange, list):
                    Y = Y - np.mean(spk_window(Y, ts, nullRange))
                else: # a single number
                    Y = Y - Y[time2ind(nullRange, ts)]
                    
            # window the plot
            X = spk_window(X, ts, viewRange[m][0])
            Y = spk_window(Y, ts, viewRange[m][0])
            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
                
            # do the plot
            if m[0] in ['Voltage', 'Current'] or not monoStim:
                ax[c].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth)
            else:
                ax[c].plot(X, Y, color='k', lw=linewidth)
            # Draw initial value
            InitVal = "{0:0.0f}".format(Y[0])      
            if m[0] == 'Voltage':
                InitVal += 'mV'
            elif m[0] == 'Current':
                InitVal += 'pA'
            elif m[0] == 'Stimulus':
                if stimReflectCurrent:
                    InitVal += 'pA'
                else:
                    InitVal = ''
                
            if m[1] not in channels:
                channels.append(m[1])
            
            #kkks = viewRange[m][0][1]-viewRange[m][0][0]
            #set_trace()
            ax[c].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]),  Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])
        
        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw more annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))
    
    # Group all the episode annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left",pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []

    # set axis
    for c, vr in enumerate(viewRange.items()):
        l, r = vr
        ax[c].set_xlim(r[0])
        ax[c].set_ylim(r[1])
        # Add scalebar
        scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if l[0]=='Voltage' else 'pA', ax=ax[c]))
        plt.subplots_adjust(hspace = .001)
        # temp = 510 + c
        temp = tic.MaxNLocator(3)
        ax[c].yaxis.set_major_locator(temp)

    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                    (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)

    # save the figure
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nchannels)
    
    fig.set_size_inches(fig_size)

    # plt.subplots_adjust(hspace=-0.8)
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi, transparent=True)
    # Close the figure after save
    plt.close(fig)
    # Convert from svg to eps
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))
        
        
    return(ax)
示例#4
0
def PlotTracesAsGrids(df, index, viewRange, saveDir=None, colorfy=False, artists=None, dpi=300,
                      fig_size=None, adjustFigH=True, adjustFigW=True, nullRange=None, 
                      annotation='Simple', setFont='default',gridSpec='Vertical', 
                      scalebarAt='all', fontSize=10, linewidth=1.0, monoStim=False,
                      stimReflectCurrent=True):
    "Export Multiple episodes arranged in a grid; default vertically""" 
    if not colorfy:
        colorfy = ['k']
        
    nchannels = len(viewRange.keys())
    nepisodes = len(index)
    if isinstance(gridSpec, str):
        nrows, ncols = {
        'ver': (nchannels*nepisodes, 1),
        'hor': (1, nchannels*nepisodes),
        'cha': (nchannels, nepisodes),
        'epi': (nepisodes, nchannels)
        }.get(gridSpec[:3].lower(), (None, None))
    
        if nrows is None:
            raise(ValueError('Unrecognized gridSpec: {}'.format(gridSpec)))
    else:
        raise(TypeError('Unrecognized type of argument: "gridSpec"'))
        
    fig, _ = plt.subplots(nrows=nrows, ncols=ncols, sharex=True)
    ax = fig.get_axes()
            
    # text annotation area
    textbox = []
    viewRange_dict = {}
    row, col = 0,0 # keep track of axis used
    first_last_mat = [[],[]]
    for n, i in enumerate(index):
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        
        for c, m in enumerate(viewRange.keys()):
            # Draw plots
            X = zData.Time
            Y = getattr(zData, m[0])[m[1]]
            # null the trace
            if nullRange is not None:
                if isinstance(nullRange, list):
                    Y = Y - np.mean(spk_window(Y, ts, nullRange))
                else: # a single number
                    Y = Y - Y[time2ind(nullRange, ts)]
            # window the plot
            X = spk_window(X, ts, viewRange[m][0])
            Y = spk_window(Y, ts, viewRange[m][0])
            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
            # do the plot
            ind = np.ravel_multi_index((row,col), (nrows, ncols), order='C')
            if n == 0:
                first_last_mat[0].append(ind)
            elif n == len(index)-1:
                first_last_mat[-1].append(ind)
            
            if m[0] in ['Voltage', 'Current'] or not monoStim:
                ax[ind].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            else:
                ax[ind].plot(X, Y, color='k', lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            # View range
            viewRange_dict[(row,col)] = list(m)+list(viewRange[m])
            # Draw initial value
            InitVal = "{0:0.0f}".format(Y[0])      
            if m[0] == 'Voltage':
                InitVal += 'mV'
            elif m[0] == 'Current':
                InitVal += 'pA'
            elif m[0] == 'Stimulus':
                if stimReflectCurrent:
                    InitVal += 'pA'
                else:
                    InitVal = ''
            
            ax[ind].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]),  Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])

            if m[1] not in channels:
                channels.append(m[1])
            
            # update axis
            row, col = {
                'ver': (row+1, col),
                'hor': (row, col+1),
                'cha': (row+1 if c<nrows-1 else 0, col+1 if c==nrows-1 else col),
                'epi': (row+1 if c==ncols-1 else row, col+1 if c<ncols-1 else 0)
                }.get(gridSpec[:3].lower())
            
        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw more annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))
            
        # Group all the episode annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left",pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []
    
    
    # set axis
    for c, vr in enumerate(viewRange_dict.items()):
        l, r = vr
        ind = np.ravel_multi_index(l, (nrows, ncols), order='C')
        ax[ind].set_xlim(r[2])
        ax[ind].set_ylim(r[3])
        # Add scalebar
        if scalebarAt.lower()=='all' or (scalebarAt.lower()=='first' and ind in first_last_mat[0]) or (scalebarAt.lower()=='last' and ind in first_last_mat[-1]):
            scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if r[0]=='Voltage' else 'pA', ax=ax[ind]))
        else: # including 'none'
            TurnOffAxis(ax=ax[ind])
            
        plt.subplots_adjust(hspace = .001)
        # temp = 510 + c
        temp = tic.MaxNLocator(3)
        ax[ind].yaxis.set_major_locator(temp)

        # Draw annotation artist for each export
        DrawAnnotationArtists(artists, axs=[ax[ind]])
                        
    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                    (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)

    # save the figure
    if adjustFigW:
        fig_size = (fig_size[0]*ncols, fig_size[1])
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nrows)
    fig.set_size_inches(fig_size)
    
    # plt.subplots_adjust(hspace=-0.8)
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi, transparent=True)
    # Close the figure after save
    plt.close(fig)
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))

    return(ax)
示例#5
0
def PlotTracesConcatenated(df, index, viewRange, saveDir, colorfy=False, artists=None, dpi=300,
                           fig_size=None, nullRange=None, hSpaceType='Fixed', hFixedSpace=0.10,
                           adjustFigW=True, adjustFigH=True, trimH=(None,None),
                           annotation='Simple', setFont='default', fontSize=10,
                           linewidth=1.0, monoStim=False, stimReflectCurrent=True):
    """Export traces arranged horizontally.
    Good for an experiments acquired over multiple episodes.
    trimH: (t1, t2) trim off the beginning of first episode by t1 seconds, and the
        the end of the last episode by t2 seconds
    """
    nchannels = len(viewRange.keys())
    if not colorfy:
        colorfy=['k']
    fig, _= plt.subplots(nrows=nchannels, ncols=1, sharex=True)
    ax = fig.get_axes()
    # text annotation area
    textbox = []
    nullBase = dict()
    currentTime = 0
    maxWindow = max(df['Duration'])
    for n, i in enumerate(index): #iterate over episodes
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        for c, m in enumerate(viewRange.keys()): # iterate over channels/streams
            # Draw plots
            X = zData.Time + currentTime
            Y = getattr(zData, m[0])[m[1]]
            # null the trace
            if nullRange is not None:
                if n == 0: # calculate nullBase
                    if isinstance(nullRange, list):
                        nullBase[(m[0],m[1])] = np.mean(spk_window(Y, ts, nullRange))
                    else:
                        nullBase[(m[0],m[1])] = Y[time2ind(nullRange, ts)]
                Y = Y - nullBase[(m[0],m[1])]
            if n == 0 and trimH[0] is not None:
                X = spk_window(X, ts, (trimH[0], None))
                Y = spk_window(X, ts, (trimH[0], None))
            elif n + 1 == len(index) and trimH[1] is not None:
                X = spk_window(X, ts, (None, trimH[1]))
                Y = spk_window(X, ts, (None, trimH[1]))

            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
            # do the plot
            if m[0] in ['Voltage', 'Current'] or not monoStim: # temporary workaround
                ax[c].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            else:
                ax[c].plot(X, Y, color='k', lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            # Draw the initial value, only for the first plot
            if n == 0:
                InitVal = "{0:0.0f}".format(Y[0])
                if m[0] == 'Voltage':
                    InitVal += 'mV'
                elif m[0] == 'Current':
                    InitVal += 'pA'
                elif m[0] == 'Stimulus':
                    if stimReflectCurrent:
                        InitVal += 'pA'
                    else:
                        InitVal = ''

                ax[c].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]), Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])

            if m[1] not in channels:
                channels.append(m[1])

        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw some annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))

        # Set some spacing for the next episode
        if n+1 < len(index):
            if hSpaceType.lower() == 'fixed':
                currentTime = currentTime + (len(Y)-1)*ts + maxWindow * hFixedSpace / 100.0
            elif hSpaceType.lower() in ['real time', 'realtime', 'rt']:
                currentTime = currentTime + (df['Data'][index[n+1]].Protocol.WCtime - zData.Protocol.WCtime)*1000

    # Group all the episodes annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left",pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []
    
    # set axis
    for c, vr in enumerate(viewRange.items()):
        ax[c].set_ylim(vr[1][1])
        # Add scalebar
        scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if vr[0][0]=='Voltage' else 'pA', ax=ax[c]))
        plt.subplots_adjust(hspace = .001)
        temp = tic.MaxNLocator(3)
        ax[c].yaxis.set_major_locator(temp)

    # Set font
    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)
            
    # figure out and set the figure size
    if adjustFigW:
        fig_size = (np.ptp(ax[0].get_xlim()) / maxWindow * fig_size[0], fig_size[1])
    
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nchannels)
        
    fig.set_size_inches(fig_size)
    
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi)
    # Close the figure after save
    plt.close(fig)
    # Convert svg file to eps
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))
    
    return(ax)
示例#6
0
def PlotTraces(df, index, viewRange, saveDir, colorfy=False, artists=None, dpi=300, fig_size=None,
               adjustFigH=True, adjustFigW=True, nullRange=None, annotation='Simple', 
               setFont='default', fontSize=10, linewidth=1.0, monoStim=False, stimReflectCurrent=True):
    """Export multiple traces overlapping each other"""    
    # np.savez('R:/tmp.npz', df=df, index=index, viewRange=[viewRange], saveDir=saveDir, colorfy=colorfy)
    # return
    # set_trace()
    # Start the figure
    # viewRange= {(channel, stream):[[xmin,xmax],[ymin),ymax]]}
    nchannels = len(viewRange.keys())
    if not fig_size: # if not specified size, set to (4, 4*nchannels)
        fig_size = (4, 4*nchannels)

    if not colorfy:
        colorfy=['k']
    fig, _ = plt.subplots(nrows=nchannels, ncols=1, sharex=True)
    ax = fig.get_axes()
    # text annotation area
    textbox = []
    for n, i in enumerate(index):
        zData = df['Data'][i]
        ts = zData.Protocol.msPerPoint
        channels = []
        
        for c, m in enumerate(viewRange.keys()):
            # Draw plots
            X = zData.Time
            Y = getattr(zData, m[0])[m[1]]
            # null the trace, but ignore arithmetic data since their data were already nulled
            if nullRange is not None and zData.Protocol.acquireComment != 'PySynapse Arithmetic Data':
                if isinstance(nullRange, list):
                    Y = Y - np.mean(spk_window(Y, ts, nullRange))
                else: # a single number
                    Y = Y - Y[time2ind(nullRange, ts)]
                    
            # window the plot
            X = spk_window(X, ts, viewRange[m][0])
            Y = spk_window(Y, ts, viewRange[m][0])
            # Stim channel reflects current channel
            if stimReflectCurrent and m[0]=='Stimulus':
                CurBase = spk_window(zData.Current[m[1]], ts, viewRange[m][0]) # use view range of stimulus on current
                CurBase = np.mean(spk_window(CurBase, ts, [0,50]))
                Y = Y + CurBase
                
            # do the plot
            if m[0] in ['Voltage', 'Current'] or not monoStim:
                ax[c].plot(X, Y, color=colorfy[n%len(colorfy)], lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            else:
                ax[c].plot(X, Y, color='k', lw=linewidth, solid_joinstyle='bevel', solid_capstyle='butt')
            # Draw initial value
            InitVal = "{0:0.0f}".format(Y[0])      
            if m[0] == 'Voltage':
                InitVal += 'mV'
            elif m[0] == 'Current':
                InitVal += 'pA'
            elif m[0] == 'Stimulus':
                if stimReflectCurrent:
                    InitVal += 'pA'
                else:
                    InitVal = ''
                
            if m[1] not in channels:
                channels.append(m[1])
            
            #kkks = viewRange[m][0][1]-viewRange[m][0][0]
            #set_trace()
            ax[c].text(X[0]-0.03*(viewRange[m][0][1]-viewRange[m][0][0]),  Y[0]-1, InitVal, ha='right', va='center', color=colorfy[n%len(colorfy)])
        
        if annotation.lower() != 'none':
            final_notes = writeEpisodeNote(zData, viewRange[m][0], channels=channels, mode=annotation)
            # Draw more annotations
            textbox.append(TextArea(final_notes, minimumdescent=False, textprops=dict(color=colorfy[n%len(colorfy)])))
    
    # Group all the episode annotation text
    if annotation.lower() != 'none':
        box = VPacker(children=textbox, align="left", pad=0, sep=2)
        annotationbox = AnchoredOffsetbox(loc=3, child=box, frameon=False, bbox_to_anchor=[1, 1.1])
        ax[-1].add_artist(annotationbox)
        scalebar = [annotationbox]
    else:
        scalebar = []

    # Draw annotation artists
    DrawAnnotationArtists(artists, axs=ax)

    # set axis
    for c, vr in enumerate(viewRange.items()):
        l, r = vr
        ax[c].set_xlim(r[0])
        ax[c].set_ylim(r[1])
        # Add scalebar
        scalebar.append(AddTraceScaleBar(xunit='ms', yunit='mV' if l[0]=='Voltage' else 'pA', ax=ax[c]))
        plt.subplots_adjust(hspace=.001)
        # temp = 510 + c
        temp = tic.MaxNLocator(3)
        ax[c].yaxis.set_major_locator(temp)

    if (isinstance(setFont, str) and setFont.lower() in ['default', 'arial', 'helvetica']) or \
                    (isinstance(setFont, bool) and setFont):
        SetFont(ax, fig, fontsize=fontSize, fontname=os.path.join(__location__,'../resources/Helvetica.ttf'))
    else:
        SetFont(ax, fig, fontsize=fontSize, fontname=setFont)

    # save the figure
    if adjustFigH:
        fig_size = (fig_size[0], fig_size[1]*nchannels)

    fig.set_size_inches(fig_size)

    # plt.subplots_adjust(hspace=-0.8)
    fig.savefig(saveDir, bbox_inches='tight', bbox_extra_artists=tuple(scalebar), dpi=dpi, transparent=True)
    # Close the figure after save
    plt.close(fig)
    # Convert from svg to eps
    if '.svg' in saveDir:
        svg2eps_ai(source_file=saveDir, target_file=saveDir.replace('.svg', '.eps'))


    return(ax)