Neural Query System NQS Data-Mining From Within the NEURON Simulator (Lytton 2006)

 Download zip file   Auto-launch 
Help downloading and running models
Accession:97874
NQS is a databasing program with a query command modeled loosely on the SQL select command. Please see the manual NQS.pdf for details of use. An NQS database must be populated with data to be used. This package includes MFP (model fingerprint) which provides an example of NQS use with the model provided in the modeldb folder (see readme for usage).
Reference:
1 . Lytton WW (2006) Neural Query System: Data-mining from within the NEURON simulator. Neuroinformatics 4:163-76 [PubMed]
Model Information (Click on a link to find other models with that property)
Model Type: Neuron or other electrically excitable cell;
Brain Region(s)/Organism:
Cell Type(s):
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: NEURON;
Model Concept(s): Methods;
Implementer(s): Lytton, William [bill.lytton at downstate.edu];
// $Id: grvec.hoc,v 1.432 2005/02/08 17:47:50 billl Exp $

// 0 -> double, ie $1
// 1 -> object, ie $o1
// 2 -> string, ie $s1
// 3 -> address,ie $&1

// main panel is 'vecpanel()'
proc grvec () {}
load_file("decvec.hoc")  // declare vectors
load_file("declist.hoc")  // declare lists
strdef grep,tstr2 // LINUX grep requires -a to handle a binary file 
strdef ddir,symb
objref tf1
if (sfunc.substr(osname,"inux")==1) grep="grep -a" else grep="grep"
ddir = "data"
symb = "O"
gvmarkflag=gveraseflag=0
newstyle=(unix_mac_pc()==3)||1 // newstyle splits text dot-file from binary file

//* templates
//** attrpanl(attribute panel) template stores the information about
// the attributes of a particular set of graphs including line colors,
// world coordinates, ...
// glist is a list of all graphs created from this panel
// llist is a list of available names and associated vectors or locations
begintemplate panattr
  public color,line,super,curcol,graph,filename,comment
  public glist,llist,tvec,size,shift,vsz,vjmp,tloc,vloc,remote
  public printStep,entries,segments,bytes,clear,locokflag
  double color[1],line[1],super[1],curcol[1],printStep[1],remote[1]
  double size[4],entries[1],segments[1],bytes[1],shift[1]
  double vsz[2],tloc[1],vloc[1],vjmp[1],locokflag[1]
  objref glist,llist,tvec
  strdef filename,comment
  proc init () {
    if (numarg()==1) filename = $s1
    color=1 line=1 curcol=1 tloc=-1 super=0 bytes=0 vjmp=50 entries=1 segments=1
    locokflag=0
    vsz[0] = 300  vsz[1] = 200
    glist = new List()
    llist = new List()
    tvec  = new Vector(0)
  }
  proc remgrs () {
    glist.remove_all
    glist = nil
    glist = new List()
  }
  proc clear () {
    bytes=0 entries=1 segments=1
    comment = ""
    llist.remove_all()
  }
endtemplate panattr

//** vfile_line (vector file line) template gives information about a line
//  in a file that gives a vector: name, size and location
begintemplate vfile_line
  public name, size, loc, num
  strdef name
  double size[1],loc[1],num[1],tvec[1]
  proc init () { 
    name=$s1 size=$2 num=$4
    double loc[num],tvec[num]
    loc[0] = $3
  }
endtemplate vfile_line

//** vitem (vector item) is an internal vector used to store output from 
// new vitem(var_name,vec_size,friendly_name)
// new vitem(var_name,vec_size,1) -- force tvec creation even if not cvode_local
// a simulation holds the name and the vector itself
using_cvode_=use_lvardt_=0
begintemplate vitem
  external using_cvode_,use_lvardt_
  public tvec,vec,var,flag,o
  objref tvec,vec,o // vector
  strdef var // variable name
  proc init () { local tvflag
    var=$s1  tvflag=0  flag=0
    if (use_lvardt_==1) tvflag=1 else { 
      // print "WARNING CVODE LOCAL IS NOT SET" 
    }
    vec=new Vector($2)
    flag=-1
    // NB label is labile
    vec.label("") // use label for friendly name
    if (numarg()==3) {
      if (argtype(3)==2) vec.label($s3)
      if (argtype(3)==0) if ($3==1) tvflag=1
    }
    if (tvflag==1) tvec=new Vector($2) 
  }
endtemplate vitem

//* object declarations
objref vite, scob, printlist, panobj, panobjl, szstr[4], g[10]
panobj = new panattr(simname)
panobjl = new List()
proc pno () { panobj=panobjl.object($1) }
printlist = new List()
panobjl.append(panobj) // global graphing attributes
panobj.llist = printlist 
strdef filename, recstr, grvecstr, readtag
readtag = "^//[:pbCM ]"  // regexp used to identify header in mixed binary files
for ii=0,3 { szstr[ii] = new String() }
{ szstr[0].s="Set xmin" szstr[1].s="Set xmax" szstr[2].s="Set ymin" szstr[3].s="Set ymax" }
multi_files = 1 // set 0 to show individual segments of multi-seg files
dec_runnum = 0  // whether to decrement runnum when saving a new file
byte_store = 4  // store as ascii (0), byte (1), int (2), float (3), double (4)
tvec_bytesize = 4  // always store tvecs with more precision
show_panel = 1  // whether or not to put a full panel up when a file is read
outvecint = 0     // dump vectors every outvecint time if not 0
outvect = 0     // time for next vec dump
labelm = 1       // set to 0 to turn off labeling
strdef rvvec_name
rvvec_name = "vec"

//* abbreviated proc alls
proc pwpl () { pwman_place(500,500) }
proc vp () { vecpanel() }
proc ap () {if (numarg()==1) {attrpanl($1) rpanel($1)} else {attrpanl(0) pbrgr("Graph","gv")}}
proc apo () { 
  panobj=panobjl.object($1) XO=panobj
  if (panobj.glist.count) {g=panobj.glist.object(0) graphItem=g}
}
iterator apl () { local ii
  for ii=1,panobjl.count-1 {
    if (numarg()==1) {$&1=ii} else {i2=ii}
    panobj=panobjl.object(ii) XO=panobj
    if (panobj.glist.count) {g=panobj.glist.object(0) graphItem=g}
    iterator_statement
  }
}
proc wp () {if (numarg()==1) wvpanl($1) else wvpanl(0) }
proc gp () {if (numarg()==1) rpanel($1) else  pbrgr("Graph","gv")  }
proc tog (){if (numarg()==0) print panobj.super=1-panobj.super else print $&1=1-$&1}
proc togmark () {
  if (gvmarkflag==0) { gvmarkflag=1
    if (panobj.line<4) panobj.line+=6
  } else {             gvmarkflag=0
    if (panobj.line>6) panobj.line-=6
  }
  sprint(panobjl.object(attrnum).comment,"mark=%d",gvmarkflag)
}

//* store cvode state in a double in form active.local
func cvode_status () { return cvode_active() + cvode_local()/10 }
ulvflag=1
proc ulv () { 
  if (ulvflag || numarg()==1) { // else leave these other flags alone
    using_cvode_ = cvode_active() 
    use_lvardt_ = cvode_active() && cvode_local()
  }
} 
cvode_state = cvode_status()

//** return true and update cvode_state if cvode state has changed
func cvode_change () { 
  if (cvode_state!=cvode_status()) {
    cvode_state=cvode_status() return 1
  } else { return 0 }
}

//** verbose form of cvode_change
func cvode_what () { local act,loc,newstat,newact,newloc
  act=int(cvode_state)  loc=(cvode_state-act)*10
  newstat = cvode_status()
  if (cvode_state!=newstat) {
    newact=int(newstat)  newloc=(newstat-newact)*10
    printf("Updating active/local from %d/%d to %d/%d\n",act,loc,newact,newloc)
    cvode_state=cvode_status() return 1
  } else {
    printf("cvode_state: active %d, local %d\n",act,loc)
    return 0	
  }
}

if (xwindows) scob = new SymChooser()

//* vecpanel() main panel
proc vecpanel () {
  fchooser_flag = 0  // used to initialize the file chooser
  sprint(temp_string_,"%s Vectors",simname)
  xpanel(temp_string_)
  xbutton("Graph from file","fchooser(-1)")
  xbutton("Graph vector","pbrgr(\"Graph\",\"gv\")")
  xbutton("Archive to file:","pbrgr(\"Archive\",\"pv\")")
  xbutton("Archive all to output file","pvall()")
  xstatebutton("Superimpose",&panobjl.object(0).super)
  xbutton("Attributes","attrpanl(0)")
  redo_printlist()
  redo_attrlist()
  xpanel()
}

//* pbrgr(browser name,action) is used to put up a browser
// note action given without '()'
proc pbrgr () {
  if (printlist.count == 1) {
    gv(0)
  } else if (printlist.count <= 8) {
    mkpanel("Vector",$s1,$s2)
  } else {
    sprint(temp_string_,"%s:%s",simname,$s1)
    printlist.browser(temp_string_,"var")
    sprint(temp_string2_,"%s()",$s2)
    printlist.accept_action(temp_string2_)
  }
}

//* record(list,what,vecptr) from items in $o1 object(ii).$s2 in vectors
// $o1 is the list arg $s2 is the thing to be recorded [eg soma.v(0.5)]
// optional $3 is the name of an object belonging to list items that will
// serve as a pointer to the recording vector
proc record () { local ii, dur, na3
  if (isobj($o1,"List")) for ltr(XO,$o1) {
    sprint(recstr,"%s.%s",XO,$s2)
    new_printlist_item(recstr) 
    if (numarg()==3) { 
      sprint(temp_string_,"%s.%s=printlist.object(printlist.count-1).vec",XO,$s3)
      execute(temp_string_) // only way to get call by ref for object
    }
  } else forsec $o1 { // assume sectionlist
    sprint(recstr,"%s.%s",secname(),$s2)
    new_printlist_item(recstr) 
    if (numarg()==3) { 
      sprint(temp_string_,"%s.%s=printlist.object(printlist.count-1).vec",XO,$s3)
      execute(temp_string_) // only way to get call by ref for object
    }
  } 
}

//* record_spks(list[,what]) takes a list of netcons and puts in printlist objects for them
// assumes that the PP will be called pp
proc record_spks () { local ii,flag
  ulv(1)
  for ltr(XO,$o1) {
    flag=1
    if (cvode.netconlist(XO, "", "").count>0) {
      YO=cvode.netconlist(XO, "", "").object(0)
      sprint(recstr,"%s%s",YO.precell,"_spks")
    } else if (cvode.netconlist(XO.pp, "", "").count>0) {
      YO=cvode.netconlist(XO.pp, "", "").object(0) 
      sprint(recstr,"%s%s",YO.pre,"_spks")
    } else { printf("%s not connected.\n",XO) flag=0 }
    if (flag) {
      vite = new vitem(recstr,100)
      if (use_lvardt_) { YO.record(vite.tvec) vite.vec.resize(0) } else YO.record(vite.vec)
      printlist.append(vite)
    }
  }
  YO=nil
}
//* redo_printlist() menu allows removal or addition of inidividual items
proc redo_printlist () {
  xmenu("Print list")
  xbutton("Add var to printlist","redolist(0)")
  xbutton("Clear printlist","printlist.remove_all()")
  xbutton("Remove item from printlist","redolist(1)")
  xbutton("Vector.op","redolist(2)")
  xbutton("Proc(vector)","redolist(6)")
  xbutton("Link XO->vec,YO->tvec","redolist(7)")
  xbutton("Graph vector","redolist(4)")
  xbutton("Save printlist","redolist(5)")
  xbutton("Add all obj's of this type to printlist","redolist(3)")
  xmenu()
}

//* redolist() set of functions for altering the printlist called by redo_printlist()
proc redolist () { local ii,flag
  flag = $1  rdstr = 1
  if (numarg()==2) { recstr=$s2  rdstr=0 }
  if (flag==0) {
    if (scob.run()) {
      scob.text(temp_string_)
      new_printlist_item(temp_string_)
    }
  } else if (flag==1) { // remove item
    printlist.browser("Double click on item to remove","var")
    printlist.accept_action("printlist.remove(hoc_ac_)")
  } else if (flag==2) { // .op
    if (rdstr) string_dialog("Enter operation to be run on vec",recstr)
    temp_string_ = "\"%s.%s = %g\\n\""
    sprint(temp_string_,"printf(%s,printlist.object(hoc_ac_).var,\"%s\",x=printlist.object(hoc_ac_).vec.%s)",temp_string_,recstr,recstr)
    printlist.browser(recstr,"var")
    printlist.accept_action(temp_string_)
  } else if (flag==3) { // put another set of things on list
    if (rdstr) string_dialog("String to be used as suffix for all items on list",recstr)
    scob.run()
    scob.text(temp_string_)
    tmplist = new List(temp_string_)
    record(tmplist,recstr)
  } else if (flag==4) { // show it
    pbrgr("Graph","gv")
  } else if (flag==5) {
    fchooser_flag = 0
    tmpfile.chooser("a","Add printlist to file")
    if (tmpfile.chooser()==1) {
      tmpfile.printf("\nproc make_printlist() { \n")
      tmpfile.printf("  printlist.remove_all()\n")
      for ii=0,printlist.count-1 {
        tmpfile.printf("  new_printlist_item(\"%s\")\n",printlist.object(ii).var)
      }
      tmpfile.printf("}\nmake_printlist()\n")
      tmpfile.close()
    }
  } else if (flag==6) { // proc(vec)
    if (rdstr) string_dialog("Enter procedure name \"proc\",called as proc(vec,var,num)",recstr)
    printlist.browser(recstr,"var")
    sprint(temp_string_,"%s(printlist.object(hoc_ac_).vec,printlist.object(hoc_ac_).var,hoc_ac_)",recstr)
    printlist.accept_action(temp_string_)
  } else if (flag==7) { // XO is pointer to vec
    printlist.browser("XO","var")
    sprint(temp_string_,"{tmpobj=printlist.object(hoc_ac_) print hoc_ac_,tmpobj.var XO=tmpobj.vec YO=tmpobj.tvec}")
    printlist.accept_action(temp_string_)
  } 
}

//** lkprl([num]) link X0 to vector in printlist, optional arg can be pos or neg
proc lkprl () { local num,cnt
  ulv()
  cnt = printlist.count
  if (numarg()==1) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
  if (num>cnt-1 || num<0) {
    printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
  }
  print num,":XO -> ",printlist.object(num).var
  XO = printlist.object(num).vec
  if (use_lvardt_) YO = printlist.object(num).tvec else YO = panobj.tvec
}

//** cpplitem([num]) copy X0 to new item in printlist, optional arg can be pos or neg
proc cpplitem () { local num,cnt
  cnt = printlist.count
  if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
  if (num>cnt-1 || num<0) {
    printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
  }
  if (numarg()>1) grvecstr=$s2 else sprint(grvecstr,"Copy_of_%s",printlist.object(num).var)
  new_printlist_item(grvecstr,printlist.object(num).vec)
  print printlist.count-1,":XO -> ",grvecstr
  XO = printlist.object(printlist.count-1).vec
}


//** cpplitem([num]) copy X0 to new item in printlist, optional arg can be pos or neg
proc chgplname () { local num,cnt
  cnt = printlist.count
  if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
  if (num>cnt-1 || num<0) {
    printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
  }
  printlist.object(num).var=$s2
}

//* new_printlist_item(name) adds this item to the printlist
//  new_printlist_item(name,vec) adds this vec to the printlist
//  new_printlist_item(name,vec,tvec) adds this vec to the printlist
//  new_printlist_item(var,name) use name instead of variable name
//  new_printlist_item(var,ptr) provide an objref to point to the vec
//  new_printlist_item(name,num,vec)??adds this vec to the printlist under name_num0,name_num1,...
proc new_printlist_item () { local dur,nflag,tvflag
  ulv() tvflag=nflag=0
  panobj = panobjl.object(0)  
  if (outvecint == 0) dur = tstop else dur = outvecint
  grvecstr = $s1
  remove_spaces(grvecstr,temp_string2_) // splits on '/'
  // eg new_printlist_item(name,ii,vec)
  if (numarg()>=3) { // allows formation of tags on the fly
    if (argtype(3)==0) { tvflag=1
    } else if (argtype(2)==0) {
      sprint(temp_string_,"%s%s",grvecstr,":%d")
      sprint(temp_string_,temp_string_,$2)
      vite = new vitem(temp_string_,$o3.size,temp_string2_)
      vite.vec.copy($o3)
      if (numarg()==4) vite.tvec.copy($o4)
      printlist.append(vite)
      return
    } else if (argtype(2)==1) { 
      vite = new vitem(grvecstr,$o2.size,1)
      vite.vec.copy($o2) vite.tvec.copy($o3)
      printlist.append(vite)
      return
    }
  }
  if (numarg()>=2) { // second arg is a vector to store
    if (argtype(2)==1) {
      vite = new vitem(grvecstr,$o2.size,temp_string2_)
      vite.vec.copy($o2)
      printlist.append(vite)
      return
    } else if (argtype(2)==2) {  // give explicit name for the thing to store
      nflag=1
    }
  }
  if (use_lvardt_) { 
    panobj.printStep=-2
  } else if (using_cvode_) { 
    panobj.printStep=-1
  } else { 
    panobj.printStep=printStep 
  }
  if (using_cvode_ && !use_lvardt_) { 
    if (panobj.tvec.buffer_size==0){panobj.tvec.resize(dur/printStep+10) panobj.tvec.resize(0)}
    panobj.tvec.record(&t) 
  } else if (isobj(panobj.tvec,"Vector")) if (panobj.tvec.size!=0) { 
    panobj.tvec.resize(0) panobj.tvec.play_remove()          
  }
  if (nflag) { 
    if (tvflag) { vite = new vitem($s2,dur/printStep+10,1) } else {
                  vite = new vitem($s2,dur/printStep+10,temp_string2_)   }
  } else {
    if (tvflag) { vite = new vitem(grvecstr,dur/printStep+10,1) } else {
                  vite = new vitem(grvecstr,dur/printStep+10,temp_string2_) }
  }
  if (numarg()==2) if (argtype(2)==1) $o2=vite.vec // allow user to assign a pointer
  printlist.append(vite)
  if (use_lvardt_ || tvflag) {
    vite.vec.resize(dur/printStep+10) vite.tvec.resize(dur/printStep+10)
    find_secname(grvecstr,temp_string_) // with lvardt, need to assign in proper context
    sprint(temp_string_,"%s {cvode.record(&%s,vite.vec,vite.tvec)}",temp_string_,grvecstr)
  } else if (using_cvode_) { // don't give an explicit printStep
    vite.vec.resize(dur/printStep+10)
    sprint(temp_string_,"{vite.vec.record(&%s)}",grvecstr)
  } else {
    sprint(temp_string_,"vite.vec.record(&%s,%g)",grvecstr,printStep)
  }
  execute(temp_string_)
  vite=nil
}

// new_pri(NAME,TVEC,VEC) quick and dirty new_printlist_item
proc new_pri () {
  vite = new vitem($s1,$o2.size)
  if (numarg()==3) { vite.tvec.copy($o2) vite.vec.copy($o3) } else vite.vec.copy($o2)
  printlist.append(vite)
  vite=nil
}

//* prlexp(sz) expands all the vectors in printlist to size sz
proc prlexp () { 
  sz = $1
  tvec.resize(sz)
  for ltr(XO,printlist) { XO.vec.resize(sz) }
}


//* redo_attrlist() menu allows removal or addition of inidividual items
proc redo_attrlist() {
  xmenu("Attribute panels")
  xbutton("Read file","attrlist(0)")
  xbutton("Remove","attrlist(1)")
  xbutton("Show","attrlist(2)")
  xbutton("Clear list","attrlist(3)")
  xbutton("New","attrlist(4)")
  xmenu()
}

//* attrlist() set of functions for altering panobjl (list of graph attributes)
proc attrlist () { local ii
  if ($1==0) {
    fchooser(-1)
  } else if ($1==1) { // remove item
    panobjl.browser("Double click on item to remove","filename")
    panobjl.accept_action("panobjl.remove(hoc_ac_)")
  } else if ($1==2) {
    panobjl.browser("Double click on item",temp_string_,"numovecs()")
    panobjl.accept_action("attrpanl(hoc_ac_)")    
  } else if ($1==3) { // clear but leave #0
    for (ii=panobjl.count-1;ii>0;ii=ii-1) { panobjl.remove(ii) }
  } else if ($1==4) { // create a new one without reading a file in
    panobj = new panattr()
    panobj.filename = "EMPTY"
    panobjl.append(panobj)
    panobj.remote = panobjl.count()-1
    attrpanl(panobjl.count()-1)
  } else if ($1==5) { // create one with given num and name
    for ii=panobjl.count,$2 { // create more if needed
      panobj = new panattr()
      panobjl.append(panobj)
      panobj.remote = ii
    }
    panobj = panobjl.object($2)
    panobj.filename = $s3
    panobj.comment = $s4
    panobj.printStep = $5
  }
}

// show the number of vectors as well as the name of the file
proc numovecs () { local num
  if (hoc_ac_==0) num=printlist.count() else num=panobjl.object(hoc_ac_).llist.count() 
  sprint(temp_string_,"#%d %s: %d",hoc_ac_,panobjl.object(hoc_ac_).filename,num)
}

//* fchooser(attrnum) finds file and then create panel from it using rpanel
proc fchooser () { local attr0
  attr0=$1
  if (fchooser_flag == 0) {  // create panel first time only
    sprint(temp_string_,"v0*")
    tmpfile.chooser("","Read from a file",temp_string_)
  }
  fchooser_flag = 1
  if (tmpfile.chooser() == 1) {
    // find out whether this is a vector file or not
    tmpfile.getname(filename)
    sfunc.tail(filename,"/data.*/",grvecstr) // just take the file name without the leading stuff
    attrnum=read_vfile(attr0) 
    if (attrnum == 0) {print "ERROR in fchooser" return }// error
    // a new one so should show something
    if (attr0==-1) if (show_panel) rpanel(attrnum) else attrpanl(attrnum)
  }
}

//* routines for reading in a vector file

//** read_vfile(attrnum) creates a panattr object from information in a file
// (uses grep to avoid loading big file)
// assumes file in tmpfile
func read_vfile () { local flag, ii, sz, loc, mult, sze, cloc, segs
  if (numarg()==0) { print "read_vfile(attrnum,filename)" return 0 }
  if (numarg()==2) filename = $s2
  read_findattr($1) // set panobj and attrnum
  panobj.locokflag=0
  // grab hold of the different lines using grep
  file_with_dot(filename,temp_string_,temp_string2_) // put .filename into temp_string_
  if (!tmpfile.ropen(temp_string_)) { // newstyle -> dotfile will exist already
    if (! tmpfile.ropen(filename)) { print "E1: Can't open ",filename // avoid grep error
      return 0 }
    sprint(temp_string2_,"%s '%s' %s > %s",grep,readtag,filename,temp_string_)
    system(temp_string2_)
    tmpfile.close()
    if (! tmpfile.ropen(temp_string_)) { print "E2: Can't open ",temp_string_," (",filename,")" 
      return 0 }
    flag = 0
  } else flag = 1 // signifies that .file exists to use as key
  while ((numr = tmpfile.scanstr(temp_string_)) != -1) {  // throw out the leading '//'
    // read the line
    if (!panobj.locokflag && unix_mac_pc()!=3) cloc=tmpfile.tell-numr // loc of beginning of line
    if (sfunc.head(temp_string_,"//[^b]",temp_string2_)==0) {
      read_vinfo()  // a line giving info about the file (eg comment)
    } else {   // NB: code in v60:516 to pickup byte_store value
      if (panobj.bytes==0 && \
          sfunc.head(temp_string_,"//b[1-9]",temp_string2_)==0) { panobj.bytes = 1 }
      if (flag && panobj.entries>1) { // a .file with MULTI segs
        tmpfile.seek(-numr,1) // backup to beginning of line
        read_vdotfile()
      } else if (panobj.segments > 1) { // mult segs: different times for same var
        tmpfile.seek(-numr,1) // backup to beginning of line
        panobj.segments = read_vsegs()
      } else {  // read each line in for itself
        tmpfile.scanstr(temp_string_) // name of a var
        sze = tmpfile.scanvar()   // size of the vector or time it was dumped
        loc = tmpfile.scanvar()   // location of the vector
        if (panobj.bytes && !panobj.locokflag) { 
          if (unix_mac_pc()==3) {printf("ERR: can't read mixed binary text file\n") return 0}
          tmpfile.seek(cloc) // go back and measure the line length
          loc = loc + tmpfile.gets(temp_string2_) 
        }
        // create the item
        if (strcmp(temp_string_,"tvec")!=0) {
          tmpobj = new vfile_line(temp_string_,sze,loc,1)
          panobjl.object(attrnum).llist.append(tmpobj)
          tmpobj = nil
        } else {
          panobj.tvec.resize(0)
          panobj.printStep=-1
          panobj.tloc = loc // where to find tvec later
        }
      }
    }
  }
  if (panobj.llist.count==0) {
    printf("grvec.hoc::read_vfile ERR no vecs read from %s (?saved newstyle)\n",panobj.filename)}
  if (panobj.entries==1) panobj.entries = panobj.llist.count
  if (! flag && panobj.segments>1) write_vsegs()  // create key .file
  if (! tmpfile.ropen(panobj.filename)) { print "E3: Can't open ",panobj.filename
    return 0 }
  if (panobj.printStep==-1) { rtvec(attrnum) // code for cvode_active()
  } else if (panobj.printStep==0) panobj.printStep = printStep
  return attrnum
}

//** read_findattr()
// see if want to use old attributes or start new ones
proc read_findattr () { 
  if ($1 > -1 && $1 < panobjl.count()) {
    attrnum = $1
    panobj = panobjl.object(attrnum)
    panobj.clear()
    panobj.filename = filename
  } else {   // create a new panel attribute object to hold color and line type
    panobj = new panattr(filename)
    panobjl.append(panobj)
    panobj.remote = panobjl.index(panobj)
    attrnum = panobjl.index(panobj)
  }
}

//** read_vinfo()
// fill in panobj entries based on an information line in a vector file
proc read_vinfo () {
  if (strcmp(temp_string_,"//printStep")==0) {
    panobj.printStep = tmpfile.scanvar() // printstep==-1 means cvode
  } else if (strcmp(temp_string_,"//:")==0) { // a comment
    tmpfile.gets(temp_string_)
    sfunc.head(temp_string_,"\n",panobj.comment) // chop final newline
  } else if (strcmp(temp_string_,"//CPU")==0) { // the machine type for byte storage
    tmpfile.scanstr(temp_string_)
    if (strcmp(temp_string_,uname)!=0) {
      printf("%s written from %s\n",filename,temp_string_)
    }
  } else if (strcmp(temp_string_,"//LOC_OK")==0) { // uncorrected vector locations
    panobj.locokflag=1
  } else if (strcmp(temp_string_,"//MULTI")==0) { // multiple lines for each entry
    panobj.entries = tmpfile.scanvar()
    if (multi_files) { panobj.segments = tmpfile.scanvar() }
  } else {
    printf("Line:\t%s\n\tnot recognized in %s\n",temp_string_,panobj.filename)
    tmpfile.seek(-1,1)
    tmpfile.gets(temp_string_) // clear this line out
  }
}

//** read_vdotfile() read .file in abbreviated format (see write_vsegs)
proc read_vdotfile() { local loc,entries,segments,ii
  entries=panobj.entries segments=panobj.segments
  panobj.bytes = 1
  for i=1,entries {  // read this abbreviated file version (much faster)
    tmpfile.scanstr(temp_string_)
    loc = tmpfile.scanvar()
    tmpobj = new vfile_line(temp_string_,-1,loc,segments) // don't set size
    panobj.llist.append(tmpobj)
    for ii=1,segments-1 { tmpobj.loc[ii] = tmpfile.scanvar() }
  }
}

//** read_vsegs() read a file that is segmented with diff vectors at diff times
// (see outvecs)
func read_vsegs () { local segments,entries,i,ii,jj,sze,loc,ret,cloc,clocend,llen
  entries=panobj.entries segments=panobj.segments ret=1
  for i=1,entries { // usually will be the number of cells recorded
    cloc = tmpfile.tell()   // starting location in the file
    tmpfile.scanstr(temp_string_)
    tmpfile.scanstr(temp_string_) // name of a var
    sze = tmpfile.scanvar()   // size of the vector or time it was dumped
    loc = tmpfile.scanvar() + (tmpfile.tell() - cloc) // add line length
    cloc = tmpfile.tell()  // a location where a vec begins
    tmpobj = new vfile_line(temp_string_,sze,loc,segments)
    panobj.llist.append(tmpobj)
    for ii=1,segments-1 {  // go through all the different time segs
      for jj=1,entries-1 { // go through all the cells
        if ((ret = tmpfile.gets(temp_string_))==-1) { break } // EOF error
      }
      clocend = tmpfile.tell()  // loc of end of this seg
      tmpfile.scanstr(temp_string_) tmpfile.scanstr(temp_string_) // name of a var
      if (strcmp(temp_string_,tmpobj.name)!=0) {  // name should match
        printf("ERROR: %d not %d segs found (%s)\n",ii,segments,tmpobj.name) 
        segments = ii
        break
      }
      tmpfile.scanvar()  // a time 
      tmpobj.loc[ii] = tmpfile.scanvar()+(tmpfile.tell()-clocend) // where the vector starts
      clocend = tmpfile.tell()
    }
    tmpfile.seek(cloc)   // go back for next entry
  }
  tmpfile.seek(clocend)  // go to end of all this stuff
  return segments
}

//** write_vsegs()
// write out names of all entries along with locations where the vecs start
proc write_vsegs () { local ii
  file_with_dot(filename,temp_string_,temp_string2_) // put .filename into temp_string_
  sprint(temp_string2_,"grep '^//[^bM]' %s > %s",xtmp,temp_string_)
  system(temp_string2_)  // copy the non-location lines into the new file
  tmpfile.aopen(temp_string_)
  tmpfile.printf("//MULTI %d %d\n",panobj.entries,panobj.segments) // redo in case differs
  for ltr(XO,panobj.llist) {
    tmpfile.printf("%s ",XO.name)
    for ii=0,panobj.segments-1 { tmpfile.printf("%d ",XO.loc[ii]) }
    tmpfile.printf("\n")
  }
  tmpfile.close()
}

//** make_vdot_files() go through a list of filenames to convert into .file format
proc make_vdot_files () { local ii,sav,cnt
  cnt = panobjl.count()
  for ltr(XO,$o1) {
    filename = XO.s
    print "Processing ",filename
    read_vfile(cnt) // don't overwrite one that's being used
  }
}

//* print out the CPU name
proc vfcpu () {
  sprint(temp_string_,"%s '^//CPU' %s",grep,$s1)
  system(temp_string_)
}

//* rpanel() creates a panel from information in llist
proc rpanel () { local ii
  print $1
  attrnum = $1
  panobj = panobjl.object(attrnum)  
  if (panobj.llist.count > 8) { rlist($1) return }
  sprint(temp_string_,"#%d:%s ",attrnum,simname)
  xpanel(temp_string_)
  xlabel(panobj.filename)

  for ii=0,panobj.llist.count-1 {
    sprint(temp_string2_,"rv(%d,%d)",attrnum,ii)
    xbutton(panobj.llist.object(ii).name,temp_string2_)
  }
  sprint(temp_string_,"attrpanl(%d)",attrnum)
  xbutton("Attributes",temp_string_)
  sprint(temp_string_,"lpvec(filename,vrtmp,%g)",panobj.printStep)
  xbutton("Print last vec",temp_string_)
  xbutton("Erase","ge()")
  xpanel()
}

//* rlist(): like rpanel() but puts up a browser list instead of a panel
proc rlist () {
  panobjl.object($1).llist.browser(panobjl.object($1).filename,"name")
  sprint(temp_string_,"rv(%d,hoc_ac_)",$1)
  panobjl.object($1).llist.accept_action(temp_string_)
}

//* rvlist(): like rpanel() but puts up a browser list instead of a panel
proc rvlist () { local flag,attrnum,rdstr
  rdstr = 1
  flag = $1 attrnum = $2 
  if (numarg()==3) { recstr=$s3  rdstr=0 }
  if (flag==0) {
    panobjl.object(attrnum).llist.browser(panobjl.object(attrnum).filename,"name")
    sprint(temp_string_,"rvec(%d,hoc_ac_)",attrnum)
    panobjl.object(attrnum).llist.accept_action(temp_string_)
  } else if (flag==1) { // proc(vec)
    if (rdstr) string_dialog("Procedure name: proc, called as proc(vec)",recstr)
    panobjl.object(attrnum).llist.browser(recstr,"name")
    sprint(temp_string_,"{rvec(%d,hoc_ac_) %s(%s)}",attrnum,recstr,rvvec_name)
    panobjl.object(attrnum).llist.accept_action(temp_string_)
    print attrnum,":",recstr,":",temp_string_,":",rvvec_name
  } else if (flag==2) { // vec.command
    if (rdstr) string_dialog("comm: print vec.comm",recstr)
    panobjl.object(attrnum).llist.browser(recstr,"name")
    sprint(temp_string_,"{rvec(%d,hoc_ac_) print %s.%s}",attrnum,rvvec_name,recstr)
    panobjl.object(attrnum).llist.accept_action(temp_string_)
  }
}

proc disptray () { print "Must load boxes.hoc to get trays" }
objref apvb,aphb
//* attrpanl() gives attributes for a set of graphs
proc attrpanl () { local ii,jj
  attrnum = $1 // use global for xbuttn
  panobj=panobjl.object(attrnum)
  sfunc.tail(panobjl.object(attrnum).filename,"data.*/",grvecstr)
  sprint(temp_string_,"#%d:%s:%s (ATTRPANL)",attrnum,simname,grvecstr)
  apvb=new VBox() apvb.intercept(1)
  xpanel(temp_string_)
  xvarlabel(panobjl.object(attrnum).filename)
  xvarlabel(panobjl.object(attrnum).comment)
  sprint(temp_string_,"panobjl.object(%d).color",attrnum)
  xvalue("Color(-1=multi)",temp_string_,1)
  sprint(temp_string_,"panobjl.object(%d).line",attrnum)
  xvalue("Line",temp_string_,1)
  xvalue("Superimpose - Graph[#]","gnum",1,"tog(&panobjl.object(attrnum).super) sprint(panobjl.object(attrnum).comment,\"super=%d\",panobjl.object(attrnum).super)")
  xpanel()
  xpanel("",1)
  xbuttn("Limits","wvpanl(")
  sprint(temp_string2_,"geall(%d)",attrnum)
  xbutton("Erase",temp_string2_)
  xbutton("Mark","togmark()")
  if (attrnum==0) xbutton("Panel","pbrgr(\"Graph\",\"gv\")") else {
    xbuttn("New file","fchooser(") }
  xpanel()
  xpanel("")
  xmenu("Manipulate graphs")
  xbutton("Mark","togmark()")
  xbutton("Erase/redraw","tog(&gveraseflag) sprint(panobjl.object(attrnum).comment,\"ERASE = %d\",gveraseflag)")
  xbuttn("Label graphs","lblall(")
  xbuttn("Erase graphs","geall(")
  xbuttn("Remove graphs","remgrs(")
  xbuttn("Clean graph list","collapsegrs(")
  sprint(temp_string2_,"setrange(%d,3)",attrnum)
  xbutton("Erase axes",temp_string2_)
  sprint(temp_string2_,"disptray(%d)",attrnum)
  xbutton("Make tray",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"View = plot\")",attrnum)
  xbutton("View = plot",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Crosshair\")",attrnum)
  xbutton("Crosshair",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"NewView\")",attrnum)
  xbutton("New view",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Delete\")",attrnum)
  xbutton("Delete Text",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Move Text\")",attrnum)
  xbutton("Move Text",temp_string2_)
  sprint(temp_string2_,"for ltr(XO,panobjl.object(%d).glist) XO.exec_menu(\"Change Text\")",attrnum)
  xbutton("Change Text",temp_string2_)
  xmenu()
  // sprint(temp_string_,"panobjl.object(%d).remote",attrnum)
  // sprint(temp_string2_,"grall(%d)",attrnum)
  // xvalue("Graph all",temp_string_,0,temp_string2_)
  if (attrnum != 0) {
    xmenu("Manipulate vectors")
    xbutton("Vector name","string_dialog(\"Change Vector name\",rvvec_name)")
    xbuttn("Write to vector","rvlist(0,")
    xbuttn("Proc(vector)","rvlist(1,")
    xbuttn("vector.command","rvlist(2,")
    xmenu()
    xbuttn("Show full panel","rpanel(")
  } else {

  }
  xpanel()
  apvb.intercept(0) apvb.map()
}

// allows inclusion of attrnum for each item
proc xbuttn () { sprint(temp_string2_,"%s%d)",$s2,attrnum)  xbutton($s1,temp_string2_) }

//* set something for attrpanl() to value
func attrset () { local attrnum, ii
  if (numarg()==0) { printf("attrset(attrnum,\"thing\",val)\n") 
  } else if (numarg()==2) {
    sprint(temp_string_,"tempvar = panobjl.object(%d).%s",$1,$s2)
    execute(temp_string_)
    return tempvar
  } else { 
    sprint(temp_string_,"panobjl.object(%d).%s=%g",$1,$s2,$3)
    execute(temp_string_) 
    return $3
  }
}

proc wvpanl () { local attrnum, ii
  attrnum = $1
  sfunc.tail(panobjl.object(attrnum).filename,"data.*/",grvecstr)
  sprint(temp_string_,"#%d:%s:%s (WVPANL)",attrnum,simname,grvecstr)
  xpanel(temp_string_)
  sprint(temp_string_,"%d Vectors",panobjl.object(attrnum).llist.count)
  xlabel(temp_string_)
  for ii=0,3 {
     sprint(temp_string_,"panobjl.object(%d).size[%d]",attrnum,ii)
     sprint(temp_string2_,"chrange(%d,%d)",attrnum,ii)
     xvalue(szstr[ii].s,temp_string_,0,temp_string2_)
  }
  sprint(temp_string_,"panobjl.object(%d).shift",attrnum)
  sprint(temp_string2_,"chrange(%d,-2)",attrnum)
  xvalue("Shift L/R",temp_string_,0,temp_string2_)
  sprint(temp_string2_,"chrange(%d,%d)",attrnum,-1)
  xmenu("Other")
  xbutton("Clear/Set to G0",temp_string2_)
  sprint(temp_string2_,"viewplot(%d)",attrnum)
  xbutton("View=plot",temp_string2_)
  sprint(temp_string2_,"setrange(%d,0,tstop,-90,50)",attrnum)
  xbutton("0,tstop,-90,50",temp_string2_)
  xbutton("Clean graph list","collapsegrs()")
  sprint(temp_string2_,"attrpanl(%d)",attrnum)
  xbutton("Attributes",temp_string2_)
  xmenu()
  xpanel()
  for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
}

//* remgrs() gets rid of all of the graphs (called from attrpanl)
proc remgrs () { local ii,cnt
  if (isobj(graphItem,"Graph")) { graphItem.unmap graphItem = nil }
  panobj = panobjl.object($1)
  for ltr (XO,panobj.glist) XO.unmap()
  panobj.glist.remove_all
}

//* collapsegrs () take off of glist graphs that have been closed on screen
proc collapsegrs () { local ii
  if (numarg()==0) { panobj = panobjl.object(0)
  } else { panobj = panobjl.object($1) }
  for (ii=panobj.glist.count-1;ii>=0;ii-=1) {
    if (panobj.glist.object(ii).view_count() == 0) { 
      panobj.glist.remove(ii)
    }
  }
}

//* viewplot() set the world for each graph correctly
proc viewplot () { local cnt,ii,flag,sz1,sz2,sz3,sz4
  if (numarg()==2) flag=$2 else flag=-1
  if (flag==0) { sz1=sz3=1e10 sz2=sz4=-1e10 }
  panobj = panobjl.object($1)
  for ltr(XO,panobj.glist) {
    XO.size(&x[0])
    if (flag==0) { 
      if (x[0]<sz1) sz1=x[0]
      if (x[1]>sz2) sz2=x[1]
      if (x[2]<sz3) sz3=x[2]
      if (x[3]>sz4) sz4=x[3]
    } else if (flag==9) {
      XO.size(0,tstop,x[2],x[3])
    } else { XO.size(x[0],x[1],x[2],x[3]) }
  }
  if (flag==9) { panobj.size[0]=0 panobj.size[1]=tstop }
  if (flag==0) for ltr(XO,panobj.glist) XO.size(sz1,sz2,sz3,sz4)
}

//* nvwall() changes the size of the graphs
proc nvwall () { local cnt,ii,sz1,sz2,sz3,sz4,wd,ht
  panobj = panobjl.object($1)
  if (numarg()==3) { wd=$2 ht=$3 } else { wd=panobj.vsz[0] ht=panobj.vsz[1] }
  cnt = panobj.glist.count()
  for (ii=cnt-1;ii>=0;ii=ii-1) { 
    if (panobj.glist.object(ii).view_count()==0) {panobj.glist.remove(ii)
    } else {
      sz1 = panobj.glist.object(ii).size(1)
      sz2 = panobj.glist.object(ii).size(2)
      sz3 = panobj.glist.object(ii).size(3)
      sz4 = panobj.glist.object(ii).size(4)
      panobj.glist.object(ii).unmap()
      panobj.vloc = panobj.vloc+panobj.vjmp
      if (panobj.vloc > 700) { panobj.vloc = 0 }
      panobj.glist.object(ii).view(sz1,sz3,sz2-sz1,sz4-sz3,0,panobj.vloc,wd,ht)
    }
  }
}

//* geall() erases all of the graphs
proc geall () { local cnt,ii
  panobj = panobjl.object($1)
  cnt = panobj.glist.count()
  for ii=0,cnt-1 { 
    panobj.glist.object(ii).erase_all()
  }
}

//* lblall(attrnum,label,#,xloc,yloc) put label on all of the graphs
// arg3 tells which single graph to put it on
proc lblall () { local cnt,ii,min,max,attrnum,lx,ly
  if (numarg()==0) { printf("lblall(attrnum[,loc])\n")  return }
  attrnum = $1 panobj = panobjl.object(attrnum)
  cnt = panobj.glist.count()
  if (numarg()>2) { min=max=$3 } else { min=0 max=cnt-1 }
  if (numarg()==5) { lx=$4 ly=$5 } else { lx=0.1 ly=0.8 }
  if (numarg()>1) { if (sfunc.len($s2)>0) { temp_string_ = $s2
  }} else if (attrnum==0) { temp_string_ = comment 
  } else sprint(temp_string_,"%s",panobjl.object(0).comment)
  for ii=min,max { 
    panobj.glist.object(ii).color(panobj.color)
    panobj.glist.object(ii).label(lx,ly,temp_string_)
    // if (attrnum!=0&&ii<panobj.llist.count()) panobj.glist.object(ii).label(panobj.llist.object(ii).name)
  }
}

//* relbl() put appropriate label on all of the graphs
proc relbl () { local cnt,ii,min,max,attrnum,lx,ly
  if (numarg()==0) { printf("relbl(attrnum[,str])\n")  return }
  attrnum = $1 panobj = panobjl.object(attrnum)
  cnt = panobj.glist.count()
  if (numarg()==4) { lx=$3 ly=$4 } else { lx=0.1 ly=0.8 }
  if (numarg()>1) panobj.glist.object(0).label($s2)
  for ltr2(XO,YO,panobj.glist,panobj.llist) {
    XO.color(0)
    if (attrnum==0) XO.label(0.,.9,YO.var) else XO.label(0.,.9,YO.name) 
    XO.color(panobj.color)
    XO.label(lx,ly,YO.vec.label)
  }
}

//* iterators for printlist and files
//** rvtr() read vector iterator
// usage 'for rvtr(vec,#) XO.vec.printf' where # is attrpanl#
// not debugged for presence of tvec in cvode
iterator rvtr () { local i,flag,s4flag
  if (numarg()>=3) {$&3=0} else {i1 = 0}
  if (numarg()==4) s4flag=1 else s4flag=0
  attrnum=$2
  panobj=panobjl.object(attrnum)
  for i = 0, panobj.entries - 1 {
    tstr=panobj.llist.object(i).name
    if (s4flag) {if (strm(tstr,$s4)) flag=1 else flag=0}
    if (flag) {
      rv_readvec(attrnum,i,$o1)    
      iterator_statement
      if (numarg()>=3) { $&3+=1 } else { i1+=1 }
    }
  }
}

//** vrdr(attrnum,"regexp"[,flag,&y,indv]) -- used for panobj.llist
// similar to rvtr() but does interpolation
// use regexp eg for prdr("PYR2.8") { ... }
// optional flag to NOT interpolate
// indv gives set of llist nums to search through (can use with "" as regexp)
// sets mso[v1],mso[tv1],mso[v2],mso[tv2]
iterator vrdr () { local flag,ipt,attrnum
  attrnum=$1
  if (numarg()>=3) flag=$3 else flag=0
  if (numarg()>=4) {$&4=0} else {i1 = 0}
  v1=tv1=v2=tv2=ipt=allocvecs(5) tv1+=1 v2+=2 tv2+=3 ipt+=4
  ulv()
  panobj=panobjl.object(attrnum)
  if (numarg()==5) mso[ipt].copy($o5) else {
    mso[ipt].indgen(0,panobj.llist.count-1,1) }
  if (cvode_status()==0) mso[tv1].indgen(0,tstop+0.01,printStep)
  if (!flag) {
    if (tvec.max != tstop) printf("WARNING: tvec set?: %g %g\n",tstop,tvec.max)
    mso[tv2].copy(tvec)  // tvec must be preassigned for interpolation
  }
  tmpfile.ropen(panobj.filename)
  for i1=0,panobj.llist.count-1 {
    if (mso[ipt].contains(i1)) {
      XO=panobj.llist.object(i1)
      if (strm(XO.name,$s2)) {
        tmpfile.seek(XO.loc)
        if (use_lvardt_) mso[tv1].vread(tmpfile) 
        mso[v1].vread(tmpfile)
        tstr=XO.name
        mso[v2].resize(0)
        if (!flag) mso[v2].interpolate(mso[tv2],mso[tv1],mso[v1])
        iterator_statement
        panobj=panobjl.object(attrnum) // make sure is still set
        if (numarg()>=4) { $&4+=1 }
      }    
    }
  }
  dealloc(v1)
}

//** prdr() -- used for printlist
// use regexp eg for prdr("PYR2.8") { ... }
// optional flag to NOT interpolate
// ind=panobj.tvec, vec1=original trace, vec interpolated on tvec
// note that i1 here gives list number, not sequential
iterator prdr () { local flag
  if (numarg()>1) flag=$2 else flag=0
  if (numarg()==3) {$&3=0} else {i1 = 0}
  v1=tv1=v2=tv2=allocvecs(4) tv1+=1 v2+=2 tv2+=3
  if (!flag) {
    if (tvec.max != tstop) printf("WARNING: tvec set?: %g %g\n",tstop,tvec.max)
    mso[tv2].copy(tvec)  // tvec must be preassigned for interpolation
  }
  for i1=0,printlist.count-1 {
    XO=printlist.object(i1)
    if (strm(XO.var,$s1)) {
      // print XO.var
      tstr=XO.var
      mso[v1].copy(XO.vec) mso[tv1].copy(XO.tvec) 
      if (!flag) mso[v2].interpolate(mso[tv2],XO.tvec,XO.vec)
      iterator_statement
      if (numarg()==3) { $&3+=1 }
    }    
  }
  dealloc(v1)
}

//* grall() graphs all of the lines from the file
// use vector $o2 as indices for vectors (see tposvec)
proc grall () { local attrnum,cnt,ii,min,max,gr,skip,iskp,vind,sind,a
  if (numarg()==0) {printf("grall(attrnum[,min,max,remote,gr_offset,skipgr,iskp]): graph vectors.\n")
    return }
  attrnum=$1  sind=vind=0
  panobj = panobjl.object(attrnum)
  if (attrnum == 0) cnt = printlist.count() else cnt = panobj.llist.count()
  min=0 max=cnt-1
  // will reset max if is vector with numarg()==2
  // with 2 args, vector $o2 gives indices for vectors (see tposvec)
  if (numarg()>=2) {
    if (argtype(2)==0) {
      if (numarg()>2) { min=$2 max=$3 }
    } else { // a vector of indices or a string for prdr/vrdr
      a=allocvecs(1)
      if (argtype(2)==1) { vind=1 mso[a].copy($o2) } else sind=1
    }
  }
  if (numarg()>3) { panobj.super=1 panobj.remote=$4 }
  if (numarg()>4) gr=$5 else gr=0
  if (numarg()>5) skip=$6 else skip=1
  if (numarg()>6) iskp=$7 else iskp=1
  if (iskp==0) iskp=1 if (skip==0) skip=1
  if (panobj.super==1 && panobj.remote==attrnum && panobj.glist.count==0) { 
    remgrs(attrnum)
    print "Creating plot"
    skip=0
    newPlot(0,tstop,-100,100) panobj.glist.append(graphItem)}
  if (panobj.super==0 && panobj.glist.count==0) panobj.size[1]=0
  if (sind) { 
    if (attrnum==0) for prdr($s2,1) mso[a].append(i1) else {
      for vrdr(1,$s2,1) mso[a].append(i1) }
    vind=1
  }
  if (vind) { min=0 max=mso[a].size-1 }
  for (ii=min;ii<=max;ii+=iskp) {
    if (panobj.super == 1) { 
      if (gr >= panobjl.object(panobj.remote).glist.count()) break
      graphItem = panobjl.object(panobj.remote).glist.object(gr) 
      gr=gr+skip
    }
    if (vind) rv(attrnum,mso[a].x[ii]) else rv(attrnum,ii)
  }
  if (vind) dealloc(a)
}

// tposvec(rows,cols): generate the indices for a transposed matrix of rows x cols
proc tposvec () { local rows,cols,i,j
  rows=$2 cols=$3
  $o1.resize($2*$3)
  for (i=0;i<rows;i+=1) for (j=0;j<cols;j+=1) $o1.x[j*rows+i]=i*cols+j
}

// fliptb(rows,cols): generate the indices for a transposed matrix of rows x cols
proc fliptb () { local rows,cols,i,j,p
  rows=$2 cols=$3
  if ($o1.size != $2*$3) {print "Wrong size vector in fliptb()" return}
  p = allocvecs(1) mso[p].resize(rows)
  for (j=0;j<cols;j+=1) {
    mso[p].copy($o1,j*rows,(j+1)*rows-1)
    mso[p].reverse
    $o1.copy(mso[p],j*rows)
  }
}

//* setrange() sets the range
// setrange(attrnum,x0,x1,y0,y1)
proc setrange () { local i,ii
  if (numarg()==0){print "setrange(attrnum,x0,x1,y0,y1)\n setrange(attrnum,3) erases axes" return}
  panobj = panobjl.object($1)
  if (numarg()==1) { for ltr(XO,panobj.glist) XO.size(0,tstop,-100,50)
  } else if (numarg()==2) { for ltr(XO,panobj.glist) XO.xaxis(3)
  } else if (numarg()==3) { for ltr(XO,panobj.glist) XO.size(0,tstop,$2,$3)
  } else {
    panobj.size[0]=$2
    for ltr(XO,panobj.glist) XO.size($2,$3,$4,$5)
    for i=2,5 panobj.size[i-2]=$i
  }
  for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
}

//* grransel() -- graph range select
proc setgrransel () { local attrnum
  attrnum=$1
  panobj = panobjl.object(attrnum)
  for ltr(XO,panobj.glist) { 
    XO.menu_remove("REVIEW")
    sprint(tstr,"proc p%d%d(){grransel($1,$2,$3,$4,%d,%d,%s)}",attrnum,i1,attrnum,i1,XO)
    execute1(tstr)
    sprint(tstr,"p%d%d",attrnum,i1)
    XO.menu_tool("REVIEW", tstr)
    XO.exec_menu("REVIEW")
  }
}
  
//** grransel(): CTL-hit == Crosshair
//               SHT-hit == resize
//               hit-drag-release == show in square
//               SHT-hit-drag-release == show new thing there
// Type: press (2), drag (1), release (3)
// Keystate: META-SHT-CTL eg 101=5 is META-CTL
grrcnt=-1
proc grransel () { local type, x0, y0, keystate, ii, attrnum, gr
  type=$1 x0=$2 y0=$3 keystate=$4 attrnum=$5 gr=$6
  graphItem=$o7 // = panobj.glist.object(gr)
  panobj=panobjl.object(attrnum)
  if (keystate==1 && type==2) { graphItem.exec_menu("Crosshair") // CTL-MOUSE-1
  } else if (keystate==3 && type==3) { 
    print grrcnt
    if (grrcnt>-1) { printf("Graphing %s\n",printlist.object(grrcnt).var)
      graphItem.erase_all()
      rv(attrnum,grrcnt) 
      graphItem.exec_menu("View = plot")
    }
    graphItem.size(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
  } else if (keystate==2 && type==2) { grrcnt=-1
  } else if (keystate==2 && type==1) { 
    x+=1 // slow it down five-fold
    if (x>5) { grrcnt=(grrcnt+1)%printlist.count
      printf("%d: %s\n",grrcnt,printlist.object(grrcnt).var)
      x=0
    }
  } else if (keystate==0 && type==2) { x=x0 y=y0 } else if (keystate==0 && type==3) {
    graphItem.size(x,x0,y,y0) // resize to chosen square
  } 
}

//* chrange() changes range for a set of graphs (called from attrpanl)
luprd=0
proc chrange () { local cnt, flag, ii, sz1, sz2, sz3, sz4
  if (numarg()==2) { flag = $2 } else { flag = -1 }
  panobj = panobjl.object($1)
  cnt = panobj.glist.count()
  for (ii=cnt-1;ii>=0;ii=ii-1) if (panobj.glist.object(ii).view_count() == 0) panobj.glist.remove(ii)
  cnt = panobj.glist.count() // check again after removing any with no views
  if (cnt==0) { for ii=0,3 panobj.size[ii]=0 return }
  // flag -1 means set everything from the first graph
  if (flag==-1) for ii=0,3 panobj.size[ii] = panobj.glist.object(0).size(ii+1)
  if (flag==-2) for ii=0+luprd,1+luprd panobj.size[ii] += panobj.shift // shift right or left
  if (flag==5) { panobj.size[0]=0 panobj.size[1]=tstop } // just set x
  // for each of the graphs
  for ltr(XO,panobj.glist) {
    sz1=XO.size(1) sz2=XO.size(2) sz3=XO.size(3) sz4=XO.size(4)
    if (flag==0) XO.size(panobj.size[0],sz2,sz3,sz4)
    if (flag==1) XO.size(sz1,panobj.size[1],sz3,sz4)
    if (flag==2) XO.size(sz1,sz2,panobj.size[2],sz4)
    if (flag==3) XO.size(sz1,sz2,sz3,panobj.size[3])
    if (flag==-1 || flag==4) XO.size(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
    if ((flag==-2 && !luprd) || flag==5) XO.size(panobj.size[0],panobj.size[1],sz3,sz4)
    if (flag==-2 && luprd) XO.size(sz1,sz2,panobj.size[2],panobj.size[3])
  }
  for ii=0,3 if (panobj.size[ii]==0) panobj.size[ii]=panobj.glist.object(0).size(ii+1)
}

//* rtvec() reads tvec if it exists, returns -1 if it doesn't
// rtvec(attrnum)
func rtvec () { local attrnum,inx,inx2
  attrnum = $1
  panobj = panobjl.object(attrnum)
  if (panobj.tloc > -1) {
    tmpfile.seek(panobj.tloc)
    panobj.tvec.vread(tmpfile)
    return 1
  } else {
    return 0
  }
}

//* rv() reads line of vector file into IV graph via vector
// rv(attrnum,llist_ind1[,llist_ind2])
// rvaltdisp(tvec,vec,name)
func rvaltdisp () { return 0 } // if returns 1 means there is an alternate display for rv
proc rv2 () { }  // stub for manipulating the vectors before graphing
proc rv3 () { }  // stub for manipulating the label
proc rv () { local attrnum,inx,inx2
  // open the file and go to correct position
  if (numarg() == 0) { print "rv(attrnum,ind1,ind2) reads into vrtmp bzw vec" return }
  attrnum = $1
  inx = $2
  if (panobj.printStep>0 && numarg() > 2) { inx2 = $3 } else { inx2 = -1 }
  if (attrnum==0) { gv(inx) return }
  rv_readvec(attrnum,inx,vrtmp)  // will set panobj
  rv2(vrtmp)
  // create a new plot if necessary and set color
  nvplt(vrtmp)
  if (vrtmp.size==0) { // assume this is a spike train in tvec
    ind.resize(panobj.tvec.size) ind.fill(0)
    ind.mark(graphItem,panobj.tvec,"O",panobj.line+4,panobj.curcol)
    // grrtsize()
  } else if (inx2>-1) {
    rv_readvec(attrnum,inx2,vec)
    graphItem.size(0,vrtmp.max,0,vec.max)
    if (numarg() > 3) {
      vec.mark(graphItem,vrtmp,$s4,6,panobj.curcol)
    } else {
      vec.mark(graphItem,vrtmp,"O",6,panobj.curcol)
    }
  } else if (panobj.printStep<0) {
    if (gvmarkflag) {
      if (! rvaltdisp(panobj.tvec,vrtmp,panobj.llist.object(inx).name)) {
        vrtmp.mark(graphItem,panobj.tvec,"O",4,panobj.curcol,panobj.line) 
        graphItem.exec_menu("View = plot")
      }
    } else if (numarg() >= 3) {
      round(vrtmp) // round off this index vector
      vrtmp.mark(graphItem,panobj.tvec,"O",$3,panobj.curcol,panobj.line) 
    } else {
      vrtmp.line(graphItem,panobj.tvec,panobj.curcol,panobj.line) }
  } else {
    vrtmp.line(graphItem,panobj.printStep,panobj.curcol,panobj.line) }
  // graph it and label the graph
  if (sfunc.substr(panobj.filename,"batch")!=-1 || \
      sfunc.substr(panobj.filename,"data")==-1) {
    grvecstr = panobj.filename
    } else { sfunc.tail(panobj.filename,"data",grvecstr) }
  if (sfunc.len(panobj.llist.object(inx).name)>40) {
    grvecstr=panobj.llist.object(inx).name } else {
    sprint(grvecstr,"%s:%s",grvecstr,panobj.llist.object(inx).name) }
  rv3(grvecstr)
  if (panobj.super == 0 && labelm) { graphItem.label(0,0.9,grvecstr)
  } else if (labelm) graphItem.label(0.0,0.95,grvecstr)
}

// rv_readvec(attrnum,index,vec)
// read vector #index from file associated with attrnum into vector vec
proc rv_readvec () { local size,attrnum,inx,ii
  attrnum = $1
  inx = $2
  panobj = panobjl.object(attrnum)
  tmpfile.getname(temp_string_)
  if (strcmp(temp_string_,panobj.filename)!=0 || tmpfile.isopen()==0) {
    if (! tmpfile.ropen(panobj.filename)) { 
      print "ERROR rv() can't read ",panobj.filename return }}
  tmpfile.seek(panobj.llist.object(inx).loc)
  if (panobj.bytes) { 
    if (numarg()==4) { $o3.vread(tmpfile) $o4.vread(tmpfile) } else {
      if (panobj.printStep==-2) { 
        if (! panobj.tvec.vread(tmpfile)) print "rv_readvec tvec READ failure"
      }
      if (!$o3.vread(tmpfile)) print "rv_readvec READ failure"
    }
    if (panobj.segments>1) {
      tmpvec = new Vector($o3.size)
      for ii=1,panobj.segments-1 {
        tmpfile.seek(panobj.llist.object(inx).loc[ii])
        tmpvec.vread(tmpfile)
        $o3.copy(tmpvec,$o3.size)
      }
      tmpvec = nil
    }
  } else {
    tmpfile.scanstr(temp_string_) // get rid of '//'
    size = tmpfile.scanvar()
    tmpfile.scanvar() // get rid of the seek number
    $o3.scanf(tmpfile,size)
  }
}

//* rvec(attrnum,num[,vec]) writes to vec, or contents of rvvec_name or
//  to vector of same name if rvvec_name is empty
proc rvec () { local flag,ln,on
  flag=0 ln=$1
  if (sfunc.len(rvvec_name)==0) flag=1
  if (numarg()<2) on=hoc_ac_ else on=$2
  if (numarg()>2) sprint(rvvec_name,"%s",$o3)
  if (sfunc.len(rvvec_name)==0) rvvec_name=panobjl.object(ln).llist.object(on).name 
  printf("Copying %s to %s\n",panobjl.object(ln).llist.object(on).name,rvvec_name) 
  sprint(temp_string_,"rv_readvec(%d,%d,%s)",ln,on,rvvec_name)
  if (flag) rvvec_name="" // clear it again
  if (! execute1(temp_string_)) print "ERROR: Declare target as a vector"
  if (numarg()==4) $o4.copy(panobj.tvec)
}

//* rvl() reads line of vector file into IV graph via vector
// rvl(attrnum,name,pos[,pos2,pos3,...])
proc rvl () { local i
  // open the file and go to correct position
  panobj=panobjl.object($1)
  tmpfile.getname(temp_string_)
  if (strcmp(temp_string_,panobj.filename)!=0 || tmpfile.isopen()==0) {
    tmpfile.ropen(panobj.filename) }  // only open if necessary
  if (tmpfile.isopen==0) { printf("ERROR: %s not found.\n",panobj.filename)
      return }
  if (numarg() == 3) { 
    tmpfile.seek($3)
    tmpfile.gets(temp_string_) // throw away line
    vrtmp.vread(tmpfile)
  } else {
    tmpvec = new Vector()
    for i=3,numarg() {
      tmpfile.seek($i)
      tmpvec.vread(tmpfile)
      vrtmp.copy(tmpvec,vrtmp.size)
    } 
  }
  tmpvec = nil
  nvplt(vrtmp)
  vrtmp.line(graphItem,panobj.printStep,panobj.curcol,panobj.line)
  // graph it and label the graph
  if (sfunc.substr(panobj.filename,"batch")!=-1) { grvecstr = panobj.filename
  } else { sfunc.tail(panobj.filename,"data",grvecstr) }
  sprint(grvecstr,"%s:%s",grvecstr,$s2)
  if (panobj.super==0 && labelm) { graphItem.label(0,0.9,grvecstr)
  } else if (labelm) graphItem.label(grvecstr)
}

//* read_file(file,cols[,length]): read multicolumn file
//  see /u/billl/nrniv/jun/tidata/proc.hoc for improved version
func read_file () { local ii,cols,pt,length
  if (numarg()==0) { print "\tread_file(\"file\",cols)"
    print "\t(must set tstop and printStep.)"
    return 0
  }
  panobjl.object(0).printStep = use_lvardt_ = using_cvode_ = 0
  if (cvode_status()!=0) print "WARNING: Turn off cvode."
  if (numarg()==3) { length = $3 } else { length=tstop/printStep }
  cols = $2
  if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return 0}
//  printlist.remove_all()
  tmpfile.scanstr(temp_string_)  pt = 0
  // skip over a comment line; note that this will skip extra line if comment line is
  // just one word long
  while (sfunc.head(temp_string_,"[^-+0-9.e]",temp_string2_) != -1) {
    tmpfile.gets(temp_string_)  // first word in line was not a number so next line
    pt = tmpfile.tell()         // location at next line
    tmpfile.scanstr(temp_string_) // get first word here
    print temp_string2_
  }
  for ii=1,cols { // pick up all of the columns
    tmpfile.seek(pt)
    vrtmp.scanf(tmpfile,length,ii,cols)
    new_printlist_item("col",ii,vrtmp)
  }
  return 1
}

//* read_rfile(file): read multirow file
//  use col2row to transpose columnar file first
proc read_rfile() { local num
  if (numarg()==0) { print "\tread_rfile(\"file\")" return }
  if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return}
  printlist.remove_all()
  while (tmpfile.scanstr(temp_string_) != -1) {  // read lines
    num = tmpfile.scanvar() // pick up number of items in col
    vrtmp.scanf(tmpfile,num)
    new_printlist_item(temp_string_,vrtmp)
  }
}

// restore_printlist() restores the plist from a file in an attrnum
proc restore_printlist () { local cnt,ii,attrnum,savlvar
  printlist.remove_all
  attrnum=$1
  panobj=panobjl.object(attrnum)
  if (panobj.printStep == -2 && tvec.size==0) { print "Set tvec for interpolation" return }
  panobjl.object(0).printStep=tvec.x[1]-tvec.x[0]
  print "Setting printStep to ",tvec.x[1]-tvec.x[0]
  if (numarg()==1) for vrdr(attrnum,tstr) {
    vite= new vitem(tstr,mso[v2].size)
    vite.vec.copy(mso[v2])
    printlist.append(vite)
  } else for vrdr(attrnum,$s2) {
    vite= new vitem(tstr,mso[v2].size)
    vite.vec.copy(mso[v2])
    printlist.append(vite)
  }
  if (use_lvardt_) tstop=panobj.tvec.max
}

//* sgv() print out spikes from IF recordings like spkt()
proc sgv () {  local cl
  if (numarg()==1) cl=$1 else cl=1
  sgv1()
  nvplt(ind)
  panobj.curcol=cl
  // g.erase_all()
  vec.mark(graphItem,ind,"O",panobj.line+4,panobj.curcol,4)
  graphItem.size(0,ind.max+1,0,tstop)
}

proc sgv1 () { 
  revec(ind) revec(vec)
  for ltr(XO,printlist) if (XO.vec.size==0) {
    szt=XO.tvec.size
    if (szt>0) {
      szi=ind.size 
      vec.append(XO.tvec)
      ind.resize(szi+szt)
      ind.fill(i1,szi,szi+szt-1)
    }
  }
}

//* gv(vnum) graphs vector
proc gv () {  local inx,clr,lin
  ulv()
  inx=-1
  panobj = panobjl.object(0)
  lin=panobj.line clr=panobj.color
  if (numarg()==0) { inx = hoc_ac_ } else { 
    if (argtype(1)==0) inx = $1
    if (argtype(1)==2) {
      for ltr(XO,printlist) if (strm(XO.var,$s1)) inx=i1
      if (inx==-1) {print $s1," not found" return }}
  }
  if (numarg()>=2) { clr=$2 }
  if (numarg()>=3) { lin=$3 }
  if (use_lvardt_) { panobj.tvec = printlist.object(inx).tvec }
  XO = printlist.object(inx).vec
  rv2(XO)
  if (XO.size==0) { // assume that this is spk trace
    if (panobj.tvec.size==0) { printf("\tNO SPIKES IN %s\n",printlist.object(inx).var)
    } else {
      nvplt(panobj.tvec)
      ind.resize(panobj.tvec.size) ind.fill(1)
      ind.mark(graphItem,panobj.tvec,"O",lin,clr)
      // grrtsize()
    }
  } else { 
    nvplt(XO)
    if (using_cvode_) {
      if (gvmarkflag) { XO.mark(graphItem,panobj.tvec,"O",lin,clr) 
      } else {          XO.line(graphItem,panobj.tvec,clr,lin) }
    } else {
      if (gvmarkflag) { XO.mark(graphItem,printStep,"O",lin,clr)
      } else {          XO.line(graphItem,printStep,clr,lin) }
    }
    if (labelm) {
      grvecstr=printlist.object(inx).var 
      rv3(grvecstr) graphItem.label(0.,0.9,grvecstr) 
    }
  }
}

proc gvmt () { gvmarkflag=-(gvmarkflag-1) printf("gv Mark: %d\n",gvmarkflag) }
proc llist () { 
  if (numarg()>=1) { 
    if ($o1.count==0) {print "empty list" return}
    if (isobj($o1.object(0),"String2")) {
      for ltr(XO,$o1) print XO.s,XO.t
    } else {
      for ltr(XO,$o1) print XO.s 
    }
  } else if (eqobj(panobj,panattr[0])) {
    for ltr(XO,printlist) print i1,XO.var 
  } else {
    for ltr(XO,panobj.llist) print i1,XO.name
  }
}

//* dispspks() display spike times
proc dispspks () { local attrnum,n
  attrnum = $1  n=0
  panobj=panobjl.object(attrnum)
  if (panobj.super == 1) { 
    graphItem = panobj.glist.object(panobj.glist.count-1)
  } else {
    newPlot(0,1,0,1)
    panobj.glist.append(graphItem)
  }
  if (attrnum==0) {for ltr(XO,printlist) dispspks2(XO.var,XO.tvec,i1)
  } else for ltr(XO,panobj.llist) {
    rv_readvec(attrnum,i1,ind) // ind is scratch here since info in tvec
    dispspks2(XO.name,panobj.tvec,i1) 
  }
  grrtsize()
}

// $s1 name, $o2 tvec, $3 n
proc dispspks2 () { local n,col
  n=$3
  col = panobj.curcol
  if (sfunc.substr($s1,"_spks")) {
    if ($o2.size>0) {
      ind.resize($o2.size) ind.fill(n)
      if (sfunc.substr($s1,"NetStim")!=-1) col+=1
      ind.mark(graphItem,$o2,"O",panobj.line+4,col)
    }
  }
}

//** grrtsize() use view=plot and then pad a little
proc grrtsize () { local h,w,frac
  if (numarg()>=1) tmpobj=$o1 else tmpobj=graphItem
  if (numarg()>=2) frac = $2 else frac=.05
  tmpobj.exec_menu("View = plot")
  tmpobj.size(&x)
  w=frac*(x[1]-x[0])  h=frac*(x[3]-x[2])
  x[0]-=2*w x[1]+=w x[2]-=4*h x[3]+=h // need extra padding on bottom
  tmpobj.size(x[0],x[1],x[2],x[3])
}

//* gvv() like gv() but give it vector statt vnum
proc gvv () {  local inx
  nvplt($o1)
  if (numarg()==1) {
    $o1.line(graphItem,printStep,panobj.curcol,panobj.line)
  } else { 
    $o1.line(graphItem,$o2,panobj.curcol,panobj.line)
    graphItem.size($o2.min,$o2.max,$o1.min,$o1.max)
  }
}

//* ge() erases IV graph
proc ge () { if (numarg()==0) graphItem.erase_all() else g[$1].erase_all }

//* pvall() dumps all vectors to output_file
// Save logic:
// 1) Interactive mode: you're watching simulations while printing out
// data.  You see something you like and save it - the runnum in the
// index file then corrsponds to the number on the data file, it is
// subsequently augmented
// 2) Batch mode: you're running very long sims and saving directly to
// vector files.  You put together a simulation you want and save it
// immediately rather than waiting for the sim to return (in 1 or 2
// days).  To correspond, the data file (v*) must then be numbered
// 'runnum-dec_runnum'
proc pvall () { 
  sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
  while (tmpfile.ropen(output_file)) { runnum = runnum+1
    printf("%s found, trying %s/v%s.%02d\n",output_file,ddir,datestr,runnum-dec_runnum)
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum) 
  }
  if (numarg()>0) { comment = $s1 // a comment
  } else {
    sprint(temp_string_,"%s.%02d",datestr,runnum-dec_runnum) 
    if (sfunc.substr(comment,temp_string_) == -1) { comment = "" } // clear comment
  }
  printf("Saving to %s\n",output_file)
  pvplist(output_file,comment)
  sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum)
}

// pvplist(file,comment) print out the printlist with comment at head
proc pvother () {}  // user can dump other vectors at top with prvec()
proc pvplist () { local inx
  ulv()
  output_file=$s1
  if (! pvplist0()) return // open file(s)
  pvplist1($s2) // print string header
  pvout() 
  tmpfile.close()
  if (newstyle) tf1.close
}

// pvplist0() -- open output_file and ancillary dot file if needed
func pvplist0 () {
  file_with_dot(output_file,temp_string_,temp_string2_) // put .filename into temp_string_
  if (tmpfile.ropen(temp_string_)) { printf("WARNING: removing %s\n",temp_string_)
    sprint(temp_string2_,"rm %s",temp_string_) system(temp_string2_) }
  if (newstyle) {
    if (tmpfile.wopen(temp_string_)==0) { print "Can't open ",temp_string_  return 0}
    if (!isassigned(tf1)) tf1=new File()
    tf1.wopen(output_file)
  } else {
    if (tmpfile.wopen(output_file)==0) { print "Can't open ",output_file  return 0}
  }
  return 1
}

proc pvplist1 () {
  tmpfile.printf("//: %s\n",$s1) // comment
  if (use_lvardt_) {
    tmpfile.printf("//printStep -2\n")
  } else if (using_cvode_) {
    tmpfile.printf("//printStep -1\n")
  } else {
    tmpfile.printf("//printStep %g\n",printStep)
  }
  if (byte_store) tmpfile.printf("//CPU %s\n",uname)
  if (newstyle) tmpfile.printf("//LOC_OK\n")
}

// pvnext() append another printlist set to same file
proc pvnext () { local ii
  if ($1==0) { 
    pvall(comment)
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-1) // decrement back to name
    return
  }
  tmpfile.aopen(output_file)
  pvout()
  printf("Append to %s\n",output_file)
  tmpfile.close()
}

// pvout() called by pvplist() and pvnext(), actually puts out the vecs
proc pvout () {
  ulv()
  if (!use_lvardt_ && using_cvode_) { prvec("tvec",panobjl.object(0).tvec,tvec_bytesize) }
  for ltr(XO,printlist) { // no whitespace allowed
    if (sfunc.len(XO.vec.label)>0) sprint(temp_string_,"%s__(%s)",XO.vec.label,XO.var) else {
      temp_string_=XO.var } 
    if (use_lvardt_==1) if (eqobj(XO.tvec,nil)) {
      print "ERROR: can't save under cvode_local, must recreate printlist\n" 
      return 
    }
    if (byte_store) {
      if (newstyle) {
        tmpfile.printf("//b%d %s %d %d\n",byte_store,temp_string_,XO.vec.size,tf1.tell)
        if (use_lvardt_==1) XO.tvec.vwrite(tf1,tvec_bytesize) 
        XO.vec.vwrite(tf1,byte_store)
      } else {
        tmpfile.printf("//b%d %s %d %d\n",byte_store,temp_string_,XO.vec.size,tmpfile.tell)
        if (use_lvardt_==1) XO.tvec.vwrite(tmpfile,tvec_bytesize) 
        XO.vec.vwrite(tmpfile,byte_store)
        tmpfile.printf("\n")
      }
    } else {
      if (newstyle) { printf("pvout ERR: only does byte_store\n")
      } else {
        tmpfile.printf("// %s %d %d\n",temp_string_,XO.vec.size,tmpfile.tell())
        XO.vec.printf(tmpfile)
      }
    }
  }
}

// prvec(name,vec,byte_flag[,file])  byte_flag=0 means printf
proc prvec () { local bflag
  if (numarg()>3) { tmpfile.aopen($s4) }
  bflag = $3
  if (newstyle) {
    tmpfile.printf("//b%d %s %d %d\n",bflag,$s1,$o2.size,tf1.tell())
    if (bflag==0) {
      $o2.printf(tf1)    
    } else { $o2.vwrite(tf1,bflag) }
  } else {
    tmpfile.printf("//b%d %s %d %d\n",bflag,$s1,$o2.size,tmpfile.tell())
    if (bflag==0) {
      $o2.printf(tmpfile)    
    } else { $o2.vwrite(tmpfile,bflag) tmpfile.printf("\n") }
  }
  if (numarg()>3) { tmpfile.close() }
}

//* pv() dumps a single vector into output_file
proc pv () { local inx
  ulv()
  sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
  if (numarg()==0) { inx = hoc_ac_ } else { inx = $1 }
  printf("Printing %s to %s\n",printlist.object(inx).var,output_file)
  // string_dialog("Name for saved vector",printlist.object(inx).var)
  if (tmpfile.ropen(output_file)) { // file exists already
    if (newstyle) {
      file_with_dot(output_file,temp_string_,temp_string2_) // put .filename into temp_string_
      tmpfile.aopen(temp_string_) tf1.aopen(output_file)
    } else tmpfile.aopen(output_file)
    printf("Appending to %s\n",output_file)
  } else { 
    pvplist0()
    pvplist1(comment)
  }
  if (byte_store) {
    if (use_lvardt_==1) if (eqobj(printlist.object(inx).tvec,nil)) { 
      print "ERROR: can't save under cvode_local, must recreate printlist\n" 
      return 
    }
    if (newstyle) {
      tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(inx).var,\
                     printlist.object(inx).vec.size,tf1.tell())
      if (use_lvardt_==1) printlist.object(inx).tvec.vwrite(tf1,tvec_bytesize)
      printlist.object(inx).vec.vwrite(tf1,byte_store)
    } else {
      tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(inx).var,\
                     printlist.object(inx).vec.size,tmpfile.tell())
      if (use_lvardt_==1) printlist.object(inx).tvec.vwrite(tmpfile,tvec_bytesize)
      printlist.object(inx).vec.vwrite(tmpfile,byte_store)
      tmpfile.printf("\n")
    }
  } else {
    if (newstyle) { printf("ERRQ not implemented\n") return }
    tmpfile.printf("// %s %d %d\n",printlist.object(inx).var,\
                   printlist.object(inx).vec.size,tmpfile.tell())
    printlist.object(inx).vec.printf(tmpfile)
  }
  tmpfile.close()
  if (newstyle) tf1.close
}

//* lpv() calls lpvec from printlist
proc lpv () { local inx
  if (numarg()==0) { inx = hoc_ac_ } else { inx = $1 }
  sprint(temp_string_,"%s.%02d:%s",datestr,runnum-dec_runnum,printlist.object(inx).var)
  lpvec(temp_string_,printlist.object(inx).vec,printStep)
}

//* lpvec(title,vector,printstep) dumps a single vector onto the printer using jgraph
proc lpvec () { local inx,ii
  tmpfile.wopen("lptmp")
  tmpfile.printf("newgraph\nnewcurve pts\n")
  for ii = 0,$o2.size-1 {
    tmpfile.printf("%g ",ii*$3)
    $o2.printf(tmpfile,"%g",ii,ii)
  }
  tmpfile.printf("marktype none\nlinetype solid\ntitle : %s\n",$s1)
  tmpfile.close()
  system("jgraph -P lptmp > lptmp2")
  system("lpt lptmp2")
}

//* phase planes
//** gppl(n1,n2) graph phase planes from printlist
proc gppl () {
  newPlot(0,1,0,1)
  panobjl.object(0).glist.append(graphItem)
  printlist.object($2).vec.line(graphItem,printlist.object($1).vec)
}

//* routines for printing out in sections

//** outvec_init([output_file,comment])
proc outvec_init() { local segs
  if (numarg()>0) { output_file = $s1 } else {
    sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum)
    while (tmpfile.ropen(output_file)) { runnum = runnum+1 // don't allow an overwrite
      sprint(output_file,"%s/v%s.%02d",ddir,datestr,runnum-dec_runnum) }
  }
  if (numarg()>1) { comment = $s2 }
  print "\nOutput to ",output_file
  if (print_flag) { print "WARNING: print_flag=1 --> 0\n"
    print_flag = 0 }
  if (outvecint==0 || outvecint>tstop) {
    printf("WARNING: outvecint being set to tstop\n")
    outvecint = tstop }
  outvect = outvecint
  segs = int(tstop/outvecint)
  if (tstop/outvecint > segs) { segs=segs+1 }
  tmpfile.wopen(output_file)
  if (strcmp(comment,"")!=0) { tmpfile.printf("//: %s\n",comment) }
  tmpfile.printf("//printStep %g\n",printStep)
  tmpfile.printf("//MULTI %d %d\n",printlist.count,segs)
  tmpfile.close()
}

//** outvecs()  : print out the vectors and reset them for recording
proc outvecs () { local ii
  if (t<outvect || outvecint == 0) { return }
  tmpfile.aopen(output_file)
  for ii=0,printlist.count-1 {
    tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(ii).var,t-outvecint,tmpfile.tell())
    printlist.object(ii).vec.vwrite(tmpfile,byte_store)
    tmpfile.printf("\n")
    printlist.object(ii).vec.play_remove()
    sprint(temp_string_,"printlist.object(%d).vec.record(&%s,%g)",\
           ii,printlist.object(ii).var,printStep)
    execute(temp_string_)
  }
  tmpfile.close
  outvect = outvect+outvecint
}

//** outvec_finish () : put out the last section if needed, update the output_file name
proc outvec_finish() {
  if (t > outvect-outvecint+2*dt) {
    tmpfile.aopen(output_file)
    for ii=0,printlist.count-1 {
      tmpfile.printf("//b%d %s %d %d\n",byte_store,printlist.object(ii).var,t-outvecint,tmpfile.tell())
      printlist.object(ii).vec.vwrite(tmpfile,byte_store)
      tmpfile.printf("\n")
    }
    tmpfile.close()
  }
}

//* utility programs (not all used)
gnum=-1
//** nvplt() put up new voltage plot
proc nvplt () { local xs,ys,flag
  if (panobj.super == 0) flag=1 else {
    if (gnum>-1) {
      sprint(tstr,"x=Graph[%d].view_count",gnum)
      if (execute1(tstr,0)) if (x>0) {  // use Graph[gnum] if exists and has views
        graphItem=Graph[gnum] flag=0
      }                                 // else use graphItem if has views
    } else if (isobj(graphItem,"Graph")) if (graphItem.view_count() > 0) { 
      flag=0
    } else { flag=1 }                   // else need new graph
  }
  if (flag) {
    if (panobj.printStep==0) { panobj.printStep=printStep }
    if (panobj.size[1] != 0) { // xmax is set
      newpl(panobj.size[0],panobj.size[1],panobj.size[2],panobj.size[3])
    } else if (panobj.printStep<0) {
      newpl(0,panobj.tvec.max,$o1.min,$o1.max)
    } else {
      newpl(0,$o1.size()*panobj.printStep,$o1.min,$o1.max)
    }
  } else if (gveraseflag) graphItem.erase_all
  if (panobj.color == -1) {
    panobj.curcol += 1
    if (panobj.curcol == 0 || panobj.curcol>7) panobj.curcol = 1 
  } else panobj.curcol = panobj.color
  graphItem.color(panobj.curcol)
  g=graphItem
}

double wvloc[4]
{wvloc[0]=50 wvloc[1]=50 wvloc[2]=800 wvloc[3]=150}
//** newpl()
proc newpl () { local w,h
  if (numarg()==5) newPlot($1,$2,$3,$4) // 5th arg is flag
  if (numarg()==8) {wvloc[0]=$5 wvloc[1]=$6 wvloc[2]=$7 wvloc[3]=$8}
  graphItem = new Graph(0) 
  g=graphItem
  graphItem.xaxis()	// view axis for x and y
  graphItem.view($1,$3,$2-$1,$4-$3,wvloc[0],wvloc[1],wvloc[2],wvloc[3])
  panobj.glist.append(graphItem)
}

//** gs(#) select graph (by setting g and graphItem to this Graph#
proc gs () { if (numarg()==2) { g[$1]=Graph[$2] } else {g=Graph[$1] graphItem=g }}
//** gg() graph vectors and functions
// gg(g[i],vec) gg(vec,step) gg(vec,ind) gg(g,"FUNC","min,max") [color,line,symbol]
proc gg () { local ii,na,a1,a2,a3,newgr,clr,a,b,c,flag,stp
  na=a1=a2=a3=-1  newgr=1  min=0 max=10 stp=0
  clr=panobj.color lne=panobj.line
  na=numarg()  if (na>=1) a1=argtype(1)  if (na>=2) a2=argtype(2)  if (na>=3) a3=argtype(3)
  if (a1==0) ii=$1 else ii=0
  if (isassigned(g[ii])) if (g[ii].view_count>0) newgr=0
  if (newgr) g[ii]=new Graph()
  graphItem=g[ii]
  graphList[0].append(g[ii])  panobj.glist.append(g[ii])
  if (gvmarkflag) tstr="mark" else tstr="line"
  if (na==1 && a1==0) return // gg(#) just put up the graph
  if (na==1 && a1==1) sprint(tstr,"%s.%s(%s,%s",$o1,tstr,g[ii],"1")   // gg(vec)
  if (na==1 && a1==2) flag=2
  if (na==2) { 
    if (a1==0 && a2==1) sprint(tstr,"%s.%s(%s,1",$o2,tstr,g[ii])      // gg(g[i],vec) 
    if (a1==1 && a2==0) sprint(tstr,"%s.%s(%s,%g",$o1,tstr,g[ii],$2)  // gg(vec,step)
    if (a1==1 && a2==1) sprint(tstr,"%s.%s(%s,%s",$o1,tstr,g[ii],$o2) // gg(vec,ind)
  }
  if (na>=3) { 
    if (a2==1 && a3==1) sprint(tstr,"%s.%s(%s,%s",$o2,tstr,g[ii],$o3)   // gg(g[i],vec,ind)
    if (a2==1 && a3==0) sprint(tstr,"%s.%s(%s,%g",$o2,tstr,g[ii],$3)    // gg(g[i],vec,step)
  } 
  if ((na>=2&&a2==2) || flag==2) {
    a=b=c=allocvecs(3) b+=1 c+=2                           // gg(g,"FUNC","min,max")
    if (a3==2) {
      split($s3,mso[c]) min=mso[c].x[0] max=mso[c].x[1] 
      if (mso[c].size==3) stp=mso[c].x[2]
    }
    if (stp==0) stp=(max-min)/200
    mso[a].indgen(min,max,stp) mso[b].copy(mso[a]) 
    sprint(tstr,"%s.%s(%s,%s",mso[b],tstr,g[ii],mso[a])
    if (a2==2) mso[b].apply($s2) else mso[b].apply($s1)
    dealloc(a)
  }
  if (na>=4) { clr=$4 } if (na>=5) { lne=$5 } if (na>=6) { symb=$s6 }
  if (sfunc.len(tstr)>4) {
    if (gvmarkflag) { sprint(tstr,"%s,\"%s\",%d,%d,1)",tstr,symb,lne+5,clr)
    } else { sprint(tstr,"%s,%d,%d)",tstr,clr,lne) }
    execute(tstr)
  }
}

//** remove_spaces(string,scratch) removes spaces and splits on '/'
// ie remove_spaces(temp_string_,temp_string2_)
proc remove_spaces () {
  $s2=""  // clear it out
  while (sfunc.substr($s1," ") != -1) { // still have spaces
    sfunc.tail($s1," ",$s2)
    sfunc.head($s1," ",$s1)
    sprint($s1,"%s%s",$s1,$s2)
  }
  $s2="" // clear again
  if (sfunc.substr($s1,"/") != -1) { // split it up
    sfunc.tail($s1,"/",$s2)
    sfunc.head($s1,"/",$s1)
  }
}

//** dirname(full,path) filname(full,file) splits up path/file
// eg filname("/home/billl/nrniv/thal/params.hoc",temp_string_)
//    temp_string_ => params.hoc
proc dirname () { sfunc.head($s1,"[^/]+$",$s2) }
proc filname () { local ii,cnt
  cnt = 0
  $s2=$s1  while (sfunc.tail($s2,"/",$s2) != -1) cnt += 1
  $s2=$s1  for ii=1,cnt sfunc.tail($s2,"/",$s2)
}

//** file_with_dot(filename,result,scratch): put .filename into result
proc file_with_dot() {
  if (sfunc.substr($s1,"/") == -1) {
    sprint($s2,".%s",$s1)
  } else {
    sfunc.tail($s1,".*/",$s3)
    sfunc.head($s1,"/[^/]+$",$s2)
    sprint($s2,"%s/.%s",$s2,$s3)
  }
}

//** find_secname(variable,result): put secname into result
proc find_secname () { 
  if ((sfunc.head($s1,"\.[_A-Za-z0-9]+$",$s2))==0) { // strip off stuff after terminal .
    printf("grvec.hoc:find_secname ERR: no section found: %s\n",$s1) err() }
  if (    strm($s1,"\.[_A-Za-z0-9]+[(][0-9.]+[)]$")) {  // form eg v(0.5)
    sfunc.head($s1,"\.[_A-Za-z0-9]+[(][0-9.]+[)]$",$s2)
  } else if (isit($s2)) {  // the stem is an obj
    XO.get_loc() // isit sets XO
    sectionname($s2)
    pop_section()
  } else {
    printf("grvec.hoc:f_s ERR0: Can't find sec: %s\n",$s1) err() 
  }
}

//** mkmenu(title,action,proc) makes a menu from printlist
proc mkmenu () { local ii
  xmenu($s1)
  for ii=0,printlist.count-1 {
    sprint(temp_string_,"%s %s",$s2,printlist.object(ii).var)
    sprint(temp_string2_,"%s(%d)",$s3,ii)
    xbutton(temp_string_,temp_string2_)
  }
  sprint(temp_string_,"mkpanel(\"%s\",\"%s\",\"%s\")",$s1,$s2,$s3)
  xbutton("Leave up",temp_string_)
  xmenu()
}

//** mkpanel(title,action,proc) makes a panel from printlist
proc mkpanel () { local ii
  sprint(temp_string_,"%s:%s",simname,$s1)
  xpanel(temp_string_)
  for ii=0,printlist.count-1 {
    sprint(temp_string_,"%s %s",$s2,printlist.object(ii).var)
    sprint(temp_string2_,"%s(%d)",$s3,ii)
    xbutton(temp_string_,temp_string2_)
  }
  xpanel()
}

//** drline(x0,y0,x1,y1,OPT graph or color) 
proc drline () {
  if (numarg()==0) { print "drline(x0,y0,x1,y1,OPT graph)"
    return }
  if (numarg()>4) { 
    if (argtype(5)==0) { panobj.color=$5 
                         if (numarg()>5) panobj.line=$6
    } else {             graphItem = $o5 
                         if (numarg()>5) panobj.color=$6
                         if (numarg()>6) panobj.line=$7      }}
  graphItem.beginline(panobj.color,panobj.line)
  graphItem.line($1,$2)
  graphItem.line($3,$4)
  graphItem.flush()
}

//** seevec(varname,min,max) -- uses a stringmatch to find a particular vector
proc shprl () { 
  if (numarg()==1) {
    print panobjl.object($1).filename
    for ltr(XO,panobjl.object($1).llist) print i1," ",XO.name
  } else for ltr(XO,printlist) print i1," ",XO.var,XO.vec,XO.tvec
}

proc remprl () { local flag
  flag=0
  if (numarg()==2) flag=1 else print "LISTING ONLY; rerun with 2 args to remove"
  for (ii=printlist.count-1;ii>=0;ii-=1) {
    XO=printlist.object(ii)
    if (strm(XO.var,$s1)) if (flag) printlist.remove(ii) else print XO.var
  }
}

//** seevec(regexp,flag)
// flag: 1 savevec, 2 save sections
proc seevec2 () {} // stub
proc seevec () { local min,max,flag,a,b,n
  b=a=allocvecs(2) b+=1
  flag=0
  if (numarg()==2) {
    if (argtype(2)==0) flag=$2
    if (argtype(2)==1) flag=4
  }
  if (numarg()==3) { min=$2 max=$3 flag=2 }
  if (flag==1 || flag==2 || flag==4) clrveclist()
  for ltr(XO,printlist) {
    if (strm(XO.var,$s1)) {
      printf("%d %s: %s/%s\n",i1,XO.var,printlist.object(i1).vec,printlist.object(i1).tvec)
      if (flag==3) seevec2(XO)
      if (flag==1) savevec(XO.vec,XO.tvec)
      if (flag==4) {
        mso[b].interpolate($o2,XO.tvec,XO.vec)
        savevec($o2,mso[b])
      }
      if (flag==2) {
        mso[b].indvwhere(XO.tvec,"()",min,max)
        mso[a].index(XO.vec,mso[b])
        mso[b].where(XO.tvec,"()",min,max)
        savevec(mso[a],mso[b])
      } 
      n+=1
    }
  }
  dealloc(a)
}

//** file_len(fname): retrieve file length; uses global x
func file_len () { 
  sprint(temp_string_,"wc %s",$s1)
  sassign(temp_string_,temp_string_)
  sscanf(temp_string_,"%d",&x)
  return x
}

//** count_substr(str,sub): count occurences of substring in str
func count_substr () { local cnt
  cnt = 0
  while (sfunc.tail($s1,$s2,$s1) != -1) { cnt += 1}
  return cnt
}

// for ltr(XO,panobj.glist) { print XO,XO.view_count }

//** xgetargs(panel_name,command,arg1[,arg2,...],defaults)
// eg xgetargs("Random session","newrand","# of patts","patt size  ","overlap   ","5,33,7")
objref argvl,argv
argvl = new List()
strdef mesg
proc xgetargs () { local i,args
  args=numarg()-3  i=numarg()
  argv = new Vector(args)
  argvl.append(argv)
  argv.resize(0)
  sprint(temp_string_,"argv.append(%s)",$si)
  execute(temp_string_)
  if (argv.size!=args) argv.resize(args)
  xpanel($s1)
  mesg=""  xvarlabel(mesg)
  for i=3,numarg()-1 {
    sprint(temp_string_,"%s.x[%d]",argv,i-3)
    xvalue($si,temp_string_)
  }
  sprint(temp_string_,"xgetexec(\"%s\",%d,%s)",$s2,args,argv)
  xbutton($s1,temp_string_)
  xpanel()
}

proc xgetexec () { local i,args
  args = $2
  if ($o3.size!=args) { mesg="Error-close & relaunch panel" return }
  sprint(temp_string_,"%s(",$s1)
  for i=0,args-2 sprint(temp_string_,"%s%g,",temp_string_,$o3.x[i])
  sprint(temp_string_,"%s%g)",temp_string_,$o3.x[i])
  // print temp_string_
  execute(temp_string_)
}
  
//** procbutt() put up a single proc in a button
proc procbutt () {
  xpanel($s1)
  xbutton($s1,$s1)
  xpanel(500,500)
}

proc prlclr () {
  for ltr(XO,printlist) {
    cvode.record_remove(XO.vec)
  }
  printlist.remove_all
}

//* read the files in dir and add one item to printlist
// see also collect.hoc for batch use
proc dir2pr () { local ix
  printlist.remove_all cvode_local(1) // assuming this
  ix=$1
  for ltr(dir) {
    read_vfile(1,XO.s)
    rv_readvec(1,ix,vrtmp)
    new_printlist_item(panobj.comment,vrtmp,panobj.tvec)
  }
  if (numarg()==3) { pvplist($s2,$s3) read_vfile(1,$s2) }
}

// op([obj,list],num) -- create object pointer
proc op () {
  if (numarg()==1) {             XO=tmpobj.object($1) } else\
  if (numarg()==2) { tmpobj=$o1  XO=tmpobj.object($2) } else\
  if (numarg()==3) { tmpobj=$o2 $o1=tmpobj.object($3) }
}

Loading data, please wait...