Package: pyclamp
pyCLAMPTime series recordings analysis in Python with UI similar to pCLAMP.What is pyCLAMP for?pyCLAMP is generally useful for analysis of any(x,y)data series that may be recorded in multiple channels and in respose to repeated episodes or triggered recording periods.More specifically, pyCLAMP aims to be a drop-in replacement (and improvement) for electrophysiology recording software such as pCLAMP, Patchmaster, Axograph, WinWCP, etc.Can you aquire data recordings with pyCLAMP?Not yet. Currently pyCLAMP can only view/analyze previously recorded data series.But keep an eye out as the ability to aquire data is one of the things that pyCLAMP hopes to be capable of in the future.Why use pyCLAMP?As of now you still need a different program to aquire data anyway, and as pyCLAMP is in its infancy it is undoubtably the case that it cannot yet do everything that other programs such as pCLAMP can. So why use pyCLAMP at all?pyCLAMP saves your data in a simple self-describing and highly flexible and extensible data structure that is easily loaded and explored in Python or MATLAB and will always be retrievable independent of pyCLAMP. You will never have to rely on having access to specific recording software to analyze your data and you will have the power of Python or MATLAB at your fingertips to write whatever analysis code you want. See the section below onpyCLAMP Data Structure.pyCLAMP provides a well designed UI for exploring and analyzing your data that in certain areas is already more feature rich than conventional alternatives.pyCLAMP already provides tools such as baseline fitting and detrending that are superior to the options in conventional alternatives, and which are still being developed further nonetheless.pyCLAMP is open source, so you have access to everything and can modify or customize the UI and analysis options to your liking. Please contribute your additions so that pyCLAMP's cababilities can grow for everyone. Eventually, pyCLAMP will be more powerful than the expensive closed source options that are currently available.Need a specific capability? Just ask for it and it may be provided in short order.INSTALL pyCLAMPpip install pyclampThis should install everything you need including all requirements.RequirementsnumpyscipylmfitPyQt6pyqtgraphqtawesomeRun the pyCLAMP UIJust run the commandpython -m pyclampto bring up the UI.pyCLAMP Data StructureData is stored as nested dictionaries or lists of dictionaries for maximum flexiblity and extensibility.Need new functionality? Just add a new key at whichever level of the heirarchy is appropriate.The data is entirely composed only ofdict,list,str,int,float, and numpyndarrayvalues and thus can be easily serialized to JSON, .MAT, etc.The data is entirely self-describing and can be easily explored and manipulated independent of the UI or any other code in this package.Data series traces are organized heirarchically by episode, channel, trace which should cover most experimental recording paradigms.EPISODE: A single recording sweep.CHANNEL: A single recorded signal (e.g., current, voltage, etc.).TRACE: A single data trace.Overlay TRACE: A single data trace associated with a parent trace (e.g., fit, measurement, etc.).EVENT: A labeled x-axis interval.For memory efficiency any data arrays that are shared amongst traces (e.g., XData) should all be references/views to the same shared array. These should generally be numpy ndarrays.In most cases each (EPISODE,CHANNEL) pair will have only a single TRACE and all fits, etc. will be handled with overlaid child traces. Multiple TRACEs per (EPISODE,CHANNEL) pair are for things like triggered recordings of variable segments within each sweep.The basic tree structure of nested dictionary objects or lists of dictionary objects:DATA={'Type':'Data''Episodes':[EPISODE,...]'Notes':notes}EPISODE={'Type':'Episode''Channels':[CHANNEL,...]}CHANNEL={'Type':'Channel''Traces':[TRACE,...]'Events':[EVENT,...]}TRACE={'Type':'Trace''Name':tracelabel(defaultsto'Data')'XData':ndarray[sample]ORsampleinterval(defaultstosampleindexes)'YData':ndarray[sample]'XLabel':x-axislabel'YLabel':y-axislabel'XUnit':x-axisunit'YUnit':y-axisunit'XZero':x-axiszeropoint,XData->XData-XZero'YZero':baselinendarray[sample]ORconstant,YData->YData-YZero'Mask':logicalmask,YData->YData[Mask]'Style':STYLE'Traces':[TRACE,...]}Nested traces inTRACE['Traces']are for overlay traces associated with their parent trace (e.g., fits, measurements, etc.).EVENT={'Type':'Event''Group':eventgrouplabel(defaultsto0)'XStart':x-axiseventstart'XStop':x-axiseventstop(defaultstoXStart)'Text':eventinfo}STYLE={'Type':'Style''Color':(r,g,b)or(r,g,b,a)in0-255or'auto'(defaultsto'auto'=>basedoncolormap)'LineStyle':oneof['none','-','--',':','-.'](defaultsto'-')'LineWidth':(defaultsto1)'Marker':oneof['none','o','t','t1','t2','t3','s','p','h','star','+','d','x'](defaultsto'none')'MarkerSize':(defaultsto10)'MarkerEdgeWidth':(defaultstolinewidth)'MarkerEdgeColor':(r,g,b)or(r,g,b,a)in0-255or'auto'(defaultsto'auto'=>Color)'MarkerFaceColor':(r,g,b)or(r,g,b,a)in0-255or'auto'(defaultsto'auto'=>MarkerEdgeColorwithalpha=0)}For example, to access thekthtrace in thejthchannel for theithepisode:DATA['Episodes'][i]['Channels'][j]['Traces'][k]['YData']=...Because alldictobjects are passed by reference, it is generally simpler to store references to desired objects and then manipulate their data through these refereces:TRACE=DATA['Episodes'][i]['Channels'][j]['Traces'][k]TRACE['YData']=...If the above trace contained a fit curve as its first child trace, then you would access the data in the fit curve as:TRACE['Traces'][0]['YData']=...Similarly, to access thekthevent in thejthchannel for theithepisode:EVENT=DATA['Episodes'][i]['Channels'][j]['Events'][k]EVENT['XStart']=...References from child to parent dict objects are stored separately from the data structure itself in a list of(CHILD, PARENT)tuples. These are very useful for manipulating the data structure, but are not required and can be derived from the data structure as needed. Were they to be included in the data structure itself, then they would prevent simple serialization to JSON, .MAT, etc.!!!If you manipulate the data structure with custom code, then it is up to you to insure that these(CHILD, PARENT)references are up-to-date for the UI to work as expected.Note thatDataModel.refreshParents()will refresh these references for the entire data structure whenever needed.