X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcharts%2Fbarchart.c;h=da72fc89f87b84e3b7e3a4b33da38304792ad69f;hb=42d90dac4bc5ee06ef0dd3cd62b84378f16e7ea9;hp=07a39e818f65193b6ddc6ed4816eab19c3a65dd5;hpb=3f0b72d8777ae89902dcf069f850fe557d5323b5;p=pspp diff --git a/src/output/charts/barchart.c b/src/output/charts/barchart.c index 07a39e818f..da72fc89f8 100644 --- a/src/output/charts/barchart.c +++ b/src/output/charts/barchart.c @@ -28,6 +28,7 @@ #include "gl/xalloc.h" #include "data/variable.h" +#include "data/settings.h" #include "language/stats/freq.h" @@ -72,12 +73,74 @@ compare_freq_2level_ptr_3way (const void *a_, const void *b_, const void *bc_) return level0; } +/* Print out a textual representation of a barchart. + This is intended only for testing, and not as a means + of visualising the data. +*/ +static void +barchart_dump (const struct barchart *bc, FILE *fp) +{ + fprintf (fp, "Graphic: Barchart\n"); + fprintf (fp, "Percentage: %d\n", bc->percent); + fprintf (fp, "Total Categories: %d\n", bc->n_nzcats); + fprintf (fp, "Primary Categories: %d\n", bc->n_pcats); + fprintf (fp, "Largest Category: %g\n", bc->largest); + fprintf (fp, "Total Count: %g\n", bc->total_count); + + fprintf (fp, "Y Label: \"%s\"\n", bc->ylabel); + + fprintf (fp, "Categorical Variables:\n"); + for (int i = 0; i < bc->n_vars; ++i) + { + fprintf (fp, " Var: \"%s\"\n", var_get_name (bc->var[i])); + } + + fprintf (fp, "Categories:\n"); + struct category *cat; + HMAP_FOR_EACH (cat, struct category, node, &bc->primaries) + { + fprintf (fp, " %d \"%s\"\n", cat->idx, ds_cstr(&cat->label)); + } + + if (bc->ss) + { + fprintf (fp, "Sub-categories:\n"); + for (int i = 0; i < bc->n_nzcats / bc->n_pcats; ++i) + { + const struct category *cat = bc->ss[i]; + fprintf (fp, " %d \"%s\"\n", cat->idx, ds_cstr(&cat->label)); + } + } + + fprintf (fp, "All Categories:\n"); + for (int i = 0; i < bc->n_nzcats; ++i) + { + const struct freq *frq = bc->cats[i]; + fprintf (fp, "Count: %g; ", frq->count); + + struct string s = DS_EMPTY_INITIALIZER; + var_append_value_name (bc->var[0], &frq->values[0], &s); + + fprintf (fp, "Cat: \"%s\"", ds_cstr (&s)); + ds_clear (&s); + + if (bc->ss) + { + var_append_value_name (bc->var[1], &frq->values[1], &s); + fprintf (fp, ", \"%s\"", ds_cstr (&s)); + } + ds_destroy (&s); + fputc ('\n', fp); + } + + fputc ('\n', fp); +} /* Creates and returns a chart that will render a barchart with - the given TITLE and the N_CATS described in CATS. + the given TITLE and the N_CATS described in CATS. - VAR is an array containing the categorical variables, and N_VAR + VAR is an array containing the categorical variables, and N_VAR the number of them. N_VAR must be exactly 1 or 2. CATS are the counts of the values of those variables. N_CATS is the @@ -85,7 +148,7 @@ compare_freq_2level_ptr_3way (const void *a_, const void *b_, const void *bc_) */ struct chart_item * barchart_create (const struct variable **var, int n_vars, - const char *ylabel, + const char *ylabel, bool percent, struct freq *const *cats, int n_cats) { struct barchart *bar; @@ -100,6 +163,7 @@ barchart_create (const struct variable **var, int n_vars, assert (n_vars >= 1); bar = xzalloc (sizeof *bar); + bar->percent = percent; bar->var = var; bar->n_vars = n_vars; bar->n_nzcats = n_cats; @@ -112,7 +176,7 @@ barchart_create (const struct variable **var, int n_vars, int idx = 0; hmap_init (&bar->primaries); - /* + /* Iterate the categories and create a hash table of the primary categories. We need to do this to find out how many there are and to cache the labels. */ @@ -132,12 +196,13 @@ barchart_create (const struct variable **var, int n_vars, } } - if (!flag) + if (!flag) { struct category *s = xzalloc (sizeof *s); s->idx = idx++; - value_init (&s->val, var_get_width (var[pidx])); - value_copy (&s->val, &src->values[pidx], var_get_width (var[pidx])); + s->width = var_get_width (var[pidx]); + value_init (&s->val, s->width); + value_copy (&s->val, &src->values[pidx], s->width); ds_init_empty (&s->label); var_append_value_name (var[pidx], &s->val, &s->label); @@ -168,12 +233,13 @@ barchart_create (const struct variable **var, int n_vars, break; } } - - if (!flag) + + if (!flag) { struct category *s = xzalloc (sizeof *s); s->idx = idx++; - value_init (&s->val, var_get_width (var[sidx])); + s->width = var_get_width (var[sidx]); + value_init (&s->val, s->width); value_copy (&s->val, &src->values[sidx], var_get_width (var[sidx])); ds_init_empty (&s->label); var_append_value_name (var[sidx], &s->val, &s->label); @@ -189,7 +255,7 @@ barchart_create (const struct variable **var, int n_vars, sort (bar->ss, n_category, sizeof *bar->ss, compare_category_3way, bar); } - + /* Deep copy. Not necessary for cmd line, but essential for the GUI, since an expose callback will access these structs which may not @@ -205,36 +271,38 @@ barchart_create (const struct variable **var, int n_vars, struct hmap level2table; hmap_init (&level2table); int x = 0; - + for (i = 0; i < n_cats; i++) { struct freq *c = cats[i]; struct freq *foo; - int flag = 0; + bool flag = false; size_t hash = hash_freq_2level_ptr (&c, bar); HMAP_FOR_EACH_WITH_HASH (foo, struct freq, node, hash, &level2table) { if (0 == compare_freq_2level_ptr_3way (&foo, &c, bar)) { foo->count += c->count; - + bar->total_count += c->count; + if (foo->count > bar->largest) bar->largest = foo->count; - - flag = 1; + + flag = true; break; } } - - if (!flag) + + if (!flag) { - struct freq *aggregated_freq = freq_clone (c, n_vars, bar->widths); + struct freq *aggregated_freq = freq_clone (c, n_vars, bar->widths); hmap_insert (&level2table, &aggregated_freq->node, hash); - + if (c->count > bar->largest) bar->largest = aggregated_freq->count; - + + bar->total_count += c->count; bar->cats[x++] = aggregated_freq; } } @@ -246,6 +314,9 @@ barchart_create (const struct variable **var, int n_vars, sort (bar->cats, bar->n_nzcats, sizeof *bar->cats, compare_freq_2level_ptr_3way, bar); + if (settings_get_testing_mode ()) + barchart_dump (bar, stdout); + return &bar->chart_item; } @@ -256,6 +327,8 @@ destroy_cat_map (struct hmap *m) struct category *next = NULL; HMAP_FOR_EACH_SAFE (foo, next, struct category, node, m) { + value_destroy (&foo->val, foo->width); + ds_destroy (&foo->label); free (foo); } @@ -280,7 +353,7 @@ barchart_destroy (struct chart_item *chart_item) { freq_destroy (bar->cats[i], bar->n_vars, bar->widths); } - + free (bar->cats); free (bar->ylabel); free (bar->ss);