/* * Grace - GRaphing, Advanced Computation and Exploration of data * * Home page: http://plasma-gate.weizmann.ac.il/Grace/ * * Copyright (c) 1991-1995 Paul J Turner, Portland, OR * Copyright (c) 1996-2000 Grace Development Team * * Maintained by Evgeny Stambulchik * * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * featext.c - routines to perform feature extraction on a set of curves */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "globals.h" #include "utils.h" #include "graphs.h" #include "protos.h" #include "motifinc.h" typedef struct _Featext_ui { Widget top; ListStructure *tograph; OptionStructure *feature_item; Widget *xval_item; ListStructure *absic_graph; SetChoiceItem absic_set; Widget legload_rc; } Featext_ui; static Featext_ui feui; static Widget but2[3]; void do_fext_proc( Widget, XtPointer, XtPointer ); double linear_interp( double, double, double, double, double ); int dbl_comp( const void *, const void * ); int getmedian( int grno, int setno, int sorton, double *median ); int get_zero_crossing( int setl, double *xv, double *yv, double *crossing ); int get_rise_time( int setl, double *xv, double *yv, double min, double max, double *width ); int get_fall_time( int setl, double *xv, double *yv, double min, double max, double *width ); int mute_linear_regression(int n, double *x, double *y, double *slope, double *intercept); int get_half_max_width(int len, double *x, double *y, double *width); int get_barycenter( int n, double *x, double *y, double *barycenter ); void fext_routine( int gto, int feature, int abs_src, int abs_set, int abs_graph ); void get_max_pos( double *a, double *b, int n, double max, double *d ); void do_fext_toggle (Widget w, XtPointer client_data, XtPointer call_data) { int value = (int) client_data; if (value == 2 || value == 3) { SetSensitive(feui.legload_rc, True); } else { SetSensitive(feui.legload_rc, False); } } void create_featext_frame(void *data) { set_wait_cursor(); if (feui.top == NULL) { Widget dialog; char *label2[2]; int i; OptionItem feature_option_items[] = { { 0, "Y minimum" }, { 1, "Y maximum" }, { 2, "Y average" }, { 3, "Y std. dev." }, { 4, "Y median" }, { 5, "X minimum" }, { 6, "X maximum" }, { 7, "X average" }, { 8, "X std. dev." }, { 9, "X median" }, {10, "Frequency" }, {11, "Period" }, {12, "Zero crossing" }, {13, "Rise time" }, {14, "Fall time" }, {15, "Slope" }, {16, "Y intercept" }, {17, "Set length" }, {18, "Half maximal width"}, {19, "Barycenter X" }, {20, "Barycenter Y" }, {21, "X(Y max)" }, {22, "Y(X max)" }, {23, "Integral" } }; label2[0] = "Accept"; label2[1] = "Close"; feui.top = XmCreateDialogShell(app_shell, "Feature Extraction", NULL, 0); handle_close(feui.top); dialog = XmCreateRowColumn(feui.top, "dialog_rc", NULL, 0); feui.tograph = CreateGraphChoice(dialog, "Results to graph:", LIST_TYPE_SINGLE); feui.feature_item = CreateOptionChoice(dialog, "Feature:", 3, 24, feature_option_items); feui.xval_item = CreatePanelChoice(dialog, "X values from:", 5, "Index", "Legends", "X from Set", "Y from set", NULL); for (i = 0; i < 4; i++) { XtAddCallback(feui.xval_item[2 + i], XmNactivateCallback, (XtCallbackProc) do_fext_toggle, (XtPointer) i); } CreateSeparator(dialog); feui.legload_rc= XmCreateRowColumn(dialog, "fext_legload_rc", NULL, 0); feui.absic_graph = CreateGraphChoice(feui.legload_rc, "Abscissa from graph:", LIST_TYPE_SINGLE); feui.absic_set = CreateSetSelector(feui.legload_rc, "set:", SET_SELECT_ACTIVE, FILTER_SELECT_NONE, 0, SELECTION_TYPE_SINGLE); update_save_set_list( feui.absic_set, 0 ); ManageChild(feui.legload_rc); SetSensitive(feui.legload_rc, False); CreateSeparator(dialog); CreateCommandButtons(dialog, 2, but2, label2); XtAddCallback(but2[0], XmNactivateCallback, (XtCallbackProc) do_fext_proc,(XtPointer) & feui); XtAddCallback(but2[1], XmNactivateCallback, (XtCallbackProc)destroy_dialog,(XtPointer)feui.top); ManageChild(dialog); } RaiseWindow(feui.top); unset_wait_cursor(); } void do_fext_proc( Widget w, XtPointer client_data, XtPointer call_data ) { int gto, feature, abs_graph = -1, abs_set = -1, abs_src; Featext_ui *ui = (Featext_ui *) client_data; feature = GetOptionChoice(ui->feature_item); GetSingleListChoice(ui->tograph, >o); if( gto == -1 ) gto = get_cg(); abs_src = (int) GetChoice(ui->xval_item); if( abs_src ==2 || abs_src==3 ) { abs_set = GetSelectedSet(ui->absic_set); GetSingleListChoice(ui->absic_graph, &abs_graph); } fext_routine( gto, feature, abs_src, abs_set, abs_graph ); update_set_lists(gto); xdrawgraph(); } 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; double xmin, xmax, ymin, ymax; int cg = get_cg(); double *x; abscissa = xmalloc(number_of_sets(cg)*SIZEOF_FLOAT); if( !is_graph_active( 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(get_cg()); switch( abs_src ) { case 0: /* use index */ for( i=0; iamp90 ) x90++; if( x90==setl || x90==0) return 1; x10= x90+1; while( x10amp10 ) x10++; if( x10==setl ) return 1; *width = linear_interp( yv[x10-1], xv[x10-1], yv[x10], xv[x10], amp10 )- linear_interp( yv[x90-1], xv[x90-1], yv[x90], xv[x90], amp90 ); return 0; } int get_zero_crossing( int setl, double *xv, double *yv, double *crossing ) { int i=0; while( i0. ) i++; if( i==setl ) return 1; if( yv[i] == 0 ) *crossing = xv[i]; else *crossing = linear_interp( yv[i], xv[i], yv[i+1], xv[i+1], 0 ); return 0; } /* Get FWHM of the highest peak */ int get_half_max_width(int len, double *x, double *y, double *width) { int i, imin, imax; double ymin, ymax, yavg; double x_u, x_d; minmax(y, len, &ymin, &ymax, &imin, &imax); yavg = (ymin + ymax)/2.0; i = imax; while (i >= 0 && y[i] > yavg) { i--; } if (i < 0) { return RETURN_FAILURE; } x_d = linear_interp(y[i], x[i], y[i + 1], x[i + 1], yavg); i = imax; while (i < len && y[i] > yavg) { i++; } if (i == len) { return RETURN_FAILURE; } x_u = linear_interp(y[i - 1], x[i - 1], y[i], x[i], yavg); *width = fabs(x_u - x_d); return RETURN_SUCCESS; } /* linear interpolate between two points, return a y value given an x */ double linear_interp( double x1, double y1, double x2, double y2, double x ) { return y1 + ( x-x1 )*(y2-y1)/(x2-x1); } /* 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( get_cg(), setno ); setdata = (double *)xmalloc( 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.; xfree( setdata ); return 0; } int dbl_comp( const void *a, const void *b ) { if( *(double *)a < *(double *)b ) return -1; else if( *(double *)a > *(double *)b ) return 1; else return 0; } int get_barycenter( int n, double *x, double *y, double *barycenter ) { double wsum=0; *barycenter = 0; for( n--; n>=0; n-- ) { wsum += x[n]*y[n]; *barycenter += x[n]; } *barycenter = wsum/(*barycenter); return 0; } /* given maximum of set a, find the corresponding entry in set b */ void get_max_pos( double *a, double *b, int n, double max, double *d ) { int i=-1; while( ++i