XForms: tick values for xyplot

moini@eleceng.adelaide.edu.au
Wed, 11 Nov 1998 16:21:00 +1030 (CST)

# To subscribers of the xforms list from moini@eleceng.adelaide.edu.au :

The current ticking functions for xyplot seem to generate strange numbers
very often.
Here are a couple of functions that I use to generate more sensible tick
numbers for my xyplot print outs.

People can give these a try and if everyone becomes happy, these may be
implemented for the xyplot.

Note that after these functions the program should check the numbers
against min and max.
In my program I also check whether the size of the fonts and amount of
available space allows a reasonable spacing between the numbers.

/**************************************************************************/
/**************************************************************************/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define DEBUG_PRINT
int DEBUG=0;

/**************************************************/
double dabs(double x)
{
if(x>0.0)return x;
else return (-x);
}

/**************************************************/
double
round(double x)
{
return (double)((int)(x < 0 ? x - 0.5 : x + 0.5));
}
/**************************************************/
int logscale(double xmin,double xmax,int n ,double *xout, int *nout, int *loglin)
{

double xo1,xo2,ticsep,xo[100];
int i=0,nmin,nmax,nticsout;

/*
* Check whether proper input values were supplied.
*/
if (xmin >= xmax || n <= 0 || xmin <= 0.0) {
fprintf(stderr, "logscale: Improper values supplied as input\n");
if (xmin <= 0.0)
fprintf(stderr, "Zero or negative minimum value input: %f\n", xmin);

return(1);
}
#ifdef DEBUG_PRINT
if(DEBUG)printf("log1\n");
#endif

/*
* Values are translated from the linear region to the logarithmic
*/

#ifdef DEBUG_PRINT
if(DEBUG)printf("ll1 %d\n",(int)(log10(xmax)-log10(xmin)));
#endif
if((((int)(log10(xmax)-log10(xmin)))>=1.0) && (xmax/xmin>3.0)){

nmin=(int)(floor(log10(xmin)));
nmax=(int)(ceil(log10(xmax)));
*nout=nmax-nmin+1;


for(i=0;i<=(nmax-nmin);i++){
xout[i]=pow(10.0,(double)(i+nmin));
#ifdef DEBUG_PRINT
if(DEBUG)printf("log2 %d %g\n",i,xout[i]);
#endif
}
*loglin=1;
}
else{
#ifdef DEBUG_PRINT
if(DEBUG)printf("log3\n");
#endif
*loglin=0;
*nout=n;
linscale(xmin,xmax,*nout, xo, &nticsout);
xo1=xo[0];
xo2=xo[nticsout];
ticsep=xo[1]-xo[0];
*nout=nticsout;



for(i=0;i<= *nout;i++){
xout[i]=xo1+ticsep*(double)i;
#ifdef DEBUG_PRINT
if(DEBUG)printf("log3 %d %g\n",i,xout[i]);
#endif
}
#ifdef DEBUG_PRINT
if(DEBUG)printf("log1\n");
#endif


}

#ifdef DEBUG_PRINT
if(DEBUG){
for(i=0;i<*nout;i++){
printf("%g ",xout[i]);
}
printf("nout=%d\n",*nout);
}
#endif


return 0;

}


/**************************************************/
double ten2pow(int i)
{
double a = 1.0;
int j;

#ifdef DEBUG_PRINT
if(DEBUG)printf("ten2p %d\n",i);
#endif
if (i > 0)
for (j = 0; j < i; j++)
a *= 10.0;
else if (i < 0)
for (j = 0; j > i; j--)
a /= 10.0;

#ifdef DEBUG_PRINT
if(DEBUG)printf("ten2p\n");
#endif
return (a);
}

/**************************************************/
int
linscale(double min,double max,int n,double *xout,int *nout)
{
static double vint[] = { 1.0, 2.0, 5.0, 10.0 };
static double sqr[] = { 1.414214, 3.162278, 7.071068 };
double fn, a, al, b, fm1;
double dist,minp,maxp;
static double del = 0.000002;
char tmp_s[256];
int i,nal,m1,m2;
int changed_minp=0;

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1 %g %g %d\n",min,max,n);
#endif

/*
* check whether proper input values were supplied
*/

if (min > max || n < 0) {
fprintf(stderr,"Improper input supplied %f %f %d\n", min, max, n);
return(1);
}

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif
fn = (double) n;

/*
* find approximate interval size a
*/

a = (max - min) / fn;
if (max==min) {
for(i=0;i<n;i++){
xout[i]=min;
}
*nout=n;
return (0);
}

al = log10((double)a);
nal = (int) al;
if (a < 1.0)
nal -= 1;

/*
* a is scaled into variable named b between 1 and 10
*/
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1 min %g max %g fn %g a %d al %g nal %d\n",min,max,fn,a,al,nal);
#endif

b = a / ten2pow(nal);

/*
* the closest permissible value for b is found
*/
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1 fn %g a %d al %g nal %d\n",fn,a,al,nal);
#endif

for (i = 0; b > sqr[i] && i < 3; i++);
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1 i=%d\n",i);
#endif

/*
* the interval size is computed
*/

dist = vint[i] * ten2pow(nal);
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif
fm1 = min / dist;
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif

m1 = fm1;
#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif

if (fm1 < 0.0)
m1 -= 1;

if (dabs(((double)m1 + 1.0 - fm1)) < del)
m1 += 1;

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif
/*
* the new minimum and maximum limits are found
*/

minp = (dist) * (double)m1;
m2=m1;

fm1 = max / dist;
m1 = (int)(fm1 + 1.0);

if (fm1 < -1.0 || dabs((fm1 + 1.0 - (double)m1)) < del)
m1 -= 1;

maxp = dist * (double)m1;

/*
* adjust limits to account for round-off if necessary
*/

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1 %g %g\n",minp,min);
#endif

changed_minp=0;
if (minp > min) {
minp = min;
changed_minp=1;
}

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin1\n");
#endif
if (maxp < max){
maxp = max;
}

#ifdef DEBUG_PRINT
if(DEBUG)printf("lin10 min=%g max=%g dist=%g\n",minp,maxp,dist);
#endif

for(i=0;i<=(int)round((maxp-minp)/(dist));i++){
xout[i]=(minp)+(double)i * (dist);
if(changed_minp==0 && m2+i==0){
xout[i]=0.0;
}
#ifdef DEBUG_PRINT
if(DEBUG)printf("out[%d]=%g\n",i,xout[i]);
#endif
}
*nout=(int)round(((maxp-minp)/(dist)))+1;
#ifdef DEBUG_PRINT
if(DEBUG)printf("\n nout=%d\n",*nout);
#endif

return 0;
}

/**************************************************************/
/**************************************************************/
/**************************************************************/
/**************************************************************/

main()
{
int i=0;
double xout[100];
int nout=0;
int loglin=0;


linscale(0,5.0,5,xout,&nout);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

linscale(0,3.6,5,xout,&nout);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

linscale(-0.67,-0.33,5,xout,&nout);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

logscale(1,1e6,5,xout,&nout,&loglin);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

logscale(0.001,1e3,5,xout,&nout,&loglin);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

logscale(0.1,0.33,5,xout,&nout,&loglin);
for(i=0;i<nout;i++)printf("%g ",xout[i]);
printf("\n\n");

}
_________________________________________________
To unsubscribe, send the message "unsubscribe" to
xforms-request@bob.usuf2.usuhs.mil or see
http://bob.usuf2.usuhs.mil/mailserv/xforms.html
XForms Home Page: http://bragg.phys.uwm.edu/xforms
List Archive: http://bob.usuf2.usuhs.mil/mailserv/list-archives/