Esempio n. 1
0
int
PLP_usedata( )
{
char attr[NAMEMAXLEN], val[256];
char *line, *lineval;
int nt, lvp;
int first;


TDH_errprog( "pl proc usedata" );

if( PLD.curds < 0 ) return( Eerr( 2478, "no data have been read yet", "" ));

/* get attributes.. */
first = 1;
while( 1 ) {
	line = getnextattr( first, attr, val, &lvp, &nt );
	if( line == NULL ) break;
	first = 0;
	lineval = &line[lvp];

	if( stricmp( attr, "element" )== 0 ) {
		if( atoi( val ) <= PLD.curds ) PLD.curds = atoi( val );
		}
	else if( stricmp( attr, "pop" )== 0 ) PLD.curds -= atoi( val );
	else if( strnicmp( attr, "original", 8 )== 0 ) PLD.curds = 0;
	else if( stricmp( attr, "fieldnames" )==0 ) definefieldnames( lineval );
	else Eerr( 1, "attribute not recognized", attr );
	}

if( first == 1 ) PLD.curds = 0;   /* no attributes specified - (originaldata) */

if( PLD.curds < 0 ) PLD.curds = 0;

if( PLS.debug ) fprintf( PLS.diagfp, "using data set %d\n", PLD.curds );
setintvar( "NRECORDS", Nrecords );
setintvar( "NFIELDS", Nfields );

return( 0 );
}
Esempio n. 2
0
/* DO_PRELIMINARIES - set defaults, read config file, etc. */
int
PL_do_preliminaries()
{
char buf[512];
FILE *fp;
char *filename, *getenv();
char attr[80];
char val[512];
char *lineval;
int ix;
int valused, found;
int i, stat, j;
int projectrootfound;
char pathslash;
char uniq[80];
char configfile[MAXPATH];
char cgierrfile[80];


TDH_errprog( "pl" );


/* set pre-config (hard-coded) defaults.. */
PLS.debug = 0;
PLS.echolines = 0;
PLS.skipout = 0;
PLS.eready = 0;
PLS.prefabsdir = NULL;
strcpy( PLS.outfile, "" );
PLS.winx = 100; PLS.winy = 0; PLS.winw = 8.0; PLS.winh = 8.0;
PLS.winsizegiven = 0;
PLS.bkcolorgiven = 0;
PLS.clickmap = 0;
PLS.usingcm = 0;
strcpy( PLS.viewer, "" );
strcpy( PLS.mapfile, "" );
PLS.noshell = 0;
TDH_prohibit_shell( 0 );

#ifndef WIN32
TDH_reslimits( "cpu", CPULIMIT );
#endif
#ifdef LOCALE
 setlocale(LC_CTYPE, "" );
 setlocale(LC_COLLATE, "" );
#endif

#ifdef NOX11
PLS.device = 'e';
#else
PLS.device = 'x';    
#endif

PLD.maxrows = MAXDROWS;
PLD.maxdf = MAXD;
PLL.maxproclines = MAXPROCLINES;
PLVsize = MAXDAT;

PLG_set_early_defaults();

PLS.errfp = stderr; 	/* portability? */
PLS.diagfp = stderr;	/* portability? */
PLS.bignumspacer = '\0'; 	/* use standard number notation */
PLS.bignumthres = 4; 
suppress_convmsg( 1 ); /* suppress unplottable data msgs by default - user can turn on */
DT_checkdatelengths( 0 ); /* don't be strict about the length of date items */
setintvar( "CM_UNITS", 0 );
projectrootfound = 0;

strcpy( TDH_tmpdir, TMPDIR );
pathslash = PATH_SLASH;

/* set this now, but it might be updated depending on what's in config file.. */
GL_make_unique_string( uniq, 0 );
sprintf( PLS.tmpname, "%s%cplo%s", TDH_tmpdir, pathslash, uniq ); 

/* make cgierrfile (default /tmp/plcgi_err) for cgi errors */
sprintf( cgierrfile, "%s%cplcgi_err", TDH_tmpdir, PATH_SLASH );




/* reads and process config file, if any.. */
if( PLS.cgiargs != NULL ) {
	/* determine name of config file.. (can't use PLOTICUS_CONFIG in CGI context) */
	char *cgiprogname;
	strcpy( buf, "file=" );
	strcat( buf, CONFIGFILE );
	if( strlen( buf ) == 5 ) {   /* CONFIGFILE not set.. retrieve prog name from CGI environment and 
					 build config file name from that..  */
		cgiprogname = getenv( "SCRIPT_FILENAME" );
		if( cgiprogname == NULL ) {
			PLS.errfp = fopen( cgierrfile, "w" );
			if( PLS.errfp != NULL ) {
				fprintf( PLS.errfp, "cgi var SCRIPT_FILENAME not found.\n" );
#ifdef UNIX
				fchmod( fileno( PLS.errfp ), 00666 );
#endif
				}
			TDH_errfile( PLS.errfp ); /* set it for TDH */
			return( 1 );
			}
		strcat( buf, cgiprogname );
		j = strlen( buf ) -4;
		if( strcmp( &buf[ j ], ".cgi" )==0 ) buf[ j ] = '\0';
		else if( strcmp( &buf[ j ], ".exe" )==0 ) buf[ j ] = '\0';
		strcat( buf, ".cnf" );
		}
	strcpy( configfile, buf );
	}
else	{
	/* command line usage.. check PLOTICUS_CONFIG.. */
	filename = getenv( "PLOTICUS_CONFIG" );
	if( filename == NULL ) goto SKIPCONFIG;
	sprintf( configfile, "file=%s", filename );
	}

if( strlen( configfile ) == 5 ) {
	if( PLS.cgiargs != NULL ) goto BAD_CGI_CONFIG;
	else goto SKIPCONFIG;  /* no config file given.. */
	}


stat = TDH_readconfig( configfile );
/* no point in checking return stat.. */


/* do this again because TDH_tmpdir might have been updated.. */
GL_make_unique_string( uniq, 0 );
sprintf( PLS.tmpname, "%s%cplo%s", TDH_tmpdir, pathslash, uniq ); 

/* now read it again to get pl-specific items.. */

fp = fopen( &configfile[5], "r" );
if( fp == NULL ) {
	if( PLS.cgiargs != NULL ) {
		BAD_CGI_CONFIG:
		PLS.errfp = fopen( cgierrfile, "w" );
		if( PLS.errfp != NULL ) {
			fprintf( PLS.errfp, "cgi mode: cannot open config file (%s).\n", &configfile[5] );
#ifdef UNIX
			fchmod( fileno( PLS.errfp ), 00666 );
#endif
			}
		return( 1 );
		}
	else Eerr( 15060, "Cannot open ploticus config file", &configfile[5] );
	return( 0 );
	}


/* get user settings.. */
while( fgets( buf, 511, fp ) != NULL ) {
	buf[ strlen( buf ) -1 ] = '\0';
	ix = 0;
	strcpy( attr, GL_getok( buf, &ix ) );
	if( attr[0] == '\0' ) continue;
	if( attr[0] == '#' || attr[0] == '/' ) continue; /* skip comments of various kinds */
	while( isspace( (int) buf[ix] ) )ix++;
	lineval = &buf[ix];
	strcpy( val, GL_getok( buf, &ix ) );

	if( attr[ strlen( attr ) -1 ] == ':' ) attr[ strlen( attr ) - 1 ] = '\0';


	/* attributes that exist in config file, but not proc settings, go here: */

	if( strcmp( attr, "projectroot" )==0 ) {
		stat = chdir( val );
		if( stat != 0 ) goto CGI_BAD_CHDIR;
		projectrootfound = 1;
		if( PLS.debug ) fprintf( PLS.diagfp, "config: found projectroot.. chdir to %s..\n", val );
		}

	else if( strcmp( attr, "option" )==0 ) {
		val[0] = '\0';
		sscanf( buf, "%*s %s %s", attr, val );

		/* check for embedded '=' in attr.. if found indicates prefab parm setting.. send lineval as attr.. */
		for( i = 0, found = 0; attr[i] != '\0'; i++ ) if( attr[i] == '=' ) { found = 1; break; }
		if( found ) { strcpy( attr, lineval ); strcpy( val, "" ); }

		if( PLS.debug ) fprintf( PLS.diagfp, "config file: got option: %s %s\n", attr, val );
		PL_process_arg( attr, val, &valused, &found );	
		if( !found ) Eerr( 2784, "invalid 'option:' in config file", attr );
		}

	/* shared settings takes care of settings that can be set in config file OR proc settings */
	else 	{
		stat = PL_sharedsettings( attr, val, lineval ); 
		if( stat == 0 && PLS.debug ) fprintf( PLS.diagfp, "config: setting %s to %s\n", attr, lineval );
		}

	/* don't forget that there are other settings (tmpdir, date-related, etc.) 
	 * that were handled by the TDH config file reader !! 
	 */

	}

fclose( fp );

SKIPCONFIG:
if( PLS.cgiargs != NULL && !projectrootfound ) {
	CGI_BAD_CHDIR:
	PLS.errfp = fopen( cgierrfile, "w" );
	if( PLS.errfp != NULL ) {
		fprintf( PLS.errfp, "cgi mode: no projectroot in config file, or could not chdir to projectroot\n" );
#ifdef UNIX
		fchmod( fileno( PLS.errfp ), 00666 );
#endif
		}
	return( 1 );
	}

/* get prefabs directory name if available.. */
/* this must come after config file is read, because in cgi mode PLOTICUS_PREFABS is set via config file. */
PLS.prefabsdir = getenv( "PLOTICUS_PREFABS" );
if( PLS.prefabsdir != NULL ) {
	TDH_setspecialincdir( PLS.prefabsdir ); /* set special include directory (#include $foo) */
        /* note: prefabsdir must reference static storage, either via getenv() or constant */
	}


return( 0 );
}
Esempio n. 3
0
int
PLP_print()
{
int i, lvp, first;
char attr[NAMEMAXLEN], *line, *lineval;

char *printstring, *label, *selectex, *outfile, *outmode;
char buf[512], tok[80];
int result, dontclose, nrecords;
FILE *outfp;

TDH_errprog( "pl proc print" );

/* initialize */
printstring = ""; label = ""; selectex = ""; outfile = ""; 
outmode = "w";

/* get attributes.. */
first = 1;
while( 1 ) {
	line = getnextattr( first, attr, &lvp );
	if( line == NULL ) break;
	first = 0;
	lineval = &line[lvp];

	if( strcmp( attr, "select" )==0 ) selectex = lineval;
	else if( strcmp( attr, "label" )==0 ) { label = lineval; convertnl( label ); }
	else if( strcmp( attr, "print" )==0 ) { printstring = lineval; convertnl( printstring ); }
	else if( strcmp( attr, "outfile" )==0 ) outfile = lineval;
	else if( strcmp( attr, "outmode" )==0 ) outmode = lineval;
	else Eerr( 1, "attribute not recognized", attr );
	}

if( printstring[0] != '\0' && Nrecords < 1 ) return( Eerr( 17, "Warning: no data has been read yet w/ proc getdata", "" ) );

fprintf( PLS.errfp, "Warning, proc print is deprecated in 2.40\n" );


/* now do the work.. */
dontclose = 0;
if( outfile[0] != '\0' ) {
	sprintf( tok, "%c", outmode[0] );
	outfp = fopen( outfile, tok );
	if( outfp == NULL ) { Eerr( 7259, "cannot open outfile", outfile ); outfp = PLS.diagfp; dontclose = 1; }
	}
else 	{ 
	outfp = PLS.diagfp; 
	dontclose = 1;
	}

if( label[0] != '\0' ) fprintf( outfp, "%s\n", label );

nrecords = 0;
for( i = 0; i < Nrecords; i++ ) {
	do_select( selectex, i, &result );
	if( result == 1 ) {
		if( printstring[0] != '\0' ) {
			do_subst( buf, printstring, i, NORMAL );
			fprintf( outfp, "%s\n", buf );
			}
		nrecords++;
		}
	}

setintvar( "NSELECTED", nrecords );

if( !dontclose ) fclose( outfp );

return( 0 );
}
Esempio n. 4
0
int
PLP_scatterplot()
{
int i;
char attr[NAMEMAXLEN], val[256];
char *line, *lineval;
int nt, lvp;
int first;

int stat;
int align;
double adjx, adjy;

int xfield, yfield;
char symbol[256];
double linelen;
char linedetails[256];
double xloc, yloc;
int cluster;
double radius;
char symcode[80];
double x, y;
char text[256];
double cx, cy;
double hlinelen;
char textdetails[256];
int lblfield;
char selex[256];
int result;
double sizescale;
int sizefield;
double ox[38], oy[38];
double clusterfact;
double oldx, oldy;
int dupcount;
int subdupcount;
int clustevery;
int verttext;
int nrow;
char legendlabel[256]; /* raised (can contain urls for clickmap) scg 4/22/04 */
char xrange[80], yrange[80];
double xlo, xhi, ylo, yhi;
char rhi[40], rlo[40];
double clusterdiff;
int realrow;
int clustermeth;
int symfield;
int symfield_userange;
int dupsleg;
char mapurl[MAXPATH], expurl[MAXPATH];
char maplabel[MAXTT], explabel[MAXTT];
int irow;
double ptx, pty;
double hw, txhi;
char linedir, reqlinedir;
double rectw, recth;
int dorect, rectoutline;
int clickmap_on;
int flop2;
int maxdups;
char labelword[80], labeltxt[80];
double vennden;

TDH_errprog( "pl proc scatterplot" );


/* initialize */
xfield = -1; yfield = -1;
strcpy( symbol, "" );
linelen = -1.0;
strcpy( linedetails, "" );
xloc = 0.0;
yloc = 0.0;
/* cluster = 1; */
cluster = 0;   /* changed and added to "breakers" in docs, scg 5/29/06 */
strcpy( text, "" );
strcpy( textdetails, "" );
lblfield = -1;
strcpy( selex, "" );
sizefield = -1;
sizescale = 0.5/72.0; /* correspond roughly with pt size */
clusterfact = 0.01;
verttext = 0;
strcpy( legendlabel, "" );
strcpy( xrange, "" );
strcpy( yrange, "" );
clustevery = 0;
clusterdiff = 0.001;
clustermeth = 0;
symfield = -1;
dupsleg = 0;
symfield_userange = 0;
strcpy( mapurl, "" ); strcpy( expurl, "" );
strcpy( maplabel, "" ); strcpy( explabel, "" );
dorect = 0;
rectoutline = 0;
linedir = reqlinedir = '\0'; /* scg 3/4/03 */
clickmap_on = 0;
strcpy( labelword, "@VAL" );
vennden = 0.0;

/* get attributes.. */
first = 1;
while( 1 ) {
	line = getnextattr( first, attr, val, &lvp, &nt );
	if( line == NULL ) break;
	first = 0;
	lineval = &line[lvp];

	if( stricmp( attr, "xfield" )==0 ) xfield = fref( val ) -1;
		
	else if( stricmp( attr, "yfield" )==0 ) yfield = fref( val ) -1;
	else if( stricmp( attr, "labelfield" )==0 ) lblfield = fref( val ) -1;
		
	else if( stricmp( attr, "symbol" )==0 ) strcpy( symbol, lineval );
	else if( stricmp( attr, "text" )==0 ) strcpy( text, val );
	else if( stricmp( attr, "textdetails" )==0 ) strcpy( textdetails, lineval );

	else if( stricmp( attr, "sizefield" )==0 ) sizefield = fref( val ) -1;
	else if( stricmp( attr, "sizescale" )==0 ) sizescale = atof( val ) * 0.5/72.0;
	else if( stricmp( attr, "xrange" )==0 ) strcpy( xrange, lineval );
	else if( stricmp( attr, "yrange" )==0 ) strcpy( yrange, lineval );
	else if( stricmp( attr, "clickmapurl" )==0 ) {
		if( PLS.clickmap ) { strcpy( mapurl, val ); clickmap_on = 1; }
		}
	else if( stricmp( attr, "clickmaplabel" )==0 ) {
		if( PLS.clickmap ) { strcpy( maplabel, lineval ); clickmap_on = 1; }
		}
        else if( stricmp( attr, "clickmaplabeltext" )==0 ) {
                if( PLS.clickmap ) { getmultiline( "clickmaplabeltext", lineval, MAXTT, maplabel ); clickmap_on = 1; }
                }

	else if( stricmp( attr, "linelen" )==0 ) {
		if( val[0] == '\0' ) linelen = -1.0;
		else	{
			linelen = atof( val );
			if( PLS.usingcm ) linelen /= 2.54;
			}
		}
	else if( stricmp( attr, "linedir" )==0 ) reqlinedir = tolower( val[0] );
	else if( stricmp( attr, "linedetails" )==0 ) strcpy( linedetails, lineval );
		
	else if( stricmp( attr, "xlocation" )==0 ) {
		Eposex( lineval, X, &xloc ); /* val -> lineval scg 5/3/99 */
		if( Econv_error() ) Eerr( 2394, "invalid xlocation", val );
		}
		
	else if( stricmp( attr, "ylocation" )==0 ) {
		Eposex( lineval, Y, &yloc ); /* val -> lineval 5/3/99 */
		if( Econv_error() ) Eerr( 2395, "invalid ylocation", val );
		}
		
	else if( stricmp( attr, "select" )==0 ) strcpy( selex, lineval );
	else if( stricmp( attr, "legendlabel" )==0 ) strcpy( legendlabel, lineval );

	else if( stricmp( attr, "cluster" )==0 ) {
		if( strnicmp( val, YESANS, 1 )==0 ) cluster = 1;
		else cluster = 0;
		}
	else if( stricmp( attr, "clusterdiff" )==0 ) {
		cluster = 1;
		clusterdiff = atof( val );
		}
	else if( stricmp( attr, "clustermethod" )==0 ) {
		cluster = 1;
		clustermeth = tolower( val[0] );  /* h, v, 2, u, r, ..  */
		}
	else if( stricmp( attr, "clusterfact" )==0 ) {
		cluster = 1;
		clusterfact = atof( val ) * .01;
		}
	else if( stricmp( attr, "clustevery" )==0 ) {
		cluster = 1;
		clustevery = atoi( val );
		if( clustevery < 1 ) clustevery = 1;
		}
	else if( stricmp( attr, "dupsleg" )==0 ) {
		if( strnicmp( val, YESANS, 1 )==0 ) { 
			dupsleg = 1; 
			cluster = 1; 
			clustermeth = 'l';
			strcpy( symbol, "sym6a" ); /* just to get us into symbol mode */
			}
		else dupsleg = 0;
		}
	else if( stricmp( attr, "symfield" )==0 ) {
		strcpy( symbol, "sym6a" ); /* just to get us into symbol mode */
		symfield = fref( val ) -1;
		symfield_userange = 0;
		}
	else if( stricmp( attr, "symrangefield" )==0 ) {
		strcpy( symbol, "sym6a" ); /* just to get us into symbol mode */
		symfield = fref( val ) -1;
		symfield_userange = 1;
		}
	else if( stricmp( attr, "verticaltext" )==0 ) {
		if( strnicmp( val, YESANS, 1 )==0 ) verttext = 1;
		else verttext = 0;
		}
	else if( stricmp( attr, "rectangle" )==0 ) {
		nt = sscanf( lineval, "%lf %lf %s", &rectw, &recth, val );
		if( nt == 3 ) rectoutline = 1;
		rectw *= 0.5;
		recth *= 0.5;
		rectw = Eax( rectw ) - Eax( 0.0 );
		recth = Eay( recth ) - Eay( 0.0 );
		dorect = 1;
		}

	else if( stricmp( attr, "labelword" ) == 0 ) strcpy( labelword, lineval );
	else if( stricmp( attr, "vennden" ) == 0 ) vennden = atof( val );

	else Eerr( 1, "attribute not recognized", attr );
	}


/* overrides and degenerate cases */
/* -------------------------- */
if( Nrecords < 1 ) return( Eerr( 17, "No data has been read yet w/ proc getdata", "" ) );
if( !scalebeenset() )
         return( Eerr( 51, "No scaled plotting area has been defined yet w/ proc areadef", "" ) );

if( xfield < 0 && yfield < 0 ) return( Eerr( 2205, "Niether xfield nor yfield defined", "" ));

if( lblfield >= 0 ) cluster = 0;  /* added scg 12/21/00 */

if( stricmp( legendlabel, "#usexname" )==0 ) getfname( xfield+1, legendlabel );
if( stricmp( legendlabel, "#useyname" )==0 ) getfname( yfield+1, legendlabel );

if( dorect ) strcpy( symbol, "" );


/* now do the plotting work.. */
/* -------------------------- */

if( cluster ) {
	/* make offsets */
	for( i = 0; i < 38; i++ ) {
		ox[i] = xofst[i] * clusterfact;
		oy[i] = yofst[i] * clusterfact;
		}

	/* determine cluster method */
	if( clustermeth == 0 ) {
		if( yfield < 0 ) clustermeth = 'v'; 	 /* 1-d horizontal - cluster vertically (was 'h'-scg 4/21/05) */
		else if( xfield < 0 ) clustermeth = 'h'; /* 1-d vertical - cluster horizontally (was 'v'-scg 4/21/05) */
		else clustermeth = '2'; 		 /* 2-d cluster */
		}
	}

/* ranges */
xlo = EDXlo;
xhi = EDXhi;
ylo = EDYlo;
yhi = EDYhi;
if( xrange[0] != '\0' ) {
	nt = sscanf( xrange, "%s %s", rlo, rhi );
	xlo = Econv( X, rlo );
	if( Econv_error() ) { Eerr( 3958, "xrange bad format", rlo ); xlo = EDXlo; }
	if( nt == 2 ) xhi = Econv( X, rhi );
	if( Econv_error() ) { Eerr( 3958, "xrange bad format", rhi ); xhi = EDXhi; }
	}
if( yrange[0] != '\0' ) {
	nt = sscanf( yrange, "%s %s", rlo, rhi );
	ylo = Econv( Y, rlo );
	if( Econv_error() ) { Eerr( 3958, "yrange bad format", rlo ); ylo = EDYlo; }
	if( nt == 2 ) yhi = Econv( Y, rhi );
	if( Econv_error() ) { Eerr( 3958, "yrange bad format", rhi ); yhi = EDYhi; }
	}






nrow = 0;
for( i = 0; i < Nrecords; i++ ) {

	if( selex[0] != '\0' ) { /* process against selection condition if any.. */
                stat = do_select( selex, i, &result );
                if( stat != 0 ) { Eerr( stat, "Select error", selex ); continue; }
                if( result == 0 ) continue; /* reject */
                }

	/* get x value.. */
	if( xfield >= 0 ) {
		x = fda( i, xfield, 'x' );
        	if( Econv_error() ) { conv_msg( i, xfield, "xfield" ); continue; }
		if( x < xlo || x > xhi ) continue;
		}

	/* get y value.. */
	if( yfield >= 0 ) {
		y = fda( i, yfield, 'y' );
        	if( Econv_error() ) { conv_msg( i, yfield, "yfield" ); continue; }
		if( y < ylo || y > yhi ) continue;
		}

	/* go to absolute units.. */
	if( xfield < 0 ) x = xloc;
	else x = Eax(x);
	if( yfield < 0 ) y = yloc;
	else y = Eay(y);


	/* put (x,y) into PLV array so points can be sorted.. */
	if( nrow >= PLVthirdsize ) {
		fprintf( PLS.errfp, "point capacity exceeded, skipping data point (raise using -maxvector)\n" );
		continue;
		}
	dat3d( nrow, 0 ) = x;
	dat3d( nrow, 1 ) = y;
	dat3d( nrow, 2 ) = (double)i;  /* added scg 12/21/00 - went from dat2d to dat3d */
				       /* need to keep track of actual location in data array for labels, sizefield, etc.. */
	nrow++;
	}


/* if clustering and not using a label field, sort PLV array */
if( cluster && lblfield < 0 && sizefield < 0 ) {
	if( PLS.debug ) fprintf( PLS.diagfp, "sorting points for scatterplot\n" );
	qsort( PLV, nrow, sizeof(double)*3, ptcompare );
	}



if( verttext ) Etextdir( 90 );

/* these are used in clustering.. */
oldx = NEGHUGE;
oldy = NEGHUGE;
dupcount = 0;
subdupcount = 0;
maxdups = 0;

strcpy( symcode, "sym6a" );
radius = 0.04;


/* in the following, text must come before symbol.. */
if( text[0] != '\0' || lblfield >= 0 ) {
	textdet( "textdetails", textdetails, &align, &adjx, &adjy, -3, "R", 1.0 );
	}
if( symbol[0] != '\0' ) {
	symdet( "symbol", symbol, symcode, &radius );
	}
if( linelen > 0.0 || rectoutline ) {
	linedet( "linedetails", linedetails, 0.5 );
	}
cx = Ecurtextwidth * 0.3;
cy = Ecurtextheight * 0.3;
hlinelen = linelen * 0.5;
txhi = cy + cy;
if( text[0] != '\0' ) hw = strlen( text ) * Ecurtextwidth * 0.5;

/* now display points.. */
for( irow = 0; irow < nrow; irow++ ) {
	x = dat3d( irow, 0 );
	y = dat3d( irow, 1 );
	realrow = (int)dat3d( irow, 2 ); /* added scg 12/21/00 */

	/* in this loop, you MUST USE REALROW, NOT IROW for accessing ancillary data fields!! */

	if( cluster ) {
		if( GL_close_to( x, oldx, clusterdiff ) && GL_close_to( y, oldy, clusterdiff ) ) {
			subdupcount++;
			if( subdupcount >= clustevery ) {
				dupcount++;
				subdupcount = 0;
				}

			if( dupcount % 2 == 0 ) flop2 = 1;
			else flop2 = -1;

			if( clustermeth == '2' && dupcount > 37 ) {
				maxdups = 37;
				dupcount = 0; /* mod */
				}

			if( clustermeth == 'h' ) x += ((dupcount+1)/2) * clusterfact * 2.0 * flop2;
			else if( clustermeth == 'v' ) y += ((dupcount+1)/2) * clusterfact * 2.0 * flop2;
			else if( clustermeth == 'u' ) y += dupcount * clusterfact * 2.0; /* 1D upward */
			else if( clustermeth == 'r' ) x += dupcount * clusterfact * 2.0; /* 1D rightward */
			else if( clustermeth == 'l' ) ; /* legend lookup, no offset */
			else if( clustermeth == '2' ) {  x += ox[dupcount%38]; y += oy[dupcount%38]; } /* 2-D */

			if( clustermeth == 'l' ) { /* if more duplicate points coming, skip.. */
				if( irow < nrow-1 ) {
					double nextx, nexty;
					nextx = dat3d( irow+1, 0 );
					nexty = dat3d( irow+1, 1 );
					if( GL_close_to( x, nextx, clusterdiff ) && 
					    GL_close_to( y, nexty, clusterdiff ) ) continue;
					}
				}
			}
		else {
			if( dupcount > maxdups ) maxdups = dupcount;
			oldx = x;
			oldy = y;
			dupcount = 0;
			subdupcount = 0;
			}
		}

	/* allow @field substitutions into url */
        if( clickmap_on ) {
		do_subst( expurl, mapurl, realrow, URL_ENCODED );
		do_subst( explabel, maplabel, realrow, NORMAL );
		}



	/* render text, mark or line.. */
	/* text can be combined with mark if text and symbol both specified */

	/* symbol or rectangle.. */
	if( symbol[0] != '\0' || dorect || ( text[0] == '\0' && linelen <= 0.0 && lblfield < 0 ) ) {
		if( symfield >= 0 ) {  /* look it up in legend list.. */
			if( symfield_userange ) {
                		stat = PL_get_legent_rg( atof( da( realrow, symfield ) ), symbol, NULL, NULL );
				}
                	else stat = PL_get_legent( da( realrow, symfield ), symbol, NULL, NULL );
			if( stat ) Eerr( 7429, "warning: symfield: no matching legend entry tag found", da( realrow, symfield ) );
			if( !dorect ) symdet( "symfield", symbol, symcode, &radius );
			}
		if( dupsleg ) {  /* look it up in legend list.. */
                	stat = PL_get_legent_rg( (double)dupcount+1, symbol, NULL, NULL );
			if( stat ) Eerr( 7692, "warning: dupsleg: no appropriate legend entry tag\n", "" );
			if( !dorect ) symdet( "symfield", symbol, symcode, &radius );
			/* note: currently all marks will be rendered; the last one will be on "top"  */
			}
		if( sizefield >= 0 ) 
			radius = sqrt((atof( da( realrow, sizefield ) ) * sizescale)/3.1415927);
			         /* sizefield scales up the AREA of symbol, not the diameter */
		if( dorect ) {
			char color[ COLORLEN ];
			strcpy( color, "" ); /* added scg 9/1/05 - heatmap bug */
			if( symfield >=0 || dupsleg ) sscanf( symbol, "%s", color ); /* strip off any trailing space */
			Ecblock( x-rectw, y-recth, x+rectw, y+recth, color, rectoutline );
			symbol[0] = '\0';
			}
		else if( vennden > 0.0 ) {
			double urad;
			for( urad = 0.01; urad < radius; urad += vennden ) Emark( x, y, symcode, urad );
			} 
		else Emark( x, y, symcode, radius );

		if( clickmap_on ) {
			if( dorect ) clickmap_entry( 'r', expurl, 0, x-rectw, y-recth, x+rectw, y+recth, 0, 0, explabel );
			else clickmap_entry( 'r', expurl, 0, x-radius, y-radius, x+radius, y+radius, 0, 0, explabel );
			}
			
		}

	/* text */
	if( text[0] != '\0' ) {
		if( symbol[0] != '\0' )  /* set text color etc... */
			textdet( "textdetails", textdetails, &align, &adjx, &adjy, -3, "R", 1.0 );
		if( sizefield >= 0 ) Etextsize( (int) (atof( da( realrow, sizefield ) ) * sizescale) );
		if( verttext ) { ptx = (x+cy)+adjx; pty = y; } /* cy puts midheight of character on point */
		else { ptx = x+adjx; pty = (y-cy)+adjy; }

		convertnl( text );
		Emov( ptx, pty );
		if( align == '?' ) Edotext( text, 'C' );
		else Edotext( text, align );
		if( symbol[0] != '\0'  )  /* restore symbol color etc... */
			symdet( "symbol", symbol, symcode, &radius );

		if( clickmap_on ) clickmap_entry( 'r', expurl, 0, ptx-hw, pty, x+hw, y+txhi, 0, 0, explabel );
		}

	/* label from data */
	else if( lblfield  >= 0 ) {
		if( sizefield >= 0 ) Etextsize( (int) (atof( da( realrow, sizefield ) ) * sizescale) );
		if( verttext) { ptx = (x+cy)+adjx; pty = y+adjy; } /* cy puts midheight of character on point */
		else { ptx = x+adjx; pty = (y-cy)+adjy; } 

		strcpy( labeltxt, labelword );
		GL_varsub( labeltxt, "@VAL", da( realrow, lblfield ) );

		Emov( ptx, pty );
		if( align == '?' ) Edotext( labeltxt, 'C' );
		else Edotext( labeltxt, align );

		if( clickmap_on ) {
			hw = strlen( labeltxt ) * Ecurtextwidth * 0.5;
			if( GL_member( align, "C?" ))clickmap_entry( 'r', expurl, 0, ptx-hw, pty, x+hw, y+txhi, 0, 0, explabel );
			else if( align == 'L' ) clickmap_entry( 'r', expurl, 0, ptx, pty, x+(hw*2.0), y+txhi, 0, 0, explabel );
			else if( align == 'R' ) clickmap_entry( 'r', expurl, 0, ptx-(hw*2.0), pty, x, y+txhi, 0, 0, explabel );
			}
		}

	/* line */         /* (no clickmap support) */   /* no legend support either (?) */
	else if( linelen > 0.0 ) {
		if( sizefield >= 0 ) hlinelen = linelen * 0.5 * atof( da( realrow, sizefield ) ); 
					/* sizefield acts as a scale factor to linelen */

		if( reqlinedir != '\0' ) linedir = reqlinedir;
		else if( xfield >= 0 && yfield >= 0 ) linedir = 'h'; 	/* arbitrary .. scg 5/16/03 */
		else if( xfield >= 0 ) linedir = 'v';
		else linedir = 'h';			/* scg 3/5/03 */

		if( linedir == 'v' ) { Emov( x, y-hlinelen ); Elin( x, y+hlinelen ); }
		else if( linedir == 'u' ) { Emov( x, y ); Elin( x, y+(hlinelen*2.0) ); }
		else if( linedir == 'r' ) { Emov( x, y ); Elin( x+(hlinelen*2.0), y ); }
		else { Emov( x-hlinelen, y ); Elin( x+hlinelen, y ); }
		}

	}
if( verttext ) Etextdir( 0 );

if( legendlabel[0] != '\0' ) {
	char s[40];
	sprintf( s, "%d", nrow );
	GL_varsub( legendlabel, "@NVALUES", s );
	if( linelen <= 0.0 && lblfield < 0 && text[0] == '\0' )
		PL_add_legent( LEGEND_SYMBOL, legendlabel, "", symbol, "", "" );
	else if( symbol[0] != '\0' && text[0] != '\0' )
		PL_add_legent( LEGEND_SYMBOL+LEGEND_TEXT, legendlabel, "", text, textdetails, symbol );
	else if( linelen > 0.0 ) {
		char dirstr[8];
		sprintf( dirstr, "%c", linedir );
		PL_add_legent( LEGEND_LINEMARK, legendlabel, "", linedetails, dirstr, "" );
		}
	}

setintvar( "NVALUES", nrow );
maxdups++;
setintvar( "MAXDUPS", maxdups );

return( 0 );
}