1 /*
2  * analysis-normality.c:
3  *
4  *
5  * Author:
6  *   Andreas J. Guelzow  <aguelzow@pyrshep.ca>
7  *
8  * (C) Copyright 2009 by Andreas J. Guelzow  <aguelzow@pyrshep.ca>
9  *
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, see <https://www.gnu.org/licenses/>.
23  */
24 
25 #include <gnumeric-config.h>
26 #include <glib/gi18n-lib.h>
27 #include <gnumeric.h>
28 #include <tools/analysis-normality.h>
29 #include <tools/analysis-tools.h>
30 #include <value.h>
31 #include <ranges.h>
32 #include <expr.h>
33 #include <func.h>
34 #include <numbers.h>
35 #include <sheet-object-graph.h>
36 #include <graph.h>
37 #include <goffice/goffice.h>
38 #include <sheet.h>
39 
40 
41 static gboolean
analysis_tool_normality_engine_run(data_analysis_output_t * dao,analysis_tools_data_normality_t * info)42 analysis_tool_normality_engine_run (data_analysis_output_t *dao,
43 				      analysis_tools_data_normality_t *info)
44 {
45 	guint   col;
46 	GSList *data = info->base.input;
47 	GnmFunc *fd;
48 	GnmFunc *fd_if;
49 
50 	char const *fdname;
51 	char const *testname;
52 	char const *n_comment;
53 
54 	GogGraph     *graph = NULL;
55 	GogPlot	     *plot = NULL;
56 	SheetObject *so;
57 
58 	switch (info->type) {
59 	case normality_test_type_andersondarling:
60 		fdname = "ADTEST";
61 		testname = N_("Anderson-Darling Test");
62 		n_comment = N_("For the Anderson-Darling Test\n"
63 			       "the sample size must be at\n"
64 			       "least 8.");
65 		break;
66 	case normality_test_type_cramervonmises:
67 		fdname = "CVMTEST";
68 		testname = N_("Cram\xc3\xa9r-von Mises Test");
69 		n_comment = N_("For the Cram\xc3\xa9r-von Mises Test\n"
70 			       "the sample size must be at\n"
71 			       "least 8.");
72 		break;
73 	case normality_test_type_lilliefors:
74 		fdname = "LKSTEST";
75 		testname = N_("Lilliefors (Kolmogorov-Smirnov) Test");
76 		n_comment = N_("For the Lilliefors (Kolmogorov-Smirnov) Test\n"
77 			       "the sample size must be at least 5.");
78 		break;
79 	case normality_test_type_shapirofrancia:
80 		fdname = "SFTEST";
81 		testname = N_("Shapiro-Francia Test");
82 		n_comment = N_("For the Shapiro-Francia Test\n"
83 			       "the sample size must be at\n"
84 			       "least 5 and at most 5000.");
85 		break;
86 	default:
87 		g_assert_not_reached();
88 	}
89 
90 	fd = gnm_func_lookup_or_add_placeholder	(fdname);
91 	gnm_func_inc_usage (fd);
92 	fd_if = gnm_func_lookup_or_add_placeholder ("IF");
93 	gnm_func_inc_usage (fd_if);
94 
95 	dao_set_italic (dao, 0, 0, 0, 5);
96         dao_set_cell (dao, 0, 0, _(testname));
97 
98 
99 	if (info->graph) {
100 		GogChart     *chart;
101 
102 		graph = g_object_new (GOG_TYPE_GRAPH, NULL);
103 		chart = GOG_CHART (gog_object_add_by_name (
104 						   GOG_OBJECT (graph), "Chart", NULL));
105 
106 		plot = gog_plot_new_by_name ("GogProbabilityPlot");
107 		go_object_set_property (G_OBJECT (plot), "distribution",
108 						"Distribution", "GODistNormal",
109 						NULL, NULL);
110 
111 		gog_object_add_by_name (GOG_OBJECT (chart),
112 					"Plot", GOG_OBJECT (plot));
113 	}
114 
115 
116 	/* xgettext:
117 	 * Note to translators: in the following string and others like it,
118 	 * the "/" is a separator character that can be changed to anything
119 	 * if the translation needs the slash; just use, say, "|" instead.
120 	 *
121 	 * The items are bundled like this to increase translation context.
122 	 */
123         set_cell_text_col (dao, 0, 1, _("/Alpha"
124 					"/p-Value"
125 					"/Statistic"
126 					"/N"
127 					"/Conclusion"));
128 
129 	dao_set_cell_comment (dao, 0, 4, _(n_comment));
130 
131 	for (col = 1; data != NULL; data = data->next, col++) {
132 		GnmValue *val_org = value_dup (data->data);
133 
134 		/* Note that analysis_tools_write_label may modify val_org */
135 		dao_set_italic (dao, col, 0, col, 0);
136 		analysis_tools_write_label (val_org, dao, &info->base,
137 					    col, 0, col);
138 		if (info->graph) {
139 			GogSeries    *series;
140 
141 			series = gog_plot_new_series (plot);
142 			gog_series_set_dim (series, 0,
143 					    gnm_go_data_vector_new_expr
144 					    (val_org->v_range.cell.a.sheet,
145 					     gnm_expr_top_new (gnm_expr_new_constant (value_dup (val_org)))),
146 					    NULL);
147 		}
148 
149 		if (col == 1)
150 			dao_set_cell_float (dao, col, 1, info->alpha);
151 		else
152 			dao_set_cell_expr (dao, col, 1,
153 					   make_cellref (1 - col, 0));
154 
155 		dao_set_array_expr (dao, col, 2, 1, 3,
156 				    gnm_expr_new_funcall1 (fd, gnm_expr_new_constant (val_org)));
157 		dao_set_cell_expr (dao, col, 5,
158 				   gnm_expr_new_funcall3
159 				   (fd_if, gnm_expr_new_binary
160 				    (make_cellref (0, -4),
161 				     GNM_EXPR_OP_GTE,
162 				     make_cellref (0, -3)),
163 				    gnm_expr_new_constant (value_new_string (_("Not normal"))),
164 				    gnm_expr_new_constant (value_new_string (_("Possibly normal")))));
165 	}
166 
167 	if (info->graph) {
168 		so = sheet_object_graph_new (graph);
169 		g_object_unref (graph);
170 
171 		dao_set_sheet_object (dao, 0, 1, so);
172 	}
173 
174 
175 	gnm_func_dec_usage (fd);
176 	gnm_func_dec_usage (fd_if);
177 
178 	dao_redraw_respan (dao);
179 	return 0;
180 }
181 
182 gboolean
analysis_tool_normality_engine(G_GNUC_UNUSED GOCmdContext * gcc,data_analysis_output_t * dao,gpointer specs,analysis_tool_engine_t selector,gpointer result)183 analysis_tool_normality_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao, gpointer specs,
184 				   analysis_tool_engine_t selector, gpointer result)
185 {
186 	analysis_tools_data_normality_t *info = specs;
187 
188 	switch (selector) {
189 	case TOOL_ENGINE_UPDATE_DESCRIPTOR:
190 		return (dao_command_descriptor (dao, _("Normality Test (%s)"), result)
191 			== NULL);
192 	case TOOL_ENGINE_UPDATE_DAO:
193 		prepare_input_range (&info->base.input, info->base.group_by);
194 		dao_adjust (dao, 1 + g_slist_length (info->base.input), 6);
195 		return FALSE;
196 	case TOOL_ENGINE_CLEAN_UP:
197 		return analysis_tool_generic_clean (specs);
198 	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
199 		return FALSE;
200 	case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
201 		dao_prepare_output (NULL, dao, _("Normality Test"));
202 		return FALSE;
203 	case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
204 		return dao_format_output (dao, _("Normality Test"));
205 	case TOOL_ENGINE_PERFORM_CALC:
206 	default:
207 		return analysis_tool_normality_engine_run (dao, specs);
208 	}
209 	return TRUE;  /* We shouldn't get here */
210 }
211 
212