#!/bin/sh
#
# gensspp - generate a start-stop analysis polar plot file
#
# Usage:  gensspp [-g gifopt] [-cpval] [-cw] [-rnum] [-nnum] [-s[b]] [-tst,en] \
#	    [-xp#] [-yp#] [-ymc] [-yw#] [-ffps] runfile xwfnum ywfnum [outname]
#  or	  gensspp [options] -a[n[g]] xwfnum ywfnum runfile ...
#
# where:  -g		specifies that you want HPGL plotfile converted to GIF
#			this can be followed by options to hpgl2gif if desired,
#			and if valid hpgl2gif options are given without -g, the
#			-g is assumed
#	  -c[pval]	specifies circular statistics, with optional p values
#			(comma-separated, default is no circular stats)
#	  -cw		specifies a clockwise polar plot, with 0 at the top
#	  -rnum		specifies a number of samples to be taken at random
#			from the generated data
#	  -nnum		specifies the number of samples (cycles) to be taken
#			from the start of the generated data
#			(when both -r and -n are specified, the -r option should
#			specify a smaller number, and that number of samples is
#			taken at random from the first n cycles)
#	  -s		specifies that spike positions, rather than burst start
#			times, are plotted for the Y-axis waveform number
#	  -sb		specifies that several burst positions per cycle, not
#			just the 1st, are plotted for the Y-axis waveform number
#	  -tst,en	specifies the start and end of the analysis range
#			(default is taken from analysis parameters, or all)
#	  -xp#		specifies the pen number for axes and labels
#			(default is 1 or black for GIF output)
#	  -yp#		specifies the pen number for data
#			(default is 1 or blue for GIF output)
#	  -ymc		specifies the data point marker symbol, as for genplot
#			c can be one of ., o, b, s, t, d, x
#			(default is . for a solid filled circle)
#	  -yw#		specifies the width in mm for data point marker symbols
#			(default is 2 mm)
#	  -ffps		specifies "frame" rate, in plot files per second of data
#			(default is 1 single frame)
#	  -a		specifies that burst start positions are averaged for
#			each specified runfile, and a single average angle is
#			plotted for each run
#			(note that with -a, runfile arguments must be specified
#			after the two waveform number arguments, no outfile
#			argument can be specified, and -f won't work with -a)
#	  -an		specifies that burst start positions are collected and
#			compared across two or more runfiles, using three
#			statistical analyses: Shapiro-Wilk test and QQ plot to
#			test for normality, and Watson-Williams test to compare
#			dispersion patterns
#			(as with -a, runfile arguments must follow wfnums)
#	  -ang		specifies that burst start positions for each runfile
#			are shown on standard output, in CSV format, as angle
#			in degrees, followed by runfile name
#			(as with -a, runfile arguments must follow wfnums)
#	  runfile	specifies a run file name or analysis parameter file
#			(no default, runfile must be specified)
#			You can also use a .csv file of angle data, as output
#			by the -ang option, instead of a run file, to reanalyse
#			extracted angle data later, or process angle data not
#			originating from run files. While this is specifically
#			intended for use with the -an option, you can also use
#			it to plot raw or averaged angles. For the plots, labels
#			will be sparse as most of the labeling info extracted
#			from run files is absent in the .csv file. The two
#			waveform numbers must still be specified, but will be
#			ignored when analysing .csv angle data.
#	  xwfnum	specifies the X-axis waveform number (and cycle W.F.)
#			(no default, W.F. must be specified)
#	  ywfnum	specifies the Y-axis waveform number
#			(no default, W.F. must be specified)
#	  outname	specifies output plot file name
#			(default is std output, or "sspp0000.plt" if -f used)
#			a maximum of 10000 plot files will be generated
#
# Copyright (c) 2002-2017, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

ofilt="replot -s"
outname=
pens=
gifopts=
aopt=
copt=
cwopt=
ropt=
nopt=
sopt=
topt=
xypopt=
ymwopt="-ym."
fopt=
T=/tmp/sspp$$
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-debug|--debug)	shift; T=sspp.out. ;;
	-g)	shift; test -z "$pens" && pens="-yp2" ;;
	-a*)	aopt="$1"; shift ;;
	# probabilities after -c are optional...
	#-c)	shift; copt="-c$1"; shift ;;
	-cw)	cwopt="$1"; shift ;;
	-c*)	copt="$1"; shift ;;
	-r)	shift; ropt="-r$1"; shift ;;
	-r[0-9]*)	ropt="$1"; shift ;;
	-n)	shift; nopt="-n$1"; shift ;;
	-n[0-9]*)	nopt="$1"; shift ;;
	-s*)	sopt="$1"; shift ;;
	-t)	shift; topt="-t$1"; shift ;;
	-t[A-Za-z0-9]*)	topt="$1"; shift ;;
	-[xy]p*)	xypopt="$xypopt $1"; shift ;;
	-y[mw]*)	ymwopt="$ymwopt $1"; shift ;;
	-f)	shift; fopt="-f$1"; shift ;;
	-f[0-9]*)	fopt="$1"; shift ;;
	-G)	gifopts="$gifopts $1"
		test -z "$pens" && pens="-yp2"
		shift ;;
	-[pbhw])
		gifopts="$gifopts $1 '$2'"
		test -z "$pens" && pens="-yp2"
		# use only pen 1 for fast b&w bitmaps...
		case "$1-$2" in -p-bw|-p-wb) pens="-yp1" ;; esac
		shift; shift ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done

case "$#" in
3)	;;
4)	outname="$4" ;;
*)	if [ -z "$aopt" -o "$#" -lt 3 ]
	then
	    echo "Usage:  gensspp [-g gifopt] [-cpval] [-cw] [-rnum] [-nnum] [-s[b]] [-tst,en] \\
	    [-xp#] [-yp#] [-ymc] [-yw#] [-ffps] runfile xwfnum ywfnum [outname]
	or gensspp [options] -a[n[g]] xwfnum ywfnum runfile ...
	or gensspp --help	for detailed usage information" >&2
	    exit 1
	fi
	;;
esac
prmfile="$1"
xwf="$2"
ywf="$3"

case "$aopt" in
-a*)	outname=
	xwf="$1"
	ywf="$2"
	shift; shift
	case "$fopt" in
	-f*)	echo "$0: -f option can't be combined with -a option" >&2
		exit 1
		;;
	esac
	;;
*)	set -- "$prmfile"
	;;
esac

case "$fopt" in
-f*)	# perform animation by generating multiple frames
	case "$outname" in
	"")	outname=sspp0000.plt ;;
	#*.[Pp][Ll][Tt]|*.[Gg][Ii][Ff])
	#	outname=`expr "$outname" : '\(.*\)\....'` ;;
	esac
	fps=`expr "x${fopt}" : 'x-f\(.*\)'`
	rend=`echo "sdutsqqqcvwqyn" |
		TERM=dumb DISPLAY= analysis "$prmfile" 2>/dev/null |
		sed -n 's/^Run length:[ 	]*\([0-9]*\).*/\1/p'`
	case "$rend" in
	[0-9]*) ;;
	*)	echo "$0: Unable to determine length of run '$prmfile'" >&2
		exit 1
		;;
	esac
	case "$topt" in
	-t[Aa][Ll][Ll])
		start=0 end=$rend
		;;
	-t[0-9]*\,[0-9]* | -t[0-9]*\,[Mm][Aa][Xx]*)
		start=`expr "x$topt" : 'x-t\([^,]*\),.*'`
		end=`expr "x$topt" : 'x-t[^,]*,\(.*\)'`
		case "$end" in
		[Mm][Aa][Xx]*)	end=$rend ;;
		esac
		topt=`sysvecho "$topt" | sed 's/^-t/srs/; s/,/s\\\\ne/; s/ *$/s\\\\nqq/; s/[Xx]s/x/'`
		;;
	*)	start=`echo "sdutsqqqasvr                    qyn" |
			TERM=dumb DISPLAY= analysis "$prmfile" 2>/dev/null |
			sed -n 's/^<.*Start of run:[ 	]*\([-0-9.e+]*\).*/\1/p'`
		end=`echo "sdutsqqqasvr                    qyn" |
			TERM=dumb DISPLAY= analysis "$prmfile" 2>/dev/null |
			sed -n 's/^<.*End of run:[ 	]*\([-0-9.e+]*\).*/\1/p'`
		case "$topt" in
		"")	;;
		*)	echo "$0: Invalid time range $topt ignored" >&2
			;;
		esac
		;;
	esac
	case "$start" in
	[0-9]*) ;;
	*)	echo "$0: Unable to determine start of run parameter from '$prmfile'" >&2
		exit 1
		;;
	esac
	case "$end" in
	[0-9]*) ;;
	*)	echo "$0: Unable to determine end of run parameter from '$prmfile'" >&2
		exit 1
		;;
	esac
	echo "Analysing $prmfile..." >&2
	(echo "$outname"
	 sysvecho "sdutsqqqw$xwf\nec/dev/stdout\nyqqqyn" |
		TERM=dumb DISPLAY= analysis "$prmfile" 2>/dev/null |
		sed -n 's/^\([-0-9.e+]*\), *\([-0-9.e+]*\) *$/\1|\2/p'
	) |
	  sed -e 's/^[^.]*$/&.plt/' \
	      -e 's/^.*\/[^.]*$/&.plt/' \
	      -e 's/^\(.*[^0-9]\)\([0-9][0-9]*\)\([^\/]*\.[A-Za-z]*\)$/\1|\2|\3/' \
	      -e 's/^\([^|]*[^0-9]\)\(\.[A-Za-z]*\)$/\1|0000|\2/' |
	  awk -F'|' 'NR == 1 {
		start='"$start"'; end='"$end"'; fps='"$fps"'; rend='"$rend"'
		xypopt="'"$xypopt"'"; ymwopt="'"$ymwopt"'"
		pens="'"$pens"'"; gifopts="'"$gifopts"'"
		copt="'"$copt"'"; ropt="'"$ropt"'"; nopt="'"$nopt"'"; sopt="'"$sopt"'"
		prmfile="'"$prmfile"'"; xwf="'"$xwf"'"; ywf="'"$ywf"'"
		outpref=$1; outnum=$2; outsuff=$3
		ndig = length(outnum)
		if (pens != "") sub(/\.gif/, ".plt", outsuff)
		outfmt = outpref "%0" ndig "d" outsuff
		giffmt = outfmt
		sub(/\.[A-Za-z]*$/, "", giffmt)
		mkgiffmt = "hpgl2gif " gifopts " \"" outfmt "\" > \"" giffmt ".gif\"\n"
		if (end > rend)
			end = rend
		printf("'"$0"' %s %s %s %s %s %s %s -t%g,%g \"%s\" %s %s \"", copt, ropt, nopt, sopt, pens, xypopt, ymwopt, start, end, prmfile, xwf, ywf)
		printf(outfmt, outnum)
		printf("\" || exit\n")
		printf("sysvecho \"LT;\" >> \"" outfmt "\"\n", outnum)
		if (pens != "")
		    printf(mkgiffmt, outnum, outnum)
		sub(/[0-9.e+].*/, "", copt)
		nb = 0
	    }
	    NR > 1 {
		bstart[nb] = $1; bend[nb] = $2; ++nb
	    }
	    END {
		bn = -1
		for (i = 1; i < 10000 && start+i/fps <= end; i++) {
		    printf("cat \"")
		    printf(outfmt, outnum)
		    printf("\" > \"")
		    printf(outfmt, outnum + i)
		    printf("\"\n")
		    while (bn < nb-2 && bstart[bn+1] <= start+i/fps)
			++bn
		    if (bn >= 0 && bn < nb-1) {
			printf("'"$0"' %s %s -xp0 -yp4 -t", copt, sopt)
			s = bstart[bn] - 0.01
			e = bstart[bn+1] + 0.01
			if (s < 0.0)
				s = 0
			printf("%g,%g", s, e)
			printf(" \"%s\" %s %s >> \"", prmfile, xwf, ywf)
			printf(outfmt, outnum + i)
			printf("\"\n")
			printf("sysvecho \"PU5580,7270;LO13;DR1,0;LB%g-%g s, cycle %d/%d\003;\" >> \"", bstart[bn], bstart[bn+1], bn+1, nb-1)
			printf(outfmt, outnum + i)
			printf("\"\n")
		    }
		    if (pens != "") {
			printf(mkgiffmt, outnum + i, outnum + i)
			printf("rm -f \"" outfmt "\"\n", outnum + i)
		    }
		}
		if (pens != "")
		    printf("rm -f \"" outfmt "\"\n", outnum)
	    }' | sh 2>&1 |
		sed '/^Analysing.*\.\.\./d; /^ppmtogif: computing colormap.../d' |
		uniq -c |
		sed 's/^      1 //; s/^  *\([0-9]*\) \(.*\)/\2 (\1 times)/' >&2
	exit
	;;
esac

ascript=${T}a
anafile=${T}b
ststfile=${T}c
diags=${T}d
extras=${T}e
case "${T}" in
/tmp/*)	trap "rm -f ${T}[a-e]" 0	# cleanup on exit
	trap "exit 1" 1 2 3 15		# exit, & cleanup, if killed
	;;
esac

case "$pens" in
"")	;;
*)	ofilt="$ofilt | hpgl2gif $gifopts" ;;
esac

case "$topt" in
"")	;;
-t[Aa][Ll][Ll])
	topt="srs0\nemax\nqq"
	;;
-t[0-9]*\,[0-9]* | -t[0-9]*\,[Mm][Aa][Xx]*)
	topt=`sysvecho "$topt" | sed 's/^-t/srs/; s/,/s\\\\ne/; s/ *$/s\\\\nqq/; s/[Xx]s/x/'`
	;;
*)	echo "$0: Invalid time range $topt ignored" >&2
	topt=
	;;
esac

case "$sopt" in
-sb*)
	sysvecho "agwd${topt}scw${xwf}\nqlwn${ywf}\naYqqmbd0fNvYscNqqqgnYqdnx\\\\n\nqqb\ncvwqyn" > $ascript
	xscale=360
	;;
-s*)
	sysvecho "agavp${topt}scw${xwf}\nqswn${ywf}\nqqgnYqdnx\\\\n\nqqb\ncvwqyn" > $ascript
	xscale=360
	;;
*)
	sysvecho "as${topt}scw${xwf}\nqmsxw${xwf}\nqyw${ywf}\nqcyqqgnYqdny\\\\n\nqqb\nvr                           qyn" > $ascript
	xscale=3.6
	;;
esac

avgs=
for prmfile
do
	echo "Analysing $prmfile..." >&2
	case "$prmfile" in
	*.csv|*.txt)
		case "$aopt" in
		-an*)	a=`cat "$prmfile"`
			avgs="$avgs$a
"
			;;
		-a*)	a=`awk -F, '{x=$1*3.141592654/180;
				     xs[$2]+=cos(x);ys[$2]+=sin(x);n[$2]++};
				END {
				     for(i in ys){
					x=0; if (ys[i]<0) x=360;
					a=atan2(ys[i]/n[i],xs[i]/n[i])*180/3.141592654+x;
					print a ", " i;
				     }
				}' "$prmfile"`
			avgs="$avgs$a
"
			;;
		*)	awk '{$1 /= '"$xscale"';print}' "$prmfile" >> $ststfile
			;;
		esac
		: >> $anafile
		continue ;;
	esac
	if TERM=dumb DISPLAY= analysis $prmfile < $ascript > $anafile 2> $diags
	then
		:
	else
		sed -n -e 's/FATAL ERROR: /analysis: /p' $diags >&2
		echo "$0: analysis failed!" >&2
		exit 1
	fi

	sed -e '1,2d' -e '/^Run:/,$d' -e '/2\.14.*e/d' -e '/^[ 	]*$/d' $anafile > $ststfile
	if [ `wc -l < $ststfile` -le 0 ]
	then
		echo "$0: analysis did not produce any usable numbers." >&2
		exit 1
	fi

	tsamp=`expr "x$nopt" : 'x-n\(.*\)'`
	nsamp=`expr "x$ropt" : 'x-r\(.*\)'`
	test -z "$nsamp" && nsamp=$tsamp
	case "$nsamp" in
	[0-9]*)	sortcol1="+0n" sortcol2="+1n"
		sort $sortcol1 </dev/null 2>/dev/null || sortcol1="-k 1n" sortcol2="-k 2n"
		n=`wc -l < $ststfile | sed -e 's/[ 	]*//g'`
		test -z "$tsamp" && tsamp=$n
		awk 'BEGIN { srand(); }
		     NR<='"$tsamp"' { printf("%g\t%d\t%s\n", rand(), NR, $0); }' $ststfile |
			sort $sortcol1 | head -"$nsamp" | sort $sortcol2 > $extras
		if [ `wc -l < $extras` -gt 0 ]
		then
			sed 's/^[0-9.]*	[0-9]*	//' $extras > $ststfile
		fi
		test $tsamp -lt $n && n=$tsamp
		if [ $nsamp -lt $n ]
		then
			nsamp="`wc -l < $ststfile | sed -e 's/[ 	]*//g'` (of $n)"
		fi
		;;
	esac

	case "$DEBUG" in
	[2-9]*)	(sysvecho "$0: $prmfile X values: "; tr '\012' ' ' < $ststfile; echo "";
		 awk '{s+=$1;
			x=$1*'"$xscale"'*3.141592654/180;
			xs+=cos(x);ys+=sin(x);};
		  END {print "Average X = " s/NR*'"$xscale"' " deg.";
			x=0; if (ys<0) x=360;
			print "Circ. av. X = " atan2(ys/NR, xs/NR)*180/3.141592654+x " deg., r = " sqrt(xs*xs+ys*ys)/NR;}' $ststfile ) >&2 ;;
	esac

	case "$aopt" in
	-an*)	b=`basename "$prmfile" .prm`
		b=`basename "$b" .frm`
		a=`awk '{print $1*'"$xscale"' ", \"'"$b"'\""}' < $ststfile`
		avgs="$avgs$a
"
		;;
	-a*)	a=`genplot -xf$ststfile -xc1 -xs$xscale -xr0,360 -xg90 \
			  -ys0 -yo1 -yr0,1 -yg1 -yt- -c -p -u |
		    sed -n 's/^.*LBa=\([-+0-9.e]*\).*/\1/p'`
		avgs="$avgs$a
"
		;;
	esac
done

case "$aopt" in
-ang*)	echo "$avgs" | sed '/^$/d' ; exit ;;
-an*)	echo "$avgs" | sed '/^$/d; s/, /,/' > $ststfile
	cat > $ascript <<!
library("circular")
x<-read.table("$ststfile", sep=",")
groups<-x[,2]
g<-unique(groups)
angles<-circular(x[,1], units="degrees")

watson.williams.test.default(angles, groups)

x11()
#pdf("$extras")
c<-floor(sqrt(length(g))+0.5)
r<- -floor(-length(g)/c)
op<-par(mfrow=c(r,c))
for (i in g) {
   t<-angles[groups==i]
   t<-conversion.circular(t-mean.circular(t)+180, units="degrees", modulo="2pi")-180
   p<-shapiro.test(t)\$p.value
   if (p < 0.05)
      cat("Shapiro-Wilk test of normality: data in",i,"\n  may not be normally distributed, p =",p,", p < .05\n")
   qqnorm(t, main=i, ylim=c(-180,180))
   tf<-data.frame(t, t)
   qqline(tf)
}
par(op)
#Sys.sleep(10)
cat("Press [Enter] to continue ", file="/dev/stderr")
invisible(scan(file="stdin", what=character(), nlines=1, quiet=T))
invisible(dev.off())
q()
!
	#echo "$avgs" | sed '/^$/d' | Rscript $ascript
	Rscript $ascript
#	test -s $extras && evince $extras
	exit
	;;
-a*)	echo "$avgs" | sed '/^$/d' > $ststfile
	xscale=1
	case "$DEBUG" in
	[1-9]*)	(sysvecho "$0: Average X values: "; tr '\012' ' ' < $ststfile; echo "";
		 awk '{s+=$1;
			x=$1*'"$xscale"'*3.141592654/180;
			xs+=cos(x);ys+=sin(x);};
		  END {print "Average X = " s/NR*'"$xscale"' " deg.";
			x=0; if (ys<0) x=360;
			print "Circ. av. X = " atan2(ys/NR, xs/NR)*180/3.141592654+x " deg., r = " sqrt(xs*xs+ys*ys)/NR;}' $ststfile ) >&2 ;;
	esac
	;;
esac

case "$outname" in
"")	;;
*)	exec > "$outname" ;;
esac

(
  case "$cwopt" in
  -cw)	# generate clockwise plot...
    a=`genplot -xf$ststfile -xc1 -xs$xscale -xr0,360 -xg90 \
	  -ys0 -yo1 -yr0,1 -yg1 -yt- $pens $xypopt $ymwopt $copt -p -u |
        sed -n 's/^.*LBa=\([-+0-9.e]*\).*/\1/p'`
    genplot -xf$ststfile -xc1 -xs-$xscale -xo90 -xr0,360 -xg90 \
	-ys0 -yo1 -yr0,1 -yg1 -yt- $pens $xypopt $ymwopt $copt -p -u |
        sed 's/LB180/LB270/; /PU5080/s/LB270/LB180/;
	     s/LB0/LB90/; /PU5080/s/LB90/LB0/;
	     s/LBa=[-+0-9.e]*/LBa='"$a"'/'
    ;;
  *)
    genplot -xf$ststfile -xc1 -xs$xscale -xr0,360 -xg90 \
	-ys0 -yo1 -yr0,1 -yg1 -yt- $pens $xypopt $ymwopt $copt -p -u
    ;;
  esac
  run=`sed -n -e '/^Run:/p' $anafile | head -1`
  xwname=`sed -n -e 's|, *Avg cycle length:.*||p' $anafile`
  n=`wc -l < $ststfile | sed -e 's/[ 	]*//g'`
  case "$sopt" in
  -s*)
    ywname=`sed -n -e 's|^ *'"${ywf}"'  *.* uV  ||p' $anafile`
    case "$sopt" in
    -sb*)	ywname="$ywname Bursts" ;;
    -s*)	ywname="$ywname Spikes" ;;
    esac
    : > $extras
    ;;
  *)
    ywname=`sed -n -e '1s| (.*||p' $anafile`
    case "$aopt" in
    -a*) echo ": $n averages" > $extras ;;
    *)
      ywstop=`sed -n -e 's|^<.*Base Y on stop time:[ 	]*||p' $anafile`
      ywtrain=`sed -n -e 's|^<.*Base Y on spike trains:[ 	]*||p' $anafile`
      sysvecho "asscw${ywf}\ns${ywstop}t${ywtrain}qmsxw${ywf}\nqyw${xwf}\nqcyqqdny\\\\n\nqqb\nqyn" |
	TERM=dumb DISPLAY= analysis $prmfile 2>> $diags |
	sed -n -e 's|^.*: \(.*\) cycles, *Avg cycle length:.*|: \1 bursts|p' > $extras
	;;
    esac
    ;;
  esac
  label=n
  case "$aopt" in
  -a*)	run="Averaged angles" ;;
  esac
  case "$ropt" in
  -r[0-9]*)	label=random ; n="$nsamp" ;;
  esac
  case "$xypopt" in
  *-xp0*)	;;
  *)
	sysvecho "PU580,7520;LO13;SR1,1.94444;LB$run, $label=$n\003;"
	sysvecho "PU5080,320;LO14;LBY=#$ywf $ywname`cat $extras` vs X=#$xwf $xwname\003;"
	;;
  esac
) | eval $ofilt
