Пример #1
0
EditPoints *newep(int gno, int setno)
{
    int i;
    EditPoints *ep;
    ep = (EditPoints *) malloc(sizeof(EditPoints));
    ep->gno = gno;
    ep->setno = setno;
    ep->ncols = getncols(gno, setno);
    ep->nrows = getsetlength(gno, setno);
    g[gno].p[setno].ep = ep;
    switch (dataset_type(gno, setno)) {
    case SET_XY:
	ep->collabels = labels1;
	break;
    case SET_XYDX:
	ep->collabels = labels2;
	break;
    case SET_XYDY:
	ep->collabels = labels3;
	break;
    case SET_XYDXDX:
	ep->collabels = labels4;
	break;
    case SET_XYDYDY:
	ep->collabels = labels5;
	break;
    case SET_XYDXDY:
	ep->collabels = labels6;
	break;
    case SET_XYZ:
	ep->collabels = labels7;
	break;
    case SET_XYHILO:
	ep->collabels = labels8;
	break;
    case SET_XYRT:
	ep->collabels = labels9;
	break;
    }
    for (i=0; i < MAX_SET_COLS; i++) {
		ep->cwidth[i] = widths[i];
		ep->cprec[i] = precision[i];
		ep->cformat[i] = format[i];
    }
    return ep;
}
Пример #2
0
/* get the median of the X or Y portion of a set */
int getmedian( int grno, int setno, int sorton, double *median )
{
	int setlen;
	double *setdata;
	
	setlen = getsetlength( cg, setno );
	setdata = (double *)malloc( setlen*sizeof(double) );
	if( sorton == DATA_X )
		memcpy( setdata, getx( grno, setno ), setlen*sizeof(double) );
	else
		memcpy( setdata, gety( grno, setno ), setlen*sizeof(double) );
	
	qsort( setdata, setlen, sizeof(double), dbl_comp );
	
	if( setlen%2 )		/* odd set */
		*median = setdata[(setlen+1)/2-1];
	else
		*median = ( setdata[setlen/2-1] + setdata[setlen/2] )/2.;

	free( setdata );
	return 0;
}
Пример #3
0
void update_cells(Widget w, XtPointer client_data, XtPointer call_data)
/*
 * redo frame since number of data points or set type, etc.,  may change 
 */
{
	EditPoints *ep = (EditPoints *)client_data;
	int i, j, nr, nc;
	short width;
	char buf[32];
	
    ep->nrows = getsetlength(ep->gno, ep->setno);
    switch (dataset_type(ep->gno, ep->setno)) {
    	case SET_XY:
			ep->collabels = labels1;
			break;
    	case SET_XYDX:
			ep->collabels = labels2;
			break;
    	case SET_XYDY:
			ep->collabels = labels3;
			break;
    	case SET_XYDXDX:
			ep->collabels = labels4;
			break;
    	case SET_XYDYDY:
			ep->collabels = labels5;
			break;
    	case SET_XYDXDY:
			ep->collabels = labels6;
			break;
    	case SET_XYZ:
			ep->collabels = labels7;
			break;
    	case SET_XYHILO:
			ep->collabels = labels8;
			break;
    	case SET_XYRT:
			ep->collabels = labels9;
			break;
    }
    switch (dataset_type(ep->gno, ep->setno)) {
    case SET_XY:
		ep->ncols = 2;
		break;
    case SET_XYDX:
    case SET_XYDY:
    case SET_XYZ:
    case SET_POLY:
		ep->ncols = 3;
		break;
    case SET_XYDXDX:
    case SET_XYDYDY:
    case SET_XYDXDY:
    case SET_XYZW:
    case SET_XYRT:
    case SET_XYUV:
    case SET_XYYY:
    case SET_XYXX:
		ep->ncols = 4;
		break;
    case SET_XYHILO:
    case SET_XYBOX:
		ep->ncols = 5;
		break;
    case SET_XYBOXPLOT:
		ep->ncols = 6;
		break;
	}    

	cells = MakeCells( ep );
			
    rowlabels = (String *) malloc(ep->nrows * sizeof(String));
    for (i = 0; i < ep->nrows; i++) {
    	sprintf(buf, "%d", i + 1);
    	rowlabels[i] = (String) malloc((sizeof(buf) + 1) * sizeof(char));
    	strcpy(rowlabels[i], buf);
    }
    width = (short) ceil(log10(i))+2;	/* increase row label width by 1 */

	/* get current size of widget 			*/
	XtVaGetValues( ep->mw, XmNcolumns, &nc, 
						   XmNrows, &nr, 
    					   NULL );
	if( ep->nrows > nr )
		XbaeMatrixAddRows( ep->mw, 0, NULL, NULL, NULL, ep->nrows-nr );
	else if( ep->nrows < nr )
		XbaeMatrixDeleteRows( ep->mw, 0, nr - ep->nrows );
	if( ep->ncols > nc )
		XbaeMatrixAddColumns( ep->mw, 0, NULL, NULL, widths, NULL, 
					    NULL, NULL, NULL, ep->ncols-nc );
	else if( ep->ncols < nc )
		XbaeMatrixDeleteColumns( ep->mw, 0, nc - ep->ncols );

    XtVaSetValues(ep->mw, XmNrowLabels, rowlabels,
			  XmNcells, cells,
			  XmNcolumnLabels, ep->collabels,
			  XmNrowLabelWidth, width,
			  NULL);

    /* free memory used to hold strings */
    for (i = 0; i < ep->nrows; i++) {
		for (j = 0; j < ep->ncols; j++) {
	    	XtFree((XtPointer) cells[i][j]);
		}
		XtFree((XtPointer) cells[i]);
		free( rowlabels[i] );
    }
    XtFree((XtPointer) cells);
}
Пример #4
0
/* ARGSUSED */
static void do_nonl_proc(Widget, XtPointer, XtPointer)
{
    int i, setno, loadset, loadto, graphto, npar, info;
    double tol, a[MAXPARM];
    char fstr[256];
    double *y, *yp;

    set_wait_cursor();
    curset = setno = (int)GetChoice(nonl_set_item);
    loadto = (int)GetChoice(nonl_load_item);
    graphto = (int)GetChoice(nonl_loadgraph_item) - 1;
    tol = atof((char *)xv_getstr(nonl_tol_item));
    if (graphto < 0)
    {
        graphto = cg;
    }
    npar = atoi((char *)xv_getstr(nonl_nparm_item));
    strcpy(fstr, (char *)xv_getstr(nonl_formula_item));
    for (i = 0; i < MAXPARM; i++)
    {
        a[i] = 0.0;
        strcpy(buf, (char *)xv_getstr(nonl_initial_item[i]));
        sscanf(buf, "%lf", &a[i]);
    }
    yp = (double *)calloc(getsetlength(cg, setno), sizeof(double));
    if (yp == NULL)
    {
        errwin("Memory allocation error, operation cancelled");
        unset_wait_cursor();
        return;
    }
    y = gety(cg, setno);
    for (i = 0; i < getsetlength(cg, setno); i++)
    {
        yp[i] = y[i];
    }
    sprintf(buf, "Fitting: %s\n", fstr);
    stufftext(buf, 0);
    sprintf(buf, "Initial guess:\n");
    stufftext(buf, 0);
    for (i = 0; i < npar; i++)
    {
        sprintf(buf, "\ta%1d = %.9lf\n", i, a[i]);
        stufftext(buf, 0);
    }
    sprintf(buf, "Tolerance = %.9lf\n", tol);
    stufftext(buf, 0);
    lmfit(fstr, getsetlength(cg, setno), getx(cg, setno),
          yp, y, npar, a, tol, &info);
    for (i = 0; i < getsetlength(cg, setno); i++)
    {
        y[i] = yp[i];
    }
    free(yp);
    for (i = 0; i < MAXPARM; i++)
    {
        sprintf(buf, "%.9lf", a[i]);
        xv_setstr(nonl_computed_item[i], buf);
        nonl_parms[i] = a[i];
    }
    if (info > 0 && info < 4)
    {
        sprintf(buf, "Computed values:\n");
        stufftext(buf, 0);
        for (i = 0; i < npar; i++)
        {
            sprintf(buf, "\ta%1d = %.9lf\n", i, a[i]);
            stufftext(buf, 0);
        }
        loadset = nextset(cg);
        if (loadset != -1)
        {
            do_copyset(cg, setno, cg, loadset);
        }
        else
        {
            unset_wait_cursor();
            return;
        }
        switch (loadto)
        {
        case 0:
            sprintf(buf, "Evaluating function and loading result to set %d:\n", loadset);
            stufftext(buf, 0);
            do_compute(loadset, 0, graphto, fstr);
            break;
        case 1:
            sprintf(buf, "Evaluating function and loading residuals to set %d:\n", loadset);
            stufftext(buf, 0);
            do_compute(loadset, 0, graphto, fstr);
            break;
        case 2:
            sprintf(buf, "Computed function not evaluated\n");
            stufftext(buf, 0);
            break;
        }
    }
    /*
       if (info >= 4) {
      do_compute(setno, 1, graphto, fstr);
       }
   */
    if (info >= 0 && info <= 7)
    {
        char *s;
        switch (info)
        {
        case 0:
            s = (char *)"Improper input parameters.\n";
            break;
        case 1:
            s = (char *)"Relative error in the sum of squares is at most tol.\n";
            break;
        case 2:
            s = (char *)"Relative error between A and the solution is at most tol.\n";
            break;
        case 3:
            s = (char *)"Relative error in the sum of squares and A and the solution is at most tol.\n";
            break;
        case 4:
            s = (char *)"Fvec is orthogonal to the columns of the jacobian to machine precision.\n";
            break;
        case 5:
            s = (char *)"Number of calls to fcn has reached or exceeded 200*(n+1).\n";
            break;
        case 6:
            s = (char *)"Tol is too small. No further reduction in the sum of squares is possible.\n";
            break;
        case 7:
            s = (char *)"Tol is too small. No further improvement in the approximate solution A is possible.\n";
            break;
        }
        stufftext(s, 0);
        stufftext((char *)"\n", 0);
    }
    unset_wait_cursor();
}
Пример #5
0
/* ARGSUSED */
static void do_nonl_proc(Widget w, XtPointer client_data, XtPointer call_data)
{
    int i, npts = 0, info;
    double delx, *xfit, *y, *yfit;
    int nsteps = (int) client_data;
    
    set_wait_cursor();
    curset = nlsetno = GetSelectedSet(nonl_set_item);
    if (curset == SET_SELECT_ERROR) {
    	errmsg("No set selected");
    	unset_wait_cursor();
    	return;
    }
    
    nonl_opts.tolerance = atof((char *) xv_getstr(nonl_tol_item));
    nonl_opts.parnum = GetChoice(nonl_nparm_item);
    strcpy(nonl_opts.formula, (char *) xv_getstr(nonl_formula_item));
    for (i = 0; i < nonl_opts.parnum; i++) {
	strcpy(buf, (char *) xv_getstr(nonl_value_item[i]));
	if (sscanf(buf, "%lf", &nonl_parms[i].value) != 1) {
	    errmsg("Invalid input in parameter field");
	    unset_wait_cursor();
	    return;
	}
	
	nonl_parms[i].constr = XmToggleButtonGetState(nonl_constr_item[i]);
	if (nonl_parms[i].constr) {
	    strcpy(buf, (char *) xv_getstr(nonl_lowb_item[i]));
	    if (sscanf(buf, "%lf", &nonl_parms[i].min) != 1) {
	    	errmsg("Invalid input in low-bound field");
	    	unset_wait_cursor();
	    	return;
	    }
	    strcpy(buf, (char *) xv_getstr(nonl_uppb_item[i]));
	    if (sscanf(buf, "%lf", &nonl_parms[i].max) != 1) {
	    	errmsg("Invalid input in upper-bound field");
	    	unset_wait_cursor();
	    	return;
	    }
	    if ((nonl_parms[i].value < nonl_parms[i].min) || (nonl_parms[i].value > nonl_parms[i].max)) {
	    	errmsg("Initial values must be within bounds");
	    	unset_wait_cursor();
	    	return;
	    }
	}
    }
    
    nonl_prefs.autoload = XmToggleButtonGetState(nonl_autol_item);
    for (i = 0; i < 3; i++) {
        if (XmToggleButtonGetState(nonl_load_item[i])) {
            nonl_prefs.load = i;
            break;
        }
    }
    
    if (nonl_prefs.load == LOAD_FUNCTION) {
        strcpy(buf, (char *) xv_getstr(nonl_start_item));
	if (sscanf(buf, "%lf", &nonl_prefs.start) != 1) {
	    errmsg("Invalid input in start field");
	    unset_wait_cursor();
	    return;
	}
	strcpy(buf, (char *) xv_getstr(nonl_stop_item));
	if (sscanf(buf, "%lf", &nonl_prefs.stop) != 1) {
	    errmsg("Invalid input in stop field");
	    unset_wait_cursor();
	    return;
	}
	strcpy(buf, (char *) xv_getstr(nonl_npts_item));
	if (sscanf(buf, "%d", &nonl_prefs.npoints) != 1) {
	    errmsg("Invalid input in start field");
	    unset_wait_cursor();
	    return;
	}
    }
    
    if (nsteps) { /* we are asked to fit */
    	sprintf(buf, "Fitting with formula: %s\n", nonl_opts.formula);
    	stufftext(buf, 0);
    	sprintf(buf, "Initial guesses:\n");
    	stufftext(buf, 0);
    	for (i = 0; i < nonl_opts.parnum; i++) {
	    sprintf(buf, "\ta%1d = %g\n", i, nonl_parms[i].value);
	    stufftext(buf, 0);
    	}
    	sprintf(buf, "Tolerance = %g\n", nonl_opts.tolerance);
    	stufftext(buf, 0);

/*
 * The fit itself!
 */    	

    	info = do_nonlfit(cg, nlsetno, nsteps);
    	if (info == -1) {
	    errmsg("Memory allocation error in do_nonlfit()");  
	    unset_wait_cursor();
	    return;  	
    	}
   	    	
    	for (i = 0; i < nonl_opts.parnum; i++) {
	    sprintf(buf, "%g", nonl_parms[i].value);
	    xv_setstr(nonl_value_item[i], buf);
    	}

    	if ((info > 0 && info < 4) || (info == 5)) {
	    sprintf(buf, "Computed values:\n");
	    stufftext(buf, 0);
	    for (i = 0; i < nonl_opts.parnum; i++) {
		sprintf(buf, "\ta%1d = %g\n", i, nonl_parms[i].value);
		stufftext(buf, 0);
	    }
    	}


    	if (info >= 0 && info <= 7) {
    	    char *s;
    	    switch (info) {
    	    case 0:
    		s = "Improper input parameters.\n";
    		break;
    	    case 1:
    		s = "Relative error in the sum of squares is at most tol.\n";
    		break;
    	    case 2:
    		s = "Relative error between A and the solution is at most tol.\n";
    		break;
    	    case 3:
    		s = "Relative error in the sum of squares and A and the solution is at most tol.\n";
    		break;
    	    case 4:
    		s = "Fvec is orthogonal to the columns of the jacobian to machine precision.\n";
    		break;
    	    case 5:
    		s = "\n";
    		break;
    	    case 6:
    		s = "Tol is too small. No further reduction in the sum of squares is possible.\n";
    		break;
    	    case 7:
    		s = "Tol is too small. No further improvement in the approximate solution A is possible.\n";
    		break;
    	    default:
    		s = "\n";
    		errmsg("Internal error in do_nonl_proc(), please report");
    		break;
    	    }
    	    stufftext(s, 0);
    	    stufftext("\n", 0);
    	}
    } /* endif (nsteps) */

/*
 * Select & activate a set to load results to
 */    
    if (!nsteps || nonl_prefs.autoload) {
    	/* check if the set is already allocated */
    	if ((nlloadset == -1) || (nlloadset == nlsetno) || !getsetlength(cg, nlloadset)) {
    	    nlloadset = nextset(cg);
    	    if (nlloadset == -1) {
    	      errmsg("No more sets!");
    	      unset_wait_cursor();
    	      return;
    	    } else {
    		activateset(cg, nlloadset);
    		setlength(cg, nlloadset, 1);
    	    }
    	}
    	    	
    	switch (nonl_prefs.load) {
    	case LOAD_VALUES:
    	  sprintf(buf, "Evaluating fitted values and loading result to set %d:\n", nlloadset);
    	  stufftext(buf, 0);
    	  npts = getsetlength(cg, nlsetno);
    	  setlength(cg, nlloadset, npts);
    	  copycol2(cg, nlsetno, cg, nlloadset, 0);
    	  break;
    	case LOAD_RESIDUALS:
    	  sprintf(buf, "Evaluating fitted values and loading residuals to set %d:\n", nlloadset);
    	  stufftext(buf, 0);
    	  npts = getsetlength(cg, nlsetno);
    	  setlength(cg, nlloadset, npts);
    	  copycol2(cg, nlsetno, cg, nlloadset, 0);
    	  break;
    	case LOAD_FUNCTION:
    	  sprintf(buf, "Computing fitting function and loading result to set %d:\n", nlloadset);
    	  stufftext(buf, 0);
    	  
    	  npts  = nonl_prefs.npoints;
    	  if (npts <= 1) {
    	      errmsg("Number of points must be > 1");
    	      unset_wait_cursor();
    	      return;
    	  }
    	  
    	  setlength(cg, nlloadset, npts);
    	  
    	  delx = (nonl_prefs.stop - nonl_prefs.start)/(npts - 1);
    	  xfit = getx(cg, nlloadset);
	  for (i = 0; i < npts; i++) {
	      xfit[i] = nonl_prefs.start + i * delx;
	  }
    	  break;
    	}
    	
    	setcomment(cg, nlloadset, nonl_opts.formula);
    	
    	do_compute(nlloadset, 0, cg, nonl_opts.formula);
    	
    	if (nonl_prefs.load == LOAD_RESIDUALS) { /* load residuals */
    	    y = gety(cg, nlsetno);
    	    yfit = gety(cg, nlloadset);
    	    for (i = 0; i < npts; i++) {
	      yfit[i] -= y[i];
	    }
    	}
    	
    	update_set_lists(cg);
    	drawgraph();
    }
    unset_wait_cursor();
}
Пример #6
0
void flipxy(int gno)
{
    int i, j;
    tickmarks t;
    double *x, *y;

    for (i = 0; i < MAXAXES; i += 2)
    {
        memcpy(&t, &g[gno].t[i], sizeof(tickmarks));
        memcpy(&g[gno].t[i], &g[gno].t[i + 1], sizeof(tickmarks));
        memcpy(&g[gno].t[i + 1], &t, sizeof(tickmarks));
        if (g[gno].t[i].t_op == RIGHT)
        {
            g[gno].t[i].t_op = TOP;
        }
        else if (g[gno].t[i].t_op == LEFT)
        {
            g[gno].t[i].t_op = BOTTOM;
        }
        if (g[gno].t[i].tl_op == RIGHT)
        {
            g[gno].t[i].tl_op = TOP;
        }
        else if (g[gno].t[i].tl_op == LEFT)
        {
            g[gno].t[i].tl_op = BOTTOM;
        }
        if (g[gno].t[i + 1].t_op == TOP)
        {
            g[gno].t[i + 1].t_op = RIGHT;
        }
        else if (g[gno].t[i + 1].t_op == BOTTOM)
        {
            g[gno].t[i + 1].t_op = LEFT;
        }
        if (g[gno].t[i + 1].tl_op == TOP)
        {
            g[gno].t[i + 1].tl_op = RIGHT;
        }
        else if (g[gno].t[i + 1].tl_op == BOTTOM)
        {
            g[gno].t[i + 1].tl_op = LEFT;
        }
    }
    if (g[gno].type == LOGX)
    {
        g[gno].type = LOGY;
    }
    else if (g[gno].type == LOGY)
    {
        g[gno].type = LOGX;
    }
    fswap(&g[gno].w.xg1, &g[gno].w.yg1);
    fswap(&g[gno].w.xg2, &g[gno].w.yg2);
    fswap(&g[gno].dsx, &g[gno].dsy);
    iswap(&g[gno].fx, &g[gno].fy);
    iswap(&g[gno].px, &g[gno].py);
    for (i = 0; i < g[gno].maxplot; i++)
    {
        if (isactive(gno, i))
        {
            x = getx(gno, i); /* TODO really need to just swap pointers */
            y = gety(gno, i);
            for (j = 0; j < getsetlength(gno, i); j++)
            {
                fswap(&x[j], &y[j]);
            }
            updatesetminmax(gno, i);
        }
    }
    update_all(gno);
}
Пример #7
0
void fext_routine( int gto, int feature, int abs_src, int abs_set, int abs_graph )
{
	int i, cs, ns, fts, ncurves, extract_err;
	double datum, dummy, *absy;
	double y1, y2;
	int iy1, iy2;
	char tbuf[1024];
	float *abscissa;

	abscissa = (float *)malloc( maxplot*sizeof(float) );
	
	if( !isactive_graph( gto )	){
		errwin("Graph for results must be active");
	    return;
	}
	if( (ns=nextset( gto ) )== -1 ) {
		errwin("Choose a new graph or kill sets!");
	    return;
	}
	ncurves = nactive(cg);
	switch( abs_src ) {
		case 0:		/* use index */
			for( i=0; i<ncurves; i++ )
				abscissa[i] = i+1;
			break;	
		case 1:		/* use legend label */
			cs = 0;
			for( i=0; i<ncurves; i++ ){
				while( !isactive_set( cg, cs ) )
					cs++;
				if(!sscanf( g[cg].p[cs].lstr, "%f", &abscissa[i]))
					break;
				cs++;
			}
			if( i != ncurves ) {
				errwin("Bad legend label");
				return;
			}
			break;
		case 2:		/* use X from set */
			if( !isactive_set( abs_graph, abs_set ) ){
	    		errwin("Abscissa set not active");
	    		return;
			}
			if( getsetlength( abs_graph, abs_set ) < ncurves ) {
				errwin("Not enough points in set");
				return;
			}
			absy = getx( abs_graph, abs_set );
			for( i=0; i<ncurves; i++ )
				abscissa[i] = absy[i];
			break;			
		case 3:										/* use Y from set */
			if( !isactive_set( abs_graph, abs_set ) ){
	    		errwin("Abscissa set not active");
	    		return;
			}
			if( getsetlength( abs_graph, abs_set ) < ncurves ) {
				errwin("Not enough points in set");
				return;
			}
			absy = gety( abs_graph, abs_set );
			for( i=0; i<ncurves; i++ )
				abscissa[i] = absy[i];
			break;
	}

	cs = 0;
	tbuf[0] = '\0';
	for( i=0; i<ncurves; i++ ) {
		while( !isactive_set( cg, cs ) )
			cs++;
		extract_err = 0;
			
		switch( feature ) {
			case 0:			/* Y minimum */
				datum = g[cg].p[cs].ymin;		
				break;
			case 1: 		/* Y maximum */
				datum = g[cg].p[cs].ymax;		
				break;
			case 2: 		/* Y mean    */
				stasum(gety(cg, cs), getsetlength(cg, cs), &datum, &dummy, 0);
				break;
			case 3:			/* Y std dev */
				stasum(gety(cg, cs), getsetlength(cg, cs), &dummy, &datum, 0);
				break;
			case 4: 		/* Y median  */
				getmedian( cg, cs, DATA_Y, &datum );
				break;
			case 5:			/* X minimum */
				datum = g[cg].p[cs].xmin;		
				break;
			case 6: 		/* X maximum */
				datum = g[cg].p[cs].xmax;		
				break;
			case 7: 		/* X mean    */
				stasum(getx(cg, cs), getsetlength(cg, cs), &datum, &dummy, 0);
				break;
			case 8:			/* X std dev */
				stasum(getx(cg, cs), getsetlength(cg, cs), &dummy, &datum, 0);
				break;
			case 9:			/* X median  */
				getmedian( cg, cs, DATA_X, &datum );
				break;
			case 10: 		/* frequency and period */
			case 11:
				if ( ilog2(getsetlength(cg, cs)) <= 0)    /* only DFT */
					do_fourier(0, cs, 0, 1, 0, 0, 0);
				else							/* FFT      */
					do_fourier(1, cs, 0, 1, 0, 0, 0);

				sprintf( tbuf, "FT of set %d", cs );
				fts = 0;
				while( strcmp( tbuf, g[cg].p[fts].comments+1 ) )
					fts++;
					
				minmax(gety(cg, fts), getsetlength(cg, fts),&y1,&y2,&iy1,&iy2);
				if( feature == 8 )
					datum = g[cg].p[fts].ex[0][iy2-1];
				else
					datum = 1./g[cg].p[fts].ex[0][iy2-1];
				killset( cg, fts );				/* get rid of Fourier set */
				break;
			case 12:		/* first zero crossing */
				if( get_zero_crossing( getsetlength( cg, cs ), 
									getx( cg, cs ),gety( cg, cs ), &datum ) ){
					sprintf( tbuf+strlen(tbuf), 
								"Unable to find zero crossing of set %d\n", cs );
					errwin( tbuf );
					extract_err = 1;
				}
				break;
			case 13:		/* rise time   */
				if( get_rise_time( getsetlength(cg,cs), getx(cg,cs), 
					gety(cg,cs), g[cg].p[cs].ymin, g[cg].p[cs].ymax, &datum ) ){
					sprintf( tbuf+strlen(tbuf), 
							"Unable to find rise time of set %d\n", cs );
					errwin( tbuf );
					extract_err = 1;
				}
				break;
			case 14: 		/* fall time   */
				if( get_fall_time( getsetlength(cg,cs), getx(cg,cs), 
					gety(cg,cs), g[cg].p[cs].ymin, g[cg].p[cs].ymax, &datum ) ){
					sprintf( tbuf+strlen(tbuf), 
									"Unable to find fall time of set %d\n", cs );
					extract_err = 1;
					errwin( tbuf );
				}
				break;
			case 15:		/* slope       */
				if( mute_linear_regression( getsetlength( cg, cs ), 
					getx( cg, cs ),gety( cg, cs ), &datum, &dummy ) ) {
					sprintf( tbuf+strlen(tbuf), 
										"Unable to find slope of set %d\n", cs );
					errwin( tbuf );
					extract_err = 1;
				}
				break;
			case 16:		/* Y intercept */
				if( mute_linear_regression( getsetlength( cg, cs ), 
						getx( cg, cs ), gety( cg, cs ), &dummy, &datum ) ) {
					sprintf( tbuf+strlen(tbuf), 
						"Unable to find y-intercept of set %d\n", cs );
					errwin( tbuf );
					extract_err = 1;
				}
				break;
			case 17:		/* set length  */
				datum = getsetlength( cg, cs );
				break;
			case 18:		/* half maximal widths */
				if( get_half_max_width(getsetlength( cg, cs ), getx(cg,cs), 
					   gety(cg,cs), g[cg].p[cs].ymin, g[cg].p[cs].ymax,&datum) ) {
					sprintf( tbuf+strlen(tbuf), 
						"Unable to find half maximal width of set %d\n", cs );
					extract_err = 1;
					errwin( tbuf );
				}
				break;
			case 19:		/* Barycenter X */
				get_barycenter( getsetlength( cg, cs ), gety(cg,cs), 
									getx(cg,cs), &datum );
				break;
			case 20:		/* Barycenter Y */
				get_barycenter( getsetlength( cg, cs ), getx(cg,cs), 
									gety(cg,cs), &datum );
				break;
			case 21:		/* X of Maximum Y */
				get_max_pos( gety(cg, cs), getx( cg, cs ),
							getsetlength( cg, cs ), g[cg].p[cs].ymax, &datum ); 
				break;
			case 22:		/* Y of Maximum X */
				get_max_pos( getx(cg, cs), gety( cg, cs ),
							getsetlength( cg, cs ), g[cg].p[cs].xmax, &datum ); 
				break;
		}
		if( !extract_err )
			add_point( gto, ns, abscissa[i], datum, 0, 0, SET_XY );
		cs++;
	}

	/* set comment */	
	switch( feature ) {
		case 0:			/* Y minimum */
			sprintf(tbuf,"Y minima of graph %d",cg); 
			break;
		case 1: 		/* Y maximum */
			sprintf(tbuf,"Y maxima of graph %d",cg);
			break;
		case 2: 		/* Y mean    */
			sprintf(tbuf,"Y means of graph %d",cg);
			break;
		case 3:			/* Y std dev */
			sprintf(tbuf,"Y std. dev.'s of graph %d",cg);
			break;
		case 4:			/* Y median  */
			sprintf(tbuf,"Y medians of graph %d",cg);
			break;
		case 5:			/* X minimum */
			sprintf(tbuf,"X minima of graph %d",cg); 
			break;
		case 6: 		/* X maximum */
			sprintf(tbuf,"X maxima of graph %d",cg);
			break;
		case 7: 		/* X mean    */
			sprintf(tbuf,"X means of graph %d",cg);
			break;
		case 8:			/* X std dev */
			sprintf(tbuf,"X std. dev.'s of graph %d",cg);
			break;
		case 9:			/* X median  */
			sprintf(tbuf,"X medians of graph %d",cg);
			break;
		case 10: 		/* frequency and period */
			sprintf(tbuf,"frequencies of graph %d",cg);
			break;
		case 11:
			sprintf(tbuf,"periods of graph %d",cg);
			break;
		case 12:		/* first zero crossing */
			sprintf(tbuf,"zero crossings of graph %d",cg);
			break;
		case 13:		/* rise time */
			sprintf(tbuf,"rise times of graph %d",cg);
			break;
		case 14: 		/* fall time */
			sprintf(tbuf,"fall times of graph %d",cg);
			break;
		case 15: 		/* slopes     */
			sprintf(tbuf,"slopes of graph %d",cg);
			break;
		case 16: 		/* Y intercepts */
			sprintf(tbuf,"Y intercepts of graph %d",cg);
			break;
		case 17: 		/* set lengths */
			sprintf(tbuf,"set lengths of graph %d",cg);
			break;
		case 18: 		/* 1/2 maximal widths */
			sprintf(tbuf,"half maximal widths of graph %d",cg);
			break;
		case 19: 		/* barycenter X */
			sprintf(tbuf,"X barycenters of graph %d",cg);
			break;
		case 20: 		/* barycenter Y */
			sprintf(tbuf,"Y barycenters of graph %d",cg);
			break;
		case 21:		/* X of maximum Y */
			sprintf(tbuf,"X positions of maximum Y's of graph %d",cg);
			break;
		case 22:		/* Y of maximum X */
			sprintf(tbuf,"Y positions of maximum X's of graph %d",cg);
			break;
	}
	setcomment( gto, ns, tbuf );
	free( abscissa );
	plotone( gto );
}