From 4d688b2e05945b3e3c733a005fb2775110ebb78b Mon Sep 17 00:00:00 2001 From: Jason Stover Date: Wed, 27 Feb 2008 04:04:16 +0000 Subject: [PATCH] Added egression dialog --- src/ui/gui/automake.mk | 3 + src/ui/gui/data-editor.c | 12 ++ src/ui/gui/data-editor.h | 1 + src/ui/gui/regression-dialog.c | 336 +++++++++++++++++++++++++++++++ src/ui/gui/regression-dialog.h | 27 +++ src/ui/gui/regression.glade | 350 +++++++++++++++++++++++++++++++++ 6 files changed, 729 insertions(+) create mode 100644 src/ui/gui/regression-dialog.c create mode 100644 src/ui/gui/regression-dialog.h create mode 100644 src/ui/gui/regression.glade diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index d5b5ec95..7dce4ad2 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -60,6 +60,7 @@ dist_src_ui_gui_psppire_DATA = \ $(top_srcdir)/src/ui/gui/psppire.glade \ $(top_srcdir)/src/ui/gui/rank.glade \ $(top_srcdir)/src/ui/gui/recode.glade \ + $(top_srcdir)/src/ui/gui/regression.glade \ $(top_srcdir)/src/ui/gui/syntax-editor.glade \ $(top_srcdir)/src/ui/gui/t-test.glade \ $(top_srcdir)/src/ui/gui/psppicon.png \ @@ -154,6 +155,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/rank-dialog.h \ src/ui/gui/recode-dialog.c \ src/ui/gui/recode-dialog.h \ + src/ui/gui/regression-dialog.c \ + src/ui/gui/regression-dialog.h \ src/ui/gui/select-cases-dialog.c \ src/ui/gui/select-cases-dialog.h \ src/ui/gui/sort-cases-dialog.c \ diff --git a/src/ui/gui/data-editor.c b/src/ui/gui/data-editor.c index 038b9685..96f42cc2 100644 --- a/src/ui/gui/data-editor.c +++ b/src/ui/gui/data-editor.c @@ -46,6 +46,7 @@ #include "frequencies-dialog.h" #include "examine-dialog.h" #include "dict-display.h" +#include "regression-dialog.h" #include "clipboard.h" #include "oneway-anova-dialog.h" @@ -732,6 +733,14 @@ new_data_editor (void) G_CALLBACK (examine_dialog), de); + de->invoke_regression_dialog = + gtk_action_new ("regression-dialog", + _("Linear _Regression"), + _("Estimate parameters of the linear model"), + "pspp-regression"); + + g_signal_connect (de->invoke_regression_dialog, "activate", + G_CALLBACK (regression_dialog), de); e->window = GTK_WINDOW (get_widget_assert (de->xml, "data_editor")); @@ -903,6 +912,9 @@ new_data_editor (void) get_widget_assert (de->xml, "analyze_explore") ); + gtk_action_connect_proxy (de->invoke_regression_dialog, + get_widget_assert (de->xml, "linear-regression") + ); g_signal_connect (get_widget_assert (de->xml,"help_about"), "activate", diff --git a/src/ui/gui/data-editor.h b/src/ui/gui/data-editor.h index 8d79082c..3101ee6b 100644 --- a/src/ui/gui/data-editor.h +++ b/src/ui/gui/data-editor.h @@ -51,6 +51,7 @@ struct data_editor GtkAction *invoke_descriptives_dialog; GtkAction *invoke_frequencies_dialog; GtkAction *invoke_examine_dialog; + GtkAction *invoke_regression_dialog; GtkAction *invoke_t_test_independent_samples_dialog; GtkAction *invoke_t_test_paired_samples_dialog; diff --git a/src/ui/gui/regression-dialog.c b/src/ui/gui/regression-dialog.c new file mode 100644 index 00000000..2036fa7c --- /dev/null +++ b/src/ui/gui/regression-dialog.c @@ -0,0 +1,336 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 Free Software Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "checkbox-treeview.h" +#include "regression-dialog.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + + +#define REGRESSION_STATS \ + RG (COEFF, N_("Coeff")) \ + RG (R, N_("R")) \ + RG (ANOVA, N_("Anova")) \ + RG (BCOV, N_("Bcov")) +enum + { +#define RG(NAME, LABEL) RG_##NAME, + REGRESSION_STATS +#undef RG + N_REGRESSION_STATS + }; + +enum + { +#define RG(NAME, LABEL) B_RG_##NAME = 1u << RG_##NAME, + REGRESSION_STATS +#undef RG + B_RG_STATS_ALL = (1u << N_REGRESSION_STATS) - 1, + B_RG_STATS_DEFAULT = B_RG_ANOVA | B_RG_COEFF | B_RG_R + }; + +static const struct checkbox_entry_item stats[] = + { +#define RG(NAME, LABEL) {#NAME, LABEL}, + REGRESSION_STATS +#undef RG + }; + +struct save_options +{ + gboolean pred; + gboolean resid; +}; +struct regression_dialog +{ + GtkTreeView *dep_vars; + GtkTreeView *indep_vars; + PsppireDict *dict; + + GtkToggleButton *resid_button; + GtkToggleButton *pred_button; + + GtkWidget *stat_dialog; + GtkWidget *save_dialog; + + GtkWidget *stat_view; + GtkTreeModel *stat; + struct save_options current_opts; +}; + +static void +refresh (PsppireDialog *dialog, struct regression_dialog *rd) +{ + GtkTreeModel *liststore = gtk_tree_view_get_model (rd->dep_vars); + gtk_list_store_clear (GTK_LIST_STORE (liststore)); + + liststore = gtk_tree_view_get_model (rd->indep_vars); + gtk_list_store_clear (GTK_LIST_STORE (liststore)); +} + +static void +on_statistics_clicked (struct regression_dialog *rd) +{ + GtkListStore *liststore; + int ret; + + liststore = clone_list_store (GTK_LIST_STORE (rd->stat)); + + ret = psppire_dialog_run (PSPPIRE_DIALOG (rd->stat_dialog)); + + if ( ret == PSPPIRE_RESPONSE_CONTINUE ) + { + g_object_unref (liststore); + } + else + { + g_object_unref (rd->stat); + gtk_tree_view_set_model (GTK_TREE_VIEW (rd->stat_view) , GTK_TREE_MODEL (liststore)); + rd->stat = GTK_TREE_MODEL (liststore); + } +} + +static void +on_save_clicked (struct regression_dialog *rd) +{ + int ret; + if (rd->current_opts.pred) + { + gtk_toggle_button_set_active (rd->pred_button, TRUE); + } + if (rd->current_opts.resid) + { + gtk_toggle_button_set_active (rd->resid_button, TRUE); + } + + ret = psppire_dialog_run (PSPPIRE_DIALOG (rd->save_dialog)); + + if ( ret == PSPPIRE_RESPONSE_CONTINUE ) + { + rd->current_opts.pred = (gtk_toggle_button_get_active (rd->pred_button) == TRUE) + ? TRUE : FALSE; + rd->current_opts.resid = (gtk_toggle_button_get_active (rd->resid_button) == TRUE) + ? TRUE : FALSE; + } +} + +static char * +generate_syntax (const struct regression_dialog *rd) +{ + gint i; + int n; + guint selected; + GtkTreeIter iter; + gboolean ok; + + gchar *text; + GString *string = g_string_new ("REGRESSION"); + + g_string_append (string, "\n\t/VARIABLES="); + append_variable_names (string, rd->dict, GTK_TREE_VIEW (rd->indep_vars), 0); + g_string_append (string, "\n\t/DEPENDENT=\t"); + append_variable_names (string, rd->dict, GTK_TREE_VIEW (rd->dep_vars), 0); + + selected = 0; + for (i = 0, ok = gtk_tree_model_get_iter_first (rd->stat, &iter); ok; + i++, ok = gtk_tree_model_iter_next (rd->stat, &iter)) + { + gboolean toggled; + gtk_tree_model_get (rd->stat, &iter, + CHECKBOX_COLUMN_SELECTED, &toggled, -1); + if (toggled) + selected |= 1u << i; + else + selected &= ~(1u << i); + } + + if (selected) + { + g_string_append (string, "\n\t/STATISTICS="); + n = 0; + for (i = 0; i < N_REGRESSION_STATS; i++) + if (selected & (1u << i)) + { + if (n++) + g_string_append (string, " "); + g_string_append (string, stats[i].name); + } + } + if (rd->current_opts.pred || rd->current_opts.resid) + { + g_string_append (string, "\n\t/SAVE="); + if (rd->current_opts.pred) + g_string_append (string, " PRED"); + if (rd->current_opts.resid) + g_string_append (string, " RESID"); + } + g_string_append (string, ".\n"); + + text = string->str; + + g_string_free (string, FALSE); + + return text; +} + +/* Dialog is valid iff at least one dependent and one independent variable have + been selected. */ +static gboolean +dialog_state_valid (gpointer data) +{ + struct regression_dialog *rd = data; + + GtkTreeModel *dep_vars = gtk_tree_view_get_model (rd->dep_vars); + GtkTreeModel *indep_vars = gtk_tree_view_get_model (rd->indep_vars); + + GtkTreeIter notused; + + return (gtk_tree_model_get_iter_first (dep_vars, ¬used) + && gtk_tree_model_get_iter_first (indep_vars, ¬used)); +} + +/* Pops up the Regression dialog box */ +void +regression_dialog (GObject *o, gpointer data) +{ + gint response; + struct data_editor *de = data; + + struct regression_dialog rd; + + GladeXML *xml = XML_NEW ("regression.glade"); + GtkSheet *var_sheet; + PsppireVarStore *vs; + + GtkWidget *dialog = get_widget_assert (xml, "regression-dialog"); + GtkWidget *source = get_widget_assert (xml, "dict-view"); + GtkWidget *dest_dep = get_widget_assert (xml, "dep-view"); + GtkWidget *dest_indep = get_widget_assert (xml, "indep-view"); + GtkWidget *dep_selector = get_widget_assert (xml, "dep-selector"); + GtkWidget *indep_selector = get_widget_assert (xml, "indep-selector"); + GtkWidget *stat_button = get_widget_assert (xml, "stat-button"); + GtkWidget *save_button = get_widget_assert (xml, "save-button"); + + + rd.stat_view = get_widget_assert (xml, "stat-view"); + + var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet")); + + vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet)); + + put_checkbox_items_in_treeview (GTK_TREE_VIEW(rd.stat_view), + B_RG_STATS_DEFAULT, + N_REGRESSION_STATS, + stats + ); + + gtk_window_set_transient_for (GTK_WINDOW (dialog), de->parent.window); + + attach_dictionary_to_treeview (GTK_TREE_VIEW (source), + vs->dict, + GTK_SELECTION_MULTIPLE, NULL); + + set_dest_model (GTK_TREE_VIEW (dest_dep), vs->dict); + set_dest_model (GTK_TREE_VIEW (dest_indep), vs->dict); + + psppire_selector_set_subjects (PSPPIRE_SELECTOR (dep_selector), + source, + dest_dep, + insert_source_row_into_tree_view, + NULL, + NULL); + + psppire_selector_set_subjects (PSPPIRE_SELECTOR (indep_selector), + source, + dest_indep, + insert_source_row_into_tree_view, + NULL, + NULL); + + rd.dep_vars = GTK_TREE_VIEW (dest_dep); + rd.indep_vars = GTK_TREE_VIEW (dest_indep); + rd.dict = vs->dict; + rd.save_dialog = get_widget_assert (xml, "save-dialog"); + rd.pred_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pred-button")); + rd.resid_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "resid-button")); + rd.stat_dialog = get_widget_assert (xml, "statistics-dialog"); + + rd.stat = gtk_tree_view_get_model (GTK_TREE_VIEW (rd.stat_view)); + rd.current_opts.pred = FALSE; + rd.current_opts.resid = FALSE; + + gtk_window_set_transient_for (GTK_WINDOW (rd.save_dialog), de->parent.window); + gtk_window_set_transient_for (GTK_WINDOW (rd.stat_dialog), de->parent.window); + + g_signal_connect (dialog, "refresh", G_CALLBACK (refresh), &rd); + + psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog), + dialog_state_valid, &rd); + + g_signal_connect_swapped (stat_button, "clicked", + G_CALLBACK (on_statistics_clicked), &rd); + g_signal_connect_swapped (save_button, "clicked", + G_CALLBACK (on_save_clicked), &rd); + + response = psppire_dialog_run (PSPPIRE_DIALOG (dialog)); + + + switch (response) + { + case GTK_RESPONSE_OK: + { + gchar *syntax = generate_syntax (&rd); + struct getl_interface *sss = create_syntax_string_source (syntax); + execute_syntax (sss); + + g_free (syntax); + } + break; + case PSPPIRE_RESPONSE_PASTE: + { + gchar *syntax = generate_syntax (&rd); + + struct syntax_editor *se = + (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL); + + gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1); + + g_free (syntax); + } + break; + default: + break; + } + + g_object_unref (xml); +} diff --git a/src/ui/gui/regression-dialog.h b/src/ui/gui/regression-dialog.h new file mode 100644 index 00000000..ca79ba35 --- /dev/null +++ b/src/ui/gui/regression-dialog.h @@ -0,0 +1,27 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 Free Software Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef __REGRESSION_DIALOG_H +#define __REGRESSION_DIALOG_H + + +#include +#include + + +void regression_dialog (GObject *o, gpointer data); + +#endif diff --git a/src/ui/gui/regression.glade b/src/ui/gui/regression.glade new file mode 100644 index 00000000..b0d9a758 --- /dev/null +++ b/src/ui/gui/regression.glade @@ -0,0 +1,350 @@ + + + + + + + Regression + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 3 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_SPREAD + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Statistics... + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Save... + 0 + + + 1 + + + + + 3 + 2 + 3 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + 5 + + + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + 5 + + + 1 + 2 + 1 + 2 + + + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + + + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_SHADOW_NONE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Dependent + True + + + label_item + + + + + 2 + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_SHADOW_NONE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Independent + True + + + label_item + + + + + 2 + 3 + 1 + 2 + + + + + + + True + 5 + + + False + False + GTK_PACK_END + 1 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Regression: Save + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Predicted values + 0 + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Residuals + 0 + True + + + 1 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK + + + False + False + GTK_PACK_END + 1 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Regression: Statistics + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_SHADOW_NONE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Statistics + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK + + + False + False + GTK_PACK_END + 1 + + + + + + -- 2.30.2