gnumeric r16964 - in trunk: . src/dialogs src/tools



Author: guelzow
Date: Fri Nov 14 07:36:31 2008
New Revision: 16964
URL: http://svn.gnome.org/viewvc/gnumeric?rev=16964&view=rev

Log:
2008-11-11  Andreas J. Guelzow <aguelzow pyrshep ca>

	* kaplan-meier.glade: add groups tab
	* dialog-analysis-tool-kaplan-meier.c (KaplanMeierToolState): add new
	  fields 
	(kaplan_meier_tool_update_sensitivity_cb): handle new tab
	(kaplan_meier_tool_get_groups_cb): new
	(kaplan_meier_tool_get_groups): new
	(kaplan_meier_tool_ok_clicked_cb): handle new tab
	(cb_group_name_edited): new
	(cb_change_from): new
	(cb_selection_changed): new
	(kaplan_meier_tool_update_groups_sensitivity_cb): new
	(dialog_kaplan_meier_tool_treeview_add_item): new
	(dialog_kaplan_meier_tool_setup_treeview): new
	(kaplan_meier_tool_add_group_cb): new
	(kaplan_meier_tool_remove_group_cb): new
	(dialog_kaplan_meier_tool): handle new tab

2008-11-14  Andreas J. Guelzow <aguelzow pyrshep ca>

	* analysis-kaplan-meier.c (analysis_tool_kaplan_meier_engine_run):
	  handle multiple groups
	(analysis_tool_kaplan_meier_clear_gl_cb): new
	(analysis_tool_kaplan_meier_engine): properly dispose of all data
	* analysis-kaplan-meier.h (analysis_tools_data_kaplan_meier_t): add 
	  new fields
	(analysis_tools_kaplan_meier_group_t): new
	



Modified:
   trunk/NEWS
   trunk/src/dialogs/ChangeLog
   trunk/src/dialogs/dialog-analysis-tool-kaplan-meier.c
   trunk/src/dialogs/dialog-analysis-tools.c
   trunk/src/dialogs/kaplan-meier.glade
   trunk/src/tools/ChangeLog
   trunk/src/tools/analysis-kaplan-meier.c
   trunk/src/tools/analysis-kaplan-meier.h

Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS	(original)
+++ trunk/NEWS	Fri Nov 14 07:36:31 2008
@@ -7,7 +7,8 @@
 	* Permit lexicographic sorting by sheet names in the manage sheets
 	  dialog [#527076]
 	* Add functional seealso links in the function browser
-	* Allow ranges of censor marks in Kaplan-Meier tool [#558582]
+	* Allow ranges of censor marks in Kaplan-Meier tool and
+	  multiple groups [#558582]
 
 Hib Eris:
 	* Fix problems with toolbars when no handle bar present.  [#559249]

Modified: trunk/src/dialogs/dialog-analysis-tool-kaplan-meier.c
==============================================================================
--- trunk/src/dialogs/dialog-analysis-tool-kaplan-meier.c	(original)
+++ trunk/src/dialogs/dialog-analysis-tool-kaplan-meier.c	Fri Nov 14 07:36:31 2008
@@ -52,10 +52,7 @@
 
 #include <glade/glade.h>
 #include <string.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtklabel.h>
+#include <gtk/gtk.h>
 
 #define KAPLAN_MEIER_KEY      "analysistools-kaplan-meier-dialog"
 
@@ -66,9 +63,27 @@
 	GtkWidget *censor_spin_to;
 	GtkWidget *graph_button;
 	GtkWidget *tick_button;
+	GtkWidget *add_group_button;
+	GtkWidget *remove_group_button;
 	GtkWidget *std_error_button;
+	GtkWidget *groups_check;
+	GtkWidget *groups_table;
+	GnmExprEntry *groups_input;
+	GtkTreeView *groups_treeview;
+	GtkListStore *groups_list;
 } KaplanMeierToolState;
 
+enum
+{
+     GROUP_NAME,
+     GROUP_FROM,
+     GROUP_TO,
+     GROUP_ADJUSTMENT_FROM,
+     GROUP_ADJUSTMENT_TO,
+     GROUP_COLUMNS
+};
+
+
 /**
  * kaplan_meier_tool_update_sensitivity_cb:
  * @dummy:
@@ -81,12 +96,15 @@
 				      KaplanMeierToolState *state)
 {
 	gboolean censorship;
+	gboolean groups;
         GnmValue *input_range;
         GnmValue *input_range_2 = NULL;
 	int height, width;
 
 	censorship = gtk_toggle_button_get_active (
 		GTK_TOGGLE_BUTTON (state->censorship_button));
+	groups = gtk_toggle_button_get_active (
+		GTK_TOGGLE_BUTTON (state->groups_check));
 	
 	gtk_widget_set_sensitive (state->tick_button, censorship);
 
@@ -138,6 +156,34 @@
 
 		value_release (input_range_2);
 	}
+
+	if (groups) {
+		input_range_2 =  gnm_expr_entry_parse_as_value
+			(GNM_EXPR_ENTRY (state->groups_input), state->base.sheet);
+		
+		if (input_range_2 == NULL) {
+			gtk_label_set_text (GTK_LABEL (state->base.warning),
+					    _("The groups column is not valid."));
+			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
+			return;
+		}
+		if (input_range_2->v_range.cell.b.col != input_range_2->v_range.cell.a.col) {
+			gtk_label_set_text (GTK_LABEL (state->base.warning),
+					    _("The groups column should be part of a single column."));
+			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
+			value_release (input_range_2);
+			return;
+		} 
+		if (input_range_2->v_range.cell.b.row - input_range_2->v_range.cell.a.row != height) {
+			gtk_label_set_text (GTK_LABEL (state->base.warning),
+					    _("The groups and time columns should have the same height."));
+			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
+			value_release (input_range_2);
+			return;
+		}
+
+		value_release (input_range_2);
+	}
 		
         if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
 		gtk_label_set_text (GTK_LABEL (state->base.warning),
@@ -153,6 +199,37 @@
 	return;
 }
 
+static gboolean 
+kaplan_meier_tool_get_groups_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
+				 gpointer data)
+{
+	GSList **list = data;
+	analysis_tools_kaplan_meier_group_t *group_item = g_new0 (analysis_tools_kaplan_meier_group_t, 1);
+	
+	gtk_tree_model_get (model, iter,
+			    GROUP_NAME, &(group_item->name),
+			    GROUP_FROM, &(group_item->group_from),
+			    GROUP_TO, &(group_item->group_to),	    
+			    -1);
+	*list = g_slist_prepend (*list, group_item);
+
+	return FALSE;
+}
+
+static GSList *
+kaplan_meier_tool_get_groups (KaplanMeierToolState *state)
+{
+	GSList *list = NULL;
+	
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->groups_check)))
+		return NULL;
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (state->groups_list),
+				kaplan_meier_tool_get_groups_cb,
+				&list);
+	return g_slist_reverse (list);
+}
+
 /**
  * kaplan_meier_tool_ok_clicked_cb:
  * @button:
@@ -193,6 +270,10 @@
 	data->censor_mark = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (state->censor_spin_from));
 	data->censor_mark_to = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (state->censor_spin_to));
 
+	data->group_list = kaplan_meier_tool_get_groups (state);
+	data->range_3 = ((data->group_list == NULL) ? NULL : gnm_expr_entry_parse_as_value
+			 (GNM_EXPR_ENTRY (state->groups_input), state->base.sheet)); 
+
 	data->chart = gtk_toggle_button_get_active (
 		GTK_TOGGLE_BUTTON (state->graph_button));
 	data->ticks = gtk_toggle_button_get_active (
@@ -239,6 +320,17 @@
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->censorship_button), TRUE);
 	return FALSE;
 }
+
+static gboolean
+kaplan_meier_tool_set_groups_cb (G_GNUC_UNUSED GtkWidget *widget,
+				 G_GNUC_UNUSED GdkEventFocus *event,
+				 KaplanMeierToolState *state)
+{
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->groups_check), TRUE);
+	return FALSE;
+}
+
+
 static gboolean
 kaplan_meier_tool_set_censor_from_cb (G_GNUC_UNUSED GtkWidget *dummy,
 				KaplanMeierToolState *state)
@@ -258,6 +350,226 @@
 	return FALSE;
 }
 
+static void
+cb_group_name_edited (GtkCellRendererText *cell,
+		      gchar               *path_string,
+		      gchar               *new_text,
+		      KaplanMeierToolState *state)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	if (cell != NULL) {
+		path = gtk_tree_path_new_from_string (path_string);
+		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list), 
+					     &iter, path))
+			gtk_list_store_set (state->groups_list, &iter, 
+					    GROUP_NAME, new_text, -1);
+		else
+			g_warning ("Did not get a valid iterator");
+		gtk_tree_path_free (path);
+	}
+}
+
+static void
+cb_change_to (GtkCellRendererText *cell,
+	      gchar               *path_string,
+	      gchar               *new_text,
+	      KaplanMeierToolState *state)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	guint val = (guint) (atoi (new_text));
+
+	if (cell != NULL) {
+		path = gtk_tree_path_new_from_string (path_string);
+		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list), 
+					     &iter, path))
+			gtk_list_store_set (state->groups_list, &iter, 
+					    GROUP_TO, val, -1);
+		else
+			g_warning ("Did not get a valid iterator");
+		gtk_tree_path_free (path);
+	}
+}
+
+static void
+cb_change_from (GtkCellRendererText *cell,
+	      gchar               *path_string,
+	      gchar               *new_text,
+	      KaplanMeierToolState *state)
+{
+	if (cell != NULL) {
+		GtkTreeIter iter;
+		GtkTreePath *path;
+		guint val = (guint) (atoi (new_text));
+		guint old_to;
+		GtkObject *adjustment_to;
+   
+
+		path = gtk_tree_path_new_from_string (path_string);
+		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list), 
+					     &iter, path))
+			gtk_list_store_set (state->groups_list, &iter, 
+					    GROUP_FROM, val,
+					    -1);
+		else
+			g_warning ("Did not get a valid iterator");
+		gtk_tree_path_free (path);
+
+		gtk_tree_model_get (GTK_TREE_MODEL (state->groups_list), &iter, 
+				    GROUP_TO, &old_to, 
+				    GROUP_ADJUSTMENT_TO, &adjustment_to,
+				    -1);
+
+		if (old_to < val)
+			gtk_list_store_set (state->groups_list, &iter, 
+					    GROUP_TO, val,
+					    -1);
+		g_object_set (G_OBJECT (adjustment_to), "lower", (gdouble) val, NULL);
+			
+	}
+}
+
+static void
+cb_selection_changed (GtkTreeSelection *selection,
+		      KaplanMeierToolState *state)
+{
+	gtk_widget_set_sensitive (state->remove_group_button, 
+				  gtk_tree_selection_get_selected (selection, NULL, NULL));
+}
+
+static void
+kaplan_meier_tool_update_groups_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
+				      KaplanMeierToolState *state)
+{
+	gboolean groups = gtk_toggle_button_get_active (
+		GTK_TOGGLE_BUTTON (state->groups_check));
+	GtkTreeSelection  *selection = gtk_tree_view_get_selection (state->groups_treeview);
+
+	gtk_widget_set_sensitive (state->add_group_button, groups);
+	gtk_widget_set_sensitive (GTK_WIDGET (state->groups_treeview), groups);
+
+	if (groups)
+		cb_selection_changed (selection, state);
+	else {
+		gtk_tree_selection_unselect_all (selection);
+		gtk_widget_set_sensitive (state->remove_group_button, FALSE);
+	}
+}
+
+static void
+dialog_kaplan_meier_tool_treeview_add_item  (KaplanMeierToolState *state, guint i)
+{
+		GtkTreeIter iter;
+		char * name = g_strdup_printf (_("Group %d"), i);
+		GtkObject *adjustment_to = gtk_adjustment_new (0, 0, G_MAXUSHORT, 1, 1, 1);
+		GtkObject *adjustment_from = gtk_adjustment_new (0, 0, G_MAXUSHORT, 1, 1, 1);
+		gtk_list_store_append (state->groups_list, &iter);
+		gtk_list_store_set (state->groups_list, &iter,
+				    GROUP_NAME, name,
+				    GROUP_FROM, (uint) i,
+				    GROUP_TO, (uint) i,
+				    GROUP_ADJUSTMENT_FROM, adjustment_from,
+				    GROUP_ADJUSTMENT_TO, adjustment_to,
+				    -1);
+		g_free (name);	
+}
+
+static void
+dialog_kaplan_meier_tool_setup_treeview (KaplanMeierToolState *state)
+{
+	guint i;
+	GtkCellRenderer *renderer;
+	GtkWidget *scrolled = glade_xml_get_widget (state->base.gui, "groups-scrolled");
+	GtkTreeSelection  *selection;
+
+	state->groups_treeview = GTK_TREE_VIEW (glade_xml_get_widget
+						(state->base.gui,
+						 "groups-tree"));
+	state->groups_list = gtk_list_store_new (GROUP_COLUMNS, 
+						 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_OBJECT);
+	state->groups_treeview = GTK_TREE_VIEW (gtk_tree_view_new_with_model
+						(GTK_TREE_MODEL (state->groups_list)));
+	selection = gtk_tree_view_get_selection (state->groups_treeview);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+	for (i = 0; i<2; i++)
+		dialog_kaplan_meier_tool_treeview_add_item (state, i);
+
+	g_signal_connect (selection,
+			  "changed",
+			  G_CALLBACK (cb_selection_changed), state);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (G_OBJECT (renderer),
+		      "editable", TRUE,
+		      NULL);
+	gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
+						     -1, _("Group"),
+						     renderer,
+						     "text", GROUP_NAME, 
+						     NULL);
+	g_signal_connect (G_OBJECT (renderer), "edited",
+			  G_CALLBACK (cb_group_name_edited), state);
+
+	renderer = gtk_cell_renderer_spin_new ();
+
+	g_object_set (G_OBJECT (renderer), "editable", TRUE, "xalign", 1.0, 
+		      "digits", 0, NULL);
+	g_signal_connect (G_OBJECT (renderer), "edited",
+			  G_CALLBACK (cb_change_from), state);
+	gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
+						     -1, _("From"),
+						     renderer,
+						     "text", GROUP_FROM,
+						     "adjustment", GROUP_ADJUSTMENT_FROM,
+						     NULL);
+
+	renderer = gtk_cell_renderer_spin_new ();
+	g_object_set (G_OBJECT (renderer), "editable", TRUE, "xalign", 1.0,
+		      "digits", 0, NULL);
+	g_signal_connect (G_OBJECT (renderer), "edited",
+			  G_CALLBACK (cb_change_to), state);
+	gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
+						     -1, _("To"),
+						     renderer,
+						     "text", GROUP_TO,
+						     "adjustment", GROUP_ADJUSTMENT_TO,
+						     NULL);
+
+	gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (state->groups_treeview));
+
+	cb_selection_changed (selection, state);
+}
+
+static gboolean
+kaplan_meier_tool_add_group_cb (G_GNUC_UNUSED GtkWidget *dummy,
+				KaplanMeierToolState *state)
+{
+	dialog_kaplan_meier_tool_treeview_add_item 
+		(state, gtk_tree_model_iter_n_children (GTK_TREE_MODEL (state->groups_list),
+                                                        NULL));
+	return FALSE;
+}
+
+static gboolean
+kaplan_meier_tool_remove_group_cb (G_GNUC_UNUSED GtkWidget *dummy,
+				KaplanMeierToolState *state)
+{
+	GtkTreeSelection  *selection;
+	GtkTreeIter iter;
+
+	selection = gtk_tree_view_get_selection (state->groups_treeview);
+
+	if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+		gtk_list_store_remove ( state->groups_list, &iter);
+	}
+
+	return FALSE;
+}
+
+
 /**
  * dialog_kaplan_meier_tool:
  * @wbcg:
@@ -270,6 +582,7 @@
 dialog_kaplan_meier_tool (WBCGtk *wbcg, Sheet *sheet)
 {
         KaplanMeierToolState *state;
+	GtkWidget *widget;
 
 	if (wbcg == NULL) {
 		return 1;
@@ -311,9 +624,33 @@
 	state->tick_button = GTK_WIDGET (glade_xml_get_widget
 						  (state->base.gui,
 						   "tick-button"));
+	state->add_group_button = GTK_WIDGET (glade_xml_get_widget
+						  (state->base.gui,
+						   "add-button"));
+	state->remove_group_button = GTK_WIDGET (glade_xml_get_widget
+						  (state->base.gui,
+						   "remove-button"));
 	state->std_error_button = GTK_WIDGET (glade_xml_get_widget
 						  (state->base.gui,
 						   "std-error-button"));
+
+	state->groups_check = GTK_WIDGET (glade_xml_get_widget
+						  (state->base.gui,
+						   "groups-check"));
+	state->groups_table = GTK_WIDGET (glade_xml_get_widget
+						  (state->base.gui,
+						   "groups-table"));
+	state->groups_input = gnm_expr_entry_new (state->base.wbcg, TRUE);
+	gnm_expr_entry_set_flags (state->groups_input, GNM_EE_FORCE_ABS_REF,
+				  GNM_EE_MASK);
+	gtk_table_attach (GTK_TABLE (state->groups_table), GTK_WIDGET (state->groups_input),
+			  1, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+
+	dialog_kaplan_meier_tool_setup_treeview (state);
+
+	g_signal_connect_after (G_OBJECT (state->groups_check),
+		"toggled",
+		G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
 	g_signal_connect_after (G_OBJECT (state->censorship_button),
 		"toggled",
 		G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
@@ -323,9 +660,23 @@
 	g_signal_connect_after (G_OBJECT (state->std_error_button),
 		"toggled",
 		G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
+	g_signal_connect_after (G_OBJECT (state->groups_input),
+				"changed",
+				G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb),
+				state);
+
+	g_signal_connect_after (G_OBJECT (state->groups_check),
+		"toggled",
+		G_CALLBACK (kaplan_meier_tool_update_groups_sensitivity_cb), state);
 	g_signal_connect_after (G_OBJECT (state->tick_button),
 		"toggled",
 		G_CALLBACK (kaplan_meier_tool_set_graph_cb), state);
+	g_signal_connect_after (G_OBJECT (state->add_group_button),
+		"clicked",
+		G_CALLBACK (kaplan_meier_tool_add_group_cb), state);
+	g_signal_connect_after (G_OBJECT (state->remove_group_button),
+		"clicked",
+		G_CALLBACK (kaplan_meier_tool_remove_group_cb), state);
 	g_signal_connect_after (G_OBJECT (state->censor_spin_from),
 		"value-changed",
 		G_CALLBACK (kaplan_meier_tool_set_censor_from_cb), state);
@@ -335,12 +686,28 @@
 	g_signal_connect (G_OBJECT
 			  (gnm_expr_entry_get_entry (
 				  GNM_EXPR_ENTRY (state->base.input_entry_2))),
-		"focus-in-event",
-		G_CALLBACK (kaplan_meier_tool_set_censorship_cb), state);
+			  "focus-in-event",
+			  G_CALLBACK (kaplan_meier_tool_set_censorship_cb), state);
+	g_signal_connect (G_OBJECT
+			  (gnm_expr_entry_get_entry (
+				  GNM_EXPR_ENTRY (state->groups_input))),
+			  "focus-in-event",
+			  G_CALLBACK (kaplan_meier_tool_set_groups_cb), state);
+
+	gnumeric_editable_enters (GTK_WINDOW (state->base.dialog),
+					  GTK_WIDGET (state->groups_input));
+
+	widget = glade_xml_get_widget (state->base.gui, "groups-label");
+	gtk_label_set_mnemonic_widget (GTK_LABEL (widget),
+				       GTK_WIDGET (state->groups_input));
+	go_atk_setup_label (widget, GTK_WIDGET (state->groups_input));
 
 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
 	kaplan_meier_tool_update_sensitivity_cb (NULL, state);
+	kaplan_meier_tool_update_groups_sensitivity_cb (NULL, state);
 	tool_load_selection ((GenericToolState *)state, TRUE);
 
+	gtk_widget_show_all (GTK_WIDGET (state->base.dialog));
+
         return 0;
 }

Modified: trunk/src/dialogs/dialog-analysis-tools.c
==============================================================================
--- trunk/src/dialogs/dialog-analysis-tools.c	(original)
+++ trunk/src/dialogs/dialog-analysis-tools.c	Fri Nov 14 07:36:31 2008
@@ -411,13 +411,21 @@
 	if (widget == NULL) {
 		state->input_entry = NULL;
 	} else {
-		table = GTK_TABLE (glade_xml_get_widget (state->gui,
-							 "input-table"));
+		GList *this_label_widget;
+		GtkTableChild *tchild;
+
+		table = GTK_TABLE (gtk_widget_get_parent (widget));
 		state->input_entry = gnm_expr_entry_new (state->wbcg, TRUE);
 		gnm_expr_entry_set_flags (state->input_entry, flags | GNM_EE_FORCE_ABS_REF,
 					  GNM_EE_MASK);
+
+		this_label_widget = g_list_find_custom
+		  (table->children, widget, (GCompareFunc) dialog_tool_cmp);
+		tchild = (GtkTableChild *)(this_label_widget->data);
+
 		gtk_table_attach (table, GTK_WIDGET (state->input_entry),
-				  1, 2, 0, 1,
+				  tchild->right_attach, tchild->right_attach + 1, 
+				  tchild->top_attach, tchild->bottom_attach,
 				  GTK_EXPAND | GTK_FILL, 0,
 				  0, 0);
 		g_signal_connect_after (G_OBJECT (state->input_entry),
@@ -452,9 +460,10 @@
 		tchild = (GtkTableChild *)(this_label_widget->data);
 
 		gtk_table_attach (table, GTK_WIDGET (state->input_entry_2),
-			  1, 2, tchild->top_attach, tchild->bottom_attach,
-			  GTK_EXPAND | GTK_FILL, 0,
-			  0, 0);
+				  tchild->right_attach, tchild->right_attach + 1, 
+				  tchild->top_attach, tchild->bottom_attach,
+				  GTK_EXPAND | GTK_FILL, 0,
+				  0, 0);
 		g_signal_connect_after (G_OBJECT (state->input_entry_2),
 					"changed",
 					G_CALLBACK (sensitivity_cb), state);

Modified: trunk/src/dialogs/kaplan-meier.glade
==============================================================================
--- trunk/src/dialogs/kaplan-meier.glade	(original)
+++ trunk/src/dialogs/kaplan-meier.glade	Fri Nov 14 07:36:31 2008
@@ -24,7 +24,7 @@
                     <property name="visible">True</property>
                     <property name="border_width">12</property>
                     <property name="n_rows">5</property>
-                    <property name="n_columns">2</property>
+                    <property name="n_columns">3</property>
                     <property name="column_spacing">12</property>
                     <property name="row_spacing">2</property>
                     <child>
@@ -37,6 +37,12 @@
                       <placeholder/>
                     </child>
                     <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
                       <widget class="GtkCheckButton" id="censor-button">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
@@ -46,6 +52,7 @@
                         <property name="draw_indicator">True</property>
                       </widget>
                       <packing>
+                        <property name="right_attach">3</property>
                         <property name="top_attach">1</property>
                         <property name="bottom_attach">2</property>
                         <property name="x_options">GTK_FILL</property>
@@ -56,12 +63,13 @@
                       <widget class="GtkLabel" id="var2-label">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="xpad">25</property>
-                        <property name="label" translatable="yes">Censor column:</property>
+                        <property name="label" translatable="yes">Censor co_lumn:</property>
                         <property name="use_underline">True</property>
                         <property name="justify">GTK_JUSTIFY_RIGHT</property>
                       </widget>
                       <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
                         <property name="top_attach">2</property>
                         <property name="bottom_attach">3</property>
                         <property name="x_options">GTK_FILL</property>
@@ -73,11 +81,12 @@
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
                         <property name="xpad">5</property>
-                        <property name="label" translatable="yes">Time column:</property>
+                        <property name="label" translatable="yes">_Time column:</property>
                         <property name="use_underline">True</property>
                         <property name="justify">GTK_JUSTIFY_RIGHT</property>
                       </widget>
                       <packing>
+                        <property name="right_attach">2</property>
                         <property name="x_options">GTK_FILL</property>
                         <property name="y_options">GTK_FILL</property>
                       </packing>
@@ -90,6 +99,8 @@
                         <property name="justify">GTK_JUSTIFY_RIGHT</property>
                       </widget>
                       <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
                         <property name="top_attach">3</property>
                         <property name="bottom_attach">4</property>
                       </packing>
@@ -102,6 +113,8 @@
                         <property name="justify">GTK_JUSTIFY_RIGHT</property>
                       </widget>
                       <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
                         <property name="top_attach">4</property>
                         <property name="bottom_attach">5</property>
                       </packing>
@@ -114,8 +127,8 @@
                         <property name="climb_rate">1</property>
                       </widget>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
                         <property name="top_attach">3</property>
                         <property name="bottom_attach">4</property>
                       </packing>
@@ -128,8 +141,8 @@
                         <property name="climb_rate">1</property>
                       </widget>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
                         <property name="top_attach">4</property>
                         <property name="bottom_attach">5</property>
                       </packing>
@@ -154,6 +167,136 @@
               </packing>
             </child>
             <child>
+              <widget class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="border_width">12</property>
+                <property name="spacing">5</property>
+                <child>
+                  <widget class="GtkCheckButton" id="groups-check">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Define _multiple groups</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkTable" id="groups-table">
+                    <property name="visible">True</property>
+                    <property name="n_rows">7</property>
+                    <property name="n_columns">3</property>
+                    <property name="column_spacing">5</property>
+                    <property name="row_spacing">5</property>
+                    <property name="homogeneous">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="groups-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Groups column:</property>
+                      </widget>
+                      <packing>
+                        <property name="y_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="add-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="remove-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">gtk-remove</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkScrolledWindow" id="groups-scrolled">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="shadow_type">GTK_SHADOW_IN</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">7</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Groups</property>
+                <property name="use_underline">True</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">3</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
               <widget class="GtkVBox" id="vbox4">
                 <property name="visible">True</property>
                 <property name="border_width">12</property>
@@ -221,7 +364,7 @@
                 </child>
               </widget>
               <packing>
-                <property name="position">1</property>
+                <property name="position">2</property>
               </packing>
             </child>
             <child>
@@ -234,7 +377,7 @@
               </widget>
               <packing>
                 <property name="type">tab</property>
-                <property name="position">1</property>
+                <property name="position">2</property>
                 <property name="tab_fill">False</property>
               </packing>
             </child>
@@ -246,7 +389,7 @@
                 </child>
               </widget>
               <packing>
-                <property name="position">2</property>
+                <property name="position">3</property>
               </packing>
             </child>
             <child>
@@ -258,7 +401,7 @@
               </widget>
               <packing>
                 <property name="type">tab</property>
-                <property name="position">2</property>
+                <property name="position">3</property>
                 <property name="tab_fill">False</property>
               </packing>
             </child>

Modified: trunk/src/tools/analysis-kaplan-meier.c
==============================================================================
--- trunk/src/tools/analysis-kaplan-meier.c	(original)
+++ trunk/src/tools/analysis-kaplan-meier.c	Fri Nov 14 07:36:31 2008
@@ -51,10 +51,15 @@
 				    analysis_tools_data_kaplan_meier_t *info)
 {
 	int rows, row;
-	int std_err_col = info->censored ? 5 : 4;
-	int prob_col = info->censored ? 4 : 3;
+	int std_err_col = info->censored ? 4 : 3;
+	int prob_col = info->censored ? 3 : 2;
+	int repetitions = ((info->group_list == NULL) ? 1 
+			   : g_slist_length (info->group_list));
+	int colspan = ((info->std_err ? 4 : 3) + (info->censored ? 1 : 0));
+	int i;
 
 	GnmExpr const *expr_data;
+	GnmExpr const *expr_group_data = NULL;
 	GnmExpr const *expr_small;
 	GnmExpr const *expr_time;
 	GnmExpr const *expr_at_risk;
@@ -70,6 +75,13 @@
 	GnmFunc *fd_sum;
 	GnmFunc *fd_sqrt = NULL;
 
+	GogGraph     *graph;
+	GogPlot	     *plot;
+	SheetObject *so;
+	GOData *times;
+
+	GSList *gl = info->group_list;
+
 	fd_small = gnm_func_lookup ("SMALL", NULL);
 	gnm_func_ref (fd_small);
 	fd_if = gnm_func_lookup ("IF", NULL);
@@ -90,132 +102,32 @@
 	dao_set_italic (dao, 0, 0, 0, 0);
 	dao_set_cell (dao, 0, 0, _("Kaplan-Meier"));
 
-	dao_set_italic (dao, 0, 1, prob_col, 1);
-	if (info->censored) 
-		set_cell_text_row (dao, 0, 1, 
-				   "/Time"
-				   "/At Risk"
-				   "/Deaths"
-				   "/Censures"
-				   "/Probability");
-	else
-		set_cell_text_row (dao, 0, 1, 
-				   "/Time"
-				   "/At Risk"
-				   "/Deaths"
-				   "/Probability");
-	if (info->std_err) {
-		dao_set_italic (dao, std_err_col, 1, std_err_col, 1);
-		dao_set_cell (dao, std_err_col, 1, "Standard Error"); 
+
+	if (info->chart) {
+		GogChart     *chart;
+		
+		graph = g_object_new (GOG_GRAPH_TYPE, NULL);
+		chart = GOG_CHART (gog_object_add_by_name (
+						   GOG_OBJECT (graph), "Chart", NULL));
+
+		plot = gog_plot_new_by_name ("GogXYPlot");
+		go_object_set_property (G_OBJECT (plot), "interpolation",
+						"Default interpolation", "step-start",
+						NULL, NULL);
+
+		gog_object_add_by_name (GOG_OBJECT (chart),
+					"Plot", GOG_OBJECT (plot));
+		times = dao_go_data_vector (dao, 0, 2, 0, 1+rows);
 	}
 
-	expr_data = gnm_expr_new_constant (value_dup (info->base.range_1));
-	
-	expr_at_risk = gnm_expr_new_funcall3 
-		(fd_if,
-		 gnm_expr_new_binary (make_cellref (-1, 0),
-				      GNM_EXPR_OP_EQUAL,
-				      gnm_expr_new_constant (value_new_string (""))),
-		 gnm_expr_new_constant (value_new_string ("")),
-		 gnm_expr_new_funcall1 (fd_sum,
-					gnm_expr_new_funcall3 
-					(fd_if,
-					 gnm_expr_new_binary
-					 (gnm_expr_copy (expr_data),
-					  GNM_EXPR_OP_LT,
-					  make_cellref (-1, 0)),
-					 gnm_expr_new_constant (value_new_int (0)),
-					 gnm_expr_new_constant (value_new_int (1)))));
+	dao_set_italic (dao, 0, 1, 0, 1);
+	dao_set_cell (dao, 0, 1, _("Time"));
 
-	if (info->censored) {
-		GnmExpr const *expr_censor;
+	expr_data = gnm_expr_new_constant (value_dup (info->base.range_1));
 
-		if (info->censor_mark == info->censor_mark_to)
-			expr_censor = gnm_expr_new_funcall3 
-				(fd_if,
-				 gnm_expr_new_binary
-				 (gnm_expr_new_constant (value_dup (info->base.range_2)),
-				  GNM_EXPR_OP_EQUAL,
-				  gnm_expr_new_constant (value_new_int (info->censor_mark))),
-				 gnm_expr_new_constant (value_new_int (1)),
-				 gnm_expr_new_constant (value_new_int (0)));
-		else
-			expr_censor = gnm_expr_new_binary 
-				(gnm_expr_new_funcall3 
-				 (fd_if,
-				  gnm_expr_new_binary
-				  (gnm_expr_new_constant (value_dup (info->base.range_2)),
-				   GNM_EXPR_OP_GTE,
-				   gnm_expr_new_constant (value_new_int (info->censor_mark))),
-				  gnm_expr_new_constant (value_new_int (1)),
-				  gnm_expr_new_constant (value_new_int (0))),
-				 GNM_EXPR_OP_MULT,
-				 gnm_expr_new_funcall3 
-				 (fd_if,
-				  gnm_expr_new_binary
-				  (gnm_expr_new_constant (value_dup (info->base.range_2)),
-				   GNM_EXPR_OP_LTE,
-				   gnm_expr_new_constant (value_new_int (info->censor_mark_to))),
-				  gnm_expr_new_constant (value_new_int (1)),
-				  gnm_expr_new_constant (value_new_int (0))));
-			
+	if (info->group_list != NULL && info->range_3 != NULL)
+		expr_group_data = gnm_expr_new_constant (value_dup (info->range_3));
 
-		expr_deaths = gnm_expr_new_funcall3 
-			(fd_if,
-			 gnm_expr_new_binary (make_cellref (-1, 0),
-					      GNM_EXPR_OP_EQUAL,
-					      gnm_expr_new_constant (value_new_string (""))),
-			 gnm_expr_new_constant (value_new_string ("")),
-			 gnm_expr_new_funcall1 (fd_sum,
-						gnm_expr_new_binary
-						(gnm_expr_new_funcall3 
-						 (fd_if,
-						  gnm_expr_new_binary
-						  (gnm_expr_copy (expr_data),
-						   GNM_EXPR_OP_EQUAL,
-						   make_cellref (-2, 0)),
-						  gnm_expr_new_constant (value_new_int (1)),
-						  gnm_expr_new_constant (value_new_int (0))),
-						 GNM_EXPR_OP_MULT,
-						 gnm_expr_new_binary 
-						 (gnm_expr_new_constant (value_new_int (1)),
-						  GNM_EXPR_OP_SUB,
-						  gnm_expr_copy (expr_censor)))));
-		expr_censures =  gnm_expr_new_funcall3 
-			(fd_if,
-			 gnm_expr_new_binary (make_cellref (-1, 0),
-					      GNM_EXPR_OP_EQUAL,
-					      gnm_expr_new_constant (value_new_string (""))),
-			 gnm_expr_new_constant (value_new_string ("")),
-			 gnm_expr_new_funcall1 (fd_sum,
-						gnm_expr_new_binary
-						(gnm_expr_new_funcall3 
-						 (fd_if,
-						  gnm_expr_new_binary
-						  (gnm_expr_copy (expr_data),
-						   GNM_EXPR_OP_EQUAL,
-						   make_cellref (-3, 0)),
-						  gnm_expr_new_constant (value_new_int (1)),
-						  gnm_expr_new_constant (value_new_int (0))),
-						 GNM_EXPR_OP_MULT,
-						 expr_censor)));
-	} else
-		expr_deaths = gnm_expr_new_funcall3 
-			(fd_if,
-			 gnm_expr_new_binary (make_cellref (-1, 0),
-					      GNM_EXPR_OP_EQUAL,
-					      gnm_expr_new_constant (value_new_string (""))),
-			 gnm_expr_new_constant (value_new_string ("")),
-			 gnm_expr_new_funcall1 (fd_sum,
-						gnm_expr_new_funcall3 
-						(fd_if,
-						 gnm_expr_new_binary
-						 (gnm_expr_copy (expr_data),
-						  GNM_EXPR_OP_EQUAL,
-						  make_cellref (-2, 0)),
-						 gnm_expr_new_constant (value_new_int (1)),
-						 gnm_expr_new_constant (value_new_int (0)))));
-		
 	expr_small = gnm_expr_new_funcall2 (fd_small, 
 					    gnm_expr_new_funcall3
 					    (fd_if,
@@ -223,7 +135,7 @@
 					     (gnm_expr_copy (expr_data),
 					      GNM_EXPR_OP_GT,
 					      make_cellref (0, -1)),
-					     expr_data,
+					     gnm_expr_copy (expr_data),
 					     gnm_expr_new_constant (value_new_string ("N/A"))),
 					    gnm_expr_new_constant (value_new_int (1)));
 	expr_time = gnm_expr_new_funcall3 (fd_if,
@@ -231,165 +143,361 @@
 								  gnm_expr_copy (expr_small)),
 					   gnm_expr_new_constant (value_new_string ("")),
 					   expr_small);
-	
-	expr_prob_zero = gnm_expr_new_binary (gnm_expr_new_binary (make_cellref (1 - prob_col, 0),
-								   GNM_EXPR_OP_SUB,
-								   make_cellref (2 - prob_col, 0)),
-					      GNM_EXPR_OP_DIV,
-					      make_cellref (1 - prob_col, 0));
-	expr_prob = gnm_expr_new_funcall3 (fd_if,
-					   gnm_expr_new_binary
-					   (make_cellref (2 - prob_col, 0),
-					    GNM_EXPR_OP_EQUAL,
-					    gnm_expr_new_constant (value_new_string (""))),
-					   gnm_expr_new_constant (value_new_string ("")),
-					   gnm_expr_new_binary (gnm_expr_copy (expr_prob_zero),
-								GNM_EXPR_OP_MULT,
-								make_cellref (0, -1)));
-
-	if (info->std_err) {
-		expr_std_err = gnm_expr_new_funcall3 (fd_if,
-						      gnm_expr_new_binary
-						      (make_cellref (-1, 0),
-						       GNM_EXPR_OP_EQUAL,
-						       gnm_expr_new_constant (value_new_string (""))),
-						      gnm_expr_new_constant (value_new_string ("")),
-						      gnm_expr_new_binary (make_cellref (-1, 0),
-									   GNM_EXPR_OP_MULT,
-									   gnm_expr_new_funcall1
-									   (fd_sqrt,
-									    gnm_expr_new_binary 
-									    (gnm_expr_new_binary 
-									     (gnm_expr_new_constant 
-									      (value_new_int (1)),
-									      GNM_EXPR_OP_SUB,
-									      make_cellref (-1, 0)),
-									     GNM_EXPR_OP_DIV,
-									     make_cellref 
-									     (1 - std_err_col, 0)))));
-
-		dao_set_format  (dao, std_err_col, 2, std_err_col, rows + 1, "0.0000");
-		dao_set_cell_expr (dao, std_err_col, 2, gnm_expr_copy (expr_std_err));
-	}
-
-	dao_set_format  (dao, prob_col, 2, prob_col, rows + 1, "0.00%");
 
 	dao_set_cell_int (dao, 0, 2, 0);
-	dao_set_cell_array_expr (dao, 1, 2, gnm_expr_copy (expr_at_risk)); 	
-	dao_set_cell_array_expr (dao, 2, 2, gnm_expr_copy (expr_deaths)); 	
-	dao_set_cell_expr (dao, prob_col, 2, expr_prob_zero);
-
-	if (expr_censures != NULL)
-		dao_set_cell_array_expr (dao, 3, 2, gnm_expr_copy (expr_censures));
-
-	for (row = 1; row < rows; row++) {
-		dao_set_cell_array_expr (dao, 0, 2+row, gnm_expr_copy (expr_time)); 	
-		dao_set_cell_array_expr (dao, 1, 2+row, gnm_expr_copy (expr_at_risk)); 	
-		dao_set_cell_array_expr (dao, 2, 2+row, gnm_expr_copy (expr_deaths)); 	
-		dao_set_cell_array_expr (dao, prob_col, 2+row, gnm_expr_copy (expr_prob)); 
-		if (expr_censures != NULL)
-			dao_set_cell_array_expr (dao, 3, 2+row, gnm_expr_copy (expr_censures));
-		if (info->std_err)
-			dao_set_cell_expr (dao, std_err_col, 2+row, gnm_expr_copy (expr_std_err));
-	}
-
+	for (row = 1; row < rows; row++)
+		dao_set_cell_array_expr (dao, 0, 2+row, gnm_expr_copy (expr_time));
+	
 	gnm_expr_free (expr_time);
-	gnm_expr_free (expr_at_risk);
-	gnm_expr_free (expr_deaths);
-	gnm_expr_free (expr_prob);
-	if (expr_censures != NULL)
-		gnm_expr_free (expr_censures);
-	if (expr_std_err != NULL)
-		gnm_expr_free (expr_std_err);
+
 	
-	gnm_func_unref (fd_small);
-	gnm_func_unref (fd_if);
-	gnm_func_unref (fd_iserror);
-	gnm_func_unref (fd_sum);
-	if (fd_sqrt != NULL)
-		gnm_func_unref (fd_sqrt);
 
-	/* Create Chart if requested */
-	if (info->chart) {
-		SheetObject *so;
-		GogGraph     *graph;
-		GogChart     *chart;
-		GogPlot	     *plot;
-		GogSeries    *series;
-		GOData *times;
-		GOData *probabilities;
-		GogStyle  *style;
+	dao->offset_col++;
+
+	/* Repeated Info start */
+	for (i = 0; i < repetitions; i++) {
+		GnmExpr const *expr_group = NULL;
 		
-		graph = g_object_new (GOG_GRAPH_TYPE, NULL);
-		chart = GOG_CHART (gog_object_add_by_name (
-						   GOG_OBJECT (graph), "Chart", NULL));
+		if (gl != NULL && gl->data != NULL) {
+			analysis_tools_kaplan_meier_group_t *gd = gl->data;
+			if (gd->name != NULL) {
+				dao_set_italic (dao, 0, 0, 0, 0);
+				dao_set_cell (dao, 0, 0, gd->name);
 
-		plot = gog_plot_new_by_name ("GogXYPlot");
-		go_object_set_property (G_OBJECT (plot), "interpolation",
-						"Default interpolation", "step-start",
-						NULL, NULL);
+				if (gd->group_from == gd->group_to)
+					expr_group = gnm_expr_new_funcall3 
+					(fd_if,
+					 gnm_expr_new_binary
+					 (gnm_expr_copy (expr_group_data),
+					  GNM_EXPR_OP_EQUAL,
+					  gnm_expr_new_constant (value_new_int (gd->group_from))),
+					 gnm_expr_new_constant (value_new_int (1)),
+					 gnm_expr_new_constant (value_new_int (0)));
+				else
+					expr_group =  gnm_expr_new_binary 
+					(gnm_expr_new_funcall3 
+					 (fd_if,
+					  gnm_expr_new_binary
+					  (gnm_expr_copy (expr_group_data),
+					   GNM_EXPR_OP_GTE,
+					   gnm_expr_new_constant (value_new_int (gd->group_from))),
+					  gnm_expr_new_constant (value_new_int (1)),
+					  gnm_expr_new_constant (value_new_int (0))),
+					 GNM_EXPR_OP_MULT,
+					 gnm_expr_new_funcall3 
+					 (fd_if,
+					  gnm_expr_new_binary
+					  (gnm_expr_copy (expr_group_data),
+					   GNM_EXPR_OP_LTE,
+					   gnm_expr_new_constant (value_new_int (gd->group_to))),
+					  gnm_expr_new_constant (value_new_int (1)),
+					  gnm_expr_new_constant (value_new_int (0))));
+			}
+		}
 
-		gog_object_add_by_name (GOG_OBJECT (chart),
-					"Plot", GOG_OBJECT (plot));
+		if (expr_group == NULL)
+			expr_group = gnm_expr_new_constant (value_new_int (1));
 		
-		times = dao_go_data_vector (dao, 0, 2, 0, 1+rows);
-		probabilities = dao_go_data_vector (dao, prob_col, 2, prob_col, 1+rows);
-
-		if (info->censored && info->ticks)
-			g_object_ref (times);
+		dao_set_italic (dao, 0, 1, prob_col, 1);
+		if (info->censored) 
+			set_cell_text_row (dao, 0, 1, 
+					   _("/At Risk"
+					     "/Deaths"
+					     "/Censures"
+					     "/Probability"));
+		else
+			set_cell_text_row (dao, 0, 1, 
+					   _("/At Risk"
+					     "/Deaths"
+					     "/Probability"));
+		if (info->std_err) {
+			dao_set_italic (dao, std_err_col, 1, std_err_col, 1);
+			dao_set_cell (dao, std_err_col, 1, _("Standard Error")); 
+		}
+		
+		expr_at_risk = gnm_expr_new_funcall3 
+			(fd_if,
+			 gnm_expr_new_binary (make_cellref (-1-i*colspan, 0),
+					      GNM_EXPR_OP_EQUAL,
+					      gnm_expr_new_constant (value_new_string (""))),
+			 gnm_expr_new_constant (value_new_string ("")),
+			 gnm_expr_new_funcall1 (fd_sum,
+						gnm_expr_new_binary (
+						gnm_expr_new_funcall3 
+						(fd_if,
+						 gnm_expr_new_binary
+						 (gnm_expr_copy (expr_data),
+						  GNM_EXPR_OP_LT,
+						  make_cellref (-1-i*colspan, 0)),
+						 gnm_expr_new_constant (value_new_int (0)),
+						 gnm_expr_new_constant (value_new_int (1))),
+						GNM_EXPR_OP_MULT,
+						gnm_expr_copy (expr_group))));
+		
+		if (info->censored) {
+			GnmExpr const *expr_censor;
 			
-		series = gog_plot_new_series (plot);
-		gog_series_set_dim (series, 0, times, NULL);
-		gog_series_set_dim (series, 1, probabilities, NULL);
-
-		style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
-		style->marker.auto_shape = FALSE;
-		go_marker_set_shape (style->marker.mark, GO_MARKER_NONE);
-		gog_styled_object_set_style (GOG_STYLED_OBJECT (series), style);
-
-		if (info->censored && info->ticks) {
-			GOData *censures;
-			GnmExpr const *expr;
-
-			expr = gnm_expr_new_binary 
-				(gnm_expr_new_binary (dao_get_rangeref (dao, prob_col, 2, prob_col, 1+rows),
+			if (info->censor_mark == info->censor_mark_to)
+				expr_censor = gnm_expr_new_funcall3 
+					(fd_if,
+					 gnm_expr_new_binary
+					 (gnm_expr_new_constant (value_dup (info->base.range_2)),
+					  GNM_EXPR_OP_EQUAL,
+					  gnm_expr_new_constant (value_new_int (info->censor_mark))),
+					 gnm_expr_new_constant (value_new_int (1)),
+					 gnm_expr_new_constant (value_new_int (0)));
+			else
+				expr_censor = gnm_expr_new_binary 
+					(gnm_expr_new_funcall3 
+					 (fd_if,
+					  gnm_expr_new_binary
+					  (gnm_expr_new_constant (value_dup (info->base.range_2)),
+					   GNM_EXPR_OP_GTE,
+					   gnm_expr_new_constant (value_new_int (info->censor_mark))),
+					  gnm_expr_new_constant (value_new_int (1)),
+					  gnm_expr_new_constant (value_new_int (0))),
+					 GNM_EXPR_OP_MULT,
+					 gnm_expr_new_funcall3 
+					 (fd_if,
+					  gnm_expr_new_binary
+					  (gnm_expr_new_constant (value_dup (info->base.range_2)),
+					   GNM_EXPR_OP_LTE,
+					   gnm_expr_new_constant (value_new_int (info->censor_mark_to))),
+					  gnm_expr_new_constant (value_new_int (1)),
+					  gnm_expr_new_constant (value_new_int (0))));
+			
+			
+			expr_deaths = gnm_expr_new_funcall3 
+				(fd_if,
+				 gnm_expr_new_binary (make_cellref (-1, 0),
+						      GNM_EXPR_OP_EQUAL,
+						      gnm_expr_new_constant (value_new_string (""))),
+				 gnm_expr_new_constant (value_new_string ("")),
+				 gnm_expr_new_funcall1 (fd_sum,
+							gnm_expr_new_binary 
+							(gnm_expr_copy (expr_group),
+							 GNM_EXPR_OP_MULT,
+							 gnm_expr_new_binary
+							 (gnm_expr_new_funcall3 
+							  (fd_if,
+							   gnm_expr_new_binary
+							   (gnm_expr_copy (expr_data),
+							    GNM_EXPR_OP_EQUAL,
+							    make_cellref (-2-i*colspan, 0)),
+							   gnm_expr_new_constant (value_new_int (1)),
+							   gnm_expr_new_constant (value_new_int (0))),
+							  GNM_EXPR_OP_MULT,
+							  gnm_expr_new_binary 
+							  (gnm_expr_new_constant (value_new_int (1)),
+							   GNM_EXPR_OP_SUB,
+							   gnm_expr_copy (expr_censor))))));
+			expr_censures =  gnm_expr_new_funcall3 
+				(fd_if,
+				 gnm_expr_new_binary (make_cellref (-1, 0),
+						      GNM_EXPR_OP_EQUAL,
+						      gnm_expr_new_constant (value_new_string (""))),
+				 gnm_expr_new_constant (value_new_string ("")),
+				 gnm_expr_new_funcall1 (fd_sum,
+							gnm_expr_new_binary 
+							(gnm_expr_copy (expr_group),
+							 GNM_EXPR_OP_MULT,
+							 gnm_expr_new_binary
+							 (gnm_expr_new_funcall3 
+							  (fd_if,
+							   gnm_expr_new_binary
+							   (gnm_expr_copy (expr_data),
+							    GNM_EXPR_OP_EQUAL,
+							    make_cellref (-3-i*colspan, 0)),
+							   gnm_expr_new_constant (value_new_int (1)),
+							   gnm_expr_new_constant (value_new_int (0))),
+							  GNM_EXPR_OP_MULT,
+							  expr_censor))));
+		} else
+			expr_deaths = gnm_expr_new_funcall3 
+				(fd_if,
+				 gnm_expr_new_binary (make_cellref (-1, 0),
+						      GNM_EXPR_OP_EQUAL,
+						      gnm_expr_new_constant (value_new_string (""))),
+				 gnm_expr_new_constant (value_new_string ("")),
+				 gnm_expr_new_funcall1 (fd_sum,
+							gnm_expr_new_binary 
+							(gnm_expr_copy (expr_group),
+							 GNM_EXPR_OP_MULT,
+							 gnm_expr_new_funcall3 
+							 (fd_if,
+							  gnm_expr_new_binary
+							  (gnm_expr_copy (expr_data),
+							   GNM_EXPR_OP_EQUAL,
+							   make_cellref (-2-i*colspan, 0)),
+							  gnm_expr_new_constant (value_new_int (1)),
+							  gnm_expr_new_constant (value_new_int (0))))));
+		
+		expr_prob_zero = gnm_expr_new_binary (gnm_expr_new_binary (make_cellref ( - prob_col, 0),
+									   GNM_EXPR_OP_SUB,
+									   make_cellref (1 - prob_col, 0)),
 						      GNM_EXPR_OP_DIV,
-						      dao_get_rangeref (dao, 3, 2, 3, 1+rows)),
-				 GNM_EXPR_OP_MULT,
-				 dao_get_rangeref (dao, 3, 2, 3, 1+rows));
+						      make_cellref ( - prob_col, 0));
+		expr_prob = gnm_expr_new_funcall3 (fd_if,
+						   gnm_expr_new_binary
+						   (make_cellref (1 - prob_col, 0),
+						    GNM_EXPR_OP_EQUAL,
+						    gnm_expr_new_constant (value_new_string (""))),
+						   gnm_expr_new_constant (value_new_string ("")),
+						   gnm_expr_new_binary (gnm_expr_copy (expr_prob_zero),
+									GNM_EXPR_OP_MULT,
+									make_cellref (0, -1)));
+		
+		if (info->std_err) {
+			expr_std_err = gnm_expr_new_funcall3 (fd_if,
+							      gnm_expr_new_binary
+							      (make_cellref (-1, 0),
+							       GNM_EXPR_OP_EQUAL,
+							       gnm_expr_new_constant (value_new_string (""))),
+							      gnm_expr_new_constant (value_new_string ("")),
+							      gnm_expr_new_binary (make_cellref (-1, 0),
+										   GNM_EXPR_OP_MULT,
+										   gnm_expr_new_funcall1
+										   (fd_sqrt,
+										    gnm_expr_new_binary 
+										    (gnm_expr_new_binary 
+										     (gnm_expr_new_constant 
+										      (value_new_int (1)),
+										      GNM_EXPR_OP_SUB,
+										      make_cellref (-1, 0)),
+										     GNM_EXPR_OP_DIV,
+										     make_cellref 
+										     ( - std_err_col, 0)))));
 			
-			censures = gnm_go_data_vector_new_expr (dao->sheet, gnm_expr_top_new (expr));
-
+			dao_set_format  (dao, std_err_col, 2, std_err_col, rows + 1, "0.0000");
+			dao_set_cell_expr (dao, std_err_col, 2, gnm_expr_copy (expr_std_err));
+		}
+		
+		dao_set_format  (dao, prob_col, 2, prob_col, rows + 1, "0.00%");
+		
+		dao_set_cell_array_expr (dao, 0, 2, gnm_expr_copy (expr_at_risk)); 	
+		dao_set_cell_array_expr (dao, 1, 2, gnm_expr_copy (expr_deaths)); 	
+		dao_set_cell_expr (dao, prob_col, 2, expr_prob_zero);
+		
+		if (expr_censures != NULL)
+			dao_set_cell_array_expr (dao, 2, 2, gnm_expr_copy (expr_censures));
+		
+		for (row = 1; row < rows; row++) {
+			dao_set_cell_array_expr (dao, 0, 2+row, gnm_expr_copy (expr_at_risk)); 	
+			dao_set_cell_array_expr (dao, 1, 2+row, gnm_expr_copy (expr_deaths)); 	
+			if (expr_censures != NULL)
+				dao_set_cell_array_expr (dao, 2, 2+row, gnm_expr_copy (expr_censures));
+			dao_set_cell_array_expr (dao, prob_col, 2+row, gnm_expr_copy (expr_prob)); 
+			if (info->std_err)
+				dao_set_cell_expr (dao, std_err_col, 2+row, gnm_expr_copy (expr_std_err));
+		}
+		
+		gnm_expr_free (expr_at_risk);
+		gnm_expr_free (expr_deaths);
+		gnm_expr_free (expr_prob);
+		if (expr_censures != NULL) {
+			gnm_expr_free (expr_censures);
+			expr_censures = NULL;
+		}
+		if (expr_std_err != NULL) {
+			gnm_expr_free (expr_std_err);
+			expr_std_err = NULL;
+		}
+		
+		/* Create Chart if requested */
+		if (info->chart) {
+			GogSeries    *series;
+			GOData *probabilities;
+			GogStyle  *style;
+			
+			probabilities = dao_go_data_vector (dao, prob_col, 2, prob_col, 1+rows);
+			
+			g_object_ref (times);
 			series = gog_plot_new_series (plot);
 			gog_series_set_dim (series, 0, times, NULL);
-			gog_series_set_dim (series, 1, censures, NULL);
-
+			gog_series_set_dim (series, 1, probabilities, NULL);
+			
 			style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
 			style->marker.auto_shape = FALSE;
-			go_marker_set_shape (style->marker.mark, GO_MARKER_TRIANGLE_DOWN);
-			style->line.dash_type = GO_LINE_NONE;
-			style->line.auto_dash = FALSE;
-			style->line.width = 0;
+			go_marker_set_shape (style->marker.mark, GO_MARKER_NONE);
 			gog_styled_object_set_style (GOG_STYLED_OBJECT (series), style);
+			
+			if (info->censored && info->ticks) {
+				GOData *censures;
+				GnmExpr const *expr;
+				
+				expr = gnm_expr_new_binary 
+					(gnm_expr_new_binary (dao_get_rangeref (dao, prob_col, 2, prob_col, 1+rows),
+							      GNM_EXPR_OP_DIV,
+							      dao_get_rangeref (dao, 2, 2, 2, 1+rows)),
+					 GNM_EXPR_OP_MULT,
+					 dao_get_rangeref (dao, 2, 2, 2, 1+rows));
+				
+				censures = gnm_go_data_vector_new_expr (dao->sheet, gnm_expr_top_new (expr));
+				
+				series = gog_plot_new_series (plot);
+				g_object_ref (times);
+				gog_series_set_dim (series, 0, times, NULL);
+				gog_series_set_dim (series, 1, censures, NULL);
+				
+				style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
+				style->marker.auto_shape = FALSE;
+				go_marker_set_shape (style->marker.mark, GO_MARKER_TRIANGLE_DOWN);
+				style->line.dash_type = GO_LINE_NONE;
+				style->line.auto_dash = FALSE;
+				style->line.width = 0;
+				gog_styled_object_set_style (GOG_STYLED_OBJECT (series), style);
+			}
 		}
 
+		gnm_expr_free (expr_group);
+
+		dao->offset_col += colspan;
+		if (gl != NULL)
+			gl = gl->next;
+	}
+	/* End of Loop */
+
+	if (info->chart) {
 		so = sheet_object_graph_new (graph);
 		g_object_unref (graph);
+		g_object_unref (times);
 		
 		dao_set_sheet_object (dao, 0, 1, so);
-	}
+	}	
+
+	gnm_expr_free (expr_data);
+	if (expr_group_data != NULL)
+		gnm_expr_free (expr_group_data);
+
+	gnm_func_unref (fd_small);
+	gnm_func_unref (fd_if);
+	gnm_func_unref (fd_iserror);
+	gnm_func_unref (fd_sum);
+	if (fd_sqrt != NULL)
+		gnm_func_unref (fd_sqrt);
 
 	dao_redraw_respan (dao);
 
 	return FALSE;
 }
 
+static void
+analysis_tool_kaplan_meier_clear_gl_cb (gpointer data, G_GNUC_UNUSED gpointer user_data)
+{
+	analysis_tools_kaplan_meier_group_t *group = data;
+
+	g_return_if_fail (data != NULL);
+
+	g_free (group->name);
+	g_free (group);
+}
 
 gboolean
 analysis_tool_kaplan_meier_engine (data_analysis_output_t *dao, gpointer specs,
 			      analysis_tool_engine_t selector, gpointer result)
 {
 	analysis_tools_data_kaplan_meier_t *info = specs;
+	int multiple;
 
 	switch (selector) {
 	case TOOL_ENGINE_UPDATE_DESCRIPTOR:
@@ -398,11 +506,17 @@
 						result) 
 			== NULL);
 	case TOOL_ENGINE_UPDATE_DAO:
-		dao_adjust (dao, (info->std_err ? 5 : 4) + (info->censored ? 1 : 0), 
+		multiple = ((info->group_list == NULL) ? 1 :  g_slist_length (info->group_list));
+		dao_adjust (dao, 1 + multiple * ((info->std_err ? 4 : 3) + (info->censored ? 1 : 0)), 
 			    info->base.range_1->v_range.cell.b.row 
 			    - info->base.range_1->v_range.cell.a.row + 3);
 		return FALSE;
 	case TOOL_ENGINE_CLEAN_UP:
+		value_release (info->range_3);
+		info->range_3 = NULL;
+		g_slist_foreach (info->group_list, analysis_tool_kaplan_meier_clear_gl_cb, NULL);
+		g_slist_free (info->group_list);
+		info->group_list = NULL;
 		return analysis_tool_generic_b_clean (specs);
 	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
 		return FALSE;

Modified: trunk/src/tools/analysis-kaplan-meier.h
==============================================================================
--- trunk/src/tools/analysis-kaplan-meier.h	(original)
+++ trunk/src/tools/analysis-kaplan-meier.h	Fri Nov 14 07:36:31 2008
@@ -33,7 +33,6 @@
 #include "tools.h"
 #include "analysis-tools.h"
 
-
 /* typedef struct { */
 /* 	analysis_tools_error_code_t err; */
 /* 	WorkbookControl *wbc; */
@@ -41,19 +40,27 @@
 /* 	GnmValue *range_2; */
 /* 	gboolean   labels; */
 /* 	gnm_float alpha; */
-/* } analysis_tools_data_ftest_t; */
-
+/* } analysis_tools_data_generic_b_t; */
 
 typedef struct {
 	analysis_tools_data_generic_b_t base;
+	GnmValue *range_3;
 	gboolean censored;
 	int censor_mark;
 	int censor_mark_to;
 	gboolean chart;
 	gboolean ticks;
 	gboolean std_err;
+	GSList *group_list;
 } analysis_tools_data_kaplan_meier_t;
 
+typedef struct {
+	char *name;
+	guint group_from;
+	guint group_to;
+} analysis_tools_kaplan_meier_group_t;
+
+
 gboolean analysis_tool_kaplan_meier_engine (data_analysis_output_t *dao, 
 					    gpointer specs,
 					   analysis_tool_engine_t selector, 



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