GnmFunc: make this a GObject.
[gnumeric.git] / src / tools / analysis-frequency.c
blobe96df17d963c4d4aaaaed0f34e34f1241c7a3eb5
1 /*
2 * analysis-frequency.c:
4 * Author:
5 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
7 * (C) Copyright 2008 by Andreas J. Guelzow <aguelzow@pyrshep.ca>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
27 #include <tools/analysis-frequency.h>
28 #include <tools/analysis-tools.h>
29 #include <value.h>
30 #include <ranges.h>
31 #include <expr.h>
32 #include <func.h>
33 #include <numbers.h>
34 #include <sheet-object-graph.h>
35 #include <goffice/goffice.h>
36 #include <sheet.h>
38 static gboolean
39 analysis_tool_frequency_engine_run (data_analysis_output_t *dao,
40 analysis_tools_data_frequency_t *info)
42 gint i_limit, col;
43 GSList *l;
45 GnmFunc *fd_sum;
46 GnmFunc *fd_if;
47 GnmFunc *fd_index;
48 GnmFunc *fd_isblank;
49 GnmFunc *fd_rows = NULL;
50 GnmFunc *fd_columns = NULL;
51 GnmFunc *fd_exact = NULL;
53 fd_sum = gnm_func_lookup_or_add_placeholder ("SUM");
54 gnm_func_inc_usage (fd_sum);
55 fd_if = gnm_func_lookup_or_add_placeholder ("IF");
56 gnm_func_inc_usage (fd_if);
57 fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
58 gnm_func_inc_usage (fd_index);
59 fd_isblank = gnm_func_lookup_or_add_placeholder ("ISBLANK");
60 gnm_func_inc_usage (fd_isblank);
62 if (info->exact) {
63 fd_exact = gnm_func_lookup_or_add_placeholder ("EXACT");
64 gnm_func_inc_usage (fd_exact);
66 if (info->percentage) {
67 fd_rows = gnm_func_lookup_or_add_placeholder ("ROWS");
68 gnm_func_inc_usage (fd_rows);
69 fd_columns = gnm_func_lookup_or_add_placeholder ("COLUMNS");
70 gnm_func_inc_usage (fd_columns);
72 /* General Info */
74 dao_set_italic (dao, 0, 0, 0, 1);
75 set_cell_text_col (dao, 0, 0, _("/Frequency Table"
76 "/Category"));
78 /* Setting up the categories */
80 if (info->predetermined) {
81 int row = 2, i, j, i_h_limit, i_w_limit;
82 GnmExpr const *expr_bin;
83 GnmRange range;
85 range_init_value (&range, info->bin);
86 i_h_limit = range_height (&range);
87 i_w_limit = range_width (&range);
88 i_limit = i_h_limit * i_w_limit;
90 expr_bin = gnm_expr_new_constant (info->bin);
92 for (i = 1; i <= i_h_limit; i++)
93 for (j = 1; j <= i_w_limit; j++) {
94 GnmExpr const *expr_index;
96 expr_index = gnm_expr_new_funcall3
97 (fd_index,
98 gnm_expr_copy (expr_bin),
99 gnm_expr_new_constant (value_new_int (i)),
100 gnm_expr_new_constant (value_new_int (j)));
102 dao_set_cell_expr (dao, 0, row++,
103 gnm_expr_new_funcall3
104 (fd_if,
105 gnm_expr_new_funcall1
106 (fd_isblank,
107 gnm_expr_copy (expr_index)),
108 gnm_expr_new_constant (value_new_string ("")),
109 expr_index));
111 gnm_expr_free (expr_bin);
112 } else {
113 i_limit = info->n;
116 for (l = info->base.input, col = 1; l; col++, l = l->next) {
117 GnmValue *val = value_dup ((GnmValue *)l->data);
118 GnmValue *val_c = NULL;
119 GnmExpr const *expr_count;
120 GnmExpr const *expr_data;
121 GnmExpr const *expr_if;
122 int i, row = 2;
125 dao_set_italic (dao, col, 1, col, 1);
126 if (info->base.labels) {
127 val_c = value_dup (val);
128 switch (info->base.group_by) {
129 case GROUPED_BY_ROW:
130 val->v_range.cell.a.col++;
131 break;
132 default:
133 val->v_range.cell.a.row++;
134 break;
136 dao_set_cell_expr (dao, col, 1,
137 gnm_expr_new_funcall1 (fd_index,
138 gnm_expr_new_constant (val_c)));
139 } else {
140 char *txt;
142 switch (info->base.group_by) {
143 case GROUPED_BY_ROW:
144 txt = g_strdup_printf (_("Row %d"), col);
145 break;
146 case GROUPED_BY_COL:
147 txt = g_strdup_printf (_("Column %d"), col);
148 break;
149 default:
150 txt = g_strdup_printf (_("Area %d"), col);
151 break;
153 dao_set_cell (dao, col, 1, txt);
154 g_free (txt);
157 expr_data = gnm_expr_new_constant (val);
159 if (info->exact)
160 expr_if = gnm_expr_new_funcall2
161 (fd_exact, gnm_expr_copy (expr_data),
162 make_cellref (- col, 0));
163 else
164 expr_if = gnm_expr_new_binary
165 (gnm_expr_copy (expr_data),
166 GNM_EXPR_OP_EQUAL, make_cellref (- col, 0));
168 expr_count = gnm_expr_new_funcall1 (fd_sum,
169 gnm_expr_new_funcall3
170 (fd_if, expr_if,
171 gnm_expr_new_constant (value_new_int (1)),
172 gnm_expr_new_constant (value_new_int (0))));
174 if (info->percentage) {
175 dao_set_format (dao, col, 2, col, i_limit + 2, "0.0%");
176 expr_count = gnm_expr_new_binary (expr_count,
177 GNM_EXPR_OP_DIV,
178 gnm_expr_new_binary
179 (gnm_expr_new_funcall1
180 (fd_rows, gnm_expr_copy (expr_data)),
181 GNM_EXPR_OP_MULT,
182 gnm_expr_new_funcall1
183 (fd_columns, expr_data)));
184 } else
185 gnm_expr_free (expr_data);
187 for (i = 0; i < i_limit; i++, row++)
188 dao_set_cell_array_expr (dao, col, row, gnm_expr_copy (expr_count));
190 gnm_expr_free (expr_count);
193 gnm_func_dec_usage (fd_if);
194 gnm_func_dec_usage (fd_sum);
195 gnm_func_dec_usage (fd_index);
196 gnm_func_dec_usage (fd_isblank);
197 if (fd_rows != NULL)
198 gnm_func_dec_usage (fd_rows);
199 if (fd_columns != NULL)
200 gnm_func_dec_usage (fd_columns);
201 if (fd_exact != NULL)
202 gnm_func_dec_usage (fd_exact);
204 /* Create Chart if requested */
205 if (info->chart != NO_CHART) {
206 SheetObject *so;
207 GogGraph *graph;
208 GogChart *chart;
209 GogPlot *plot;
210 GogSeries *series;
211 GOData *cats;
212 GOData *values;
213 int ct;
215 graph = g_object_new (GOG_TYPE_GRAPH, NULL);
216 chart = GOG_CHART (gog_object_add_by_name (
217 GOG_OBJECT (graph), "Chart", NULL));
218 plot = gog_plot_new_by_name ("GogBarColPlot");
219 if (info->chart == BAR_CHART)
220 go_object_toggle (plot, "horizontal");
221 gog_object_add_by_name (GOG_OBJECT (chart),
222 "Plot", GOG_OBJECT (plot));
224 cats = dao_go_data_vector (dao, 0, 2,
225 0, 2 + i_limit);
227 for (ct = 1; ct < col; ct ++) {
228 g_object_ref (cats);
229 values = dao_go_data_vector (dao, ct, 2,
230 ct, 2 + i_limit);
232 series = gog_plot_new_series (plot);
233 gog_series_set_dim (series, 0, cats, NULL);
234 gog_series_set_dim (series, 1, values, NULL);
236 g_object_unref (cats);
238 so = sheet_object_graph_new (graph);
239 g_object_unref (graph);
241 dao_set_sheet_object (dao, 0, 1, so);
244 dao_redraw_respan (dao);
246 return FALSE;
250 static gint
251 calc_length (GnmValue *bin)
253 g_return_val_if_fail (bin != NULL, 0);
254 g_return_val_if_fail (VALUE_IS_CELLRANGE (bin), 0);
256 return ((bin->v_range.cell.b.col - bin->v_range.cell.a.col + 1) *
257 (bin->v_range.cell.b.row - bin->v_range.cell.a.row + 1));
261 gboolean
262 analysis_tool_frequency_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao, gpointer specs,
263 analysis_tool_engine_t selector, gpointer result)
265 analysis_tools_data_frequency_t *info = specs;
267 switch (selector) {
268 case TOOL_ENGINE_UPDATE_DESCRIPTOR:
269 return (dao_command_descriptor (dao, _("Frequency Table (%s)"), result)
270 == NULL);
271 case TOOL_ENGINE_UPDATE_DAO:
273 int i;
275 prepare_input_range (&info->base.input, info->base.group_by);
277 i = 2 + ((info->predetermined) ? calc_length (info->bin) : info->n);
279 dao_adjust (dao, g_slist_length (info->base.input) + 1, i);
281 return FALSE;
283 case TOOL_ENGINE_CLEAN_UP:
284 return analysis_tool_generic_clean (specs);
285 case TOOL_ENGINE_LAST_VALIDITY_CHECK:
286 return FALSE;
287 case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
288 dao_prepare_output (NULL, dao, _("Frequency Table"));
289 return FALSE;
290 case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
291 return dao_format_output (dao, _("Frequency Table"));
292 case TOOL_ENGINE_PERFORM_CALC:
293 default:
294 return analysis_tool_frequency_engine_run (dao, specs);
296 return TRUE;