1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
-------- Extending XGobi --------
There are two ways in which you can add your own functionality to
XGobi. The first is to modify the code directly. This has been
successfully done by one person, but I suspect that it is the
more difficult of the two options. The second is to write your
own main() and call XGobi as a function, and the files in this
directory provide a simple example of how to do this.
Before going into any detail, let me say that I hope that anyone
choosing this option will communicate with us while designing and
writing the code. First because we're interested in knowing what
people want to do with XGobi, and second because we might be able
to help you do it better or more easily. And third, come to
think of it, because you can let us know that we should be
careful not to modify the XGobi code in such a way that your work
has to be done over.
Deborah, dfs@research.att.com; Di, dicook@iastate.edu
-------- Sample program --------
The files in this directory are as follows:
prog.c contains main() and a few other functions used in prog.
widgets.c contains the code that creates the simple prog control
panel and attaches functionality to its two buttons.
prog.h contains declarations of a small number of global
variables.
Prog contains resources for the color and font of the prog
control panel.
runprog is a shell script that tells prog where to find
the resource file; that is, if you run prog without the
resource file, you'll just get a black and white control panel;
if you move Prog to wherever you keep your resource files or
use runprog, you'll see a more colorful panel with a big italic
font.
The sample program prog is called with an argument, and two
sample datafiles are in the data subdirectory. 'runprog
data/river' and 'runprog data/tes' can be run.
Essentially, prog creates its own control panel, then initiates
an XGobi process by passing its single argument through as a
string so that XGobi knows where to find the data. Prog then has
its own version of a function called RunWorkProcs() instead of
using XGobi's version.
-------- The Event Loop --------
An X program always has an event loop running, looking for
input: usually user-generated mouse motions and so forth. The
XGobi event loop is called XGobiMainLoop() and it's in
xgobitop.h.
A work proc is a routine that runs once whenever the event loop
finds no events, a sort of run-while-idle routine. In XGobi,
continuous processes such as rotation are handled using work
procs: for example, if no user input is found, spin_once().
Usually, an X programmer doesn't write her own RunWorkProcs()
routine, but we found it necessary to do so for XGobi.
In prog, I added one additional background routine to the set
used in XGobi -- it is called loop_once() and it changes the
color, plotting character and location of each point every time
it runs.
-------- How it works --------
It's easy to change color, plotting character and even point
location because prog owns every one of XGobi's data structures.
In loop_once(), prog uses xg->nrows and xg->ncols_used to
define its for loops, and it writes directly into the following
data arrays:
xg->color_now[]
xg->glyph_now[].type
xg->glyph_now[].size
xg->raw_data[][]
The changes to color and glyph will show up on the screen
with the next plot_once() command; the changes to the raw data
need to be sent through the data pipeline: the raw data
values are mapped to big integers (xg->world_data[][]) then projected
down into the plane (xg->planar[].x and xg->planar[].y) and
finally mapped onto the screen (xg->screen[].x and .y). (I've
skipped a couple of steps, but that's the idea.)
Here is a list of data structures you might want to write into:
xg->raw_data[][]
float, xg->nrows x xg->ncols
Actually, there's one tricky point about the number of
columns. The user supplies a matrix of size n by p; XGobi
builds a data matrix of size n by p+1 so that it can allow
the user to create a variable during brushing. So you
probably want to look over xg->ncols_used (p before the
extra variable has been created, p+1 afterwards) rather than
xg->ncols (always p+1).
In fact, there's a similar tricky point about xg->nrows.
If the user has deleted points during brushing, then the
number of points actually displayed in the plot is
xg->nrows_in_plot. In the XGobi code, we often loop over
xg->nrows_in_plot to save time.
I don't recommend trying to muck about with xg->nrows or
xg->ncols once you've initiated an XGobi. So many things
would need to be reallocated that we haven't dared to
try this ourselves. If you aren't sure in advance how
much space you're going to need, then allocate space for
lots of columns and lots of rows, and then use rows_in_plot[]
to hold the data you're really working with.
xg->color_now[]
unsigned long, of length xg->nrows
xg->glyph_now[].type
int, of length xg->nrows. The types are defined in xgobitypes.h
#define PLUS_GLYPH 1
#define X_GLYPH 2
#define OPEN_RECTANGLE_GLYPH 3
#define FILLED_RECTANGLE_GLYPH 4
#define OPEN_CIRCLE_GLYPH 5
#define FILLED_CIRCLE_GLYPH 6
#define POINT_GLYPH 7
xg->glyph_now[].size
int, of length xg->nrows. The values range from 1 (TINY) to
5 (JUMBO).
xg->erased[]
unsigned short, of length xg->nrows, 0 if not erased,
1 if erased
xg->nrows_in_plot
int, number of points to be plotted
xg->rows_in_plot[]
int *, of length xg->nrows_in_plot
xg->delete_erased_points
Boolean; if True, then the currently erased points are
deleted: that is, they aren't considered when scaling
or doing projection pursuit.
xg->nlinks
int, number of connecting line segments
xg->connecting_lines[]
connect_lines: struct {int a, b;}, of length xg->nlinks,
specifies the row numbers of the pair of points to be
connected. If you change of xg->nlinks, you can use
XtRealloc() to reallocate this vector.
xg->line_color_now[]
unsigned long, the color of each line, in the order
in which they appear in xg->connecting_lines[]
xg->nsticky_ids
int, number of sticky (persistent) labels
xg->sticky_ids[]
Cardinal (unsigned int), of length xg->nsticky_ids,
the row numbers of the points to be labelled with sticky
labels. If you change of xg->nsticky_ids, you can
use XtRealloc() to reallocate this vector.
xg->rowlab[][]
char **, of length xg->nrows, the label of each row
xg->collab[][]
char **, of length xg->ncols, the label of each column
In some cases, you might want to call routines rather than write
into data structures. Let's suppose that you want to use
software to choose the variables that will be used in a grand
tour. You can call tour_varselect(j, &xgobi) where j is the
number of the variable that you want to add or delete from the
current set. This routine will set the value of xg->numvars_t,
the number of variables in the current tour, add or subtract an
item from xg->tour_vars[], and fix up the appearance of the
variable selection panel.
-------- Compiling --------
The XGobi main(), found in xgobi.c, has simply been replaced
with the main() for prog. So when prog is compiled, it needs
the XGobi include files and libxgobi.a, an archive containing
every .o file from the XGobi source with the exception of
xgobi.o. We build that library by including these lines in our
XGobi Makefile:
lib: ${OBJ}
rm -f libxgobi.a
ar cr libxgobi.a ${OBJ}
ranlib libxgobi.a
|