def _demo_01_offests(): """ Demonstrate how to use sweepDataRange to estimate excellent offsets for pretty graphing of ABFs with wildly different scales. """ for fname in sorted(glob.glob(PATH_DATA+"/*.abf"))[5:8]: abf = pyabf.ABF(fname) sweeps(abf, offsetXsec=abf.sweepLengthSec/20, offsetYunits=sweepDataRange(abf, .05)) scalebar(abf) plt.show()
def _demo_epoch_table(): """Demonstrate the text epoch table feature.""" import matplotlib.pyplot as plt abfFiles = glob.glob(PATH_DATA + "/18702001-*.abf") for fname in abfFiles: abf = pyabf.ABF(fname) print("\n\n", "#" * 20, abf.abfID, "(CH 1)", "#" * 20) # show the epoch table as a big text block epochTable = EpochTable(abf, 1) print(epochTable)
def demo_15_epochs(self): """ ## Accessing Epoch Information In some ABFs an epoch table is used to control the command level of the DAC to control voltage or current. While the epoch table can be confusing to access directly from the header (e.g., the first epoch does not start at time 0, but rather 1/64 of the sweep length), a simplified way to access epoch types and levels is provided with the `abf.sweepEpochs` object, which contains epoch points, levels, and types for the currently-loaded sweep. For example, the output of this script: ```python import pyabf abf = pyabf.ABF("2018_08_23_0009.abf") for i, p1 in enumerate(abf.sweepEpochs.p1s): epochLevel = abf.sweepEpochs.levels[i] epochType = abf.sweepEpochs.types[i] print(f"epoch index {i}: at point {p1} there is a {epochType} to level {epochLevel}") ``` looks like this: ``` epoch index 0: at point 0 there is a Step to level -70.0 epoch index 1: at point 187 there is a Step to level -80.0 epoch index 2: at point 4187 there is a Step to level -70.0 epoch index 3: at point 8187 there is a Ramp to level -80.0 epoch index 4: at point 9187 there is a Ramp to level -70.0 epoch index 5: at point 10187 there is a Step to level -70.0 ``` """ import pyabf abf = pyabf.ABF("data/abfs/2018_08_23_0009.abf") fig = plt.figure(figsize=self.figsize) ax1 = fig.add_subplot(211) ax1.plot(abf.sweepY, color='b') ax1.set_ylabel("ADC (measurement)") ax1.set_xlabel("sweep point (index)") ax2 = fig.add_subplot(212) ax2.plot(abf.sweepC, color='r') ax2.set_ylabel("DAC (command)") ax2.set_xlabel("sweep point (index)") for p1 in abf.sweepEpochs.p1s: ax1.axvline(p1, color='k', ls='--', alpha=.5) ax2.axvline(p1, color='k', ls='--', alpha=.5) plt.tight_layout() self.saveAndClose()
def test_findStimulusFile_NansIfNotFound(): """When the stimulus file isn't found the waveform should be all NANs.""" warnings.simplefilter("ignore") abf = pyabf.ABF(ABF_PATH) stimulus = abf.stimulusByChannel[0] waveform = stimulus.stimulusWaveform(stimulusSweep=0) assert isinstance(waveform, np.ndarray) assert len(waveform) == len(abf.sweepY) assert np.isnan(waveform).all()
def _demo_sweepC(): """Demonstrate how to generate the sweepC waveform.""" import matplotlib.pyplot as plt for fname in glob.glob(PATH_DATA + "/18702001-*.abf"): abf = pyabf.ABF(fname) print("\n%s (CH 1)" % abf.abfID) epochTable = EpochTable(abf, 1) for sweep in abf.sweepList: sweepWaveform = epochTable.epochWaveformsBySweep[sweep] sweepC = sweepWaveform.getWaveform() print("SweepC", sweep, "=", sweepC)
def getElectroPara(file): name = getCellID(file) abf = pyabf.ABF(file) rmp = abf.sweepY[abf.sweepEpochs.p1s[0]:abf.sweepEpochs.p2s[0]].mean() ivFile = AbfMatchIVfile(file) if ivFile: ivData = getOneIVdata(ivFile) RmRes = computeRm(ivData) return ({'ID': name, 'RMP': rmp, 'Rm': RmRes['Rm']}) else: return None
def getListOfProtocol(protocol="0111", folderPath="X:/Data/SD/OXT-Subiculum/abfs"): matchingPaths = [] for path in glob.glob(folderPath + "/*.abf"): abf = pyabf.ABF(path, loadData=False) if (abf.adcUnits[0] != "mV"): print("bad units: " + path) continue if abf.protocol.startswith("0111"): matchingPaths.append(path) return matchingPaths
def getIdealABFs(): print("scanning ABFs...") idealAbfs = [] for abfFilePath in glob.glob(PATH_DATA+"/*.abf"): abf = pyabf.ABF(abfFilePath) if (abf.sweepUnitsY == "pA" and abf.sweepLengthSec <= 60 and abf.dataRate <= 20000): idealAbfs.append(abf) print(f"Found {len(idealAbfs)} ideal ABFs to analyze") return idealAbfs
def getDataLine(abfFilePath): dataLine = "" try: abf = pyabf.ABF(abfFilePath, loadData=False) comments = " | ".join(abf.tagComments) abfPath = abfBrowse.getXdrivePath(abfFilePath) dataLine = f"ABF: {abfPath}, {abf.protocol}, {comments}" dataLine += "\n" except Exception as ex: print(f"### EXCEPTION: {ex}") return dataLine
def calc_refract_mean(list_of_files, sweep, channel=0): if not list_of_files: print(f"[calc_refract_mean] list_of_files is None, exiting") assert (len(list_of_files) == 5 ), f"should be 5 files, but there are {len(list_of_files)}" b = [] for f in list_of_files: abf = pyabf.ABF(f) abf.setSweep(sweep, channel=channel) b.append(abf.sweepY) b = np.asarray(b) return abf.sweepX, b.mean(axis=0)
def plot_stim_aligned(f_list, stim_chan, xii_chan, dia_chan, pre=0.1, post=0.5): xii_slice = [] dia_slice = [] for f in f_list: dat = pyabf.ABF(f) sr = dat.dataRate pre_samp = int(pre * sr) post_samp = int(post * sr) tvec = np.arange(-pre, post, 1 / sr) * 1000 stim_id = abf.get_channel_id_by_label(dat, stim_chan) xii_id = abf.get_channel_id_by_label(dat, xii_chan) dia_id = abf.get_channel_id_by_label(dat, dia_chan) for ii in range(dat.sweepCount): dat.setSweep(ii, stim_id) stim_on, stim_off = rlab_signal.binary_onsets(dat.sweepY, 1) stim_on = stim_on[0] stim_off = stim_off[0] dat.setSweep(ii, xii_id) xii_data = dat.sweepY xii_slice.append(xii_data[stim_on - pre_samp:stim_on + post_samp]) dat.setSweep(ii, dia_id) dia_data = dat.sweepY dia_data = rlab_signal.remove_EKG(dia_data, sr) dia_data = rlab_signal.integrator(dia_data, sr, 0.05, acausal=False) dia_slice.append(dia_data[stim_on - pre_samp:stim_on + post_samp]) xii_slice = np.array(xii_slice).T dia_slice = np.array(dia_slice).T f, ax = plt.subplots(nrows=2, sharex=True, figsize=(3, 2)) ax[0].plot(tvec, xii_slice, 'k', alpha=0.2, lw=1) ax[0].axvspan(0, (stim_off - stim_on) / sr * 1000, color='c', alpha=0.3) ax[1].plot(tvec, dia_slice, 'k', alpha=0.2, lw=1) ax[1].axvspan(0, (stim_off - stim_on) / sr * 1000, color='c', alpha=0.3) ax[1].set_xlabel('Time (ms)') ax[0].set_ylabel('XII') ax[1].set_ylabel('Dia') sns.despine() plt.tight_layout()
def _demo_create_graphs(): """Plot sweepC of ABFs containing waveforms of all types.""" import matplotlib.pyplot as plt for fname in glob.glob(PATH_DATA + "/18702001-*.abf"): abf = pyabf.ABF(fname) plt.figure() eptbl = EpochTable(abf, 1) for epwv in eptbl.epochWaveformsBySweep: sweepC = epwv.getWaveform() plt.plot(sweepC) plt.title(abf.abfID) plt.show()
def stimulusWaveformFromFile(abf, channel=0): """ Attempt to find the stimulus file used to record an ABF, read the stimulus file (ABF or ATF), and return the stimulus waveform (as a numpy array). """ assert isinstance(abf, pyabf.ABF) assert channel in abf.channelList # prepare potential file paths where the stimulus file may exist stimFname = abf._stringsIndexed.lDACFilePath[channel] stimBN = os.path.basename(stimFname) abfFolder = os.path.dirname(abf.abfFilePath) pathSameFolder = os.path.join(abfFolder, stimBN) pathAlt = os.path.join(str(abf.stimulusFileFolder), stimBN) # try to find the stimulus file if os.path.exists(stimFname): stimFname = os.path.abspath(stimFname) elif os.path.exists(pathSameFolder): stimFname = pathSameFolder elif pathAlt and os.path.exists(pathAlt): stimFname = pathAlt else: return np.full(abf.sweepPointCount, np.nan) # the stimulus waveform file was found, consider caching if abf._cacheStimulusFiles: stimFname = os.path.realpath(stimFname) if not stimFname in cachedStimuli.keys(): if stimFname.upper().endswith(".ABF"): cachedStimuli[stimFname] = pyabf.ABF(stimFname) elif stimFname.upper().endswith(".ATF"): cachedStimuli[stimFname] = pyabf.ATF(stimFname) return cachedStimuli[stimFname].sweepY else: if stimFname.upper().endswith(".ABF"): return pyabf.ABF(stimFname) elif stimFname.upper().endswith(".ATF"): return pyabf.ATF(stimFname)
def test_cookbook_createHeaderImages(abfPath): warnings.simplefilter("ignore") abf = pyabf.ABF(abfPath) assert isinstance(abf, pyabf.ABF) if platform.architecture()[0] == "32bit": raise Exception("ABF plotting with matplotlib requires 64-bit") # create figure and subplots fig = plt.figure(figsize=(8, 6)) fig.patch.set_alpha(0) # transparent background ax1 = fig.add_subplot(211) ax2 = fig.add_subplot(212) ax1.grid(alpha=.4, ls='--') ax2.grid(alpha=.4, ls='--') ax1.patch.set_facecolor('w') ax2.patch.set_facecolor('w') ax1.set_xmargin(0) ax2.set_xmargin(0) # overlap or continuous view depends on protocol absoluteTime = False if "0111" in abf.protocol: absoluteTime = True if "loose" in abf.protocol: absoluteTime = True # usually we plot channel 0, but sometimes manually override channel = 0 if "18702001" in abf.abfID: channel = 1 # plot the data sweep by sweep maxSweepsToPlot = min(abf.sweepCount, 20) for sweep in range(maxSweepsToPlot): abf.setSweep(sweep, channel=channel, absoluteTime=absoluteTime) ax1.plot(abf.sweepX, abf.sweepY, alpha=.5, color='b', lw=.5) ax2.plot(abf.sweepX, abf.sweepC, color='r') # decorate plot and save it ax1.set_title( f"{abf.abfID}.abf [channel: {abf.sweepChannel+1}/{abf.channelCount}] [sweeps: {abf.sweepNumber+1}]" ) ax1.set_ylabel(abf.sweepLabelY) ax1.set_xlabel(abf.sweepLabelX) ax2.set_ylabel(abf.sweepLabelC) ax2.set_xlabel(abf.sweepLabelX) fig.tight_layout() ax1.margins(0, .1) ax2.margins(0, .1) fig.savefig(f"{PATH_HEADERS}/{abf.abfID}.png") plt.close()
def pageParentChildAbfList(abfFolder, parentNote): assert isinstance(abfFolder, abfBrowse.AbfFolder) assert isinstance(parentNote, abfBrowse.cellsFile.CellNote) abfs = abfFolder.abfList.family[parentNote.abfID] abfFileNames = [x+".abf" for x in abfs] abfPaths = [os.path.join(abfFolder.path, x) for x in abfFileNames] html = "" html += "<div style='background-color: #EEE; padding: .5em;'>" for i, abfFileName in enumerate(abfFileNames): # don't list ABFs currently being recorded rsvFilePath = os.path.splitext(abfPaths[i])[0]+".rsv" if os.path.exists(rsvFilePath): continue # use pyABF to extract useful ABF information abf = pyabf.ABF(abfPaths[i], loadData=False) clampType = "VC" if abf.adcUnits[0] == "pA" else "IC" sweepCount = len(abf.sweepList) duration = f"{round(abf.dataLengthMin, 2)} min" if abf.dataLengthMin > 1 else f"{round(abf.dataLengthSec, 2)} sec" comments = [] for tagComment, tagTimeMin in zip(abf.tagComments, abf.tagTimesMin): comments.append("\"%s\" at %s min" % (tagComment, round(tagTimeMin, 2))) commentsLine = ", ".join(comments) # determine abf type by its protocol isMemTest = ("memtest" in abf.protocol.lower() or "membrane" in abf.protocol.lower()) # create the HTML row for this ABF html += f"<div class='abfInfoRow'>{abfFileName} " xDrivePath = abfBrowse.getXdrivePath(abfPaths[i]) html += abfBrowse.htmlTools.copyButton("copy path", xDrivePath) setpathCommand = "setpath \"%s\"; " % (xDrivePath) html += abfBrowse.htmlTools.copyButton("setpath", setpathCommand) html += abfBrowse.htmlTools.ignoreButton(abfPaths[i]) html += f"{abf.protocol}, {clampType} with {sweepCount} sweeps ({abf.sweepLengthSec} sec each, {duration} total)" # display messages at the end of the line if (len(comments)): html += f", <span class='abfInfoComment'>Comments: {commentsLine}</span>" if i == 0 and not isMemTest: html += f" <span class='abfInfoWarning'>WARNING: the parent ABF should be a memtest!</span>" if (abf.adcUnits[0] == abf.dacUnits[0]): html += f" <span class='abfInfoWarning'>WARNING: unit error!</span>" html += "</div>" html += "</div>" return html
def test_stimulus_cache(useCache=True): """Load ABFs which use an external ABF and ATF stimulus files""" abfFiles = sorted(glob.glob(testDirectory + "/cool_*.abf")) for i, filename in enumerate(abfFiles): #abf = pyabf.ABF(filename, cacheStimulusFiles=False) abf = pyabf.ABF(filename) abf.stimulusFileFolder = PATH_DATA # alternate path for stimulus files t1 = time.perf_counter() sweepC = abf.sweepC # stimulus file is only read if this is accessed t2 = time.perf_counter() stimFile = os.path.basename(abf._stringsIndexed.lDACFilePath[0]) timeMs = (t2 - t1) * 1000.0 print('"%s" loaded in %.02f ms' % (stimFile, timeMs), sweepC)
def demo_02a_plot_matplotlib_sweep(self): """ ## Plot Sweep Data Plot a sweep of ABF data using matplotlib. """ import pyabf abf = pyabf.ABF("data/abfs/17o05028_ic_steps.abf") abf.setSweep(14) plt.figure(figsize=self.figsize) plt.plot(abf.sweepX, abf.sweepY, lw=.5) self.saveAndClose()
def addFakeParentImages(abfFolder, parentProtocols=['0201 memtest', '1 MTIV3']): tifSourcePath = R"X:\Users_Public\Scott\x.tif" for abfPath in glob.glob(abfFolder + "/*.abf"): abf = pyabf.ABF(abfPath, loadData=False) for protocol in parentProtocols: if protocol in abf.protocol: abfFileName = os.path.basename(abfPath) tifFileName = os.path.basename(abfPath.replace(".abf", ".tif")) tifFilePath = os.path.join(abfFolder, tifFileName) if not os.path.exists(tifFilePath): print("CREATING:", tifFilePath) shutil.copy(tifSourcePath, tifFilePath)
def __init__(self, sweep_info=None, abf_file=None, ontology=None, api_sweeps=True, validate_stim=True): super(ABFDataSet, self).__init__(ontology, validate_stim) self._abf_data = pyabf.ABF(abf_file) if sweep_info is None: sweep_info = self.extract_sweep_stim_info() self.build_sweep_table(sweep_info)
def load_abf(fpath=fpath): print('Loading %s' % fpath) a = pyabf.ABF(fpath) fs = a.dataRate # sampling frequency V = a.data t = np.arange(0, len(V[0])) * (1.0 / fs) # length of the data, converted to seconds by dividing by the sampling frequency print('ABF File Comment: ', a.abfFileComment) print('Sampling rate: ', fs) print('length of recording (seconds): ', t[-1]) print('number of datapoints: ', len(V[0])) return a, fs, t, V
def process_files( files ): global args_ if args_.dir: resdir = os.path.join(args_.dir, '_CSV') if not os.path.isdir(resdir): os.makedirs(resdir) else: resdir = os.path.dirname(args_.input) for f in files: abf = pyabf.ABF( f ) df = extractData(abf) saveData(df, os.path.join(resdir , '%s.csv' % relative_path(f, args_.dir)))
def go(): print("Testing core API", end=" ") abf1 = pyabf.ABF(PATH_DATA+"/05210017_vc_abf1.abf") abf2 = pyabf.ABF(PATH_DATA+"/18702001-ramp.abf") log.debug("Testing generic calls which work on any ABF") for functionName in sorted(globals()): if not functionName.startswith("test_"): continue log.debug(f"Running {functionName}() on {abf1.abfID} (ABF1)") globals()[functionName](abf1) log.debug(f"Running {functionName}() on {abf2.abfID} (ABF2)") globals()[functionName](abf2) log.debug("Testing calls work best on specific ABFs") specialTest_comments(PATH_DATA+"/16d05007_vc_tags.abf",commentCount=2) specialTest_comments(PATH_DATA+"/abf1_with_tags.abf",commentCount=1) generateMarkdown() print(" OK")
def __init__(self, file_path: str, sampling_rate: int = None, trace_threshold: float = 0, rate_threshold: float = 5): self.file_path = file_path self.sampling_rate = sampling_rate self.trace_threshold = trace_threshold self.rate_threshold = rate_threshold # Read abf file self.abf = pyabf.ABF(file_path) self.sweep_list = self.abf.sweepList self.sweep_count = len(self.sweep_list)
def good_path_and_map(): path = str(pathlib.Path("data", "abfs", "20104002.abf").resolve()) abf = pyabf.ABF(path) abf.setSweep(sweepNumber=1, channel=0) good = { "path": path, "sweep": 1, "channel": 0, "x": abf.sweepX, "y": abf.sweepY, "short_name": "20104002", "error": [], } return path, good
def get_current_step(self, file_id=0, file=""): """Returns the current step of the n-th abf file.""" if not (file): file = self.files["abf"][file_id] check = self.check_abf_valid(file_id) else: check = self.check_abf_valid(file=file) apDemoAbf = pyabf.ABF(file) cur_step = [] if check: for sweep in apDemoAbf.sweepList: apDemoAbf.setSweep(sweep) cur_step.append(apDemoAbf.sweepEpochs.levels[2]) return cur_step
def autoAnalyzeAbf(abf, reanalyze=True): """ Given an abf filename (or ABF object), produce an analysis graph of its data. If the protocol has a known analysis routine, run it. If not, run the unknown() analysis routine. In all cases, an input ABF should produce at least some type of output graph. """ # error checking if isinstance(abf, str): abf = pyabf.ABF(abf, False) assert isinstance(abf, pyabf.ABF) log.debug(f"Auto-analyzing {abf.abfID}.abf") # determine if old files exist matchingFiles = abfnav.dataFilesForAbf(abf.abfFilePath) if reanalyze is False: if len(matchingFiles): log.debug(f"skipping {abf.abfID} (data files exist)") return else: for fname in matchingFiles: if ".tif" in fname.lower(): continue log.debug(f"deleting {fname}") os.remove(fname) # if the protocol is in the autoanalysis format determine its function functionName = None if " " in abf.protocol and len(abf.protocol.split(" ")[0]) == 4: functionName = "protocol_"+abf.protocol.split(" ")[0] if not functionName in dir(analysisByProtocol): functionName = None if functionName and not hasattr(analysisByProtocol, functionName): functionName = None # if a properly formatted protoocl was found, run its analysis if functionName: log.debug(f"analyzing known protocol via: {functionName}()") getattr(analysisByProtocol, functionName)(abf) else: msg = f"{abf.abfID} uses an unknown protocol: {abf.protocol}" log.warn(msg) with open(os.path.dirname(abf.abfFilePath)+"/pyabf.log", 'a') as f: timestamp = str(datetime.datetime.now()) f.write(f"[{timestamp}] [{abf.abfFilePath}] {msg}\n") log.debug("analyzing with unknown()") analysisByProtocol.unknown(abf) return
def thefile(self, dropdownfile): self.fullfilepath = os.path.join(self.fileloc, dropdownfile) self.currentfile = dropdownfile self.abf = pyabf.ABF(self.fullfilepath) self.numsweep = self.abf.sweepCount - 1 self.slidsweep = interact( self.setsweep, sweeppick=widgets.IntSlider( min=0, max=self.numsweep, values=1, step=1, description='Sweep:', ), )
def test_cookbook_createHeaderPages(abfPath): abf = pyabf.ABF(abfPath) assert isinstance(abf, pyabf.ABF) page = abfInfoPage(abf) # modify a few infos to make things cleaner for source control abfFilePath = f"C:/some/path/to/{abf.abfID}.abf" abfFolderPath = f"C:/some/path" page.replaceThing("abfFilePath", abfFilePath) page.replaceThing("stimulusFileFolder", abfFilePath) page.replaceThing("abfFolderPath", abfFolderPath) page.replaceThing("strings", "not shown due to non-ASCII characters") with open(f"{PATH_HEADERS}/{abf.abfID}.md", 'w') as f: f.write(page.generateMarkdown())
def return_flat_list_of_treatment(dict_of_groups, treatment): try: abf = pyabf.ABF(dict_of_groups[0]["fpath"]) time = abf.sweepX except TypeError as e: print(f"ERROR! \n {dict_of_groups}\n") target = [ db.str_list_to_list_ints(peaks["peaks"]) for peaks in dict_of_groups if peaks["treatment"] == treatment ] empty_less = [i for i in target if i] flat = [item for sublist in empty_less for item in sublist] x_time = time[flat] return x_time, flat
def figure_quietVsNoisy(): plt.figure(figsize=(8, 6)) plt.subplot(211) abf = pyabf.ABF(PATH_DATA+"/171116sh_0011.abf") # noisy plt.title(f"171116sh_0011.abf (RMS noise: 1.769 pA)") plt.ylabel(abf.sweepLabelY) plt.plot(abf.sweepX, abf.sweepY, alpha=.3) plt.plot(abf.sweepX, lowPassHanning(abf, 1), color='k', lw=1) plt.axis([.30, .50, -225, -100]) plt.subplot(212) abf = pyabf.ABF(PATH_DATA+"/f1_saved.abf") # noisy plt.title(f"f1_saved.abf (RMS noise: 4.933 pA)") plt.plot(abf.sweepX, abf.sweepY, alpha=.3) plt.plot(abf.sweepX, lowPassHanning(abf, 1), color='k', lw=1) plt.ylabel(abf.sweepLabelY) plt.xlabel(abf.sweepLabelX) plt.axis([.68, .88, -125, 0]) plt.tight_layout() plt.savefig("2019-06-07 auto detect lowpass filter 4.png") plt.show()