1 /* barchart.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  * Contributing author of barchart and histogram code:  Heike Hofmann
17 */
18 
19 
20 /* not dealt with: missings, hiddens in overflow bins */
21 
22 #include <math.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include "vars.h"
28 #include "externs.h"
29 
30 #include "barchartDisplay.h"
31 
32 #define WIDTH   370
33 #define HEIGHT  370
34 
35 gfloat barchart_sort_index (gfloat * yy, gint ny, ggobid * gg,
36                             barchartSPlotd * sp);
37 void barchart_init_categorical (barchartSPlotd * sp, GGobiData * d);
38 void barchart_set_initials (barchartSPlotd * sp, GGobiData * d);
39 void rectangle_inset (gbind * bin);
40 void barchart_allocate_structure (barchartSPlotd * sp, GGobiData * d);
41 void button_draw_with_shadows (GdkPoint * region, GdkDrawable * drawable,
42                                ggobid * gg);
43 gboolean rect_intersect (GdkRectangle * rect1, GdkRectangle * rect2,
44                          GdkRectangle * dest);
45 gboolean pt_in_rect (icoords pt, GdkRectangle rect);
46 
47 /*----------------------------------------------------------------------*/
48 /*                          Options section                             */
49 /*----------------------------------------------------------------------*/
50 
51 /*
52 static const gchar *menu_ui =
53   "<ui>"
54   "	<menubar>"
55   "		<menu action='Options'>"
56   "			<menuitem action='ShowPoints'/>"
57   "			<separator/>"
58   "			<menuitem action='ShowAxes'/>" "		</menu>" "	</menubar>" "</ui>";
59 */
60 
61 static const gchar *menu_ui =
62   "<ui>"
63   "	<menubar>"
64   "	</menubar>" "</ui>";
65 
66 static void
action_toggle_show_bars(GtkToggleAction * action,displayd * display)67 action_toggle_show_bars (GtkToggleAction * action, displayd * display)
68 {
69   set_display_option (gtk_toggle_action_get_active (action), DOPT_POINTS,
70                       display);
71 }
72 
73 /* the 'ShowPoints' display action is overridden here for bar display */
74 static GtkToggleActionEntry toggle_entries[] = {
75   {"ShowPoints", NULL, "Show _bars", "<control>B", "Toggle bar display",
76    G_CALLBACK (action_toggle_show_bars), true},
77 };
78 
79 static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);
80 
81 displayd *
barchart_new(gboolean use_window,gboolean missing_p,splotd * sp,GGobiData * d,ggobid * gg)82 barchart_new (gboolean use_window, gboolean missing_p, splotd * sp, GGobiData * d, ggobid * gg)
83 {
84   return (createBarchart (NULL, use_window, missing_p, sp, -1, d, gg));
85 }
86 
87 displayd *
barchart_new_with_vars(gboolean use_window,gboolean missing_p,gint nvars,gint * vars,GGobiData * d,ggobid * gg)88 barchart_new_with_vars (gboolean use_window, gboolean missing_p, gint nvars,
89                         gint * vars, GGobiData * d, ggobid * gg)
90 {
91   return (createBarchart (NULL, use_window, missing_p, NULL, vars ? vars[0] : 0, d, gg));
92 }
93 
94 displayd *
createBarchart(displayd * display,gboolean use_window,gboolean missing_p,splotd * sp,gint var,GGobiData * d,ggobid * gg)95 createBarchart (displayd * display, gboolean use_window, gboolean missing_p,
96                 splotd * sp, gint var, GGobiData * d, ggobid * gg)
97 {
98   GtkWidget *table, *vbox;
99 
100   if (d == NULL || d->ncols < 1)
101     return (NULL);
102 
103   if (!display) {
104     if (sp == NULL || sp->displayptr == NULL) {
105       display = g_object_new (GGOBI_TYPE_BARCHART_DISPLAY, NULL);
106       display_set_values (display, d, gg);
107     }
108     else {
109       display = (displayd *) sp->displayptr;
110       display->d = d;
111     }
112   }
113 
114   GGOBI_WINDOW_DISPLAY(display)->useWindow = use_window;
115 
116   /* Want to make certain this is true, and perhaps it may be different
117      for other plot types and so not be set appropriately in DefaultOptions.
118      display->options.axes_center_p = true;
119    */
120 
121   barchart_cpanel_init (&display->cpanel, gg);
122 
123   if (GGOBI_IS_WINDOW_DISPLAY (display)
124       && GGOBI_WINDOW_DISPLAY (display)->useWindow)
125     display_window_init (GGOBI_WINDOW_DISPLAY (display), WIDTH, HEIGHT, 3, gg);  /*-- 3 = width = any small int --*/
126 
127   /*-- Add the main menu bar --*/
128   vbox = GTK_WIDGET (display);
129   gtk_container_set_border_width (GTK_CONTAINER (vbox), 1);
130   display->menu_manager = display_menu_manager_create (display);
131   if (GGOBI_IS_WINDOW_DISPLAY (display)
132       && GGOBI_WINDOW_DISPLAY (display)->window) {
133     GtkActionGroup *actions = gtk_action_group_new ("BarchartActions");
134     gtk_action_group_add_toggle_actions (actions, toggle_entries,
135                                          n_toggle_entries, display);
136     gtk_ui_manager_insert_action_group (display->menu_manager, actions, 0);
137     g_object_unref (G_OBJECT (actions));
138     display->menubar =
139       create_menu_bar (display->menu_manager, menu_ui,
140                        GGOBI_WINDOW_DISPLAY (display)->window);
141 
142     gtk_container_add (GTK_CONTAINER (GGOBI_WINDOW_DISPLAY (display)->window),
143                        vbox);
144     gtk_box_pack_start (GTK_BOX (vbox), display->menubar, false, true, 0);
145   }
146 
147   /*-- Initialize a single splot --*/
148   if (sp == NULL) {
149     sp = ggobi_barchart_splot_new (display, gg);
150   }
151 
152   /* Reset sp->p1dvar based on the plotted variables in the current
153      display, if appropriate -- it has already been initialized to
154      zero in splot_init, a few levels down from
155      ggobi_barchart_splot_new(), */
156   if (gg->current_display != NULL && gg->current_display != display &&
157       gg->current_display->d == d &&
158       GGOBI_IS_EXTENDED_DISPLAY (gg->current_display)) {
159     gint nplotted_vars;
160     gint *plotted_vars = (gint *) g_malloc (d->ncols * sizeof (gint));
161     displayd *dsp = gg->current_display;
162 
163     nplotted_vars =
164       GGOBI_EXTENDED_DISPLAY_GET_CLASS (dsp)->plotted_vars_get (dsp,
165                                                                 plotted_vars,
166                                                                 d, gg);
167     if (nplotted_vars && plotted_vars[0] != 0) {
168       sp->p1dvar = plotted_vars[0];
169       barchart_clean_init (GGOBI_BARCHART_SPLOT (sp));
170       barchart_recalc_counts (GGOBI_BARCHART_SPLOT (sp), d, gg);
171     }
172   }
173 
174 
175   display->splots = NULL;
176   display->splots = g_list_append (display->splots, (gpointer) sp);
177 
178   /*-- Initialize tours if possible --*/
179   display_tour1d_init_null (display, gg);
180   if (d->ncols >= MIN_NVARS_FOR_TOUR1D)
181     display_tour1d_init (display, gg);
182 
183   table = gtk_table_new (3, 2, false);  /* rows, columns, homogeneous */
184   gtk_box_pack_start (GTK_BOX (vbox), table, true, true, 0);
185   gtk_table_attach (GTK_TABLE (table),
186                     sp->da, 1, 2, 0, 1,
187                     (GtkAttachOptions) (GTK_SHRINK | GTK_EXPAND | GTK_FILL),
188                     (GtkAttachOptions) (GTK_SHRINK | GTK_EXPAND | GTK_FILL),
189                     0, 0);
190 
191 
192 
193   /*
194    * The horizontal ruler goes on top. As the mouse moves across the
195    * drawing area, a motion_notify_event is passed to the
196    * appropriate event handler for the ruler.
197    */
198 
199   display->hrule = gtk_hruler_new ();
200 /*
201   gtk_table_attach (GTK_TABLE (table),
202                     display->hrule, 1, 2, 1, 2,
203                     (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
204                     (GtkAttachOptions) GTK_FILL, 0, 0);
205 */
206 
207 
208   /*
209    * The vertical ruler goes on the left. As the mouse moves across
210    * the drawing area, a motion_notify_event is passed to the
211    * appropriate event handler for the ruler.
212    */
213 
214 
215   display->vrule = gtk_vruler_new ();
216 /*
217   gtk_table_attach (GTK_TABLE (table),
218                     display->vrule, 0, 1, 0, 1,
219                     (GtkAttachOptions) GTK_FILL,
220                     (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
221                     0, 0);
222 
223   display->p1d_orientation = VERTICAL;
224   scatterplot_show_rulers (display, P1PLOT);
225 */
226 
227   if (GGOBI_IS_WINDOW_DISPLAY (display)
228       && GGOBI_WINDOW_DISPLAY (display)->useWindow)
229   {
230     gtk_widget_show_all (GGOBI_WINDOW_DISPLAY (display)->window);
231     // ruler_ranges_set (true, display, sp, gg);
232   } else gtk_widget_show_all (table);
233 
234   return display;
235 }
236 
237 void
barchart_clean_init(barchartSPlotd * sp)238 barchart_clean_init (barchartSPlotd * sp)
239 {
240   displayd *display;
241   GGobiData *d;
242   gint i, j;
243 
244   display = (displayd *) GGOBI_SPLOT (sp)->displayptr;
245   d = display->d;
246 
247   sp->bar->nbins = -1;
248 
249   sp->bar->new_nbins = -1;
250   barchart_allocate_structure (sp, d);
251 
252   for (i = 0; i < sp->bar->nbins; i++) {
253     sp->bar->bins[i].count = 0;
254     sp->bar->bins[i].nhidden = 0;
255     sp->bar->bar_hit[i] = FALSE;
256     sp->bar->old_bar_hit[i] = FALSE;
257     for (j = 0; j < sp->bar->ncolors; j++) {
258       sp->bar->cbins[i][j].count = 0;
259       sp->bar->cbins[i][j].rect.width = 1;
260     }
261   }
262   for (i = 0; i < sp->bar->nbins + 2; i++)
263     sp->bar->bar_hit[i] = sp->bar->old_bar_hit[i] = false;
264   sp->bar->old_nbins = -1;
265 
266 /* */
267 
268   barchart_set_initials (sp, d);
269   sp->bar->offset = 0;
270   GGOBI_SPLOT (sp)->pmid.y = 0;
271 
272   vectori_realloc (&sp->bar->index_to_rank, d->nrows_in_plot);
273   barchart_init_categorical (sp, d);
274 }
275 
276 static void
barchart_recalc_group_counts(barchartSPlotd * sp,GGobiData * d,ggobid * gg)277 barchart_recalc_group_counts (barchartSPlotd * sp, GGobiData * d, ggobid * gg)
278 {
279   gint i, j, m, bin;
280   vartabled *vtx = vartable_element_get (GGOBI_SPLOT (sp)->p1dvar, d);
281 
282   g_assert (sp->bar->index_to_rank.nels == d->nrows_in_plot);
283 
284   for (i = 0; i < sp->bar->nbins; i++)
285     for (j = 0; j < sp->bar->ncolors; j++)
286       sp->bar->cbins[i][j].count = 0;
287 
288 /*  initialize overflow bins */
289   if (sp->bar->high_pts_missing) {
290     for (j = 0; j < sp->bar->ncolors; j++)
291       sp->bar->col_high_bin[j].count = 0;
292   }
293   if (sp->bar->low_pts_missing) {
294     for (j = 0; j < sp->bar->ncolors; j++)
295       sp->bar->col_low_bin[j].count = 0;
296   }
297 
298 /* count points in bins */
299   for (i = 0; i < d->nrows_in_plot; i++) {
300     m = d->rows_in_plot.els[i];
301 
302     /*-- skip missings?  --*/
303     if (!d->missings_show_p && ggobi_data_is_missing(d, m, GGOBI_SPLOT (sp)->p1dvar))
304       continue;
305 
306     /*-- skip hiddens?  here, yes. --*/
307     if (d->hidden_now.els[m]) {
308       continue;
309     }
310 
311     bin = GGOBI_SPLOT (sp)->planar[m].x;
312 /* dfs */
313     if (vtx->vartype == categorical)
314       bin = sp->bar->index_to_rank.els[i];
315 /* --- */
316     if ((bin >= 0) && (bin < sp->bar->nbins)) {
317       sp->bar->cbins[bin][d->color_now.els[m]].count++;
318     }
319     if (bin == -1) {
320       sp->bar->col_low_bin[d->color_now.els[m]].count++;
321     }
322     else if (bin == sp->bar->nbins) {
323       sp->bar->col_high_bin[d->color_now.els[m]].count++;
324     }
325   }
326 
327   barchart_recalc_group_dimensions (sp, gg);
328 }
329 
330 
331 void
barchart_recalc_group_dimensions(barchartSPlotd * sp,ggobid * gg)332 barchart_recalc_group_dimensions (barchartSPlotd * sp, ggobid * gg)
333 {
334   gint colorwidth, i, j, xoffset;
335 
336   for (i = 0; i < sp->bar->nbins; i++) {
337     xoffset = sp->bar->bins[i].rect.x;
338 
339 /* first all bins in the current color */
340     j = gg->color_id;
341     colorwidth = 1;
342     if (sp->bar->bins[i].count > 0)
343       colorwidth =
344         (gint) ((gfloat) sp->bar->cbins[i][j].count /
345                 sp->bar->bins[i].count * sp->bar->bins[i].rect.width);
346     sp->bar->cbins[i][j].rect.x = xoffset;
347     sp->bar->cbins[i][j].rect.y = sp->bar->bins[i].rect.y;
348     sp->bar->cbins[i][j].rect.height = sp->bar->bins[i].rect.height;
349 
350     sp->bar->cbins[i][j].rect.width = colorwidth;
351     if (colorwidth) {
352       colorwidth++;
353       rectangle_inset (&sp->bar->cbins[i][j]);
354     }
355     xoffset += colorwidth;
356 
357 /* then all other colors follow in the order of the color table */
358     for (j = 0; j < sp->bar->ncolors; j++) {
359       if (j != gg->color_id) {
360         colorwidth = 0;
361         if (sp->bar->bins[i].count > 0)
362           colorwidth =
363             (gint) ((gfloat) sp->bar->cbins[i][j].count /
364                     sp->bar->bins[i].count * sp->bar->bins[i].rect.width);
365         sp->bar->cbins[i][j].rect.x = xoffset;
366         sp->bar->cbins[i][j].rect.y = sp->bar->bins[i].rect.y;
367         sp->bar->cbins[i][j].rect.height = sp->bar->bins[i].rect.height;
368 
369         sp->bar->cbins[i][j].rect.width = colorwidth;
370         if (colorwidth) {
371           colorwidth++;
372           rectangle_inset (&sp->bar->cbins[i][j]);
373         }
374         xoffset += colorwidth;
375       }
376     }
377   }
378 
379 /* now eliminate rounding problems - last color in each bin gets adjusted */
380   for (i = 0; i < sp->bar->nbins; i++) {
381     gboolean stop = FALSE;
382 
383     /*-- dfs:   don't do this if nmissing > 0; leave the shadow in place --*/
384     if (sp->bar->bins[i].nhidden)
385       continue;
386 
387     for (j = sp->bar->ncolors - 1; (j >= 0) && (!stop); j--)
388       if (j != gg->color_id)
389         if (sp->bar->cbins[i][j].count > 0)
390           stop = TRUE;          /* find last color used */
391 
392     if (stop) {
393       j++;
394       sp->bar->cbins[i][j].rect.width =
395         sp->bar->bins[i].rect.x + sp->bar->bins[i].rect.width -
396         sp->bar->cbins[i][j].rect.x + 2;
397     }
398   }
399 
400 /* deal with overflow bins to the left and right now:  */
401   if (sp->bar->high_pts_missing) {
402     j = gg->color_id;
403     xoffset = sp->bar->high_bin->rect.x;
404     colorwidth =
405       (gint) ((gfloat) sp->bar->col_high_bin[j].count /
406               sp->bar->high_bin->count * sp->bar->high_bin->rect.width);
407     sp->bar->col_high_bin[j].rect.x = xoffset;
408     sp->bar->col_high_bin[j].rect.y = sp->bar->high_bin->rect.y;
409     sp->bar->col_high_bin[j].rect.height = sp->bar->high_bin->rect.height;
410     sp->bar->col_high_bin[j].rect.width = colorwidth;
411     if (colorwidth) {
412       colorwidth++;
413       rectangle_inset (&sp->bar->col_high_bin[j]);
414     }
415     xoffset += colorwidth;
416 
417     for (j = 0; j < sp->bar->ncolors; j++) {
418       if (j != gg->color_id) {
419         colorwidth =
420           (gint) ((gfloat) sp->bar->col_high_bin[j].count /
421                   sp->bar->high_bin->count * sp->bar->high_bin->rect.width);
422         sp->bar->col_high_bin[j].rect.x = xoffset;
423         sp->bar->col_high_bin[j].rect.y = sp->bar->high_bin->rect.y;
424         sp->bar->col_high_bin[j].rect.height = sp->bar->high_bin->rect.height;
425         sp->bar->col_high_bin[j].rect.width = colorwidth;
426         if (colorwidth) {
427           colorwidth++;
428           rectangle_inset (&sp->bar->col_high_bin[j]);
429         }
430         xoffset += colorwidth;
431 
432       }
433     }
434   }
435   if (sp->bar->low_pts_missing) {
436     j = gg->color_id;
437     xoffset = sp->bar->low_bin->rect.x;
438     colorwidth =
439       (gint) ((gfloat) sp->bar->col_low_bin[j].count /
440               sp->bar->low_bin->count * sp->bar->low_bin->rect.width);
441     sp->bar->col_low_bin[j].rect.x = xoffset;
442     sp->bar->col_low_bin[j].rect.y = sp->bar->low_bin->rect.y;
443     sp->bar->col_low_bin[j].rect.height = sp->bar->low_bin->rect.height;
444     sp->bar->col_low_bin[j].rect.width = colorwidth;
445     if (colorwidth) {
446       colorwidth++;
447       rectangle_inset (&sp->bar->col_low_bin[j]);
448     }
449     xoffset += colorwidth;
450 
451     for (j = 0; j < sp->bar->ncolors; j++) {
452       if (j != gg->color_id) {
453         colorwidth =
454           (gint) ((gfloat) sp->bar->col_low_bin[j].count /
455                   sp->bar->low_bin->count * sp->bar->low_bin->rect.width);
456         sp->bar->col_low_bin[j].rect.x = xoffset;
457         sp->bar->col_low_bin[j].rect.y = sp->bar->low_bin->rect.y;
458         sp->bar->col_low_bin[j].rect.height = sp->bar->low_bin->rect.height;
459         sp->bar->col_low_bin[j].rect.width = colorwidth;
460         if (colorwidth) {
461           colorwidth++;
462           rectangle_inset (&sp->bar->col_low_bin[j]);
463         }
464         xoffset += colorwidth;
465       }
466     }
467   }
468 
469 
470 }
471 
472 void
rectangle_inset(gbind * bin)473 rectangle_inset (gbind * bin)
474 {
475 /* works around the gdk convention, that the areas of filled and
476    framed rectangles differ by one pixel in each dimension */
477 
478   bin->rect.height += 1;
479   if (bin->rect.height < 1)
480     bin->rect.height = 1;       /* set minimal height */
481   bin->rect.x += 1;
482   bin->rect.width += 1;
483 
484   if (bin->rect.width < 1)
485     bin->rect.width = 1;        /* set minimal width */
486 }
487 
488 void
barchart_init_vectors(barchartSPlotd * sp)489 barchart_init_vectors (barchartSPlotd * sp)
490 {
491 /* shouldn't be necessary ...*/
492   if (sp->bar != NULL) {
493     sp->bar->bins = NULL;
494     sp->bar->cbins = NULL;
495     sp->bar->breaks = NULL;
496     sp->bar->high_bin = NULL;
497     sp->bar->low_bin = NULL;
498     sp->bar->col_high_bin = NULL;
499     sp->bar->col_low_bin = NULL;
500     sp->bar->bar_hit = NULL;
501     sp->bar->old_bar_hit = NULL;
502   }
503 }
504 
505 void
barchart_free_structure(barchartSPlotd * sp)506 barchart_free_structure (barchartSPlotd * sp)
507 {
508   gint i;
509 
510 /* free all previously allocated pointers */
511   if (sp->bar->bins)
512     g_free ((gpointer) (sp->bar->bins));
513 
514   if (sp->bar->cbins) {
515     gint nbins = sp->bar->nbins;
516 
517     for (i = 0; i < nbins; i++)
518       if (sp->bar->cbins[i])
519         g_free ((gpointer) (sp->bar->cbins[i]));
520     g_free ((gpointer) (sp->bar->cbins));
521   }
522 
523   if (sp->bar->breaks)
524     g_free ((gpointer) sp->bar->breaks);
525 
526   if (sp->bar->high_bin)
527     g_free ((gpointer) sp->bar->high_bin);
528 
529   if (sp->bar->low_bin)
530     g_free ((gpointer) sp->bar->low_bin);
531 
532   if (sp->bar->col_high_bin)
533     g_free ((gpointer) sp->bar->col_high_bin);
534 
535   if (sp->bar->col_low_bin)
536     g_free ((gpointer) sp->bar->col_low_bin);
537 
538   if (sp->bar->bar_hit)
539     g_free ((gpointer) sp->bar->bar_hit);
540 
541   if (sp->bar->old_bar_hit)
542     g_free ((gpointer) sp->bar->old_bar_hit);
543 
544   barchart_init_vectors (sp);
545 }
546 
547 void
barchart_allocate_structure(barchartSPlotd * sp,GGobiData * d)548 barchart_allocate_structure (barchartSPlotd * sp, GGobiData * d)
549 {
550   vartabled *vtx;
551   gint i, nbins;
552   splotd *rawsp = GGOBI_SPLOT (sp);
553   ggobid *gg = GGobiFromSPlot (rawsp);
554   colorschemed *scheme = gg->activeColorScheme;
555 
556   vtx = vartable_element_get (rawsp->p1dvar, d);
557 
558   if (sp->bar->new_nbins < 0) {
559     if (vtx->vartype == categorical) {
560       nbins = (ggobi_data_get_col_n_missing(d, rawsp->p1dvar)) ? vtx->nlevels + 1 : vtx->nlevels;
561       sp->bar->is_histogram = FALSE;
562     }
563     else {
564       nbins = 10;               /* replace by a more sophisticated rule */
565       sp->bar->is_histogram = TRUE;
566     }
567   }
568   else
569     nbins = sp->bar->new_nbins;
570   sp->bar->new_nbins = -1;
571 
572   if (vtx->lim_specified_p) {
573     rawsp->p1d.lim.min = vtx->lim_specified.min;
574     rawsp->p1d.lim.max = vtx->lim_specified.max;
575   }
576   else {
577     rawsp->p1d.lim.min = vtx->lim.min;
578     rawsp->p1d.lim.max = vtx->lim.max;
579 /* dfs */
580     if (vtx->vartype == categorical) {
581       rawsp->p1d.lim.min = MIN (rawsp->p1d.lim.min, vtx->level_values[0]);
582       rawsp->p1d.lim.max = MAX (rawsp->p1d.lim.max,
583                                 vtx->level_values[vtx->nlevels - 1]);
584     }
585 /* --- */
586   }
587 
588   if (sp->bar->nbins && nbins == sp->bar->nbins)
589     return;                     /* nothing else to be done */
590 
591 
592 /* free all previously allocated pointers */
593   barchart_free_structure (sp);
594 
595   sp->bar->nbins = nbins;
596 
597 /* allocate space */
598   sp->bar->bins = (gbind *) g_malloc (nbins * sizeof (gbind));
599   sp->bar->cbins = (gbind **) g_malloc (nbins * sizeof (gbind *));
600   sp->bar->ncolors = scheme->n;
601   sp->bar->bar_hit = (gboolean *) g_malloc ((nbins + 2) * sizeof (gboolean));
602   sp->bar->old_bar_hit =
603     (gboolean *) g_malloc ((nbins + 2) * sizeof (gboolean));
604 
605   for (i = 0; i < sp->bar->nbins; i++) {
606     sp->bar->cbins[i] =
607       (gbind *) g_malloc (sp->bar->ncolors * sizeof (gbind));
608   }
609 
610   sp->bar->breaks = (gfloat *) g_malloc ((nbins + 1) * sizeof (nbins));
611 }
612 
613 void
barchart_init_categorical(barchartSPlotd * sp,GGobiData * d)614 barchart_init_categorical (barchartSPlotd * sp, GGobiData * d)
615 {
616   splotd *rawsp = GGOBI_SPLOT (sp);
617   displayd *display = (displayd *) rawsp->displayptr;
618   gint proj = display->cpanel.pmode;
619   gint i, j, m, jvar = rawsp->p1dvar;
620   ggobid *gg = GGobiFromSPlot (rawsp);
621   vartabled *vtx = vartable_element_get (rawsp->p1dvar, d);
622   gfloat mindist, maxheight;
623   gfloat min, max;
624 
625   gfloat *yy;
626   yy = (gfloat *) g_malloc (d->nrows_in_plot * sizeof (gfloat));
627 
628   if (proj == TOUR1D) {
629     for (m=0; m < d->nrows_in_plot; m++) {
630       i = d->rows_in_plot.els[m];
631       yy[m] = rawsp->planar[i].x = 0;
632       rawsp->planar[i].y = 0;
633       for (j=0; j<d->ncols; j++)
634       {
635         yy[m] += (gfloat)(display->t1d.F.vals[0][j]*d->world.vals[i][j]);
636       }
637     }
638   }
639   else {
640     for (i = 0; i < d->nrows_in_plot; i++)
641       yy[i] = d->tform.vals[d->rows_in_plot.els[i]][jvar];
642   }
643   mindist = barchart_sort_index (yy, d->nrows_in_plot, gg, sp);
644   g_free ((gpointer) yy);
645 
646   min = vtx->lim_tform.min;
647   max = vtx->lim_tform.max;
648 /* dfs */
649   if (vtx->vartype == categorical) {
650     min = MIN (min, vtx->level_values[0]);
651     max = MAX (max, vtx->level_values[vtx->nlevels - 1]);
652   }
653 /* --- */
654 
655   maxheight = max - min;
656 
657   rawsp->scale.y =
658     (1 - (1.0 - SCALE_DEFAULT) / 2) * maxheight / (maxheight + mindist);
659 }
660 
661 
662 gboolean
barchart_redraw(splotd * rawsp,GGobiData * d,ggobid * gg,gboolean binned)663 barchart_redraw (splotd * rawsp, GGobiData * d, ggobid * gg, gboolean binned)
664 {
665   gint i, j, radius;
666   colorschemed *scheme = gg->activeColorScheme;
667   barchartSPlotd *sp = GGOBI_BARCHART_SPLOT (rawsp);
668   gbind *bin;
669 
670   barchart_recalc_counts (sp, d, gg);
671   barchart_recalc_group_counts (sp, d, gg);
672 
673 /* dfs: if there are hiddens, draw the entire rectangle in the shadow color */
674   gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_hidden);
675   for (i = 0; i < sp->bar->nbins; i++) {
676     bin = &sp->bar->bins[i];
677     if (bin->nhidden) {
678       gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
679                           bin->rect.x, bin->rect.y, bin->rect.width,
680                           bin->rect.height + 1);
681     }
682   }
683 /* */
684   for (j = 0; j < sp->bar->ncolors; j++) {
685     gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb[j]);
686 
687     for (i = 0; i < sp->bar->nbins; i++) {
688       bin = &sp->bar->cbins[i][j];
689       if (bin->count > 0) {
690         gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
691                             bin->rect.x, bin->rect.y, bin->rect.width,
692                             bin->rect.height);
693       }
694     }
695   }
696 
697 /* draw overflow bins if necessary */
698   if (sp->bar->high_pts_missing) {
699     /*  start with the hiddens */
700     if (sp->bar->high_bin->nhidden) {
701       bin = sp->bar->high_bin;
702       gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_hidden);
703       gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
704                           bin->rect.x, bin->rect.y, bin->rect.width,
705                           bin->rect.height + 1);
706     }
707     for (j = 0; j < sp->bar->ncolors; j++) {
708       gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb[j]);
709       bin = &sp->bar->col_high_bin[j];
710       if (bin->count > 0)
711         gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
712                             bin->rect.x, bin->rect.y, bin->rect.width,
713                             bin->rect.height);
714     }
715   }
716   if (sp->bar->low_pts_missing) {
717     /*  start with the hiddens */
718     if (sp->bar->low_bin->nhidden) {
719       bin = sp->bar->low_bin;
720       gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_hidden);
721       gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
722                           bin->rect.x, bin->rect.y, bin->rect.width,
723                           bin->rect.height + 1);
724     }
725     for (j = 0; j < sp->bar->ncolors; j++) {
726       gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb[j]);
727       bin = &sp->bar->col_low_bin[j];
728       if (bin->count > 0)
729         gdk_draw_rectangle (rawsp->pixmap0, gg->plot_GC, TRUE,
730                             bin->rect.x, bin->rect.y, bin->rect.width,
731                             bin->rect.height);
732     }
733   }
734 
735 /* mark empty bins with a small circle */
736   gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_accent);
737   for (i = 0; i < sp->bar->nbins; i++) {
738     bin = &sp->bar->bins[i];
739     if (bin->count == 0) {
740       radius = bin->rect.height / 4;
741       gdk_draw_line (rawsp->pixmap0, gg->plot_GC,
742                      bin->rect.x, bin->rect.y,
743                      bin->rect.x, bin->rect.y + bin->rect.height);
744       gdk_draw_arc (rawsp->pixmap0, gg->plot_GC, FALSE,
745                     bin->rect.x - radius / 2,
746                     bin->rect.y + bin->rect.height / 2 - radius / 2,
747                     radius, radius, 0, 64 * 360);
748     }
749   }
750 
751   return (false);
752 }
753 
754 void
barchart_splot_add_plot_labels(splotd * sp,GdkDrawable * drawable,ggobid * gg)755 barchart_splot_add_plot_labels (splotd * sp, GdkDrawable * drawable,
756                                 ggobid * gg)
757 {
758   displayd *display = (displayd *) sp->displayptr;
759   GGobiData *d = display->d;
760   PangoLayout *layout =
761     gtk_widget_create_pango_layout (GTK_WIDGET (sp->da), NULL);
762   PangoRectangle rect;
763 
764   vartabled *vtx;
765 
766   vtx = vartable_element_get (sp->p1dvar, d);
767 
768   layout_text (layout, ggobi_data_get_col_name(d, sp->p1dvar), &rect);
769   gdk_draw_layout (drawable, gg->plot_GC, sp->max.x - rect.width - 5,
770                    sp->max.y - rect.height - 5, layout);
771 
772   if (vtx->vartype == categorical) {
773     gint i;
774     gchar *catname;
775     barchartSPlotd *bsp = GGOBI_BARCHART_SPLOT (sp);
776     gint level;
777 
778     layout_text (layout, "yA", &rect);
779 
780     /* is there enough space for labels? If not - return */
781     if (!bsp->bar->is_spine) {
782       if (bsp->bar->bins[1].rect.height < rect.height)
783         return;
784     }
785 
786     for (i = 0; i < bsp->bar->nbins; i++) {
787       level = checkLevelValue (vtx, (gdouble) bsp->bar->bins[i].value);
788       catname = g_strdup_printf ("%s",
789                                  (level ==
790                                   -1) ? "missing" : vtx->level_names[level]);
791 
792       layout_text (layout, catname, NULL);
793       gdk_draw_layout (drawable, gg->plot_GC,
794                        bsp->bar->bins[i].rect.x + 2,
795                        bsp->bar->bins[i].rect.y +
796                        bsp->bar->bins[i].rect.height / 2 + 2, layout);
797 
798       g_free (catname);
799     }
800   }
801   g_object_unref (G_OBJECT (layout));
802 }
803 
804 void
barchart_set_breakpoints(gfloat width,barchartSPlotd * sp,GGobiData * d)805 barchart_set_breakpoints (gfloat width, barchartSPlotd * sp, GGobiData * d)
806 {
807   gfloat rdiff;
808   gint i, nbins;
809   splotd *rawsp = GGOBI_SPLOT (sp);
810 
811   rdiff = rawsp->p1d.lim.max - rawsp->p1d.lim.min;
812 
813   nbins = (gint) (rdiff / width + 1);
814 
815   sp->bar->new_nbins = nbins;
816   barchart_allocate_structure (sp, d);
817 
818   for (i = 0; i <= sp->bar->nbins; i++) {
819     sp->bar->breaks[i] = rawsp->p1d.lim.min + width * i;
820     sp->bar->old_bar_hit[i] = FALSE;
821     sp->bar->bar_hit[i] = FALSE;
822   }
823 
824 }
825 
826 void
barchart_set_initials(barchartSPlotd * sp,GGobiData * d)827 barchart_set_initials (barchartSPlotd * sp, GGobiData * d)
828 {
829   splotd *rawsp = GGOBI_SPLOT (sp);
830   vartabled *vtx = vartable_element_get (rawsp->p1dvar, d);
831   gboolean foundp = false;
832 
833   if (vtx->vartype == categorical) {
834     if (vtx->nlevels > 1) {
835       gint i, level;
836       gfloat missing_val;
837       gboolean add_level = false;
838       if (ggobi_data_get_col_n_missing(d, rawsp->p1dvar)) {
839         for (i = 0; i < d->nrows_in_plot; i++) {
840           if (ggobi_data_is_missing(d, d->rows_in_plot.els[i], rawsp->p1dvar)) {
841             missing_val = d->tform.vals[i][rawsp->p1dvar];
842             foundp = true;
843             break;
844           }
845         }
846         /* If the currently "imputed" value for missings is not one
847            of the levels we already have, then we need an extra bin
848            for the missings.
849          */
850         if (foundp && checkLevelValue (vtx, missing_val) == -1) {
851           add_level = true;
852           level = 0;
853           for (i = 0; i < sp->bar->nbins; i++) {
854             if (add_level && (gint) missing_val < vtx->level_values[level]) {
855               sp->bar->bins[i].value = (gint) missing_val;
856               add_level = false;
857             }
858             else {
859               sp->bar->bins[i].value = vtx->level_values[level++];
860             }
861           }
862           if (add_level &&
863               (gint) missing_val > vtx->level_values[vtx->nlevels - 1])
864             sp->bar->bins[sp->bar->nbins - 1].value = missing_val;
865         }
866         else {
867           for (i = 0; i < vtx->nlevels; i++)
868             sp->bar->bins[i].value = vtx->level_values[i];
869           sp->bar->nbins -= 1;
870 
871           sp->bar->bins = (gbind *) g_realloc (sp->bar->bins,
872                                                sp->bar->nbins *
873                                                sizeof (gbind));
874           sp->bar->bar_hit =
875             (gboolean *) g_realloc (sp->bar->bar_hit,
876                                     (sp->bar->nbins + 2) * sizeof (gboolean));
877           sp->bar->old_bar_hit =
878             (gboolean *) g_realloc (sp->bar->old_bar_hit,
879                                     (sp->bar->nbins + 2) * sizeof (gboolean));
880 
881           g_free ((gpointer) (sp->bar->cbins[sp->bar->nbins]));
882           sp->bar->cbins = (gbind **) g_realloc (sp->bar->cbins,
883                                                  sp->bar->nbins *
884                                                  sizeof (gbind *));
885         }
886       }
887       else {
888         for (i = 0; i < vtx->nlevels; i++)
889           sp->bar->bins[i].value = vtx->level_values[i];
890       }
891     }
892 /* --- */
893   }
894   else {
895     gint i;
896     gfloat rdiff = rawsp->p1d.lim.max - rawsp->p1d.lim.min;
897 
898     for (i = 0; i < sp->bar->nbins; i++) {
899       sp->bar->breaks[i] = rawsp->p1d.lim.min + rdiff / sp->bar->nbins * i;
900     }
901     sp->bar->breaks[sp->bar->nbins] = rawsp->p1d.lim.max;
902   }
903 }
904 
905 void
barchart_recalc_counts(barchartSPlotd * sp,GGobiData * d,ggobid * gg)906 barchart_recalc_counts (barchartSPlotd * sp, GGobiData * d, ggobid * gg)
907 {
908   gfloat yy;
909   gint i, bin, m;
910   splotd *rawsp = GGOBI_SPLOT (sp);
911   vartabled *vtx = vartable_element_get (rawsp->p1dvar, d);
912 
913   if (sp->bar->index_to_rank.nels != d->nrows_in_plot) {
914     vectori_realloc (&sp->bar->index_to_rank, d->nrows_in_plot);
915     barchart_init_categorical (sp, d);
916   }
917 
918   if (vtx->vartype != categorical)
919     rawsp->scale.y = 1 - (1 - SCALE_DEFAULT) / 2;
920   for (i = 0; i < sp->bar->nbins; i++) {
921     sp->bar->bins[i].count = 0;
922     sp->bar->bins[i].nhidden = 0;
923   }
924 
925   sp->bar->high_pts_missing = sp->bar->low_pts_missing = FALSE;
926 
927   if (vtx->vartype == categorical) {
928 
929     for (i = 0; i < d->nrows_in_plot; i++) {
930       m = d->rows_in_plot.els[i];
931 
932       /*-- skip missings?  --*/
933       if (!d->missings_show_p && ggobi_data_is_missing(d, m, rawsp->p1dvar))
934         continue;
935 
936       bin = sp->bar->index_to_rank.els[i];
937       if ((bin >= 0) && (bin < sp->bar->nbins)) {
938         sp->bar->bins[bin].count++;
939         if (d->hidden_now.els[m])
940           sp->bar->bins[bin].nhidden++;
941       }
942       rawsp->planar[m].x = (greal) sp->bar->bins[bin].value;
943     }
944   }
945   else {                        /* all vartypes but categorical */
946     gint index, m, rank = 0;
947 
948     index = sp->bar->index_to_rank.els[rank];
949     m = d->rows_in_plot.els[index];
950     yy = d->tform.vals[m][rawsp->p1dvar];
951 
952     while ((yy < sp->bar->breaks[0] + sp->bar->offset) &&
953            (rank < d->nrows_in_plot - 1)) {
954       rawsp->planar[m].x = -1;
955       rank++;
956       index = sp->bar->index_to_rank.els[rank];
957       m = d->rows_in_plot.els[index];
958       yy = d->tform.vals[m][rawsp->p1dvar];
959     }
960 
961     if (rank > 0) {
962       gint k;
963       sp->bar->low_pts_missing = TRUE;
964       if (sp->bar->low_bin == NULL)
965         sp->bar->low_bin = (gbind *) g_malloc (sizeof (gbind));
966       if (sp->bar->col_low_bin == NULL)
967         sp->bar->col_low_bin =
968           (gbind *) g_malloc (sp->bar->ncolors * sizeof (gbind));
969       sp->bar->low_bin->count = rank;
970       /*-- count the hiddens among the elements in low_bin --*/
971       sp->bar->low_bin->nhidden = 0;
972       for (k = 0; k < rank; k++) {
973         index = sp->bar->index_to_rank.els[k];
974         m = d->rows_in_plot.els[index];
975         if (d->hidden_now.els[m])
976           sp->bar->low_bin->nhidden++;
977       }
978     }
979 
980     bin = 0;
981     while (rank < d->nrows_in_plot) {
982       index = sp->bar->index_to_rank.els[rank];
983       m = d->rows_in_plot.els[index];
984 
985       yy = d->tform.vals[m][rawsp->p1dvar];
986       while ((bin < sp->bar->nbins) &&
987              (sp->bar->breaks[bin + 1] + sp->bar->offset < yy)) {
988         bin++;
989       }
990 
991       if (bin > sp->bar->nbins - 1) {
992 /* check whether the value is the maximum, if so, add it to the last bin -
993    slight inconsistency with histograms */
994         if (yy == sp->bar->breaks[sp->bar->nbins] + sp->bar->offset) {
995           bin--;
996           sp->bar->bins[bin].count++;
997           if (d->hidden_now.els[m])
998             sp->bar->bins[bin].nhidden++;
999         }
1000         else {
1001           if (sp->bar->high_pts_missing == FALSE) {
1002             sp->bar->high_pts_missing = TRUE;
1003             if (sp->bar->high_bin == NULL)
1004               sp->bar->high_bin = (gbind *) g_malloc (sizeof (gbind));
1005             if (sp->bar->col_high_bin == NULL) {
1006               sp->bar->col_high_bin = (gbind *)
1007                 g_malloc (sp->bar->ncolors * sizeof (gbind));
1008             }
1009             sp->bar->high_bin->count = 0;
1010             sp->bar->high_bin->nhidden = 0;
1011           }
1012           sp->bar->high_bin->count++;
1013           if (d->hidden_now.els[m])
1014             sp->bar->high_bin->nhidden++;
1015         }
1016       }
1017       else {
1018         sp->bar->bins[bin].count++;
1019         if (d->hidden_now.els[m])
1020           sp->bar->bins[bin].nhidden++;
1021       }
1022       rawsp->planar[m].x = bin;
1023       rank++;
1024     }
1025   }
1026   if (sp->bar->low_pts_missing == FALSE) {
1027     if (sp->bar->low_bin != NULL)
1028       g_free ((gpointer) (sp->bar->low_bin));
1029     if (sp->bar->col_low_bin != NULL)
1030       g_free ((gpointer) (sp->bar->col_low_bin));
1031     sp->bar->low_bin = NULL;
1032     sp->bar->col_low_bin = NULL;
1033   }
1034   if (sp->bar->high_pts_missing == FALSE) {
1035     if (sp->bar->high_bin != NULL)
1036       g_free ((gpointer) (sp->bar->high_bin));
1037     if (sp->bar->col_high_bin != NULL)
1038       g_free ((gpointer) (sp->bar->col_high_bin));
1039     sp->bar->high_bin = NULL;
1040     sp->bar->col_high_bin = NULL;
1041   }
1042 
1043   barchart_recalc_dimensions (GGOBI_SPLOT (sp), d, gg);
1044 }
1045 
1046 void
barchart_recalc_dimensions(splotd * rawsp,GGobiData * d,ggobid * gg)1047 barchart_recalc_dimensions (splotd * rawsp, GGobiData * d, ggobid * gg)
1048 {
1049   gint i, maxbincount = 0, maxbin = -1;
1050   gfloat precis = PRECISION1;
1051   vartabled *vtx;
1052 
1053   gfloat scale_y;
1054   gint index;
1055   gint minwidth;
1056   gfloat rdiff, ftmp;
1057   gbind *bin;
1058 
1059   GdkRectangle *rect;
1060   barchartSPlotd *sp = GGOBI_BARCHART_SPLOT (rawsp);
1061 
1062   scale_y = rawsp->scale.y;
1063 
1064   /*
1065    * Calculate is, a scale factor.  Scale so as to use the entire
1066    * plot window (well, as much of the plot window as scale.x and
1067    * scale.y permit.)
1068    */
1069   vtx = vartable_element_get (rawsp->p1dvar, d);
1070 
1071   rdiff = rawsp->p1d.lim.max - rawsp->p1d.lim.min;
1072   index = 0;
1073   for (i = 0; i < sp->bar->nbins; i++) {
1074     bin = &sp->bar->bins[i];
1075     if (bin->count > maxbincount) {
1076       maxbincount = bin->count;
1077       maxbin = i;
1078     }
1079 
1080     sp->bar->bins[i].planar.x = -1;
1081     if (vtx->vartype == categorical) {
1082       ftmp = -1.0 + 2.0 * ((greal) bin->value - rawsp->p1d.lim.min)
1083         / rdiff;
1084       bin->planar.y = (greal) (PRECISION1 * ftmp);
1085     }
1086     else {
1087       ftmp = -1.0 + 2.0 * (sp->bar->breaks[i] - sp->bar->breaks[0]) / rdiff;
1088       bin->planar.y = (glong) (precis * ftmp);
1089     }
1090   }
1091   sp->bar->maxbincounts = maxbincount;
1092 
1093   if (!sp->bar->is_spine) {
1094     greal precis = (greal) PRECISION1;
1095     greal gtmp;
1096     gbind *binminus;
1097 
1098     scale_y /= 2;
1099 
1100     rawsp->iscale.y = (greal) (-1 * (gfloat) rawsp->max.y * scale_y);
1101 
1102     minwidth = rawsp->max.y;
1103     for (i = 0; i < sp->bar->nbins; i++) {
1104       bin = &sp->bar->bins[i];
1105       rect = &sp->bar->bins[i].rect;
1106 
1107       gtmp = bin->planar.y - rawsp->pmid.y;
1108       rect->y = (gint) (gtmp * rawsp->iscale.y / precis);
1109 
1110       rect->x = 10;
1111       rect->y += (rawsp->max.y / 2);
1112       if (i == 0)
1113         minwidth = 2 * (rawsp->max.y - rect->y);
1114       if (i > 0) {
1115         binminus = &sp->bar->bins[i - 1];
1116         minwidth = MIN (minwidth, binminus->rect.y - rect->y - 2);
1117         binminus->rect.height = binminus->rect.y - rect->y - 2;
1118       }
1119 
1120       rect->width = MAX (1, (gint) ((gfloat) (rawsp->max.x - 2 * rect->x)
1121                                     * bin->count / sp->bar->maxbincounts));
1122 
1123     }
1124     sp->bar->bins[sp->bar->nbins - 1].rect.height =
1125       sp->bar->bins[sp->bar->nbins - 2].rect.y -
1126       sp->bar->bins[sp->bar->nbins - 1].rect.y - 1;
1127 
1128 /* set overflow bins to the left and right */
1129     if (sp->bar->low_pts_missing) {
1130       gbind *lbin = sp->bar->low_bin;
1131       lbin->rect.height = minwidth;
1132       lbin->rect.x = 10;
1133       lbin->rect.width = MAX (1, (gint) ((gfloat)
1134                                          (rawsp->max.x - 2 * lbin->rect.x)
1135                                          * lbin->count /
1136                                          sp->bar->maxbincounts));
1137       lbin->rect.y = sp->bar->bins[0].rect.y + 2;
1138     }
1139 
1140     if (sp->bar->high_pts_missing) {
1141       gbind *hbin = sp->bar->high_bin;
1142       hbin->rect.height = sp->bar->bins[0].rect.height;
1143       hbin->rect.x = 10;
1144       hbin->rect.width = MAX (1, (gint) ((gfloat)
1145                                          (rawsp->max.x - 2 * hbin->rect.x)
1146                                          * hbin->count /
1147                                          sp->bar->maxbincounts));
1148       i = sp->bar->nbins - 1;
1149       hbin->rect.y =
1150         sp->bar->bins[i].rect.y - 2 * sp->bar->bins[i].rect.height - 1;
1151     }
1152 
1153     minwidth = MAX ((gint) (0.9 * minwidth), 0);
1154     for (i = 0; i < sp->bar->nbins; i++) {
1155       if (vtx->vartype != categorical)
1156         sp->bar->bins[i].rect.y -= sp->bar->bins[i].rect.height;
1157       else {
1158         sp->bar->bins[i].rect.height = minwidth;
1159         sp->bar->bins[i].rect.y -= minwidth / 2;
1160       }
1161     }
1162   }
1163   else {                        /* spine plot representation */
1164     GdkRectangle *rect;
1165     gint bindist = 2;           /* distance between two bins */
1166     gint maxheight;
1167     gint yoffset;
1168     gint n = d->nrows_in_plot;
1169 
1170     scale_y = 1 - (1 - SCALE_DEFAULT) / 2;
1171     maxheight = (rawsp->max.y - (sp->bar->nbins - 1) * bindist) * scale_y;
1172     yoffset = (gint) (rawsp->max.y * .5 * (1 + scale_y));
1173 
1174     for (i = 0; i < sp->bar->nbins; i++) {
1175       rect = &sp->bar->bins[i].rect;
1176       rect->x = 10;
1177       rect->width = rawsp->max.x - 2 * rect->x;
1178 
1179       rect->height = (gint) ((gfloat) sp->bar->bins[i].count / n * maxheight);
1180       rect->y = yoffset;
1181       yoffset -= (rect->height + bindist);
1182     }
1183 
1184     minwidth = (gint) (0.9 * minwidth);
1185     for (i = 0; i < sp->bar->nbins; i++) {
1186       sp->bar->bins[i].rect.y -= sp->bar->bins[i].rect.height;
1187     }
1188 
1189 /* draw overflow bins */
1190 
1191     if (sp->bar->high_pts_missing) {
1192       sp->bar->high_bin->rect.width = rawsp->max.x - 2 * 10; //10=rect->x;
1193       sp->bar->high_bin->rect.x = 10;
1194       sp->bar->high_bin->rect.height =
1195         (gint) ((gfloat) sp->bar->high_bin->count / n * maxheight);
1196       i = sp->bar->nbins - 1;
1197       sp->bar->high_bin->rect.y =
1198         (gint) (rawsp->max.y * .5 * (1 - scale_y)) -
1199         sp->bar->high_bin->rect.height - 2;
1200     }
1201     if (sp->bar->low_pts_missing) {
1202       sp->bar->low_bin->rect.x = 10;
1203       sp->bar->low_bin->rect.width = rawsp->max.x - 2 * 10; //10=rect->x;
1204       sp->bar->low_bin->rect.height =
1205         (gint) ((gfloat) sp->bar->low_bin->count / n * maxheight);
1206       sp->bar->low_bin->rect.y =
1207         (gint) (rawsp->max.y * .5 * (1 + scale_y)) + 2;
1208     }
1209   }
1210 }
1211 
1212 gboolean
barchart_active_paint_points(splotd * rawsp,GGobiData * d,ggobid * gg)1213 barchart_active_paint_points (splotd * rawsp, GGobiData * d, ggobid * gg)
1214 {
1215   barchartSPlotd *sp = GGOBI_BARCHART_SPLOT (rawsp);
1216   brush_coords *brush_pos = &rawsp->brush_pos;
1217   gint i, m, indx;
1218   GdkRectangle brush_rect;
1219   GdkRectangle dummy;
1220   gint x1 = MIN (brush_pos->x1, brush_pos->x2);
1221   gint x2 = MAX (brush_pos->x1, brush_pos->x2);
1222   gint y1 = MIN (brush_pos->y1, brush_pos->y2);
1223   gint y2 = MAX (brush_pos->y1, brush_pos->y2);
1224   gboolean *hits;
1225   vartabled *vtx = vartable_element_get (rawsp->p1dvar, d);
1226   cpaneld *cpanel = &gg->current_display->cpanel;
1227 
1228   hits = (gboolean *) g_malloc ((sp->bar->nbins + 2) * sizeof (gboolean));
1229 
1230   brush_rect.x = x1;
1231   brush_rect.y = y1;
1232   brush_rect.width = x2 - x1;
1233   brush_rect.height = y2 - y1;
1234 
1235   for (i = 0; i < sp->bar->nbins; i++) {
1236     hits[i + 1] = rect_intersect (&sp->bar->bins[i].rect, &brush_rect,
1237                                   &dummy);
1238   }
1239   if (sp->bar->high_pts_missing)
1240     hits[sp->bar->nbins + 1] =
1241       rect_intersect (&sp->bar->high_bin->rect, &brush_rect, &dummy);
1242   else
1243     hits[sp->bar->nbins + 1] = FALSE;
1244 
1245   if (sp->bar->low_pts_missing)
1246     hits[0] = rect_intersect (&sp->bar->low_bin->rect, &brush_rect, &dummy);
1247   else
1248     hits[0] = FALSE;
1249 
1250   d->npts_under_brush = 0;
1251 
1252   for (i = 0; i < d->nrows_in_plot; i++) {
1253     m = d->rows_in_plot.els[i];
1254 
1255     /*-- skip missings?  --*/
1256     if (!d->missings_show_p && ggobi_data_is_missing(d, m, rawsp->p1dvar))
1257       continue;
1258 
1259     if (d->hidden_now.els[m] &&
1260         (cpanel->br.point_targets != br_shadow
1261          && cpanel->br.point_targets != br_unshadow)) {
1262       continue;
1263     }
1264 
1265     /*-- dfs -- this seems to assume that the values of planar begin at 0,
1266          which may not be true ... this change makes it work for categorical,
1267          but breaks it otherwise --*/
1268     if (vtx->vartype == categorical) {
1269       indx = (gint) (rawsp->planar[m].x - rawsp->p1d.lim.min + 1);
1270     }
1271     else {
1272       indx = (gint) (rawsp->planar[m].x + 1);
1273     }
1274 
1275     d->pts_under_brush.els[m] = hits[indx];
1276     if (hits[indx])
1277       d->npts_under_brush++;
1278 #ifdef PREV
1279     d->pts_under_brush.els[m] = hits[(gint) rawsp->planar[m].x + 1];
1280     if (hits[(gint) rawsp->planar[m].x + 1])
1281       d->npts_under_brush++;
1282 #endif
1283   }
1284 
1285   g_free ((gpointer) hits);
1286 
1287   return d->npts_under_brush;
1288 }
1289 
1290 static ggobid *CurrentGGobi = NULL;
1291 
1292 gint
barpsort(const void * arg1,const void * arg2)1293 barpsort (const void *arg1, const void *arg2)
1294 {
1295   ggobid *gg = CurrentGGobi;
1296 
1297   gint val = 0;
1298   gint *x1 = (gint *) arg1;
1299   gint *x2 = (gint *) arg2;
1300 
1301   if (gg->p1d.gy[*x1] == gg->p1d.gy[*x2])
1302     return 0;
1303 /* to speed things up for categorical variables */
1304 
1305   if (gg->p1d.gy[*x1] < gg->p1d.gy[*x2])
1306     val = -1;
1307   else if (gg->p1d.gy[*x1] > gg->p1d.gy[*x2])
1308     val = 1;
1309 
1310   return (val);
1311 }
1312 
1313 
1314 gfloat
barchart_sort_index(gfloat * yy,gint ny,ggobid * gg,barchartSPlotd * sp)1315 barchart_sort_index (gfloat * yy, gint ny, ggobid * gg, barchartSPlotd * sp)
1316 {
1317   gint i, *indx;
1318   gint rank;
1319   gfloat mindist = 0.0;
1320 
1321   indx = (gint *) g_malloc (ny * sizeof (gint));
1322 
1323 /*
1324  * gy is needed solely for the psort routine:  psort is used by
1325  * qsort to put an index vector in the order that yy will assume.
1326 */
1327   gg->p1d.gy = (gfloat *) g_malloc (ny * sizeof (gfloat));
1328   for (i = 0; i < ny; i++) {
1329     indx[i] = i;
1330     gg->p1d.gy[i] = yy[i];
1331   }
1332   CurrentGGobi = gg;
1333 
1334   qsort ((void *) indx, (gsize) ny, sizeof (gint), barpsort);
1335 
1336   CurrentGGobi = NULL;
1337 /*
1338  * Bug here:  this is screwy if ny < 4.
1339 */
1340   if (sp->bar->is_histogram) {  /* vartype != categorical */
1341     mindist = 0;
1342 
1343     for (i = 0; i < ny; i++) {
1344       sp->bar->index_to_rank.els[i] = indx[i];
1345     }
1346 
1347   }
1348   else {                        /* vartype = categorical */
1349 
1350 /* dfs */
1351     /* XXX
1352        Later, when labelling, if a value doesn't match one of the
1353        level_values, label it 'missing'
1354      */
1355 /* assumption:  there exist at least two bins */
1356     mindist = sp->bar->bins[1].value - sp->bar->bins[0].value;
1357     for (i = 1; i < sp->bar->nbins; i++)
1358       mindist = MIN (mindist,
1359                      sp->bar->bins[i].value - sp->bar->bins[i - 1].value);
1360 
1361     rank = 0;
1362     /*-- there are bin values that don't exist in the data --*/
1363     while (yy[indx[0]] > sp->bar->bins[rank].value)
1364       rank++;
1365 
1366     for (i = 0; i < sp->bar->nbins; i++)
1367       sp->bar->bins[i].index = -1;
1368 
1369     for (i = 0; i < ny; i++) {
1370 
1371       if (i > 0) {
1372         if (yy[indx[i]] != yy[indx[i - 1]]) {
1373           rank++;
1374 
1375           while (yy[indx[i]] > sp->bar->bins[rank].value) {
1376             rank++;
1377           }
1378 
1379           sp->bar->bins[rank].index = indx[i];  /* do I care? */
1380         }
1381       }
1382 
1383       /* This takes me from index to bin -- dfs */
1384       sp->bar->index_to_rank.els[indx[i]] = rank;
1385     }
1386 
1387 /* --- */
1388 #ifdef PREV
1389     rank = 0;
1390     for (i = 0; i < sp->bar->nbins; i++)
1391       sp->bar->bins[i].index = -1;
1392 
1393     mindist = yy[indx[ny - 1]] - yy[indx[0]];
1394     sp->bar->bins[rank].index = indx[0];
1395     for (i = 0; i < ny; i++) {
1396       if (i > 0) {
1397         if (yy[indx[i]] != yy[indx[i - 1]]) {
1398           rank++;
1399           mindist = MIN (yy[indx[i]] - yy[indx[i - 1]], mindist);
1400           sp->bar->bins[rank].index = indx[i];
1401         }
1402       }
1403       sp->bar->index_to_rank.els[indx[i]] = rank;
1404     }
1405 #endif
1406 
1407   }
1408 
1409   g_free ((gpointer) (gg->p1d.gy));
1410   g_free ((gpointer) (indx));
1411 
1412   return mindist;
1413 }
1414 
1415 void
barchart_default_visual_cues_draw(splotd * rawsp,GdkDrawable * drawable,ggobid * gg)1416 barchart_default_visual_cues_draw (splotd * rawsp, GdkDrawable * drawable,
1417                                    ggobid * gg)
1418 {
1419   vartabled *vtx;
1420   displayd *display = gg->current_display;
1421   GGobiData *d = display->d;
1422   barchartSPlotd *sp = GGOBI_BARCHART_SPLOT (rawsp);
1423   vtx = vartable_element_get (GGOBI_SPLOT (sp)->p1dvar, d);
1424 
1425   GdkPoint btn[4];
1426   /* Experiment: ontinue to draw small triangular buttons, but allow
1427      the regions to grow into long rectangles running along the bars.
1428      dfs
1429    */
1430 
1431 
1432   if (vtx->vartype != categorical) {
1433 /* calculate & draw anchor_rgn */
1434     gint y = sp->bar->bins[0].rect.y + sp->bar->bins[0].rect.height;
1435     gint x = sp->bar->bins[0].rect.x;
1436     gint halfwidth = sp->bar->bins[0].rect.height / 2 - 2;
1437 
1438     if (halfwidth <= 0)
1439       halfwidth = 1;
1440 
1441     sp->bar->anchor_rgn[0].x = sp->bar->anchor_rgn[1].x = x - 5;
1442     sp->bar->anchor_rgn[2].x = x + GGOBI_SPLOT (sp)->max.x; // extend
1443     sp->bar->anchor_rgn[0].y = y + halfwidth;
1444     sp->bar->anchor_rgn[1].y = y - halfwidth;
1445     //sp->bar->anchor_rgn[2].y = y;
1446 
1447     // Rectangle instead of triangle
1448     sp->bar->anchor_rgn[3].x = sp->bar->anchor_rgn[2].x;
1449     sp->bar->anchor_rgn[2].y = sp->bar->anchor_rgn[1].y;
1450     sp->bar->anchor_rgn[3].y = sp->bar->anchor_rgn[0].y;
1451 
1452     btn[0].x = btn[1].x = x - 5;
1453     btn[2].x = x;
1454     btn[0].y = y + halfwidth;
1455     btn[1].y = y - halfwidth;
1456     btn[2].y = y;
1457     button_draw_with_shadows (btn, drawable, gg);
1458     //button_draw_with_shadows(sp->bar->anchor_rgn, drawable, gg);
1459 
1460 /* calculate & draw offset_rgn */
1461     y = sp->bar->bins[0].rect.y;
1462     sp->bar->offset_rgn[0].x = sp->bar->offset_rgn[1].x = x - 5;
1463     sp->bar->offset_rgn[2].x = x + GGOBI_SPLOT (sp)->max.x; // extend
1464     sp->bar->offset_rgn[0].y = y + halfwidth;
1465     sp->bar->offset_rgn[1].y = y - halfwidth;
1466     //sp->bar->offset_rgn[2].y = y;
1467 
1468     // Rectangle instead of triangle -- dfs
1469     sp->bar->offset_rgn[3].x = sp->bar->offset_rgn[2].x;
1470     sp->bar->offset_rgn[2].y = sp->bar->offset_rgn[1].y;
1471     sp->bar->offset_rgn[3].y = sp->bar->offset_rgn[0].y;
1472 
1473 
1474     btn[0].x = btn[1].x = x - 5;
1475     btn[2].x = x;
1476     btn[0].y = y + halfwidth;
1477     btn[1].y = y - halfwidth;
1478     btn[2].y = y;
1479     button_draw_with_shadows (btn, drawable, gg);
1480     //button_draw_with_shadows(sp->bar->offset_rgn, drawable, gg);
1481   }
1482 }
1483 
1484 void
button_draw_with_shadows(GdkPoint * region,GdkDrawable * drawable,ggobid * gg)1485 button_draw_with_shadows (GdkPoint * region, GdkDrawable * drawable,
1486                           ggobid * gg)
1487 {
1488   colorschemed *scheme = gg->activeColorScheme;
1489 
1490   /*gdk_gc_set_foreground(gg->plot_GC, &gg->wvis.gray3); */
1491   gdk_gc_set_foreground (gg->plot_GC, &gg->lightgray);
1492   gdk_draw_polygon (drawable, gg->plot_GC, TRUE, region, 3);
1493 
1494 /* dark shadows */
1495   gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_bg);
1496 
1497   gdk_draw_polygon (drawable, gg->plot_GC, FALSE, region, 3);
1498   gdk_draw_line (drawable, gg->plot_GC, region[0].x, region[2].y,
1499                  region[2].x, region[2].y);
1500 
1501 /* light shadows */
1502   gdk_gc_set_foreground (gg->plot_GC, &scheme->rgb_accent);
1503 
1504   gdk_draw_line (drawable, gg->plot_GC, region[0].x, region[0].y,
1505                  region[1].x, region[1].y);
1506   gdk_draw_line (drawable, gg->plot_GC, region[1].x, region[1].y,
1507                  region[2].x, region[2].y);
1508   gdk_draw_line (drawable, gg->plot_GC, region[0].x, region[2].y + 1,
1509                  region[2].x, region[2].y + 1);
1510 }
1511 
1512 gboolean
rect_intersect(GdkRectangle * rect1,GdkRectangle * rect2,GdkRectangle * dest)1513 rect_intersect (GdkRectangle * rect1, GdkRectangle * rect2,
1514                 GdkRectangle * dest)
1515 {
1516   gint right, bottom;
1517   icoords pt;
1518 
1519 // horizontal intersection
1520   pt.x = dest->x = MAX (rect1->x, rect2->x);
1521   right = MIN (rect1->x + rect1->width, rect2->x + rect2->width);
1522   dest->width = MAX (0, right - dest->x);
1523 
1524 // vertical intersection
1525   pt.y = dest->y = MAX (rect1->y, rect2->y);
1526   bottom = MIN (rect1->y + rect1->height, rect2->y + rect2->height);
1527   dest->height = MAX (0, bottom - dest->y);
1528 
1529   return (pt_in_rect (pt, *rect1) && pt_in_rect (pt, *rect2));
1530 }
1531 
1532 gboolean
pt_in_rect(icoords pt,GdkRectangle rect)1533 pt_in_rect (icoords pt, GdkRectangle rect)
1534 {
1535   return ((pt.x >= rect.x) && (pt.x <= rect.x + rect.width)
1536           && (pt.y >= rect.y) && (pt.y <= rect.y + rect.height));
1537 }
1538 
1539 
1540 /* Cues that are drawn in the default mode, indicating that the
1541  * binwidth and anchor point can be changed. */
1542 void
barchart_add_bar_cues(splotd * rawsp,GdkDrawable * drawable,ggobid * gg)1543 barchart_add_bar_cues (splotd * rawsp, GdkDrawable * drawable, ggobid * gg)
1544 {
1545   displayd *display = rawsp->displayptr;
1546   cpaneld *cpanel = &display->cpanel;
1547 
1548   if (cpanel->imode != DEFAULT_IMODE)
1549     return;
1550 
1551   barchart_default_visual_cues_draw (rawsp, drawable, gg);
1552 }
1553 
1554 
1555 gboolean
barchart_identify_bars(icoords mousepos,splotd * rawsp,GGobiData * d,ggobid * gg)1556 barchart_identify_bars (icoords mousepos, splotd * rawsp, GGobiData * d,
1557                         ggobid * gg)
1558 {
1559 /* returns 0 if nothing has changed from the last time */
1560 /*         1 if different bars are hit */
1561   gint i, nbins;
1562   gboolean stop;
1563   barchartSPlotd *sp = GGOBI_BARCHART_SPLOT (rawsp);
1564   nbins = sp->bar->nbins;
1565 
1566   /* check, which bars are hit */
1567   if (sp->bar->low_pts_missing)
1568     sp->bar->bar_hit[0] = pt_in_rect (mousepos, sp->bar->high_bin->rect);
1569   else
1570     sp->bar->bar_hit[0] = FALSE;
1571 
1572   for (i = 0; i < sp->bar->nbins; i++) {
1573     sp->bar->bar_hit[i + 1] = pt_in_rect (mousepos, sp->bar->bins[i].rect);
1574   }
1575 
1576   if (sp->bar->high_pts_missing)
1577     sp->bar->bar_hit[nbins + 1] =
1578       pt_in_rect (mousepos, sp->bar->high_bin->rect);
1579   else
1580     sp->bar->bar_hit[nbins + 1] = FALSE;
1581 
1582 
1583 /* are those bars the same as last time? */
1584   stop = FALSE;
1585 
1586   if (sp->bar->old_nbins == sp->bar->nbins) {
1587     for (i = 0; (i < nbins + 2) && !stop; i++)
1588       stop = (sp->bar->bar_hit[i] != sp->bar->old_bar_hit[i]);
1589 
1590   }
1591   else {
1592     sp->bar->old_nbins = sp->bar->nbins;
1593   }
1594 
1595   sp->bar->same_hits = !stop;
1596 
1597   if (!stop)
1598     return FALSE;               /* nothing else needs to be changed */
1599 
1600 /* set old bar hits to match the new results */
1601   for (i = 0; i < nbins + 2; i++)
1602     sp->bar->old_bar_hit[i] = sp->bar->bar_hit[i];
1603 
1604   return TRUE;
1605 }
1606 
1607 splotd *
ggobi_barchart_splot_new(displayd * dpy,ggobid * gg)1608 ggobi_barchart_splot_new (displayd * dpy, ggobid * gg)
1609 {
1610   barchartSPlotd *bsp;
1611   splotd *sp;
1612 
1613   bsp = g_object_new (GGOBI_TYPE_BARCHART_SPLOT, NULL);
1614   sp = GGOBI_SPLOT (bsp);
1615 
1616   splot_init (sp, dpy, gg);
1617   barchart_clean_init (bsp);
1618   barchart_recalc_counts (bsp, dpy->d, gg);
1619 
1620   return (sp);
1621 }
1622 
1623 /**
1624  Called when we create the barchart.
1625 */
1626 void
barchart_cpanel_init(cpaneld * cpanel,ggobid * gg)1627 barchart_cpanel_init (cpaneld * cpanel, ggobid * gg)
1628 {
1629   cpanel->imode = DEFAULT_IMODE;
1630   cpanel->pmode = EXTENDED_DISPLAY_PMODE;
1631   cpanel->barchart_display_mode = 0;
1632 
1633   /*-- 1d plots --*/
1634   cpanel_p1d_init (cpanel, gg);
1635 
1636   /*-- available modes --*/
1637   cpanel_brush_init (cpanel, gg);
1638   cpanel_identify_init (cpanel, gg);
1639 }
1640 
1641 void
barchartRulerRangesSet()1642 barchartRulerRangesSet ( ) {
1643   // Do nothing!
1644 }
1645