1 /* p1d.c */
2 /*
3 * ggobi
4 * Copyright (C) AT&T, Duncan Temple Lang, Dianne Cook 1999-2005
5 *
6 * ggobi is free software; you may use, redistribute, and/or modify it
7 * under the terms of the Eclipse Public License, which is distributed
8 * with the source code and displayed on the ggobi web site,
9 * www.ggobi.org. For more information, contact the authors:
10 *
11 * Deborah F. Swayne dfs@research.att.com
12 * Di Cook dicook@iastate.edu
13 * Duncan Temple Lang duncan@wald.ucdavis.edu
14 * Andreas Buja andreas.buja@wharton.upenn.edu
15 */
16
17 /*
18 * The 1d plots use the values of world_data (or missing_world_data)
19 * for the variable of interest, but they use tform (or missing)
20 * to do the spreading calculations, which are done in floating point.
21 *
22 * At the very end, to deal with jittering, they remove the jitter
23 * from the selected variable and add it to the spread direction.
24 */
25
26 #include <gtk/gtk.h>
27 #include "vars.h"
28 #include "externs.h"
29
30 /*
31 * min and max for 'forget it' dotplot's texturing axis;
32 * they're defined so as to locate the plot in the center of
33 * the window, with the texturing values returned on a range
34 * of [0,100].
35 *
36 * The min and max are calculated on the fly for the ash.
37 */
38 #define FORGETITAXIS_MIN -100.
39 #define FORGETITAXIS_MAX 200.
40
41 RedrawStyle
p1d_activate(gint state,displayd * display,ggobid * gg)42 p1d_activate (gint state, displayd * display, ggobid * gg)
43 {
44 GList *slist;
45 splotd *sp;
46 GGobiData *d = display->d;
47
48 if (state) {
49 for (slist = display->splots; slist; slist = slist->next) {
50 sp = (splotd *) slist->data;
51 if (sp->p1dvar >= d->ncols)
52 sp->p1dvar = 0;
53 }
54 varpanel_refresh (display, gg);
55 }
56 else {
57 /*
58 * Turn cycling off when leaving the mode, but don't worry
59 * for now about turning it on when re-entering.
60 */
61 GtkWidget *pnl;
62 pnl = mode_panel_get_by_name (GGOBI (getPModeName) (P1PLOT), gg);
63 if (pnl) {
64 GtkWidget *w = widget_find_by_name (pnl, "P1PLOT:cycle_toggle");
65 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), off);
66 }
67 }
68
69 return NONE;
70 }
71
72
73 void
p1d_spread_var(displayd * display,gfloat * yy,splotd * sp,GGobiData * d,ggobid * gg)74 p1d_spread_var (displayd * display, gfloat * yy, splotd * sp, GGobiData * d,
75 ggobid * gg)
76 {
77 /*
78 * Set up the next dot plot.
79 */
80 gint i;
81 gfloat del = 1.;
82 gint option = 1, stages = 3;
83 gfloat min, max, mean;
84 cpaneld *cpanel = &display->cpanel;
85
86 if (sp->p1d.spread_data.nels != d->nrows)
87 vectorf_realloc (&sp->p1d.spread_data, d->nrows);
88
89 switch (cpanel->p1d.type) {
90 case TEXTURE:
91 sp->p1d.lim.min = FORGETITAXIS_MIN;
92 sp->p1d.lim.max = FORGETITAXIS_MAX;
93
94 textur (yy, sp->p1d.spread_data.els, d->nrows_in_plot,
95 option, del, stages, gg);
96 break;
97
98 case ASH:
99 do_ash1d (yy, d->nrows_in_plot,
100 cpanel->p1d.nbins, cpanel->p1d.nASHes,
101 sp->p1d.spread_data.els, &min, &max, &mean);
102 /*
103 * Instead of using the returned minimum, set the minimum to 0.
104 * This scales the plot so that the baseline (also set to 0) is
105 * within the range, the connecting lines look terrific, and the
106 * plot makes more sense.
107 */
108 sp->p1d.lim.min = 0.0;
109 sp->p1d.lim.max = max;
110 sp->p1d.mean = mean;
111 break;
112
113 case DOTPLOT:
114 sp->p1d.lim.min = FORGETITAXIS_MIN;
115 sp->p1d.lim.max = FORGETITAXIS_MAX;
116 for (i = 0; i < d->nrows_in_plot; i++)
117 sp->p1d.spread_data.els[i] = 50; /*-- halfway between _MIN and _MAX --*/
118 break;
119 }
120 }
121
122 void
p1d_reproject(splotd * sp,greal ** world_data,GGobiData * d,ggobid * gg)123 p1d_reproject (splotd * sp, greal ** world_data, GGobiData * d, ggobid * gg)
124 {
125 /*
126 * Project the y variable down from the ncols-dimensional world_data[]
127 * to the 2-dimensional array planar[]; get the x variable directly
128 * from p1d.spread_data[].
129 */
130 gint i, m, jvar = 0;
131 gfloat rdiff, ftmp;
132 gfloat precis = PRECISION1;
133 displayd *display = (displayd *) sp->displayptr;
134 gfloat *yy;
135
136 if (sp == NULL)
137 return;
138
139 yy = (gfloat *) g_malloc (d->nrows_in_plot * sizeof (gfloat));
140 jvar = sp->p1dvar;
141
142 /*
143 * in order to have jittering in the direction of the variable
144 * instead of in the direction of the "spreading variable", we
145 * have to apply the ASH (in particular) after the jitter has
146 * been added in. That is, we have to ASH the world data instead
147 * of the tform data. By some unexpected miracle, all the scaling
148 * still works.
149 */
150 for (i = 0; i < d->nrows_in_plot; i++)
151 yy[i] = d->world.vals[d->rows_in_plot.els[i]][jvar];
152 /*yy[i] = d->tform.vals[d->rows_in_plot.els[i]][jvar]; */
153
154 p1d_spread_var (display, yy, sp, d, gg);
155
156 /* Then project it */
157 rdiff = sp->p1d.lim.max - sp->p1d.lim.min;
158 for (i = 0; i < d->nrows_in_plot; i++) {
159 m = d->rows_in_plot.els[i];
160
161 /*
162 * Use p1d.spread_data[i] not [m] because p1d.spread_data[] is
163 * populated only up to d->nrows_in_plot
164 */
165 ftmp =
166 -1.0 + 2.0 * (sp->p1d.spread_data.els[i] - sp->p1d.lim.min) / rdiff;
167
168 if (display->p1d_orientation == VERTICAL) {
169 sp->planar[m].x = (glong) (precis * ftmp);
170 sp->planar[m].y = (glong) world_data[m][jvar];
171 }
172 else {
173 sp->planar[m].x = (glong) world_data[m][jvar];
174 sp->planar[m].y = (glong) (precis * ftmp);
175 }
176 }
177
178 g_free ((gpointer) yy);
179 }
180
181 gboolean
p1d_varsel(splotd * sp,gint jvar,gint * jprev,gint toggle,gint mouse)182 p1d_varsel (splotd * sp, gint jvar, gint * jprev, gint toggle, gint mouse)
183 {
184 gboolean redraw = true;
185 displayd *display = (displayd *) sp->displayptr;
186 gint orientation = display->p1d_orientation;
187 gboolean allow = true;
188
189 if (GGOBI_IS_EXTENDED_DISPLAY (display)) {
190 allow = GGOBI_EXTENDED_DISPLAY_GET_CLASS (display)->allow_reorientation;
191 }
192
193 /*-- if button == -1, don't change orientation. That protects
194 changes made during cycling --*/
195 if (allow && mouse > 0)
196 display->p1d_orientation = (mouse == 1) ? HORIZONTAL : VERTICAL;
197
198 redraw = (orientation != display->p1d_orientation) || (jvar != sp->p1dvar);
199
200 *jprev = sp->p1dvar;
201 sp->p1dvar = jvar;
202
203 if (orientation != display->p1d_orientation)
204 scatterplot_show_rulers (display, P1PLOT);
205
206 return redraw;
207 }
208
209 /*---------------------------------------------------------------------*/
210
211 void
ash_baseline_set(icoords * baseline,splotd * sp)212 ash_baseline_set (icoords * baseline, splotd * sp)
213 {
214 greal ftmp, precis = (greal) PRECISION1;
215 greal pl, gtmp;
216 gint iscr;
217
218 /*
219 ftmp = -1 + 2.0 * (0 - sp->p1d.lim.min)/
220 (sp->p1d.lim.max - sp->p1d.lim.min);
221 */
222 ftmp = -1 /* and the rest of the usual expression is 0 now */ ;
223 pl = (greal) (precis * ftmp);
224
225 /*-- HORIZONTAL --*/
226 gtmp = pl - sp->pmid.y;
227 iscr = (gint) (gtmp * sp->iscale.y / precis);
228 iscr += (sp->max.y / 2);
229
230 baseline->y = iscr;
231
232 /*-- VERTICAL --*/
233 gtmp = pl - sp->pmid.x;
234 iscr = (gint) (gtmp * sp->iscale.x / precis);
235 iscr += (sp->max.x / 2);
236
237 baseline->x = iscr;
238 }
239
240 /*--------------------------------------------------------------------*/
241 /* Cycling */
242 /*--------------------------------------------------------------------*/
243
244
245 gint
p1dcycle_func(ggobid * gg)246 p1dcycle_func (ggobid * gg)
247 {
248 displayd *display = gg->current_display;
249 GGobiData *d = gg->current_display->d;
250 splotd *sp = gg->current_splot;
251 cpaneld *cpanel = &display->cpanel;
252
253 gint varno, jvar_prev;
254
255 if (cpanel->p1d.cycle_dir == 1) {
256 varno = sp->p1dvar + 1;
257
258 if (varno == d->ncols) {
259 varno = 0;
260 }
261 }
262 else {
263 varno = sp->p1dvar - 1;
264
265 if (varno < 0) {
266 varno = d->ncols - 1;
267 }
268 }
269
270 if (varno != sp->p1dvar) {
271 jvar_prev = sp->p1dvar;
272 if (p1d_varsel (sp, varno, &jvar_prev, -1, -1)) {
273 varpanel_refresh (display, gg);
274 display_tailpipe (display, FULL, gg);
275 }
276 }
277
278 return true;
279 }
280