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