/* DX module to read XmdvTool format multivariate data and create 3 dx fields which will form the parallel coordinates view, the data itself, the labels, and the axes. Used in parcoord.net Last modified: 6/13/96 by MOW */ #include #include #include #define MAXDIM 20 /* arbitrary, to avoid dynamic allocation of arrays */ #define SCALE 100.0 /* this allows text to be of proper proportion to plot */ Error m_ReadMDVpc(Object *input, Object *out) { FILE *in; /* input data file */ int i, j, vert = 0; float datum, norm, *p_dp, *p_lp, *p_ap; int dim, count, *p_dc, *p_ac; char *filename, *p_ld; Array dp = NULL, dc = NULL, lp = NULL, ld = NULL, ap = NULL, ac = NULL; Field d = NULL, l = NULL, a = NULL; float min[MAXDIM], max[MAXDIM], xpos[MAXDIM]; int card[MAXDIM]; char label[MAXDIM][80], *label_p[MAXDIM]; if(!input[0]) { DXSetError(ERROR_BAD_PARAMETER, "missing filename"); goto error; } else if(!DXExtractString(input[0], &filename)) { DXSetError(ERROR_BAD_PARAMETER, "filename must be a string"); goto error; } in = fopen(filename,"r"); if (!in) { fprintf(stderr, "cannot open filename %s\n", filename); return 0; } /* read first line of input and insure it is valid */ fscanf(in, "%d %d", &dim, &count); if (dim < 1 || dim >= MAXDIM || count < 1) { fprintf(stderr, "bad dimension size or count: %d, %d\n", dim, count); return 0; } /* skip end of line from previous read, then scan in labels */ fgets(label[0], 80, in); for(i = 0;i < dim;i++) { fgets(label[i], 80, in); /* strip off newline character */ label[i][strlen(label[i])-1] = '\0'; label_p[i] = label[i]; } /* read in min and max for each dimension */ for(i = 0;i < dim;i++) fscanf(in, "%f %f %d", &min[i], &max[i], &card[i]); /* compute the normalized (between 0 and SCALE) x positions based on the number of dimensions */ for(i = 0;i < dim;i++) xpos[i] = SCALE * (float)i / ((float)dim - 1.0); /* create 6 arrays */ dp = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 2); dc = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); lp = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 2); ld = DXMakeStringListV(dim, label_p); ap = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 2); ac = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); if(!dp || !dc || !lp || !ld || !ap || !ac) goto error; /* create 3 fields */ d = DXNewField(); l = DXNewField(); a = DXNewField(); if(!d || !l || !a) goto error; /* allocate space in arrays to hold data */ if(!DXAddArrayData(dp, 0, dim*count, NULL)) goto error; if(!DXAddArrayData(dc, 0, (dim-1)*count, NULL)) goto error; if(!DXAddArrayData(lp, 0, dim, NULL)) goto error; if(!DXAddArrayData(ap, 0, dim*2, NULL)) goto error; if(!DXAddArrayData(ac, 0, dim, NULL)) goto error; /* read the data, normalize it (between 0 and SCALE), and write it to the first output field */ p_dp = (float *)DXGetArrayData(dp); if(!p_dp) goto error; for(i = 0;i < count;i++) { for(j = 0;j < dim;j++) { fscanf(in, "%f", &datum); norm = SCALE * (datum - min[j]) / (max[j] - min[j]); *(p_dp++) = xpos[j]; *(p_dp++) = norm; } } /* now compute connections - note only have N-1 connections per datum for N dimensions */ p_dc = (int *)DXGetArrayData(dc); if(!p_dc) goto error; for(i = 0;i < count;i++) { for(j = 0;j < dim-1; j++) { *(p_dc++) = vert; *(p_dc++) = vert+1; vert++; } /* last vertex doesn't connect to anything - all connections 1-way */ vert++; } if(!DXSetStringAttribute((Object)dc, "element type", "lines")) goto error; /* finish up field description */ if(!DXSetComponentValue(d, "positions", (Object)dp)) goto error; if(!DXSetComponentValue(d, "connections", (Object)dc)) goto error; if(!DXEndField(d)) goto error; out[0] = (Object)d; /* now create field for text labels (positions and data) */ /* note the y-value of position is fixed */ p_lp = (float *)DXGetArrayData(lp); if(!p_lp) goto error; for(i = 0;i < dim;i++) { *(p_lp++) = xpos[i]; *(p_lp++) = SCALE; } if(!DXSetComponentValue(l, "positions", (Object)lp)) goto error; if(!DXSetComponentValue(l, "data", (Object)ld)) goto error; if(!DXEndField(l)) goto error; out[1] = (Object)l; /* finally, create field for axes (positions and connections) */ p_ap = (float *)DXGetArrayData(ap); if(!p_ap) goto error; /* each axis has 2 positions and 1 connection */ for(i = 0;i < dim;i++) { *(p_ap++) = xpos[i]; *(p_ap++) = SCALE; *(p_ap++) = xpos[i]; *(p_ap++) = 0.0; } p_ac = (int *)DXGetArrayData(ac); if(!p_ac) goto error; for(i = 0;i < dim*2;i= i+2) { *(p_ac++) = i; *(p_ac++) = i+1; } if(!DXSetStringAttribute((Object)ac, "element type", "lines")) goto error; if(!DXSetComponentValue(a, "positions", (Object)ap)) goto error; if(!DXSetComponentValue(a, "connections", (Object)ac)) goto error; if(!DXEndField(a)) goto error; out[2] = (Object)a; return OK; error: DXDelete((Object)d); DXDelete((Object)l); DXDelete((Object)a); DXDelete((Object)dp); DXDelete((Object)dc); DXDelete((Object)lp); DXDelete((Object)ld); DXDelete((Object)ap); DXDelete((Object)ac); }