file: parcoord.c
/* parcoord.c - function to plotting data using parallel coordinates for
XmdvTool */
/* Copyright 1994, Matthew O. Ward
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without fee
* is granted provided that the above copyright notice appears in all copies.
* It is provided "as is" without express or implied warranty.
*/
/* display data using parallel coordinates. Each dimensional axis is layed
out in a vertical line, evenly spaced between dimensions. The top and
bottom of each line coincide with the maximum and minimum for that
dimension. Each data point creates a polyline across these axes. Labels
are printed along the top of each dimension, and brush coverage display
consists of a single shaded region across the drawing area. */
#include "XmdvTool.h"
#include "parcoord.h"
#include "brush_oper.h"
#include "util.h"
#include "multi_select.h"
extern Widget appShell;
extern GC gc, xor_gc;
extern unsigned long color_cells[NUM_COLOR_CELLS];
extern XColor outline_col;
extern int dims, data_size;
extern double dim_min[MAXDIM], dim_max[MAXDIM];
extern char names[MAXDIM][MAXLABEL];
extern double *br_pos, *br_size;
/* the brushes */
extern Brush brushes[MAXBRUSH];
/* is this a color display? */
extern int COLOR;
extern int X_SIZE, Y_SIZE;
char message[MAXLABEL];
Arg wargs[10];
void do_par(Widget w)
{
int i, j, dimwidth, halfwidth;
double data[MAXDIM];
XPoint xpts[MAXDIM*2+1];
XFontStruct *font; /* the font to draw text with */
int font_height; /* the height of the font */
int dummy; /* dummy var passed to XTextExtents() */
XCharStruct overall; /* for finding extents */
int x,y; /* x/y location for labels */
int brush; /* the current brush number */
unsigned long pixel; /* the brush color pixel value */
/* compute layout of axes */
dimwidth = X_SIZE/dims;
halfwidth = dimwidth/2;
/* if brush coverage is to be displayed, compute polyline by going first */
/* through the top edges of the brush and then through the bottom edges */
if(COLOR == 1)
for(brush=0; brush<MAXBRUSH; brush++)
{
/* if this brush is not being displayed, skip it */
if(brushes[brush].display == FALSE)
continue;
/* set the appropriate brush color */
XSetForeground(XtDisplay(w),gc, color_cells[BRUSH_COLOR(brush)]);
for(i=0, j=0; j<dims; j++)
{
/* x positions are fixed y positions normalized over axis height */
xpts[i].x = j*dimwidth + halfwidth;
xpts[i].y = (brushes[brush].pos[j] + brushes[brush].size[j]/2. -
dim_min[j]) *
((double) Y_SIZE) / (dim_max[j] - dim_min[j]);
xpts[i].y = Y_SIZE - xpts[i].y;
i++;
}
/* same thing for bottom extent of brush */
for(j = dims-1;j >= 0;j--)
{
xpts[i].x = j*dimwidth + halfwidth;
xpts[i].y = (brushes[brush].pos[j] - brushes[brush].size[j]/2. -
dim_min[j]) *
((double) Y_SIZE) / (dim_max[j] - dim_min[j]);
xpts[i].y = Y_SIZE - xpts[i].y;
i++;
}
xpts[i].x = xpts[0].x;
xpts[i].y = xpts[0].y;
/* output brush coverage */
XFillPolygon(XtDisplay(w), XtWindow(w), gc, xpts, dims*2+1,
Complex, CoordModeOrigin);
/* draw boundary coverage if necessary */
if(brushes[brush].bound != BOUND_STEP)
ParCoordDrawBound(brush);
}
if(COLOR == 1)
{
/* first draw all points in the data color */
for(i=0; i<data_size; i++)
{
get_data(data, i);
pixel = ColorFromOperations(data);
/* if this point is masked, skip it */
if(pixel == COLOR_NONE)
continue;
/* first time through only paint regular data */
if(pixel != color_cells[CCELL_DATA])
continue;
XSetForeground(XtDisplay(w),gc, pixel);
for(j=0; j<dims; j++)
{
xpts[j].x = j*dimwidth + halfwidth;
xpts[j].y = (data[j] - dim_min[j]) * ((double) Y_SIZE) /
(dim_max[j] - dim_min[j]);
xpts[j].y = Y_SIZE - xpts[j].y;
}
XDrawLines(XtDisplay(w), XtWindow(w), gc, xpts, dims,
CoordModeOrigin);
}
/* now paint all points covered by an operation */
for(i=0; i<data_size; i++)
{
get_data(data, i);
pixel = ColorFromOperations(data);
/* if this point is masked, skip it */
if(pixel == COLOR_NONE)
continue;
/* second time through don't paint regular data */
if(pixel == color_cells[CCELL_DATA])
continue;
XSetForeground(XtDisplay(w),gc, pixel);
for(j=0; j<dims; j++)
{
xpts[j].x = j*dimwidth + halfwidth;
xpts[j].y = (data[j] - dim_min[j]) * ((double) Y_SIZE) /
(dim_max[j] - dim_min[j]);
xpts[j].y = Y_SIZE - xpts[j].y;
}
XDrawLines(XtDisplay(w), XtWindow(w), gc, xpts, dims,
CoordModeOrigin);
}
}
else
{
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_TEXT]);
for(i=0; i<data_size; i++)
{
get_data(data, i);
for(j=0; j<dims; j++)
{
xpts[j].x = j*dimwidth + halfwidth;
xpts[j].y = (data[j] - dim_min[j]) * ((double) Y_SIZE) /
(dim_max[j] - dim_min[j]);
xpts[j].y = Y_SIZE - xpts[j].y;
}
XDrawLines(XtDisplay(w), XtWindow(w), gc, xpts, dims,
CoordModeOrigin);
}
}
/* finally, draw axes and labels */
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_TEXT]);
for(i=0; i<dims; i++)
XDrawLine(XtDisplay(w), XtWindow(w), gc,
i*dimwidth+halfwidth, 0, i*dimwidth+halfwidth, Y_SIZE);
/* do labels */
/* get the font */
font = XQueryFont(XtDisplay(w), XGContextFromGC(gc));
/* Get initial extents */
XTextExtents(font, "X", 1, &dummy, &dummy, &dummy,
&overall);
font_height = overall.ascent + overall.descent;
/* add letters one at a time until space runs out */
for(i=0; i<dims; i++)
{
/* initial coordinates */
x = i*dimwidth + halfwidth + overall.width/2;
y = font_height * 1.1;
for(j=0; j<strlen(names[i]); j++)
{
XTextExtents(font, &names[i][j], 1, &dummy, &dummy, &dummy,
&overall);
if(x+overall.width > (i+1)*dimwidth+halfwidth-overall.width)
break;
XDrawString(XtDisplay(w), XtWindow(w), gc, x, y,
&names[i][j], 1);
x += overall.width;
}
}
}
/*
* RedrawSingleParCoord() - Redraw a single polyline in the the parallel
* coordinate display.
*/
void RedrawSingleParCoord(Widget w, int point)
{
int j, dimwidth, halfwidth;
double data[MAXDIM];
XPoint xpts[MAXDIM*2+1];
/* compute layout of axes */
dimwidth = X_SIZE/dims;
halfwidth = dimwidth/2;
/* set the color */
if(COLOR == 1)
{
if(MultiSelectCovered(point))
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_PAINT]);
/*********** this needs to be fixed at some point ***********/
else if(covered(data) == 1)
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_HIGHLIGHT]);
else
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_DATA]);
}
else
XSetForeground(XtDisplay(w),gc, color_cells[CCELL_TEXT]);
/* draw polyline */
get_data(data, point);
for(j = 0;j < dims;j++) {
xpts[j].x = j*dimwidth + halfwidth;
xpts[j].y = (data[j] - dim_min[j]) * ((double) Y_SIZE) /
(dim_max[j] - dim_min[j]);
xpts[j].y = Y_SIZE - xpts[j].y;
}
XDrawLines(XtDisplay(w), XtWindow(w), gc, xpts, dims, CoordModeOrigin);
}
/*
* ParCoordDrawAverage() - Draw an average value on the parallel
* coordinate display.
*
* PARAMETERS
* data The average point to draw
*
* RETURNS
* void
*/
void ParCoordDrawAverage(double data[MAXDIM])
{
Widget canvas_w;
int j, dimwidth, halfwidth;
XPoint xpts[MAXDIM*2+1];
/* get the canvas widget */
if(!(canvas_w = WcFullNameToWidget(appShell,"*canvas")))
{
fprintf(stderr, "Error getting *canvas in ParCoordDrawAverage()\n");
return;
}
/* compute layout of axes */
dimwidth = X_SIZE/dims;
halfwidth = dimwidth/2;
/* draw polyline */
for(j = 0;j < dims;j++) {
xpts[j].x = j*dimwidth + halfwidth;
xpts[j].y = (data[j] - dim_min[j]) * ((double) Y_SIZE) /
(dim_max[j] - dim_min[j]);
xpts[j].y = Y_SIZE - xpts[j].y;
}
XDrawLines(XtDisplay(canvas_w), XtWindow(canvas_w),
gc, xpts, dims, CoordModeOrigin);
}
/*
* ParCoordDrawBound() - Draw the brush boundary in the parallel
* coordinate view.
*
* PARAMETERS
* br_num Brush number to draw boundary for
*
* RETURNS
* void
*/
void ParCoordDrawBound(int br_num)
{
int i;
Widget canvas_w; /* the canvas */
XPoint xpts[MAXDIM]; /* XPoint array for drawline polyline */
int dimwidth, halfwidth;
/* get the canvas widget */
if(!(canvas_w = WcFullNameToWidget(appShell,"*canvas")))
{
fprintf(stderr, "Error getting *canvas in ParCoordDrawBound()\n");
return;
}
/* compute layout of axes */
dimwidth = X_SIZE/dims;
halfwidth = dimwidth/2;
/* set the appropriate color */
XSetForeground(XtDisplay(canvas_w), xor_gc,
color_cells[BRUSH_COLOR(br_num)]);
for(i=0; i<dims; i++)
{
xpts[i].x = i*dimwidth + halfwidth;
xpts[i].y = (brushes[br_num].pos[i] + brushes[br_num].size[i]/2.0 +
brushes[br_num].bound_offset[i] -
dim_min[i]) * ((double) Y_SIZE) / (dim_max[i] - dim_min[i]);
xpts[i].y = Y_SIZE - xpts[i].y;
}
XDrawLines(XtDisplay(canvas_w), XtWindow(canvas_w), xor_gc, xpts, dims,
CoordModeOrigin);
for(i=0; i<dims; i++)
{
xpts[i].x = i*dimwidth + halfwidth;
xpts[i].y = (brushes[br_num].pos[i] - brushes[br_num].size[i]/2.0 -
brushes[br_num].bound_offset[i] -
dim_min[i]) * ((double) Y_SIZE) / (dim_max[i] - dim_min[i]);
xpts[i].y = Y_SIZE - xpts[i].y;
}
XDrawLines(XtDisplay(canvas_w), XtWindow(canvas_w), xor_gc, xpts, dims,
CoordModeOrigin);
}
C++ to HTML Conversion by ctoohtml