[gnumeric] Extend regression tool to perform multiple simple regressions. [#614031]



commit 8ae1db236e15b06d3e8f463b3ec9eac21da1cdd3
Author: Andreas J. Guelzow <aguelzow pyrshep ca>
Date:   Wed Mar 31 00:44:45 2010 -0600

    Extend regression tool to perform multiple simple regressions. [#614031]
    
    2010-03-31 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* regression.glade: add radio buttons
    	* dialog-analysis-tools.c (regression_tool_ok_clicked_cb): handle
    	  new radio buttons
    
    2010-03-31 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* analysis-tools.h (analysis_tools_data_regression_t): add fields
    	* analysis-tools.c (analysis_tools_remove_label): change arguments
    	  and change all callers
    	(analysis_tools_write_a_label): new
    	(analysis_tool_regression_simple_engine_run): new
    	(analysis_tool_regression_engine): hook up second engine

 NEWS                                |    2 +
 src/dialogs/ChangeLog               |    6 +
 src/dialogs/dialog-analysis-tools.c |    3 +
 src/dialogs/regression.glade        |  100 ++++++++++++++-----
 src/tools/ChangeLog                 |    9 ++
 src/tools/analysis-tools.c          |  183 +++++++++++++++++++++++++++++++++--
 src/tools/analysis-tools.h          |    2 +
 7 files changed, 269 insertions(+), 36 deletions(-)
---
diff --git a/NEWS b/NEWS
index 5139fc7..80632df 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ Andreas:
 	* Fix column and row header display under Quartz. [#600085]
 	* Fix preferences in gconf-less situations. [#613523]
 	* Implement first letter capitalization. [#613768]
+	* Extend regression tool to perform multiple simple regressions.
+	  [#614031]
 
 Morten:
 	* Improve object sizing tooltip positioning a bit.
diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog
index 63afd77..38c5315 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,9 @@
+2010-03-31 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* regression.glade: add radio buttons
+	* dialog-analysis-tools.c (regression_tool_ok_clicked_cb): handle 
+	  new radio buttons
+
 2010-03-25 Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* dialog-preferences.c (int_pref_widget_to_conf): get the
diff --git a/src/dialogs/dialog-analysis-tools.c b/src/dialogs/dialog-analysis-tools.c
index 4392e8c..d7fdebf 100644
--- a/src/dialogs/dialog-analysis-tools.c
+++ b/src/dialogs/dialog-analysis-tools.c
@@ -2149,6 +2149,9 @@ regression_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
 	w = glade_xml_get_widget (state->base.gui, "intercept-button");
 	data->intercept = 1 - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
 
+	w = glade_xml_get_widget (state->base.gui, "multiple-regression-button");
+	data->multiple_regression = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
 	if (cmd_analysis_tool (WORKBOOK_CONTROL (state->base.wbcg), state->base.sheet,
 			       dao, data, analysis_tool_regression_engine)) {
 		char *text;
diff --git a/src/dialogs/regression.glade b/src/dialogs/regression.glade
index 5401912..f902c84 100644
--- a/src/dialogs/regression.glade
+++ b/src/dialogs/regression.glade
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--*- mode: xml -*-->
+<?xml version="1.0"?>
 <glade-interface>
+  <!-- interface-requires gtk+ 2.6 -->
+  <!-- interface-naming-policy toplevel-contextual -->
   <widget class="GtkDialog" id="Regression">
     <property name="title" translatable="yes">Regression</property>
     <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
@@ -23,15 +23,6 @@
                 <property name="column_spacing">12</property>
                 <property name="row_spacing">6</property>
                 <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
                   <widget class="GtkLabel" id="var1-label">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
@@ -63,11 +54,11 @@
                 </child>
                 <child>
                   <widget class="GtkCheckButton" id="labels_button">
+                    <property name="label" translatable="yes">_Labels</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="label" translatable="yes">_Labels</property>
+                    <property name="receives_default">False</property>
                     <property name="use_underline">True</property>
-                    <property name="response_id">0</property>
                     <property name="draw_indicator">True</property>
                   </widget>
                   <packing>
@@ -77,6 +68,15 @@
                     <property name="y_options"></property>
                   </packing>
                 </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
               </widget>
             </child>
             <child>
@@ -86,8 +86,8 @@
                 <property name="use_underline">True</property>
               </widget>
               <packing>
-                <property name="type">tab</property>
                 <property name="tab_fill">False</property>
+                <property name="type">tab</property>
               </packing>
             </child>
             <child>
@@ -107,13 +107,13 @@
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
+                        <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
                       <widget class="GtkEntry" id="confidence-entry">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="invisible_char">*</property>
                         <property name="text" translatable="yes">0.95</property>
                       </widget>
                       <packing>
@@ -124,16 +124,17 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
+                    <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
                   <widget class="GtkCheckButton" id="intercept-button">
+                    <property name="label" translatable="yes">_Force intercept to be zero</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
                     <property name="border_width">3</property>
-                    <property name="label" translatable="yes">_Force intercept to be zero</property>
                     <property name="use_underline">True</property>
-                    <property name="response_id">0</property>
                     <property name="draw_indicator">True</property>
                   </widget>
                   <packing>
@@ -143,6 +144,41 @@
                   </packing>
                 </child>
                 <child>
+                  <widget class="GtkRadioButton" id="multiple-regression-button">
+                    <property name="label" translatable="yes">_Multiple linear regression</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="border_width">3</property>
+                    <property name="use_underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkRadioButton" id="simple-regression-button">
+                    <property name="label" translatable="yes">Multiple 2-_variable regressions</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="border_width">3</property>
+                    <property name="use_underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                    <property name="group">multiple-regression-button</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
                   <placeholder/>
                 </child>
               </widget>
@@ -157,9 +193,9 @@
                 <property name="use_underline">True</property>
               </widget>
               <packing>
-                <property name="type">tab</property>
                 <property name="position">1</property>
                 <property name="tab_fill">False</property>
+                <property name="type">tab</property>
               </packing>
             </child>
             <child>
@@ -180,9 +216,9 @@
                 <property name="use_underline">True</property>
               </widget>
               <packing>
-                <property name="type">tab</property>
                 <property name="position">2</property>
                 <property name="tab_fill">False</property>
+                <property name="type">tab</property>
               </packing>
             </child>
           </widget>
@@ -193,7 +229,7 @@
         <child>
           <widget class="GtkLabel" id="warnings">
             <property name="visible">True</property>
-            <property name="justify">GTK_JUSTIFY_CENTER</property>
+            <property name="justify">center</property>
           </widget>
           <packing>
             <property name="position">2</property>
@@ -205,38 +241,47 @@
             <property name="layout_style">GTK_BUTTONBOX_END</property>
             <child>
               <widget class="GtkButton" id="helpbutton">
+                <property name="label">gtk-help</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
-                <property name="label">gtk-help</property>
+                <property name="receives_default">False</property>
                 <property name="use_stock">True</property>
-                <property name="response_id">0</property>
               </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
             </child>
             <child>
               <widget class="GtkButton" id="cancelbutton">
+                <property name="label">gtk-cancel</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
-                <property name="label">gtk-cancel</property>
+                <property name="receives_default">False</property>
                 <property name="use_stock">True</property>
-                <property name="response_id">0</property>
               </widget>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
                 <property name="position">1</property>
               </packing>
             </child>
             <child>
               <widget class="GtkButton" id="okbutton">
+                <property name="label">gtk-ok</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
                 <property name="has_default">True</property>
-                <property name="label">gtk-ok</property>
+                <property name="receives_default">False</property>
                 <property name="use_stock">True</property>
-                <property name="response_id">0</property>
               </widget>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
                 <property name="position">2</property>
               </packing>
             </child>
@@ -244,6 +289,7 @@
           <packing>
             <property name="expand">False</property>
             <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">0</property>
           </packing>
         </child>
       </widget>
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index c0b4dc2..4a24143 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,12 @@
+2010-03-31 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* analysis-tools.h (analysis_tools_data_regression_t): add fields
+	* analysis-tools.c (analysis_tools_remove_label): change arguments
+	  and change all callers
+	(analysis_tools_write_a_label): new
+	(analysis_tool_regression_simple_engine_run): new
+	(analysis_tool_regression_engine): hook up second engine
+
 2010-03-28  Morten Welinder  <terra gnome org>
 
 	* goal-seek.c (update_data): Properly handle NaNs.  Fixes #614147.
diff --git a/src/tools/analysis-tools.c b/src/tools/analysis-tools.c
index 7b097f2..40ecf27 100644
--- a/src/tools/analysis-tools.c
+++ b/src/tools/analysis-tools.c
@@ -129,17 +129,15 @@ cb_adjust_areas (gpointer data, G_GNUC_UNUSED gpointer user_data)
 
 /*
  *  analysis_tools_remove_label:
- *  @val: range to extract label from
- *  @info: analysis_tools_data_generic_t info
  *
  */
 
 static void
 analysis_tools_remove_label (GnmValue *val,
-			    analysis_tools_data_generic_t *info)
+			     gboolean labels, group_by_t group_by)
 {
-	if (info->labels) {
-		switch (info->group_by) {
+	if (labels) {
+		switch (group_by) {
 		case GROUPED_BY_ROW:
 			val->v_range.cell.a.col++;
 			break;
@@ -178,7 +176,7 @@ analysis_tools_write_label (GnmValue *val, data_analysis_output_t *dao,
 
 		label->v_range.cell.b = label->v_range.cell.a;
 		dao_set_cell_expr (dao, x, y, gnm_expr_new_constant (label));
-		analysis_tools_remove_label (val, info);
+		analysis_tools_remove_label (val, info->labels, info->group_by);
 	} else {
 		switch (info->group_by) {
 		case GROUPED_BY_ROW:
@@ -201,6 +199,54 @@ analysis_tools_write_label (GnmValue *val, data_analysis_output_t *dao,
 }
 
 /*
+ *  analysis_tools_write_label:
+ *  @val: range to extract label from
+ *  @dao: data_analysis_output_t, where to write to
+ *  @labels: analysis_tools_data_generic_t infowhether the 
+ *           @val contains label info
+ *  @group_by: grouping info
+ *  @x: output col number
+ *  @y: output row number
+ *  @i: default col/row number
+ *
+ */
+
+static void
+analysis_tools_write_a_label (GnmValue *val, data_analysis_output_t *dao,
+			      gboolean   labels, group_by_t group_by,
+			      int x, int y)
+{
+	if (labels) {
+		GnmValue *label = value_dup (val);
+
+		label->v_range.cell.b = label->v_range.cell.a;
+		dao_set_cell_expr (dao, x, y, gnm_expr_new_constant (label));
+		analysis_tools_remove_label (val, labels, group_by);
+	} else {
+		char const *str = ((group_by == GROUPED_BY_ROW) ? "row" : "col");
+		char const *label = ((group_by == GROUPED_BY_ROW) ? _("Row") : _("Column"));
+
+		GnmFunc *fd_concatenate;
+		GnmFunc *fd_cell;
+
+		fd_concatenate = gnm_func_lookup_or_add_placeholder ("CONCATENATE", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+		gnm_func_ref (fd_concatenate);
+		fd_cell = gnm_func_lookup_or_add_placeholder ("CELL", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+		gnm_func_ref (fd_cell);
+
+		dao_set_cell_expr (dao, x, y, gnm_expr_new_funcall3
+				   (fd_concatenate, gnm_expr_new_constant (value_new_string (label)),
+				    gnm_expr_new_constant (value_new_string (" ")),
+				    gnm_expr_new_funcall2 (fd_cell,
+							   gnm_expr_new_constant (value_new_string (str)),
+							   gnm_expr_new_constant (value_dup (val)))));
+
+		gnm_func_unref (fd_concatenate);
+		gnm_func_unref (fd_cell);
+	}
+}
+
+/*
  *  analysis_tools_write_label_ftest:
  *  @val: range to extract label from
  *  @dao: data_analysis_output_t, where to write to
@@ -3242,6 +3288,109 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 	return FALSE;
 }
 
+static gboolean
+analysis_tool_regression_simple_engine_run (data_analysis_output_t *dao,
+				     analysis_tools_data_regression_t *info)
+{
+	GnmFunc *fd_linest;
+	GnmFunc *fd_index;
+	GnmFunc *fd_fdist;
+	GnmFunc *fd_rows;
+	GnmFunc *fd_columns;
+
+	GSList *inputdata;
+	guint row;
+
+	GnmValue *val_dep = value_dup (info->base.range_2);
+	GnmExpr const *expr_intercept = gnm_expr_new_constant (value_new_bool (info->intercept));
+	GnmExpr const *expr_observ;
+	GnmExpr const *expr_val_dep;
+
+	fd_linest = gnm_func_lookup_or_add_placeholder ("LINEST", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+	gnm_func_ref (fd_linest);
+	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+	gnm_func_ref (fd_index);
+	fd_fdist = gnm_func_lookup_or_add_placeholder ("FDIST", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+	gnm_func_ref (fd_fdist);
+	fd_rows = gnm_func_lookup_or_add_placeholder ("ROWS", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+	gnm_func_ref (fd_rows);
+	fd_columns = gnm_func_lookup_or_add_placeholder ("COLUMNS", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
+	gnm_func_ref (fd_columns);
+
+	dao_set_italic (dao, 0, 0, 4, 0);
+	dao_set_italic (dao, 0, 2, 5, 2);
+        set_cell_text_row (dao, 0, 0, _("/SUMMARY OUTPUT"
+					"/"
+					"/Response Variable:"
+					"/"
+					"/Observations:"));
+        set_cell_text_row (dao, 0, 2, _("/Independent Variable"
+					"/R^2"
+					"/Slope"
+					"/Intercept"
+					"/F"
+					"/Significance of F"));
+	analysis_tools_write_a_label (val_dep, dao,
+				      info->base.labels, info->group_by,
+				      3, 0);
+
+	expr_val_dep = gnm_expr_new_constant (val_dep);
+	dao_set_cell_expr (dao, 5, 0, gnm_expr_new_binary (gnm_expr_new_funcall1 (fd_rows, gnm_expr_copy (expr_val_dep)),
+							   GNM_EXPR_OP_MULT,
+							   gnm_expr_new_funcall1 (fd_columns, gnm_expr_copy (expr_val_dep))));
+	expr_observ = dao_get_cellref (dao, 5, 0);
+
+	for (row = 3, inputdata = info->indep_vars; inputdata != NULL;
+	     inputdata = inputdata->next, row++) {
+		GnmValue *val_indep = value_dup (inputdata->data);
+		GnmExpr const *expr_linest;
+		
+		dao_set_italic (dao, 0, row, 0, row);
+		analysis_tools_write_a_label (val_indep, dao,
+					      info->base.labels, info->group_by,
+					      0, row);
+		expr_linest = gnm_expr_new_funcall4 (fd_linest,
+						     gnm_expr_copy (expr_val_dep),
+						     gnm_expr_new_constant (val_indep),
+						     gnm_expr_copy (expr_intercept),
+						     gnm_expr_new_constant (value_new_bool (TRUE)));
+		dao_set_cell_array_expr (dao, 1, row,
+				 gnm_expr_new_funcall3 (fd_index,
+							gnm_expr_copy (expr_linest),
+							gnm_expr_new_constant (value_new_int (3)),
+							gnm_expr_new_constant (value_new_int (1))));
+		dao_set_cell_array_expr (dao, 4, row,
+				 gnm_expr_new_funcall3 (fd_index,
+							gnm_expr_copy (expr_linest),
+							gnm_expr_new_constant (value_new_int (4)),
+							gnm_expr_new_constant (value_new_int (1))));
+		dao_set_array_expr (dao, 2, row, 2, 1, expr_linest);
+
+		dao_set_cell_expr (dao, 5, row, gnm_expr_new_funcall3 
+				   (fd_fdist,
+				    make_cellref (-1, 0),
+				    gnm_expr_new_constant (value_new_int (1)),
+				    gnm_expr_new_binary (gnm_expr_copy (expr_observ),
+							 GNM_EXPR_OP_SUB,
+							 gnm_expr_new_constant (value_new_int (2)))));
+
+	}
+
+	gnm_expr_free (expr_intercept);
+	gnm_expr_free (expr_observ);
+	gnm_expr_free (expr_val_dep);
+
+	gnm_func_unref (fd_fdist);
+	gnm_func_unref (fd_linest);
+	gnm_func_unref (fd_index);
+	gnm_func_unref (fd_rows);
+	gnm_func_unref (fd_columns);
+
+	dao_redraw_respan (dao);
+
+	return FALSE;
+}
+
 gboolean
 analysis_tool_regression_engine (data_analysis_output_t *dao, gpointer specs,
 			    analysis_tool_engine_t selector, gpointer result)
@@ -3256,11 +3405,22 @@ analysis_tool_regression_engine (data_analysis_output_t *dao, gpointer specs,
 	{
 		gint xdim = calculate_xdim (info->base.range_1, info->group_by);
 
-		dao_adjust (dao, 7, 17 + xdim);
+		if (info->multiple_regression) {
+			info->indep_vars = NULL;
+			dao_adjust (dao, 7, 17 + xdim);
+		} else {
+			info->indep_vars = g_slist_prepend (NULL, info->base.range_1);
+			info->base.range_1 = NULL;
+			prepare_input_range (&info->indep_vars, info->group_by);
+			dao_adjust (dao, 6, 3 + xdim);
+		}
 		return FALSE;
 	}
 	case TOOL_ENGINE_CLEAN_UP:
+		range_list_destroy (info->indep_vars);
+		info->indep_vars = NULL;
 		return analysis_tool_generic_b_clean (specs);
+		
 	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
 		return FALSE;
 	case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
@@ -3270,7 +3430,10 @@ analysis_tool_regression_engine (data_analysis_output_t *dao, gpointer specs,
 		return dao_format_output (dao, _("Regression"));
 	case TOOL_ENGINE_PERFORM_CALC:
 	default:
-		return analysis_tool_regression_engine_run (dao, specs);
+		if (info->multiple_regression)
+			return analysis_tool_regression_engine_run (dao, specs);
+		else
+			return analysis_tool_regression_simple_engine_run (dao, specs);
 	}
 	return TRUE;  /* We shouldn't get here */
 }
@@ -3948,7 +4111,9 @@ analysis_tool_anova_single_engine_run (data_analysis_output_t *dao, gpointer spe
 			GnmExpr const *expr_one;
 			GnmExpr const *expr_count_one;
 
-			analysis_tools_remove_label (val_org, &info->base);
+			analysis_tools_remove_label (val_org, 
+						     info->base.labels,
+						     info->base.group_by);
 			expr_one = gnm_expr_new_constant (value_dup (val_org));
 
 			arg_ss_total =  gnm_expr_list_append
diff --git a/src/tools/analysis-tools.h b/src/tools/analysis-tools.h
index b5a4af5..a2e325c 100644
--- a/src/tools/analysis-tools.h
+++ b/src/tools/analysis-tools.h
@@ -166,6 +166,8 @@ typedef struct {
 	analysis_tools_data_generic_b_t base;
 	gint       intercept;
 	group_by_t group_by;
+	gboolean   multiple_regression;
+	GSList    *indep_vars;
 } analysis_tools_data_regression_t;
 
 gboolean analysis_tool_regression_engine (data_analysis_output_t *dao, gpointer specs,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]