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